/* * 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 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* Copyright (c) 1987, 1988 Microsoft Corporation */ /* All Rights Reserved */ #include "lint.h" #include "libc.h" #include #include #include #include #include #include #include #include "tsd.h" #define TSTBITS(flags, mask) (((flags) & (mask)) == (mask)) struct thr_data { int Dcflags; /* [re-]initialized on each call to defopen() */ FILE *fp; char *buf; }; static int defopen_common(const char *, struct thr_data *); static void strip_quotes(char *); #define BUFFERSIZE 1024 /* * destructor for per-thread data, registered with tsdalloc() */ static void free_thr_data(void *arg) { struct thr_data *thr_data = (struct thr_data *)arg; if (thr_data->fp) { (void) fclose(thr_data->fp); thr_data->fp = NULL; } if (thr_data->buf) { lfree(thr_data->buf, BUFFERSIZE); thr_data->buf = NULL; } } /* * get the per-thread-data-item for the calling thread */ static struct thr_data * get_thr_data(void) { struct thr_data *thr_data = tsdalloc(_T_DEFREAD, sizeof (*thr_data), free_thr_data); return (thr_data); } /* * defopen() - declare defopen filename * * defopen(fn) * char *fn * * If 'fn' is non-null; it is a full pathname of a file * which becomes the one read by subsequent defread() calls. * If 'fn' is null the defopen file is closed. * * see defread() for more details. * * EXIT returns 0 if ok * returns -1 if error */ int defopen(char *fn) { struct thr_data *thr_data = get_thr_data(); return (defopen_common(fn, thr_data)); } /* * defopen_r() - declare defopen filename (reentrant) * * defopen_r(const char *fn) * * 'fn' is a full pathname of a file which becomes the one read * by subsequent defread_r() calls. defopen_r returns a pointer * to the internally allocated buffer containing the file descriptor. * The pointer should be specified to the following defread_r and * defcntl_r functions. As the pointer to be returned points to * the libc lmalloc'd memory, defclose_r must be used to close * the defopen file and to release the allocated memory. Caller * must not try to release the memory by free(). * * see defread_r() for more details. * * EXIT returns non-NULL pointer if success * returns NULL if error */ void * defopen_r(const char *fn) { /* memory allocated by lmalloc gets initialized to zeros */ struct thr_data *thr_data = lmalloc(sizeof (struct thr_data)); if (defopen_common(fn, thr_data) < 0) { if (thr_data != NULL) lfree(thr_data, sizeof (struct thr_data)); return (NULL); } return ((void *)thr_data); } static int defopen_common(const char *fn, struct thr_data *thr_data) { if (thr_data == NULL) return (-1); if (thr_data->fp != NULL) { (void) fclose(thr_data->fp); thr_data->fp = NULL; } if (fn == NULL) return (0); if ((thr_data->fp = fopen(fn, "rF")) == NULL) return (-1); /* * We allocate the big buffer only if the fopen() succeeds. * Notice that we deallocate the buffer only when the thread exits * for defopen(). * There are misguided applications that assume that data returned * by defread() continues to exist after defopen(NULL) is called. */ if (thr_data->buf == NULL && (thr_data->buf = lmalloc(BUFFERSIZE)) == NULL) { (void) fclose(thr_data->fp); thr_data->fp = NULL; return (-1); } thr_data->Dcflags = DC_STD; return (0); } /* * defread() - read an entry from the defopen file * * defread(cp) * char *cp * * The defopen data file must have been previously opened by * defopen(). defread scans the data file looking for a line * which begins with the string '*cp'. If such a line is found, * defread returns a pointer to the first character following * the matched string (*cp). If no line is found or no file * is open, defread() returns NULL. * * Note that there is no way to simultaneously peruse multiple * defopen files; since there is no way of indicating 'which one' * to defread(). If you want to peruse a secondary file you must * recall defopen(). If you need to go back to the first file, * you must call defopen() again. */ char * defread(char *cp) { struct thr_data *thr_data = get_thr_data(); return (defread_r(cp, thr_data)); } /* * defread_r() - read an entry from the defopen file * * defread_r(const char *cp, void *defp) * * defread_r scans the data file associated with the pointer * specified by 'defp' that was returned by defopen_r(), and * looks for a line which begins with the string '*cp'. * If such a line is found, defread_r returns a pointer to * the first character following the matched string (*cp). * If no line is found or no file is open, defread_r() returns NULL. */ char * defread_r(const char *cp, void *ptr) { struct thr_data *thr_data = (struct thr_data *)ptr; int (*compare)(const char *, const char *, size_t); char *buf_tmp; char *ret_ptr = NULL; size_t off, patlen; if (thr_data == NULL || thr_data->fp == NULL) return (NULL); compare = TSTBITS(thr_data->Dcflags, DC_CASE) ? strncmp : strncasecmp; patlen = strlen(cp); if (!TSTBITS(thr_data->Dcflags, DC_NOREWIND)) rewind(thr_data->fp); while (fgets(thr_data->buf, BUFFERSIZE, thr_data->fp)) { for (buf_tmp = thr_data->buf; *buf_tmp == ' '; buf_tmp++) ; off = strlen(buf_tmp) - 1; if (buf_tmp[off] == '\n') buf_tmp[off] = 0; else break; /* line too long */ if ((*compare)(cp, buf_tmp, patlen) == 0) { /* found it */ /* strip quotes if requested */ if (TSTBITS(thr_data->Dcflags, DC_STRIP_QUOTES)) { strip_quotes(buf_tmp); } ret_ptr = &buf_tmp[patlen]; break; } } return (ret_ptr); } /* * defcntl -- default control * * SYNOPSIS * oldflags = defcntl(cmd, arg); * * ENTRY * cmd Command. One of DC_GET, DC_SET. * arg Depends on command. If DC_GET, ignored. * If DC_SET, new flags value, created by ORing * the DC_* bits. * RETURN * oldflags Old value of flags. -1 on error. * NOTES * The following commands are implemented: * * DC_CASE: respect(on)/ignore(off) case * DC_NOREWIND: don't(on)/do(off) reqind in defread * DC_STRIP_QUOTES: strip(on)/leave(off) qoates */ int defcntl(int cmd, int newflags) { struct thr_data *thr_data = get_thr_data(); return (defcntl_r(cmd, newflags, thr_data)); } /* * defcntl_r -- default control * * SYNOPSIS * oldflags = defcntl_r(int cmd, int arg, void *defp); * * ENTRY * cmd Command. One of DC_GET, DC_SET. * arg Depends on command. If DC_GET, ignored. * If DC_SET, new flags value, created by ORing * the DC_* bits. * defp pointer to the defopen'd descriptor * * RETURN * oldflags Old value of flags. -1 on error. * NOTES * The following commands are implemented: * * DC_CASE: respect(on)/ignore(off) case * DC_NOREWIND: don't(on)/do(off) reqind in defread * DC_STRIP_QUOTES: strip(on)/leave(off) qoates */ int defcntl_r(int cmd, int newflags, void *ptr) { struct thr_data *thr_data = (struct thr_data *)ptr; int oldflags; if (thr_data == NULL) return (-1); switch (cmd) { case DC_GETFLAGS: /* query */ oldflags = thr_data->Dcflags; break; case DC_SETFLAGS: /* set */ oldflags = thr_data->Dcflags; thr_data->Dcflags = newflags; break; default: /* error */ oldflags = -1; break; } return (oldflags); } /* * defclose_r() - close defopen file * * defclose_r(void *defp) * * defclose_r closes the defopen file associated with the specified * pointer and releases the allocated resources. */ void defclose_r(void *ptr) { struct thr_data *thr_data = (struct thr_data *)ptr; (void) fclose(thr_data->fp); lfree(thr_data->buf, BUFFERSIZE); lfree(thr_data, sizeof (struct thr_data)); } /* * strip_quotes -- strip double (") or single (') quotes from a buffer * * ENTRY * ptr initial string * * EXIT * ptr string with quotes (if any) removed */ static void strip_quotes(char *ptr) { char *strip_ptr = NULL; while (*ptr != '\0') { if ((*ptr == '"') || (*ptr == '\'')) { if (strip_ptr == NULL) strip_ptr = ptr; /* skip over quote */ } else { if (strip_ptr != NULL) { *strip_ptr = *ptr; strip_ptr++; } } ptr++; } if (strip_ptr != NULL) { *strip_ptr = '\0'; } }