/* * Print out the contents of a PRG file in human-readable form * * Copyright (c) 2010 Benjamin Moody * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include #include #include #include "utils.h" static const struct charinfo { char value; const char* utf8; const char* utf8multi; const char* html; } specialchars[] = { { '\201', "ε", "ε", "E" }, { '\202', "→", "→", "→" }, { '\203', "≠", "≠", "≠" }, { '\204', "≤", "≤", "≤" }, { '\205', "≥", "≥", "≥" }, { '\206', "⁻", "⁻", "⁻" }, { '\207', "√", "√", "√" }, { '\210', "³", "³", "3" }, { '\211', "⏨", "₁₀", "10" }, { '\212', "¹", "⁻¹", "-1" }, { '\213', "²", "²", "2" }, { '\214', "⸆", "⸆", "T" }, { '\215', "ʳ", "ʳ", "r" }, { '\216', "°", "°", "°" }, { '\217', "▸", "▸", "▸" }, { '\220', "␣", "␣", " " }, { '\221', "θ", "θ", "θ" }, { '\222', "Σ", "Σ", "Σ" }, { '\223', "x\314\204", "x\314\204", "x\314\204" }, { '\224', "σ", "σ", "σ" }, { '\225', "ȳ", "ȳ", "ȳ" }, { '\226', "π", "π", "π" }, { '\227', "₁", "₁", "1" }, { '\230', "₂", "₂", "2" }, { '\231', "₃", "₃", "3" }, { '\232', "₄", "₄", "4" }, { '\233', "┬", "┬", "T" }, { 0, 0, 0, 0 } }; static const struct tokeninfo { const char* asciistr; const char* bytestr; const char* keystrokes; } tokens[256] = { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { "Prgm", "Prgm", "PRGM ← 1 ← DEL"}, { 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" }, { "1", "1", "1" }, { "2", "2", "2" }, { "3", "3", "3" }, { "4", "4", "4" }, { "5", "5", "5" }, { "6", "6", "6" }, { "7", "7", "7" }, { "8", "8", "8" }, { "9", "9", "9" }, { ".", ".", "." }, { "e", "\201", "EE" }, { "->", "\202", "STO▸" }, { ")", ")", ")" }, { ",", ",", "ALPHA ." }, { "(", "(", "(" }, { "=", "=", "2nd MATH 1" }, { "<>", "\203", "2nd MATH 2" }, { "<", "<", "2nd MATH 5" }, { "<=", "\204", "2nd MATH 6" }, { ">", ">", "2nd MATH 3" }, { ">=", "\205", "2nd MATH 4" }, { "+", "+", "+" }, { "-", "-", "-" }, { "*", "*", "×" }, { "/", "/", "÷" }, { " nCr ", " nCr ", "MATH ← 3" }, { " nPr ", " nPr ", "MATH ← 2" }, { "\"", "\"", "ALPHA +" }, { "IPart ", "IPart ", "MATH → 2" }, { "Int ", "Int ", "MATH → 4" }, { "FPart ", "FPart ", "MATH → 3" }, { "(-)", "\206", "(-)" }, { "abs ", "abs ", "2nd x⁻¹" }, { "\\SquareRoot\\", "\207", "2nd x²" }, { "\\CubeRoot\\", "\210\207", "MATH 4" }, { "ln ", "ln ", "LN" }, { "e^", "e^", "2nd LN" }, { "log ", "log ", "LOG" }, { "\\10^\\", "\211^", "2nd LOG" }, { "sin ", "sin ", "SIN" }, { "sin^-1 ", "sin\212 ", "2nd SIN" }, { "cos ", "cos ", "COS" }, { "cos^-1 ", "cos\212 ", "2nd COS" }, { "tan ", "tan ", "TAN" }, { "tan^-1 ", "tan\212 ", "2nd TAN" }, { "sinh ", "sinh ", "MATH → → 1" }, { "sinh^-1 ", "sinh\212 ", "MATH → → 4" }, { "cosh ", "cosh ", "MATH → → 2" }, { "cosh^-1 ", "cosh\212 ", "MATH → → 5" }, { "tanh ", "tanh ", "MATH → → 3" }, { "tanh^-1 ", "tanh\212 ", "MATH → → 6" }, { "det", "det", "MATRX 5" }, { "?", "?", "ALPHA (-)" }, { "^", "^", "^" }, { "\\^-1\\", "\212", "x⁻¹" }, { "\\^2\\", "\213", "x²" }, { "t", "\214", "MATRX 6" }, { "\\^3\\", "\210", "MATH 3" }, { "!", "!", "MATH 5" }, { "\\radian\\", "\215", "MATH 7" }, { "\\degree\\", "\216", "MATH 6" }, { "Round(", "Round(", "MATH → 1" }, { "\\R>P(\\", "R\217P(", "MATH 1" }, { "\\P>R(\\", "P\217R(", "MATH 2" }, { "RowSwap(", "RowSwap(", "MATRX 1" }, { "Row+(", "Row+(", "MATRX 2" }, { "*Row(", "*Row(", "MATRX 3" }, { "*Row+(", "*Row+(", "MATRX 4" }, { "NDeriv(", "NDeriv(", "MATH 8" }, { " ", "\220", "ALPHA 0" }, { "Ans", "Ans", "2nd (-)" }, { "Rand", "Rand", "MATH ← 1" }, { "A", "A", "ALPHA MATH" }, { "B", "B", "ALPHA MATRX" }, { "C", "C", "ALPHA PRGM" }, { "D", "D", "ALPHA x⁻¹" }, { "E", "E", "ALPHA SIN" }, { "F", "F", "ALPHA COS" }, { "G", "G", "ALPHA TAN" }, { "H", "H", "ALPHA ^" }, { "I", "I", "ALPHA x²" }, { "J", "J", "ALPHA EE" }, { "K", "K", "ALPHA (" }, { "L", "L", "ALPHA )" }, { "M", "M", "ALPHA ÷" }, { "N", "N", "ALPHA LOG" }, { "O", "O", "ALPHA 7" }, { "P", "P", "ALPHA 8" }, { "Q", "Q", "ALPHA 9" }, { "R", "R", "ALPHA ×" }, { "S", "S", "ALPHA LN" }, { "T", "T", "ALPHA 4" }, { "U", "U", "ALPHA 5" }, { "V", "V", "ALPHA 6" }, { "W", "W", "ALPHA -" }, { "X", "X", "ALPHA STO▸" }, { "Y", "Y", "ALPHA 1" }, { "Z", "Z", "ALPHA 2" }, { "\\Theta\\", "\221", "ALPHA 3" }, { "Arow", "Arow", "VARS ← ← 1" }, { "Acol", "Acol", "VARS ← ← 2" }, { "Brow", "Brow", "VARS ← ← 3" }, { "Bcol", "Bcol", "VARS ← ← 4" }, { "Crow", "Crow", "VARS ← ← 5" }, { "Ccol", "Ccol", "VARS ← ← 6" }, { "Tmin", "Tmin", "VARS ← 8" }, { "Tmax", "Tmax", "VARS ← 9" }, { "Tstep", "Tstep", "VARS ← 0" }, { "Xmin", "Xmin", "VARS ← 1" }, { "Xmax", "Xmax", "VARS ← 2" }, { "Xscl", "Xscl", "VARS ← 3" }, { "Ymin", "Ymin", "VARS ← 4" }, { "Ymax", "Ymax", "VARS ← 5" }, { "Yscl", "Yscl", "VARS ← 6" }, { "Xres", "Xres", "VARS ← 7" }, { "{x}(", "{x}(", "2nd 0" }, { "{y}(", "{y}(", "2nd ." }, { "[A]", "[A]", "2nd 1" }, { "[B]", "[B]", "2nd 2" }, { "[C]", "[C]", "2nd 3" }, { "\\Sigma-x\\", "\222x", "VARS → 1" }, { "\\Sigma-x^2\\", "\222x\213", "VARS → 2" }, { "\\Sigma-xy\\", "\222xy", "VARS → 5" }, { "\\Sigma-y\\", "\222y", "VARS → 3" }, { "\\Sigma-y^2\\", "\222y\213", "VARS → 4" }, { "n", "n", "VARS 1" }, { "\\x-bar\\", "\223", "VARS 2" }, { "\\sx\\", "\224x", "VARS 4" }, { "Sx", "Sx", "VARS 3" }, { "\\y-bar\\", "\225", "VARS 5" }, { "\\sy\\", "\224y", "VARS 7" }, { "Sy", "Sy", "VARS 6" }, { "b", "b", "VARS → → 2" }, { "a", "a", "VARS → → 1" }, { "r", "r", "VARS → → 3" }, { "Dim{x}", "Dim{x}", "VARS ← ← 7" }, { "\\pi\\", "\226", "2nd ^" }, { "1-Var", "1-Var", "2nd MATRX 1" }, { "LinReg", "LinReg", "2nd MATRX 2" }, { "ExpReg", "ExpReg", "2nd MATRX 4" }, { "LnReg", "LnReg", "2nd MATRX 3" }, { "PwrReg", "PwrReg", "2nd MATRX 5" }, { "xSort", "xSort", "2nd MATRX ← 3" }, { "ySort", "ySort", "2nd MATRX ← 4" }, { "ClrStat", "ClrStat", "2nd MATRX ← 2" }, { 0, 0, 0 }, { "Hist", "Hist", "2nd MATRX → 1" }, { "xyLine", "xyLine", "2nd MATRX → 3" }, { "Scatter", "Scatter", "2nd MATRX → 2" }, { "Rad", "Rad", "MODE 6" }, { "Deg", "Deg", "MODE 7" }, { "Norm", "Norm", "MODE 1" }, { "Sci", "Sci", "MODE 2" }, { "Eng", "Eng", "MODE 3" }, { "Float", "Float", "MODE 5" }, { "Fix ", "Fix ", "MODE 4" }, { "Function", "Function", "MODE → 1" }, { "Param", "Param", "MODE → 2" }, { "Connected", "Connected", "MODE → 3" }, { "Dot", "Dot", "MODE → 4" }, { "Sequence", "Sequence", "MODE → 5" }, { "Simul", "Simul", "MODE → 6" }, { "Grid Off", "Grid Off", "MODE → 7" }, { "Grid On", "Grid On", "MODE → 8" }, { "Rect", "Rect", "MODE → 9" }, { "Polar", "Polar", "MODE → 0" }, { "Disp ", "Disp ", "PRGM → 1" }, { "Input ", "Input ", "PRGM → 2" }, { "Pause", "Pause", "PRGM 6" }, { "End", "End", "PRGM 7" }, { "Stop", "Stop", "PRGM 8" }, { "Lbl ", "Lbl ", "PRGM 1" }, { "Goto ", "Goto ", "PRGM 2" }, { "If ", "If ", "PRGM 3" }, { "IS>(", "IS>(", "PRGM 4" }, { "DS<(", "DS<(", "PRGM 5" }, { "Y1", "Y\227", "2nd VARS 1" }, { "Y2", "Y\230", "2nd VARS 2" }, { "Y3", "Y\231", "2nd VARS 3" }, { "Y4", "Y\232", "2nd VARS 4" }, { "X1t", "X\227\233", "2nd VARS 5" }, { "Y1t", "Y\227\233", "2nd VARS 6" }, { "X2t", "X\230\233", "2nd VARS 7" }, { "Y2t", "Y\230\233", "2nd VARS 8" }, { "X3t", "X\231\233", "2nd VARS 9" }, { "Y3t", "Y\231\233", "2nd VARS 0" }, { "All-On", "All-On", "2nd VARS → 1" }, { "Y1-On", "Y\227-On", "2nd VARS → 2" }, { "Y2-On", "Y\230-On", "2nd VARS → 3" }, { "Y3-On", "Y\231-On", "2nd VARS → 4" }, { "Y4-On", "Y\232-On", "2nd VARS → 5" }, { "X1t-On", "X\227\233-On", "2nd VARS → 6" }, { "X2t-On", "X\230\233-On", "2nd VARS → 7" }, { "X3t-On", "X\231\233-On", "2nd VARS → 8" }, { "All-Off", "All-Off", "2nd VARS ← 1" }, { "Y1-Off", "Y\227-Off", "2nd VARS ← 2" }, { "Y2-Off", "Y\230-Off", "2nd VARS ← 3" }, { "Y3-Off", "Y\231-Off", "2nd VARS ← 4" }, { "Y4-Off", "Y\232-Off", "2nd VARS ← 5" }, { "X1t-Off", "X\227\233-Off", "2nd VARS ← 6" }, { "X2t-Off", "X\230\233-Off", "2nd VARS ← 7" }, { "X3t-Off", "X\231\233-Off", "2nd VARS ← 8" }, { "Line(", "Line(", "2nd PRGM 2" }, { "PT-On(", "PT-On(", "2nd PRGM 3" }, { "PT-Off(", "PT-Off(", "2nd PRGM 4" }, { "PT-Chg(", "PT-Chg(", "2nd PRGM 5" }, { "DrawF ", "DrawF ", "2nd PRGM 6" }, { "Shade(", "Shade(", "2nd PRGM 7" }, { "ClrDraw", "ClrDraw", "2nd PRGM 1" }, { "ClrHome", "ClrHome", "PRGM → 5" }, { "DispHome", "DispHome", "PRGM → 3" }, { "DispGraph", "DispGraph", "PRGM → 4" }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { "\n", "\n", "ENTER" }, { 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 } }; /* output modes */ enum { ASCII81P, UTF8_UNWRAPPED, UTF8_WRAPPED, UTF8_TWO_COLUMN, HTML }; static int isvalid(unsigned int t) { return (tokens[t].bytestr ? 1 : 0); } static const char* getasciistr(unsigned int t) { static char buf[7]; if (tokens[t].asciistr) return tokens[t].asciistr; else { sprintf(buf, " #%02X# ", t); return buf; } } static const char* getbytestr(unsigned int t) { static char buf[7]; if (tokens[t].bytestr) return tokens[t].bytestr; else { sprintf(buf, " #%02X# ", t); return buf; } } static const char* getkeystrokes(unsigned int t) { if (tokens[t].keystrokes) return tokens[t].keystrokes; else return "INVALID"; } static int isalphakey(unsigned int t) { return !strncmp(getkeystrokes(t), "ALPHA ", 6); } static int is2ndkey(unsigned int t) { return !strncmp(getkeystrokes(t), "2nd ", 4); } static const struct charinfo* getci(char c) { int i; for (i = 0; specialchars[i].value; i++) if (specialchars[i].value == c) return &specialchars[i]; return NULL; } static void printutf8mtok(unsigned int t, FILE* outf) { const char* s = getbytestr(t); const struct charinfo* ci; while (*s) { ci = getci(*s); if (ci) fputs(ci->utf8multi, outf); else fputc(*s, outf); s++; } } static void printhtmlchar(char c, FILE* outf) { const struct charinfo* ci; ci = getci(c); if (ci) fputs(ci->html, outf); else if (c == '\"') fputs(""", outf); else if (c == '<') fputs("<", outf); else if (c == '>') fputs(">", outf); else if (c == ' ') fputs(" ", outf); else if (c == '-') fputs("\342\210\222", outf); else fputc(c, outf); } static void printhtmltok(unsigned int t, FILE* outf) { const char* s = getbytestr(t); while (*s) { printhtmlchar(*s, outf); s++; } } static const char* gethtmlclass(unsigned int t, int parity, int key) { if (!isvalid(t)) return (key ? "ki" : "ci"); else if (t == 0xEC) return (key ? "keol" : "cbol"); else if (parity) return (key ? "ke" : "ce"); else return (key ? "ko" : "co"); } static void print_display_line(FILE* outf, int fmt, const unsigned char* data, int start, int end, int skipchars, int* parity) { const char* s; const char* c; const struct charinfo* ci; int n; if (fmt == HTML) { fprintf(outf, "\n"); if (skipchars == -1) { fprintf(outf, ":"); n = 1; *parity = 0; skipchars = 0; } else { if (skipchars) *parity = !*parity; n = 0; } while (start < end) { s = getbytestr(data[start]); s += skipchars; skipchars = 0; c = gethtmlclass(data[start], *parity, 0); *parity = !*parity; while (*s && n < 16) { fprintf(outf, "", c); printhtmlchar(*s, outf); fputs("", outf); s++; n++; } start++; } fprintf(outf, ""); } else { if (skipchars == -1) { fprintf(outf, ":"); n = 1; skipchars = 0; } else { n = 0; } while (start < end) { s = getbytestr(data[start]); s += skipchars; skipchars = 0; while (*s && n < 16) { ci = getci(*s); if (ci) fputs(ci->utf8, outf); else fputc(*s, outf); s++; n++; } start++; } if (fmt == UTF8_TWO_COLUMN) { while (n < 20) { fputc(' ', outf); n++; } fputc('\t', outf); } else fputs("\r\n", outf); } } static void print_key_sequence(FILE* outf, int fmt, unsigned int t, const char* keys, int parity) { int inkey = 0; while (*keys) { if (*keys == ' ' && inkey) { if (fmt == HTML) fputs("", outf); else fputc(']', outf); inkey = 0; } else if (*keys != ' ' && !inkey) { if (fmt == HTML) fprintf(outf, "", gethtmlclass(t, parity, 1)); else fputc('[', outf); inkey = 1; } fputc(*keys, outf); keys++; } if (inkey) { if (fmt == HTML) fputs("", outf); else fputc(']', outf); } } static void print_keystroke_line(FILE* outf, int fmt, const unsigned char* data, int start, int end, int* parity, int* kstate) { const char* curkeys; int sep; if (fmt == UTF8_WRAPPED) return; if (fmt == HTML) fputs("\n", outf); while (start < end) { if (data[start] == 7 && ((data[start + 1] >= 0x10 && data[start + 1] <= 0x19) || (data[start + 1] >= 0x59 && data[start + 1] <= 0x73))) { curkeys = "PRGM ←"; sep = 0; } else { curkeys = getkeystrokes(data[start]); sep = 1; } if (isalphakey(data[start])) { if (*kstate) curkeys += 6; else if (isalphakey(data[start + 1]) && isalphakey(data[start + 2])) { print_key_sequence(outf, fmt, data[start], "2nd ", *parity); *kstate = 1; } } print_key_sequence(outf, fmt, data[start], curkeys, *parity); if (*kstate && !isalphakey(data[start + 1])) { if (data[start + 1] && data[start + 1] != 0xEC && !is2ndkey(data[start + 1])) print_key_sequence(outf, fmt, data[start], " ALPHA", *parity); *kstate = 0; } if (data[start] == 0xEC) *parity = 0; else *parity = !*parity; start++; if (start < end) { if (sep) fputc(';', outf); fputc(' ', outf); } } if (fmt == HTML) fprintf(outf, "\n"); else fprintf(outf, "\r\n"); } static void print_tokens(FILE* outf, int fmt, const unsigned char* data, unsigned int length) { unsigned int i, firsttok, firstfulltok; int width, skipchars; int parityleft = 0; int parityright = 0; int kstate = 0; const char* s; i = firsttok = firstfulltok = 0; skipchars = -1; width = 1; while (i < length) { if (data[i] == 0xEC) { print_display_line(outf, fmt, data, firsttok, i, skipchars, &parityleft); print_keystroke_line(outf, fmt, data, firstfulltok, i + 1, &parityright, &kstate); firsttok = firstfulltok = i + 1; skipchars = -1; width = 1; } else { s = getbytestr(data[i]); width += strlen(s); if (width >= 16) { print_display_line(outf, fmt, data, firsttok, i + 1, skipchars, &parityleft); print_keystroke_line(outf, fmt, data, firstfulltok, i + 1, &parityright, &kstate); firsttok = i; firstfulltok = i + 1; width -= 16; skipchars = strlen(s) - width; } } i++; } print_display_line(outf, fmt, data, firsttok, i, skipchars, &parityleft); print_keystroke_line(outf, fmt, data, firstfulltok, i, &parityright, &kstate); } static int list_program(FILE* outf, int fmt, const char* infilename, const char* title, const unsigned char* header, const unsigned char* data, unsigned int length) { unsigned int i; int j; int pos; int ok = 1; const char* s; for (i = 0; i < length; i++) if (!isvalid(data[i])) ok = 0; switch (fmt) { case ASCII81P: if (title) fprintf(outf, "%s\r\n", title); fprintf(outf, "\\START81\\\r\n"); fprintf(outf, "\\NAME="); for (i = 12; i < 20; i++) fprintf(outf, "%s", getasciistr(header[i])); fprintf(outf, "\r\n\\FILE=%s\r\n", infilename); pos = 0; for (i = 0; i < length; i++) { if (data[i] == 0xEC) { fprintf(outf, "\r\n"); pos = 0; } else { s = getasciistr(data[i]); for (j = 0; s[j]; j++) { if (pos >= 70) { fprintf(outf, "\\#\\%cF", 0); pos = 0; } fputc(s[j], outf); pos++; } } } fprintf(outf, "\r\n\\STOP81\\\r\n"); break; case UTF8_UNWRAPPED: if (title) fprintf(outf, "%s\r\n\r\n:", title); else { fprintf(outf, "Program: "); for (i = 12; i < 20; i++) { if (header[i] == 0x56) fputc(' ', outf); else printutf8mtok(header[i], outf); } fprintf(outf, "\r\n\r\n:"); } for (i = 0; i < length; i++) { if (data[i] == 0xEC) { fprintf(outf, "\r\n:"); } else { fputs("\342\200\211", outf); printutf8mtok(data[i], outf); } } fprintf(outf, "\r\n\r\n"); break; case UTF8_WRAPPED: case UTF8_TWO_COLUMN: if (title) fprintf(outf, "%s\r\n\r\n", title); else { fprintf(outf, "Program: "); for (i = 12; i < 20; i++) { if (header[i] == 0x56) fputc(' ', outf); else printutf8mtok(header[i], outf); } fprintf(outf, "\r\n\r\n"); } print_tokens(outf, fmt, data, length); fprintf(outf, "\r\n"); break; case HTML: fprintf(outf, "\n"); fprintf(outf, "\n"); print_tokens(outf, HTML, data, length); fprintf(outf, "
"); if (title) fputs(title, outf); else { fprintf(outf, "Program: "); for (i = 12; i < 20; i++) { if (header[i] == 0x56) fputc(' ', outf); else printhtmltok(header[i], outf); } } fprintf(outf, "
\n"); } return !ok; } static int list_program_file(FILE* outf, int fmt, const char* infilename, const char* title) { FILE* inf; unsigned char header[20]; unsigned char* data; unsigned int length, sum, j; int ok = 1; if (infilename && strcmp(infilename, "-")) { inf = fopen(infilename, "rb"); if (!inf) { perror(infilename); return 1; } } else inf = stdin; while (fread(header, 1, 20, inf) == 20) { length = header[10] | (header[11] << 8); data = xmalloc(length + 2); if (fread(data, 1, length + 2, inf) != length + 2) { fprintf(stderr, "%s: I/O error\n", infilename); xfree(data); ok = 0; break; } sum = 0; for (j = 12; j < 20; j++) sum += header[j]; for (j = 0; j < length; j++) sum += data[j]; if ((sum & 0xff) != data[length] || ((sum >> 8) & 0xff) != data[length + 1]) { fprintf(stderr, "%s: warning: checksum incorrect\n", infilename); } data[length] = 0; if (list_program(outf, fmt, infilename, title, header, data, length)) ok = 0; xfree(data); } if (inf != stdin) fclose(inf); return !ok; } static const char usage[] = "Usage: %s [[-t title] prgfile]... [-f format] [-o outfile]\n"; int main(int argc, char** argv) { const char* outfilename = "-"; const char* titlestr = NULL; int fmt = UTF8_TWO_COLUMN; FILE* outf; int i; int ok = 1; const char* arg; for (i = 1; i < argc; i++) { if (argv[i][0] == '-' && argv[i][1] != 0) { switch (argv[i][1]) { case 'o': if (argv[i][2]) outfilename = &argv[i][2]; else if (i < argc - 1) outfilename = argv[++i]; else { fprintf(stderr, "%s: -o: requires argument\n", argv[0]); return 1; } break; case 't': if (argv[i][2]) arg = &argv[i][2]; else if (i < argc - 1) arg = argv[++i]; else { fprintf(stderr, "%s: -t: requires argument\n", argv[0]); return 1; } break; case 'f': if (argv[i][2]) arg = &argv[i][2]; else if (i < argc - 1) arg = argv[++i]; else { fprintf(stderr, "%s: -f: requires argument\n", argv[0]); return 1; } if (!strcasecmp(arg, "ascii81p") || !strcmp(arg, "a")) fmt = ASCII81P; else if (!strcasecmp(arg, "unwrapped") || !strcmp(arg, "u")) fmt = UTF8_UNWRAPPED; else if (!strcasecmp(arg, "wrapped") || !strcmp(arg, "w")) fmt = UTF8_WRAPPED; else if (!strcasecmp(arg, "two-column") || !strcmp(arg, "2")) fmt = UTF8_TWO_COLUMN; else if (!strcasecmp(arg, "html") || !strcmp(arg, "h")) fmt = HTML; else { fprintf(stderr, "%s: unknown format %s\n", argv[0], arg); return 1; } break; default: fprintf(stderr, "%s: unknown option %s\n", argv[0], argv[i]); fprintf(stderr, usage, argv[0]); return 1; } } } if (outfilename && strcmp(outfilename, "-")) { outf = fopen(outfilename, "wb"); if (!outf) { perror(outfilename); return 1; } } else outf = stdout; for (i = 1; i < argc; i++) { if (argv[i][0] == '-' && argv[i][1] == 't') { if (argv[i][2]) titlestr = &argv[i][2]; else if (i < argc - 1) titlestr = argv[++i]; } else if (argv[i][0] != '-' || argv[i][1] == 0) { if (list_program_file(outf, fmt, argv[i], titlestr)) ok = 0; titlestr = NULL; } } if (outf != stdout) fclose(outf); return !ok; }