1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* Copyright (c) 1987, 1988 Microsoft Corporation */ 31 /* All Rights Reserved */ 32 33 #pragma ident "%Z%%M% %I% %E% SMI" 34 35 #include "lint.h" 36 #include "libc.h" 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <deflt.h> 40 #include <sys/types.h> 41 #include <string.h> 42 #include <ctype.h> 43 #include <unistd.h> 44 #include "tsd.h" 45 46 #define TSTBITS(flags, mask) (((flags) & (mask)) == (mask)) 47 48 static void strip_quotes(char *); 49 50 struct thr_data { 51 int Dcflags; /* [re-]initialized on each call to defopen() */ 52 FILE *fp; 53 char *buf; 54 }; 55 56 #define BUFFERSIZE 1024 57 58 /* 59 * destructor for per-thread data, registered with tsdalloc() 60 */ 61 static void 62 free_thr_data(void *arg) 63 { 64 struct thr_data *thr_data = (struct thr_data *)arg; 65 66 if (thr_data->fp) { 67 (void) fclose(thr_data->fp); 68 thr_data->fp = NULL; 69 } 70 if (thr_data->buf) { 71 lfree(thr_data->buf, BUFFERSIZE); 72 thr_data->buf = NULL; 73 } 74 } 75 76 /* 77 * get the per-thread-data-item for the calling thread 78 */ 79 static struct thr_data * 80 get_thr_data(void) 81 { 82 struct thr_data *thr_data = 83 tsdalloc(_T_DEFREAD, sizeof (*thr_data), free_thr_data); 84 85 return (thr_data); 86 } 87 88 /* 89 * defopen() - declare defopen filename 90 * 91 * defopen(fn) 92 * char *fn 93 * 94 * If 'fn' is non-null; it is a full pathname of a file 95 * which becomes the one read by subsequent defread() calls. 96 * If 'fn' is null the defopen file is closed. 97 * 98 * see defread() for more details. 99 * 100 * EXIT returns 0 if ok 101 * returns -1 if error 102 */ 103 int 104 defopen(char *fn) 105 { 106 struct thr_data *thr_data = get_thr_data(); 107 108 if (thr_data == NULL) 109 return (-1); 110 111 if (thr_data->fp != NULL) { 112 (void) fclose(thr_data->fp); 113 thr_data->fp = NULL; 114 } 115 116 if (fn == NULL) 117 return (0); 118 119 if ((thr_data->fp = fopen(fn, "rF")) == NULL) 120 return (-1); 121 122 /* 123 * We allocate the big buffer only if the fopen() succeeds. 124 * Notice that we deallocate the buffer only when the thread exits. 125 * There are misguided applications that assume that data returned 126 * by defread() continues to exist after defopen(NULL) is called. 127 */ 128 if (thr_data->buf == NULL && 129 (thr_data->buf = lmalloc(BUFFERSIZE)) == NULL) { 130 (void) fclose(thr_data->fp); 131 thr_data->fp = NULL; 132 return (-1); 133 } 134 135 thr_data->Dcflags = DC_STD; 136 137 return (0); 138 } 139 140 /* 141 * defread() - read an entry from the defopen file 142 * 143 * defread(cp) 144 * char *cp 145 * 146 * The defopen data file must have been previously opened by 147 * defopen(). defread scans the data file looking for a line 148 * which begins with the string '*cp'. If such a line is found, 149 * defread returns a pointer to the first character following 150 * the matched string (*cp). If no line is found or no file 151 * is open, defread() returns NULL. 152 * 153 * Note that there is no way to simulatniously peruse multiple 154 * defopen files; since there is no way of indicating 'which one' 155 * to defread(). If you want to peruse a secondary file you must 156 * recall defopen(). If you need to go back to the first file, 157 * you must call defopen() again. 158 */ 159 char * 160 defread(char *cp) 161 { 162 struct thr_data *thr_data = get_thr_data(); 163 int (*compare)(const char *, const char *, size_t); 164 char *buf_tmp, *ret_ptr = NULL; 165 size_t off, patlen; 166 167 if (thr_data == NULL || thr_data->fp == NULL) 168 return (NULL); 169 170 compare = TSTBITS(thr_data->Dcflags, DC_CASE) ? strncmp : strncasecmp; 171 patlen = strlen(cp); 172 173 if (!TSTBITS(thr_data->Dcflags, DC_NOREWIND)) 174 rewind(thr_data->fp); 175 176 while (fgets(thr_data->buf, BUFFERSIZE, thr_data->fp)) { 177 for (buf_tmp = thr_data->buf; *buf_tmp == ' '; buf_tmp++) 178 ; 179 off = strlen(buf_tmp) - 1; 180 if (buf_tmp[off] == '\n') 181 buf_tmp[off] = 0; 182 else 183 break; /* line too long */ 184 if ((*compare)(cp, buf_tmp, patlen) == 0) { 185 /* found it */ 186 /* strip quotes if requested */ 187 if (TSTBITS(thr_data->Dcflags, DC_STRIP_QUOTES)) { 188 strip_quotes(buf_tmp); 189 } 190 ret_ptr = &buf_tmp[patlen]; 191 break; 192 } 193 } 194 195 return (ret_ptr); 196 } 197 198 /* 199 * defcntl -- default control 200 * 201 * SYNOPSIS 202 * oldflags = defcntl(cmd, arg); 203 * 204 * ENTRY 205 * cmd Command. One of DC_GET, DC_SET. 206 * arg Depends on command. If DC_GET, ignored. If 207 * DC_GET, new flags value, created by ORing the DC_* bits. 208 * RETURN 209 * oldflags Old value of flags. -1 on error. 210 * NOTES 211 * Currently only one bit of flags implemented, namely respect/ 212 * ignore case. The routine is as general as it is so that we 213 * leave our options open. E.g. we might want to specify rewind/ 214 * norewind before each defread. 215 */ 216 217 int 218 defcntl(int cmd, int newflags) 219 { 220 struct thr_data *thr_data = get_thr_data(); 221 int oldflags; 222 223 if (thr_data == NULL) 224 return (-1); 225 226 switch (cmd) { 227 case DC_GETFLAGS: /* query */ 228 oldflags = thr_data->Dcflags; 229 break; 230 case DC_SETFLAGS: /* set */ 231 oldflags = thr_data->Dcflags; 232 thr_data->Dcflags = newflags; 233 break; 234 default: /* error */ 235 oldflags = -1; 236 break; 237 } 238 239 return (oldflags); 240 } 241 242 /* 243 * strip_quotes -- strip double (") or single (') quotes from a buffer 244 * 245 * ENTRY 246 * ptr initial string 247 * 248 * EXIT 249 * ptr string with quotes (if any) removed 250 */ 251 static void 252 strip_quotes(char *ptr) 253 { 254 char *strip_ptr = NULL; 255 256 while (*ptr != '\0') { 257 if ((*ptr == '"') || (*ptr == '\'')) { 258 if (strip_ptr == NULL) 259 strip_ptr = ptr; /* skip over quote */ 260 } else { 261 if (strip_ptr != NULL) { 262 *strip_ptr = *ptr; 263 strip_ptr++; 264 } 265 } 266 ptr++; 267 } 268 if (strip_ptr != NULL) { 269 *strip_ptr = '\0'; 270 } 271 } 272