mkinit.c revision 218306
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 218306 2011-02-04 22:47:55Z jilles $"); 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 const char *name; /* name of event (e.g. INIT) */ 106 const char *routine; /* name of routine called on event */ 107 const 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 129 130struct event event[] = { 131 { "INIT", "init", init, { NULL, 0, NULL, NULL } }, 132 { "RESET", "reset", reset, { NULL, 0, NULL, NULL } }, 133 { NULL, NULL, NULL, { NULL, 0, NULL, NULL } } 134}; 135 136 137const char *curfile; /* current file */ 138int linno; /* current line */ 139char *header_files[200]; /* list of header files */ 140struct text defines; /* #define statements */ 141struct text decls; /* declarations */ 142int amiddecls; /* for formatting */ 143 144 145void readfile(const char *); 146int match(const char *, const char *); 147int gooddefine(const char *); 148void doevent(struct event *, FILE *, const char *); 149void doinclude(char *); 150void dodecl(char *, FILE *); 151void output(void); 152void addstr(const char *, struct text *); 153void addchar(int, struct text *); 154void writetext(struct text *, FILE *); 155FILE *ckfopen(const char *, const char *); 156void *ckmalloc(size_t); 157char *savestr(const char *); 158void error(const char *); 159 160#define equal(s1, s2) (strcmp(s1, s2) == 0) 161 162int 163main(int argc __unused, char *argv[]) 164{ 165 char **ap; 166 167 header_files[0] = savestr("\"shell.h\""); 168 header_files[1] = savestr("\"mystring.h\""); 169 header_files[2] = savestr("\"init.h\""); 170 for (ap = argv + 1 ; *ap ; ap++) 171 readfile(*ap); 172 output(); 173 rename(OUTTEMP, OUTFILE); 174 exit(0); 175} 176 177 178/* 179 * Parse an input file. 180 */ 181 182void 183readfile(const char *fname) 184{ 185 FILE *fp; 186 char line[1024]; 187 struct event *ep; 188 189 fp = ckfopen(fname, "r"); 190 curfile = fname; 191 linno = 0; 192 amiddecls = 0; 193 while (fgets(line, sizeof line, fp) != NULL) { 194 linno++; 195 for (ep = event ; ep->name ; ep++) { 196 if (line[0] == ep->name[0] && match(ep->name, line)) { 197 doevent(ep, fp, fname); 198 break; 199 } 200 } 201 if (line[0] == 'I' && match("INCLUDE", line)) 202 doinclude(line); 203 if (line[0] == 'M' && match("MKINIT", line)) 204 dodecl(line, fp); 205 if (line[0] == '#' && gooddefine(line)) { 206 char *cp; 207 char line2[1024]; 208 static const char undef[] = "#undef "; 209 210 strcpy(line2, line); 211 memcpy(line2, undef, sizeof(undef) - 1); 212 cp = line2 + sizeof(undef) - 1; 213 while(*cp && (*cp == ' ' || *cp == '\t')) 214 cp++; 215 while(*cp && *cp != ' ' && *cp != '\t' && *cp != '\n') 216 cp++; 217 *cp++ = '\n'; *cp = '\0'; 218 addstr(line2, &defines); 219 addstr(line, &defines); 220 } 221 } 222 fclose(fp); 223} 224 225 226int 227match(const char *name, const char *line) 228{ 229 const char *p, *q; 230 231 p = name, q = line; 232 while (*p) { 233 if (*p++ != *q++) 234 return 0; 235 } 236 if (*q != '{' && *q != ' ' && *q != '\t' && *q != '\n') 237 return 0; 238 return 1; 239} 240 241 242int 243gooddefine(const char *line) 244{ 245 const char *p; 246 247 if (! match("#define", line)) 248 return 0; /* not a define */ 249 p = line + 7; 250 while (*p == ' ' || *p == '\t') 251 p++; 252 while (*p != ' ' && *p != '\t') { 253 if (*p == '(') 254 return 0; /* macro definition */ 255 p++; 256 } 257 while (*p != '\n' && *p != '\0') 258 p++; 259 if (p[-1] == '\\') 260 return 0; /* multi-line definition */ 261 return 1; 262} 263 264 265void 266doevent(struct event *ep, FILE *fp, const char *fname) 267{ 268 char line[1024]; 269 int indent; 270 const char *p; 271 272 sprintf(line, "\n /* from %s: */\n", fname); 273 addstr(line, &ep->code); 274 addstr(" {\n", &ep->code); 275 for (;;) { 276 linno++; 277 if (fgets(line, sizeof line, fp) == NULL) 278 error("Unexpected EOF"); 279 if (equal(line, "}\n")) 280 break; 281 indent = 6; 282 for (p = line ; *p == '\t' ; p++) 283 indent += 8; 284 for ( ; *p == ' ' ; p++) 285 indent++; 286 if (*p == '\n' || *p == '#') 287 indent = 0; 288 while (indent >= 8) { 289 addchar('\t', &ep->code); 290 indent -= 8; 291 } 292 while (indent > 0) { 293 addchar(' ', &ep->code); 294 indent--; 295 } 296 addstr(p, &ep->code); 297 } 298 addstr(" }\n", &ep->code); 299} 300 301 302void 303doinclude(char *line) 304{ 305 char *p; 306 char *name; 307 char **pp; 308 309 for (p = line ; *p != '"' && *p != '<' && *p != '\0' ; p++); 310 if (*p == '\0') 311 error("Expecting '\"' or '<'"); 312 name = p; 313 while (*p != ' ' && *p != '\t' && *p != '\n') 314 p++; 315 if (p[-1] != '"' && p[-1] != '>') 316 error("Missing terminator"); 317 *p = '\0'; 318 319 /* name now contains the name of the include file */ 320 for (pp = header_files ; *pp && ! equal(*pp, name) ; pp++); 321 if (*pp == NULL) 322 *pp = savestr(name); 323} 324 325 326void 327dodecl(char *line1, FILE *fp) 328{ 329 char line[1024]; 330 char *p, *q; 331 332 if (strcmp(line1, "MKINIT\n") == 0) { /* start of struct/union decl */ 333 addchar('\n', &decls); 334 do { 335 linno++; 336 if (fgets(line, sizeof line, fp) == NULL) 337 error("Unterminated structure declaration"); 338 addstr(line, &decls); 339 } while (line[0] != '}'); 340 amiddecls = 0; 341 } else { 342 if (! amiddecls) 343 addchar('\n', &decls); 344 q = NULL; 345 for (p = line1 + 6 ; *p && strchr("=/\n", *p) == NULL; p++) 346 continue; 347 if (*p == '=') { /* eliminate initialization */ 348 for (q = p ; *q && *q != ';' ; q++); 349 if (*q == '\0') 350 q = NULL; 351 else { 352 while (p[-1] == ' ') 353 p--; 354 *p = '\0'; 355 } 356 } 357 addstr("extern", &decls); 358 addstr(line1 + 6, &decls); 359 if (q != NULL) 360 addstr(q, &decls); 361 amiddecls = 1; 362 } 363} 364 365 366 367/* 368 * Write the output to the file OUTTEMP. 369 */ 370 371void 372output(void) 373{ 374 FILE *fp; 375 char **pp; 376 struct event *ep; 377 378 fp = ckfopen(OUTTEMP, "w"); 379 fputs(writer, fp); 380 for (pp = header_files ; *pp ; pp++) 381 fprintf(fp, "#include %s\n", *pp); 382 fputs("\n\n\n", fp); 383 writetext(&defines, fp); 384 fputs("\n\n", fp); 385 writetext(&decls, fp); 386 for (ep = event ; ep->name ; ep++) { 387 fputs("\n\n\n", fp); 388 fputs(ep->comment, fp); 389 fprintf(fp, "\nvoid\n%s(void)\n{\n", ep->routine); 390 writetext(&ep->code, fp); 391 fprintf(fp, "}\n"); 392 } 393 fclose(fp); 394} 395 396 397/* 398 * A text structure is simply a block of text that is kept in memory. 399 * Addstr appends a string to the text struct, and addchar appends a single 400 * character. 401 */ 402 403void 404addstr(const char *s, struct text *text) 405{ 406 while (*s) { 407 if (--text->nleft < 0) 408 addchar(*s++, text); 409 else 410 *text->nextc++ = *s++; 411 } 412} 413 414 415void 416addchar(int c, struct text *text) 417{ 418 struct block *bp; 419 420 if (--text->nleft < 0) { 421 bp = ckmalloc(sizeof *bp); 422 if (text->start == NULL) 423 text->start = bp; 424 else 425 text->last->next = bp; 426 text->last = bp; 427 text->nextc = bp->text; 428 text->nleft = BLOCKSIZE - 1; 429 } 430 *text->nextc++ = c; 431} 432 433/* 434 * Write the contents of a text structure to a file. 435 */ 436void 437writetext(struct text *text, FILE *fp) 438{ 439 struct block *bp; 440 441 if (text->start != NULL) { 442 for (bp = text->start ; bp != text->last ; bp = bp->next) 443 fwrite(bp->text, sizeof (char), BLOCKSIZE, fp); 444 fwrite(bp->text, sizeof (char), BLOCKSIZE - text->nleft, fp); 445 } 446} 447 448FILE * 449ckfopen(const char *file, const char *mode) 450{ 451 FILE *fp; 452 453 if ((fp = fopen(file, mode)) == NULL) { 454 fprintf(stderr, "Can't open %s: %s\n", file, strerror(errno)); 455 exit(2); 456 } 457 return fp; 458} 459 460void * 461ckmalloc(size_t nbytes) 462{ 463 char *p; 464 465 if ((p = malloc(nbytes)) == NULL) 466 error("Out of space"); 467 return p; 468} 469 470char * 471savestr(const char *s) 472{ 473 char *p; 474 475 p = ckmalloc(strlen(s) + 1); 476 strcpy(p, s); 477 return p; 478} 479 480void 481error(const char *msg) 482{ 483 if (curfile != NULL) 484 fprintf(stderr, "%s:%d: ", curfile, linno); 485 fprintf(stderr, "%s\n", msg); 486 exit(2); 487} 488