xref: /illumos-gate/usr/src/lib/libc/port/gen/deflt.c (revision 03100a6332bd4edc7a53091fcf7c9a7131bcdaa7)
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