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