/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ #include #include #include #include "s_string.h" #include /* global to this file */ #define STRLEN 128UL #define STRALLOC 128UL #define MAXINCR 250000UL /* buffer pool for allocating string structures */ typedef struct { string s[STRALLOC]; size_t o; } stralloc; static stralloc *freep = NULL; /* pool of freed strings */ static string *freed = NULL; static string *s_alloc(void); static void s_simplegrow(string *, size_t); void s_free(string *sp) { if (sp != NULL) { sp->ptr = (char *)freed; freed = sp; } } /* allocate a string head */ static string * s_alloc(void) { if (freep == NULL || freep->o >= STRALLOC) { freep = (stralloc *)malloc(sizeof (stralloc)); if (freep == NULL) { perror("allocating string"); exit(1); } freep->o = (size_t)0; } return (&(freep->s[freep->o++])); } /* create a new `short' string */ string * s_new(void) { string *sp; if (freed != NULL) { sp = freed; /*LINTED*/ freed = (string *)(freed->ptr); sp->ptr = sp->base; return (sp); } sp = s_alloc(); sp->base = sp->ptr = malloc(STRLEN); if (sp->base == NULL) { perror("allocating string"); exit(1); } sp->end = sp->base + STRLEN; s_terminate(sp); return (sp); } /* grow a string's allocation by at least `incr' bytes */ static void s_simplegrow(string *sp, size_t incr) { char *cp; size_t size; /* * take a larger increment to avoid mallocing too often */ if (((sp->end - sp->base) < incr) && (MAXINCR < incr)) size = (sp->end - sp->base) + incr; else if ((sp->end - sp->base) > MAXINCR) size = (sp->end - sp->base) + MAXINCR; else size = (size_t)2 * (sp->end - sp->base); cp = realloc(sp->base, size); if (cp == NULL) { perror("string:"); exit(1); } sp->ptr = (sp->ptr - sp->base) + cp; sp->end = cp + size; sp->base = cp; } /* grow a string's allocation */ int s_grow(string *sp, int c) { s_simplegrow(sp, (size_t)2); s_putc(sp, c); return (c); } /* return a string containing a character array (this had better not grow) */ string * s_array(char *cp, size_t len) { string *sp = s_alloc(); sp->base = sp->ptr = cp; sp->end = sp->base + len; return (sp); } /* return a string containing a copy of the passed char array */ string* s_copy(char *cp) { string *sp; size_t len; sp = s_alloc(); len = strlen(cp)+1; sp->base = malloc(len); if (sp->base == NULL) { perror("string:"); exit(1); } sp->end = sp->base + len; /* point past end of allocation */ (void) strcpy(sp->base, cp); sp->ptr = sp->end - (size_t)1; /* point to NULL terminator */ return (sp); } /* convert string to lower case */ void s_tolower(string *sp) { char *cp; for (cp = sp->ptr; *cp; cp++) *cp = tolower(*cp); } void s_skipwhite(string *sp) { while (isspace(*sp->ptr)) s_skipc(sp); } /* append a char array to a string */ string * s_append(string *to, char *from) { if (to == NULL) to = s_new(); if (from == NULL) return (to); for (; *from; from++) s_putc(to, (int)(unsigned int)*from); s_terminate(to); return (to); } /* * Append a logical input sequence into a string. Ignore blank and * comment lines. Backslash preceding newline indicates continuation. * The `lineortoken' variable indicates whether the sequence to beinput * is a whitespace delimited token or a whole line. * * FILE *fp; stream to read from * string *to; where to put token * int lineortoken; how the sequence terminates * * Returns a pointer to the string or NULL. Trailing newline is stripped off. */ string * s_seq_read(FILE *fp, string *to, int lineortoken) { int c; int done = 0; if (feof(fp)) return (NULL); /* get rid of leading goo */ do { c = getc(fp); switch (c) { case EOF: if (to != NULL) s_terminate(to); return (NULL); case '#': /*LINTED*/ while ((c = getc(fp)) != '\n' && c != EOF) continue; break; case ' ': case '\t': case '\n': case '\r': case '\f': break; default: done = 1; break; } } while (!done); if (to == NULL) to = s_new(); /* gather up a sequence */ for (;;) { switch (c) { case '\\': c = getc(fp); if (c != '\n') { s_putc(to, (int)(unsigned int)'\\'); s_putc(to, c); } break; case EOF: case '\r': case '\f': case '\n': s_terminate(to); return (to); case ' ': case '\t': if (lineortoken == TOKEN) { s_terminate(to); return (to); } /* fall through */ default: s_putc(to, c); break; } c = getc(fp); } } string * s_tok(string *from, char *split) { char *splitend = strpbrk(from->ptr, split); if (splitend) { string *to = s_new(); for (; from->ptr < splitend; ) { s_putc(to, (int)(unsigned int)*from->ptr); from->ptr++; } s_terminate(to); s_restart(to); /* LINT: warning due to lint bug */ from->ptr += strspn(from->ptr, split); return (to); } else if (from->ptr[0]) { string *to = s_clone(from); while (*from->ptr) from->ptr++; return (to); } else return (NULL); } /* * Append an input line to a string. * * Returns a pointer to the string (or NULL). * Trailing newline is left on. */ char * s_read_line(FILE *fp, string *to) { int c; size_t len = 0; s_terminate(to); /* end of input */ if (feof(fp) || (c = getc(fp)) == EOF) return (NULL); /* gather up a line */ for (; ; ) { len++; switch (c) { case EOF: s_terminate(to); return (to->ptr - len); case '\n': s_putc(to, (int)(unsigned int)'\n'); s_terminate(to); return (to->ptr - len); default: s_putc(to, c); break; } c = getc(fp); } } /* * Read till eof */ size_t s_read_to_eof(FILE *fp, string *to) { size_t got; size_t have; s_terminate(to); for (; ; ) { if (feof(fp)) break; /* allocate room for a full buffer */ have = to->end - to->ptr; if (have < 4096UL) s_simplegrow(to, (size_t)4096); /* get a buffers worth */ have = to->end - to->ptr; got = fread(to->ptr, (size_t)1, have, fp); if (got == (size_t)0) break; /* LINT: warning due to lint bug */ to->ptr += got; } /* null terminate the line */ s_terminate(to); return (to->ptr - to->base); } /* * Get the next field from a string. The field is delimited by white space, * single or double quotes. * * string *from; string to parse * string *to; where to put parsed token */ string * s_parse(string *from, string *to) { while (isspace(*from->ptr)) from->ptr++; if (*from->ptr == '\0') return (NULL); if (to == NULL) to = s_new(); if (*from->ptr == '\'') { from->ptr++; for (; *from->ptr != '\'' && *from->ptr != '\0'; from->ptr++) s_putc(to, (int)(unsigned int)*from->ptr); if (*from->ptr == '\'') from->ptr++; } else if (*from->ptr == '"') { from->ptr++; for (; *from->ptr != '"' && *from->ptr != '\0'; from->ptr++) s_putc(to, (int)(unsigned int)*from->ptr); if (*from->ptr == '"') from->ptr++; } else { for (; !isspace(*from->ptr) && *from->ptr != '\0'; from->ptr++) s_putc(to, (int)(unsigned int)*from->ptr); } s_terminate(to); return (to); }