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 (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
24 /*	  All Rights Reserved  	*/
25 
26 /*
27  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
28  * Use is subject to license terms.
29  */
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 /*LINTLIBRARY*/
33 
34 #include "c_synonyms.h"
35 #include <sys/types.h>
36 #include <stdio.h>
37 #include <ctype.h>
38 #include "s_string.h"
39 #include <stdlib.h>
40 
41 /* global to this file */
42 #define	STRLEN 128UL
43 #define	STRALLOC 128UL
44 #define	MAXINCR 250000UL
45 
46 /* buffer pool for allocating string structures */
47 typedef struct {
48 	string s[STRALLOC];
49 	size_t o;
50 } stralloc;
51 static stralloc *freep = NULL;
52 
53 /* pool of freed strings */
54 static string *freed = NULL;
55 static string *s_alloc(void);
56 static void s_simplegrow(string *, size_t);
57 
58 void
59 s_free(string *sp)
60 {
61 	if (sp != NULL) {
62 		sp->ptr = (char *)freed;
63 		freed = sp;
64 	}
65 }
66 
67 /* allocate a string head */
68 static string *
69 s_alloc(void)
70 {
71 	if (freep == NULL || freep->o >= STRALLOC) {
72 		freep = (stralloc *)malloc(sizeof (stralloc));
73 		if (freep == NULL) {
74 			perror("allocating string");
75 			exit(1);
76 		}
77 		freep->o = (size_t)0;
78 	}
79 	return (&(freep->s[freep->o++]));
80 }
81 
82 /* create a new `short' string */
83 string *
84 s_new(void)
85 {
86 	string *sp;
87 
88 	if (freed != NULL) {
89 		sp = freed;
90 		/*LINTED*/
91 		freed = (string *)(freed->ptr);
92 		sp->ptr = sp->base;
93 		return (sp);
94 	}
95 	sp = s_alloc();
96 	sp->base = sp->ptr = malloc(STRLEN);
97 	if (sp->base == NULL) {
98 		perror("allocating string");
99 		exit(1);
100 	}
101 	sp->end = sp->base + STRLEN;
102 	s_terminate(sp);
103 	return (sp);
104 }
105 
106 /* grow a string's allocation by at least `incr' bytes */
107 static void
108 s_simplegrow(string *sp, size_t incr)
109 {
110 	char *cp;
111 	size_t size;
112 
113 	/*
114 	 *  take a larger increment to avoid mallocing too often
115 	 */
116 	if (((sp->end - sp->base) < incr) && (MAXINCR < incr))
117 		size = (sp->end - sp->base) + incr;
118 	else if ((sp->end - sp->base) > MAXINCR)
119 		size = (sp->end - sp->base) + MAXINCR;
120 	else
121 		size = (size_t)2 * (sp->end - sp->base);
122 
123 	cp = realloc(sp->base, size);
124 	if (cp == NULL) {
125 		perror("string:");
126 		exit(1);
127 	}
128 	sp->ptr = (sp->ptr - sp->base) + cp;
129 	sp->end = cp + size;
130 	sp->base = cp;
131 }
132 
133 /* grow a string's allocation */
134 int
135 s_grow(string *sp, int c)
136 {
137 	s_simplegrow(sp, (size_t)2);
138 	s_putc(sp, c);
139 	return (c);
140 }
141 
142 /* return a string containing a character array (this had better not grow) */
143 string *
144 s_array(char *cp, size_t len)
145 {
146 	string *sp = s_alloc();
147 
148 	sp->base = sp->ptr = cp;
149 	sp->end = sp->base + len;
150 	return (sp);
151 }
152 
153 /* return a string containing a copy of the passed char array */
154 string*
155 s_copy(char *cp)
156 {
157 	string *sp;
158 	size_t len;
159 
160 	sp = s_alloc();
161 	len = strlen(cp)+1;
162 	sp->base = malloc(len);
163 	if (sp->base == NULL) {
164 		perror("string:");
165 		exit(1);
166 	}
167 	sp->end = sp->base + len;	/* point past end of allocation */
168 	(void) strcpy(sp->base, cp);
169 	sp->ptr = sp->end - (size_t)1;	/* point to NULL terminator */
170 	return (sp);
171 }
172 
173 /* convert string to lower case */
174 void
175 s_tolower(string *sp)
176 {
177 	char *cp;
178 
179 	for (cp = sp->ptr; *cp; cp++)
180 		*cp = tolower(*cp);
181 }
182 
183 void
184 s_skipwhite(string *sp)
185 {
186 	while (isspace(*sp->ptr))
187 		s_skipc(sp);
188 }
189 
190 /* append a char array to a string */
191 string *
192 s_append(string *to, char *from)
193 {
194 	if (to == NULL)
195 		to = s_new();
196 	if (from == NULL)
197 		return (to);
198 	for (; *from; from++)
199 		s_putc(to, (int)(unsigned int)*from);
200 	s_terminate(to);
201 	return (to);
202 }
203 
204 /*
205  * Append a logical input sequence into a string.  Ignore blank and
206  * comment lines.  Backslash preceding newline indicates continuation.
207  * The `lineortoken' variable indicates whether the sequence to beinput
208  * is a whitespace delimited token or a whole line.
209  *
210  *	FILE *fp;		stream to read from
211  *	string *to;		where to put token
212  *	int lineortoken;	how the sequence terminates
213  *
214  * Returns a pointer to the string or NULL. Trailing newline is stripped off.
215  */
216 string *
217 s_seq_read(FILE *fp, string *to, int lineortoken)
218 {
219 	int c;
220 	int done = 0;
221 
222 	if (feof(fp))
223 		return (NULL);
224 
225 	/* get rid of leading goo */
226 	do {
227 		c = getc(fp);
228 		switch (c) {
229 		case EOF:
230 			if (to != NULL)
231 				s_terminate(to);
232 			return (NULL);
233 		case '#':
234 			/*LINTED*/
235 			while ((c = getc(fp)) != '\n' && c != EOF);
236 			break;
237 		case ' ':
238 		case '\t':
239 		case '\n':
240 		case '\r':
241 		case '\f':
242 			break;
243 		default:
244 			done = 1;
245 			break;
246 		}
247 	} while (!done);
248 
249 	if (to == NULL)
250 		to = s_new();
251 
252 	/* gather up a sequence */
253 	for (;;) {
254 		switch (c) {
255 		case '\\':
256 			c = getc(fp);
257 			if (c != '\n') {
258 				s_putc(to, (int)(unsigned int)'\\');
259 				s_putc(to, c);
260 			}
261 			break;
262 		case EOF:
263 		case '\r':
264 		case '\f':
265 		case '\n':
266 			s_terminate(to);
267 			return (to);
268 		case ' ':
269 		case '\t':
270 			if (lineortoken == TOKEN) {
271 				s_terminate(to);
272 				return (to);
273 			}
274 			/* fall through */
275 		default:
276 			s_putc(to, c);
277 			break;
278 		}
279 		c = getc(fp);
280 	}
281 }
282 
283 string *
284 s_tok(string *from, char *split)
285 {
286 	char *splitend = strpbrk(from->ptr, split);
287 
288 	if (splitend) {
289 		string *to = s_new();
290 		for (; from->ptr < splitend; ) {
291 			s_putc(to, (int)(unsigned int)*from->ptr);
292 			from->ptr++;
293 		}
294 		s_terminate(to);
295 		s_restart(to);
296 		/* LINT: warning due to lint bug */
297 		from->ptr += strspn(from->ptr, split);
298 		return (to);
299 	}
300 
301 	else if (from->ptr[0]) {
302 		string *to = s_clone(from);
303 		while (*from->ptr)
304 			from->ptr++;
305 		return (to);
306 	}
307 
308 	else
309 		return (NULL);
310 }
311 
312 /*
313  * Append an input line to a string.
314  *
315  * Returns a pointer to the string (or NULL).
316  * Trailing newline is left on.
317  */
318 char *
319 s_read_line(FILE *fp, string *to)
320 {
321 	int c;
322 	size_t len = 0;
323 
324 	s_terminate(to);
325 
326 	/* end of input */
327 	if (feof(fp) || (c = getc(fp)) == EOF)
328 		return (NULL);
329 
330 	/* gather up a line */
331 	for (; ; ) {
332 		len++;
333 		switch (c) {
334 		case EOF:
335 			s_terminate(to);
336 			return (to->ptr - len);
337 		case '\n':
338 			s_putc(to, (int)(unsigned int)'\n');
339 			s_terminate(to);
340 			return (to->ptr - len);
341 		default:
342 			s_putc(to, c);
343 			break;
344 		}
345 		c = getc(fp);
346 	}
347 }
348 
349 /*
350  * Read till eof
351  */
352 size_t
353 s_read_to_eof(FILE *fp, string *to)
354 {
355 	size_t got;
356 	size_t have;
357 
358 	s_terminate(to);
359 
360 	for (; ; ) {
361 		if (feof(fp))
362 			break;
363 		/* allocate room for a full buffer */
364 		have = to->end - to->ptr;
365 		if (have < 4096UL)
366 			s_simplegrow(to, (size_t)4096);
367 
368 		/* get a buffers worth */
369 		have = to->end - to->ptr;
370 		got = fread(to->ptr, (size_t)1, have, fp);
371 		if (got == (size_t)0)
372 			break;
373 		/* LINT: warning due to lint bug */
374 		to->ptr += got;
375 	}
376 
377 	/* null terminate the line */
378 	s_terminate(to);
379 	return (to->ptr - to->base);
380 }
381 
382 /*
383  * Get the next field from a string.  The field is delimited by white space,
384  * single or double quotes.
385  *
386  *	string *from;	string to parse
387  *	string *to;	where to put parsed token
388  */
389 string *
390 s_parse(string *from, string *to)
391 {
392 	while (isspace(*from->ptr))
393 		from->ptr++;
394 	if (*from->ptr == '\0')
395 		return (NULL);
396 	if (to == NULL)
397 		to = s_new();
398 	if (*from->ptr == '\'') {
399 		from->ptr++;
400 		for (; *from->ptr != '\'' && *from->ptr != '\0'; from->ptr++)
401 			s_putc(to, (int)(unsigned int)*from->ptr);
402 		if (*from->ptr == '\'')
403 			from->ptr++;
404 	} else if (*from->ptr == '"') {
405 		from->ptr++;
406 		for (; *from->ptr != '"' && *from->ptr != '\0'; from->ptr++)
407 			s_putc(to, (int)(unsigned int)*from->ptr);
408 		if (*from->ptr == '"')
409 			from->ptr++;
410 	} else {
411 		for (; !isspace(*from->ptr) && *from->ptr != '\0'; from->ptr++)
412 			s_putc(to, (int)(unsigned int)*from->ptr);
413 	}
414 	s_terminate(to);
415 
416 	return (to);
417 }
418