mkinit.c revision 223494
1/*- 2 * Copyright (c) 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Kenneth Almquist. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 4. Neither the name of the University nor the names of its 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 THE REGENTS 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 THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33#ifndef lint 34static char const copyright[] = 35"@(#) Copyright (c) 1991, 1993\n\ 36 The Regents of the University of California. All rights reserved.\n"; 37#endif /* not lint */ 38 39#ifndef lint 40#if 0 41static char sccsid[] = "@(#)mkinit.c 8.2 (Berkeley) 5/4/95"; 42#endif 43#endif /* not lint */ 44#include <sys/cdefs.h> 45__FBSDID("$FreeBSD: head/bin/sh/mkinit.c 223494 2011-06-24 07:29:04Z kevlo $"); 46 47/* 48 * This program scans all the source files for code to handle various 49 * special events and combines this code into one file. This (allegedly) 50 * improves the structure of the program since there is no need for 51 * anyone outside of a module to know that that module performs special 52 * operations on particular events. 53 * 54 * Usage: mkinit sourcefile... 55 */ 56 57 58#include <sys/types.h> 59#include <stdio.h> 60#include <stdlib.h> 61#include <string.h> 62#include <fcntl.h> 63#include <unistd.h> 64#include <errno.h> 65 66 67/* 68 * OUTFILE is the name of the output file. Output is initially written 69 * to the file OUTTEMP, which is then moved to OUTFILE. 70 */ 71 72#define OUTFILE "init.c" 73#define OUTTEMP "init.c.new" 74 75 76/* 77 * A text structure is basically just a string that grows as more characters 78 * are added onto the end of it. It is implemented as a linked list of 79 * blocks of characters. The routines addstr and addchar append a string 80 * or a single character, respectively, to a text structure. Writetext 81 * writes the contents of a text structure to a file. 82 */ 83 84#define BLOCKSIZE 512 85 86struct text { 87 char *nextc; 88 int nleft; 89 struct block *start; 90 struct block *last; 91}; 92 93struct block { 94 struct block *next; 95 char text[BLOCKSIZE]; 96}; 97 98 99/* 100 * There is one event structure for each event that mkinit handles. 101 */ 102 103struct event { 104 const char *name; /* name of event (e.g. INIT) */ 105 const char *routine; /* name of routine called on event */ 106 const char *comment; /* comment describing routine */ 107 struct text code; /* code for handling event */ 108}; 109 110 111char writer[] = "\ 112/*\n\ 113 * This file was generated by the mkinit program.\n\ 114 */\n\ 115\n"; 116 117char init[] = "\ 118/*\n\ 119 * Initialization code.\n\ 120 */\n"; 121 122char reset[] = "\ 123/*\n\ 124 * This routine is called when an error or an interrupt occurs in an\n\ 125 * interactive shell and control is returned to the main command loop.\n\ 126 */\n"; 127 128 129struct event event[] = { 130 { "INIT", "init", init, { NULL, 0, NULL, NULL } }, 131 { "RESET", "reset", reset, { NULL, 0, NULL, NULL } }, 132 { NULL, NULL, NULL, { NULL, 0, NULL, NULL } } 133}; 134 135 136const char *curfile; /* current file */ 137int linno; /* current line */ 138char *header_files[200]; /* list of header files */ 139struct text defines; /* #define statements */ 140struct text decls; /* declarations */ 141int amiddecls; /* for formatting */ 142 143 144void readfile(const char *); 145int match(const char *, const char *); 146int gooddefine(const char *); 147void doevent(struct event *, FILE *, const char *); 148void doinclude(char *); 149void dodecl(char *, FILE *); 150void output(void); 151void addstr(const char *, struct text *); 152void addchar(int, struct text *); 153void writetext(struct text *, FILE *); 154FILE *ckfopen(const char *, const char *); 155void *ckmalloc(size_t); 156char *savestr(const char *); 157void error(const char *); 158 159#define equal(s1, s2) (strcmp(s1, s2) == 0) 160 161int 162main(int argc __unused, char *argv[]) 163{ 164 char **ap; 165 166 header_files[0] = savestr("\"shell.h\""); 167 header_files[1] = savestr("\"mystring.h\""); 168 header_files[2] = savestr("\"init.h\""); 169 for (ap = argv + 1 ; *ap ; ap++) 170 readfile(*ap); 171 output(); 172 rename(OUTTEMP, OUTFILE); 173 exit(0); 174} 175 176 177/* 178 * Parse an input file. 179 */ 180 181void 182readfile(const char *fname) 183{ 184 FILE *fp; 185 char line[1024]; 186 struct event *ep; 187 188 fp = ckfopen(fname, "r"); 189 curfile = fname; 190 linno = 0; 191 amiddecls = 0; 192 while (fgets(line, sizeof line, fp) != NULL) { 193 linno++; 194 for (ep = event ; ep->name ; ep++) { 195 if (line[0] == ep->name[0] && match(ep->name, line)) { 196 doevent(ep, fp, fname); 197 break; 198 } 199 } 200 if (line[0] == 'I' && match("INCLUDE", line)) 201 doinclude(line); 202 if (line[0] == 'M' && match("MKINIT", line)) 203 dodecl(line, fp); 204 if (line[0] == '#' && gooddefine(line)) { 205 char *cp; 206 char line2[1024]; 207 static const char undef[] = "#undef "; 208 209 strcpy(line2, line); 210 memcpy(line2, undef, sizeof(undef) - 1); 211 cp = line2 + sizeof(undef) - 1; 212 while(*cp && (*cp == ' ' || *cp == '\t')) 213 cp++; 214 while(*cp && *cp != ' ' && *cp != '\t' && *cp != '\n') 215 cp++; 216 *cp++ = '\n'; *cp = '\0'; 217 addstr(line2, &defines); 218 addstr(line, &defines); 219 } 220 } 221 fclose(fp); 222} 223 224 225int 226match(const char *name, const char *line) 227{ 228 const char *p, *q; 229 230 p = name, q = line; 231 while (*p) { 232 if (*p++ != *q++) 233 return 0; 234 } 235 if (*q != '{' && *q != ' ' && *q != '\t' && *q != '\n') 236 return 0; 237 return 1; 238} 239 240 241int 242gooddefine(const char *line) 243{ 244 const char *p; 245 246 if (! match("#define", line)) 247 return 0; /* not a define */ 248 p = line + 7; 249 while (*p == ' ' || *p == '\t') 250 p++; 251 while (*p != ' ' && *p != '\t') { 252 if (*p == '(') 253 return 0; /* macro definition */ 254 p++; 255 } 256 while (*p != '\n' && *p != '\0') 257 p++; 258 if (p[-1] == '\\') 259 return 0; /* multi-line definition */ 260 return 1; 261} 262 263 264void 265doevent(struct event *ep, FILE *fp, const char *fname) 266{ 267 char line[1024]; 268 int indent; 269 const char *p; 270 271 sprintf(line, "\n /* from %s: */\n", fname); 272 addstr(line, &ep->code); 273 addstr(" {\n", &ep->code); 274 for (;;) { 275 linno++; 276 if (fgets(line, sizeof line, fp) == NULL) 277 error("Unexpected EOF"); 278 if (equal(line, "}\n")) 279 break; 280 indent = 6; 281 for (p = line ; *p == '\t' ; p++) 282 indent += 8; 283 for ( ; *p == ' ' ; p++) 284 indent++; 285 if (*p == '\n' || *p == '#') 286 indent = 0; 287 while (indent >= 8) { 288 addchar('\t', &ep->code); 289 indent -= 8; 290 } 291 while (indent > 0) { 292 addchar(' ', &ep->code); 293 indent--; 294 } 295 addstr(p, &ep->code); 296 } 297 addstr(" }\n", &ep->code); 298} 299 300 301void 302doinclude(char *line) 303{ 304 char *p; 305 char *name; 306 char **pp; 307 308 for (p = line ; *p != '"' && *p != '<' && *p != '\0' ; p++); 309 if (*p == '\0') 310 error("Expecting '\"' or '<'"); 311 name = p; 312 while (*p != ' ' && *p != '\t' && *p != '\n') 313 p++; 314 if (p[-1] != '"' && p[-1] != '>') 315 error("Missing terminator"); 316 *p = '\0'; 317 318 /* name now contains the name of the include file */ 319 for (pp = header_files ; *pp && ! equal(*pp, name) ; pp++); 320 if (*pp == NULL) 321 *pp = savestr(name); 322} 323 324 325void 326dodecl(char *line1, FILE *fp) 327{ 328 char line[1024]; 329 char *p, *q; 330 331 if (strcmp(line1, "MKINIT\n") == 0) { /* start of struct/union decl */ 332 addchar('\n', &decls); 333 do { 334 linno++; 335 if (fgets(line, sizeof line, fp) == NULL) 336 error("Unterminated structure declaration"); 337 addstr(line, &decls); 338 } while (line[0] != '}'); 339 amiddecls = 0; 340 } else { 341 if (! amiddecls) 342 addchar('\n', &decls); 343 q = NULL; 344 for (p = line1 + 6 ; *p && strchr("=/\n", *p) == NULL; p++) 345 continue; 346 if (*p == '=') { /* eliminate initialization */ 347 for (q = p ; *q && *q != ';' ; q++); 348 if (*q == '\0') 349 q = NULL; 350 else { 351 while (p[-1] == ' ') 352 p--; 353 *p = '\0'; 354 } 355 } 356 addstr("extern", &decls); 357 addstr(line1 + 6, &decls); 358 if (q != NULL) 359 addstr(q, &decls); 360 amiddecls = 1; 361 } 362} 363 364 365 366/* 367 * Write the output to the file OUTTEMP. 368 */ 369 370void 371output(void) 372{ 373 FILE *fp; 374 char **pp; 375 struct event *ep; 376 377 fp = ckfopen(OUTTEMP, "w"); 378 fputs(writer, fp); 379 for (pp = header_files ; *pp ; pp++) 380 fprintf(fp, "#include %s\n", *pp); 381 fputs("\n\n\n", fp); 382 writetext(&defines, fp); 383 fputs("\n\n", fp); 384 writetext(&decls, fp); 385 for (ep = event ; ep->name ; ep++) { 386 fputs("\n\n\n", fp); 387 fputs(ep->comment, fp); 388 fprintf(fp, "\nvoid\n%s(void)\n{\n", ep->routine); 389 writetext(&ep->code, fp); 390 fprintf(fp, "}\n"); 391 } 392 fclose(fp); 393} 394 395 396/* 397 * A text structure is simply a block of text that is kept in memory. 398 * Addstr appends a string to the text struct, and addchar appends a single 399 * character. 400 */ 401 402void 403addstr(const char *s, struct text *text) 404{ 405 while (*s) { 406 if (--text->nleft < 0) 407 addchar(*s++, text); 408 else 409 *text->nextc++ = *s++; 410 } 411} 412 413 414void 415addchar(int c, struct text *text) 416{ 417 struct block *bp; 418 419 if (--text->nleft < 0) { 420 bp = ckmalloc(sizeof *bp); 421 if (text->start == NULL) 422 text->start = bp; 423 else 424 text->last->next = bp; 425 text->last = bp; 426 text->nextc = bp->text; 427 text->nleft = BLOCKSIZE - 1; 428 } 429 *text->nextc++ = c; 430} 431 432/* 433 * Write the contents of a text structure to a file. 434 */ 435void 436writetext(struct text *text, FILE *fp) 437{ 438 struct block *bp; 439 440 if (text->start != NULL) { 441 for (bp = text->start ; bp != text->last ; bp = bp->next) 442 fwrite(bp->text, sizeof (char), BLOCKSIZE, fp); 443 fwrite(bp->text, sizeof (char), BLOCKSIZE - text->nleft, fp); 444 } 445} 446 447FILE * 448ckfopen(const char *file, const char *mode) 449{ 450 FILE *fp; 451 452 if ((fp = fopen(file, mode)) == NULL) { 453 fprintf(stderr, "Can't open %s: %s\n", file, strerror(errno)); 454 exit(2); 455 } 456 return fp; 457} 458 459void * 460ckmalloc(size_t nbytes) 461{ 462 char *p; 463 464 if ((p = malloc(nbytes)) == NULL) 465 error("Out of space"); 466 return p; 467} 468 469char * 470savestr(const char *s) 471{ 472 char *p; 473 474 p = ckmalloc(strlen(s) + 1); 475 strcpy(p, s); 476 return p; 477} 478 479void 480error(const char *msg) 481{ 482 if (curfile != NULL) 483 fprintf(stderr, "%s:%d: ", curfile, linno); 484 fprintf(stderr, "%s\n", msg); 485 exit(2); 486} 487