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