- Ansify function definitions.
[dragonfly.git] / usr.sbin / ndiscvt / inf.c
1 /*
2  * Copyright (c) 2003
3  *      Bill Paul <wpaul@windriver.com>.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by Bill Paul.
16  * 4. Neither the name of the author nor the names of any co-contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30  * THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  * $DragonFly: src/usr.sbin/ndiscvt/inf.c,v 1.2 2005/12/05 02:40:27 swildner Exp $
33  */
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <sys/types.h>
39
40 #include <sys/queue.h>
41
42 #include "inf.h"
43
44 extern FILE *yyin;
45 int yyparse (void);
46
47 const char *words[W_MAX];       /* More than we'll need. */
48 int idx;
49
50 static struct section_head sh;
51 static struct reg_head rh;
52 static struct assign_head ah;
53
54 static char     *sstrdup        (const char *);
55 static struct assign
56                 *find_assign    (const char *, const char *);
57 static struct section
58                 *find_section   (const char *);
59 static void     dump_deviceids_pci      (void);
60 static void     dump_deviceids_pcmcia   (void);
61 static void     dump_pci_id     (const char *);
62 static void     dump_pcmcia_id  (const char *);
63 static void     dump_regvals    (void);
64 static void     dump_paramreg   (const struct section *,
65                                 const struct reg *, int);
66
67 static FILE     *ofp;
68
69 int
70 inf_parse(FILE *fp, FILE *outfp)
71 {
72         TAILQ_INIT(&sh);
73         TAILQ_INIT(&rh);
74         TAILQ_INIT(&ah);
75
76         ofp = outfp;
77         yyin = fp;
78         yyparse();
79
80         dump_deviceids_pci();
81         dump_deviceids_pcmcia();
82         fprintf(outfp, "#ifdef NDIS_REGVALS\n");
83         dump_regvals();
84         fprintf(outfp, "#endif /* NDIS_REGVALS */\n");
85
86         return (0);
87 }
88
89 void
90 section_add(const char *s)
91 {
92         struct section *sec;
93
94         sec = malloc(sizeof(struct section));
95         bzero(sec, sizeof(struct section));
96         sec->name = s;
97         TAILQ_INSERT_TAIL(&sh, sec, link);
98
99         return;
100 }
101
102 static struct assign *
103 find_assign(const char *s, const char *k)
104 {
105         struct assign *assign;
106         char newkey[256];
107
108         /* Deal with string section lookups. */
109
110         if (k != NULL && k[0] == '%') {
111                 bzero(newkey, sizeof(newkey));
112                 strncpy(newkey, k + 1, strlen(k) - 2);
113                 k = newkey;
114         }
115
116         TAILQ_FOREACH(assign, &ah, link) {
117                 if (strcasecmp(assign->section->name, s) == 0) {
118                         if (k == NULL)
119                                 return(assign);
120                         else
121                                 if (strcasecmp(assign->key, k) == 0)
122                                         return(assign);
123                 }
124         }
125         return(NULL);
126 }
127
128 static const char *
129 stringcvt(const char *s)
130 {
131         struct assign *manf;
132
133         manf = find_assign("strings", s);
134         if (manf == NULL)
135                 return(s);
136         return(manf->vals[0]);
137 }
138
139 struct section *
140 find_section(const char *s)
141 {
142         struct section *section;
143
144         TAILQ_FOREACH(section, &sh, link) {
145                 if (strcasecmp(section->name, s) == 0)
146                         return(section);
147         }
148         return(NULL);
149 }
150
151 static void
152 dump_pcmcia_id(const char *s)
153 {
154         char *manstr, *devstr;
155         char *p0, *p;
156
157         p0 = __DECONST(char *, s);
158
159         p = strchr(p0, '\\');
160         if (p == NULL)
161                 return;
162         p0 = p + 1;
163
164         p = strchr(p0, '-');
165         if (p == NULL)
166                 return;
167         *p = '\0';
168
169         manstr = p0;
170
171         /* Convert any underscores to spaces. */
172
173         while (*p0 != '\0') {
174                 if (*p0 == '_')
175                         *p0 = ' ';
176                 p0++;
177         }
178
179         p0 = p + 1;
180         p = strchr(p0, '-');
181         if (p == NULL)
182                 return;
183         *p = '\0';
184
185         devstr = p0;
186
187         /* Convert any underscores to spaces. */
188
189         while (*p0 != '\0') {
190                 if (*p0 == '_')
191                         *p0 = ' ';
192                 p0++;
193         }
194
195         fprintf(ofp, "\t\\\n\t{ \"%s\", \"%s\", ", manstr, devstr);
196         return;
197 }
198
199 static void
200 dump_pci_id(const char *s)
201 {
202         char *p;
203         char vidstr[7], didstr[7], subsysstr[14];
204
205         p = strcasestr(s, "VEN_");
206         if (p == NULL)
207                 return;
208         p += 4;
209         strcpy(vidstr, "0x");
210         strncat(vidstr, p, 4);
211         p = strcasestr(s, "DEV_");
212         if (p == NULL)
213                 return;
214         p += 4;
215         strcpy(didstr, "0x");
216         strncat(didstr, p, 4);
217         if (p == NULL)
218                 return;
219         p = strcasestr(s, "SUBSYS_");
220         if (p == NULL)
221                 strcpy(subsysstr, "0x00000000");
222         else {
223                 p += 7;
224                 strcpy(subsysstr, "0x");
225                 strncat(subsysstr, p, 8);
226         }
227
228         fprintf(ofp, "\t\\\n\t{ %s, %s, %s, ", vidstr, didstr, subsysstr);
229         return;
230 }
231
232 static void
233 dump_deviceids_pci(void)
234 {
235         struct assign *manf, *dev;
236         struct section *sec;
237         struct assign *assign;
238         char xpsec[256];
239         int found = 0;
240
241         /* Find manufacturer name */
242         manf = find_assign("Manufacturer", NULL);
243
244         /* Find manufacturer section */
245         if (manf->vals[1] != NULL &&
246             (strcasecmp(manf->vals[1], "NT.5.1") == 0 ||
247             strcasecmp(manf->vals[1], "NTx86") == 0 ||
248             strcasecmp(manf->vals[1], "NTx86.5.1") == 0)) {
249                 /* Handle Windows XP INF files. */
250                 snprintf(xpsec, sizeof(xpsec), "%s.%s",
251                     manf->vals[0], manf->vals[1]);
252                 sec = find_section(xpsec);
253         } else
254                 sec = find_section(manf->vals[0]);
255
256         /* See if there are any PCI device definitions. */
257
258         TAILQ_FOREACH(assign, &ah, link) {
259                 if (assign->section == sec) {
260                         dev = find_assign("strings", assign->key);
261                         if (strcasestr(assign->vals[1], "PCI") != NULL) {
262                                 found++;
263                                 break;
264                         }
265                 }
266         }
267
268         if (found == 0)
269                 return;
270
271         found = 0;
272
273         /* Emit start of PCI device table */
274         fprintf (ofp, "#define NDIS_PCI_DEV_TABLE");
275
276 retry:
277
278         /*
279          * Now run through all the device names listed
280          * in the manufacturer section and dump out the
281          * device descriptions and vendor/device IDs.
282          */
283
284         TAILQ_FOREACH(assign, &ah, link) {
285                 if (assign->section == sec) {
286                         dev = find_assign("strings", assign->key);
287                         /* Emit device IDs. */
288                         if (strcasestr(assign->vals[1], "PCI") != NULL)
289                                 dump_pci_id(assign->vals[1]);
290                         else
291                                 continue;
292                         /* Emit device description */
293                         fprintf (ofp, "\t\\\n\t\"%s\" },", dev->vals[0]);
294                         found++;
295                 }
296         }
297
298         /* Someone tried to fool us. Shame on them. */
299         if (!found) {
300                 found++;
301                 sec = find_section(manf->vals[0]);
302                 goto retry;
303         }
304
305         /* Emit end of table */
306
307         fprintf(ofp, "\n\n");
308
309 }
310
311 static void
312 dump_deviceids_pcmcia(void)
313 {
314         struct assign *manf, *dev;
315         struct section *sec;
316         struct assign *assign;
317         char xpsec[256];
318         int found = 0;
319
320         /* Find manufacturer name */
321         manf = find_assign("Manufacturer", NULL);
322
323         /* Find manufacturer section */
324         if (manf->vals[1] != NULL &&
325             (strcasecmp(manf->vals[1], "NT.5.1") == 0 ||
326             strcasecmp(manf->vals[1], "NTx86") == 0 ||
327             strcasecmp(manf->vals[1], "NTx86.5.1") == 0)) {
328                 /* Handle Windows XP INF files. */
329                 snprintf(xpsec, sizeof(xpsec), "%s.%s",
330                     manf->vals[0], manf->vals[1]);
331                 sec = find_section(xpsec);
332         } else
333                 sec = find_section(manf->vals[0]);
334
335         /* See if there are any PCMCIA device definitions. */
336
337         TAILQ_FOREACH(assign, &ah, link) {
338                 if (assign->section == sec) {
339                         dev = find_assign("strings", assign->key);
340                         if (strcasestr(assign->vals[1], "PCMCIA") != NULL) {
341                                 found++;
342                                 break;
343                         }
344                 }
345         }
346
347         if (found == 0)
348                 return;
349
350         found = 0;
351
352         /* Emit start of PCMCIA device table */
353         fprintf (ofp, "#define NDIS_PCMCIA_DEV_TABLE");
354
355 retry:
356
357         /*
358          * Now run through all the device names listed
359          * in the manufacturer section and dump out the
360          * device descriptions and vendor/device IDs.
361          */
362
363         TAILQ_FOREACH(assign, &ah, link) {
364                 if (assign->section == sec) {
365                         dev = find_assign("strings", assign->key);
366                         /* Emit device IDs. */
367                         if (strcasestr(assign->vals[1], "PCMCIA") != NULL)
368                                 dump_pcmcia_id(assign->vals[1]);
369                         else
370                                 continue;
371                         /* Emit device description */
372                         fprintf (ofp, "\t\\\n\t\"%s\" },", dev->vals[0]);
373                         found++;
374                 }
375         }
376
377         /* Someone tried to fool us. Shame on them. */
378         if (!found) {
379                 found++;
380                 sec = find_section(manf->vals[0]);
381                 goto retry;
382         }
383
384         /* Emit end of table */
385
386         fprintf(ofp, "\n\n");
387
388 }
389
390 static void
391 dump_addreg(const char *s, int devidx)
392 {
393         struct section *sec;
394         struct reg *reg;
395
396         /* Find the addreg section */
397         sec = find_section(s);
398
399         /* Dump all the keys defined in it. */
400         TAILQ_FOREACH(reg, &rh, link) {
401                 /*
402                  * Keys with an empty subkey are very easy to parse,
403                  * so just deal with them here. If a parameter key
404                  * of the same name also exists, prefer that one and
405                  * skip this one.
406                  */
407                 if (reg->section == sec) {
408                         if (reg->subkey == NULL) {
409                                 fprintf(ofp, "\n\t{ \"%s\",", reg->key);
410                                 fprintf(ofp,"\n\t\"%s \",", reg->key);
411                                 fprintf(ofp, "\n\t{ \"%s\" }, %d },",
412                                     reg->value == NULL ? "" :
413                                     stringcvt(reg->value), devidx);
414                         } else if (strncasecmp(reg->subkey,
415                             "Ndi\\params", strlen("Ndi\\params")-1) == 0 &&
416                             (reg->key != NULL && strcasecmp(reg->key,
417                             "ParamDesc") == 0))
418                                 dump_paramreg(sec, reg, devidx);
419                 }
420         }
421
422         return;
423 }
424
425 static void
426 dump_enumreg(const struct section *s, const struct reg *r)
427 {
428         struct reg *reg;
429         char enumkey[256];
430
431         sprintf(enumkey, "%s\\enum", r->subkey);
432         TAILQ_FOREACH(reg, &rh, link) {
433                 if (reg->section != s)
434                         continue;
435                 if (reg->subkey == NULL || strcasecmp(reg->subkey, enumkey))
436                         continue;
437                 fprintf(ofp, " [%s=%s]", reg->key,
438                     stringcvt(reg->value));
439         }
440         return;
441 }
442
443 static void
444 dump_editreg(const struct section *s, const struct reg *r)
445 {
446         struct reg *reg;
447
448         TAILQ_FOREACH(reg, &rh, link) {
449                 if (reg->section != s)
450                         continue;
451                 if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
452                         continue;
453                 if (reg->key == NULL)
454                         continue;
455                 if (strcasecmp(reg->key, "LimitText") == 0)
456                         fprintf(ofp, " [maxchars=%s]", reg->value);
457                 if (strcasecmp(reg->key, "Optional") == 0 &&
458                     strcmp(reg->value, "1") == 0)
459                         fprintf(ofp, " [optional]");
460         }
461         return;
462 }
463
464 /* Use this for int too */
465 static void
466 dump_dwordreg(const struct section *s, const struct reg *r)
467 {
468         struct reg *reg;
469
470         TAILQ_FOREACH(reg, &rh, link) {
471                 if (reg->section != s)
472                         continue;
473                 if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
474                         continue;
475                 if (reg->key == NULL)
476                         continue;
477                 if (strcasecmp(reg->key, "min") == 0)
478                         fprintf(ofp, " [min=%s]", reg->value);
479                 if (strcasecmp(reg->key, "max") == 0)
480                         fprintf(ofp, " [max=%s]", reg->value);
481         }
482         return;
483 }
484
485 static void
486 dump_defaultinfo(const struct section *s, const struct reg *r, int devidx)
487 {
488         struct reg *reg;
489         TAILQ_FOREACH(reg, &rh, link) {
490                 if (reg->section != s)
491                         continue;
492                 if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
493                         continue;
494                 if (reg->key == NULL || strcasecmp(reg->key, "Default"))
495                         continue;
496                 fprintf(ofp, "\n\t{ \"%s\" }, %d },", reg->value == NULL ? "" :
497                     stringcvt(reg->value), devidx);
498                         break;
499         }
500         return;
501 }
502
503 static void
504 dump_paramdesc(const struct section *s, const struct reg *r)
505 {
506         struct reg *reg;
507         TAILQ_FOREACH(reg, &rh, link) {
508                 if (reg->section != s)
509                         continue;
510                 if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
511                         continue;
512                 if (reg->key == NULL || strcasecmp(reg->key, "ParamDesc"))
513                         continue;
514                 fprintf(ofp, "\n\t\"%s", stringcvt(r->value));
515                         break;
516         }
517         return;
518 }
519
520 static void
521 dump_typeinfo(const struct section *s, const struct reg *r)
522 {
523         struct reg *reg;
524         TAILQ_FOREACH(reg, &rh, link) {
525                 if (reg->section != s)
526                         continue;
527                 if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
528                         continue;
529                 if (reg->key == NULL)
530                         continue;
531                 if (strcasecmp(reg->key, "type"))
532                         continue;
533                 if (strcasecmp(reg->value, "dword") == 0 ||
534                     strcasecmp(reg->value, "int") == 0)
535                         dump_dwordreg(s, r);
536                 if (strcasecmp(reg->value, "enum") == 0)
537                         dump_enumreg(s, r);
538                 if (strcasecmp(reg->value, "edit") == 0)
539                         dump_editreg(s, r);
540         }
541         return;
542 }
543
544 static void
545 dump_paramreg(const struct section *s, const struct reg *r, int devidx)
546 {
547         const char *keyname;
548
549         keyname = r->subkey + strlen("Ndi\\params\\");
550         fprintf(ofp, "\n\t{ \"%s\",", keyname);
551         dump_paramdesc(s, r);
552         dump_typeinfo(s, r);
553         fprintf(ofp, "\",");
554         dump_defaultinfo(s, r, devidx);
555
556         return;
557 }
558
559 static void
560 dump_regvals(void)
561 {
562         struct assign *manf, *dev;
563         struct section *sec;
564         struct assign *assign;
565         char sname[256];
566         int found = 0, i, is_winxp = 0, is_winnt = 0, devidx = 0;
567
568         /* Find signature to check for special case of WinNT. */
569         assign = find_assign("version", "signature");
570         if (strcasecmp(assign->vals[0], "$windows nt$") == 0)
571                 is_winnt++;
572
573         /* Find manufacturer name */
574         manf = find_assign("Manufacturer", NULL);
575
576         /* Find manufacturer section */
577         if (manf->vals[1] != NULL &&
578             (strcasecmp(manf->vals[1], "NT.5.1") == 0 ||
579             strcasecmp(manf->vals[1], "NTx86") == 0 ||
580             strcasecmp(manf->vals[1], "NTx86.5.1") == 0)) {
581                 is_winxp++;
582                 /* Handle Windows XP INF files. */
583                 snprintf(sname, sizeof(sname), "%s.%s",
584                     manf->vals[0], manf->vals[1]);
585                 sec = find_section(sname);
586         } else
587                 sec = find_section(manf->vals[0]);
588
589         /* Emit start of block */
590         fprintf (ofp, "ndis_cfg ndis_regvals[] = {");
591
592 retry:
593
594         TAILQ_FOREACH(assign, &ah, link) {
595                 if (assign->section == sec) {
596                         found++;
597                         /*
598                          * Find all the AddReg sections.
599                          * Look for section names with .NT, unless
600                          * this is a WinXP .INF file.
601                          */
602                         if (is_winxp) {
603                                 sprintf(sname, "%s.NTx86", assign->vals[0]);
604                                 dev = find_assign(sname, "AddReg");
605                                 if (dev == NULL)
606                                         dev = find_assign(assign->vals[0],
607                                             "AddReg");
608                         } else {
609                                 sprintf(sname, "%s.NT", assign->vals[0]);
610                                 dev = find_assign(sname, "AddReg");
611                                 if (dev == NULL && is_winnt)
612                                         dev = find_assign(assign->vals[0],
613                                             "AddReg");
614                         }
615                         /* Section not found. */
616                         if (dev == NULL)
617                                 continue;
618                         for (i = 0; i < W_MAX; i++) {
619                                 if (dev->vals[i] != NULL)
620                                         dump_addreg(dev->vals[i], devidx);
621                         }
622                         devidx++;
623                 }
624         }
625
626         if (!found) {
627                 sec = find_section(manf->vals[0]);
628                 is_winxp = 0;
629                 found++;
630                 goto retry;
631         }
632
633         fprintf(ofp, "\n\t{ NULL, NULL, { 0 }, 0 }\n};\n\n");
634
635         return;
636 }
637
638 void
639 assign_add(const char *a)
640 {
641         struct assign *assign;
642         int i;
643
644         assign = malloc(sizeof(struct assign));
645         bzero(assign, sizeof(struct assign));
646         assign->section = TAILQ_LAST(&sh, section_head);
647         assign->key = sstrdup(a);
648         for (i = 0; i < idx; i++)
649                 assign->vals[(idx - 1) - i] = sstrdup(words[i]);
650         TAILQ_INSERT_TAIL(&ah, assign, link);
651
652         clear_words();
653         return;
654 }
655
656 void
657 define_add(const char *d __unused)
658 {
659 #ifdef notdef
660         fprintf(stderr, "define \"%s\"\n", d);
661 #endif
662         return;
663 }
664
665 static char *
666 sstrdup(const char *str)
667 {
668         if (str != NULL && strlen(str))
669                 return (strdup(str));
670         return (NULL);
671 }
672
673 static int
674 satoi(const char *nptr)
675 {
676         if (nptr != NULL && strlen(nptr))
677                 return (atoi(nptr));
678         return (0);
679 }
680
681 void
682 regkey_add(const char *r)
683 {
684         struct reg *reg;
685
686         reg = malloc(sizeof(struct reg));
687         bzero(reg, sizeof(struct reg));
688         reg->section = TAILQ_LAST(&sh, section_head);
689         reg->root = sstrdup(r);
690         reg->subkey = sstrdup(words[3]);
691         reg->key = sstrdup(words[2]);
692         reg->flags = satoi(words[1]);
693         reg->value = sstrdup(words[0]);
694         TAILQ_INSERT_TAIL(&rh, reg, link);
695
696         free(__DECONST(char *, r));
697         clear_words();
698         return;
699 }
700
701 void
702 push_word(const char *w)
703 {
704         if (w && strlen(w))
705                 words[idx++] = w;
706         else
707                 words[idx++] = NULL;
708         return;
709 }
710
711 void
712 clear_words(void)
713 {
714         int i;
715
716         for (i = 0; i < idx; i++) {
717                 if (words[i]) {
718                         free(__DECONST(char *, words[i]));
719                 }
720         }
721         idx = 0;
722         bzero(words, sizeof(words));
723         return;
724 }