xref: /illumos-gate/usr/src/lib/libmail/common/s_string.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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
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 *
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 *
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
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
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 *
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*
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
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
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 *
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 *
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 *
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 *
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
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 *
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