Initial import from FreeBSD RELENG_4:
[games.git] / usr.sbin / pccard / pccardd / file.c
1 /*
2  * Copyright (c) 1995 Andrew McRae.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  * 3. The name of the author may not be used to endorse or promote products
13  *    derived from this software without specific prior written permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #ifndef lint
28 static const char rcsid[] =
29   "$FreeBSD: src/usr.sbin/pccard/pccardd/file.c,v 1.24.2.5 2001/06/05 07:01:40 imp Exp $";
30 #endif /* not lint */
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <sys/types.h>
36 #include "cardd.h"
37
38 static FILE *in;
39 static int includes = 0;
40 static struct {
41         FILE    *filep;
42         char    *filename;
43         int     lineno;
44 } configfiles[MAXINCLUDES] = {{NULL, NULL, 0}, };
45
46 static int pushc, pusht;
47 static int lineno;
48 static char *filename;
49
50 static char *keys[] = {
51         "__EOF__",              /* 1 */
52         "io",                   /* 2 */
53         "irq",                  /* 3 */
54         "memory",               /* 4 */
55         "card",                 /* 5 */
56         "device",               /* 6 */
57         "config",               /* 7 */
58         "reset",                /* 8 */
59         "ether",                /* 9 */
60         "insert",               /* 10 */
61         "remove",               /* 11 */
62         "iosize",               /* 12 */
63         "debuglevel",           /* 13 */
64         "include",              /* 14 */
65         "function",             /* 15 */
66         "logstr",               /* 16 */
67         0
68 };
69
70 #define KWD_EOF                 1
71 #define KWD_IO                  2
72 #define KWD_IRQ                 3
73 #define KWD_MEMORY              4
74 #define KWD_CARD                5
75 #define KWD_DEVICE              6
76 #define KWD_CONFIG              7
77 #define KWD_RESET               8
78 #define KWD_ETHER               9
79 #define KWD_INSERT              10
80 #define KWD_REMOVE              11
81 #define KWD_IOSIZE              12
82 #define KWD_DEBUGLEVEL          13
83 #define KWD_INCLUDE             14
84 #define KWD_FUNCTION            15
85 #define KWD_LOGSTR              16
86
87 /* for keyword compatibility with PAO/plain FreeBSD */
88 static struct {
89         char    *alias;
90         u_int   key;
91 } key_aliases[] = {
92         {"generic", KWD_FUNCTION},
93         {0, 0}
94 };
95
96 struct flags {
97         char   *name;
98         int     mask;
99 };
100
101 extern int      doverbose;
102
103 static void    parsefile(void);
104 static char   *getline(void);
105 static char   *next_tok(void);
106 static int     num_tok(void);
107 static void    error(char *);
108 static int     keyword(char *);
109 static int     irq_tok(int);
110 static int     config_tok(unsigned char *);
111 static int     func_tok(void);
112 static int     debuglevel_tok(int);
113 static struct allocblk *ioblk_tok(int);
114 static struct allocblk *memblk_tok(int);
115 static struct driver *new_driver(char *);
116 static int     iosize_tok(void);
117 static void    file_include(char *);
118
119 static void    addcmd(struct cmd **);
120 static void    parse_card(int);
121
122 static void
123 delete_card(struct card *cp)
124 {
125         struct ether    *etherp, *ether_next;
126         struct card_config *configp, *config_next;
127         struct cmd      *cmdp, *cmd_next;
128
129         /* free strings */
130         free(cp->manuf);
131         free(cp->version);
132         free(cp->add_info1);
133         free(cp->add_info2);
134         free(cp->logstr);
135
136         /* free structures */
137         for (etherp = cp->ether; etherp; etherp = ether_next) {
138                 ether_next = etherp->next;
139                 free(etherp);
140         }
141         for (configp = cp->config; configp; configp = config_next) {
142                 config_next = configp->next;
143                 free(configp);
144         }
145         for (cmdp = cp->insert; cmdp; cmdp = cmd_next) {
146                 cmd_next = cmdp->next;
147                 free(cmdp->line);
148                 free(cmdp);
149         }
150         for (cmdp = cp->remove; cmdp; cmdp = cmd_next) {
151                 cmd_next = cmdp->next;
152                 free(cmdp->line);
153                 free(cmdp);
154         }
155         free(cp);
156 }
157
158 /*
159  * Read a file and parse the pcmcia configuration data.
160  * After parsing, verify the links.
161  */
162 void
163 readfile(char *name)
164 {
165         int i, inuse;
166         struct card *cp, *card_next;
167         struct card *genericp, *tail_gp;
168         struct card_config *configp;
169
170         /* delete all card configuration data before we proceed */
171         genericp = 0;
172         cp = cards;
173         cards = last_card = 0;
174         while (cp) {
175                 card_next = cp->next;
176
177                 /* check whether this card is in use */
178                 inuse = 0;
179                 for (configp = cp->config; configp; configp = configp->next) {
180                         if (configp->inuse) {
181                                 inuse = 1;
182                                 break;
183                         }
184                 }
185
186                 /*
187                  * don't delete entry in use for consistency.
188                  * leave normal entry in the cards list,
189                  * insert generic entry into the list after re-loading config files.
190                  */
191                 if (inuse == 1) {
192                         cp->next = 0;   /* unchain from the cards list */
193                         switch (cp->deftype) {
194                         case DT_VERS:
195                                 /* don't delete this entry for consistency */
196                                 if (debug_level >= 1) {
197                                         logmsg("Card \"%s\"(\"%s\") is in use, "
198                                             "can't change configuration\n",
199                                             cp->manuf, cp->version);
200                                 }
201                                 /* add this to the card list */
202                                 if (!last_card) {
203                                         cards = last_card = cp;
204                                 } else {
205                                         last_card->next = cp;
206                                         last_card = cp;
207                                 }
208                                 break;
209
210                         case DT_FUNC:
211                                 /* generic entry must be inserted to the list later */
212                                 if (debug_level >= 1) {
213                                         logmsg("Generic entry is in use, "
214                                             "can't change configuration\n");
215                                 }
216                                 cp->next = genericp;
217                                 genericp = cp;
218                                 break;
219                         }
220                 } else {
221                         delete_card(cp);
222                 }
223
224                 cp = card_next;
225         }
226
227         for (i = 0; i < MAXINCLUDES; i++) {
228                 if (configfiles[i].filep) {
229                         fclose(configfiles[i].filep);
230                         configfiles[i].filep = NULL;
231                         if (i > 0) {
232                                 free(configfiles[i].filename);
233                         }
234                 }
235         }
236         in = fopen(name, "r");
237         if (in == 0) {
238                 logerr(name);
239                 die("readfile");
240         }
241         includes = 0;
242         configfiles[includes].filep = in;
243         filename = configfiles[includes].filename = name;
244
245         parsefile();
246         for (cp = cards; cp; cp = cp->next) {
247                 if (cp->config == 0)
248                         logmsg("warning: card %s(%s) has no valid configuration\n",
249                             cp->manuf, cp->version);
250         }
251
252         /* insert generic entries in use into the top of generic entries */
253         if (genericp) {
254                 /* search tail of generic entries in use */
255                 for (tail_gp = genericp; tail_gp->next; tail_gp = tail_gp->next)
256                         ;
257
258                 /*
259                  * if the top of cards list is generic entry,
260                  * insert generic entries in use before it.
261                  */
262                 if (cards && cards->deftype == DT_FUNC) {
263                         tail_gp->next = cards;
264                         cards = genericp;
265                         goto generic_done;
266                 }
267
268                 /* search top of generic entries */
269                 for (cp = cards; cp; cp = cp->next) {
270                         if (cp->next && cp->next->deftype == DT_FUNC) {
271                                 break;
272                         }
273                 }
274
275                 /*
276                  * if we have generic entry in the cards list,
277                  * insert generic entries in use into there.
278                  */
279                 if (cp) {
280                         tail_gp->next = cp->next;
281                         cp->next = genericp;
282                         goto generic_done;
283                 }
284
285                 /*
286                  * otherwise we don't have generic entries in
287                  * cards list, just add them to the list.
288                  */
289                 if (!last_card) {
290                         cards = genericp;
291                 } else {
292                         last_card->next = genericp;
293                         last_card = tail_gp;
294                 }
295 generic_done:
296         }
297
298         /* save the initial state of resource pool */
299         bcopy(io_avail, io_init, bitstr_size(IOPORTS));
300         bcopy(mem_avail, mem_init, bitstr_size(MEMBLKS));
301         bcopy(pool_irq, irq_init, sizeof(pool_irq));
302 }
303
304 static void
305 parsefile(void)
306 {
307         int     i;
308         int     errors = 0;
309         struct allocblk *bp, *next;
310         char    *incl;
311
312         pushc = 0;
313         lineno = 1;
314         for (;;)
315                 switch (keyword(next_tok())) {
316                 case KWD_EOF:
317                         /* EOF */
318                         return;
319                 case KWD_IO:
320                         /* override reserved I/O blocks */
321                         bit_nclear(io_avail, 0, IOPORTS-1);
322                         for (bp = pool_ioblks; bp; bp = next) {
323                                 next = bp->next;
324                                 free(bp);
325                         }
326                         pool_ioblks = NULL;
327
328                         while ((bp = ioblk_tok(0)) != 0) {
329                                 if (bp->size == 0 || bp->addr == 0) {
330                                         free(bp);
331                                         continue;
332                                 }
333                                 bit_nset(io_avail, bp->addr,
334                                          bp->addr + bp->size - 1);
335                                 bp->next = pool_ioblks;
336                                 pool_ioblks = bp;
337                         }
338                         pusht = 1;
339                         break;
340                 case KWD_IRQ:
341                         /* override reserved irqs */
342                         bzero(pool_irq, sizeof(pool_irq));
343                         while ((i = irq_tok(0)) > 0)
344                                 pool_irq[i] = 1;
345                         pusht = 1;
346                         break;
347                 case KWD_MEMORY:
348                         /* override reserved memory blocks. */
349                         bit_nclear(mem_avail, 0, MEMBLKS-1);
350                         for (bp = pool_mem; bp; bp = next) {
351                                 next = bp->next;
352                                 free(bp);
353                         }
354                         pool_mem = NULL;
355
356                         while ((bp = memblk_tok(0)) != 0) {
357                                 if (bp->size == 0 || bp->addr == 0) {
358                                         free(bp);
359                                         continue;
360                                 }
361                                 bit_nset(mem_avail, MEM2BIT(bp->addr),
362                                     MEM2BIT(bp->addr + bp->size) - 1);
363                                 bp->next = pool_mem;
364                                 pool_mem = bp;
365                         }
366                         pusht = 1;
367                         break;
368                 case KWD_CARD:
369                         /* Card definition. */
370                         parse_card(DT_VERS);
371                         break;
372                 case KWD_FUNCTION:
373                         /* Function definition. */
374                         parse_card(DT_FUNC);
375                         break;
376                 case KWD_DEBUGLEVEL:
377                         i = debuglevel_tok(0);
378                         if (i > 0)
379                                 debug_level = i;
380                         break;
381                 case KWD_INCLUDE:
382                         incl = newstr(next_tok());
383                         file_include(incl);
384                         break;
385                 default:
386                         error("syntax error");
387                         pusht = 0;
388                         if (errors++ >= MAXERRORS) {
389                                 error("too many errors, giving up");
390                                 return;
391                         }
392                         break;
393                 }
394 }
395
396 /*
397  *      Parse a card definition.
398  */
399 static void
400 parse_card(int deftype)
401 {
402         char   *man, *vers, *tmp;
403         char   *add_info;
404         unsigned char index_type;
405         struct card *cp;
406         int     i, iosize;
407         struct card_config *confp, *lastp;
408         struct ether *ether;
409
410         confp = 0;
411         cp = xmalloc(sizeof(*cp));
412         cp->deftype = deftype;
413         switch (deftype) {
414         case DT_VERS:
415                 man = newstr(next_tok());
416                 vers = newstr(next_tok());
417                 add_info = newstr(next_tok());
418                 if (keyword(add_info)) {
419                         pusht = 1;
420                         free(add_info);
421                         cp->add_info1 = NULL;
422                         cp->add_info2 = NULL;
423                 } else {
424                         cp->add_info1 = add_info;
425                         add_info = newstr(next_tok());
426                         if (keyword(add_info)) {
427                                 pusht = 1;
428                                 free(add_info);
429                                 cp->add_info2 = NULL;
430                         } else {
431                                 cp->add_info2 = add_info;
432                         }
433                 }
434                 cp->manuf = man;
435                 cp->version = vers;
436                 cp->logstr = NULL;
437                 asprintf(&cp->logstr, "%s (%s)", man, vers);
438                 cp->func_id = 0;
439                 break;
440         case DT_FUNC:
441                 cp->manuf = NULL;
442                 cp->version = NULL;
443                 cp->logstr = NULL;
444                 cp->func_id = (u_char) func_tok();
445                 break;
446         default:
447                 fprintf(stderr, "parse_card: unknown deftype %d\n", deftype);
448                 exit(1);
449         }
450         cp->reset_time = 50;
451         cp->next = 0;
452         if (!last_card) {
453                 cards = last_card = cp;
454         } else {
455                 last_card->next = cp;
456                 last_card = cp;
457         }
458         for (;;) {
459                 switch (keyword(next_tok())) {
460                 case KWD_CONFIG:
461                         /* config */
462                         i = config_tok(&index_type);
463                         if (i == -1) {
464                                 error("illegal card config index");
465                                 break;
466                         }
467                         confp = xmalloc(sizeof(*confp));
468                         man = next_tok();
469                         confp->driver = new_driver(man);
470                         confp->irq = irq_tok(1);
471                         confp->flags = num_tok();
472                         if (confp->flags == -1) {
473                                 pusht = 1;
474                                 confp->flags = 0;
475                         }
476                         if (confp->irq < 0 || confp->irq > 15) {
477                                 error("illegal card IRQ value");
478                                 break;
479                         }
480                         confp->index = i & 0x3F;
481                         confp->index_type = index_type;
482
483                         /*
484                          * If no valid driver for this config, then do not save
485                          * this configuration entry.
486                          */
487                         if (confp->driver) {
488                                 if (cp->config == 0)
489                                         cp->config = confp;
490                                 else {
491                                         for (lastp = cp->config; lastp->next;
492                                             lastp = lastp->next);
493                                         lastp->next = confp;
494                                 }
495                         } else
496                                 free(confp);
497                         break;
498                 case KWD_RESET:
499                         /* reset */
500                         i = num_tok();
501                         if (i == -1) {
502                                 error("illegal card reset time");
503                                 break;
504                         }
505                         cp->reset_time = i;
506                         break;
507                 case KWD_ETHER:
508                         /* ether */
509                         ether = xmalloc(sizeof(*ether));
510                         ether->type = ETHTYPE_GENERIC;
511                         tmp = next_tok();
512                         if (strcmp("attr2", tmp) == 0)
513                                 ether->type = ETHTYPE_ATTR2;
514                         else {
515                                 pusht = 1;
516                                 ether->value = num_tok();
517                                 if (ether->value == -1) {
518                                         error("illegal ether address offset");
519                                         free(ether);
520                                         break;
521                                 }
522                         }
523                         ether->next = cp->ether;
524                         cp->ether = ether;
525                         break;
526                 case KWD_INSERT:
527                         /* insert */
528                         addcmd(&cp->insert);
529                         break;
530                 case KWD_REMOVE:
531                         /* remove */
532                         addcmd(&cp->remove);
533                         break;
534                 case KWD_IOSIZE:
535                         /* iosize */
536                         iosize = iosize_tok();
537                         if (!iosize) {
538                                 error("Illegal cardio arguments");
539                                 break;
540                         }
541                         if (!confp) {
542                                 error("iosize should be placed after config");
543                                 break;
544                         }
545                         cp->iosize = iosize;
546                         break;
547                 case KWD_LOGSTR:
548                         free(cp->logstr);
549                         cp->logstr = newstr(next_tok());
550                         break;
551                 default:
552                         pusht = 1;
553                         return;
554                 }
555         }
556 }
557
558 /*
559  *      Generate a new driver structure. If one exists, use
560  *      that one after confirming the correct class.
561  */
562 static struct driver *
563 new_driver(char *name)
564 {
565         struct driver *drvp;
566         char   *p;
567
568         for (drvp = drivers; drvp; drvp = drvp->next)
569                 if (strcmp(drvp->name, name) == 0)
570                         return (drvp);
571         drvp = xmalloc(sizeof(*drvp));
572         drvp->next = drivers;
573         drivers = drvp;
574         drvp->name = newstr(name);
575         drvp->kernel = newstr(name);
576         p = drvp->kernel;
577         while (*p++)
578                 if (*p >= '0' && *p <= '9') {
579                         drvp->unit = atoi(p);
580                         *p = 0;
581                         break;
582                 }
583 #ifdef  DEBUG
584         printf("Drv %s%d created\n", drvp->kernel, drvp->unit);
585 #endif
586         return (drvp);
587 }
588
589
590 /*
591  *      Parse one I/O block.
592  */
593 static struct allocblk *
594 ioblk_tok(int force)
595 {
596         struct allocblk *io;
597         int     i, j;
598
599         /* ignore the keyword to allow separete blocks in multiple lines */
600         if (keyword(next_tok()) != KWD_IO) {
601                 pusht = 1;
602         }
603
604         if ((i = num_tok()) >= 0) {
605                 if (strcmp("-", next_tok()) || (j = num_tok()) < 0 || j < i) {
606                         error("I/O block format error");
607                         return (0);
608                 }
609                 io = xmalloc(sizeof(*io));
610                 io->addr = i;
611                 io->size = j - i + 1;
612                 if (j > IOPORTS) {
613                         error("I/O port out of range");
614                         if (force) {
615                                 free(io);
616                                 io = 0;
617                         } else
618                                 io->addr = io->size = 0;
619                 }
620                 return (io);
621         }
622         if (force)
623                 error("illegal or missing I/O block spec");
624         return (0);
625 }
626
627 /*
628  *      Parse a memory block.
629  */
630 static struct allocblk *
631 memblk_tok(int force)
632 {
633         struct allocblk *mem;
634         int     i, j;
635
636         /* ignore the keyword to allow separete blocks in multiple lines */
637         if (keyword(next_tok()) != KWD_MEMORY) {
638                 pusht = 1;
639         }
640
641         if ((i = num_tok()) >= 0) {
642                 if ((j = num_tok()) < 0)
643                         error("illegal memory block");
644                 else {
645                         mem = xmalloc(sizeof(*mem));
646                         mem->addr = i & ~(MEMUNIT - 1);
647                         mem->size = (j + MEMUNIT - 1) & ~(MEMUNIT - 1);
648                         if (i < MEMSTART || (i + j) > MEMEND) {
649                                 error("memory address out of range");
650                                 if (force) {
651                                         free(mem);
652                                         mem = 0;
653                                 } else
654                                         mem->addr = mem->size = 0;
655                         }
656                         return (mem);
657                 }
658         }
659         if (force)
660                 error("illegal or missing memory block spec");
661         return (0);
662 }
663
664 /*
665  *      IRQ token. Must be number > 0 && < 16.
666  *      If force is set, IRQ must exist, and can also be '?'.
667  */
668 static int
669 irq_tok(int force)
670 {
671         int     i;
672
673         /* ignore the keyword to allow separete blocks in multiple lines */
674         if (keyword(next_tok()) != KWD_IRQ) {
675                 pusht = 1;
676         }
677
678         if (strcmp("?", next_tok()) == 0 && force)
679                 return (0);
680         pusht = 1;
681         i = num_tok();
682         if (i > 0 && i < 16)
683                 return (i);
684         if (force)
685                 error("illegal IRQ value");
686         return (-1);
687 }
688
689 /*
690  *      Config index token
691  */
692 static int
693 config_tok(unsigned char *index_type)
694 {
695         if (strcmp("default", next_tok()) == 0) {
696                 *index_type = DEFAULT_INDEX;
697                 return 0;
698         }
699         pusht = 1;
700         if (strcmp("auto", next_tok()) == 0) {
701                 *index_type = AUTO_INDEX;
702                 return 0;
703         }
704         pusht = 1;
705         *index_type = NORMAL_INDEX;
706         return num_tok();
707 }
708 /*
709  *      Function ID token
710  */
711 static int
712 func_tok(void)
713 {
714         if (strcmp("serial", next_tok()) == 0)  
715                 return 2;
716         pusht = 1;
717         if (strcmp("fixed_disk", next_tok()) == 0)      
718                 return 4;
719         pusht = 1;
720         return num_tok();
721 }
722
723
724 /*
725  *      debuglevel token. Must be between 0 and 9.
726  */
727 static int
728 debuglevel_tok(int force)
729 {
730         int     i;
731
732         i = num_tok();
733         if (i >= 0 && i <= 9)
734                 return (i);
735         return (-1);
736 }
737
738 /*
739  *      iosize token
740  *      iosize {<size>|auto}
741  */
742 static int
743 iosize_tok(void)
744 {
745         int iosize = 0;
746         if (strcmp("auto", next_tok()) == 0)
747                 iosize = -1;    /* wildcard */
748         else {
749                 pusht = 1;
750                 iosize = num_tok();
751                 if (iosize == -1)
752                         return 0;
753         }
754 #ifdef DEBUG
755         if (doverbose)
756                 printf("iosize: size=%x\n", iosize);
757 #endif
758         return iosize;
759 }
760
761
762 /*
763  *      search the table for a match.
764  */
765 static int
766 keyword(char *str)
767 {
768         char  **s;
769         int     i = 1;
770
771         for (s = keys; *s; s++, i++)
772                 if (strcmp(*s, str) == 0)
773                         return (i);
774
775         /* search keyword aliases too */
776         for (i = 0; key_aliases[i].key ; i++)
777                 if (strcmp(key_aliases[i].alias, str) == 0)
778                         return (key_aliases[i].key);
779
780         return (0);
781 }
782
783 /*
784  *      addcmd - Append the command line to the list of
785  *      commands.
786  */
787 static void
788 addcmd(struct cmd **cp)
789 {
790         struct cmd *ncp;
791         char   *s = getline();
792
793         if (*s) {
794                 ncp = xmalloc(sizeof(*ncp));
795                 ncp->line = s;
796                 while (*cp)
797                         cp = &(*cp)->next;
798                 *cp = ncp;
799         }
800
801 }
802
803 static void
804 error(char *msg)
805 {
806         pusht = 1;
807         logmsg("%s: %s at line %d, near %s\n",
808             filename, msg, lineno, next_tok());
809         pusht = 1;
810 }
811
812 static int     last_char;
813
814 static int
815 get(void)
816 {
817         int     c;
818
819         if (pushc)
820                 c = pushc;
821         else
822                 c = getc(in);
823         pushc = 0;
824         while (c == '\\') {
825                 c = getc(in);
826                 switch (c) {
827                 case '#':
828                         return (last_char = c);
829                 case '\n':
830                         lineno++;
831                         c = getc(in);
832                         continue;
833                 }
834                 pushc = c;
835                 return ('\\');
836         }
837         if (c == '\n')
838                 lineno++;
839         if (c == '#') 
840                 while (((c = get()) != '\n') && (c != EOF));
841         return (last_char = c);
842 }
843
844 /*
845  *      num_tok - expecting a number token. If not a number,
846  *      return -1.
847  *      Handles octal (who uses octal anymore?)
848  *              hex
849  *              decimal
850  *      Looks for a 'k' at the end of decimal numbers
851  *      and multiplies by 1024.
852  */
853 static int
854 num_tok(void)
855 {
856         char   *s = next_tok(), c;
857         int     val = 0, base;
858
859         base = 10;
860         c = *s++;
861         if (c == '0') {
862                 base = 8;
863                 c = *s++;
864                 if (c == '\0') return 0; 
865                 else if (c == 'x' || c == 'X') {
866                         c = *s++;
867                         base = 16;
868                 }
869         }
870         do {
871                 switch (c) {
872                 case 'k':
873                 case 'K':
874                         if (val && base == 10 && *s == 0)
875                                 return (val * 1024);
876                         return (-1);
877                 default:
878                         return (-1);
879                 case '0':
880                 case '1':
881                 case '2':
882                 case '3':
883                 case '4':
884                 case '5':
885                 case '6':
886                 case '7':
887                         val = val * base + c - '0';
888                         break;
889
890                 case '8':
891                 case '9':
892                         if (base == 8)
893                                 return (-1);
894                         else
895                                 val = val * base + c - '0';
896                         break;
897                 case 'a':
898                 case 'b':
899                 case 'c':
900                 case 'd':
901                 case 'e':
902                 case 'f':
903                         if (base == 16)
904                                 val = val * base + c - 'a' + 10;
905                         else
906                                 return (-1);
907                         break;
908                 case 'A':
909                 case 'B':
910                 case 'C':
911                 case 'D':
912                 case 'E':
913                 case 'F':
914                         if (base == 16)
915                                 val = val * base + c - 'A' + 10;
916                         else
917                                 return (-1);
918                         break;
919                 }
920         } while ((c = *s++) != 0);
921         return (val);
922 }
923
924 static char   *_next_tok(void);
925
926 static char *
927 next_tok(void)
928 {
929         char   *s = _next_tok();
930 #if 0
931         printf("Tok = %s\n", s);
932 #endif
933         return (s);
934 }
935
936 /*
937  *      get one token. Handles string quoting etc.
938  */
939 static char *
940 _next_tok(void)
941 {
942         static char buf[1024];
943         char   *p = buf, instr = 0;
944         int     c;
945
946         if (pusht) {
947                 pusht = 0;
948                 return (buf);
949         }
950         for (;;) {
951                 c = get();
952                 switch (c) {
953                 default:
954                         *p++ = c;
955                         break;
956                 case '"':
957                         if (instr) {
958                                 *p++ = 0;
959                                 return (buf);
960                         }
961                         instr = 1;
962                         break;
963                 case '\n':
964                         if (instr) {
965                                 error("unterminated string");
966                                 break;
967                         }
968                 case ' ':
969                 case '\t':
970                         /* Eat whitespace unless in a string. */
971                         if (!instr) {
972                                 if (p != buf) {
973                                         *p++ = 0;
974                                         return (buf);
975                                 }
976                         } else
977                                 *p++ = c;
978                         break;
979                 case '-':
980                 case '?':
981                 case '*':
982                         /* Special characters that are tokens on their own. */
983                         if (instr)
984                                 *p++ = c;
985                         else {
986                                 if (p != buf)
987                                         pushc = c;
988                                 else
989                                         *p++ = c;
990                                 *p++ = 0;
991                                 return (buf);
992                         }
993                         break;
994                 case EOF:
995                         if (includes) {
996                                 fclose(in);
997                                 /* go back to previous config file */
998                                 includes--;
999                                 in = configfiles[includes].filep;
1000                                 filename = configfiles[includes].filename;
1001                                 lineno = configfiles[includes].lineno;
1002                                 return _next_tok();     /* recursive */
1003                         }
1004                         if (p != buf) {
1005                                 *p++ = 0;
1006                                 return (buf);
1007                         }
1008                         strcpy(buf, "__EOF__");
1009                         return (buf);
1010                 }
1011         }
1012 }
1013
1014 /*
1015  *      get the rest of the line. If the
1016  *      last character scanned was a newline, then
1017  *      return an empty line. If this isn't checked, then
1018  *      a getline may incorrectly return the next line.
1019  */
1020 static char *
1021 getline(void)
1022 {
1023         char    buf[1024], *p = buf;
1024         int     c, i = 0;
1025
1026         if (last_char == '\n')
1027                 return (newstr(""));
1028         do {
1029                 c = get();
1030         } while (c == ' ' || c == '\t');
1031         for (; c != '\n' && c != EOF; c = get())
1032                 if (i++ < sizeof(buf) - 10)
1033                         *p++ = c;
1034         *p = 0;
1035         return (newstr(buf));
1036 }
1037
1038 /*
1039  *      Include configuration file
1040  */
1041 static void
1042 file_include(char *incl)
1043 {
1044         int     i, included;
1045         FILE    *fp;
1046
1047         /* check nesting overflow */
1048         if (includes >= MAXINCLUDES) {
1049                 if (debug_level >= 1) {
1050                         logmsg("%s: include nesting overflow "
1051                             "at line %d, near %s\n", filename, lineno, incl);
1052                 }
1053                 free(incl);
1054                 goto out;
1055         }
1056
1057         /* check recursive inclusion */
1058         for (i = 0, included = 0; i <= includes; i++) {
1059                 if (strcmp(incl, configfiles[i].filename) == 0) {
1060                         included = 1;
1061                         break;
1062                 }
1063         }
1064         if (included == 1) {
1065                 if (debug_level >= 1) {
1066                         logmsg("%s: can't include the same file twice "
1067                             "at line %d, near %s\n", filename, lineno, incl);
1068                 }
1069                 free(incl);
1070                 goto out;
1071         }
1072
1073         if (!(fp = fopen(incl, "r"))) {
1074                 if (debug_level >= 1) {
1075                         logmsg("%s: can't open include file "
1076                             "at line %d, near %s\n", filename, lineno, incl);
1077                 }
1078                 free(incl);
1079                 goto out;
1080         }
1081
1082         /* save line number of the current config file */
1083         configfiles[includes].lineno = lineno;
1084         lineno = 1;
1085
1086         /* now we start parsing new config file */
1087         includes++;
1088         in = configfiles[includes].filep = fp;
1089         filename = configfiles[includes].filename = incl;
1090 out:
1091         return;
1092 }