mkinit.c revision 149019
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 * 4. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33#ifndef lint 34static char const copyright[] = 35"@(#) Copyright (c) 1991, 1993\n\ 36 The Regents of the University of California. All rights reserved.\n"; 37#endif /* not lint */ 38 39#ifndef lint 40#if 0 41static char sccsid[] = "@(#)mkinit.c 8.2 (Berkeley) 5/4/95"; 42#endif 43#endif /* not lint */ 44#include <sys/cdefs.h> 45__FBSDID("$FreeBSD: head/bin/sh/mkinit.c 149019 2005-08-13 08:38:02Z stefanf $"); 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. 53 * 54 * Usage: mkinit sourcefile... 55 */ 56 57 58#include <sys/cdefs.h> 59#include <sys/types.h> 60#include <stdio.h> 61#include <stdlib.h> 62#include <string.h> 63#include <fcntl.h> 64#include <unistd.h> 65#include <errno.h> 66 67 68/* 69 * OUTFILE is the name of the output file. Output is initially written 70 * to the file OUTTEMP, which is then moved to OUTFILE. 71 */ 72 73#define OUTFILE "init.c" 74#define OUTTEMP "init.c.new" 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, { NULL, 0, NULL, NULL } }, 137 { "RESET", "reset", reset, { NULL, 0, NULL, NULL } }, 138 { "SHELLPROC", "initshellproc", shellproc, { NULL, 0, NULL, NULL } }, 139 { NULL, NULL, NULL, { NULL, 0, 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(char *); 152int match(char *, char *); 153int gooddefine(char *); 154void doevent(struct event *, FILE *, char *); 155void doinclude(char *); 156void dodecl(char *, FILE *); 157void output(void); 158void addstr(char *, struct text *); 159void addchar(int, struct text *); 160void writetext(struct text *, FILE *); 161FILE *ckfopen(char *, char *); 162void *ckmalloc(int); 163char *savestr(char *); 164void error(char *); 165 166#define equal(s1, s2) (strcmp(s1, s2) == 0) 167 168int 169main(int argc __unused, char *argv[]) 170{ 171 char **ap; 172 173 header_files[0] = "\"shell.h\""; 174 header_files[1] = "\"mystring.h\""; 175 header_files[2] = "\"init.h\""; 176 for (ap = argv + 1 ; *ap ; ap++) 177 readfile(*ap); 178 output(); 179 rename(OUTTEMP, OUTFILE); 180 exit(0); 181} 182 183 184/* 185 * Parse an input file. 186 */ 187 188void 189readfile(char *fname) 190{ 191 FILE *fp; 192 char line[1024]; 193 struct event *ep; 194 195 fp = ckfopen(fname, "r"); 196 curfile = fname; 197 linno = 0; 198 amiddecls = 0; 199 while (fgets(line, sizeof line, fp) != NULL) { 200 linno++; 201 for (ep = event ; ep->name ; ep++) { 202 if (line[0] == ep->name[0] && match(ep->name, line)) { 203 doevent(ep, fp, fname); 204 break; 205 } 206 } 207 if (line[0] == 'I' && match("INCLUDE", line)) 208 doinclude(line); 209 if (line[0] == 'M' && match("MKINIT", line)) 210 dodecl(line, fp); 211 if (line[0] == '#' && gooddefine(line)) { 212 char *cp; 213 char line2[1024]; 214 static const char undef[] = "#undef "; 215 216 strcpy(line2, line); 217 memcpy(line2, undef, sizeof(undef) - 1); 218 cp = line2 + sizeof(undef) - 1; 219 while(*cp && (*cp == ' ' || *cp == '\t')) 220 cp++; 221 while(*cp && *cp != ' ' && *cp != '\t' && *cp != '\n') 222 cp++; 223 *cp++ = '\n'; *cp = '\0'; 224 addstr(line2, &defines); 225 addstr(line, &defines); 226 } 227 } 228 fclose(fp); 229} 230 231 232int 233match(char *name, char *line) 234{ 235 char *p, *q; 236 237 p = name, q = line; 238 while (*p) { 239 if (*p++ != *q++) 240 return 0; 241 } 242 if (*q != '{' && *q != ' ' && *q != '\t' && *q != '\n') 243 return 0; 244 return 1; 245} 246 247 248int 249gooddefine(char *line) 250{ 251 char *p; 252 253 if (! match("#define", line)) 254 return 0; /* not a define */ 255 p = line + 7; 256 while (*p == ' ' || *p == '\t') 257 p++; 258 while (*p != ' ' && *p != '\t') { 259 if (*p == '(') 260 return 0; /* macro definition */ 261 p++; 262 } 263 while (*p != '\n' && *p != '\0') 264 p++; 265 if (p[-1] == '\\') 266 return 0; /* multi-line definition */ 267 return 1; 268} 269 270 271void 272doevent(struct event *ep, FILE *fp, char *fname) 273{ 274 char line[1024]; 275 int indent; 276 char *p; 277 278 sprintf(line, "\n /* from %s: */\n", fname); 279 addstr(line, &ep->code); 280 addstr(" {\n", &ep->code); 281 for (;;) { 282 linno++; 283 if (fgets(line, sizeof line, fp) == NULL) 284 error("Unexpected EOF"); 285 if (equal(line, "}\n")) 286 break; 287 indent = 6; 288 for (p = line ; *p == '\t' ; p++) 289 indent += 8; 290 for ( ; *p == ' ' ; p++) 291 indent++; 292 if (*p == '\n' || *p == '#') 293 indent = 0; 294 while (indent >= 8) { 295 addchar('\t', &ep->code); 296 indent -= 8; 297 } 298 while (indent > 0) { 299 addchar(' ', &ep->code); 300 indent--; 301 } 302 addstr(p, &ep->code); 303 } 304 addstr(" }\n", &ep->code); 305} 306 307 308void 309doinclude(char *line) 310{ 311 char *p; 312 char *name; 313 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(char *line1, FILE *fp) 334{ 335 char line[1024]; 336 char *p, *q; 337 338 if (strcmp(line1, "MKINIT\n") == 0) { /* start of struct/union decl */ 339 addchar('\n', &decls); 340 do { 341 linno++; 342 if (fgets(line, sizeof line, fp) == NULL) 343 error("Unterminated structure declaration"); 344 addstr(line, &decls); 345 } while (line[0] != '}'); 346 amiddecls = 0; 347 } else { 348 if (! amiddecls) 349 addchar('\n', &decls); 350 q = NULL; 351 for (p = line1 + 6 ; *p && strchr("=/\n", *p) == NULL; p++) 352 continue; 353 if (*p == '=') { /* eliminate initialization */ 354 for (q = p ; *q && *q != ';' ; q++); 355 if (*q == '\0') 356 q = NULL; 357 else { 358 while (p[-1] == ' ') 359 p--; 360 *p = '\0'; 361 } 362 } 363 addstr("extern", &decls); 364 addstr(line1 + 6, &decls); 365 if (q != NULL) 366 addstr(q, &decls); 367 amiddecls = 1; 368 } 369} 370 371 372 373/* 374 * Write the output to the file OUTTEMP. 375 */ 376 377void 378output(void) 379{ 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(void)\n{\n", ep->routine); 396 writetext(&ep->code, fp); 397 fprintf(fp, "}\n"); 398 } 399 fclose(fp); 400} 401 402 403/* 404 * A text structure is simply a block of text that is kept in memory. 405 * Addstr appends a string to the text struct, and addchar appends a single 406 * character. 407 */ 408 409void 410addstr(char *s, struct text *text) 411{ 412 while (*s) { 413 if (--text->nleft < 0) 414 addchar(*s++, text); 415 else 416 *text->nextc++ = *s++; 417 } 418} 419 420 421void 422addchar(int c, struct text *text) 423{ 424 struct block *bp; 425 426 if (--text->nleft < 0) { 427 bp = ckmalloc(sizeof *bp); 428 if (text->start == NULL) 429 text->start = bp; 430 else 431 text->last->next = bp; 432 text->last = bp; 433 text->nextc = bp->text; 434 text->nleft = BLOCKSIZE - 1; 435 } 436 *text->nextc++ = c; 437} 438 439/* 440 * Write the contents of a text structure to a file. 441 */ 442void 443writetext(struct text *text, FILE *fp) 444{ 445 struct block *bp; 446 447 if (text->start != NULL) { 448 for (bp = text->start ; bp != text->last ; bp = bp->next) 449 fwrite(bp->text, sizeof (char), BLOCKSIZE, fp); 450 fwrite(bp->text, sizeof (char), BLOCKSIZE - text->nleft, fp); 451 } 452} 453 454FILE * 455ckfopen(char *file, char *mode) 456{ 457 FILE *fp; 458 459 if ((fp = fopen(file, mode)) == NULL) { 460 fprintf(stderr, "Can't open %s: %s\n", file, strerror(errno)); 461 exit(2); 462 } 463 return fp; 464} 465 466void * 467ckmalloc(int nbytes) 468{ 469 char *p; 470 471 if ((p = malloc(nbytes)) == NULL) 472 error("Out of space"); 473 return p; 474} 475 476char * 477savestr(char *s) 478{ 479 char *p; 480 481 p = ckmalloc(strlen(s) + 1); 482 strcpy(p, s); 483 return p; 484} 485 486void 487error(char *msg) 488{ 489 if (curfile != NULL) 490 fprintf(stderr, "%s:%d: ", curfile, linno); 491 fprintf(stderr, "%s\n", msg); 492 exit(2); 493} 494