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