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