#include <stdio.h>
#include <string.h>
#include <assert.h>
/* Bug: appears to get %c wrong if followed by a trailing space */
/* Also Imp80 allows ... %c <newline> <newline> code ... */
#define huge 1000000
char outbuf[huge] = { 255 };
char *outp = outbuf+1;
#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 > '\0' && c < '\n') || (c > '\n' && c < ' ') || (c >= 127)) {
return; // bad character in data.
}
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;
}
*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 == ' ' || *s == '\t') /* 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 */
bracedepth = 0;
if (isspace(c)) continue;
if (c == ';') continue;
assert(c != '\n');
if ((c == '\'')
||(c == '%')
||(c == '!')) {
if ((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 ! comment */ /* ERROR: %c at end of comment matters! */
/* %COMMENT not handled by this code */
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 */
/* THIS DOES NOT HANDLE %comment CORRECTLY! */
if (isalpha(c)) {
c = tolower(c);
peek = *line;
if ((c == 'c') && (peek == '\n')) {
mode = '+'; line += 1; break;
}
outch(c);
if (c == 't') {
if (
( *(outp-1) == 't') &&
( *(outp-2) == 'n') &&
( *(outp-3) == 'e') &&
( *(outp-4) == 'm') &&
( *(outp-5) == 'm') &&
( *(outp-6) == 'o') &&
( *(outp-7) == 'c'))
{
// copy over rest of comment up to newline
mode = '!';
continue;
}
}
continue;
} else {
mode = '.'; goto retry;
}
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 == ' ' || c == '\t') continue;
if (
(c == '\'') &&
(
(isalpha(lastch()) && isupper(lastch()))
|| isdigit(lastch())
|| (lastch() == '\'') // a X' or X'' variable...
)) {
outch(c); continue;
}
if (c == '(') {
bracedepth += 1;
} else if (c == ')') {
bracedepth -= 1;
}
#ifdef NEVER
else if ((c == ':') && (bracedepth == 0)) {
/* emit label on line of its own - makes for easier parsing */
outch(c);
outch('\n');
mode = '\n';
continue;
}
#endif
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 */
}