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 *
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 *
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 *
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 *
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
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 *
164 strend(char *p)
165 {
166 
167 	while (*p)
168 		p++;
169 	return (p);
170 }
171 
172 char *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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
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
373 compare(const void *p, const void *q)
374 {
375 	return (strcmp((char *)(*(char **)p), (char *)(*(char **)q)));
376 }
377 
378 void
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