No empty .Rs/.Re
[netbsd-mini2440.git] / usr.bin / config / mkheaders.c
bloba94ac6f6536ecb6fb50187a7f84dc06e3d3b9613
1 /* $NetBSD: mkheaders.c,v 1.15 2009/04/11 12:41:10 lukem Exp $ */
3 /*
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
18 * are met:
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
38 * SUCH DAMAGE.
40 * from: @(#)mkheaders.c 8.1 (Berkeley) 6/6/93
43 #if HAVE_NBTOOL_CONFIG_H
44 #include "nbtool_config.h"
45 #endif
47 #include <sys/param.h>
48 #include <ctype.h>
49 #include <errno.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <time.h>
54 #include <util.h>
55 #include <err.h>
56 #include "defs.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.
82 int
83 mkheaders(void)
85 struct files *fi;
88 * Make headers containing counts, as needed.
90 TAILQ_FOREACH(fi, &allfiles, fi_next) {
91 if (fi->fi_flags & FI_HIDDEN)
92 continue;
93 if (fi->fi_flags & (FI_NEEDSCOUNT | FI_NEEDSFLAG) &&
94 emitcnt(fi->fi_optf))
95 return (1);
98 if (emitopts() || emitlocs() || emitioconfh())
99 return (1);
102 * If the minimum required version is ever bumped beyond 20090513,
103 * emittime() can be removed.
105 if (version <= 20090513 && emittime())
106 return (1);
108 return (0);
111 static void
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
121 * same value.
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"
127 " .endif\n"
128 "#else\n"
129 "__asm(\" .ifndef _KERNEL_OPT_%s\\n"
130 " .global _KERNEL_OPT_%s\\n"
131 " .equiv _KERNEL_OPT_%s,0x%llx\\n"
132 " .endif\");\n"
133 "#endif\n",
134 name, name, name, value,
135 name, name, name, value);
138 /* Convert the option argument to a 32bit numder */
139 static unsigned int
140 global_hash(const char *str)
142 unsigned int h;
143 char *ep;
145 /* If the value is a valid numeric, just use it */
146 h = strtoul(str, &ep, 0);
147 if (*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;
156 static void
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);
165 static int
166 emitcnt(struct nvlist *head)
168 char nfname[BUFSIZ], tfname[BUFSIZ];
169 struct nvlist *nv;
170 FILE *fp;
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)
179 fprintcnt(fp, nv);
181 fflush(fp);
182 if (ferror(fp))
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.
196 static void
197 fprintstr(FILE *fp, const char *str)
200 if (strncmp(str, "\\\"", 2) != 0) {
201 (void)fprintf(fp, "\t%s", str);
202 return;
205 (void)fputc('\t', fp);
207 for (; *str; str++) {
208 switch (*str) {
209 case '\\':
210 if (!*++str) /* XXX */
211 str--;
212 /*FALLTHROUGH*/
213 default:
214 (void)fputc(*str, fp);
215 break;
221 * Callback function for walking the option file hash table. We write out
222 * the options defined for this file.
224 static int
225 /*ARGSUSED*/
226 defopts_print(const char *name, void *value, void *arg)
228 char tfname[BUFSIZ];
229 struct nvlist *nv, *option;
230 const char *opt_value;
231 int isfsoption;
232 FILE *fp;
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",
244 nv->nv_name);
245 fprint_global(fp, nv->nv_name, 0xdeadbeef);
246 continue;
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",
254 nv->nv_name);
255 fprint_global(fp, nv->nv_name, UNDEFINED);
256 continue;
259 opt_value = option != NULL ? option->nv_str : nv->nv_str;
260 if (isfsoption == 1)
261 /* For filesysteme we'd output the lower case name */
262 opt_value = NULL;
264 fprintf(fp, "#define\t%s", nv->nv_name);
265 if (opt_value != NULL)
266 fprintstr(fp, opt_value);
267 else if (!isfsoption)
268 fprintstr(fp, "1");
269 fputc('\n', fp);
270 fprint_global(fp, nv->nv_name,
271 opt_value == NULL ? 1 : global_hash(opt_value));
274 fflush(fp);
275 if (ferror(fp))
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.
287 static int
288 emitopts(void)
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).
299 static int
300 locators_print(const char *name, void *value, void *arg)
302 struct attr *a;
303 struct nvlist *nv;
304 int i;
305 char *locdup, *namedup;
306 char *cp;
307 FILE *fp = arg;
309 a = value;
310 if (a->a_locs) {
311 if (strchr(name, ' ') != NULL || strchr(name, '\t') != NULL)
313 * name contains a space; we can't generate
314 * usable defines, so ignore it.
316 return 0;
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.
328 continue;
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)
334 *cp = '_';
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);
339 free(namedup);
341 /* assert(i == a->a_loclen) */
342 fprintf(fp, "#define %sCF_NLOCS %d\n", locdup, a->a_loclen);
343 free(locdup);
345 return 0;
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.
353 static int
354 emitlocs(void)
356 const char *tfname;
357 int rval;
358 FILE *tfp;
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);
366 fflush(tfp);
367 if (ferror(tfp))
368 return (herr("writ", tfname, NULL));
369 if (fclose(tfp) == EOF)
370 return (herr("clos", tfname, NULL));
371 if (rval)
372 return (rval);
373 return (moveifchanged(tfname, "locators.h"));
377 * Build the "ioconf.h" file with extern declarations for all configured
378 * cfdrivers.
380 static int
381 emitioconfh(void)
383 const char *tfname;
384 FILE *tfp;
385 struct devbase *d;
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))
393 continue;
394 fprintf(tfp, "extern struct cfdriver %s_cd;\n", d->d_name);
397 fflush(tfp);
398 if (ferror(tfp))
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.
410 static int
411 emittime(void)
413 FILE *fp;
414 time_t t;
415 struct tm *tm;
416 char buf[128];
418 t = time(NULL);
419 tm = gmtime(&t);
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",
435 buf, (long long)t,
436 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
437 tm->tm_hour, tm->tm_min, tm->tm_sec);
439 fflush(fp);
440 if (ferror(fp))
441 return (herr("fprintf", "config_time.src", fp));
443 if (fclose(fp) != 0)
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.
450 return (0);
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];
461 FILE *tfp, *nfp;
463 if ((tfp = fopen(tfname, "r")) == NULL)
464 return (herr("open", tfname, NULL));
466 if ((nfp = fopen(nfname, "r")) == NULL)
467 goto moveit;
469 while (fgets(tbuf, sizeof(tbuf), tfp) != NULL) {
470 if (fgets(nbuf, sizeof(nbuf), nfp) == NULL) {
472 * Old file has fewer lines.
474 goto moveit;
476 if (strcmp(tbuf, nbuf) != 0)
477 goto moveit;
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.
488 goto moveit;
491 (void) fclose(nfp);
492 (void) fclose(tfp);
493 if (remove(tfname) == -1)
494 return(herr("remov", tfname, NULL));
495 return (0);
497 moveit:
499 * They're different, or the file doesn't exist.
501 if (nfp)
502 (void) fclose(nfp);
503 if (tfp)
504 (void) fclose(tfp);
505 if (rename(tfname, nfname) == -1)
506 return (herr("renam", tfname, NULL));
507 return (0);
510 static int
511 herr(const char *what, const char *fname, FILE *fp)
514 warn("error %sing %s", what, fname);
515 if (fp)
516 (void)fclose(fp);
517 return (1);
520 static char *
521 cntname(const char *src)
523 char *dst;
524 unsigned char c;
525 static char buf[100];
527 dst = buf;
528 *dst++ = 'N';
529 while ((c = *src++) != 0)
530 *dst++ = islower(c) ? toupper(c) : c;
531 *dst = 0;
532 return (buf);