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