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 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 * 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 * 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 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 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 * 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* 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 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 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 * 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 * 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 * 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 * 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 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 * 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