10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*6812Sraf * Common Development and Distribution License (the "License"). 6*6812Sraf * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 211219Sraf 22*6812Sraf /* 23*6812Sraf * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24*6812Sraf * Use is subject to license terms. 25*6812Sraf */ 26*6812Sraf 270Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 280Sstevel@tonic-gate /* All Rights Reserved */ 290Sstevel@tonic-gate 30*6812Sraf #pragma ident "%Z%%M% %I% %E% SMI" 310Sstevel@tonic-gate 320Sstevel@tonic-gate #include <sys/types.h> 330Sstevel@tonic-gate #include <stdio.h> 340Sstevel@tonic-gate #include <ctype.h> 350Sstevel@tonic-gate #include "s_string.h" 360Sstevel@tonic-gate #include <stdlib.h> 370Sstevel@tonic-gate 380Sstevel@tonic-gate /* global to this file */ 390Sstevel@tonic-gate #define STRLEN 128UL 400Sstevel@tonic-gate #define STRALLOC 128UL 410Sstevel@tonic-gate #define MAXINCR 250000UL 420Sstevel@tonic-gate 430Sstevel@tonic-gate /* buffer pool for allocating string structures */ 440Sstevel@tonic-gate typedef struct { 450Sstevel@tonic-gate string s[STRALLOC]; 460Sstevel@tonic-gate size_t o; 470Sstevel@tonic-gate } stralloc; 480Sstevel@tonic-gate static stralloc *freep = NULL; 490Sstevel@tonic-gate 500Sstevel@tonic-gate /* pool of freed strings */ 510Sstevel@tonic-gate static string *freed = NULL; 520Sstevel@tonic-gate static string *s_alloc(void); 530Sstevel@tonic-gate static void s_simplegrow(string *, size_t); 540Sstevel@tonic-gate 550Sstevel@tonic-gate void 560Sstevel@tonic-gate s_free(string *sp) 570Sstevel@tonic-gate { 580Sstevel@tonic-gate if (sp != NULL) { 590Sstevel@tonic-gate sp->ptr = (char *)freed; 600Sstevel@tonic-gate freed = sp; 610Sstevel@tonic-gate } 620Sstevel@tonic-gate } 630Sstevel@tonic-gate 640Sstevel@tonic-gate /* allocate a string head */ 650Sstevel@tonic-gate static string * 660Sstevel@tonic-gate s_alloc(void) 670Sstevel@tonic-gate { 680Sstevel@tonic-gate if (freep == NULL || freep->o >= STRALLOC) { 690Sstevel@tonic-gate freep = (stralloc *)malloc(sizeof (stralloc)); 700Sstevel@tonic-gate if (freep == NULL) { 710Sstevel@tonic-gate perror("allocating string"); 720Sstevel@tonic-gate exit(1); 730Sstevel@tonic-gate } 740Sstevel@tonic-gate freep->o = (size_t)0; 750Sstevel@tonic-gate } 760Sstevel@tonic-gate return (&(freep->s[freep->o++])); 770Sstevel@tonic-gate } 780Sstevel@tonic-gate 790Sstevel@tonic-gate /* create a new `short' string */ 800Sstevel@tonic-gate string * 810Sstevel@tonic-gate s_new(void) 820Sstevel@tonic-gate { 830Sstevel@tonic-gate string *sp; 840Sstevel@tonic-gate 850Sstevel@tonic-gate if (freed != NULL) { 860Sstevel@tonic-gate sp = freed; 870Sstevel@tonic-gate /*LINTED*/ 880Sstevel@tonic-gate freed = (string *)(freed->ptr); 890Sstevel@tonic-gate sp->ptr = sp->base; 900Sstevel@tonic-gate return (sp); 910Sstevel@tonic-gate } 920Sstevel@tonic-gate sp = s_alloc(); 930Sstevel@tonic-gate sp->base = sp->ptr = malloc(STRLEN); 940Sstevel@tonic-gate if (sp->base == NULL) { 950Sstevel@tonic-gate perror("allocating string"); 960Sstevel@tonic-gate exit(1); 970Sstevel@tonic-gate } 980Sstevel@tonic-gate sp->end = sp->base + STRLEN; 990Sstevel@tonic-gate s_terminate(sp); 1000Sstevel@tonic-gate return (sp); 1010Sstevel@tonic-gate } 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate /* grow a string's allocation by at least `incr' bytes */ 1040Sstevel@tonic-gate static void 1050Sstevel@tonic-gate s_simplegrow(string *sp, size_t incr) 1060Sstevel@tonic-gate { 1070Sstevel@tonic-gate char *cp; 1080Sstevel@tonic-gate size_t size; 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate /* 1110Sstevel@tonic-gate * take a larger increment to avoid mallocing too often 1120Sstevel@tonic-gate */ 1130Sstevel@tonic-gate if (((sp->end - sp->base) < incr) && (MAXINCR < incr)) 1140Sstevel@tonic-gate size = (sp->end - sp->base) + incr; 1150Sstevel@tonic-gate else if ((sp->end - sp->base) > MAXINCR) 1160Sstevel@tonic-gate size = (sp->end - sp->base) + MAXINCR; 1170Sstevel@tonic-gate else 1180Sstevel@tonic-gate size = (size_t)2 * (sp->end - sp->base); 1190Sstevel@tonic-gate 1200Sstevel@tonic-gate cp = realloc(sp->base, size); 1210Sstevel@tonic-gate if (cp == NULL) { 1220Sstevel@tonic-gate perror("string:"); 1230Sstevel@tonic-gate exit(1); 1240Sstevel@tonic-gate } 1250Sstevel@tonic-gate sp->ptr = (sp->ptr - sp->base) + cp; 1260Sstevel@tonic-gate sp->end = cp + size; 1270Sstevel@tonic-gate sp->base = cp; 1280Sstevel@tonic-gate } 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate /* grow a string's allocation */ 1310Sstevel@tonic-gate int 1320Sstevel@tonic-gate s_grow(string *sp, int c) 1330Sstevel@tonic-gate { 1340Sstevel@tonic-gate s_simplegrow(sp, (size_t)2); 1350Sstevel@tonic-gate s_putc(sp, c); 1360Sstevel@tonic-gate return (c); 1370Sstevel@tonic-gate } 1380Sstevel@tonic-gate 1390Sstevel@tonic-gate /* return a string containing a character array (this had better not grow) */ 1400Sstevel@tonic-gate string * 1410Sstevel@tonic-gate s_array(char *cp, size_t len) 1420Sstevel@tonic-gate { 1430Sstevel@tonic-gate string *sp = s_alloc(); 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate sp->base = sp->ptr = cp; 1460Sstevel@tonic-gate sp->end = sp->base + len; 1470Sstevel@tonic-gate return (sp); 1480Sstevel@tonic-gate } 1490Sstevel@tonic-gate 1500Sstevel@tonic-gate /* return a string containing a copy of the passed char array */ 1510Sstevel@tonic-gate string* 1520Sstevel@tonic-gate s_copy(char *cp) 1530Sstevel@tonic-gate { 1540Sstevel@tonic-gate string *sp; 1550Sstevel@tonic-gate size_t len; 1560Sstevel@tonic-gate 1570Sstevel@tonic-gate sp = s_alloc(); 1580Sstevel@tonic-gate len = strlen(cp)+1; 1590Sstevel@tonic-gate sp->base = malloc(len); 1600Sstevel@tonic-gate if (sp->base == NULL) { 1610Sstevel@tonic-gate perror("string:"); 1620Sstevel@tonic-gate exit(1); 1630Sstevel@tonic-gate } 1640Sstevel@tonic-gate sp->end = sp->base + len; /* point past end of allocation */ 1650Sstevel@tonic-gate (void) strcpy(sp->base, cp); 1660Sstevel@tonic-gate sp->ptr = sp->end - (size_t)1; /* point to NULL terminator */ 1670Sstevel@tonic-gate return (sp); 1680Sstevel@tonic-gate } 1690Sstevel@tonic-gate 1700Sstevel@tonic-gate /* convert string to lower case */ 1710Sstevel@tonic-gate void 1720Sstevel@tonic-gate s_tolower(string *sp) 1730Sstevel@tonic-gate { 1740Sstevel@tonic-gate char *cp; 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate for (cp = sp->ptr; *cp; cp++) 1770Sstevel@tonic-gate *cp = tolower(*cp); 1780Sstevel@tonic-gate } 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate void 1810Sstevel@tonic-gate s_skipwhite(string *sp) 1820Sstevel@tonic-gate { 1830Sstevel@tonic-gate while (isspace(*sp->ptr)) 1840Sstevel@tonic-gate s_skipc(sp); 1850Sstevel@tonic-gate } 1860Sstevel@tonic-gate 1870Sstevel@tonic-gate /* append a char array to a string */ 1880Sstevel@tonic-gate string * 1890Sstevel@tonic-gate s_append(string *to, char *from) 1900Sstevel@tonic-gate { 1910Sstevel@tonic-gate if (to == NULL) 1920Sstevel@tonic-gate to = s_new(); 1930Sstevel@tonic-gate if (from == NULL) 1940Sstevel@tonic-gate return (to); 1950Sstevel@tonic-gate for (; *from; from++) 1960Sstevel@tonic-gate s_putc(to, (int)(unsigned int)*from); 1970Sstevel@tonic-gate s_terminate(to); 1980Sstevel@tonic-gate return (to); 1990Sstevel@tonic-gate } 2000Sstevel@tonic-gate 2010Sstevel@tonic-gate /* 2020Sstevel@tonic-gate * Append a logical input sequence into a string. Ignore blank and 2030Sstevel@tonic-gate * comment lines. Backslash preceding newline indicates continuation. 2040Sstevel@tonic-gate * The `lineortoken' variable indicates whether the sequence to beinput 2050Sstevel@tonic-gate * is a whitespace delimited token or a whole line. 2060Sstevel@tonic-gate * 2070Sstevel@tonic-gate * FILE *fp; stream to read from 2080Sstevel@tonic-gate * string *to; where to put token 2090Sstevel@tonic-gate * int lineortoken; how the sequence terminates 2100Sstevel@tonic-gate * 2110Sstevel@tonic-gate * Returns a pointer to the string or NULL. Trailing newline is stripped off. 2120Sstevel@tonic-gate */ 2130Sstevel@tonic-gate string * 2140Sstevel@tonic-gate s_seq_read(FILE *fp, string *to, int lineortoken) 2150Sstevel@tonic-gate { 2160Sstevel@tonic-gate int c; 2170Sstevel@tonic-gate int done = 0; 2180Sstevel@tonic-gate 2190Sstevel@tonic-gate if (feof(fp)) 2200Sstevel@tonic-gate return (NULL); 2210Sstevel@tonic-gate 2220Sstevel@tonic-gate /* get rid of leading goo */ 2230Sstevel@tonic-gate do { 2240Sstevel@tonic-gate c = getc(fp); 2250Sstevel@tonic-gate switch (c) { 2260Sstevel@tonic-gate case EOF: 2270Sstevel@tonic-gate if (to != NULL) 2280Sstevel@tonic-gate s_terminate(to); 2290Sstevel@tonic-gate return (NULL); 2300Sstevel@tonic-gate case '#': 2310Sstevel@tonic-gate /*LINTED*/ 232*6812Sraf while ((c = getc(fp)) != '\n' && c != EOF) 233*6812Sraf continue; 2340Sstevel@tonic-gate break; 2350Sstevel@tonic-gate case ' ': 2360Sstevel@tonic-gate case '\t': 2370Sstevel@tonic-gate case '\n': 2380Sstevel@tonic-gate case '\r': 2390Sstevel@tonic-gate case '\f': 2400Sstevel@tonic-gate break; 2410Sstevel@tonic-gate default: 2420Sstevel@tonic-gate done = 1; 2430Sstevel@tonic-gate break; 2440Sstevel@tonic-gate } 2450Sstevel@tonic-gate } while (!done); 2460Sstevel@tonic-gate 2470Sstevel@tonic-gate if (to == NULL) 2480Sstevel@tonic-gate to = s_new(); 2490Sstevel@tonic-gate 2500Sstevel@tonic-gate /* gather up a sequence */ 2510Sstevel@tonic-gate for (;;) { 2520Sstevel@tonic-gate switch (c) { 2530Sstevel@tonic-gate case '\\': 2540Sstevel@tonic-gate c = getc(fp); 2550Sstevel@tonic-gate if (c != '\n') { 2560Sstevel@tonic-gate s_putc(to, (int)(unsigned int)'\\'); 2570Sstevel@tonic-gate s_putc(to, c); 2580Sstevel@tonic-gate } 2590Sstevel@tonic-gate break; 2600Sstevel@tonic-gate case EOF: 2610Sstevel@tonic-gate case '\r': 2620Sstevel@tonic-gate case '\f': 2630Sstevel@tonic-gate case '\n': 2640Sstevel@tonic-gate s_terminate(to); 2650Sstevel@tonic-gate return (to); 2660Sstevel@tonic-gate case ' ': 2670Sstevel@tonic-gate case '\t': 2680Sstevel@tonic-gate if (lineortoken == TOKEN) { 2690Sstevel@tonic-gate s_terminate(to); 2700Sstevel@tonic-gate return (to); 2710Sstevel@tonic-gate } 2720Sstevel@tonic-gate /* fall through */ 2730Sstevel@tonic-gate default: 2740Sstevel@tonic-gate s_putc(to, c); 2750Sstevel@tonic-gate break; 2760Sstevel@tonic-gate } 2770Sstevel@tonic-gate c = getc(fp); 2780Sstevel@tonic-gate } 2790Sstevel@tonic-gate } 2800Sstevel@tonic-gate 2810Sstevel@tonic-gate string * 2820Sstevel@tonic-gate s_tok(string *from, char *split) 2830Sstevel@tonic-gate { 2840Sstevel@tonic-gate char *splitend = strpbrk(from->ptr, split); 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate if (splitend) { 2870Sstevel@tonic-gate string *to = s_new(); 2880Sstevel@tonic-gate for (; from->ptr < splitend; ) { 2890Sstevel@tonic-gate s_putc(to, (int)(unsigned int)*from->ptr); 2900Sstevel@tonic-gate from->ptr++; 2910Sstevel@tonic-gate } 2920Sstevel@tonic-gate s_terminate(to); 2930Sstevel@tonic-gate s_restart(to); 2940Sstevel@tonic-gate /* LINT: warning due to lint bug */ 2950Sstevel@tonic-gate from->ptr += strspn(from->ptr, split); 2960Sstevel@tonic-gate return (to); 2970Sstevel@tonic-gate } 2980Sstevel@tonic-gate 2990Sstevel@tonic-gate else if (from->ptr[0]) { 3000Sstevel@tonic-gate string *to = s_clone(from); 3010Sstevel@tonic-gate while (*from->ptr) 3020Sstevel@tonic-gate from->ptr++; 3030Sstevel@tonic-gate return (to); 3040Sstevel@tonic-gate } 3050Sstevel@tonic-gate 3060Sstevel@tonic-gate else 3070Sstevel@tonic-gate return (NULL); 3080Sstevel@tonic-gate } 3090Sstevel@tonic-gate 3100Sstevel@tonic-gate /* 3110Sstevel@tonic-gate * Append an input line to a string. 3120Sstevel@tonic-gate * 3130Sstevel@tonic-gate * Returns a pointer to the string (or NULL). 3140Sstevel@tonic-gate * Trailing newline is left on. 3150Sstevel@tonic-gate */ 3160Sstevel@tonic-gate char * 3170Sstevel@tonic-gate s_read_line(FILE *fp, string *to) 3180Sstevel@tonic-gate { 3190Sstevel@tonic-gate int c; 3200Sstevel@tonic-gate size_t len = 0; 3210Sstevel@tonic-gate 3220Sstevel@tonic-gate s_terminate(to); 3230Sstevel@tonic-gate 3240Sstevel@tonic-gate /* end of input */ 3250Sstevel@tonic-gate if (feof(fp) || (c = getc(fp)) == EOF) 3260Sstevel@tonic-gate return (NULL); 3270Sstevel@tonic-gate 3280Sstevel@tonic-gate /* gather up a line */ 3290Sstevel@tonic-gate for (; ; ) { 3300Sstevel@tonic-gate len++; 3310Sstevel@tonic-gate switch (c) { 3320Sstevel@tonic-gate case EOF: 3330Sstevel@tonic-gate s_terminate(to); 3340Sstevel@tonic-gate return (to->ptr - len); 3350Sstevel@tonic-gate case '\n': 3360Sstevel@tonic-gate s_putc(to, (int)(unsigned int)'\n'); 3370Sstevel@tonic-gate s_terminate(to); 3380Sstevel@tonic-gate return (to->ptr - len); 3390Sstevel@tonic-gate default: 3400Sstevel@tonic-gate s_putc(to, c); 3410Sstevel@tonic-gate break; 3420Sstevel@tonic-gate } 3430Sstevel@tonic-gate c = getc(fp); 3440Sstevel@tonic-gate } 3450Sstevel@tonic-gate } 3460Sstevel@tonic-gate 3470Sstevel@tonic-gate /* 3480Sstevel@tonic-gate * Read till eof 3490Sstevel@tonic-gate */ 3500Sstevel@tonic-gate size_t 3510Sstevel@tonic-gate s_read_to_eof(FILE *fp, string *to) 3520Sstevel@tonic-gate { 3530Sstevel@tonic-gate size_t got; 3540Sstevel@tonic-gate size_t have; 3550Sstevel@tonic-gate 3560Sstevel@tonic-gate s_terminate(to); 3570Sstevel@tonic-gate 3580Sstevel@tonic-gate for (; ; ) { 3590Sstevel@tonic-gate if (feof(fp)) 3600Sstevel@tonic-gate break; 3610Sstevel@tonic-gate /* allocate room for a full buffer */ 3620Sstevel@tonic-gate have = to->end - to->ptr; 3630Sstevel@tonic-gate if (have < 4096UL) 3640Sstevel@tonic-gate s_simplegrow(to, (size_t)4096); 3650Sstevel@tonic-gate 3660Sstevel@tonic-gate /* get a buffers worth */ 3670Sstevel@tonic-gate have = to->end - to->ptr; 3680Sstevel@tonic-gate got = fread(to->ptr, (size_t)1, have, fp); 3690Sstevel@tonic-gate if (got == (size_t)0) 3700Sstevel@tonic-gate break; 3710Sstevel@tonic-gate /* LINT: warning due to lint bug */ 3720Sstevel@tonic-gate to->ptr += got; 3730Sstevel@tonic-gate } 3740Sstevel@tonic-gate 3750Sstevel@tonic-gate /* null terminate the line */ 3760Sstevel@tonic-gate s_terminate(to); 3770Sstevel@tonic-gate return (to->ptr - to->base); 3780Sstevel@tonic-gate } 3790Sstevel@tonic-gate 3800Sstevel@tonic-gate /* 3810Sstevel@tonic-gate * Get the next field from a string. The field is delimited by white space, 3820Sstevel@tonic-gate * single or double quotes. 3830Sstevel@tonic-gate * 3840Sstevel@tonic-gate * string *from; string to parse 3850Sstevel@tonic-gate * string *to; where to put parsed token 3860Sstevel@tonic-gate */ 3870Sstevel@tonic-gate string * 3880Sstevel@tonic-gate s_parse(string *from, string *to) 3890Sstevel@tonic-gate { 3900Sstevel@tonic-gate while (isspace(*from->ptr)) 3910Sstevel@tonic-gate from->ptr++; 3920Sstevel@tonic-gate if (*from->ptr == '\0') 3930Sstevel@tonic-gate return (NULL); 3940Sstevel@tonic-gate if (to == NULL) 3950Sstevel@tonic-gate to = s_new(); 3960Sstevel@tonic-gate if (*from->ptr == '\'') { 3970Sstevel@tonic-gate from->ptr++; 3980Sstevel@tonic-gate for (; *from->ptr != '\'' && *from->ptr != '\0'; from->ptr++) 3990Sstevel@tonic-gate s_putc(to, (int)(unsigned int)*from->ptr); 4000Sstevel@tonic-gate if (*from->ptr == '\'') 4010Sstevel@tonic-gate from->ptr++; 4020Sstevel@tonic-gate } else if (*from->ptr == '"') { 4030Sstevel@tonic-gate from->ptr++; 4040Sstevel@tonic-gate for (; *from->ptr != '"' && *from->ptr != '\0'; from->ptr++) 4050Sstevel@tonic-gate s_putc(to, (int)(unsigned int)*from->ptr); 4060Sstevel@tonic-gate if (*from->ptr == '"') 4070Sstevel@tonic-gate from->ptr++; 4080Sstevel@tonic-gate } else { 4090Sstevel@tonic-gate for (; !isspace(*from->ptr) && *from->ptr != '\0'; from->ptr++) 4100Sstevel@tonic-gate s_putc(to, (int)(unsigned int)*from->ptr); 4110Sstevel@tonic-gate } 4120Sstevel@tonic-gate s_terminate(to); 4130Sstevel@tonic-gate 4140Sstevel@tonic-gate return (to); 4150Sstevel@tonic-gate } 416