]> git.saurik.com Git - apple/libc.git/blob - gen/getttyent.c
d40361429e776114065dc95e07f94490e6e8763a
[apple/libc.git] / gen / getttyent.c
1 /*
2 * Copyright (c) 1999, 2005 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 /*
24 * Copyright (c) 1989, 1993
25 * The Regents of the University of California. All rights reserved.
26 *
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
29 * are met:
30 * 1. Redistributions of source code must retain the above copyright
31 * notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 * notice, this list of conditions and the following disclaimer in the
34 * documentation and/or other materials provided with the distribution.
35 * 3. All advertising materials mentioning features or use of this software
36 * must display the following acknowledgement:
37 * This product includes software developed by the University of
38 * California, Berkeley and its contributors.
39 * 4. Neither the name of the University nor the names of its contributors
40 * may be used to endorse or promote products derived from this software
41 * without specific prior written permission.
42 *
43 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53 * SUCH DAMAGE.
54 */
55
56 #include "xlocale_private.h"
57
58 #include <ttyent.h>
59 #include <stdio.h>
60 #include <ctype.h>
61 #include <string.h>
62 #include <stdlib.h>
63 #include <regex.h>
64 #include <limits.h>
65
66 static char zapchar;
67 static FILE *tf;
68
69 struct ttyent *
70 getttynam(tty)
71 const char *tty;
72 {
73 register struct ttyent *t;
74
75 setttyent();
76 while ((t = getttyent()) != NULL)
77 if (!strcmp(tty, t->ty_name))
78 break;
79 endttyent();
80 return (t);
81 }
82
83 static char *skip(), *value();
84
85 /*
86 * 4372480: Support for sequences in the tty name. Expressions like [000-999]
87 * for decimal sequences and [0x0-0xf] for hexidecimal sequences causes a
88 * sequence of all combinations of names to be returned by getttyent().
89 *
90 * There is also a slot=nn option, which will cause getttyent() to return
91 * non-existent ttyent structs until the slot number nn is reached. Note, slot
92 * numbers begin at 1.
93 */
94 struct seq {
95 int first;
96 int count;
97 int index;
98 char fmt[NAME_MAX + 17];
99 };
100
101 static const char *brapat = "\\[(.*)]";
102 static regex_t brapreg;
103 static const char *decpat = "^([0-9]+)-([0-9]+)$";
104 static regex_t decpreg;
105 static const char *hexpat = "^0x([0-9a-f]+)-0x([0-9a-f]+)$";
106 static regex_t hexpreg;
107 static struct seq *seq = NULL;
108 static int slot;
109
110 struct ttyent *
111 getttyent(void)
112 {
113 static struct ttyent tty;
114 static const struct ttyent nonexistent = {
115 "\01", /* this shouldn't match anything */
116 NULL,
117 NULL,
118 0,
119 NULL,
120 NULL,
121 NULL
122 };
123 register int c;
124 register char *p;
125 #define MAXLINELENGTH 1024
126 static char *line = NULL;
127 locale_t loc = __current_locale();
128 int newslot, hex;
129 long b, e;
130 regmatch_t match[3], save, bracket;
131
132 if ( line == NULL ) {
133 line = malloc(MAXLINELENGTH);
134 if( line == NULL )
135 return NULL;
136 }
137
138 if (!tf && !setttyent())
139 return (NULL);
140
141 restart:
142 if (slot < seq->first) {
143 /*
144 * the slot= option was set, and we are returning non-existent
145 * entries until we catch up.
146 */
147 slot++;
148 return (struct ttyent *)&nonexistent;
149 }
150
151 if (seq->count > 0) {
152 /*
153 * generate the next tty name; the rest of the tty entries
154 * is the same.
155 */
156 sprintf(tty.ty_name, seq->fmt, seq->index++);
157 slot++;
158 seq->count--;
159 return &tty;
160 }
161
162 if (slot == seq->first) {
163 /*
164 * this was a regular entry with slot=
165 */
166 slot++;
167 return &tty;
168 }
169
170 for (;;) {
171 if (!fgets(p = line, MAXLINELENGTH, tf))
172 return (NULL);
173 /* skip lines that are too big */
174 if (!index(p, '\n')) {
175 while ((c = getc(tf)) != '\n' && c != EOF)
176 ;
177 continue;
178 }
179 while (isspace_l(*p, loc))
180 ++p;
181 if (*p && *p != '#')
182 break;
183 }
184
185 zapchar = 0;
186 tty.ty_name = p;
187 p = skip(p);
188 if (!*(tty.ty_getty = p))
189 tty.ty_getty = tty.ty_type = NULL;
190 else {
191 p = skip(p);
192 if (!*(tty.ty_type = p))
193 tty.ty_type = NULL;
194 else
195 p = skip(p);
196 }
197 tty.ty_status = 0;
198 tty.ty_window = NULL;
199 tty.ty_onerror = NULL;
200 tty.ty_onoption = NULL;
201
202 #define scmp(e) !strncmp(p, e, sizeof(e) - 1) && isspace_l(p[sizeof(e) - 1], loc)
203 #define vcmp(e) !strncmp(p, e, sizeof(e) - 1) && p[sizeof(e) - 1] == '='
204 newslot = -1;
205 for (; *p; p = skip(p)) {
206 if (scmp(_TTYS_OFF))
207 tty.ty_status &= ~TTY_ON;
208 else if (scmp(_TTYS_ON))
209 tty.ty_status |= TTY_ON;
210 else if (scmp(_TTYS_SECURE))
211 tty.ty_status |= TTY_SECURE;
212 else if (vcmp(_TTYS_WINDOW))
213 tty.ty_window = value(p);
214 else if (vcmp(_TTYS_ONERROR))
215 tty.ty_onerror = value(p);
216 else if (vcmp(_TTYS_ONOPTION))
217 tty.ty_onoption = value(p);
218 else if (vcmp(_TTYS_SLOT)) {
219 char *slotstr = value(p);
220 if (slotstr)
221 newslot = atoi(slotstr);
222 } else
223 break;
224 }
225
226 if (zapchar == '#' || *p == '#')
227 while ((c = *++p) == ' ' || c == '\t')
228 ;
229 tty.ty_comment = p;
230 if (*p == 0)
231 tty.ty_comment = 0;
232 if ((p = index(p, '\n')) != NULL)
233 *p = '\0';
234
235 /* check if tty.tyname has a sequence */
236 if (regexec(&brapreg, tty.ty_name, 3, match, 0) != 0)
237 goto out;
238
239 /*
240 * save the range of the bracketed range, so we can find the strings
241 * before and after
242 */
243 bracket = match[0];
244 /* use REG_STARTEND to limit matching with the bracketed range */
245 match[0] = save = match[1];
246 if (regexec(&decpreg, tty.ty_name, 3, match, REG_STARTEND) == 0) {
247 /* a decimal range */
248 b = strtol(tty.ty_name + match[1].rm_so, NULL, 10);
249 e = strtol(tty.ty_name + match[2].rm_so, NULL, 10);
250 hex = 0;
251 } else {
252 match[0] = save;
253 if (regexec(&hexpreg, tty.ty_name, 3, match, REG_STARTEND) == 0) {
254 /* a hexidecimal range */
255 b = strtol(tty.ty_name + match[1].rm_so, NULL, 16);
256 e = strtol(tty.ty_name + match[2].rm_so, NULL, 16);
257 hex = 1;
258 } else
259 goto out;
260 }
261 if (b > e) /* skip */
262 goto restart;
263
264 /* seq->first is already less than slot, so just leave it */
265 seq->count = e - b + 1;
266 seq->index = b;
267 /*
268 * The fmt string contains the characters before the bracket, the
269 * a format specifier (either decimal or hex) and any characters
270 * after the bracket. Note that the length of the lower range is
271 * use as a minimum digit length, with zero fill, so the format
272 * specifier will look something like %03d.
273 */
274 sprintf(seq->fmt, "%.*s%%0%d%c%s",
275 (int)bracket.rm_so, tty.ty_name,
276 (int)(match[1].rm_eo - match[1].rm_so),
277 hex ? 'x' : 'd',
278 tty.ty_name + bracket.rm_eo);
279
280 out:
281 if (newslot > slot) {
282 /* set up to skip until newslot */
283 seq->first = newslot;
284 goto restart;
285 }
286 if (seq->count > 0) /* restart if we are doing a sequence */
287 goto restart;
288 /* regular single value return */
289 slot++;
290 return (&tty);
291 }
292
293 #define QUOTED 1
294
295 /*
296 * Skip over the current field, removing quotes, and return a pointer to
297 * the next field.
298 */
299 static char *
300 skip(p)
301 register char *p;
302 {
303 register char *t;
304 register int c, q;
305
306 for (q = 0, t = p; (c = *p) != '\0'; p++) {
307 if (c == '"') {
308 q ^= QUOTED; /* obscure, but nice */
309 continue;
310 }
311 if (q == QUOTED && *p == '\\' && *(p+1) == '"')
312 p++;
313 *t++ = *p;
314 if (q == QUOTED)
315 continue;
316 if (c == '#') {
317 zapchar = c;
318 *p = 0;
319 break;
320 }
321 if (c == '\t' || c == ' ' || c == '\n') {
322 zapchar = c;
323 *p++ = 0;
324 while ((c = *p) == '\t' || c == ' ' || c == '\n')
325 p++;
326 break;
327 }
328 }
329 *--t = '\0';
330 return (p);
331 }
332
333 static char *
334 value(p)
335 register char *p;
336 {
337
338 return ((p = index(p, '=')) ? ++p : NULL);
339 }
340
341 int
342 setttyent()
343 {
344
345 /* initialize seq and the three regexp patterns */
346 if (!seq) {
347 if (regcomp(&brapreg, brapat, REG_EXTENDED) != 0)
348 return 0;
349 if (regcomp(&decpreg, decpat, REG_EXTENDED) != 0) {
350 regfree(&brapreg);
351 return 0;
352 }
353 if (regcomp(&hexpreg, hexpat, REG_EXTENDED | REG_ICASE) != 0) {
354 regfree(&decpreg);
355 regfree(&brapreg);
356 return 0;
357 }
358 if ((seq = malloc(sizeof(struct seq))) == NULL) {
359 regfree(&hexpreg);
360 regfree(&decpreg);
361 regfree(&brapreg);
362 return 0;
363 }
364 }
365 seq->first = seq->count = 0;
366 slot = 1;
367
368 if (tf) {
369 (void)rewind(tf);
370 return (1);
371 } else if ((tf = fopen(_PATH_TTYS, "r")) != NULL)
372 return (1);
373 return (0);
374 }
375
376 int
377 endttyent()
378 {
379 int rval;
380
381 if (tf) {
382 rval = !(fclose(tf) == EOF);
383 tf = NULL;
384 return (rval);
385 }
386 return (1);
387 }