2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
2N/A/* All Rights Reserved */
2N/A
2N/A/* Copyright (c) 1987, 1988 Microsoft Corporation */
2N/A/* All Rights Reserved */
2N/A
2N/A#include "lint.h"
2N/A#include "libc.h"
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <deflt.h>
2N/A#include <sys/types.h>
2N/A#include <string.h>
2N/A#include <ctype.h>
2N/A#include <unistd.h>
2N/A#include "tsd.h"
2N/A
2N/A#define TSTBITS(flags, mask) (((flags) & (mask)) == (mask))
2N/A
2N/Astruct thr_data {
2N/A int Dcflags; /* [re-]initialized on each call to defopen() */
2N/A FILE *fp;
2N/A char *buf;
2N/A};
2N/A
2N/Astatic int defopen_common(const char *, struct thr_data *);
2N/Astatic void strip_quotes(char *);
2N/A
2N/A#define BUFFERSIZE 1024
2N/A
2N/A/*
2N/A * destructor for per-thread data, registered with tsdalloc()
2N/A */
2N/Astatic void
2N/Afree_thr_data(void *arg)
2N/A{
2N/A struct thr_data *thr_data = (struct thr_data *)arg;
2N/A
2N/A if (thr_data->fp) {
2N/A (void) fclose(thr_data->fp);
2N/A thr_data->fp = NULL;
2N/A }
2N/A if (thr_data->buf) {
2N/A lfree(thr_data->buf, BUFFERSIZE);
2N/A thr_data->buf = NULL;
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * get the per-thread-data-item for the calling thread
2N/A */
2N/Astatic struct thr_data *
2N/Aget_thr_data(void)
2N/A{
2N/A struct thr_data *thr_data =
2N/A tsdalloc(_T_DEFREAD, sizeof (*thr_data), free_thr_data);
2N/A
2N/A return (thr_data);
2N/A}
2N/A
2N/A/*
2N/A * defopen() - declare defopen filename
2N/A *
2N/A * defopen(fn)
2N/A * char *fn
2N/A *
2N/A * If 'fn' is non-null; it is a full pathname of a file
2N/A * which becomes the one read by subsequent defread() calls.
2N/A * If 'fn' is null the defopen file is closed.
2N/A *
2N/A * see defread() for more details.
2N/A *
2N/A * EXIT returns 0 if ok
2N/A * returns -1 if error
2N/A */
2N/Aint
2N/Adefopen(char *fn)
2N/A{
2N/A struct thr_data *thr_data = get_thr_data();
2N/A
2N/A return (defopen_common(fn, thr_data));
2N/A}
2N/A
2N/A/*
2N/A * defopen_r() - declare defopen filename (reentrant)
2N/A *
2N/A * defopen_r(const char *fn)
2N/A *
2N/A * 'fn' is a full pathname of a file which becomes the one read
2N/A * by subsequent defread_r() calls. defopen_r returns a pointer
2N/A * to the internally allocated buffer containing the file descriptor.
2N/A * The pointer should be specified to the following defread_r and
2N/A * defcntl_r functions. As the pointer to be returned points to
2N/A * the libc lmalloc'd memory, defclose_r must be used to close
2N/A * the defopen file and to release the allocated memory. Caller
2N/A * must not try to release the memory by free().
2N/A *
2N/A * see defread_r() for more details.
2N/A *
2N/A * EXIT returns non-NULL pointer if success
2N/A * returns NULL if error
2N/A */
2N/Avoid *
2N/Adefopen_r(const char *fn)
2N/A{
2N/A /* memory allocated by lmalloc gets initialized to zeros */
2N/A struct thr_data *thr_data = lmalloc(sizeof (struct thr_data));
2N/A
2N/A if (defopen_common(fn, thr_data) < 0) {
2N/A if (thr_data != NULL)
2N/A lfree(thr_data, sizeof (struct thr_data));
2N/A return (NULL);
2N/A }
2N/A
2N/A return ((void *)thr_data);
2N/A}
2N/A
2N/Astatic int
2N/Adefopen_common(const char *fn, struct thr_data *thr_data)
2N/A{
2N/A if (thr_data == NULL)
2N/A return (-1);
2N/A
2N/A if (thr_data->fp != NULL) {
2N/A (void) fclose(thr_data->fp);
2N/A thr_data->fp = NULL;
2N/A }
2N/A
2N/A if (fn == NULL)
2N/A return (0);
2N/A
2N/A if ((thr_data->fp = fopen(fn, "rF")) == NULL)
2N/A return (-1);
2N/A
2N/A /*
2N/A * We allocate the big buffer only if the fopen() succeeds.
2N/A * Notice that we deallocate the buffer only when the thread exits
2N/A * for defopen().
2N/A * There are misguided applications that assume that data returned
2N/A * by defread() continues to exist after defopen(NULL) is called.
2N/A */
2N/A if (thr_data->buf == NULL &&
2N/A (thr_data->buf = lmalloc(BUFFERSIZE)) == NULL) {
2N/A (void) fclose(thr_data->fp);
2N/A thr_data->fp = NULL;
2N/A return (-1);
2N/A }
2N/A
2N/A thr_data->Dcflags = DC_STD;
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * defread() - read an entry from the defopen file
2N/A *
2N/A * defread(cp)
2N/A * char *cp
2N/A *
2N/A * The defopen data file must have been previously opened by
2N/A * defopen(). defread scans the data file looking for a line
2N/A * which begins with the string '*cp'. If such a line is found,
2N/A * defread returns a pointer to the first character following
2N/A * the matched string (*cp). If no line is found or no file
2N/A * is open, defread() returns NULL.
2N/A *
2N/A * Note that there is no way to simultaneously peruse multiple
2N/A * defopen files; since there is no way of indicating 'which one'
2N/A * to defread(). If you want to peruse a secondary file you must
2N/A * recall defopen(). If you need to go back to the first file,
2N/A * you must call defopen() again.
2N/A */
2N/Achar *
2N/Adefread(char *cp)
2N/A{
2N/A struct thr_data *thr_data = get_thr_data();
2N/A
2N/A return (defread_r(cp, thr_data));
2N/A}
2N/A
2N/A/*
2N/A * defread_r() - read an entry from the defopen file
2N/A *
2N/A * defread_r(const char *cp, void *ptr)
2N/A *
2N/A * defread_r scans the data file associated with the pointer
2N/A * specified by 'ptr' that was returned by defopen_r(), and
2N/A * looks for a line which begins with the string '*cp'.
2N/A * If such a line is found, defread_r returns a pointer to
2N/A * the first character following the matched string (*cp).
2N/A * If no line is found or no file is open, defread_r() returns NULL.
2N/A */
2N/Achar *
2N/Adefread_r(const char *cp, void *ptr)
2N/A{
2N/A struct thr_data *thr_data = (struct thr_data *)ptr;
2N/A int (*compare)(const char *, const char *, size_t);
2N/A char *buf_tmp;
2N/A char *ret_ptr = NULL;
2N/A size_t off, patlen;
2N/A int i;
2N/A
2N/A if (thr_data == NULL || thr_data->fp == NULL)
2N/A return (NULL);
2N/A
2N/A compare = TSTBITS(thr_data->Dcflags, DC_CASE) ? strncmp : strncasecmp;
2N/A patlen = strlen(cp);
2N/A
2N/A if (!TSTBITS(thr_data->Dcflags, DC_NOREWIND))
2N/A rewind(thr_data->fp);
2N/A
2N/A while (fgets(thr_data->buf, BUFFERSIZE, thr_data->fp)) {
2N/A for (buf_tmp = thr_data->buf; *buf_tmp == ' '; buf_tmp++)
2N/A ;
2N/A off = strlen(buf_tmp) - 1;
2N/A if (buf_tmp[off] == '\n')
2N/A buf_tmp[off] = 0;
2N/A else
2N/A break; /* line too long */
2N/A if ((*compare)(cp, buf_tmp, patlen) == 0) {
2N/A /* found it */
2N/A /* strip quotes if requested */
2N/A if (TSTBITS(thr_data->Dcflags, DC_STRIP_QUOTES)) {
2N/A strip_quotes(buf_tmp);
2N/A }
2N/A ret_ptr = &buf_tmp[patlen];
2N/A while (*ret_ptr != '\0' && isspace(*ret_ptr))
2N/A ret_ptr++;
2N/A break;
2N/A }
2N/A }
2N/A if (ret_ptr != NULL) {
2N/A for (i = strlen(ret_ptr) - 1; i >= 0; i--) {
2N/A if ((isspace(ret_ptr[i])) == 0) {
2N/A break;
2N/A }
2N/A }
2N/A ret_ptr[i+1] = '\0';
2N/A }
2N/A
2N/A return (ret_ptr);
2N/A}
2N/A
2N/A/*
2N/A * defcntl -- default control
2N/A *
2N/A * SYNOPSIS
2N/A * oldflags = defcntl(cmd, arg);
2N/A *
2N/A * ENTRY
2N/A * cmd Command. One of DC_GET, DC_SET.
2N/A * arg Depends on command. If DC_GET, ignored.
2N/A * If DC_SET, new flags value, created by ORing
2N/A * the DC_* bits.
2N/A * RETURN
2N/A * oldflags Old value of flags. -1 on error.
2N/A * NOTES
2N/A * The following commands are implemented:
2N/A *
2N/A * DC_CASE: respect(on)/ignore(off) case
2N/A * DC_NOREWIND: don't(on)/do(off) reqind in defread
2N/A * DC_STRIP_QUOTES: strip(on)/leave(off) qoates
2N/A */
2N/Aint
2N/Adefcntl(int cmd, int newflags)
2N/A{
2N/A struct thr_data *thr_data = get_thr_data();
2N/A
2N/A return (defcntl_r(cmd, newflags, thr_data));
2N/A}
2N/A
2N/A/*
2N/A * defcntl_r -- default control
2N/A *
2N/A * SYNOPSIS
2N/A * oldflags = defcntl_r(int cmd, int arg, void *defp);
2N/A *
2N/A * ENTRY
2N/A * cmd Command. One of DC_GET, DC_SET.
2N/A * arg Depends on command. If DC_GET, ignored.
2N/A * If DC_SET, new flags value, created by ORing
2N/A * the DC_* bits.
2N/A * defp pointer to the defopen'd descriptor
2N/A *
2N/A * RETURN
2N/A * oldflags Old value of flags. -1 on error.
2N/A * NOTES
2N/A * The following commands are implemented:
2N/A *
2N/A * DC_CASE: respect(on)/ignore(off) case
2N/A * DC_NOREWIND: don't(on)/do(off) reqind in defread
2N/A * DC_STRIP_QUOTES: strip(on)/leave(off) qoates
2N/A */
2N/Aint
2N/Adefcntl_r(int cmd, int newflags, void *ptr)
2N/A{
2N/A struct thr_data *thr_data = (struct thr_data *)ptr;
2N/A int oldflags;
2N/A
2N/A if (thr_data == NULL)
2N/A return (-1);
2N/A
2N/A switch (cmd) {
2N/A case DC_GETFLAGS: /* query */
2N/A oldflags = thr_data->Dcflags;
2N/A break;
2N/A case DC_SETFLAGS: /* set */
2N/A oldflags = thr_data->Dcflags;
2N/A thr_data->Dcflags = newflags;
2N/A break;
2N/A default: /* error */
2N/A oldflags = -1;
2N/A break;
2N/A }
2N/A
2N/A return (oldflags);
2N/A}
2N/A
2N/A/*
2N/A * defclose_r() - close defopen file
2N/A *
2N/A * defclose_r(void *defp)
2N/A *
2N/A * defclose_r closes the defopen file associated with the specified
2N/A * pointer and releases the allocated resources.
2N/A */
2N/Avoid
2N/Adefclose_r(void *ptr)
2N/A{
2N/A struct thr_data *thr_data = (struct thr_data *)ptr;
2N/A
2N/A (void) fclose(thr_data->fp);
2N/A lfree(thr_data->buf, BUFFERSIZE);
2N/A lfree(thr_data, sizeof (struct thr_data));
2N/A}
2N/A
2N/A/*
2N/A * strip_quotes -- strip double (") or single (') quotes from a buffer
2N/A *
2N/A * ENTRY
2N/A * ptr initial string
2N/A *
2N/A * EXIT
2N/A * ptr string with quotes (if any) removed
2N/A */
2N/Astatic void
2N/Astrip_quotes(char *ptr)
2N/A{
2N/A char *strip_ptr = NULL;
2N/A
2N/A while (*ptr != '\0') {
2N/A if ((*ptr == '"') || (*ptr == '\'')) {
2N/A if (strip_ptr == NULL)
2N/A strip_ptr = ptr; /* skip over quote */
2N/A } else {
2N/A if (strip_ptr != NULL) {
2N/A *strip_ptr = *ptr;
2N/A strip_ptr++;
2N/A }
2N/A }
2N/A ptr++;
2N/A }
2N/A if (strip_ptr != NULL) {
2N/A *strip_ptr = '\0';
2N/A }
2N/A}