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