1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 1997-2002 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #include <stdio.h>
30 #include <string.h>
31 #include <ctype.h>
32 #include <stdlib.h>
33 #include "parser.h"
34 #include "trace.h"
35 #include "util.h"
36 #include "errlog.h"
37
38 #define TABLE_INITIAL 50
39 #define TABLE_INCREMENT 50
40
41 /*
42 * String processing
43 */
44
45 /*
46 * strnormalize -- combined tab-to-space and strtrim, plus removal
47 * of leading and trailing *$%$^@!!! semicolons.
48 * Not internationalized: TBD.
49 */
50 char *
strnormalize(char * str)51 strnormalize(char *str)
52 {
53 char *p;
54
55 if (str == NULL || *str == NULL)
56 return (str);
57 for (p = str; *p != NULL; p++) {
58 if (isspace(*p)) {
59 *p = ' ';
60 }
61 }
62 p--;
63 while (p >= str && (isspace(*p) || *p == ';'))
64 *p-- = NULL;
65
66 /* ERA - remove leading spaces */
67 while (isspace(*str))
68 str++;
69
70 return (str);
71 }
72
73 char *
strtrim(char * str)74 strtrim(char *str)
75 {
76 char *p;
77
78 for (p = str; *p != NULL; p++)
79 continue;
80 p--;
81 while (p >= str && isspace(*p))
82 *p-- = NULL;
83 return (str);
84 }
85
86 /*
87 * strlower -- make a string lower-case, destructively.
88 * Not internationalized: TBD.
89 */
90 char *
strlower(char * str)91 strlower(char *str)
92 {
93 char *p;
94
95 for (p = str; *p != NULL; p++) {
96 *p = tolower(*p);
97 }
98 return (str);
99 }
100
101 /*
102 * strset -- update a dynamically-allocated string or die trying.
103 */
104 char *
strset(char * string,char * value)105 strset(char *string, char *value)
106 {
107 size_t vlen;
108
109 assert(value != NULL, "passed a NULL value to strset");
110 vlen = strlen(value);
111 if (string == NULL) {
112 /* It was never allocated, so allocate it. */
113 if ((string = malloc(vlen+1)) == NULL) {
114 errlog(FATAL, "malloc ran out of space");
115 }
116 } else if (strlen(string) < vlen) {
117
118 /* Reallocate bigger. */
119 if ((string = realloc(string, vlen+1)) == NULL) {
120 errlog(FATAL, "realloc ran out of space", "", 0);
121 }
122 }
123 (void) strcpy(string, value);
124 return (string);
125 }
126
127 /*
128 * in_string_set --see if string matches any member of a space-separated
129 * set of strings.
130 */
131 int
in_string_set(char * p,char * set)132 in_string_set(char *p, char *set)
133 {
134 char *q;
135 char save;
136
137 errlog(BEGIN, "in_string_set( p = \"%s\", set = \"%s\") {", p, set);
138
139 for (;;) {
140 set = skipb(set);
141 q = nextsep(set);
142 if (q == set) {
143 /* We've hit the end */
144 break;
145 }
146 save = *q;
147 *q = NULL;
148 if (strcmp(p, set) == 0) {
149 *q = save;
150 errlog(VERBOSE, "return YES");
151 errlog(END, "}");
152 return (YES);
153 }
154 *q = save;
155 set = q;
156 }
157 errlog(VERBOSE, "return NO");
158 errlog(END, "}");
159 return (NO);
160
161 }
162
163 char *
strend(char * p)164 strend(char *p)
165 {
166
167 while (*p)
168 p++;
169 return (p);
170 }
171
172 char *
lastspace(char * p)173 lastspace(char *p)
174 {
175 char *q;
176
177 q = strend(p);
178 q--;
179 while (q >= p && isspace(*q))
180 q--;
181 return (++q);
182 }
183
184 /*
185 * skipb -- skip over blanks (whitespace, actually), stopping
186 * on first non-blank.
187 */
188 char *
skipb(char * p)189 skipb(char *p)
190 {
191 while (*p && isspace(*p))
192 p++;
193 return (p);
194 }
195
196 /*
197 * nextb -- skip over non-blanks (including operators!)
198 * stopping on first blank.
199 */
200 char *
nextb(char * p)201 nextb(char *p)
202 {
203 while (*p && !isspace(*p))
204 p++;
205 return (p);
206 }
207
208 /*
209 * skipsep -- skip over separators (all but alnum and _),
210 * stopping on first non-separator.
211 */
212 char *
skipsep(char * p)213 skipsep(char *p)
214 {
215 errlog(BEGIN, "skipsep() {");
216 errlog(VERBOSE, "p (in) = %s", p);
217 while (*p && !(isalnum(*p) || *p == '_' || *p == '$'))
218 p++;
219 errlog(VERBOSE, "p (out) = %s", p);
220 errlog(END, "}");
221 return (p);
222 }
223
224 /*
225 * nextsep -- skip over non-separators (alnum and _, actually),
226 * stopping on first separator.
227 */
228 char *
nextsep(char * p)229 nextsep(char *p)
230 {
231 errlog(BEGIN, "nextsep() {");
232 errlog(VERBOSE, "p (in) = %s", p);
233 while (*p && isalnum(*p) || *p == '_' || *p == '$')
234 p++;
235 errlog(VERBOSE, "p (out) = %s", p);
236 errlog(END, "}");
237 return (p);
238 }
239
240 /*
241 * nextsep2 -- same as nextsep but also skips '.'
242 */
243 char *
nextsep2(char * p)244 nextsep2(char *p)
245 {
246 errlog(BEGIN, "nextsep() {");
247 errlog(VERBOSE, "p (in) = %s", p);
248 while (*p && isalnum(*p) || *p == '_' || *p == '$' || *p == '.')
249 p++;
250 errlog(VERBOSE, "p (out) = %s", p);
251 errlog(END, "}");
252 return (p);
253 }
254
255 /*
256 * objectname -- basename was taken (in man3c), so...
257 */
258 char *
objectname(char * name)259 objectname(char *name)
260 {
261 char *p;
262 static char basename[MAXLINE];
263
264 p = strrchr(name, '/');
265 while (p != NULL && *(p+1) == NULL) {
266 /* The / was at the end of the name. */
267 *p = NULL;
268 p = strrchr(name, '/');
269 }
270 (void) strlcpy(basename, p? p+1: name, MAXLINE);
271 if ((p = strstr(basename, ".c")) != NULL) {
272 *p = NULL;
273 }
274 return (strcat(basename, ".o"));
275 }
276
277 /*
278 * String tables
279 */
280
281 table_t *
create_string_table(int size)282 create_string_table(int size)
283 {
284 table_t *t;
285
286 errlog(BEGIN, "create_string_table() {");
287 if ((t = (table_t *)calloc((size_t)1,
288 (size_t)(sizeof (table_t) + (sizeof (char *)*size)))) == NULL) {
289 errlog(FATAL, "out of memory creating a string table");
290 }
291 t->nelem = size;
292 t->used = -1;
293 errlog(END, "}");
294 return (t);
295 }
296
297 table_t *
add_string_table(table_t * t,char * value)298 add_string_table(table_t *t, char *value)
299 {
300 table_t *t2;
301 int i;
302
303 if (t == NULL) {
304 errlog(FATAL, "programmer error: tried to add to "
305 "a NULL table");
306 }
307 if (in_string_table(t, value)) {
308 return (t);
309 }
310 t->used++;
311 if (t->used >= t->nelem) {
312 if ((t2 = realloc(t, (size_t)(sizeof (table_t)+(sizeof
313 (char *)*(t->nelem+TABLE_INCREMENT)))))
314 == NULL) {
315 errlog(FATAL, "out of memory extending string table");
316 }
317 t = t2;
318 t->nelem += TABLE_INCREMENT;
319 for (i = t->used; i < t->nelem; i++) {
320 t->elements[i] = NULL;
321 }
322 }
323
324 t->elements[t->used] = strset(t->elements[t->used], value);
325 return (t);
326 }
327
328 /*
329 * free_string_table -- really only mark it empty for reuse.
330 */
331 table_t *
free_string_table(table_t * t)332 free_string_table(table_t *t)
333 {
334 errlog(BEGIN, "free_string_table() {");
335 if (t != NULL) {
336 t->used = -1;
337 }
338 errlog(END, "}");
339 return (t);
340 }
341
342 char *
get_string_table(table_t * t,int index)343 get_string_table(table_t *t, int index)
344 {
345 if (t == NULL) {
346 return (NULL);
347 } else if (index > t->used) {
348 return (NULL);
349 } else {
350 return (t->elements[index]);
351 }
352 }
353
354 int
in_string_table(table_t * t,char * value)355 in_string_table(table_t *t, char *value)
356 {
357 int i;
358 size_t len = strlen(value);
359
360 if (t == NULL) {
361 return (0);
362 }
363 for (i = 0; i <= t->used; i++) {
364 if (strncmp(value, t->elements[i], len) == 0 &&
365 (t->elements[i][len] == NULL ||
366 t->elements[i][len] == ','))
367 return (1);
368 }
369 return (0);
370 }
371
372 static int
compare(const void * p,const void * q)373 compare(const void *p, const void *q)
374 {
375 return (strcmp((char *)(*(char **)p), (char *)(*(char **)q)));
376 }
377
378 void
sort_string_table(table_t * t)379 sort_string_table(table_t *t)
380 {
381 if (t) {
382 qsort((char *)t->elements, (size_t)t->used,
383 sizeof (char *), compare);
384 }
385 }
386