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