mkinit.c revision 1556
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 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37#ifndef lint 38static char copyright[] = 39"@(#) Copyright (c) 1991, 1993\n\ 40 The Regents of the University of California. All rights reserved.\n"; 41#endif /* not lint */ 42 43#ifndef lint 44static char sccsid[] = "@(#)mkinit.c 8.1 (Berkeley) 5/31/93"; 45#endif /* not lint */ 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. The command is executed iff init.c 53 * is actually changed. 54 * 55 * Usage: mkinit command sourcefile... 56 */ 57 58 59#include <sys/cdefs.h> 60#include <sys/types.h> 61#include <stdio.h> 62#include <fcntl.h> 63#include <unistd.h> 64 65 66/* 67 * OUTFILE is the name of the output file. Output is initially written 68 * to the file OUTTEMP, which is then moved to OUTFILE if OUTTEMP and 69 * OUTFILE are different. 70 */ 71 72#define OUTFILE "init.c" 73#define OUTTEMP "init.c.new" 74#define OUTOBJ "init.o" 75 76 77/* 78 * A text structure is basicly just a string that grows as more characters 79 * are added onto the end of it. It is implemented as a linked list of 80 * blocks of characters. The routines addstr and addchar append a string 81 * or a single character, respectively, to a text structure. Writetext 82 * writes the contents of a text structure to a file. 83 */ 84 85#define BLOCKSIZE 512 86 87struct text { 88 char *nextc; 89 int nleft; 90 struct block *start; 91 struct block *last; 92}; 93 94struct block { 95 struct block *next; 96 char text[BLOCKSIZE]; 97}; 98 99 100/* 101 * There is one event structure for each event that mkinit handles. 102 */ 103 104struct event { 105 char *name; /* name of event (e.g. INIT) */ 106 char *routine; /* name of routine called on event */ 107 char *comment; /* comment describing routine */ 108 struct text code; /* code for handling event */ 109}; 110 111 112char writer[] = "\ 113/*\n\ 114 * This file was generated by the mkinit program.\n\ 115 */\n\ 116\n"; 117 118char init[] = "\ 119/*\n\ 120 * Initialization code.\n\ 121 */\n"; 122 123char reset[] = "\ 124/*\n\ 125 * This routine is called when an error or an interrupt occurs in an\n\ 126 * interactive shell and control is returned to the main command loop.\n\ 127 */\n"; 128 129char shellproc[] = "\ 130/*\n\ 131 * This routine is called to initialize the shell to run a shell procedure.\n\ 132 */\n"; 133 134 135struct event event[] = { 136 {"INIT", "init", init}, 137 {"RESET", "reset", reset}, 138 {"SHELLPROC", "initshellproc", shellproc}, 139 {NULL, NULL} 140}; 141 142 143char *curfile; /* current file */ 144int linno; /* current line */ 145char *header_files[200]; /* list of header files */ 146struct text defines; /* #define statements */ 147struct text decls; /* declarations */ 148int amiddecls; /* for formatting */ 149 150 151void readfile(), doevent(), doinclude(), dodecl(), output(); 152void addstr(), addchar(), writetext(); 153 154#define equal(s1, s2) (strcmp(s1, s2) == 0) 155 156FILE *ckfopen(); 157char *savestr(); 158void *ckmalloc __P((int)); 159void error(); 160 161main(argc, argv) 162 char **argv; 163 { 164 char **ap; 165 int fd; 166 char c; 167 168 if (argc < 2) 169 error("Usage: mkinit command file..."); 170 header_files[0] = "\"shell.h\""; 171 header_files[1] = "\"mystring.h\""; 172 for (ap = argv + 2 ; *ap ; ap++) 173 readfile(*ap); 174 output(); 175 if (file_changed()) { 176 unlink(OUTFILE); 177 link(OUTTEMP, OUTFILE); 178 unlink(OUTTEMP); 179 } else { 180 unlink(OUTTEMP); 181 if (touch(OUTOBJ)) 182 exit(0); /* no compilation necessary */ 183 } 184 printf("%s\n", argv[1]); 185 execl("/bin/sh", "sh", "-c", argv[1], (char *)0); 186 error("Can't exec shell"); 187} 188 189 190/* 191 * Parse an input file. 192 */ 193 194void 195readfile(fname) 196 char *fname; 197 { 198 FILE *fp; 199 char line[1024]; 200 struct event *ep; 201 202 fp = ckfopen(fname, "r"); 203 curfile = fname; 204 linno = 0; 205 amiddecls = 0; 206 while (fgets(line, sizeof line, fp) != NULL) { 207 linno++; 208 for (ep = event ; ep->name ; ep++) { 209 if (line[0] == ep->name[0] && match(ep->name, line)) { 210 doevent(ep, fp, fname); 211 break; 212 } 213 } 214 if (line[0] == 'I' && match("INCLUDE", line)) 215 doinclude(line); 216 if (line[0] == 'M' && match("MKINIT", line)) 217 dodecl(line, fp); 218 if (line[0] == '#' && gooddefine(line)) 219 addstr(line, &defines); 220 } 221 fclose(fp); 222} 223 224 225int 226match(name, line) 227 char *name; 228 char *line; 229 { 230 register char *p, *q; 231 232 p = name, q = line; 233 while (*p) { 234 if (*p++ != *q++) 235 return 0; 236 } 237 if (*q != '{' && *q != ' ' && *q != '\t' && *q != '\n') 238 return 0; 239 return 1; 240} 241 242 243int 244gooddefine(line) 245 char *line; 246 { 247 register char *p; 248 249 if (! match("#define", line)) 250 return 0; /* not a define */ 251 p = line + 7; 252 while (*p == ' ' || *p == '\t') 253 p++; 254 while (*p != ' ' && *p != '\t') { 255 if (*p == '(') 256 return 0; /* macro definition */ 257 p++; 258 } 259 while (*p != '\n' && *p != '\0') 260 p++; 261 if (p[-1] == '\\') 262 return 0; /* multi-line definition */ 263 return 1; 264} 265 266 267void 268doevent(ep, fp, fname) 269 register struct event *ep; 270 FILE *fp; 271 char *fname; 272 { 273 char line[1024]; 274 int indent; 275 char *p; 276 277 sprintf(line, "\n /* from %s: */\n", fname); 278 addstr(line, &ep->code); 279 addstr(" {\n", &ep->code); 280 for (;;) { 281 linno++; 282 if (fgets(line, sizeof line, fp) == NULL) 283 error("Unexpected EOF"); 284 if (equal(line, "}\n")) 285 break; 286 indent = 6; 287 for (p = line ; *p == '\t' ; p++) 288 indent += 8; 289 for ( ; *p == ' ' ; p++) 290 indent++; 291 if (*p == '\n' || *p == '#') 292 indent = 0; 293 while (indent >= 8) { 294 addchar('\t', &ep->code); 295 indent -= 8; 296 } 297 while (indent > 0) { 298 addchar(' ', &ep->code); 299 indent--; 300 } 301 addstr(p, &ep->code); 302 } 303 addstr(" }\n", &ep->code); 304} 305 306 307void 308doinclude(line) 309 char *line; 310 { 311 register char *p; 312 char *name; 313 register 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(line1, fp) 334 char *line1; 335 FILE *fp; 336 { 337 char line[1024]; 338 register char *p, *q; 339 340 if (strcmp(line1, "MKINIT\n") == 0) { /* start of struct/union decl */ 341 addchar('\n', &decls); 342 do { 343 linno++; 344 if (fgets(line, sizeof line, fp) == NULL) 345 error("Unterminated structure declaration"); 346 addstr(line, &decls); 347 } while (line[0] != '}'); 348 amiddecls = 0; 349 } else { 350 if (! amiddecls) 351 addchar('\n', &decls); 352 q = NULL; 353 for (p = line1 + 6 ; *p != '=' && *p != '/' ; p++); 354 if (*p == '=') { /* eliminate initialization */ 355 for (q = p ; *q && *q != ';' ; q++); 356 if (*q == '\0') 357 q = NULL; 358 else { 359 while (p[-1] == ' ') 360 p--; 361 *p = '\0'; 362 } 363 } 364 addstr("extern", &decls); 365 addstr(line1 + 6, &decls); 366 if (q != NULL) 367 addstr(q, &decls); 368 amiddecls = 1; 369 } 370} 371 372 373 374/* 375 * Write the output to the file OUTTEMP. 376 */ 377 378void 379output() { 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() {\n", ep->routine); 396 writetext(&ep->code, fp); 397 fprintf(fp, "}\n"); 398 } 399 fclose(fp); 400} 401 402 403/* 404 * Return true if the new output file is different from the old one. 405 */ 406 407int 408file_changed() { 409 register FILE *f1, *f2; 410 register int c; 411 412 if ((f1 = fopen(OUTFILE, "r")) == NULL 413 || (f2 = fopen(OUTTEMP, "r")) == NULL) 414 return 1; 415 while ((c = getc(f1)) == getc(f2)) { 416 if (c == EOF) 417 return 0; 418 } 419 return 1; 420} 421 422 423/* 424 * Touch a file. Returns 0 on failure, 1 on success. 425 */ 426 427int 428touch(file) 429 char *file; 430 { 431 int fd; 432 char c; 433 434 if ((fd = open(file, O_RDWR)) < 0) 435 return 0; 436 if (read(fd, &c, 1) != 1) { 437 close(fd); 438 return 0; 439 } 440 lseek(fd, (off_t)0, 0); 441 write(fd, &c, 1); 442 close(fd); 443 return 1; 444} 445 446 447 448/* 449 * A text structure is simply a block of text that is kept in memory. 450 * Addstr appends a string to the text struct, and addchar appends a single 451 * character. 452 */ 453 454void 455addstr(s, text) 456 register char *s; 457 register struct text *text; 458 { 459 while (*s) { 460 if (--text->nleft < 0) 461 addchar(*s++, text); 462 else 463 *text->nextc++ = *s++; 464 } 465} 466 467 468void 469addchar(c, text) 470 register struct text *text; 471 { 472 struct block *bp; 473 474 if (--text->nleft < 0) { 475 bp = ckmalloc(sizeof *bp); 476 if (text->start == NULL) 477 text->start = bp; 478 else 479 text->last->next = bp; 480 text->last = bp; 481 text->nextc = bp->text; 482 text->nleft = BLOCKSIZE - 1; 483 } 484 *text->nextc++ = c; 485} 486 487/* 488 * Write the contents of a text structure to a file. 489 */ 490void 491writetext(text, fp) 492 struct text *text; 493 FILE *fp; 494 { 495 struct block *bp; 496 497 if (text->start != NULL) { 498 for (bp = text->start ; bp != text->last ; bp = bp->next) 499 fwrite(bp->text, sizeof (char), BLOCKSIZE, fp); 500 fwrite(bp->text, sizeof (char), BLOCKSIZE - text->nleft, fp); 501 } 502} 503 504FILE * 505ckfopen(file, mode) 506 char *file; 507 char *mode; 508 { 509 FILE *fp; 510 511 if ((fp = fopen(file, mode)) == NULL) { 512 fprintf(stderr, "Can't open %s\n", file); 513 exit(2); 514 } 515 return fp; 516} 517 518void * 519ckmalloc(nbytes) { 520 register char *p; 521 char *malloc(); 522 523 if ((p = malloc(nbytes)) == NULL) 524 error("Out of space"); 525 return p; 526} 527 528char * 529savestr(s) 530 char *s; 531 { 532 register char *p; 533 534 p = ckmalloc(strlen(s) + 1); 535 strcpy(p, s); 536 return p; 537} 538 539void 540error(msg) 541 char *msg; 542 { 543 if (curfile != NULL) 544 fprintf(stderr, "%s:%d: ", curfile, linno); 545 fprintf(stderr, "%s\n", msg); 546 exit(2); 547} 548