1 /* $NetBSD: mkheaders.c,v 1.15 2009/04/11 12:41:10 lukem Exp $ */
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This software was developed by the Computer Systems Engineering group
8 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
9 * contributed to Berkeley.
11 * All advertising materials mentioning features or use of this software
12 * must display the following acknowledgement:
13 * This product includes software developed by the University of
14 * California, Lawrence Berkeley Laboratories.
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
24 * 3. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 * from: @(#)mkheaders.c 8.1 (Berkeley) 6/6/93
43 #if HAVE_NBTOOL_CONFIG_H
44 #include "nbtool_config.h"
47 #include <sys/param.h>
58 #include <crc_extern.h>
60 static int emitcnt(struct nvlist
*);
61 static int emitlocs(void);
62 static int emitopts(void);
63 static int emitioconfh(void);
64 static int emittime(void);
65 static int herr(const char *, const char *, FILE *);
66 static int defopts_print(const char *, void *, void *);
67 static char *cntname(const char *);
70 * We define a global symbol with the name of each option and its value.
71 * This should stop code compiled with different options being linked together.
74 /* Unlikely constant for undefined options */
75 #define UNDEFINED ('n' << 24 | 0 << 20 | 't' << 12 | 0xdefU)
76 /* Value for defined options with value UNDEFINED */
77 #define DEFINED (0xdef1U << 16 | 'n' << 8 | 0xed)
80 * Make the various config-generated header files.
88 * Make headers containing counts, as needed.
90 TAILQ_FOREACH(fi
, &allfiles
, fi_next
) {
91 if (fi
->fi_flags
& FI_HIDDEN
)
93 if (fi
->fi_flags
& (FI_NEEDSCOUNT
| FI_NEEDSFLAG
) &&
98 if (emitopts() || emitlocs() || emitioconfh())
102 * If the minimum required version is ever bumped beyond 20090513,
103 * emittime() can be removed.
105 if (version
<= 20090513 && emittime())
112 fprint_global(FILE *fp
, const char *name
, long long value
)
115 * We have to doubt the founding fathers here.
116 * The gas syntax for hppa is 'var .equ value', for all? other
117 * instruction sets it is ' .equ var,value'. both have been used in
118 * various assemblers, but supporting a common syntax would be good.
119 * Fortunately we can use .equiv since it has a consistent syntax,
120 * but requires us to detect multiple assignments - event with the
123 fprintf(fp
, "#ifdef _LOCORE\n"
124 " .ifndef _KERNEL_OPT_%s\n"
125 " .global _KERNEL_OPT_%s\n"
126 " .equiv _KERNEL_OPT_%s,0x%llx\n"
129 "__asm(\" .ifndef _KERNEL_OPT_%s\\n"
130 " .global _KERNEL_OPT_%s\\n"
131 " .equiv _KERNEL_OPT_%s,0x%llx\\n"
134 name
, name
, name
, value
,
135 name
, name
, name
, value
);
138 /* Convert the option argument to a 32bit numder */
140 global_hash(const char *str
)
145 /* If the value is a valid numeric, just use it */
146 h
= strtoul(str
, &ep
, 0);
148 /* Otherwise shove through a 32bit CRC function */
149 h
= crc_buf(0, str
, strlen(str
));
151 /* Avoid colliding with the value used for undefined options. */
152 /* At least until I stop any options being set to zero */
153 return h
!= UNDEFINED
? h
: DEFINED
;
157 fprintcnt(FILE *fp
, struct nvlist
*nv
)
159 const char *name
= cntname(nv
->nv_name
);
161 fprintf(fp
, "#define\t%s\t%lld\n", name
, nv
->nv_num
);
162 fprint_global(fp
, name
, nv
->nv_num
);
166 emitcnt(struct nvlist
*head
)
168 char nfname
[BUFSIZ
], tfname
[BUFSIZ
];
172 (void)snprintf(nfname
, sizeof(nfname
), "%s.h", head
->nv_name
);
173 (void)snprintf(tfname
, sizeof(tfname
), "tmp_%s", nfname
);
175 if ((fp
= fopen(tfname
, "w")) == NULL
)
176 return (herr("open", tfname
, NULL
));
178 for (nv
= head
; nv
!= NULL
; nv
= nv
->nv_next
)
183 return herr("writ", tfname
, fp
);
185 if (fclose(fp
) == EOF
)
186 return (herr("clos", tfname
, NULL
));
188 return (moveifchanged(tfname
, nfname
));
192 * Output a string, preceded by a tab and possibly unescaping any quotes.
193 * The argument will be output as is if it doesn't start with \".
194 * Otherwise the first backslash in a \? sequence will be dropped.
197 fprintstr(FILE *fp
, const char *str
)
200 if (strncmp(str
, "\\\"", 2) != 0) {
201 (void)fprintf(fp
, "\t%s", str
);
205 (void)fputc('\t', fp
);
207 for (; *str
; str
++) {
210 if (!*++str
) /* XXX */
214 (void)fputc(*str
, fp
);
221 * Callback function for walking the option file hash table. We write out
222 * the options defined for this file.
226 defopts_print(const char *name
, void *value
, void *arg
)
229 struct nvlist
*nv
, *option
;
230 const char *opt_value
;
234 (void)snprintf(tfname
, sizeof(tfname
), "tmp_%s", name
);
235 if ((fp
= fopen(tfname
, "w")) == NULL
)
236 return (herr("open", tfname
, NULL
));
238 for (nv
= value
; nv
!= NULL
; nv
= nv
->nv_next
) {
239 isfsoption
= OPT_FSOPT(nv
->nv_name
);
241 if (nv
->nv_flags
& NV_OBSOLETE
) {
242 fprintf(fp
, "/* %s `%s' is obsolete */\n",
243 isfsoption
? "file system" : "option",
245 fprint_global(fp
, nv
->nv_name
, 0xdeadbeef);
249 if (((option
= ht_lookup(opttab
, nv
->nv_name
)) == NULL
&&
250 (option
= ht_lookup(fsopttab
, nv
->nv_name
)) == NULL
) &&
251 (nv
->nv_str
== NULL
)) {
252 fprintf(fp
, "/* %s `%s' not defined */\n",
253 isfsoption
? "file system" : "option",
255 fprint_global(fp
, nv
->nv_name
, UNDEFINED
);
259 opt_value
= option
!= NULL
? option
->nv_str
: nv
->nv_str
;
261 /* For filesysteme we'd output the lower case name */
264 fprintf(fp
, "#define\t%s", nv
->nv_name
);
265 if (opt_value
!= NULL
)
266 fprintstr(fp
, opt_value
);
267 else if (!isfsoption
)
270 fprint_global(fp
, nv
->nv_name
,
271 opt_value
== NULL
? 1 : global_hash(opt_value
));
276 return herr("writ", tfname
, fp
);
278 if (fclose(fp
) == EOF
)
279 return (herr("clos", tfname
, NULL
));
281 return (moveifchanged(tfname
, name
));
285 * Emit the option header files.
291 return (ht_enumerate(optfiletab
, defopts_print
, NULL
));
295 * A callback function for walking the attribute hash table.
296 * Emit CPP definitions of manifest constants for the locators on the
297 * "name" attribute node (passed as the "value" parameter).
300 locators_print(const char *name
, void *value
, void *arg
)
305 char *locdup
, *namedup
;
311 if (strchr(name
, ' ') != NULL
|| strchr(name
, '\t') != NULL
)
313 * name contains a space; we can't generate
314 * usable defines, so ignore it.
317 locdup
= estrdup(name
);
318 for (cp
= locdup
; *cp
; cp
++)
319 if (islower((unsigned char)*cp
))
320 *cp
= toupper((unsigned char)*cp
);
321 for (i
= 0, nv
= a
->a_locs
; nv
; nv
= nv
->nv_next
, i
++) {
322 if (strchr(nv
->nv_name
, ' ') != NULL
||
323 strchr(nv
->nv_name
, '\t') != NULL
)
325 * name contains a space; we can't generate
326 * usable defines, so ignore it.
329 namedup
= estrdup(nv
->nv_name
);
330 for (cp
= namedup
; *cp
; cp
++)
331 if (islower((unsigned char)*cp
))
332 *cp
= toupper((unsigned char)*cp
);
333 else if (*cp
== ARRCHR
)
335 fprintf(fp
, "#define %sCF_%s %d\n", locdup
, namedup
, i
);
336 if (nv
->nv_str
!= NULL
)
337 fprintf(fp
, "#define %sCF_%s_DEFAULT %s\n",
338 locdup
, namedup
, nv
->nv_str
);
341 /* assert(i == a->a_loclen) */
342 fprintf(fp
, "#define %sCF_NLOCS %d\n", locdup
, a
->a_loclen
);
349 * Build the "locators.h" file with manifest constants for all potential
350 * locators in the configuration. Do this by enumerating the attribute
351 * hash table and emitting all the locators for each attribute.
360 tfname
= "tmp_locators.h";
361 if ((tfp
= fopen(tfname
, "w")) == NULL
)
362 return (herr("open", tfname
, NULL
));
364 rval
= ht_enumerate(attrtab
, locators_print
, tfp
);
368 return (herr("writ", tfname
, NULL
));
369 if (fclose(tfp
) == EOF
)
370 return (herr("clos", tfname
, NULL
));
373 return (moveifchanged(tfname
, "locators.h"));
377 * Build the "ioconf.h" file with extern declarations for all configured
387 tfname
= "tmp_ioconf.h";
388 if ((tfp
= fopen(tfname
, "w")) == NULL
)
389 return (herr("open", tfname
, NULL
));
391 TAILQ_FOREACH(d
, &allbases
, d_next
) {
392 if (!devbase_has_instances(d
, WILD
))
394 fprintf(tfp
, "extern struct cfdriver %s_cd;\n", d
->d_name
);
399 return herr("writ", tfname
, tfp
);
401 if (fclose(tfp
) == EOF
)
402 return (herr("clos", tfname
, NULL
));
404 return (moveifchanged(tfname
, "ioconf.h"));
408 * Make a file that config_time.h can use as a source, if required.
421 if ((fp
= fopen("config_time.src", "w")) == NULL
)
422 return (herr("open", "config_time.src", NULL
));
424 if (strftime(buf
, sizeof(buf
), "%c %Z", tm
) == 0)
425 return (herr("strftime", "config_time.src", fp
));
427 fprintf(fp
, "/* %s */\n"
428 "#define CONFIG_TIME\t%2lld\n"
429 "#define CONFIG_YEAR\t%2d\n"
430 "#define CONFIG_MONTH\t%2d\n"
431 "#define CONFIG_DATE\t%2d\n"
432 "#define CONFIG_HOUR\t%2d\n"
433 "#define CONFIG_MINS\t%2d\n"
434 "#define CONFIG_SECS\t%2d\n",
436 tm
->tm_year
+ 1900, tm
->tm_mon
+ 1, tm
->tm_mday
,
437 tm
->tm_hour
, tm
->tm_min
, tm
->tm_sec
);
441 return (herr("fprintf", "config_time.src", fp
));
444 return (herr("clos", "config_time.src", NULL
));
447 * *Don't* moveifchanged this file. Makefile.kern.inc will
448 * handle that if it determines such a move is necessary.
454 * Compare two files. If nfname doesn't exist, or is different from
455 * tfname, move tfname to nfname. Otherwise, delete tfname.
458 moveifchanged(const char *tfname
, const char *nfname
)
460 char tbuf
[BUFSIZ
], nbuf
[BUFSIZ
];
463 if ((tfp
= fopen(tfname
, "r")) == NULL
)
464 return (herr("open", tfname
, NULL
));
466 if ((nfp
= fopen(nfname
, "r")) == NULL
)
469 while (fgets(tbuf
, sizeof(tbuf
), tfp
) != NULL
) {
470 if (fgets(nbuf
, sizeof(nbuf
), nfp
) == NULL
) {
472 * Old file has fewer lines.
476 if (strcmp(tbuf
, nbuf
) != 0)
481 * We've reached the end of the new file. Check to see if new file
482 * has fewer lines than old.
484 if (fgets(nbuf
, sizeof(nbuf
), nfp
) != NULL
) {
486 * New file has fewer lines.
493 if (remove(tfname
) == -1)
494 return(herr("remov", tfname
, NULL
));
499 * They're different, or the file doesn't exist.
505 if (rename(tfname
, nfname
) == -1)
506 return (herr("renam", tfname
, NULL
));
511 herr(const char *what
, const char *fname
, FILE *fp
)
514 warn("error %sing %s", what
, fname
);
521 cntname(const char *src
)
525 static char buf
[100];
529 while ((c
= *src
++) != 0)
530 *dst
++ = islower(c
) ? toupper(c
) : c
;