deflt.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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 2004 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 */
#pragma ident "%Z%%M% %I% %E% SMI"
/* LINTLIBRARY */
#include <stdio.h>
#include <stdlib.h>
#include <deflt.h>
#include <sys/types.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include "mtlib.h"
#include <thread.h>
#include <synch.h>
#include <libintl.h>
#include <unistd.h>
#pragma init(deflt_init)
#define TSTBITS(flags, mask) (((flags) & (mask)) == (mask))
static void strip_quotes(char *);
static thread_key_t thr_key;
struct thr_data {
int Dcflags; /* [re-]initialized on each call to defopen() */
FILE *fp;
char buf[PATH_MAX];
};
/*
* destructor for per-thread data, registered with thr_keycreate()
*/
static void
free_thr_data(void *arg)
{
struct thr_data *thr_data = (struct thr_data *)arg;
if (thr_data->fp)
fclose(thr_data->fp);
free(thr_data);
}
/*
* _init routine for this library. Set up per-thread-data-key
*/
static void
deflt_init(void)
{
(void) thr_keycreate(&thr_key, free_thr_data);
}
/*
* get the per-thread-data-item for the calling thread
*/
static struct thr_data *
_get_thr_data(void)
{
struct thr_data *thr_data = NULL;
(void) thr_getspecific(thr_key, (void *)&thr_data);
if (thr_data == NULL) {
thr_data = malloc(sizeof (struct thr_data));
if (thr_data != NULL) {
thr_data->fp = NULL;
thr_data->Dcflags = DC_STD;
thr_setspecific(thr_key, 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();
if (thr_data == NULL)
return (-1);
if (thr_data->fp != NULL)
(void) fclose(thr_data->fp);
if (fn == NULL) {
thr_data->fp = NULL;
return (0);
}
if ((thr_data->fp = fopen(fn, "r")) == 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 simulatniously 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();
int (*compare)(const char *, const char *, size_t);
char *buf_tmp, *ret_ptr = NULL;
size_t off, patlen;
if (thr_data == NULL)
return (NULL);
if (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, sizeof (thr_data->buf), 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_GET, new flags value, created by ORing the DC_* bits.
* RETURN
* oldflags Old value of flags. -1 on error.
* NOTES
* Currently only one bit of flags implemented, namely respect/
* ignore case. The routine is as general as it is so that we
* leave our options open. E.g. we might want to specify rewind/
* norewind before each defread.
*/
int
defcntl(int cmd, int newflags)
{
struct thr_data *thr_data = _get_thr_data();
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);
}
/*
* 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';
}
}