#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 */
}