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 2006 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 #pragma weak defopen = _defopen 36 #pragma weak defread = _defread 37 #pragma weak defcntl = _defcntl 38 39 #include "synonyms.h" 40 #include "libc.h" 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <deflt.h> 44 #include <sys/types.h> 45 #include <string.h> 46 #include <ctype.h> 47 #include <unistd.h> 48 #include "tsd.h" 49 50 #define TSTBITS(flags, mask) (((flags) & (mask)) == (mask)) 51 52 static void strip_quotes(char *); 53 54 struct thr_data { 55 int Dcflags; /* [re-]initialized on each call to defopen() */ 56 FILE *fp; 57 char *buf; 58 }; 59 60 #define BUFFERSIZE 1024 61 62 /* 63 * destructor for per-thread data, registered with tsdalloc() 64 */ 65 static void 66 free_thr_data(void *arg) 67 { 68 struct thr_data *thr_data = (struct thr_data *)arg; 69 70 if (thr_data->fp) { 71 (void) fclose(thr_data->fp); 72 thr_data->fp = NULL; 73 } 74 if (thr_data->buf) { 75 lfree(thr_data->buf, BUFFERSIZE); 76 thr_data->buf = NULL; 77 } 78 } 79 80 /* 81 * get the per-thread-data-item for the calling thread 82 */ 83 static struct thr_data * 84 get_thr_data(void) 85 { 86 struct thr_data *thr_data = 87 tsdalloc(_T_DEFREAD, sizeof (*thr_data), free_thr_data); 88 89 return (thr_data); 90 } 91 92 /* 93 * defopen() - declare defopen filename 94 * 95 * defopen(fn) 96 * char *fn 97 * 98 * If 'fn' is non-null; it is a full pathname of a file 99 * which becomes the one read by subsequent defread() calls. 100 * If 'fn' is null the defopen file is closed. 101 * 102 * see defread() for more details. 103 * 104 * EXIT returns 0 if ok 105 * returns -1 if error 106 */ 107 int 108 defopen(char *fn) 109 { 110 struct thr_data *thr_data = get_thr_data(); 111 112 if (thr_data == NULL) 113 return (-1); 114 115 if (thr_data->fp != NULL) { 116 (void) fclose(thr_data->fp); 117 thr_data->fp = NULL; 118 } 119 120 if (fn == NULL) 121 return (0); 122 123 if ((thr_data->fp = fopen(fn, "rF")) == NULL) 124 return (-1); 125 126 /* 127 * We allocate the big buffer only if the fopen() succeeds. 128 * Notice that we deallocate the buffer only when the thread exits. 129 * There are misguided applications that assume that data returned 130 * by defread() continues to exist after defopen(NULL) is called. 131 */ 132 if (thr_data->buf == NULL && 133 (thr_data->buf = lmalloc(BUFFERSIZE)) == NULL) { 134 (void) fclose(thr_data->fp); 135 thr_data->fp = NULL; 136 return (-1); 137 } 138 139 thr_data->Dcflags = DC_STD; 140 141 return (0); 142 } 143 144 /* 145 * defread() - read an entry from the defopen file 146 * 147 * defread(cp) 148 * char *cp 149 * 150 * The defopen data file must have been previously opened by 151 * defopen(). defread scans the data file looking for a line 152 * which begins with the string '*cp'. If such a line is found, 153 * defread returns a pointer to the first character following 154 * the matched string (*cp). If no line is found or no file 155 * is open, defread() returns NULL. 156 * 157 * Note that there is no way to simulatniously peruse multiple 158 * defopen files; since there is no way of indicating 'which one' 159 * to defread(). If you want to peruse a secondary file you must 160 * recall defopen(). If you need to go back to the first file, 161 * you must call defopen() again. 162 */ 163 char * 164 defread(char *cp) 165 { 166 struct thr_data *thr_data = get_thr_data(); 167 int (*compare)(const char *, const char *, size_t); 168 char *buf_tmp, *ret_ptr = NULL; 169 size_t off, patlen; 170 171 if (thr_data == NULL || thr_data->fp == NULL) 172 return (NULL); 173 174 compare = TSTBITS(thr_data->Dcflags, DC_CASE) ? strncmp : strncasecmp; 175 patlen = strlen(cp); 176 177 if (!TSTBITS(thr_data->Dcflags, DC_NOREWIND)) 178 rewind(thr_data->fp); 179 180 while (fgets(thr_data->buf, BUFFERSIZE, thr_data->fp)) { 181 for (buf_tmp = thr_data->buf; *buf_tmp == ' '; buf_tmp++) 182 ; 183 off = strlen(buf_tmp) - 1; 184 if (buf_tmp[off] == '\n') 185 buf_tmp[off] = 0; 186 else 187 break; /* line too long */ 188 if ((*compare)(cp, buf_tmp, patlen) == 0) { 189 /* found it */ 190 /* strip quotes if requested */ 191 if (TSTBITS(thr_data->Dcflags, DC_STRIP_QUOTES)) { 192 strip_quotes(buf_tmp); 193 } 194 ret_ptr = &buf_tmp[patlen]; 195 break; 196 } 197 } 198 199 return (ret_ptr); 200 } 201 202 /* 203 * defcntl -- default control 204 * 205 * SYNOPSIS 206 * oldflags = defcntl(cmd, arg); 207 * 208 * ENTRY 209 * cmd Command. One of DC_GET, DC_SET. 210 * arg Depends on command. If DC_GET, ignored. If 211 * DC_GET, new flags value, created by ORing the DC_* bits. 212 * RETURN 213 * oldflags Old value of flags. -1 on error. 214 * NOTES 215 * Currently only one bit of flags implemented, namely respect/ 216 * ignore case. The routine is as general as it is so that we 217 * leave our options open. E.g. we might want to specify rewind/ 218 * norewind before each defread. 219 */ 220 221 int 222 defcntl(int cmd, int newflags) 223 { 224 struct thr_data *thr_data = get_thr_data(); 225 int oldflags; 226 227 if (thr_data == NULL) 228 return (-1); 229 230 switch (cmd) { 231 case DC_GETFLAGS: /* query */ 232 oldflags = thr_data->Dcflags; 233 break; 234 case DC_SETFLAGS: /* set */ 235 oldflags = thr_data->Dcflags; 236 thr_data->Dcflags = newflags; 237 break; 238 default: /* error */ 239 oldflags = -1; 240 break; 241 } 242 243 return (oldflags); 244 } 245 246 /* 247 * strip_quotes -- strip double (") or single (') quotes from a buffer 248 * 249 * ENTRY 250 * ptr initial string 251 * 252 * EXIT 253 * ptr string with quotes (if any) removed 254 */ 255 static void 256 strip_quotes(char *ptr) 257 { 258 char *strip_ptr = NULL; 259 260 while (*ptr != '\0') { 261 if ((*ptr == '"') || (*ptr == '\'')) { 262 if (strip_ptr == NULL) 263 strip_ptr = ptr; /* skip over quote */ 264 } else { 265 if (strip_ptr != NULL) { 266 *strip_ptr = *ptr; 267 strip_ptr++; 268 } 269 } 270 ptr++; 271 } 272 if (strip_ptr != NULL) { 273 *strip_ptr = '\0'; 274 } 275 } 276