#include #include #include #include #ifdef macintosh #include #endif #define IT 1 #define SC 2 #define BLD 4 #define SUP 8 #define SMALL 16 char *code[256] = { "\"^@\"", "\"^A\"", "\"^B\"", "\"^C\"", "\"^D\"", "\"^E\"", "\"^F\"", "\"^G\"", "\"^H\"", "\t", "\n", "\"^K\"", "\"^L\"", "\n", "\"^N\"", "\"^O\"", "\"^P\"", "\"^Q\"", "\"^R\"", "\"^S\"", "\"^T\"", "\"^U\"", "\"^V\"", "\"^W\"", "\"^X\"", "\"^Y\"", "\"^Z\"", "\"^[\"", "\"^\\\"", "\"^]\"", "\"^^\"", "\"^_\"", " ", "!", "\"''\"", "\"#\"", "\"$\"", "\"%\"", "&", "\"'\"", "(", ")", "\"*\"", "\"+\"", ",", "-", ".", "/", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";", "\"<\"", "\"=\"", "\">\"", "?", "@", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "\"[\"", "\"\\\"", "\"]\"", "\"^\"", "\"_\"", "`", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "\"{\"", "\"|\"", "\"}\"", "\"~\"", "\"^?\"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "\"**\"", "\"o\"", "", "\"L\"", "\"p\"", "\"-\"", "\"P\"", "\"ss\"", "\"(r)\"", "\"(c)\"", "\"TM\"", "< '>", "< \">", "<=/>", "\"AE\"", "", "\"oo\"", "\"+-\"", "\"<=\"", "\">=\"", "\"Y\"", "\"mu\"", "\"d\"", "\"S\"", "\"Pi\"", "\"pi\"", "\"I\"", "\"a_\"", "\"o_\"", "\"O\"", "\"ae\"", "", "\"?\"", "\"!\"", "\"-.\"", "\"./\"", "\"f\"", "\"~\"", "\"D\"", "`", "'", "...", " ", "", "", "", "\"OE\"", "\"oe\"", "--", "---", "`", "'", "`", "'", "\"/\"", "\"<>\"", "", "", "< />", "\">0<\"", "`", "'", "fi", "fl", "\"++\"", "\".\"", "`", "`", "\"%%\"", "", "", "", "", "", "", "", "", "", "", "", "\"@\"", "", "", "", "", "", "< ^>", "< ~>", "< +>", "< ->", "< .>", "< o>", "< ,>", "< =>", "< ;>", "< v>" }; char *prelude[] = { "{\\rtf1\\mac\\deff3{\\fonttbl{\\f3\\fswiss Geneva;}{\\f20\\froman Times;}{\\f8837\\fnil Times SC;}}\n", "\\paperw11900\\paperh16840\\margl2840\\margr2840\\margt1420\\margb2560\\deftab31680\n", "\\ftnbj\\sectd\\sbknone\\footery2260{\\footer\\pard\\s2\\qc\\sl-300\\plain\\f20{\\chpgn}}\n", 0 }; char *postlude[] = { "}", 0 }; char *escape[256] = { "\\'00", "\\'01", "\\'02", "\\'03", "\\'04", "\\'05", "\\'06", "\\'07", "\\'08", "\\'09", "\\'0a", "\\'0b", "\\'0c", "\\'0d", "\\'0e", "\\'0f", "\\'10", "\\'11", "\\'12", "\\'13", "\\'14", "\\'15", "\\'16", "\\'17", "\\'18", "\\'19", "\\'1a", "\\'1b", "\\'1c", "\\'1d", "\\'1e", "\\'1f", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "\\\\", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "\\{", 0, "\\}", 0, "\\'7f", "\\'80", "\\'81", "\\'82", "\\'83", "\\'84", "\\'85", "\\'86", "\\'87", "\\'88", "\\'89", "\\'8a", "\\'8b", "\\'8c", "\\'8d", "\\'8e", "\\'8f", "\\'90", "\\'91", "\\'92", "\\'93", "\\'94", "\\'95", "\\'96", "\\'97", "\\'98", "\\'99", "\\'9a", "\\'9b", "\\'9c", "\\'9d", "\\'9e", "\\'9f", "\\'a0", "\\'a1", "\\'a2", "\\'a3", "\\'a4", "\\'a5", "\\'a6", "\\'a7", "\\'a8", "\\'a9", "\\'aa", "\\'ab", "\\'ac", "\\'ad", "\\'ae", "\\'af", "\\'b0", "\\'b1", "\\'b2", "\\'b3", "\\'b4", "\\'b5", "\\'b6", "\\'b7", "\\'b8", "\\'b9", "\\'ba", "\\'bb", "\\'bc", "\\'bd", "\\'be", "\\'bf", "\\'c0", "\\'c1", "\\'c2", "\\'c3", "\\'c4", "\\'c5", "\\'c6", "\\'c7", "\\'c8", "\\'c9", "\\'ca", "\\'cb", "\\'cc", "\\'cd", "\\'ce", "\\'cf", "\\'d0", "\\'d1", "\\'d2", "\\'d3", "\\'d4", "\\'d5", "\\'d6", "\\'d7", "\\'d8", "\\'d9", "\\'da", "\\'db", "\\'dc", "\\'dd", "\\'de", "\\'df", "\\'e0", "\\'e1", "\\'e2", "\\'e3", "\\'e4", "\\'e5", "\\'e6", "\\'e7", "\\'e8", "\\'e9", "\\'ea", "\\'eb", "\\'ec", "\\'ed", "\\'ee", "\\'ef", "\\'f0", "\\'f1", "\\'f2", "\\'f3", "\\'f4", "\\'f5", "\\'f6", "\\'f7", "\\'f8", "\\'f9", "\\'fa", "\\'fb", "\\'fc", "\\'fd", "\\'fe", "\\'ff" }; char *car[] = { "\\qj", 0, "\\qj", 0, "\\ql\\fi-840\\li1400", "\\qj\\li280\\ri280", "\\ql\\fi-560\\li1400", 0, "\\qc", 0, "\\qr" }; char *cdr[] = { 0, 0, "\\qj\\fi280", 0, 0, "\\qj\\fi280\\li280\\ri280", 0, 0, 0, 0, 0 }; struct state { FILE *text; int line, start, parity, old, new, forced, changed, prev, second; } cur, body, notes; char *prog, *file, buf[6]; int realcaps, phase, flushing = 0, silent = 0, white = 0; void bumpline() { cur.line++; #ifdef macintosh SpinCursor(1); #endif } int get() { int c; c = getc(cur.text); if (cur.start) { bumpline(); while ((phase < 2) == (c == '|') || c == '\t') { while (c != EOF && c != '\n') c = getc(cur.text); if (c == EOF) break; bumpline(); c = getc(cur.text); } if (c == '|') { if ((c = getc(cur.text)) == ' ') c = getc(cur.text); else { if (c == '\n') (void) fprintf(stderr, "%s: %s: line %d: note line only contains \"|\"\n", prog, file, cur.line); else (void) fprintf(stderr, "%s: %s: line %d: note line starts with \"|%c\"\n", prog, file, cur.line, c); } } } cur.start = (c == '\n'); return c; } void unget(c) int c; { (void) ungetc(c, cur.text); cur.start = 0; } void putstr(s) char *s; { if (fputs(s, stdout) < 0) { (void) fprintf(stderr, "%s: couldn't write (disk full?)\n", prog); exit(1); } } void skipblanks() { int c, n; char *s; n = 0; while ((c = getc(cur.text)) == ' ') n++; (void) ungetc(c, cur.text); if (n > 10) (void) fprintf(stderr, "%s: %s: line %d: paragraph starts with too much spaces\n", prog, file, cur.line); else if (!(s = car[n])) (void) fprintf(stderr, "%s: %s: line %d: paragraph starts with strange number of spaces\n", prog, file, cur.line); else if (n != cur.prev || (cur.second && (s = cdr[n]))) { putstr("\\pard"); putstr(s); if (phase < 2) putstr("\\sl-300"); else putstr("\\sl-240"); putstr(" "); cur.forced = 1; } cur.second = (n != cur.prev); cur.prev = n; } void put(c) int c; { char *s; if (silent) return; if (white && c == ' ') return; if (cur.forced || (cur.changed && cur.new != cur.old)) { if (realcaps && (cur.new & SC)) putstr("\\plain\\f8837"); else if (cur.forced || cur.old) putstr("\\plain\\f20"); if (cur.new & SUP) { if (cur.new & SMALL) putstr("\\fs14\\up6"); else putstr("\\fs18\\up6"); } else { if (cur.new & SMALL) putstr("\\fs20"); else if (cur.old & (SUP + SMALL)) putstr("\\fs24"); } if (!realcaps && (cur.new & SC)) putstr("\\scaps"); if (cur.new & IT) putstr("\\i"); if (cur.new & BLD) putstr("\\b"); putstr(" "); cur.old = cur.new; cur.forced = 0; cur.changed = 0; } if ((s = escape[c])) putstr(s); else if (putchar(c) < 0) { (void) fprintf(stderr, "%s: couldn't write (disk full?)\n", prog); exit(1); } white = (c == ' '); } void putcode(s) char *s; { int n, saved; for (n = 0; n < 256 && strcmp(s, code[n]); n++) ; if (n < 256) put(n); else if (!s[3] && isdigit(s[1])) { saved = cur.new; cur.new |= SUP; cur.changed = 1; put(s[1]); cur.new = saved; cur.changed = 1; } else { (void) fprintf(stderr, "%s: %s: line %d: strange code %s\n", prog, file, cur.line, s); for (n = 0; s[n]; n++) if (s[n] != '"') put(s[n]); } } void startnote() { int c; body = cur; cur = notes; cur.prev = -2; cur.old = 0; cur.new = SMALL; cur.forced = 1; phase = 2; while ((c = get()) == '\n') ; unget(c); putstr("{\\plain\\f20\\fs18\\up6\\chftn{\\footnote "); skipblanks(); } void stopnote() { putstr("}}"); notes = cur; cur = body; cur.old = cur.new | SMALL; cur.forced = 1; phase = 0; } int flushother() { int c; if (phase < 2) { body = cur; cur = notes; phase = 2; while ((c = get()) == '\n') ; if (c == EOF) return 0; else { (void) fprintf(stderr, "%s: %s: line %d: unreferenced note line\n", prog, file, cur.line); phase = 2; unget(c); putstr("{\\plain\\f20\\fs18\\up6\\chftn{\\footnote "); skipblanks(); flushing = 1; } } else { if (!flushing) (void) fprintf(stderr, "%s: %s: line %d: missing footnote or end of file inside footnote\n", prog, file, cur.line); putstr("}}"); notes = cur; cur = body; phase = 0; if (flushing) return 0; } return 1; } void putlines(a) char **a; { char *s; for (; (s = *a); a++) putstr(s); } int main(argc, argv) int argc; char **argv; { int c, n; #ifdef macintosh InitCursorCtl(NULL); #endif prog = argv[0]; if (argc != 2 && (argc != 3 || strcmp(argv[1], "-k"))) { (void) fprintf(stderr, "%s: usage: %s [-k] file\n", prog, prog); exit(1); } realcaps = (argc == 3); file = argv[argc - 1]; if (!(body.text = fopen(file, "r"))) { (void) fprintf(stderr, "%s: %s: couldn't open\n", prog, file); exit(1); } if (!(notes.text = fopen(file, "r"))) { (void) fprintf(stderr, "%s: %s: couldn't open twice\n", prog, file); exit(1); } body.line = notes.line = 0; body.start = notes.start = 1; body.parity = notes.parity = 0; body.old = body.new = 0; body.forced = notes.forced = 1; body.prev = notes.prev = -2; escape['\n'] = "\\par\n"; putlines(prelude); cur = body; phase = 0; skipblanks(); while (1) { c = get(); switch (c) { case '\n': switch (phase) { case 0: break; case 1: (void) fprintf(stderr, "%s: %s: line %d: unterminated footnote reference\n", prog, file, cur.line); phase = 0; break; case 2: break; case 3: (void) fprintf(stderr, "%s: %s: line %d: unterminated footnote number\n", prog, file, cur.line); phase = 2; break; case 4: break; } c = get(); if (c == ' ' || c == '\n' || c == EOF) { if (phase && c != ' ') stopnote(); else { unget(c); if (c != EOF) { put('\n'); skipblanks(); } if (cur.new) cur.forced = 1; } } else { unget(c); put(' '); } break; case '-': n = 0; while ((c = get()) == ' ') n++; switch (c) { case '\n': if (n) put('-'); c = get(); if (c == ' ') { if (n) put(' '); put('\n'); unget(c); skipblanks(); } else { unget(c); if (n > 1) put(' '); } break; case '-': if (n) { put('-'); put(' '); unget(c); } else { n = 2; while ((c = get()) == '-') n++; unget(c); switch(n) { case 2: put(208); break; case 3: put(209); break; default: (void) fprintf(stderr, "%s: %s: line %d: more than 3 hyphens in a row\n", prog, file, cur.line); put(209); } } break; default: unget(c); put('-'); if (n) put(' '); } break; case '"': n = 0; buf[n++] = c; while (1) { c = get(); if (c == '\n') { unget(c); break; } buf[n++] = c; if (c == '"' || n == 5) break; } buf[n++] = '\0'; putcode(buf); break; case '<': buf[0] = '<'; buf[3] = '>'; buf[4] = '\0'; while (1) { c = get(); if (c == '>') break; if (c == '\n') { unget(c); (void) fprintf(stderr, "%s: %s: line %d: unterminated \"<\" code\n", prog, file, cur.line); break; } buf[1] = c; c = get(); if (c == '>' || c == '\n') { unget(c); (void) fprintf(stderr, "%s: %s: line %d: short \"<\" code\n", prog, file, cur.line); put(buf[1]); break; } buf[2] = c; putcode(buf); } break; case '.': n = 1; while ((c = get()) == '.') n++; unget(c); if (n < 3) while (n--) put('.'); else if (n == 3) put(201); else { (void) fprintf(stderr, "%s: %s: line %d: more than 3 dots in a row\n", prog, file, cur.line); put(201); } break; case '`': c = get(); if (c == '~') { cur.parity = 0; while (1) { put(cur.parity ? 210 : 212); cur.parity = !cur.parity; c = get(); if (c != '`') break; c = get(); if (c != '~') { put(cur.parity ? 210 : 212); cur.parity = !cur.parity; break; } } } else { put(cur.parity ? 210 : 212); cur.parity = !cur.parity; } unget(c); break; case '\'': c = get(); if (isalnum(c) || c == '<' || c == '"' || c == '~') put(213); else { cur.parity = !cur.parity; put(cur.parity ? 211 : 213); } unget(c); break; case '_': cur.new ^= IT; cur.changed = 1; break; case '=': cur.new ^= SC; cur.changed = 1; break; case '*': cur.new ^= BLD; cur.changed = 1; break; case '^': switch (phase) { case 0: phase++; silent = 1; break; case 1: startnote(); /* phase = 2 */ silent = 0; break; case 2: phase++; silent = 1; putstr("\\plain\\f20\\fs20{\\chftn .}"); cur.old = SMALL; cur.forced = 0; cur.changed = 1; break; case 3: phase++; silent = 0; put(' '); break; case 4: (void) fprintf(stderr, "%s: %s: line %d: double numbered footnote?\n", prog, file, cur.line); break; } break; case '~': break; case EOF: break; default: put(c); } if (c == EOF && !flushother()) break; } putlines(postlude); return 0; }