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