1/*- 2 * Copyright (c) 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * Copyright (c) 1997-2005 5 * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Kenneth Almquist. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35/* 36 * This program scans all the source files for code to handle various 37 * special events and combines this code into one file. This (allegedly) 38 * improves the structure of the program since there is no need for 39 * anyone outside of a module to know that that module performs special 40 * operations on particular events. 41 * 42 * Usage: mkinit sourcefile... 43 */ 44 45 46#include <sys/types.h> 47#include <stdio.h> 48#include <stdlib.h> 49#include <string.h> 50#include <fcntl.h> 51#include <unistd.h> 52 53 54/* 55 * OUTFILE is the name of the output file. Output is initially written 56 * to the file OUTTEMP, which is then moved to OUTFILE. 57 */ 58 59#define OUTFILE "init.c" 60#define OUTTEMP "init.c.new" 61 62 63/* 64 * A text structure is basicly just a string that grows as more characters 65 * are added onto the end of it. It is implemented as a linked list of 66 * blocks of characters. The routines addstr and addchar append a string 67 * or a single character, respectively, to a text structure. Writetext 68 * writes the contents of a text structure to a file. 69 */ 70 71#define BLOCKSIZE 512 72 73struct text { 74 char *nextc; 75 int nleft; 76 struct block *start; 77 struct block *last; 78}; 79 80struct block { 81 struct block *next; 82 char text[BLOCKSIZE]; 83}; 84 85 86/* 87 * There is one event structure for each event that mkinit handles. 88 */ 89 90struct event { 91 char *name; /* name of event (e.g. INIT) */ 92 char *routine; /* name of routine called on event */ 93 char *comment; /* comment describing routine */ 94 struct text code; /* code for handling event */ 95}; 96 97 98char writer[] = "\ 99/*\n\ 100 * This file was generated by the mkinit program.\n\ 101 */\n\ 102\n"; 103 104char init[] = "\ 105/*\n\ 106 * Initialization code.\n\ 107 */\n"; 108 109char reset[] = "\ 110/*\n\ 111 * This routine is called when an error or an interrupt occurs in an\n\ 112 * interactive shell and control is returned to the main command loop.\n\ 113 */\n"; 114 115 116struct event event[] = { 117 {"INIT", "init", init}, 118 {"RESET", "reset", reset}, 119 {NULL, NULL} 120}; 121 122 123char *curfile; /* current file */ 124int linno; /* current line */ 125char *header_files[200]; /* list of header files */ 126struct text defines; /* #define statements */ 127struct text decls; /* declarations */ 128int amiddecls; /* for formatting */ 129 130 131void readfile(char *); 132int match(char *, char *); 133int gooddefine(char *); 134void doevent(struct event *, FILE *, char *); 135void doinclude(char *); 136void dodecl(char *, FILE *); 137void output(void); 138void addstr(char *, struct text *); 139void addchar(int, struct text *); 140void writetext(struct text *, FILE *); 141FILE *ckfopen(char *, char *); 142void *ckmalloc(int); 143char *savestr(char *); 144static void error(char *); 145int main(int, char **); 146 147#define equal(s1, s2) (strcmp(s1, s2) == 0) 148 149int 150main(int argc, char **argv) 151{ 152 char **ap; 153 154 header_files[0] = "\"mystring.h\""; 155 header_files[1] = "\"shell.h\""; 156 header_files[2] = "\"init.h\""; 157 for (ap = argv + 1 ; *ap ; ap++) 158 readfile(*ap); 159 output(); 160 rename(OUTTEMP, OUTFILE); 161 exit(0); 162 /* NOTREACHED */ 163} 164 165 166/* 167 * Parse an input file. 168 */ 169 170void 171readfile(char *fname) 172{ 173 FILE *fp; 174 char line[1024]; 175 struct event *ep; 176 177 fp = ckfopen(fname, "r"); 178 curfile = fname; 179 linno = 0; 180 amiddecls = 0; 181 while (fgets(line, sizeof line, fp) != NULL) { 182 linno++; 183 for (ep = event ; ep->name ; ep++) { 184 if (line[0] == ep->name[0] && match(ep->name, line)) { 185 doevent(ep, fp, fname); 186 break; 187 } 188 } 189 if (line[0] == 'I' && match("INCLUDE", line)) 190 doinclude(line); 191 if (line[0] == 'M' && match("MKINIT", line)) 192 dodecl(line, fp); 193 if (line[0] == '#' && gooddefine(line)) { 194 char *cp; 195 char line2[1024]; 196 static const char undef[] = "#undef "; 197 198 strcpy(line2, line); 199 memcpy(line2, undef, sizeof(undef) - 1); 200 cp = line2 + sizeof(undef) - 1; 201 while(*cp && (*cp == ' ' || *cp == '\t')) 202 cp++; 203 while(*cp && *cp != ' ' && *cp != '\t' && *cp != '\n') 204 cp++; 205 *cp++ = '\n'; *cp = '\0'; 206 addstr(line2, &defines); 207 addstr(line, &defines); 208 } 209 } 210 fclose(fp); 211} 212 213 214int 215match(char *name, char *line) 216{ 217 char *p, *q; 218 219 p = name, q = line; 220 while (*p) { 221 if (*p++ != *q++) 222 return 0; 223 } 224 if (*q != '{' && *q != ' ' && *q != '\t' && *q != '\n') 225 return 0; 226 return 1; 227} 228 229 230int 231gooddefine(char *line) 232{ 233 char *p; 234 235 if (! match("#define", line)) 236 return 0; /* not a define */ 237 p = line + 7; 238 while (*p == ' ' || *p == '\t') 239 p++; 240 while (*p != ' ' && *p != '\t') { 241 if (*p == '(') 242 return 0; /* macro definition */ 243 p++; 244 } 245 while (*p != '\n' && *p != '\0') 246 p++; 247 if (p[-1] == '\\') 248 return 0; /* multi-line definition */ 249 return 1; 250} 251 252 253void 254doevent(struct event *ep, FILE *fp, char *fname) 255{ 256 char line[1024]; 257 int indent; 258 char *p; 259 260 sprintf(line, "\n /* from %s: */\n", fname); 261 addstr(line, &ep->code); 262 addstr(" {\n", &ep->code); 263 for (;;) { 264 linno++; 265 if (fgets(line, sizeof line, fp) == NULL) 266 error("Unexpected EOF"); 267 if (equal(line, "}\n")) 268 break; 269 indent = 6; 270 for (p = line ; *p == '\t' ; p++) 271 indent += 8; 272 for ( ; *p == ' ' ; p++) 273 indent++; 274 if (*p == '\n' || *p == '#') 275 indent = 0; 276 while (indent >= 8) { 277 addchar('\t', &ep->code); 278 indent -= 8; 279 } 280 while (indent > 0) { 281 addchar(' ', &ep->code); 282 indent--; 283 } 284 addstr(p, &ep->code); 285 } 286 addstr(" }\n", &ep->code); 287} 288 289 290void 291doinclude(char *line) 292{ 293 char *p; 294 char *name; 295 char **pp; 296 297 for (p = line ; *p != '"' && *p != '<' && *p != '\0' ; p++); 298 if (*p == '\0') 299 error("Expecting '\"' or '<'"); 300 name = p; 301 while (*p != ' ' && *p != '\t' && *p != '\n') 302 p++; 303 if (p[-1] != '"' && p[-1] != '>') 304 error("Missing terminator"); 305 *p = '\0'; 306 307 /* name now contains the name of the include file */ 308 for (pp = header_files ; *pp && ! equal(*pp, name) ; pp++); 309 if (*pp == NULL) 310 *pp = savestr(name); 311} 312 313 314void 315dodecl(char *line1, FILE *fp) 316{ 317 char line[1024]; 318 char *p, *q; 319 320 if (strcmp(line1, "MKINIT\n") == 0) { /* start of struct/union decl */ 321 addchar('\n', &decls); 322 do { 323 linno++; 324 if (fgets(line, sizeof line, fp) == NULL) 325 error("Unterminated structure declaration"); 326 addstr(line, &decls); 327 } while (line[0] != '}'); 328 amiddecls = 0; 329 } else { 330 if (! amiddecls) 331 addchar('\n', &decls); 332 q = NULL; 333 for (p = line1 + 6 ; *p && strchr("=/\n", *p) == NULL; p++) 334 continue; 335 if (*p == '=') { /* eliminate initialization */ 336 for (q = p ; *q && *q != ';' ; q++); 337 if (*q == '\0') 338 q = NULL; 339 else { 340 while (p[-1] == ' ') 341 p--; 342 *p = '\0'; 343 } 344 } 345 addstr("extern", &decls); 346 addstr(line1 + 6, &decls); 347 if (q != NULL) 348 addstr(q, &decls); 349 amiddecls = 1; 350 } 351} 352 353 354 355/* 356 * Write the output to the file OUTTEMP. 357 */ 358 359void 360output(void) 361{ 362 FILE *fp; 363 char **pp; 364 struct event *ep; 365 366 fp = ckfopen(OUTTEMP, "w"); 367 fputs(writer, fp); 368 for (pp = header_files ; *pp ; pp++) 369 fprintf(fp, "#include %s\n", *pp); 370 fputs("\n\n\n", fp); 371 writetext(&defines, fp); 372 fputs("\n\n", fp); 373 writetext(&decls, fp); 374 for (ep = event ; ep->name ; ep++) { 375 fputs("\n\n\n", fp); 376 fputs(ep->comment, fp); 377 fprintf(fp, "\nvoid\n%s() {\n", ep->routine); 378 writetext(&ep->code, fp); 379 fprintf(fp, "}\n"); 380 } 381 fclose(fp); 382} 383 384 385/* 386 * A text structure is simply a block of text that is kept in memory. 387 * Addstr appends a string to the text struct, and addchar appends a single 388 * character. 389 */ 390 391void 392addstr(char *s, struct text *text) 393{ 394 while (*s) { 395 if (--text->nleft < 0) 396 addchar(*s++, text); 397 else 398 *text->nextc++ = *s++; 399 } 400} 401 402 403void 404addchar(int c, struct text *text) 405{ 406 struct block *bp; 407 408 if (--text->nleft < 0) { 409 bp = ckmalloc(sizeof *bp); 410 if (text->start == NULL) 411 text->start = bp; 412 else 413 text->last->next = bp; 414 text->last = bp; 415 text->nextc = bp->text; 416 text->nleft = BLOCKSIZE - 1; 417 } 418 *text->nextc++ = c; 419} 420 421/* 422 * Write the contents of a text structure to a file. 423 */ 424void 425writetext(struct text *text, FILE *fp) 426{ 427 struct block *bp; 428 429 if (text->start != NULL) { 430 for (bp = text->start ; bp != text->last ; bp = bp->next) { 431 if ((fwrite(bp->text, sizeof (char), BLOCKSIZE, fp)) != BLOCKSIZE) 432 error("Can't write data\n"); 433 } 434 if ((fwrite(bp->text, sizeof (char), BLOCKSIZE - text->nleft, fp)) != (BLOCKSIZE - text->nleft)) 435 error("Can't write data\n"); 436 } 437} 438 439FILE * 440ckfopen(char *file, char *mode) 441{ 442 FILE *fp; 443 444 if ((fp = fopen(file, mode)) == NULL) { 445 fprintf(stderr, "Can't open %s\n", file); 446 exit(2); 447 } 448 return fp; 449} 450 451void * 452ckmalloc(int nbytes) 453{ 454 char *p; 455 456 if ((p = malloc(nbytes)) == NULL) 457 error("Out of space"); 458 return p; 459} 460 461char * 462savestr(char *s) 463{ 464 char *p; 465 466 p = ckmalloc(strlen(s) + 1); 467 strcpy(p, s); 468 return p; 469} 470 471static void 472error(char *msg) 473{ 474 if (curfile != NULL) 475 fprintf(stderr, "%s:%d: ", curfile, linno); 476 fprintf(stderr, "%s\n", msg); 477 exit(2); 478 /* NOTREACHED */ 479} 480