178527Sassar/*- 255682Smarkm * Copyright (c) 1991, 1993 355682Smarkm * The Regents of the University of California. All rights reserved. 455682Smarkm * Copyright (c) 1997-2005 555682Smarkm * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved. 655682Smarkm * 755682Smarkm * This code is derived from software contributed to Berkeley by 878527Sassar * Kenneth Almquist. 955682Smarkm * 1055682Smarkm * Redistribution and use in source and binary forms, with or without 1155682Smarkm * modification, are permitted provided that the following conditions 1255682Smarkm * are met: 1355682Smarkm * 1. Redistributions of source code must retain the above copyright 1455682Smarkm * notice, this list of conditions and the following disclaimer. 1572445Sassar * 2. Redistributions in binary form must reproduce the above copyright 1672445Sassar * notice, this list of conditions and the following disclaimer in the 1772445Sassar * documentation and/or other materials provided with the distribution. 1872445Sassar * 3. Neither the name of the University nor the names of its contributors 1972445Sassar * may be used to endorse or promote products derived from this software 2072445Sassar * without specific prior written permission. 2172445Sassar * 2272445Sassar * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2372445Sassar * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2472445Sassar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2578527Sassar * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2672445Sassar * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2772445Sassar * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2872445Sassar * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2972445Sassar * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3072445Sassar * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3172445Sassar * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3272445Sassar * SUCH DAMAGE. 3372445Sassar */ 3472445Sassar 3572445Sassar/* 3672445Sassar * This program scans all the source files for code to handle various 3772445Sassar * special events and combines this code into one file. This (allegedly) 3872445Sassar * improves the structure of the program since there is no need for 3972445Sassar * anyone outside of a module to know that that module performs special 4072445Sassar * operations on particular events. 4172445Sassar * 4272445Sassar * Usage: mkinit sourcefile... 4372445Sassar */ 4472445Sassar 4572445Sassar 4672445Sassar#include <sys/types.h> 4772445Sassar#include <stdio.h> 4872445Sassar#include <stdlib.h> 4972445Sassar#include <string.h> 5072445Sassar#include <fcntl.h> 5178527Sassar#include <unistd.h> 5272445Sassar 5372445Sassar 5472445Sassar/* 5572445Sassar * OUTFILE is the name of the output file. Output is initially written 5672445Sassar * to the file OUTTEMP, which is then moved to OUTFILE. 5772445Sassar */ 5872445Sassar 5972445Sassar#define OUTFILE "init.c" 6072445Sassar#define OUTTEMP "init.c.new" 6172445Sassar 6272445Sassar 6372445Sassar/* 6472445Sassar * A text structure is basicly just a string that grows as more characters 6572445Sassar * are added onto the end of it. It is implemented as a linked list of 6672445Sassar * blocks of characters. The routines addstr and addchar append a string 6755682Smarkm * or a single character, respectively, to a text structure. Writetext 6855682Smarkm * writes the contents of a text structure to a file. 6955682Smarkm */ 7055682Smarkm 7155682Smarkm#define BLOCKSIZE 512 7255682Smarkm 7378527Sassarstruct text { 7478527Sassar char *nextc; 7578527Sassar int nleft; 7678527Sassar struct block *start; 7778527Sassar struct block *last; 7878527Sassar}; 7978527Sassar 8078527Sassarstruct block { 8178527Sassar struct block *next; 8278527Sassar char text[BLOCKSIZE]; 8378527Sassar}; 8478527Sassar 8578527Sassar 8655682Smarkm/* 8778527Sassar * There is one event structure for each event that mkinit handles. 8878527Sassar */ 8978527Sassar 9078527Sassarstruct event { 9178527Sassar char *name; /* name of event (e.g. INIT) */ 9278527Sassar char *routine; /* name of routine called on event */ 9378527Sassar char *comment; /* comment describing routine */ 9455682Smarkm struct text code; /* code for handling event */ 9555682Smarkm}; 9655682Smarkm 9755682Smarkm 9855682Smarkmchar writer[] = "\ 9955682Smarkm/*\n\ 10055682Smarkm * This file was generated by the mkinit program.\n\ 10155682Smarkm */\n\ 10255682Smarkm\n"; 10355682Smarkm 10455682Smarkmchar init[] = "\ 10555682Smarkm/*\n\ 10655682Smarkm * Initialization code.\n\ 10755682Smarkm */\n"; 10878527Sassar 10955682Smarkmchar reset[] = "\ 11055682Smarkm/*\n\ 11178527Sassar * This routine is called when an error or an interrupt occurs in an\n\ 11255682Smarkm * interactive shell and control is returned to the main command loop.\n\ 11355682Smarkm */\n"; 11455682Smarkm 11578527Sassar 11655682Smarkmstruct event event[] = { 11755682Smarkm {"INIT", "init", init}, 11878527Sassar {"RESET", "reset", reset}, 11955682Smarkm {NULL, NULL} 12078527Sassar}; 12155682Smarkm 12278527Sassar 12355682Smarkmchar *curfile; /* current file */ 12455682Smarkmint 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