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