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 */
48char *
49strnormalize(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
71char *
72strtrim(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 */
88char *
89strlower(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 */
102char *
103strset(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 */
129int
130in_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
161char *
162strend(char *p)
163{
164
165	while (*p)
166		p++;
167	return (p);
168}
169
170char *
171lastspace(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 */
186char *
187skipb(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 */
198char *
199nextb(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 */
210char *
211skipsep(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 */
226char *
227nextsep(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 */
241char *
242nextsep2(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 */
256char *
257objectname(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
279table_t *
280create_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
295table_t *
296add_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 */
329table_t *
330free_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
340char *
341get_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
352int
353in_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
370static int
371compare(const void *p, const void *q)
372{
373	return (strcmp((char *)(*(char **)p), (char *)(*(char **)q)));
374}
375
376void
377sort_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