1 /*- 2 * Copyright (c) 1991 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Kenneth Almquist. 7 * 8 * %sccs.include.redist.c% 9 */ 10 11 #ifndef lint 12 char copyright[] = 13 "@(#) Copyright (c) 1991 The Regents of the University of California.\n\ 14 All rights reserved.\n"; 15 #endif /* not lint */ 16 17 #ifndef lint 18 static char sccsid[] = "@(#)mkinit.c 5.3 (Berkeley) 03/13/91"; 19 #endif /* not lint */ 20 21 /* 22 * This program scans all the source files for code to handle various 23 * special events and combines this code into one file. This (allegedly) 24 * improves the structure of the program since there is no need for 25 * anyone outside of a module to know that that module performs special 26 * operations on particular events. The command is executed iff init.c 27 * is actually changed. 28 * 29 * Usage: mkinit command sourcefile... 30 */ 31 32 33 #include <sys/cdefs.h> 34 #include <stdio.h> 35 #include <fcntl.h> 36 37 38 /* 39 * OUTFILE is the name of the output file. Output is initially written 40 * to the file OUTTEMP, which is then moved to OUTFILE if OUTTEMP and 41 * OUTFILE are different. 42 */ 43 44 #define OUTFILE "init.c" 45 #define OUTTEMP "init.c.new" 46 #define OUTOBJ "init.o" 47 48 49 /* 50 * A text structure is basicly just a string that grows as more characters 51 * are added onto the end of it. It is implemented as a linked list of 52 * blocks of characters. The routines addstr and addchar append a string 53 * or a single character, respectively, to a text structure. Writetext 54 * writes the contents of a text structure to a file. 55 */ 56 57 #define BLOCKSIZE 512 58 59 struct text { 60 char *nextc; 61 int nleft; 62 struct block *start; 63 struct block *last; 64 }; 65 66 struct block { 67 struct block *next; 68 char text[BLOCKSIZE]; 69 }; 70 71 72 /* 73 * There is one event structure for each event that mkinit handles. 74 */ 75 76 struct event { 77 char *name; /* name of event (e.g. INIT) */ 78 char *routine; /* name of routine called on event */ 79 char *comment; /* comment describing routine */ 80 struct text code; /* code for handling event */ 81 }; 82 83 84 char writer[] = "\ 85 /*\n\ 86 * This file was generated by the mkinit program.\n\ 87 */\n\ 88 \n"; 89 90 char init[] = "\ 91 /*\n\ 92 * Initialization code.\n\ 93 */\n"; 94 95 char reset[] = "\ 96 /*\n\ 97 * This routine is called when an error or an interrupt occurs in an\n\ 98 * interactive shell and control is returned to the main command loop.\n\ 99 */\n"; 100 101 char shellproc[] = "\ 102 /*\n\ 103 * This routine is called to initialize the shell to run a shell procedure.\n\ 104 */\n"; 105 106 107 struct event event[] = { 108 {"INIT", "init", init}, 109 {"RESET", "reset", reset}, 110 {"SHELLPROC", "initshellproc", shellproc}, 111 {NULL, NULL} 112 }; 113 114 115 char *curfile; /* current file */ 116 int linno; /* current line */ 117 char *header_files[200]; /* list of header files */ 118 struct text defines; /* #define statements */ 119 struct text decls; /* declarations */ 120 int amiddecls; /* for formatting */ 121 122 123 void readfile(), doevent(), doinclude(), dodecl(), output(); 124 void addstr(), addchar(), writetext(); 125 126 #define equal(s1, s2) (strcmp(s1, s2) == 0) 127 128 FILE *ckfopen(); 129 char *savestr(); 130 void *ckmalloc __P((int)); 131 void error(); 132 133 main(argc, argv) 134 char **argv; 135 { 136 char **ap; 137 int fd; 138 char c; 139 140 if (argc < 2) 141 error("Usage: mkinit command file..."); 142 header_files[0] = "\"shell.h\""; 143 header_files[1] = "\"mystring.h\""; 144 for (ap = argv + 2 ; *ap ; ap++) 145 readfile(*ap); 146 output(); 147 if (file_changed()) { 148 unlink(OUTFILE); 149 link(OUTTEMP, OUTFILE); 150 unlink(OUTTEMP); 151 } else { 152 unlink(OUTTEMP); 153 if (touch(OUTOBJ)) 154 exit(0); /* no compilation necessary */ 155 } 156 printf("%s\n", argv[1]); 157 execl("/bin/sh", "sh", "-c", argv[1], (char *)0); 158 error("Can't exec shell"); 159 } 160 161 162 /* 163 * Parse an input file. 164 */ 165 166 void 167 readfile(fname) 168 char *fname; 169 { 170 FILE *fp; 171 char line[1024]; 172 struct event *ep; 173 174 fp = ckfopen(fname, "r"); 175 curfile = fname; 176 linno = 0; 177 amiddecls = 0; 178 while (fgets(line, sizeof line, fp) != NULL) { 179 linno++; 180 for (ep = event ; ep->name ; ep++) { 181 if (line[0] == ep->name[0] && match(ep->name, line)) { 182 doevent(ep, fp, fname); 183 break; 184 } 185 } 186 if (line[0] == 'I' && match("INCLUDE", line)) 187 doinclude(line); 188 if (line[0] == 'M' && match("MKINIT", line)) 189 dodecl(line, fp); 190 if (line[0] == '#' && gooddefine(line)) 191 addstr(line, &defines); 192 } 193 fclose(fp); 194 } 195 196 197 int 198 match(name, line) 199 char *name; 200 char *line; 201 { 202 register char *p, *q; 203 204 p = name, q = line; 205 while (*p) { 206 if (*p++ != *q++) 207 return 0; 208 } 209 if (*q != '{' && *q != ' ' && *q != '\t' && *q != '\n') 210 return 0; 211 return 1; 212 } 213 214 215 int 216 gooddefine(line) 217 char *line; 218 { 219 register char *p; 220 221 if (! match("#define", line)) 222 return 0; /* not a define */ 223 p = line + 7; 224 while (*p == ' ' || *p == '\t') 225 p++; 226 while (*p != ' ' && *p != '\t') { 227 if (*p == '(') 228 return 0; /* macro definition */ 229 p++; 230 } 231 while (*p != '\n' && *p != '\0') 232 p++; 233 if (p[-1] == '\\') 234 return 0; /* multi-line definition */ 235 return 1; 236 } 237 238 239 void 240 doevent(ep, fp, fname) 241 register struct event *ep; 242 FILE *fp; 243 char *fname; 244 { 245 char line[1024]; 246 int indent; 247 char *p; 248 249 sprintf(line, "\n /* from %s: */\n", fname); 250 addstr(line, &ep->code); 251 addstr(" {\n", &ep->code); 252 for (;;) { 253 linno++; 254 if (fgets(line, sizeof line, fp) == NULL) 255 error("Unexpected EOF"); 256 if (equal(line, "}\n")) 257 break; 258 indent = 6; 259 for (p = line ; *p == '\t' ; p++) 260 indent += 8; 261 for ( ; *p == ' ' ; p++) 262 indent++; 263 if (*p == '\n' || *p == '#') 264 indent = 0; 265 while (indent >= 8) { 266 addchar('\t', &ep->code); 267 indent -= 8; 268 } 269 while (indent > 0) { 270 addchar(' ', &ep->code); 271 indent--; 272 } 273 addstr(p, &ep->code); 274 } 275 addstr(" }\n", &ep->code); 276 } 277 278 279 void 280 doinclude(line) 281 char *line; 282 { 283 register char *p; 284 char *name; 285 register char **pp; 286 287 for (p = line ; *p != '"' && *p != '<' && *p != '\0' ; p++); 288 if (*p == '\0') 289 error("Expecting '\"' or '<'"); 290 name = p; 291 while (*p != ' ' && *p != '\t' && *p != '\n') 292 p++; 293 if (p[-1] != '"' && p[-1] != '>') 294 error("Missing terminator"); 295 *p = '\0'; 296 297 /* name now contains the name of the include file */ 298 for (pp = header_files ; *pp && ! equal(*pp, name) ; pp++); 299 if (*pp == NULL) 300 *pp = savestr(name); 301 } 302 303 304 void 305 dodecl(line1, fp) 306 char *line1; 307 FILE *fp; 308 { 309 char line[1024]; 310 register char *p, *q; 311 312 if (strcmp(line1, "MKINIT\n") == 0) { /* start of struct/union decl */ 313 addchar('\n', &decls); 314 do { 315 linno++; 316 if (fgets(line, sizeof line, fp) == NULL) 317 error("Unterminated structure declaration"); 318 addstr(line, &decls); 319 } while (line[0] != '}'); 320 amiddecls = 0; 321 } else { 322 if (! amiddecls) 323 addchar('\n', &decls); 324 q = NULL; 325 for (p = line1 + 6 ; *p != '=' && *p != '/' ; p++); 326 if (*p == '=') { /* eliminate initialization */ 327 for (q = p ; *q && *q != ';' ; q++); 328 if (*q == '\0') 329 q = NULL; 330 else { 331 while (p[-1] == ' ') 332 p--; 333 *p = '\0'; 334 } 335 } 336 addstr("extern", &decls); 337 addstr(line1 + 6, &decls); 338 if (q != NULL) 339 addstr(q, &decls); 340 amiddecls = 1; 341 } 342 } 343 344 345 346 /* 347 * Write the output to the file OUTTEMP. 348 */ 349 350 void 351 output() { 352 FILE *fp; 353 char **pp; 354 struct event *ep; 355 356 fp = ckfopen(OUTTEMP, "w"); 357 fputs(writer, fp); 358 for (pp = header_files ; *pp ; pp++) 359 fprintf(fp, "#include %s\n", *pp); 360 fputs("\n\n\n", fp); 361 writetext(&defines, fp); 362 fputs("\n\n", fp); 363 writetext(&decls, fp); 364 for (ep = event ; ep->name ; ep++) { 365 fputs("\n\n\n", fp); 366 fputs(ep->comment, fp); 367 fprintf(fp, "\nvoid\n%s() {\n", ep->routine); 368 writetext(&ep->code, fp); 369 fprintf(fp, "}\n"); 370 } 371 fclose(fp); 372 } 373 374 375 /* 376 * Return true if the new output file is different from the old one. 377 */ 378 379 int 380 file_changed() { 381 register FILE *f1, *f2; 382 register int c; 383 384 if ((f1 = fopen(OUTFILE, "r")) == NULL 385 || (f2 = fopen(OUTTEMP, "r")) == NULL) 386 return 1; 387 while ((c = getc(f1)) == getc(f2)) { 388 if (c == EOF) 389 return 0; 390 } 391 return 1; 392 } 393 394 395 /* 396 * Touch a file. Returns 0 on failure, 1 on success. 397 */ 398 399 int 400 touch(file) 401 char *file; 402 { 403 int fd; 404 char c; 405 406 if ((fd = open(file, O_RDWR)) < 0) 407 return 0; 408 if (read(fd, &c, 1) != 1) { 409 close(fd); 410 return 0; 411 } 412 lseek(fd, 0L, 0); 413 write(fd, &c, 1); 414 close(fd); 415 return 1; 416 } 417 418 419 420 /* 421 * A text structure is simply a block of text that is kept in memory. 422 * Addstr appends a string to the text struct, and addchar appends a single 423 * character. 424 */ 425 426 void 427 addstr(s, text) 428 register char *s; 429 register struct text *text; 430 { 431 while (*s) { 432 if (--text->nleft < 0) 433 addchar(*s++, text); 434 else 435 *text->nextc++ = *s++; 436 } 437 } 438 439 440 void 441 addchar(c, text) 442 register struct text *text; 443 { 444 struct block *bp; 445 446 if (--text->nleft < 0) { 447 bp = ckmalloc(sizeof *bp); 448 if (text->start == NULL) 449 text->start = bp; 450 else 451 text->last->next = bp; 452 text->last = bp; 453 text->nextc = bp->text; 454 text->nleft = BLOCKSIZE - 1; 455 } 456 *text->nextc++ = c; 457 } 458 459 /* 460 * Write the contents of a text structure to a file. 461 */ 462 void 463 writetext(text, fp) 464 struct text *text; 465 FILE *fp; 466 { 467 struct block *bp; 468 469 if (text->start != NULL) { 470 for (bp = text->start ; bp != text->last ; bp = bp->next) 471 fwrite(bp->text, sizeof (char), BLOCKSIZE, fp); 472 fwrite(bp->text, sizeof (char), BLOCKSIZE - text->nleft, fp); 473 } 474 } 475 476 FILE * 477 ckfopen(file, mode) 478 char *file; 479 char *mode; 480 { 481 FILE *fp; 482 483 if ((fp = fopen(file, mode)) == NULL) { 484 fprintf(stderr, "Can't open %s\n", file); 485 exit(2); 486 } 487 return fp; 488 } 489 490 void * 491 ckmalloc(nbytes) { 492 register char *p; 493 char *malloc(); 494 495 if ((p = malloc(nbytes)) == NULL) 496 error("Out of space"); 497 return p; 498 } 499 500 char * 501 savestr(s) 502 char *s; 503 { 504 register char *p; 505 506 p = ckmalloc(strlen(s) + 1); 507 strcpy(p, s); 508 return p; 509 } 510 511 void 512 error(msg) 513 char *msg; 514 { 515 if (curfile != NULL) 516 fprintf(stderr, "%s:%d: ", curfile, linno); 517 fprintf(stderr, "%s\n", msg); 518 exit(2); 519 } 520