| 1 | /* |
| 2 | * ========== Copyright Header Begin ========================================== |
| 3 | * |
| 4 | * Hypervisor Software File: didepend.c |
| 5 | * |
| 6 | * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. |
| 7 | * |
| 8 | * - Do no alter or remove copyright notices |
| 9 | * |
| 10 | * - Redistribution and use of this software in source and binary forms, with |
| 11 | * or without modification, are permitted provided that the following |
| 12 | * conditions are met: |
| 13 | * |
| 14 | * - Redistribution of source code must retain the above copyright notice, |
| 15 | * this list of conditions and the following disclaimer. |
| 16 | * |
| 17 | * - Redistribution in binary form must reproduce the above copyright notice, |
| 18 | * this list of conditions and the following disclaimer in the |
| 19 | * documentation and/or other materials provided with the distribution. |
| 20 | * |
| 21 | * Neither the name of Sun Microsystems, Inc. or the names of contributors |
| 22 | * may be used to endorse or promote products derived from this software |
| 23 | * without specific prior written permission. |
| 24 | * |
| 25 | * This software is provided "AS IS," without a warranty of any kind. |
| 26 | * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, |
| 27 | * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A |
| 28 | * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN |
| 29 | * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR |
| 30 | * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR |
| 31 | * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN |
| 32 | * OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR |
| 33 | * FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE |
| 34 | * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, |
| 35 | * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF |
| 36 | * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. |
| 37 | * |
| 38 | * You acknowledge that this software is not designed, licensed or |
| 39 | * intended for use in the design, construction, operation or maintenance of |
| 40 | * any nuclear facility. |
| 41 | * |
| 42 | * ========== Copyright Header End ============================================ |
| 43 | */ |
| 44 | /* |
| 45 | * id: @(#)didepend.c 1.12 04/04/22 |
| 46 | * purpose: |
| 47 | * copyright: Copyright 1997-2004 Sun Microsystems, Inc. All Rights Reserved |
| 48 | * Use is subject to license terms. |
| 49 | */ |
| 50 | |
| 51 | #include <sys/types.h> |
| 52 | #include <sys/stat.h> |
| 53 | #include <fcntl.h> |
| 54 | #include <string.h> |
| 55 | #include <stdio.h> |
| 56 | |
| 57 | #include "defines.h" |
| 58 | |
| 59 | #define SOURCE_FLAG 0x01 |
| 60 | #define TARGET_FLAG 0x02 |
| 61 | #define DEPEND_FLAG 0x04 |
| 62 | #define CODE_FLAG 0x08 |
| 63 | #define CODE_START 0x10 |
| 64 | #define CODE_END 0x20 |
| 65 | #define COMPAT_MODE 0x40 |
| 66 | |
| 67 | #define MAXLINE 512 |
| 68 | |
| 69 | FILE *ifd; |
| 70 | char *buildcmd = NULL; |
| 71 | char *progname = NULL; |
| 72 | char *filename = NULL; |
| 73 | char *codefile = NULL; |
| 74 | char *srcfile = NULL; |
| 75 | char buffer[ MAXLINE ]; |
| 76 | int flags = 0; |
| 77 | int line_num = 0; |
| 78 | int argcount; |
| 79 | int pedantic = 0; |
| 80 | int defdepth = 0; |
| 81 | int showsyms = 0; |
| 82 | int verbose = 0; |
| 83 | |
| 84 | void |
| 85 | usage(void) |
| 86 | { |
| 87 | fprintf(stderr, "%s: [flag] sourcefile\n", progname); |
| 88 | fprintf(stderr, " -D <symbol> : define <symbol>\n"); |
| 89 | fprintf(stderr, " -U <symbol> : undefine <symbol>\n"); |
| 90 | fprintf(stderr, " -S : show symbols used\n"); |
| 91 | fprintf(stderr, " -s : print sources\n"); |
| 92 | fprintf(stderr, " -t : print targets\n"); |
| 93 | fprintf(stderr, " -d : print dependancies\n"); |
| 94 | fprintf(stderr, " -c : print code\n"); |
| 95 | fprintf(stderr, " -p : pedantic mode\n"); |
| 96 | exit(1); |
| 97 | } |
| 98 | |
| 99 | typedef void * retval; |
| 100 | |
| 101 | #define CAST(x) (retval) (x) |
| 102 | |
| 103 | #define CMD_NULL_ARGS 0x00 |
| 104 | #define CMD_OPT_ARGS 0x10 |
| 105 | #define CMD_COMPAT 0x20 |
| 106 | #define CMD_COMPAT_ONLY 0x40 |
| 107 | #define CMD_IFDEF 0x80 |
| 108 | #define CMD_MASK 0xf0 |
| 109 | |
| 110 | typedef struct CMD |
| 111 | { |
| 112 | char *name; |
| 113 | retval (*fn)(char *arg0, char *line); |
| 114 | int flags; |
| 115 | } cmd; |
| 116 | |
| 117 | retval enable_cmds(char *line, char *arg0); |
| 118 | retval disable_cmds(char *line, char *arg0); |
| 119 | retval get_source_line(char *line, char *arg0); |
| 120 | retval set_build_cmd(char *arg0, char *line); |
| 121 | retval grab_depend_line(char *arg0, char *line); |
| 122 | retval grab_target_line(char *arg0, char *line); |
| 123 | retval grab_external_line(char *arg0, char *line); |
| 124 | retval grab_source(char *arg0, char *line); |
| 125 | retval comment_line(char *arg0, char *line); |
| 126 | retval unexpected_token(char *arg0, char *line); |
| 127 | retval get_execute_token(char *arg0, char *line); |
| 128 | retval grab_next_file(char *arg0, char *line); |
| 129 | retval set_code_file(char *arg0, char *line); |
| 130 | retval set_build_flags(char *arg0, char *line); |
| 131 | retval do_message(char *arg0, char *line); |
| 132 | retval do_define(char *arg0, char *line); |
| 133 | retval do_undef(char *arg0, char *line); |
| 134 | retval do_ifdef(char *arg0, char *line); |
| 135 | retval do_ifndef(char *arg0, char *line); |
| 136 | retval do_else(char *arg0, char *line); |
| 137 | retval do_endif(char *arg0, char *line); |
| 138 | |
| 139 | #define COMPAT_NO_ARGS CMD_COMPAT|CMD_NULL_ARGS |
| 140 | #define COMPAT_OPT_ARGS CMD_COMPAT|CMD_OPT_ARGS |
| 141 | |
| 142 | cmd cmds[] = { |
| 143 | { "version1", disable_cmds, COMPAT_NO_ARGS }, |
| 144 | { "version2", enable_cmds, COMPAT_NO_ARGS }, |
| 145 | { "build", set_build_cmd, CMD_OPT_ARGS | 1 }, |
| 146 | { "depend", grab_depend_line, 1 }, |
| 147 | { "target", grab_target_line, 2 }, |
| 148 | { "external", grab_external_line, 1 }, |
| 149 | { "source{", grab_source, CMD_OPT_ARGS }, |
| 150 | { "}source", unexpected_token, CMD_NULL_ARGS }, |
| 151 | { "#", comment_line, COMPAT_OPT_ARGS }, |
| 152 | { "-", get_source_line, CMD_COMPAT_ONLY }, |
| 153 | { "include", grab_next_file, 1 }, |
| 154 | { "codefile", set_code_file, 1 }, |
| 155 | { "buildoptions", set_build_flags, CMD_OPT_ARGS | 1 }, |
| 156 | { "message", do_message, CMD_OPT_ARGS | 1 }, |
| 157 | { "#define", do_define, 1 }, |
| 158 | { "#undef", do_undef, 1 }, |
| 159 | { "#ifdef", do_ifdef, CMD_IFDEF | 1 }, |
| 160 | { "#ifndef", do_ifndef, CMD_IFDEF | 1 }, |
| 161 | { "#else", do_else, CMD_IFDEF | CMD_NULL_ARGS }, |
| 162 | { "#endif", do_endif, CMD_IFDEF | CMD_NULL_ARGS }, |
| 163 | { NULL, NULL, 0 } |
| 164 | }; |
| 165 | |
| 166 | void |
| 167 | malloc_failed(void *ptr) |
| 168 | { |
| 169 | if (ptr == NULL) { |
| 170 | fprintf(stderr, "%s:%d: Malloc failed\n", filename, line_num); |
| 171 | exit(1); |
| 172 | } |
| 173 | } |
| 174 | |
| 175 | char * |
| 176 | get_arg(char *line, int which, int *rpos) |
| 177 | { |
| 178 | static char arg[MAXLINE]; |
| 179 | char *tokens = " \t"; |
| 180 | char *start; |
| 181 | int strip; |
| 182 | int len, end, pos, prev; |
| 183 | |
| 184 | if ((line == NULL) || (*line == 0)) { |
| 185 | return (NULL); |
| 186 | } |
| 187 | |
| 188 | end = strlen(line); |
| 189 | prev = pos = 0; |
| 190 | start = line; |
| 191 | while ((which-- >= 0) && (pos < end)) { |
| 192 | strip = strspn(start, tokens); |
| 193 | start += strip; |
| 194 | pos += strip; |
| 195 | prev = pos; |
| 196 | len = strcspn(start, tokens); |
| 197 | pos += len; |
| 198 | if ((pos >= end) && (which >= 0)) { |
| 199 | if (rpos) *rpos = prev; |
| 200 | return (NULL); |
| 201 | } |
| 202 | if (len) { |
| 203 | strncpy(arg, start, len); |
| 204 | arg[len] = 0; |
| 205 | } else { |
| 206 | strcpy(arg, start); |
| 207 | } |
| 208 | start += len; |
| 209 | } |
| 210 | if (rpos) *rpos = prev; |
| 211 | return (arg); |
| 212 | } |
| 213 | |
| 214 | int |
| 215 | count_args(char *line) |
| 216 | { |
| 217 | int argc; |
| 218 | char *lastarg; |
| 219 | |
| 220 | if (line == NULL) { |
| 221 | return (0); |
| 222 | } |
| 223 | |
| 224 | argc = 0; |
| 225 | lastarg = line; |
| 226 | while (lastarg) { |
| 227 | lastarg = get_arg(line, argc+1, NULL); |
| 228 | if (lastarg) argc++; |
| 229 | } |
| 230 | return (argc); |
| 231 | } |
| 232 | |
| 233 | void |
| 234 | automatic_message(char comment) |
| 235 | { |
| 236 | printf("%c\n", comment); |
| 237 | printf("%c Warning this is a machine generated file\n", comment); |
| 238 | printf("%c Changes made here will go away\n", comment); |
| 239 | printf("%c\n", comment); |
| 240 | } |
| 241 | |
| 242 | /* This is gross, but exists for Version1 compatability. */ |
| 243 | char *fthsrc = |
| 244 | "id: %" "Z%%" "M% %" "I% %" "E%\n" |
| 245 | "purpose: %" "Y%\n" |
| 246 | "copyright: Copyright 1989-1997 Sun Microsystems, Inc. All Rights Reserved\n" |
| 247 | "\n" |
| 248 | "\" /packages/SUNW,builtin-drivers\" find-device\n" |
| 249 | "\n" |
| 250 | ": do-fcode ( str$ -- )\n" |
| 251 | " find-drop-in if\n" |
| 252 | " 2dup 2>r execute-buffer\n" |
| 253 | " 2r> free-drop-in\n" |
| 254 | " then\n" |
| 255 | ";\n\n"; |
| 256 | |
| 257 | char * |
| 258 | get_line(char *line, int from) |
| 259 | { |
| 260 | char *argp; |
| 261 | int pos; |
| 262 | |
| 263 | argp = get_arg(line, from, &pos); |
| 264 | #if 0 |
| 265 | printf("rem_line: '%s'\n", (argp ? argp : "")); |
| 266 | #endif |
| 267 | if (argp == NULL) { |
| 268 | return (""); |
| 269 | } |
| 270 | return (line + pos); |
| 271 | } |
| 272 | |
| 273 | retval |
| 274 | get_more_source(char *cmd, char *line) |
| 275 | { |
| 276 | int len; |
| 277 | char *backslash; |
| 278 | |
| 279 | printf("get_more_source('%s','%s')\n", |
| 280 | (cmd ? cmd : ""), |
| 281 | (line ? line : "")); |
| 282 | len = strlen(line); |
| 283 | if (len > 1) { |
| 284 | backslash = line+len-1; |
| 285 | if (*backslash == '\\') { |
| 286 | *backslash = 0; |
| 287 | if (cmd == NULL) |
| 288 | printf("%s\n", get_line(line, 2)); |
| 289 | else |
| 290 | printf("%s\n", line); |
| 291 | return (CAST(get_more_source)); |
| 292 | } |
| 293 | } |
| 294 | return (CAST(get_execute_token)); |
| 295 | } |
| 296 | |
| 297 | |
| 298 | retval |
| 299 | get_source_line(char *cmd, char *line) |
| 300 | { |
| 301 | char *arg0, *argp, *arg1, *argn; |
| 302 | static int once = 0; |
| 303 | int tail; |
| 304 | |
| 305 | #if 0 |
| 306 | printf("get_source_line('%s','%s')\n", |
| 307 | (cmd ? cmd : "NULL"), |
| 308 | (line ? line : "NULL")); |
| 309 | #endif |
| 310 | arg0 = arg1 = argn = NULL; |
| 311 | if (cmd == NULL) { |
| 312 | argp = get_arg(line, 0, NULL); |
| 313 | if (argp) arg0 = strdup(get_arg(line, 0, NULL)); |
| 314 | malloc_failed(arg0); |
| 315 | } else { |
| 316 | arg0 = strdup(cmd); |
| 317 | } |
| 318 | |
| 319 | argp = get_arg(line, 1, NULL); |
| 320 | if (argp) arg1 = strdup(argp); |
| 321 | malloc_failed(arg1); |
| 322 | |
| 323 | argp = get_line(line, 2); |
| 324 | if (flags & CODE_FLAG) { |
| 325 | if (!once) { |
| 326 | printf("%s", fthsrc); |
| 327 | once++; |
| 328 | } |
| 329 | get_more_source(cmd, line); |
| 330 | } |
| 331 | if (cmd == NULL) { |
| 332 | if (flags & SOURCE_FLAG) { |
| 333 | printf("%s ", arg0); |
| 334 | } |
| 335 | if (flags & TARGET_FLAG) { |
| 336 | printf("%s ", arg1); |
| 337 | } |
| 338 | if (flags & DEPEND_FLAG) { |
| 339 | printf("%s: %s\n\t%s %s %s\n\n", |
| 340 | arg0, arg1, |
| 341 | buildcmd, arg0, arg1); |
| 342 | } |
| 343 | } |
| 344 | if (arg0) free(arg0); |
| 345 | if (arg1) free(arg1); |
| 346 | return (CAST(get_more_source(cmd, line))); |
| 347 | } |
| 348 | |
| 349 | retval |
| 350 | enable_cmds(char *arg0, char *line) |
| 351 | { |
| 352 | flags &= ~COMPAT_MODE; |
| 353 | return (CAST(get_execute_token)); |
| 354 | } |
| 355 | |
| 356 | retval |
| 357 | disable_cmds(char *arg0, char *line) |
| 358 | { |
| 359 | flags |= COMPAT_MODE; |
| 360 | return (CAST(get_execute_token)); |
| 361 | } |
| 362 | |
| 363 | retval |
| 364 | set_build_cmd(char *arg0, char *line) |
| 365 | { |
| 366 | char *sptr; |
| 367 | |
| 368 | if (buildcmd) free(buildcmd); |
| 369 | sptr = get_line(line, 1); |
| 370 | if ((sptr == NULL) || ((sptr != NULL) && (strlen(sptr) == 0))) { |
| 371 | fprintf(stderr, "%s:%d: Error, Missing argument\n", |
| 372 | filename, line_num); |
| 373 | exit(1); |
| 374 | } |
| 375 | buildcmd = strdup(sptr); |
| 376 | malloc_failed(buildcmd); |
| 377 | return (CAST(get_execute_token)); |
| 378 | } |
| 379 | |
| 380 | retval |
| 381 | set_code_file(char *arg0, char *line) |
| 382 | { |
| 383 | char *sptr; |
| 384 | |
| 385 | if (codefile) free(codefile); |
| 386 | sptr = get_line(line, 1); |
| 387 | if ((sptr == NULL) || ((sptr != NULL) && (strlen(sptr) == 0))) { |
| 388 | fprintf(stderr, "%s:%d: Error, Missing argument\n", |
| 389 | filename, line_num); |
| 390 | exit(1); |
| 391 | } |
| 392 | codefile = strdup(sptr); |
| 393 | malloc_failed(codefile); |
| 394 | return (CAST(get_execute_token)); |
| 395 | } |
| 396 | |
| 397 | retval |
| 398 | grab_depend_line(char *arg0, char *line) |
| 399 | { |
| 400 | static int once = 0; |
| 401 | |
| 402 | if (flags & DEPEND_FLAG) { |
| 403 | if (!once++) automatic_message('#'); |
| 404 | printf("\ninclude %s\n", get_arg(line, 1, NULL)); |
| 405 | } |
| 406 | return (CAST(get_execute_token)); |
| 407 | } |
| 408 | |
| 409 | retval |
| 410 | grab_target_line(char *arg0, char *line) |
| 411 | { |
| 412 | char *cptr, *dptr, *source, *target, *diname; |
| 413 | int tflags; |
| 414 | |
| 415 | cptr = get_arg(line, 1, NULL); |
| 416 | source = strdup(cptr); |
| 417 | malloc_failed(source); |
| 418 | dptr = strrchr(cptr, '/'); |
| 419 | if (dptr) cptr = dptr+1; |
| 420 | target = strdup(cptr); |
| 421 | malloc_failed(target); |
| 422 | diname = get_arg(line, 2, NULL); |
| 423 | cptr = strrchr(target, '.'); |
| 424 | if (cptr) *cptr = 0; |
| 425 | |
| 426 | if (flags & TARGET_FLAG) printf("%s.di ", target); |
| 427 | if (flags & SOURCE_FLAG) printf("%s ", source); |
| 428 | if (flags & DEPEND_FLAG) { |
| 429 | printf("\n%s.di: %s %s\n\t%s %s %s\n", |
| 430 | target, srcfile, source, |
| 431 | buildcmd, source, diname); |
| 432 | } |
| 433 | free(target); |
| 434 | free(source); |
| 435 | return (CAST(get_execute_token)); |
| 436 | } |
| 437 | |
| 438 | retval |
| 439 | grab_external_line(char *arg0, char *line) |
| 440 | { |
| 441 | if (flags & TARGET_FLAG) printf("%s ", get_arg(line, 1, NULL)); |
| 442 | return (CAST(get_execute_token)); |
| 443 | } |
| 444 | |
| 445 | retval |
| 446 | wait_source_end(char *arg0, char *line) |
| 447 | { |
| 448 | int end, argc; |
| 449 | char *last_arg; |
| 450 | |
| 451 | printf("wait_source_end('%s','%s')\n", arg0, line); |
| 452 | |
| 453 | end = (strcmp(arg0, "}source") == 0); |
| 454 | if (flags & DEPEND_FLAG) { |
| 455 | if (!end) printf("%s\n", line); |
| 456 | } |
| 457 | if (!end) { |
| 458 | return (CAST(wait_source_end)); |
| 459 | } |
| 460 | return (CAST(get_execute_token)); |
| 461 | } |
| 462 | |
| 463 | retval |
| 464 | grab_source(char *arg0, char *line) |
| 465 | { |
| 466 | static int start_code = 0; |
| 467 | static int once = 0; |
| 468 | int end, start; |
| 469 | int codebase, codeend, codelen; |
| 470 | retval (*fn)(char *, char *); |
| 471 | char *args; |
| 472 | char *lptr = strdup(line); |
| 473 | |
| 474 | malloc_failed(lptr); |
| 475 | |
| 476 | fn = grab_source; |
| 477 | start = (strcmp(arg0, "source{") == 0); |
| 478 | if ((start) && (start_code++)) { |
| 479 | fprintf(stderr, "%s:%d: Warning, unbalanced start{ tokens\n", |
| 480 | filename, line_num); |
| 481 | if (pedantic) exit(1); |
| 482 | } |
| 483 | if (argcount) |
| 484 | (void) get_arg(line, 1, &codebase); |
| 485 | else |
| 486 | codebase = strlen(arg0); |
| 487 | args = get_arg(lptr, argcount, &codeend); |
| 488 | end = (strcmp(args, "}source") == 0); |
| 489 | |
| 490 | if (!start) codebase = 0; |
| 491 | if (!end) codeend = strlen(line); |
| 492 | |
| 493 | codelen = (codeend-codebase); |
| 494 | strncpy(lptr, line + codebase, codelen); |
| 495 | lptr[codelen] = 0; |
| 496 | |
| 497 | if (flags & CODE_FLAG) { |
| 498 | if (start && !once++) automatic_message('\\'); |
| 499 | printf("%s\n", lptr); |
| 500 | } |
| 501 | |
| 502 | if (end) { |
| 503 | start_code--; |
| 504 | fn = get_execute_token; |
| 505 | } |
| 506 | free(lptr); |
| 507 | return (CAST(fn)); |
| 508 | } |
| 509 | |
| 510 | retval |
| 511 | set_build_flags(char *arg0, char *line) |
| 512 | { |
| 513 | if (flags & DEPEND_FLAG) { |
| 514 | printf("\n%s", get_line(line, 1)); |
| 515 | } |
| 516 | return (CAST(get_execute_token)); |
| 517 | } |
| 518 | |
| 519 | retval |
| 520 | comment_line(char *arg0, char *line) |
| 521 | { |
| 522 | return (CAST(get_execute_token)); |
| 523 | } |
| 524 | |
| 525 | retval |
| 526 | do_message(char *arg0, char *line) |
| 527 | { |
| 528 | if (flags & CODE_FLAG) { |
| 529 | fprintf(stderr, "%s:%d: %s\n", |
| 530 | filename, line_num, get_line(line, 1)); |
| 531 | } |
| 532 | return (CAST(get_execute_token)); |
| 533 | } |
| 534 | |
| 535 | retval |
| 536 | do_define(char *arg0, char *line) |
| 537 | { |
| 538 | define_symbol(get_arg(line, 1, NULL), FORTH_DEFINE); |
| 539 | return (CAST(get_execute_token)); |
| 540 | } |
| 541 | |
| 542 | retval |
| 543 | do_undef(char *arg0, char *line) |
| 544 | { |
| 545 | define_symbol(get_arg(line, 1, NULL), FORTH_UNDEF); |
| 546 | return (CAST(get_execute_token)); |
| 547 | } |
| 548 | |
| 549 | #define DEF_ELSE 1 |
| 550 | #define DEF_ENDIF 2 |
| 551 | #define DEF_SKIP 4 |
| 552 | #define MAX_DEF_DEPTH 5 |
| 553 | |
| 554 | #define defskip (def_state[defdepth] & DEF_SKIP) |
| 555 | |
| 556 | static int def_state[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; |
| 557 | |
| 558 | void |
| 559 | def_state_check(int state, int flag, char *msg) |
| 560 | { |
| 561 | if ((state & flag) == 0) { |
| 562 | fprintf(stderr, "%s:%d: Parse Error, %s\n", |
| 563 | filename, line_num, msg); |
| 564 | exit(1); |
| 565 | } |
| 566 | if (defdepth > MAX_DEF_DEPTH) { |
| 567 | fprintf(stderr, "%s:%d: too many Nested IFDEF's\n", |
| 568 | filename, line_num); |
| 569 | exit(1); |
| 570 | } |
| 571 | } |
| 572 | |
| 573 | void |
| 574 | do_common_ifdef(char *arg0, char *line, int do_true) |
| 575 | { |
| 576 | int state = (DEF_ELSE | DEF_ENDIF); |
| 577 | int def; |
| 578 | |
| 579 | def_state_check(1, 1, ""); |
| 580 | state |= def_state[defdepth++] & DEF_SKIP; |
| 581 | def = symbol_defined(get_arg(line, 1, NULL)); |
| 582 | if ((do_true && !def) || (!do_true && def)) { |
| 583 | state |= DEF_SKIP; |
| 584 | } |
| 585 | def_state[defdepth] = state; |
| 586 | } |
| 587 | |
| 588 | retval |
| 589 | do_ifdef(char *arg0, char *line) |
| 590 | { |
| 591 | do_common_ifdef(arg0, line, 1); |
| 592 | return (CAST(get_execute_token)); |
| 593 | } |
| 594 | |
| 595 | retval |
| 596 | do_ifndef(char *arg0, char *line) |
| 597 | { |
| 598 | do_common_ifdef(arg0, line, 0); |
| 599 | return (CAST(get_execute_token)); |
| 600 | } |
| 601 | |
| 602 | retval |
| 603 | do_else(char *arg0, char *line) |
| 604 | { |
| 605 | def_state_check(def_state[defdepth], DEF_ELSE, "Dangling #else"); |
| 606 | def_state[defdepth] &= ~DEF_ELSE; |
| 607 | def_state[defdepth] ^= DEF_SKIP; |
| 608 | def_state[defdepth] |= def_state[defdepth-1] & DEF_SKIP; |
| 609 | return (CAST(get_execute_token)); |
| 610 | } |
| 611 | |
| 612 | retval |
| 613 | do_endif(char *arg0, char *line) |
| 614 | { |
| 615 | def_state_check(def_state[defdepth], DEF_ENDIF, "Dangling #endif"); |
| 616 | def_state[defdepth--] &= ~DEF_ENDIF; |
| 617 | return (CAST(get_execute_token)); |
| 618 | } |
| 619 | |
| 620 | retval |
| 621 | unexpected_token(char *arg0, char *line) |
| 622 | { |
| 623 | fprintf(stderr, "%s:%d: bad token '%s'\n", filename, line_num, arg0); |
| 624 | exit(1); |
| 625 | return (NULL); |
| 626 | } |
| 627 | |
| 628 | retval |
| 629 | get_execute_token(char *token, char *line) |
| 630 | { |
| 631 | retval (*fn)(char *p, char *); |
| 632 | cmd *cptr = cmds; |
| 633 | |
| 634 | fn = unexpected_token; |
| 635 | while (cptr->name != NULL) { |
| 636 | int nargs; |
| 637 | |
| 638 | if (strcmp(cptr->name, token) != 0) { |
| 639 | cptr++; |
| 640 | continue; |
| 641 | } |
| 642 | |
| 643 | if (((flags & COMPAT_MODE) && !(cptr->flags & CMD_COMPAT)) || |
| 644 | (!(flags & COMPAT_MODE) && (cptr->flags & CMD_COMPAT_ONLY))) |
| 645 | unexpected_token(token, line); |
| 646 | |
| 647 | nargs = cptr->flags & ~CMD_MASK; |
| 648 | if (verbose) { |
| 649 | printf("[%d,%d] CMD: '%s' args = %d, argc = %d\n", |
| 650 | defdepth, defskip, token, nargs, argcount); |
| 651 | } |
| 652 | |
| 653 | if ((argcount > nargs) && (!(cptr->flags & CMD_OPT_ARGS))) { |
| 654 | fprintf(stderr, |
| 655 | "%s:%d: Warning, extra arguments for '%s'\n", |
| 656 | filename, line_num, token); |
| 657 | if (pedantic) exit(1); |
| 658 | } |
| 659 | |
| 660 | if (argcount < nargs) { |
| 661 | fprintf(stderr, |
| 662 | "%s:%d: Missing arguments for '%s'\n", |
| 663 | filename, line_num, token); |
| 664 | exit(1); |
| 665 | } |
| 666 | fn = cptr->fn; |
| 667 | break; |
| 668 | } |
| 669 | if ((flags & COMPAT_MODE) && (fn == unexpected_token)) { |
| 670 | return (CAST(get_source_line(NULL, line))); |
| 671 | } |
| 672 | if (!(cptr->flags & CMD_IFDEF) && defskip) { |
| 673 | fn = comment_line; |
| 674 | } |
| 675 | return (CAST((*fn)(token, line))); |
| 676 | } |
| 677 | |
| 678 | void |
| 679 | process_file(char *name, int recurse) |
| 680 | { |
| 681 | char comment = 0; |
| 682 | char *savename; |
| 683 | FILE *infile; |
| 684 | int linenum; |
| 685 | int done = 0; |
| 686 | retval (*process)(char *line, char *arg); |
| 687 | |
| 688 | /* |
| 689 | * This is a gross hack! I should have made this entire thing parameter |
| 690 | * driven, instead I chose to use globals :( |
| 691 | * So I need to save and restore them for this cruft to work. |
| 692 | */ |
| 693 | if (recurse) { |
| 694 | if (flags & DEPEND_FLAG) printf("\n%s: %s\n", codefile, name); |
| 695 | linenum = line_num; |
| 696 | infile = ifd; |
| 697 | savename = filename; |
| 698 | if (flags & CODE_FLAG) { |
| 699 | comment = '\\'; |
| 700 | } else if (flags & DEPEND_FLAG) { |
| 701 | comment = '#'; |
| 702 | } |
| 703 | if (comment) printf("\n%c Included from %s\n", comment, name); |
| 704 | } |
| 705 | filename = strdup(name); |
| 706 | malloc_failed(filename); |
| 707 | ifd = fopen(filename, "r"); |
| 708 | if (ifd == NULL) { |
| 709 | fprintf(stderr, "%s: unable to open: %s for reading", |
| 710 | progname, filename); |
| 711 | exit(1); |
| 712 | } |
| 713 | |
| 714 | process = get_execute_token; |
| 715 | line_num = 0; |
| 716 | while (!done) { |
| 717 | char *line, *cptr; |
| 718 | char cmd[MAXLINE]; |
| 719 | |
| 720 | line_num++; |
| 721 | line = fgets(buffer, MAXLINE, ifd); |
| 722 | cmd[0] = 0; |
| 723 | |
| 724 | if (line) { |
| 725 | cptr = strchr(line, '\n'); |
| 726 | if (cptr) *cptr = 0; |
| 727 | argcount = count_args(line); |
| 728 | cptr = get_arg(line, 0, NULL); |
| 729 | if (cptr) strcpy(cmd, cptr); |
| 730 | } |
| 731 | done = (line == NULL) || feof(ifd); |
| 732 | |
| 733 | if (!done) { |
| 734 | if (*cmd != 0) |
| 735 | process = (retval (*)()) process(cmd, line); |
| 736 | } |
| 737 | } |
| 738 | fclose(ifd); |
| 739 | free(filename); |
| 740 | if (recurse) { |
| 741 | line_num = linenum; |
| 742 | ifd = infile; |
| 743 | filename = savename; |
| 744 | if (comment) printf("\n%c back to %s\n", comment, filename); |
| 745 | } |
| 746 | } |
| 747 | |
| 748 | retval |
| 749 | grab_next_file(char *arg0, char *line) |
| 750 | { |
| 751 | char *cptr, eptr; |
| 752 | |
| 753 | cptr = get_arg(line, 1, NULL); |
| 754 | |
| 755 | if (flags & DEPEND_FLAG) { |
| 756 | printf("\n%s: %s\n", codefile, cptr); |
| 757 | } |
| 758 | |
| 759 | process_file(cptr, 1); |
| 760 | |
| 761 | return (CAST(get_execute_token)); |
| 762 | } |
| 763 | |
| 764 | main(int argc, char **argv) |
| 765 | { |
| 766 | extern char *optarg; |
| 767 | extern int optind; |
| 768 | int errflg = 0; |
| 769 | int c; |
| 770 | |
| 771 | progname = argv[0]; |
| 772 | while ((c = getopt(argc, argv, "D:U:SVstdcp")) != EOF) |
| 773 | switch (c) { |
| 774 | case 'D': |
| 775 | define_symbol(optarg, CMD_DEFINE); |
| 776 | break; |
| 777 | case 'U': |
| 778 | define_symbol(optarg, CMD_UNDEF); |
| 779 | break; |
| 780 | case 'S': |
| 781 | showsyms = 1; |
| 782 | break; |
| 783 | case 'V': |
| 784 | verbose = 1; |
| 785 | break; |
| 786 | case 's': |
| 787 | if (!flags) flags = SOURCE_FLAG; else usage(); |
| 788 | break; |
| 789 | |
| 790 | case 't': |
| 791 | if (!flags) flags = TARGET_FLAG; else usage(); |
| 792 | break; |
| 793 | |
| 794 | case 'd': |
| 795 | if (!flags) flags = DEPEND_FLAG; else usage(); |
| 796 | break; |
| 797 | |
| 798 | case 'c': |
| 799 | if (!flags) flags = CODE_FLAG; else usage(); |
| 800 | break; |
| 801 | |
| 802 | case 'p': |
| 803 | pedantic++; |
| 804 | break; |
| 805 | |
| 806 | default: |
| 807 | usage(); |
| 808 | } |
| 809 | |
| 810 | if (!flags) usage(); |
| 811 | flags |= COMPAT_MODE; |
| 812 | |
| 813 | progname = argv[0]; |
| 814 | (void) set_build_cmd(NULL, "build\t${MAKEDI}"); |
| 815 | (void) set_code_file(NULL, "codefile\tbuiltin.fth"); |
| 816 | srcfile = argv[optind]; |
| 817 | process_file(srcfile, 0); |
| 818 | finish_symbols(showsyms); |
| 819 | exit(0); |
| 820 | } |