/* * Mimas conversion tools * * 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 "mimas.h" #include "convert.h" #include "utils.h" #include "insts.h" #include "itempl.h" #include "byvalue.h" typedef struct _constant_entry { unsigned int value; char *str; } constant_entry; typedef struct _import_entry { unsigned char type; char name[9]; } import_entry; typedef struct _section_entry { int type; unsigned int data_start; unsigned int data_end; char name[9]; } section_entry; /**************** String unpacking ****************/ /* Get length of a packed symbol string */ static int symbol_length(const unsigned char *data, int limit) { int i; for (i = 0; i < limit; i++) if ((data[i] & 0x0f) == 0) return i + 1; return limit; } /* Unpack and convert a symbol string (see UnpackSymbolString) */ static char *convert_symbol(const unsigned char *data, int limit) { static const char packed_chars[12] = "`adeilnorst_"; static const char prefix_chars[64] = "``````9876543210" "`ABCDEFGHIJKLMNO" "`z``[ZYXWVUTSRQP" "`bcfghjkmpquvwxy"; char *str, *converted; unsigned int n, prefix = 0; int packedlength, pos, h, length; packedlength = symbol_length(data, limit); str = xnew(char, (packedlength * 2) + 1); pos = 0; if (data[0] & 0xf0) { length = 0; h = 1; } else { str[0] = '.'; length = 1; h = 0; } while (pos < packedlength) { if (h) { n = data[pos] >> 4; h = 0; } else { n = data[pos] & 0x0f; h = 1; pos++; } if (n == 0) break; if (prefix) { str[length++] = prefix_chars[n + prefix - 0xc0]; prefix = 0; } else if (n < 0x0c) { str[length++] = packed_chars[n]; } else { prefix = n << 4; } } if (prefix) str[length++] = '`'; str[length] = 0; converted = ti83p_to_ascii(str); xfree(str); return converted; } /* Unpack and convert a comment string (see UnpackCommentString) */ static char *convert_comment(const unsigned char *data, int packedlength) { static const char packed_chars[11] = " adeilnorst"; static const char prefix_chars[80] = "\301!\"#$%&'()*+,-./" "?>=<;:9876543210" "@ABCDEFGHIJKLMNO" "_z]\\[ZYXWVUTSRQP" "^bcfghjkmpquvwxy"; char *str, *converted; unsigned int n, prefix = 0; int length, pos, h; str = xnew(char, (packedlength * 2) + 1); length = pos = 0; h = 1; while (pos < packedlength) { if (h) { n = data[pos] >> 4; h = 0; } else { n = data[pos] & 0x0f; h = 1; pos++; } if (prefix) { str[length++] = prefix_chars[n + prefix - 0xb0]; prefix = 0; } else if (n < 0x0b) { str[length++] = packed_chars[n]; } else { prefix = n << 4; } } if (prefix) str[length++] = '`'; while (length > 0 && str[length - 1] == ' ') length--; str[length] = 0; converted = ti83p_to_ascii(str); xfree(str); return converted; } /**************** Builtins ****************/ static int compare_builtins(const void *a, const void *b) { const builtin_symbol *sa = a; const builtin_symbol *sb = b; if (sa->value < sb->value) return -1; else if (sa->value > sb->value) return 1; else return 0; } /* Get name of a builtin symbol */ static const char *find_builtin_by_value(unsigned int type, unsigned int value) { const builtin_symbol *builtins, *b; unsigned int nbuiltins; builtin_symbol k; switch (type) { case 0: builtins = sysFlagByValueTable; nbuiltins = sizeof(sysFlagByValueTable) / sizeof(builtin_symbol); k.value = value; break; case X_ROMCALL: builtins = romCallByValueTable; nbuiltins = sizeof(romCallByValueTable) / sizeof(builtin_symbol); k.value = value; break; case X_SYSADDR: builtins = sysAddrByValueTable; nbuiltins = sizeof(sysAddrByValueTable) / sizeof(builtin_symbol); k.value = value; break; case X_SYSFLAG: case X_SCANCODE: case X_DATATYPE: case X_KEY: case X_KEY_FB: case X_KEY_FC: builtins = sysEnumByValueTable; nbuiltins = sizeof(sysEnumByValueTable) / sizeof(builtin_symbol); k.value = (type << 8) | value; break; default: return NULL; } b = bsearch(&k, builtins, nbuiltins, sizeof(builtin_symbol), &compare_builtins); if (b) return b->name; else return NULL; } /**************** Expressions ****************/ /* Get length of an expression */ static int expr_length(const unsigned char *exp, int limit) { int i, depth; depth = 1; i = 0; while (i < limit && depth != 0) { if (exp[i] < 0x40) { /* symbol */ i += 2; depth--; } else if (exp[i] < 0x50) { /* special */ i++; depth--; } else if (exp[i] < 0x60) { /* byte */ i += 2; depth--; } else if (exp[i] < 0x70) { /* word */ i += 3; depth--; } else if (exp[i] < 0x90) { /* reserved expression codes */ return limit; } else if (exp[i] < 0xa0) { /* unary operator */ i++; } else if (exp[i] < 0xc0) { /* binary operator */ i++; depth++; } else { /* dec6 constant */ i++; depth--; } } if (i < limit) return i; else return limit; } /* Registers */ static const struct { unsigned int value; const char name[5]; } registers[] = {{ X_REG_B, "b" }, { X_REG_C, "c" }, { X_REG_D, "d" }, { X_REG_E, "e" }, { X_REG_H, "h" }, { X_REG_L, "l" }, { X_REG_iHL, "(hl)" }, { X_REG_A, "a" }, { X_REG_BC, "bc" }, { X_REG_DE, "de" }, { X_REG_HL, "hl" }, { X_REG_SP, "sp" }, { X_REG_IX, "ix" }, { X_REG_IY, "iy" }, { X_REG_AF2, "af'" }, { X_REG_AF, "af" }, { X_REG_I, "i" }, { X_REG_R, "r" }, { X_REG_IXH, "ixh" }, { X_REG_IXL, "ixl" }, { X_REG_IYH, "iyh" }, { X_REG_IYL, "iyl" }, { X_COND_NZ, "nz" }, { X_COND_Z, "z" }, { X_COND_NC, "nc" }, { X_COND_C, "c" }, { X_COND_PO, "po" }, { X_COND_PE, "pe" }, { X_COND_P, "p" }, { X_COND_M, "m" }}; #define NUM_REGISTERS 30 /* Binary operators and parenthesization info (see FormatExpr and the binaryOperatorParenTable) */ static const struct { const char s[3]; unsigned int pclass; unsigned int pmask; } binary_operators[] = {{ "*", 0x80, 0x7F }, { "/", 0x40, 0x7F }, { "%", 0x40, 0x7F }, { "+", 0x20, 0x1F }, { "-", 0x20, 0x1F }, { "<<", 0x10, 0x3F }, { ">>", 0x10, 0x3F }, { ">", 0x08, 0x0F }, { "<", 0x08, 0x0F }, { ">=", 0x08, 0x0F }, { "<=", 0x08, 0x0F }, { "==", 0x08, 0x0F }, { "!=", 0x08, 0x0F }, { "&", 0x04, 0xFB }, { "^", 0x02, 0xFD }, { "|", 0x01, 0xFE }}; static int print_hex(FILE *outf, unsigned int n, int width) { if (n >= 0xa000) return fprintf(outf, "%05Xh", n); else if (n >= 0xa00 || width == 4) return fprintf(outf, "%04Xh", n); else if (n >= 0xa0) return fprintf(outf, "%03Xh", n); else return fprintf(outf, "%02Xh", n); } static int print_oct(FILE *outf, unsigned int n, int width) { if (width == 6) return fprintf(outf, "%06oo", n); else return fprintf(outf, "%03oo", n); } static int print_bin(FILE *outf, unsigned int n, int width) { int i; for (i = width - 1; i >= 0; i--) fputc('0' + ((n >> i) & 1), outf); fputc('b', outf); return width + 1; } static int print_quoted_char(FILE *outf, int c, int q) { if (c == q) return fprintf(outf, "\\%c", c); else if (c >= ' ' && c <= '~' && c != '[') return fprintf(outf, "%c", c); else return fprintf(outf, "\\x%02x", c); } /* Print an expression */ static int print_expr(FILE *outf, const unsigned char *exp, int length, int islabel, unsigned int parenmask, const unsigned char *instr, const int *argexprs, unsigned int nsymbols, char **symbols) { const unsigned char *exp_a, *exp_b; int length_a, length_b; unsigned int n, pclass, pmask; const char *s; int count, j; if (length < 1) return fprintf(outf, "{**INCOMPLETE**}"); if (exp[0] < 0x40) { /* symbol */ if (length < 2) return fprintf(outf, "{**INCOMPLETE**}"); n = ((exp[0] << 8) | exp[1]); if (n < nsymbols && symbols[n]) return fprintf(outf, "%s", symbols[n]); else return fprintf(outf, "__Invalid_Sym_%d", n); } else if (exp[0] < 0x50) { /* special */ switch (exp[0]) { case X_EXECPC: return fprintf(outf, "$"); case X_LOADPC: return fprintf(outf, "$$"); case X_PREV_ANON: return fprintf(outf, "@B"); case X_NEXT_ANON: if (islabel) return fprintf(outf, "@"); else return fprintf(outf, "@F"); default: return fprintf(outf, "{**EXPR-%02X**}", exp[0]); } } else if (exp[0] < 0x60) { /* byte */ if (length < 2) return fprintf(outf, "{**INCOMPLETE**}"); n = exp[1]; switch (exp[0]) { case X_DEC8: return fprintf(outf, "%d", n); case X_HEX8: return print_hex(outf, n, 2); case X_OCT8: return print_oct(outf, n, 3); case X_BIN8: return print_bin(outf, n, 8); case X_CHAR: fputc('\'', outf); count = print_quoted_char(outf, n, '\''); fputc('\'', outf); return count + 2; default: s = find_builtin_by_value(exp[0], n); if (s) return fprintf(outf, "%s", s); else return print_hex(outf, n, 2); } } else if (exp[0] < 0x70) { /* word */ if (length < 3) return fprintf(outf, "{**INCOMPLETE**}"); n = ((exp[2] << 8) | exp[1]); switch (exp[0]) { case X_DEC16: return fprintf(outf, "%d", n); case X_HEX16: return print_hex(outf, n, 4); case X_OCT16: return print_oct(outf, n, 6); case X_BIN16: return print_bin(outf, n, 16); case X_ROMCALL: s = find_builtin_by_value(exp[0], n); if (s) return fprintf(outf, "_%s", s); else return print_hex(outf, n, 4); default: s = find_builtin_by_value(exp[0], n); if (s) return fprintf(outf, "%s", s); else return print_hex(outf, n, 2); } } else if (exp[0] < 0x90) { /* reserved expression codes */ return fprintf(outf, "{**EXPR-%02X**}", exp[0]); } else if (exp[0] < 0xa0) { /* unary operator */ exp_a = exp + 1; length_a = expr_length(exp_a, length - 1); switch (exp[0]) { case X_LSB: count = fprintf(outf, "lsb("); count += print_expr(outf, exp_a, length_a, 0, 0, instr, argexprs, nsymbols, symbols); fputc(')', outf); return count + 1; case X_MSB: count = fprintf(outf, "msb("); count += print_expr(outf, exp_a, length_a, 0, 0, instr, argexprs, nsymbols, symbols); fputc(')', outf); return count + 1; case X_MINUS: case X_COMPLEMENT: case X_NOT: fputc("-~!"[exp[0] - X_MINUS], outf); count = print_expr(outf, exp_a, length_a, 0, 0xff, instr, argexprs, nsymbols, symbols); return count + 1; case X_PAREN: fputc('(', outf); count = print_expr(outf, exp_a, length_a, 0, 0, instr, argexprs, nsymbols, symbols); fputc(')', outf); return count + 2; case X_REGVAL: if (length_a == 2 && exp_a[0] == X_ARGVAL && exp_a[1] >= 0xc0 && argexprs) { n = exp_a[1] & 3; exp_a = instr + argexprs[n]; length_a = argexprs[n + 1] - argexprs[n]; } if (length_a == 1 && exp_a[0] >= 0xc0) for (j = 0; j < NUM_REGISTERS; j++) if (registers[j].value == exp_a[0]) return fprintf(outf, "%s", registers[j].name); count = fprintf(outf, "{**REGISTER**}("); count += print_expr(outf, exp_a, length_a, 0, 0, instr, argexprs, nsymbols, symbols); fputc(')', outf); return count + 1; case X_ARGVAL: if (length_a == 1 && exp_a[0] >= 0xc0 && argexprs) { n = exp_a[0] & 3; return print_expr(outf, instr + argexprs[n], argexprs[n + 1] - argexprs[n], islabel, parenmask, NULL, NULL, nsymbols, symbols); } else { fputc('#', outf); count = print_expr(outf, exp_a, length_a, 0, 0xff, instr, argexprs, nsymbols, symbols); return count + 1; } default: count = fprintf(outf, "{**UNARY-%02X**}(", exp[0]); count += print_expr(outf, exp_a, length_a, 0, 0, instr, argexprs, nsymbols, symbols); fputc(')', outf); return count + 1; } } else if (exp[0] < 0xc0) { /* binary operator */ exp_a = exp + 1; length_a = expr_length(exp_a, length - 1); exp_b = exp_a + length_a; length_b = expr_length(exp_b, length - 1 - length_a); if (exp[0] <= X_OR) { pclass = binary_operators[exp[0] - X_MUL].pclass; pmask = binary_operators[exp[0] - X_MUL].pmask; if (pclass & parenmask) fputc('(', outf); count = print_expr(outf, exp_a, length_a, 0, pmask, instr, argexprs, nsymbols, symbols); count += fprintf(outf, " %s ", binary_operators[exp[0] - X_MUL].s); count += print_expr(outf, exp_b, length_b, 0, pclass | pmask, instr, argexprs, nsymbols, symbols); if (pclass & parenmask) { fputc(')', outf); count += 2; } } else { count = fprintf(outf, "{**BINARY-%02X**}(", exp[0]); count += print_expr(outf, exp_a, length_a, 0, 0, instr, argexprs, nsymbols, symbols); count += fprintf(outf, ", "); count += print_expr(outf, exp_b, length_b, 0, 0, instr, argexprs, nsymbols, symbols); fputc(')', outf); count++; } return count; } else { /* dec6 constant */ return fprintf(outf, "%d", (exp[0] & 0x3f)); } } static void print_label_suffix(FILE *outf) { fputc(':', outf); } static void print_comment(FILE *outf, const char *c) { fputc(';', outf); if (c[0]) fprintf(outf, " %s", c); } static void print_mnemonic_noindent(FILE *outf, const char *m) { fprintf(outf, "%s", m); } static void print_mnemonic(FILE *outf, const char *m) { fputc('\t', outf); print_mnemonic_noindent(outf, m); } static void print_argstart(FILE *outf) { fputc('\t', outf); } static void print_argsep(FILE *outf) { fputs(", ", outf); } static void print_template(FILE *outf, const unsigned char *template, const unsigned char *instr, const int *argexprs, unsigned int nsymbols, char **symbols) { int i, n; const char *s; if (!template) return; i = 0; while (i < template[0]) { if (i) print_argsep(outf); else print_argstart(outf); n = expr_length(template + i + 1, template[0] - i); if (i == 0 && (instr[1] == I_BIT_n_iIYpn || instr[1] == I_RES_n_iIYpn || instr[1] == I_RES_n_s_iIYpn || instr[1] == I_SET_n_iIYpn || instr[1] == I_SET_n_s_iIYpn) && instr[argexprs[0]] == X_SYSFLAG && instr[argexprs[1]] >= X_DEC6) { s = find_builtin_by_value(0, (instr[argexprs[0] + 1] << 8) | instr[argexprs[1]]); if (s) fprintf(outf, "%s", s); else fprintf(outf, "%d", instr[argexprs[1]] & 0x3f); } else { print_expr(outf, template + i + 1, n, 0, 0, instr, argexprs, nsymbols, symbols); } i += n; } } static void print_var_name(FILE *outf, const unsigned char *vn, int length) { int type, i; if (length == 0) fprintf(outf, "\"\""); else { type = vn[0] & 0x1f; if (type == 0x05 || type == 0x06 || type == 0x16) { fprintf(outf, "\"prgm"); for (i = 1; i < length && vn[i]; i++) print_quoted_char(outf, vn[i], '"'); fprintf(outf, "\""); } else if (type == 0x15) { fprintf(outf, "\""); for (i = 1; i < length && vn[i]; i++) print_quoted_char(outf, vn[i], '"'); fprintf(outf, "\""); } else if (type == 0x07 && vn[1] == 0x60) { fprintf(outf, "\"Pic%d\"", (vn[2] == 9 ? 0 : vn[2] + 1)); } else { fprintf(outf, "{**VAR-%02X**}", vn[1]); } } } static unsigned int byte_at(const unsigned char *data, unsigned int length, unsigned int offset) { if (offset >= length) { fprintf(stderr, "Input file corrupted (offset %x out of bounds)\n", offset); return 0; } return data[offset]; } static unsigned int word_at(const unsigned char *data, unsigned int length, unsigned int offset) { if (offset + 1 >= length) { fprintf(stderr, "Input file corrupted (offset %x out of bounds)\n", offset + 1); return 0; } return (data[offset] | (data[offset + 1] << 8)); } static const char * const segment_names[] = { "HEADER", "CODE", "DATA", "FOOTER" }; static const char * const special_mnemonics[] = { "align", "assert", "ds", "db", "else", "endif", "if", "ifdef", "ifndef", "org", "rorg", "word" }; static void export_asm_file_section(FILE *outf, const unsigned char *data, unsigned int length, unsigned int stabpos, unsigned int nsymbols, char **symbols) { unsigned int type, datastart, dataend, itype, ilength, j, k, l; unsigned char instr[65]; int argexprs[4]; const char *mnemonic; const unsigned char *template; char buf[16]; char *s; type = byte_at(data, length, stabpos + SECTHEADER_SECTION_TYPE); datastart = word_at(data, length, stabpos + SECTHEADER_DATA_START); dataend = word_at(data, length, stabpos + SECTHEADER_DATA_END); for (j = 0; j < 8; j++) buf[j] = byte_at(data, length, stabpos + SECTHEADER_NAME + j); buf[8] = 0; s = ti83p_to_ascii(buf); fprintf(outf, ";#SECTION \"%s\", %s%s\n\n", s, (type & 0x80 ? "DISABLED_" : ""), segment_names[type & 3]); xfree(s); j = datastart; while (j < dataend && j < length) { instr[0] = byte_at(data, length, j); itype = instr[0] & 0xc0; ilength = (instr[0] & 0x3f) + 2; for (k = 1; k < ilength; k++) instr[k] = byte_at(data, length, j + k); argexprs[0] = 2; for (k = 0; k < 3; k++) argexprs[k + 1] = argexprs[k] + expr_length(instr + argexprs[k], ilength - argexprs[k]); switch (itype) { case T_NORMAL: mnemonic = normal_mnemonics[instr[1]]; template = normal_templates[instr[1]]; print_mnemonic(outf, mnemonic); print_template(outf, template, instr, argexprs, nsymbols, symbols); if (instr[1] == I_RET || instr[1] == I_RETI || instr[1] == I_RETN || instr[1] == I_JP_iHL || instr[1] == I_JP_iIX || instr[1] == I_JP_iIY || instr[1] == I_JP_n || instr[1] == I_JR_n) fprintf(outf, "\n"); break; case T_LABEL: print_expr(outf, instr + 1, ilength - 1, 1, 0, NULL, NULL, nsymbols, symbols); print_label_suffix(outf); break; case T_COMMENT: s = convert_comment(instr + 1, ilength - 1); print_comment(outf, s); xfree(s); break; case T_SPECIAL: switch (instr[1]) { case S_ASCII: case S_ASCIZ: print_mnemonic(outf, "db"); print_argstart(outf); fprintf(outf, "\""); for (k = 2; k < ilength; k++) print_quoted_char(outf, instr[k], '"'); fprintf(outf, "\""); if (instr[1] == S_ASCIZ) { print_argsep(outf); fprintf(outf, "0"); } break; case S_HEX: print_mnemonic(outf, "db"); for (k = 2; k < ilength; k++) { if (k > 2) print_argsep(outf); else print_argstart(outf); print_hex(outf, instr[k], 2); } break; case S_INCBIN: print_mnemonic(outf, "incbin"); print_argstart(outf); print_var_name(outf, instr + 2, ilength - 2); break; case S_BCALL: case S_BJUMP: print_mnemonic(outf, instr[1] == S_BCALL ? "B_CALL" : "B_JUMP"); print_template(outf, templ__n, instr, argexprs, nsymbols, symbols); if (instr[1] == S_BJUMP) fprintf(outf, "\n"); break; case S_BREAK: print_mnemonic(outf, "break"); break; case S_BREAK_ccc: print_mnemonic(outf, "break"); print_template(outf, templ__ccc, instr, argexprs, nsymbols, symbols); break; case S_EQU: print_expr(outf, instr + argexprs[0], argexprs[1] - argexprs[0], 1, 0, NULL, NULL, nsymbols, symbols); fprintf(outf, " "); print_mnemonic_noindent(outf, "equ"); print_argstart(outf); print_expr(outf, instr + argexprs[1], argexprs[2] - argexprs[1], 0, 0, NULL, NULL, nsymbols, symbols); break; case S_JQ_n: print_mnemonic(outf, "jq"); print_template(outf, templ__n, instr, argexprs, nsymbols, symbols); fprintf(outf, "\n"); break; case S_JQ_cc_n: print_mnemonic(outf, "jq"); print_template(outf, templ__cc_n, instr, argexprs, nsymbols, symbols); break; default: if (instr[1] >= S_ALIGN && instr[1] <= S_WORD) print_mnemonic(outf, special_mnemonics[instr[1] - S_ALIGN]); else { sprintf(buf, "##SPECIAL-%02X##", instr[1]); print_mnemonic(outf, buf); } k = 2; while (k < ilength) { if (k > 2) print_argsep(outf); else print_argstart(outf); l = expr_length(instr + k, ilength - k); print_expr(outf, instr + k, l, 0, 0, NULL, NULL, nsymbols, symbols); k += l; } break; } break; } fprintf(outf, "\n"); j += ilength; } } static void export_asm_file(FILE *outf, const unsigned char *data, unsigned int length) { char **symbols; unsigned int symstart, symend, strstart, strend, conststart, constend, impstart, impend, sectstart, sectend, nsymbols, i, j, rc, v; char *s; symstart = word_at(data, length, PROGHEADER_SYMBOL_START); symend = word_at(data, length, PROGHEADER_SYMBOL_END); strstart = word_at(data, length, PROGHEADER_SYMBOL_STRING_START); strend = word_at(data, length, PROGHEADER_SYMBOL_STRING_END); if (symstart >= symend || strstart >= strend) { nsymbols = 0; symbols = NULL; } else { nsymbols = (symend - symstart) / 3; symbols = xnew(char*, nsymbols); for (i = 0; i < nsymbols; i++) { j = strstart + word_at(data, length, symstart + 3 * i); rc = byte_at(data, length, symstart + 3 * i + 2); if (rc) symbols[i] = convert_symbol(data + j, strend - j); else symbols[i] = NULL; } } conststart = word_at(data, length, PROGHEADER_CONSTANT_START); constend = word_at(data, length, PROGHEADER_CONSTANT_END); if (conststart != constend) { fprintf(outf, ";#CONSTANTS\n\n"); i = conststart + 3; while (i + 2 < constend) { v = word_at(data, length, i); s = convert_symbol(data + i + 2, constend - i - 2); i += 2 + symbol_length(data + i + 2, constend - i - 2); fprintf(outf, "%-32s ", s); print_mnemonic_noindent(outf, "equ"); print_argstart(outf); print_hex(outf, v, 4); fprintf(outf, "\n"); xfree(s); } fprintf(outf, "\n"); } sectstart = word_at(data, length, PROGHEADER_SECTION_TABLE_START); sectend = word_at(data, length, PROGHEADER_SECTION_TABLE_END); for (i = sectstart; i < sectend; i += SECTHEADER_LENGTH) if (!(byte_at(data, length, i + SECTHEADER_SECTION_TYPE) & 0x7f)) export_asm_file_section(outf, data, length, i, nsymbols, symbols); for (i = sectstart; i < sectend; i += SECTHEADER_LENGTH) if ((byte_at(data, length, i + SECTHEADER_SECTION_TYPE) & 0x7f)) export_asm_file_section(outf, data, length, i, nsymbols, symbols); for (i = 0; i < nsymbols; i++) xfree(symbols[i]); xfree(symbols); impstart = word_at(data, length, PROGHEADER_IMPORT_START); impend = word_at(data, length, PROGHEADER_IMPORT_END); if (impend > length) impend = length; for (i = impstart; i + 9 <= impend; i += 9) { fprintf(outf, ";#IMPORT "); print_var_name(outf, data + i, 9); fprintf(outf, "\n"); } } static int read_word(FILE* f) { unsigned char b[2]; if (fread(b, 1, 2, f) != 2) return -1; else return (b[0] | (b[1] << 8)); } static const char usage[] = "Usage: %s [-o asm-file] 8xv-file ...\n"; static int checkarg(int argc, char **argv, int *pos, char shortopt, const char *longopt, const char **arg) { const char *a; if (*pos >= argc || argv[*pos][0] != '-') return 0; if (shortopt && argv[*pos][1] == shortopt) a = argv[*pos][2] ? &argv[*pos][2] : NULL; else if (argv[*pos][1] != '-') return 0; else if (longopt && !strcasecmp(&argv[*pos][2], longopt)) a = NULL; else if (longopt && !strncasecmp(&argv[*pos][2], longopt, strlen(longopt)) && argv[*pos][2 + strlen(longopt)] == '=') a = &argv[*pos][3 + strlen(longopt)]; else return 0; if (!arg) return 1; else if (a) { *arg = a; return 1; } else { (*pos)++; if (*pos >= argc) { fprintf(stderr, "%s: %s: requires an argument\n", argv[0], argv[*pos - 1]); exit(1); } else { *arg = argv[*pos]; argv[*pos] = NULL; return 1; } } } int main(int argc, char **argv) { const char *outfilename = NULL, *arg; const char *infilename; FILE *inf; FILE *outf; unsigned char hdr[53]; unsigned char *vh = NULL, *data = NULL; int content_length, vh_length, var_length; int i, var_ok; if (argc < 2) { fprintf(stderr, usage, argv[0]); return 1; } for (i = 1; i < argc; i++) { if (argv[i][0] == '-' && argv[i][1]) { if (checkarg(argc, argv, &i, 'o', "output", &arg)) outfilename = arg; else if (checkarg(argc, argv, &i, 0, "help", NULL)) { printf(usage, argv[0]); return 0; } else if (checkarg(argc, argv, &i, 0, "version", NULL)) { printf("8xvtoasm (Mimas %s)\n" "Copyright (C) 2010 Benjamin Moody\n" "This program is free software. " "There is NO WARRANTY of any kind.\n", PACKAGE_VERSION); return 0; } else { 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, "wt"); if (!outf) { perror(outfilename); return 4; } } else outf = stdout; for (i = 1; i < argc; i++) { if (!argv[i] || (argv[i][0] == '-' && argv[i][1])) continue; else if (argv[i][0] == '-') { inf = stdin; infilename = "standard input"; } else { infilename = argv[i]; inf = fopen(infilename, "rb"); if (!inf) { perror(infilename); fclose(outf); return 2; } } if (fread(hdr, 1, 53, inf) != 53 || strncmp((char*) hdr, "**TI83F*", 8)) { fprintf(stderr, "%s: not a valid 8xv file\n", infilename); if (outf != stdout) fclose(outf); if (inf != stdin) fclose(inf); return 2; } content_length = read_word(inf); var_ok = 0; while (content_length > 0) { if ((vh_length = read_word(inf)) == -1 || (int) fread((vh = xnew(unsigned char, vh_length)), 1, vh_length, inf) != vh_length || (var_length = read_word(inf)) == -1 || (int) fread((data = xnew(unsigned char, var_length)), 1, var_length, inf) != var_length) { xfree(vh); xfree(data); fprintf(stderr, "%s: unexpected EOF\n", infilename); if (outf != stdout) fclose(outf); if (inf != stdin) fclose(inf); return 2; } if (var_length > PROGHEADER_LENGTH + 2 //&& (vh[2] & 0x1f) == 0x15 && !strncmp((char*) data + 2, "MimS\001", 5)) { export_asm_file(outf, data + 2, var_length - 2); var_ok = 1; } xfree(vh); xfree(data); vh = data = NULL; content_length -= 2 + vh_length + 2 + var_length; } if (inf != stdin) fclose(inf); if (!var_ok) { fprintf(stderr, "%s: not a valid Mimas source file\n", infilename); if (outf != stdout) fclose(outf); return 2; } } if (outf != stdout) fclose(outf); return 0; }