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