mkinit.c revision 193221
1139790Simp/*- 26512Sphk * Copyright (c) 1991, 1993 33263Sdg * The Regents of the University of California. All rights reserved. 46512Sphk * 56512Sphk * This code is derived from software contributed to Berkeley by 63263Sdg * Kenneth Almquist. 73263Sdg * 88876Srgrimes * Redistribution and use in source and binary forms, with or without 98876Srgrimes * modification, are permitted provided that the following conditions 108876Srgrimes * are met: 113263Sdg * 1. Redistributions of source code must retain the above copyright 123263Sdg * notice, this list of conditions and the following disclaimer. 133263Sdg * 2. Redistributions in binary form must reproduce the above copyright 143264Sdg * notice, this list of conditions and the following disclaimer in the 1550477Speter * documentation and/or other materials provided with the distribution. 163263Sdg * 4. Neither the name of the University nor the names of its contributors 173263Sdg * may be used to endorse or promote products derived from this software 18215140Sjkim * without specific prior written permission. 19215140Sjkim * 203263Sdg * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2155205Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2218444Sbde * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2318444Sbde * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2418444Sbde * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2518444Sbde * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 263263Sdg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 273263Sdg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2849197Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 293263Sdg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 303263Sdg * SUCH DAMAGE. 313263Sdg */ 323263Sdg 333263Sdg#ifndef lint 343263Sdgstatic char const copyright[] = 353263Sdg"@(#) Copyright (c) 1991, 1993\n\ 363263Sdg The Regents of the University of California. All rights reserved.\n"; 373263Sdg#endif /* not lint */ 383263Sdg 393263Sdg#ifndef lint 403263Sdg#if 0 413263Sdgstatic char sccsid[] = "@(#)mkinit.c 8.2 (Berkeley) 5/4/95"; 423263Sdg#endif 433263Sdg#endif /* not lint */ 443263Sdg#include <sys/cdefs.h> 453263Sdg__FBSDID("$FreeBSD: head/bin/sh/mkinit.c 193221 2009-06-01 10:50:17Z rse $"); 463263Sdg 473263Sdg/* 483263Sdg * This program scans all the source files for code to handle various 493263Sdg * special events and combines this code into one file. This (allegedly) 503263Sdg * improves the structure of the program since there is no need for 513263Sdg * anyone outside of a module to know that that module performs special 523263Sdg * operations on particular events. 533263Sdg * 543263Sdg * Usage: mkinit sourcefile... 553263Sdg */ 563263Sdg 5737414Simp 5837414Simp#include <sys/cdefs.h> 5937414Simp#include <sys/types.h> 6037414Simp#include <stdio.h> 613263Sdg#include <stdlib.h> 623263Sdg#include <string.h> 633263Sdg#include <fcntl.h> 643263Sdg#include <unistd.h> 653263Sdg#include <errno.h> 663263Sdg 673263Sdg 683263Sdg/* 693263Sdg * OUTFILE is the name of the output file. Output is initially written 703263Sdg * to the file OUTTEMP, which is then moved to OUTFILE. 713263Sdg */ 723263Sdg 733263Sdg#define OUTFILE "init.c" 743263Sdg#define OUTTEMP "init.c.new" 753263Sdg 763263Sdg 773263Sdg/* 783263Sdg * A text structure is basicly just a string that grows as more characters 793263Sdg * are added onto the end of it. It is implemented as a linked list of 803263Sdg * blocks of characters. The routines addstr and addchar append a string 813263Sdg * or a single character, respectively, to a text structure. Writetext 823263Sdg * writes the contents of a text structure to a file. 833263Sdg */ 843263Sdg 8564251Siwasaki#define BLOCKSIZE 512 863263Sdg 873263Sdgstruct text { 883263Sdg char *nextc; 893263Sdg int nleft; 903263Sdg struct block *start; 913263Sdg struct block *last; 923263Sdg}; 933263Sdg 943263Sdgstruct block { 953263Sdg struct block *next; 963263Sdg char text[BLOCKSIZE]; 973263Sdg}; 983263Sdg 993263Sdg 1003263Sdg/* 1013263Sdg * There is one event structure for each event that mkinit handles. 1023263Sdg */ 1033263Sdg 1043263Sdgstruct event { 1053263Sdg char *name; /* name of event (e.g. INIT) */ 1063263Sdg char *routine; /* name of routine called on event */ 1073263Sdg char *comment; /* comment describing routine */ 10864615Sume struct text code; /* code for handling event */ 10964615Sume}; 11064615Sume 11164615Sume 11264615Sumechar writer[] = "\ 11364615Sume/*\n\ 1143263Sdg * This file was generated by the mkinit program.\n\ 1153263Sdg */\n\ 1163263Sdg\n"; 1173263Sdg 1183263Sdgchar init[] = "\ 1193263Sdg/*\n\ 1203263Sdg * Initialization code.\n\ 1213263Sdg */\n"; 1223263Sdg 1233263Sdgchar reset[] = "\ 1243263Sdg/*\n\ 1253263Sdg * This routine is called when an error or an interrupt occurs in an\n\ 1263263Sdg * interactive shell and control is returned to the main command loop.\n\ 1273263Sdg */\n"; 1283263Sdg 1296512Sphkchar shellproc[] = "\ 1303263Sdg/*\n\ 1313263Sdg * This routine is called to initialize the shell to run a shell procedure.\n\ 1326512Sphk */\n"; 1336512Sphk 13492761Salfred 1356512Sphkstruct event event[] = { 1366512Sphk { "INIT", "init", init, { NULL, 0, NULL, NULL } }, 1376512Sphk { "RESET", "reset", reset, { NULL, 0, NULL, NULL } }, 1386512Sphk { "SHELLPROC", "initshellproc", shellproc, { NULL, 0, NULL, NULL } }, 1396512Sphk { NULL, NULL, NULL, { NULL, 0, NULL, NULL } } 1406512Sphk}; 1416512Sphk 1426512Sphk 1433263Sdgchar *curfile; /* current file */ 14455205Speterint linno; /* current line */ 14537414Simpchar *header_files[200]; /* list of header files */ 14637414Simpstruct text defines; /* #define statements */ 1476512Sphkstruct text decls; /* declarations */ 1486512Sphkint amiddecls; /* for formatting */ 1493263Sdg 1503263Sdg 1513263Sdgvoid readfile(char *); 15255205Speterint match(char *, char *); 15337414Simpint gooddefine(char *); 1546512Sphkvoid doevent(struct event *, FILE *, char *); 1553263Sdgvoid doinclude(char *); 1563263Sdgvoid dodecl(char *, FILE *); 1573263Sdgvoid output(void); 1583263Sdgvoid addstr(char *, struct text *); 1593263Sdgvoid addchar(int, struct text *); 1603263Sdgvoid writetext(struct text *, FILE *); 1613263SdgFILE *ckfopen(char *, char *); 1623263Sdgvoid *ckmalloc(size_t); 1633263Sdgchar *savestr(char *); 1643263Sdgvoid error(char *); 1653263Sdg 1663263Sdg#define equal(s1, s2) (strcmp(s1, s2) == 0) 1673263Sdg 1683263Sdgint 1693263Sdgmain(int argc __unused, char *argv[]) 1703263Sdg{ 1713263Sdg char **ap; 1723263Sdg 17337414Simp header_files[0] = "\"shell.h\""; 17437414Simp header_files[1] = "\"mystring.h\""; 1753263Sdg header_files[2] = "\"init.h\""; 1763263Sdg for (ap = argv + 1 ; *ap ; ap++) 1773263Sdg readfile(*ap); 1783263Sdg output(); 1793263Sdg rename(OUTTEMP, OUTFILE); 1806512Sphk exit(0); 1813263Sdg} 18231126Sjdp 18331126Sjdp 18431126Sjdp/* 18531126Sjdp * Parse an input file. 18631126Sjdp */ 1873263Sdg 1883263Sdgvoid 1893263Sdgreadfile(char *fname) 1903263Sdg{ 1913263Sdg FILE *fp; 19214608Snate char line[1024]; 19331126Sjdp struct event *ep; 19431126Sjdp 19531126Sjdp fp = ckfopen(fname, "r"); 19631126Sjdp curfile = fname; 19731126Sjdp linno = 0; 19831126Sjdp amiddecls = 0; 19931126Sjdp while (fgets(line, sizeof line, fp) != NULL) { 20031126Sjdp linno++; 20131126Sjdp for (ep = event ; ep->name ; ep++) { 20231126Sjdp if (line[0] == ep->name[0] && match(ep->name, line)) { 20331126Sjdp doevent(ep, fp, fname); 20431126Sjdp break; 20531126Sjdp } 20631126Sjdp } 20731126Sjdp if (line[0] == 'I' && match("INCLUDE", line)) 20831126Sjdp doinclude(line); 20931126Sjdp if (line[0] == 'M' && match("MKINIT", line)) 21037414Simp dodecl(line, fp); 21137414Simp if (line[0] == '#' && gooddefine(line)) { 21237414Simp char *cp; 2133263Sdg char line2[1024]; 2143263Sdg static const char undef[] = "#undef "; 21564615Sume 21664615Sume strcpy(line2, line); 21764615Sume memcpy(line2, undef, sizeof(undef) - 1); 21864615Sume cp = line2 + sizeof(undef) - 1; 21964615Sume while(*cp && (*cp == ' ' || *cp == '\t')) 22064615Sume cp++; 22164615Sume while(*cp && *cp != ' ' && *cp != '\t' && *cp != '\n') 22264615Sume cp++; 22364615Sume *cp++ = '\n'; *cp = '\0'; 22464615Sume addstr(line2, &defines); 22564615Sume addstr(line, &defines); 22664615Sume } 22764615Sume } 22864615Sume fclose(fp); 22964615Sume} 23064615Sume 23164615Sume 23249292Smsmithint 233197536Sjkimmatch(char *name, char *line) 234197536Sjkim{ 235197536Sjkim char *p, *q; 236197536Sjkim 237197536Sjkim p = name, q = line; 238197536Sjkim while (*p) { 23949292Smsmith if (*p++ != *q++) 24049292Smsmith return 0; 24149197Smsmith } 24249197Smsmith if (*q != '{' && *q != ' ' && *q != '\t' && *q != '\n') 24348735Siwasaki return 0; 24448735Siwasaki return 1; 24548735Siwasaki} 24648735Siwasaki 2473263Sdg 24831126Sjdpint 2493263Sdggooddefine(char *line) 2503263Sdg{ 2513263Sdg char *p; 2523263Sdg 25321362Snate if (! match("#define", line)) 25449292Smsmith return 0; /* not a define */ 25531126Sjdp p = line + 7; 25637414Simp while (*p == ' ' || *p == '\t') 25764615Sume p++; 25848735Siwasaki while (*p != ' ' && *p != '\t') { 25948735Siwasaki if (*p == '(') 26048735Siwasaki return 0; /* macro definition */ 2613263Sdg p++; 2626512Sphk } 2633263Sdg while (*p != '\n' && *p != '\0') 264215140Sjkim p++; 265 if (p[-1] == '\\') 266 return 0; /* multi-line definition */ 267 return 1; 268} 269 270 271void 272doevent(struct event *ep, FILE *fp, char *fname) 273{ 274 char line[1024]; 275 int indent; 276 char *p; 277 278 sprintf(line, "\n /* from %s: */\n", fname); 279 addstr(line, &ep->code); 280 addstr(" {\n", &ep->code); 281 for (;;) { 282 linno++; 283 if (fgets(line, sizeof line, fp) == NULL) 284 error("Unexpected EOF"); 285 if (equal(line, "}\n")) 286 break; 287 indent = 6; 288 for (p = line ; *p == '\t' ; p++) 289 indent += 8; 290 for ( ; *p == ' ' ; p++) 291 indent++; 292 if (*p == '\n' || *p == '#') 293 indent = 0; 294 while (indent >= 8) { 295 addchar('\t', &ep->code); 296 indent -= 8; 297 } 298 while (indent > 0) { 299 addchar(' ', &ep->code); 300 indent--; 301 } 302 addstr(p, &ep->code); 303 } 304 addstr(" }\n", &ep->code); 305} 306 307 308void 309doinclude(char *line) 310{ 311 char *p; 312 char *name; 313 char **pp; 314 315 for (p = line ; *p != '"' && *p != '<' && *p != '\0' ; p++); 316 if (*p == '\0') 317 error("Expecting '\"' or '<'"); 318 name = p; 319 while (*p != ' ' && *p != '\t' && *p != '\n') 320 p++; 321 if (p[-1] != '"' && p[-1] != '>') 322 error("Missing terminator"); 323 *p = '\0'; 324 325 /* name now contains the name of the include file */ 326 for (pp = header_files ; *pp && ! equal(*pp, name) ; pp++); 327 if (*pp == NULL) 328 *pp = savestr(name); 329} 330 331 332void 333dodecl(char *line1, FILE *fp) 334{ 335 char line[1024]; 336 char *p, *q; 337 338 if (strcmp(line1, "MKINIT\n") == 0) { /* start of struct/union decl */ 339 addchar('\n', &decls); 340 do { 341 linno++; 342 if (fgets(line, sizeof line, fp) == NULL) 343 error("Unterminated structure declaration"); 344 addstr(line, &decls); 345 } while (line[0] != '}'); 346 amiddecls = 0; 347 } else { 348 if (! amiddecls) 349 addchar('\n', &decls); 350 q = NULL; 351 for (p = line1 + 6 ; *p && strchr("=/\n", *p) == NULL; p++) 352 continue; 353 if (*p == '=') { /* eliminate initialization */ 354 for (q = p ; *q && *q != ';' ; q++); 355 if (*q == '\0') 356 q = NULL; 357 else { 358 while (p[-1] == ' ') 359 p--; 360 *p = '\0'; 361 } 362 } 363 addstr("extern", &decls); 364 addstr(line1 + 6, &decls); 365 if (q != NULL) 366 addstr(q, &decls); 367 amiddecls = 1; 368 } 369} 370 371 372 373/* 374 * Write the output to the file OUTTEMP. 375 */ 376 377void 378output(void) 379{ 380 FILE *fp; 381 char **pp; 382 struct event *ep; 383 384 fp = ckfopen(OUTTEMP, "w"); 385 fputs(writer, fp); 386 for (pp = header_files ; *pp ; pp++) 387 fprintf(fp, "#include %s\n", *pp); 388 fputs("\n\n\n", fp); 389 writetext(&defines, fp); 390 fputs("\n\n", fp); 391 writetext(&decls, fp); 392 for (ep = event ; ep->name ; ep++) { 393 fputs("\n\n\n", fp); 394 fputs(ep->comment, fp); 395 fprintf(fp, "\nvoid\n%s(void)\n{\n", ep->routine); 396 writetext(&ep->code, fp); 397 fprintf(fp, "}\n"); 398 } 399 fclose(fp); 400} 401 402 403/* 404 * A text structure is simply a block of text that is kept in memory. 405 * Addstr appends a string to the text struct, and addchar appends a single 406 * character. 407 */ 408 409void 410addstr(char *s, struct text *text) 411{ 412 while (*s) { 413 if (--text->nleft < 0) 414 addchar(*s++, text); 415 else 416 *text->nextc++ = *s++; 417 } 418} 419 420 421void 422addchar(int c, struct text *text) 423{ 424 struct block *bp; 425 426 if (--text->nleft < 0) { 427 bp = ckmalloc(sizeof *bp); 428 if (text->start == NULL) 429 text->start = bp; 430 else 431 text->last->next = bp; 432 text->last = bp; 433 text->nextc = bp->text; 434 text->nleft = BLOCKSIZE - 1; 435 } 436 *text->nextc++ = c; 437} 438 439/* 440 * Write the contents of a text structure to a file. 441 */ 442void 443writetext(struct text *text, FILE *fp) 444{ 445 struct block *bp; 446 447 if (text->start != NULL) { 448 for (bp = text->start ; bp != text->last ; bp = bp->next) 449 fwrite(bp->text, sizeof (char), BLOCKSIZE, fp); 450 fwrite(bp->text, sizeof (char), BLOCKSIZE - text->nleft, fp); 451 } 452} 453 454FILE * 455ckfopen(char *file, char *mode) 456{ 457 FILE *fp; 458 459 if ((fp = fopen(file, mode)) == NULL) { 460 fprintf(stderr, "Can't open %s: %s\n", file, strerror(errno)); 461 exit(2); 462 } 463 return fp; 464} 465 466void * 467ckmalloc(size_t nbytes) 468{ 469 char *p; 470 471 if ((p = malloc(nbytes)) == NULL) 472 error("Out of space"); 473 return p; 474} 475 476char * 477savestr(char *s) 478{ 479 char *p; 480 481 p = ckmalloc(strlen(s) + 1); 482 strcpy(p, s); 483 return p; 484} 485 486void 487error(char *msg) 488{ 489 if (curfile != NULL) 490 fprintf(stderr, "%s:%d: ", curfile, linno); 491 fprintf(stderr, "%s\n", msg); 492 exit(2); 493} 494