#include <stdio.h> #include <string.h> #include <assert.h> #define huge 1000000 char outbuf[huge] = { 255 }; char *outp = outbuf+1; #define CONTINUATIONCHARS ",=" #define maxline 4096 char buffer[maxline+2]; char *line, *s; int mode = '\n', savemode = '\n', c, pendch = -1, peek, bracedepth = 0;; int lastch(void) { int c; outp -= 1; c = *outp; /* I don't trust *outp[-1] */ outp += 1; return(c); } void outch(char c) { int x; if (c == '\0') { /* Explicit flush */ /* for now we assume outout buffer bigger than source file */ fwrite(outbuf+1, outp-outbuf-1, 1, stdout); outp = outbuf+1; return; } if ((c != '\n') || (mode == '!')) { *outp++ = c; return;} if (lastch() == 'c') { outp -= 1; fwrite(outbuf+1, outp-outbuf-1, 1, stdout); outp = outbuf+1; /* empty the buffer */ return; } if ((strchr(CONTINUATIONCHARS, lastch()) != NULL)) { /* last character was a continuation character */ /* Note: not yet doing a hack for %and / %or at end of line */ return; } *outp++ = c; } int main(int argc, char **argv) { buffer[0] = '\n'; for (;;) { line = fgets(buffer+1, maxline, stdin); if (line == NULL) break; /* zap all DOS-style CR's, just in case */ while ((s = strchr(line, '\r')) != NULL) { memmove(s, s+1, strlen(s) /* incl NUL */); } s = line+strlen(line); /* points to NUL */ if (s == line) break; if (*--s != '\n') { /* Line does not terminate in \n??? */ exit(1); } while (*--s == ' ') /* strip trailing spaces */; *++s = '\n'; /* Reinsert newline - we can now guarantee %c\n */ for (;;) { c = *line++; if (c == '\0') break; retry: switch (mode) { case '\n': /* pre-statement space */ if (isspace(c)) continue; assert(c != '\n'); if ((c == '\'') || (c == '"') || (c == '%') || (c == '{') || (c == '!')) { if ((c == '\'') || (c == '"') || (c == '!')) outch(c); /* why did I invent 'pendch'??? - use it here? ^ */ bracedepth = 0; savemode = mode; mode = c; continue; } mode = '.'; pendch = c; continue; case '+': /* post %c space */ if ((c == ' ') || (c == '\t')) continue; mode = '.'; goto retry; case '{': /* in curly comment */ if ((c == '}') || (c == '\n')) { mode = savemode; if (c == '\n') { if (lastch() != c) outch(c); mode = c; } continue; } continue; case '!': /* in ! comment */ /* ERROR: %c at end of comment matters! */ if (c == '%') { c = *line++; if (isalpha(c) && (toupper(c) == 'C') && (*line == '\n')) { line++; break; /* Join next line */ } else { outch('%'); outch(c); } } else outch(c); if (c == '\n') mode = c; continue; case '%': /* in keyword */ if (isalpha(c)) { c = tolower(c); peek = *line; if ((c == 'c') && (peek == '\n')) { mode = '+'; line += 1; break; } outch(c); continue; } else { mode = '.'; goto retry; } case '"': /* in "string" */ case '\'': /* in 'const' */ if ((c == mode) && (*line == mode)) { outch(c); outch(c); line += 1; /* past 2nd ' */ continue; } if (c == mode) { /* end of string */ outch(c); mode = '.'; continue; /* reclassify on next ch */ } outch(c); continue; case '.': /* everything else */; if (pendch >= 0) { if (isalpha(pendch) && islower(pendch)) pendch = toupper(pendch); outch(pendch); pendch = -1; }; if (isalpha(c) && islower(c)) c = toupper(c); if (c == ' ') continue; if (c == '(') { bracedepth += 1; } else if (c == ')') { bracedepth -= 1; } else if ((c == ':') && (bracedepth == 0)) { /* emit label on line of its own - makes for easier parsing */ outch(c); outch('\n'); mode = '\n'; continue; } /* special continuation allowed: first cheap test */ if (((strchr(CONTINUATIONCHARS, c) != NULL)) && (*line == '\n')) { outch(c); line += 1; break; /* throw away \n */ } if (c == ';') c = '\n'; if (strchr("\n{%'\"", c) != NULL) { if (strchr("\n'\"", c) != NULL) outch(c); savemode = mode; mode = c; continue; }; outch(c); } } } outch(0); /* Flush buffer */ }