]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - usr.sbin/ndiscvt/inf.c
MFC r343576:
[FreeBSD/stable/10.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
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sys/types.h>
40
41 #include <sys/queue.h>
42
43 #include "inf.h"
44
45 extern FILE *yyin;
46 int yyparse (void);
47
48 const char *words[W_MAX];       /* More than we'll need. */
49 int idx;
50
51 static struct section_head sh;
52 static struct reg_head rh;
53 static struct assign_head ah;
54
55 static char     *sstrdup        (const char *);
56 static struct assign
57                 *find_assign    (const char *, const char *);
58 static struct assign
59                 *find_next_assign
60                                 (struct assign *);
61 static struct section
62                 *find_section   (const char *);
63 static int      dump_deviceids_pci      (void);
64 static int      dump_deviceids_pcmcia   (void);
65 static int      dump_deviceids_usb      (void);
66 static void     dump_pci_id     (const char *);
67 static void     dump_pcmcia_id  (const char *);
68 static void     dump_usb_id     (const char *);
69 static void     dump_regvals    (void);
70 static void     dump_paramreg   (const struct section *,
71                                 const struct reg *, int);
72
73 static FILE     *ofp;
74
75 int
76 inf_parse (FILE *fp, FILE *outfp)
77 {
78         TAILQ_INIT(&sh);
79         TAILQ_INIT(&rh);
80         TAILQ_INIT(&ah);
81
82         ofp = outfp;
83         yyin = fp;
84         yyparse();
85
86         if (dump_deviceids_pci() == 0 &&
87             dump_deviceids_pcmcia() == 0 &&
88             dump_deviceids_usb() == 0)
89                 return (-1);
90
91         fprintf(outfp, "#ifdef NDIS_REGVALS\n");
92         dump_regvals();
93         fprintf(outfp, "#endif /* NDIS_REGVALS */\n");
94
95         return (0);
96 }
97
98 void
99 section_add (const char *s)
100 {
101         struct section *sec;
102
103         sec = malloc(sizeof(struct section));
104         bzero(sec, sizeof(struct section));
105         sec->name = s;
106         TAILQ_INSERT_TAIL(&sh, sec, link);
107
108         return;
109 }
110
111 static struct assign *
112 find_assign (const char *s, const char *k)
113 {
114         struct assign *assign;
115         char newkey[256];
116
117         /* Deal with string section lookups. */
118
119         if (k != NULL && k[0] == '%') {
120                 bzero(newkey, sizeof(newkey));
121                 strncpy(newkey, k + 1, strlen(k) - 2);
122                 k = newkey;
123         }
124
125         TAILQ_FOREACH(assign, &ah, link) {
126                 if (strcasecmp(assign->section->name, s) == 0) {
127                         if (k == NULL)
128                                 return(assign);
129                         else
130                                 if (strcasecmp(assign->key, k) == 0)
131                                         return(assign);
132                 }
133         }
134         return(NULL);
135 }
136
137 static struct assign *
138 find_next_assign (struct assign *a)
139 {
140         struct assign *assign;
141
142         TAILQ_FOREACH(assign, &ah, link) {
143                 if (assign == a)
144                         break;
145         }
146
147         assign = assign->link.tqe_next;
148
149         if (assign == NULL || assign->section != a->section)
150                 return(NULL);
151
152         return (assign);
153 }
154
155 static const char *
156 stringcvt(const char *s)
157 {
158         struct assign *manf;
159
160         manf = find_assign("strings", s);
161         if (manf == NULL)
162                 return(s);
163         return(manf->vals[0]);
164 }
165
166 struct section *
167 find_section (const char *s)
168 {
169         struct section *section;
170
171         TAILQ_FOREACH(section, &sh, link) {
172                 if (strcasecmp(section->name, s) == 0)
173                         return(section);
174         }
175         return(NULL);
176 }
177
178 static void
179 dump_pcmcia_id(const char *s)
180 {
181         char *manstr, *devstr;
182         char *p0, *p;
183
184         p0 = __DECONST(char *, s);
185
186         p = strchr(p0, '\\');
187         if (p == NULL)
188                 return;
189         p0 = p + 1;
190
191         p = strchr(p0, '-');
192         if (p == NULL)
193                 return;
194         *p = '\0';
195
196         manstr = p0;
197
198         /* Convert any underscores to spaces. */
199
200         while (*p0 != '\0') {
201                 if (*p0 == '_')
202                         *p0 = ' ';
203                 p0++;
204         }
205
206         p0 = p + 1;
207         p = strchr(p0, '-');
208         if (p == NULL)
209                 return;
210         *p = '\0';
211
212         devstr = p0;
213
214         /* Convert any underscores to spaces. */
215
216         while (*p0 != '\0') {
217                 if (*p0 == '_')
218                         *p0 = ' ';
219                 p0++;
220         }
221
222         fprintf(ofp, "\t\\\n\t{ \"%s\", \"%s\", ", manstr, devstr);
223         return;
224 }
225
226 static void
227 dump_pci_id(const char *s)
228 {
229         char *p;
230         char vidstr[7], didstr[7], subsysstr[14];
231
232         p = strcasestr(s, "VEN_");
233         if (p == NULL)
234                 return;
235         p += 4;
236         strcpy(vidstr, "0x");
237         strncat(vidstr, p, 4);
238         p = strcasestr(s, "DEV_");
239         if (p == NULL)
240                 return;
241         p += 4;
242         strcpy(didstr, "0x");
243         strncat(didstr, p, 4);
244         if (p == NULL)
245                 return;
246         p = strcasestr(s, "SUBSYS_");
247         if (p == NULL)
248                 strcpy(subsysstr, "0x00000000");
249         else {
250                 p += 7;
251                 strcpy(subsysstr, "0x");
252                 strncat(subsysstr, p, 8);
253         }
254
255         fprintf(ofp, "\t\\\n\t{ %s, %s, %s, ", vidstr, didstr, subsysstr);
256         return;
257 }
258
259 static void
260 dump_usb_id(const char *s)
261 {
262         char *p;
263         char vidstr[7], pidstr[7];
264
265         p = strcasestr(s, "VID_");
266         if (p == NULL)
267                 return;
268         p += 4;
269         strcpy(vidstr, "0x");
270         strncat(vidstr, p, 4);
271         p = strcasestr(s, "PID_");
272         if (p == NULL)
273                 return;
274         p += 4;
275         strcpy(pidstr, "0x");
276         strncat(pidstr, p, 4);
277         if (p == NULL)
278                 return;
279
280         fprintf(ofp, "\t\\\n\t{ %s, %s, ", vidstr, pidstr);
281 }
282
283 static int
284 dump_deviceids_pci()
285 {
286         struct assign *manf, *dev;
287         struct section *sec;
288         struct assign *assign;
289         char xpsec[256];
290         int first = 1, found = 0;
291
292         /* Find manufacturer name */
293         manf = find_assign("Manufacturer", NULL);
294
295 nextmanf:
296
297         /* Find manufacturer section */
298         if (manf->vals[1] != NULL &&
299             (strcasecmp(manf->vals[1], "NT.5.1") == 0 ||
300             strcasecmp(manf->vals[1], "NTx86") == 0 ||
301             strcasecmp(manf->vals[1], "NTx86.5.1") == 0 ||
302             strcasecmp(manf->vals[1], "NTamd64") == 0)) {
303                 /* Handle Windows XP INF files. */
304                 snprintf(xpsec, sizeof(xpsec), "%s.%s",
305                     manf->vals[0], manf->vals[1]);
306                 sec = find_section(xpsec);
307         } else
308                 sec = find_section(manf->vals[0]);
309
310         /* See if there are any PCI device definitions. */
311
312         TAILQ_FOREACH(assign, &ah, link) {
313                 if (assign->section == sec) {
314                         dev = find_assign("strings", assign->key);
315                         if (strcasestr(assign->vals[1], "PCI") != NULL) {
316                                 found++;
317                                 break;
318                         }
319                 }
320         }
321
322         if (found == 0)
323                 goto done;
324
325         found = 0;
326
327         if (first == 1) {
328                 /* Emit start of PCI device table */
329                 fprintf (ofp, "#define NDIS_PCI_DEV_TABLE");
330                 first = 0;
331         }
332
333 retry:
334
335         /*
336          * Now run through all the device names listed
337          * in the manufacturer section and dump out the
338          * device descriptions and vendor/device IDs.
339          */
340
341         TAILQ_FOREACH(assign, &ah, link) {
342                 if (assign->section == sec) {
343                         dev = find_assign("strings", assign->key);
344                         /* Emit device IDs. */
345                         if (strcasestr(assign->vals[1], "PCI") != NULL)
346                                 dump_pci_id(assign->vals[1]);
347                         else
348                                 continue;
349                         /* Emit device description */
350                         fprintf (ofp, "\t\\\n\t\"%s\" },", dev->vals[0]);
351                         found++;
352                 }
353         }
354
355         /* Someone tried to fool us. Shame on them. */
356         if (!found) {
357                 found++;
358                 sec = find_section(manf->vals[0]);
359                 goto retry;
360         }
361
362         /* Handle Manufacturer sections with multiple entries. */
363         manf = find_next_assign(manf);
364
365         if (manf != NULL)
366                 goto nextmanf;
367
368 done:
369         /* Emit end of table */
370
371         fprintf(ofp, "\n\n");
372
373         return (found);
374 }
375
376 static int
377 dump_deviceids_pcmcia()
378 {
379         struct assign *manf, *dev;
380         struct section *sec;
381         struct assign *assign;
382         char xpsec[256];
383         int first = 1, found = 0;
384
385         /* Find manufacturer name */
386         manf = find_assign("Manufacturer", NULL);
387
388 nextmanf:
389
390         /* Find manufacturer section */
391         if (manf->vals[1] != NULL &&
392             (strcasecmp(manf->vals[1], "NT.5.1") == 0 ||
393             strcasecmp(manf->vals[1], "NTx86") == 0 ||
394             strcasecmp(manf->vals[1], "NTx86.5.1") == 0 ||
395             strcasecmp(manf->vals[1], "NTamd64") == 0)) {
396                 /* Handle Windows XP INF files. */
397                 snprintf(xpsec, sizeof(xpsec), "%s.%s",
398                     manf->vals[0], manf->vals[1]);
399                 sec = find_section(xpsec);
400         } else
401                 sec = find_section(manf->vals[0]);
402
403         /* See if there are any PCMCIA device definitions. */
404
405         TAILQ_FOREACH(assign, &ah, link) {
406                 if (assign->section == sec) {
407                         dev = find_assign("strings", assign->key);
408                         if (strcasestr(assign->vals[1], "PCMCIA") != NULL) {
409                                 found++;
410                                 break;
411                         }
412                 }
413         }
414
415         if (found == 0)
416                 goto done;
417
418         found = 0;
419
420         if (first == 1) {
421                 /* Emit start of PCMCIA device table */
422                 fprintf (ofp, "#define NDIS_PCMCIA_DEV_TABLE");
423                 first = 0;
424         }
425
426 retry:
427
428         /*
429          * Now run through all the device names listed
430          * in the manufacturer section and dump out the
431          * device descriptions and vendor/device IDs.
432          */
433
434         TAILQ_FOREACH(assign, &ah, link) {
435                 if (assign->section == sec) {
436                         dev = find_assign("strings", assign->key);
437                         /* Emit device IDs. */
438                         if (strcasestr(assign->vals[1], "PCMCIA") != NULL)
439                                 dump_pcmcia_id(assign->vals[1]);
440                         else
441                                 continue;
442                         /* Emit device description */
443                         fprintf (ofp, "\t\\\n\t\"%s\" },", dev->vals[0]);
444                         found++;
445                 }
446         }
447
448         /* Someone tried to fool us. Shame on them. */
449         if (!found) {
450                 found++;
451                 sec = find_section(manf->vals[0]);
452                 goto retry;
453         }
454
455         /* Handle Manufacturer sections with multiple entries. */
456         manf = find_next_assign(manf);
457
458         if (manf != NULL)
459                 goto nextmanf;
460
461 done:
462         /* Emit end of table */
463
464         fprintf(ofp, "\n\n");
465
466         return (found);
467 }
468
469 static int
470 dump_deviceids_usb()
471 {
472         struct assign *manf, *dev;
473         struct section *sec;
474         struct assign *assign;
475         char xpsec[256];
476         int first = 1, found = 0;
477
478         /* Find manufacturer name */
479         manf = find_assign("Manufacturer", NULL);
480
481 nextmanf:
482
483         /* Find manufacturer section */
484         if (manf->vals[1] != NULL &&
485             (strcasecmp(manf->vals[1], "NT.5.1") == 0 ||
486             strcasecmp(manf->vals[1], "NTx86") == 0 ||
487             strcasecmp(manf->vals[1], "NTx86.5.1") == 0 ||
488             strcasecmp(manf->vals[1], "NTamd64") == 0)) {
489                 /* Handle Windows XP INF files. */
490                 snprintf(xpsec, sizeof(xpsec), "%s.%s",
491                     manf->vals[0], manf->vals[1]);
492                 sec = find_section(xpsec);
493         } else
494                 sec = find_section(manf->vals[0]);
495
496         /* See if there are any USB device definitions. */
497
498         TAILQ_FOREACH(assign, &ah, link) {
499                 if (assign->section == sec) {
500                         dev = find_assign("strings", assign->key);
501                         if (strcasestr(assign->vals[1], "USB") != NULL) {
502                                 found++;
503                                 break;
504                         }
505                 }
506         }
507
508         if (found == 0)
509                 goto done;
510
511         found = 0;
512
513         if (first == 1) {
514                 /* Emit start of USB device table */
515                 fprintf (ofp, "#define NDIS_USB_DEV_TABLE");
516                 first = 0;
517         }
518
519 retry:
520
521         /*
522          * Now run through all the device names listed
523          * in the manufacturer section and dump out the
524          * device descriptions and vendor/device IDs.
525          */
526
527         TAILQ_FOREACH(assign, &ah, link) {
528                 if (assign->section == sec) {
529                         dev = find_assign("strings", assign->key);
530                         /* Emit device IDs. */
531                         if (strcasestr(assign->vals[1], "USB") != NULL)
532                                 dump_usb_id(assign->vals[1]);
533                         else
534                                 continue;
535                         /* Emit device description */
536                         fprintf (ofp, "\t\\\n\t\"%s\" },", dev->vals[0]);
537                         found++;
538                 }
539         }
540
541         /* Someone tried to fool us. Shame on them. */
542         if (!found) {
543                 found++;
544                 sec = find_section(manf->vals[0]);
545                 goto retry;
546         }
547
548         /* Handle Manufacturer sections with multiple entries. */
549         manf = find_next_assign(manf);
550
551         if (manf != NULL)
552                 goto nextmanf;
553
554 done:
555         /* Emit end of table */
556
557         fprintf(ofp, "\n\n");
558
559         return (found);
560 }
561
562 static void
563 dump_addreg(const char *s, int devidx)
564 {
565         struct section *sec;
566         struct reg *reg;
567
568         /* Find the addreg section */
569         sec = find_section(s);
570
571         /* Dump all the keys defined in it. */
572         TAILQ_FOREACH(reg, &rh, link) {
573                 /*
574                  * Keys with an empty subkey are very easy to parse,
575                  * so just deal with them here. If a parameter key
576                  * of the same name also exists, prefer that one and
577                  * skip this one.
578                  */
579                 if (reg->section == sec) {
580                         if (reg->subkey == NULL) {
581                                 fprintf(ofp, "\n\t{ \"%s\",", reg->key);
582                                 fprintf(ofp,"\n\t\"%s \",", reg->key);
583                                 fprintf(ofp, "\n\t{ \"%s\" }, %d },",
584                                     reg->value == NULL ? "" :
585                                     stringcvt(reg->value), devidx);
586                         } else if (strncasecmp(reg->subkey,
587                             "Ndi\\params", strlen("Ndi\\params")-1) == 0 &&
588                             (reg->key != NULL && strcasecmp(reg->key,
589                             "ParamDesc") == 0))
590                                 dump_paramreg(sec, reg, devidx);
591                 }
592         }
593
594         return;
595 }
596
597 static void
598 dump_enumreg(const struct section *s, const struct reg *r)
599 {
600         struct reg *reg;
601         char enumkey[256];
602
603         sprintf(enumkey, "%s\\enum", r->subkey);
604         TAILQ_FOREACH(reg, &rh, link) {
605                 if (reg->section != s)
606                         continue;
607                 if (reg->subkey == NULL || strcasecmp(reg->subkey, enumkey))
608                         continue;
609                 fprintf(ofp, " [%s=%s]", reg->key,
610                     stringcvt(reg->value));
611         }
612         return;
613 }
614
615 static void
616 dump_editreg(const struct section *s, const struct reg *r)
617 {
618         struct reg *reg;
619
620         TAILQ_FOREACH(reg, &rh, link) {
621                 if (reg->section != s)
622                         continue;
623                 if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
624                         continue;
625                 if (reg->key == NULL)
626                         continue;
627                 if (strcasecmp(reg->key, "LimitText") == 0)
628                         fprintf(ofp, " [maxchars=%s]", reg->value);
629                 if (strcasecmp(reg->key, "Optional") == 0 &&
630                     strcmp(reg->value, "1") == 0)
631                         fprintf(ofp, " [optional]");
632         }
633         return;
634 }
635
636 /* Use this for int too */
637 static void
638 dump_dwordreg(const struct section *s, const struct reg *r)
639 {
640         struct reg *reg;
641
642         TAILQ_FOREACH(reg, &rh, link) {
643                 if (reg->section != s)
644                         continue;
645                 if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
646                         continue;
647                 if (reg->key == NULL)
648                         continue;
649                 if (strcasecmp(reg->key, "min") == 0)
650                         fprintf(ofp, " [min=%s]", reg->value);
651                 if (strcasecmp(reg->key, "max") == 0)
652                         fprintf(ofp, " [max=%s]", reg->value);
653         }
654         return;
655 }
656
657 static void
658 dump_defaultinfo(const struct section *s, const struct reg *r, int devidx)
659 {
660         struct reg *reg;
661         TAILQ_FOREACH(reg, &rh, link) {
662                 if (reg->section != s)
663                         continue;
664                 if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
665                         continue;
666                 if (reg->key == NULL || strcasecmp(reg->key, "Default"))
667                         continue;
668                 fprintf(ofp, "\n\t{ \"%s\" }, %d },", reg->value == NULL ? "" :
669                     stringcvt(reg->value), devidx);
670                 return;
671         }
672         /* Default registry entry missing */
673         fprintf(ofp, "\n\t{ \"\" }, %d },", devidx);
674         return;
675 }
676
677 static void
678 dump_paramdesc(const struct section *s, const struct reg *r)
679 {
680         struct reg *reg;
681         TAILQ_FOREACH(reg, &rh, link) {
682                 if (reg->section != s)
683                         continue;
684                 if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
685                         continue;
686                 if (reg->key == NULL || strcasecmp(reg->key, "ParamDesc"))
687                         continue;
688                 fprintf(ofp, "\n\t\"%s", stringcvt(r->value));
689                         break;
690         }
691         return;
692 }
693
694 static void
695 dump_typeinfo(const struct section *s, const struct reg *r)
696 {
697         struct reg *reg;
698         TAILQ_FOREACH(reg, &rh, link) {
699                 if (reg->section != s)
700                         continue;
701                 if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
702                         continue;
703                 if (reg->key == NULL)
704                         continue;
705                 if (strcasecmp(reg->key, "type"))
706                         continue;
707                 if (strcasecmp(reg->value, "dword") == 0 ||
708                     strcasecmp(reg->value, "int") == 0)
709                         dump_dwordreg(s, r);
710                 if (strcasecmp(reg->value, "enum") == 0)
711                         dump_enumreg(s, r);
712                 if (strcasecmp(reg->value, "edit") == 0)
713                         dump_editreg(s, r);
714         }
715         return;
716 }
717
718 static void
719 dump_paramreg(const struct section *s, const struct reg *r, int devidx)
720 {
721         const char *keyname;
722
723         keyname = r->subkey + strlen("Ndi\\params\\");
724         fprintf(ofp, "\n\t{ \"%s\",", keyname);
725         dump_paramdesc(s, r);
726         dump_typeinfo(s, r);
727         fprintf(ofp, "\",");
728         dump_defaultinfo(s, r, devidx);
729
730         return;
731 }
732
733 static void
734 dump_regvals(void)
735 {
736         struct assign *manf, *dev;
737         struct section *sec;
738         struct assign *assign;
739         char sname[256];
740         int found = 0, i, is_winxp = 0, is_winnt = 0, devidx = 0;
741
742         /* Find signature to check for special case of WinNT. */
743         assign = find_assign("version", "signature");
744         if (strcasecmp(assign->vals[0], "$windows nt$") == 0)
745                 is_winnt++;
746
747         /* Emit start of block */
748         fprintf (ofp, "ndis_cfg ndis_regvals[] = {");
749
750         /* Find manufacturer name */
751         manf = find_assign("Manufacturer", NULL);
752
753 nextmanf:
754
755         /* Find manufacturer section */
756         if (manf->vals[1] != NULL &&
757             (strcasecmp(manf->vals[1], "NT.5.1") == 0 ||
758             strcasecmp(manf->vals[1], "NTx86") == 0 ||
759             strcasecmp(manf->vals[1], "NTx86.5.1") == 0 ||
760             strcasecmp(manf->vals[1], "NTamd64") == 0)) {
761                 is_winxp++;
762                 /* Handle Windows XP INF files. */
763                 snprintf(sname, sizeof(sname), "%s.%s",
764                     manf->vals[0], manf->vals[1]);
765                 sec = find_section(sname);
766         } else
767                 sec = find_section(manf->vals[0]);
768
769 retry:
770
771         TAILQ_FOREACH(assign, &ah, link) {
772                 if (assign->section == sec) {
773                         found++;
774                         /*
775                          * Find all the AddReg sections.
776                          * Look for section names with .NT, unless
777                          * this is a WinXP .INF file.
778                          */
779
780                         if (is_winxp) {
781                                 sprintf(sname, "%s.NTx86", assign->vals[0]);
782                                 dev = find_assign(sname, "AddReg");
783                                 if (dev == NULL) {
784                                         sprintf(sname, "%s.NT",
785                                             assign->vals[0]);
786                                         dev = find_assign(sname, "AddReg");
787                                 }
788                                 if (dev == NULL)
789                                         dev = find_assign(assign->vals[0],
790                                             "AddReg");
791                         } else {
792                                 sprintf(sname, "%s.NT", assign->vals[0]);
793                                 dev = find_assign(sname, "AddReg");
794                                 if (dev == NULL && is_winnt)
795                                         dev = find_assign(assign->vals[0],
796                                             "AddReg");
797                         }
798                         /* Section not found. */
799                         if (dev == NULL)
800                                 continue;
801                         for (i = 0; i < W_MAX; i++) {
802                                 if (dev->vals[i] != NULL)
803                                         dump_addreg(dev->vals[i], devidx);
804                         }
805                         devidx++;
806                 }
807         }
808
809         if (!found) {
810                 sec = find_section(manf->vals[0]);
811                 is_winxp = 0;
812                 found++;
813                 goto retry;
814         }
815
816         manf = find_next_assign(manf);
817
818         if (manf != NULL)
819                 goto nextmanf;
820
821         fprintf(ofp, "\n\t{ NULL, NULL, { 0 }, 0 }\n};\n\n");
822
823         return;
824 }
825
826 void
827 assign_add (const char *a)
828 {
829         struct assign *assign;
830         int i;
831
832         assign = malloc(sizeof(struct assign));
833         bzero(assign, sizeof(struct assign));
834         assign->section = TAILQ_LAST(&sh, section_head);
835         assign->key = sstrdup(a);
836         for (i = 0; i < idx; i++)
837                 assign->vals[(idx - 1) - i] = sstrdup(words[i]);
838         TAILQ_INSERT_TAIL(&ah, assign, link);
839
840         clear_words();
841         return;
842 }
843
844 void
845 define_add (const char *d __unused)
846 {
847 #ifdef notdef
848         fprintf(stderr, "define \"%s\"\n", d);
849 #endif
850         return;
851 }
852
853 static char *
854 sstrdup(const char *str)
855 {
856         if (str != NULL && strlen(str))
857                 return (strdup(str));
858         return (NULL);
859 }
860
861 static int
862 satoi (const char *nptr)
863 {
864         if (nptr != NULL && strlen(nptr))
865                 return (atoi(nptr));
866         return (0);
867 }
868
869 void
870 regkey_add (const char *r)
871 {
872         struct reg *reg;
873
874         reg = malloc(sizeof(struct reg));
875         bzero(reg, sizeof(struct reg));
876         reg->section = TAILQ_LAST(&sh, section_head);
877         reg->root = sstrdup(r);
878         reg->subkey = sstrdup(words[3]);
879         reg->key = sstrdup(words[2]);
880         reg->flags = satoi(words[1]);
881         reg->value = sstrdup(words[0]);
882         TAILQ_INSERT_TAIL(&rh, reg, link);
883
884         free(__DECONST(char *, r));
885         clear_words();
886         return;
887 }
888
889 void
890 push_word (const char *w)
891 {
892
893         if (idx == W_MAX) {
894                 fprintf(stderr, "too many words; try bumping W_MAX in inf.h\n");
895                 exit(1);
896         }
897
898         if (w && strlen(w))
899                 words[idx++] = w;
900         else
901                 words[idx++] = NULL;
902         return;
903 }
904
905 void
906 clear_words (void)
907 {
908         int i;
909
910         for (i = 0; i < idx; i++) {
911                 if (words[i]) {
912                         free(__DECONST(char *, words[i]));
913                 }
914         }
915         idx = 0;
916         bzero(words, sizeof(words));
917         return;
918 }