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