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