int control(int counter) /* * Process #control lines. Simple commands are processed inline, * while complex commands have their own subroutines. * * The counter is used to force out a newline before #line, and * #pragma commands. This prevents these commands from ending up at * the end of the previous line if cpp is invoked with the -C option. */ { register int c; register char *tp; register int hash; char *ep; c = skipws(); if (c == '\n' || c == EOF_CHAR) return (counter + 1); if (!isdigit(c)) scanid(c); /* Get #word to token[] */ else { unget(); /* Hack -- allow #123 as a */ strcpy(token, "line"); /* synonym for #line 123 */ } hash = (token[1] == EOS) ? L_nogood : (token[0] + (token[2] << 1)); switch (hash) { case L_assert: tp = "assert"; break; case L_define: tp = "define"; break; case L_elif: tp = "elif"; break; case L_else: tp = "else"; break; case L_endif: tp = "endif"; break; case L_if: tp = "if"; break; case L_ifdef: tp = "ifdef"; break; case L_ifndef: tp = "ifndef"; break; case L_include: tp = "include"; break; case L_line: tp = "line"; break; case L_pragma: tp = "pragma"; break; case L_undef: tp = "undef"; break; case L_error: tp = "error"; break; #if OSL_DEBUG_LEVEL > 1 case L_debug: tp = "debug"; break; case L_nodebug: tp = "nodebug"; break; #endif default: hash = L_nogood; case L_nogood: tp = ""; break; } if (!streq(tp, token)) hash = L_nogood; /* * hash is set to a unique value corresponding to the * control keyword (or L_nogood if we think it's nonsense). */ if (infile->fp == NULL) cwarn("Control line \"%s\" within macro expansion", token); if (!compiling) { /* Not compiling now */ switch (hash) { case L_if: /* These can't turn */ case L_ifdef: /* compilation on, but */ case L_ifndef: /* we must nest #if's */ if (++ifptr >= &ifstack[BLK_NEST]) goto if_nest_err; *ifptr = 0; /* !WAS_COMPILING */ case L_line: /* Many */ /* * Are pragma's always processed? */ case L_pragma: /* options */ case L_include: /* are uninteresting */ case L_define: /* if we */ case L_undef: /* aren't */ case L_assert: /* compiling. */ case L_error: /* BP 5.3.92, #error */ dump_line: skipnl(); /* Ignore rest of line */ return (counter + 1); } } /* * Make sure that #line and #pragma are output on a fresh line. */ if (counter > 0 && (hash == L_line || hash == L_pragma)) { PUTCHAR('\n'); counter--; } switch (hash) { case L_line: /* * Parse the line to update the line number and "progname" * field and line number for the next input line. * Set wrongline to force it out later. */ c = skipws(); workp = work; /* Save name in work */ while (c != '\n' && c != EOF_CHAR) { save(c); c = get(); } unget(); save(EOS); /* * Split #line argument into <line-number> and <name> * We subtract 1 as we want the number of the next line. */ line = atoi(work) - 1; /* Reset line number */ for (tp = work; isdigit(*tp) || type[(int)*tp] == SPA; tp++) ; /* Skip over digits */ if (*tp != EOS) { /* Got a filename, so: */ if (*tp == '"' && (ep = strrchr(tp + 1, '"')) != NULL) { tp++; /* Skip over left quote */ *ep = EOS; /* And ignore right one */ } if (infile->progname != NULL) /* Give up the old name */ free(infile->progname); /* if it's allocated. */ infile->progname = savestring(tp); } wrongline = TRUE; /* Force output later */ break; case L_include: doinclude(); break; case L_define: dodefine(); break; case L_undef: doundef(); break; case L_else: if (ifptr == &ifstack[0]) goto nest_err; else if ((*ifptr & ELSE_SEEN) != 0) goto else_seen_err; *ifptr |= ELSE_SEEN; if ((*ifptr & WAS_COMPILING) != 0) { if (compiling || (*ifptr & TRUE_SEEN) != 0) compiling = FALSE; else { compiling = TRUE; } } break; case L_elif: if (ifptr == &ifstack[0]) goto nest_err; else if ((*ifptr & ELSE_SEEN) != 0) { else_seen_err: cerror("#%s may not follow #else", token); goto dump_line; } if ((*ifptr & (WAS_COMPILING | TRUE_SEEN)) != WAS_COMPILING) { compiling = FALSE; /* Done compiling stuff */ goto dump_line; /* Skip this clause */ } doif(L_if); break; case L_if: case L_ifdef: case L_ifndef: if (++ifptr >= &ifstack[BLK_NEST]) if_nest_err: cfatal("Too many nested #%s statements", token); *ifptr = WAS_COMPILING; doif(hash); break; case L_endif: if (ifptr == &ifstack[0]) { nest_err: cerror("#%s must be in an #if", token); goto dump_line; } if (!compiling && (*ifptr & WAS_COMPILING) != 0) wrongline = TRUE; compiling = ((*ifptr & WAS_COMPILING) != 0); --ifptr; break; case L_assert: if (eval() == 0) cerror("Preprocessor assertion failure", NULLST); break; case L_pragma: /* * #pragma is provided to pass "options" to later * passes of the compiler. cpp doesn't have any yet. */ fprintf( pCppOut, "#pragma "); while ((c = get()) != '\n' && c != EOF_CHAR) cput(c); unget(); break; #if OSL_DEBUG_LEVEL > 1 case L_debug: if (debug == 0) dumpdef("debug set on"); debug++; break; case L_nodebug: debug--; break; #endif case L_error: /* BP 5.3.92, #error */ { fprintf( pCppOut, "cpp: line %u, Error directive: ", line ); while ((c = get()) != '\n' && c != EOF_CHAR) cput(c); fprintf( pCppOut, "\n" ); exit( 1 ); break; } default: /* * Undefined #control keyword. * Note: the correct behavior may be to warn and * pass the line to a subsequent compiler pass. * This would allow #asm or similar extensions. */ cerror("Illegal # command \"%s\"", token); break; } if (hash != L_include) { #if OLD_PREPROCESSOR /* * Ignore the rest of the #control line so you can write * #if foo * #endif foo */ goto dump_line; /* Take common exit */ #else if (skipws() != '\n') { cwarn("Unexpected text in #control line ignored", NULLST); skipnl(); } #endif } return (counter + 1); }
int MAIN(int argc, char** argv) { int i; char** useargv; char** pfargv; if( nRunde == 0 ) { pCppIn = stdin; pCppOut = stdout; } nRunde++; InitCpp1(); InitCpp2(); InitCpp3(); InitCpp4(); InitCpp5(); InitCpp6(); #if HOST == SYS_VMS argc = getredirection(argc, argv); /* vms >file and <file */ #endif initdefines(); /* O.S. specific def's */ if ( argv[argc-1][0] == '@' ) { i = readoptions( argv[1], &pfargv ); /* Command file */ useargv=pfargv; } else { i = dooptions(argc, argv); /* Command line -flags */ useargv=argv; } switch (i) { #if OSL_DEBUG_LEVEL > 1 case 4: if ( bDumpDefs ) { /* * Get defBase file, "-" means use stdout. */ if (!streq(useargv[3], "-")) { #if HOST == SYS_VMS /* * On vms, reopen stdout with "vanilla rms" attributes. */ if ((i = creat(useargv[3], 0, "rat=cr", "rfm=var")) == -1 || dup2(i, fileno(stdout)) == -1) #else pDefOut = fopen( useargv[3], "w" ); if( pDefOut == NULL ) #endif { perror(useargv[3]); cerror("Can't open output file \"%s\"", useargv[3]); exit(IO_ERROR); } } /* Continue by opening output */ } #endif case 3: /* * Get output file, "-" means use stdout. */ if (!streq(useargv[2], "-")) { #if HOST == SYS_VMS /* * On vms, reopen stdout with "vanilla rms" attributes. */ if ((i = creat(useargv[2], 0, "rat=cr", "rfm=var")) == -1 || dup2(i, fileno(stdout)) == -1) #else pCppOut = fopen( useargv[2], "w" ); if( pCppOut == NULL ) #endif { perror(useargv[2]); cerror("Can't open output file \"%s\"", useargv[2]); exit(IO_ERROR); } } /* Continue by opening input */ case 2: /* One file -> stdin */ /* * Open input file, "-" means use stdin. */ if (!streq(useargv[1], "-")) { pCppIn = fopen( useargv[1], "r" ); if( pCppIn == NULL) { perror(useargv[1]); cerror("Can't open input file \"%s\"", useargv[1]); exit(IO_ERROR); } strncpy(work, useargv[1], NWORK); /* Remember input filename */ break; } /* Else, just get stdin */ case 0: /* No args? */ case 1: /* No files, stdin -> stdout */ #if (HOST == SYS_UNIX) || (HOST == SYS_UNKNOWN) work[0] = EOS; /* Unix can't find stdin name */ #else fgetname(stdin, work); /* Vax-11C, Decus C know name */ #endif break; default: exit(IO_ERROR); /* Can't happen */ } setincdirs(); /* Setup -I include directories */ addfile( pCppIn, work); /* "open" main input file */ #if OSL_DEBUG_LEVEL > 1 if (debug > 0 || bDumpDefs) dumpdef("preset #define symbols"); #endif if( pCppIn != stdin ) rewind( pCppIn ); cppmain(); /* Process main file */ if ((i = (ifptr - &ifstack[0])) != 0) { #if OLD_PREPROCESSOR ciwarn("Inside #ifdef block at end of input, depth = %d", i); #else cierror("Inside #ifdef block at end of input, depth = %d", i); #endif } #if OSL_DEBUG_LEVEL > 1 if( pDefOut != stdout && pDefOut != stderr ) fclose( pDefOut ); #endif if( pCppOut != stdout && pCppOut != stderr ) fclose( pCppOut ); if (errors > 0) { fprintf(stderr, (errors == 1) ? "%d error in preprocessor\n" : "%d errors in preprocessor\n", errors); if (!eflag) exit(IO_ERROR); } #ifdef NOMAIN /* BP */ /* kein exit im der LIB-Version */ return( IO_NORMAL ); #else exit(IO_NORMAL); /* No errors or -E option set */ #endif }