/* * 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 "pack.h" #include "output.h" #include "utils.h" typedef struct _predef_symbol { char *name; unsigned int value; } predef_symbol; static int parse_line(const char *line, char **name, unsigned int *value) { const char *p, *q, *r; char *e; p = line; while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '_') p++; if (p == line || (*line >= '0' && *line <= '9')) return 1; q = p; while (*q == ' ' || *q == '\t') q++; if (*q == '=') q++; else if (!strncasecmp(q, "equ", 3)) q += 3; else if (!strncasecmp(q, ".equ", 4)) q += 4; else return 1; while (*q == ' ' || *q == '\t') q++; r = q; while (*r && *r != ' ' && *r != '\t' && *r != '\n' && *r != '\r') r++; if (*q == '$') { *value = strtol(q + 1, &e, 16); q = e; } else if (*q == '%') { *value = strtol(q + 1, &e, 2); q = e; } else if (r != q && (r[-1] == 'h' || r[-1] == 'H')) { *value = strtol(q, &e, 16); q = e + 1; } else if (r != q && (r[-1] == 'b' || r[-1] == 'B')) { *value = strtol(q, &e, 2); q = e + 1; } else if (*q >= '0' && *q <= '9') { *value = strtol(q, &e, 10); q = e; } else return 1; if (q != r) return 1; while (*q == ' ' || *q == '\t') q++; if (*q != 0 && *q != '\n' && *q != '\r') return 1; *name = xstrndup(line, p - line); return 0; } static int map_char(char c) { if (c == 0) return 0; else if (c == '_') return 1; else if (c >= 'a' && c <= 'z') return c - 'a' + 'A'; else return c; } static int compare_syms(const void *a, const void *b) { const predef_symbol *sa = a; const predef_symbol *sb = b; int i, ka, kb; for (i = 0; sa->name[i] || sb->name[i]; i++) { ka = map_char(sa->name[i]); kb = map_char(sb->name[i]); if (ka != kb) return (ka - kb); } return strcmp(sa->name, sb->name); } static const char usage[] = "Usage: %s [-o 8xv-file] [-n name] inc-file\n"; int main(int argc, char **argv) { const char *infilename = NULL; char *outfilename = NULL; char *varname = NULL; FILE *inf, *outf; char *p, *line; int linenum = 0; char *name = NULL; unsigned int value; predef_symbol *symbols = NULL; int nsymbols = 0, nsymbols_a = 0; ti8x_file *f; ti8x_var_entry *v; unsigned int symstart, stringstart, conststart, impstart, sectstart, sectend; unsigned char buf[3]; unsigned char *packed; int packedlen; int status = 0; int i; for (i = 1; i < argc; i++) { if (argv[i][0] == '-' && argv[i][1]) { if (argv[i][1] == 'o') { if (argv[i][2]) outfilename = xstrdup(&argv[i][2]); else if (++i < argc) outfilename = xstrdup(argv[i]); else { fprintf(stderr, "%s: -o: requires argument\n", argv[0]); return 1; } } else if (argv[i][1] == 'n') { if (argv[i][2]) varname = xstrdup(&argv[i][2]); else if (++i < argc) varname = xstrdup(argv[i]); else { fprintf(stderr, "%s: -n: requires argument\n", argv[0]); return 1; } } else { fprintf(stderr, "%s: unknown option %s\n", argv[0], argv[i]); fprintf(stderr, usage, argv[0]); return 1; } } else { infilename = argv[i]; } } if (!infilename) { fprintf(stderr, usage, argv[0]); return 1; } if (!varname) { if (!strcmp(infilename, "-")) varname = xstrdup("OUT"); else if ((p = strrchr(infilename, '/')) || (p = strrchr(infilename, '\\'))) varname = xstrdup(p + 1); else varname = xstrdup(infilename); if ((p = strrchr(varname, '.'))) *p = 0; for (i = 0; varname[i]; i++) if (varname[i] >= 'a' && varname[i] <= 'z') varname[i] += 'A' - 'a'; } if (!outfilename) { outfilename = xnew(char, strlen(varname) + 5); strcpy(outfilename, varname); strcat(outfilename, ".8xv"); } if (!strcmp(infilename, "-")) { inf = stdin; } else { inf = fopen(infilename, "rt"); if (!inf) { perror(infilename); return 2; } } while ((line = read_line(inf))) { linenum++; if ((p = strchr(line, ';'))) *p = 0; if (*line == 0 || *line == '\n' || *line == '\r') continue; if (parse_line(line, &name, &value)) { fprintf(stderr, "%s:%d: syntax error\n", infilename, linenum); status = 3; continue; } if (nsymbols >= nsymbols_a) { nsymbols_a = nsymbols + 100; symbols = xrenew(predef_symbol, symbols, nsymbols_a); } symbols[nsymbols].name = name; symbols[nsymbols].value = value; nsymbols++; } if (inf != stdin) fclose(inf); if (!nsymbols) { fprintf(stderr, "input file empty\n"); return 3; } if (!strcmp(outfilename, "-")) outf = stdout; else { outf = fopen(outfilename, "wb"); if (!outf) { perror(outfilename); return 4; } } qsort(symbols, nsymbols, sizeof(predef_symbol), &compare_syms); f = ti8x_file_new(outfilename); v = ti8x_file_add_var(f, 0x15, varname, 1); ti8x_var_append_data(v, NULL, 2 + PROGHEADER_LENGTH); symstart = stringstart = v->length - 2; ti8x_var_append_data(v, NULL, 1); conststart = v->length - 2; /* sentinel */ buf[0] = 1; buf[1] = 1; buf[2] = 0; ti8x_var_append_data(v, buf, 3); for (i = 0; i < nsymbols; i++) { pack_symbol_string(&packed, &packedlen, symbols[i].name); if (packedlen >= 3) { buf[0] = symbols[i].value; buf[1] = symbols[i].value >> 8; ti8x_var_append_data(v, buf, 2); ti8x_var_append_data(v, packed, packedlen); } else { fprintf(stderr, "symbol '%s' is too short\n", symbols[i].name); } xfree(packed); } impstart = sectstart = sectend = v->length - 2; memcpy(v->data + 2, "MimS\1", 5); v->data[2 + PROGHEADER_TYPE] = PROGTYPE_TI83P; v->data[2 + PROGHEADER_FLAGS] = PROGFLAG_LOCKED; v->data[2 + PROGHEADER_SYMBOL_START] = symstart; v->data[2 + PROGHEADER_SYMBOL_START + 1] = symstart >> 8; v->data[2 + PROGHEADER_SYMBOL_STRING_START] = stringstart; v->data[2 + PROGHEADER_SYMBOL_STRING_START + 1] = stringstart >> 8; v->data[2 + PROGHEADER_CONSTANT_START] = conststart; v->data[2 + PROGHEADER_CONSTANT_START + 1] = conststart >> 8; v->data[2 + PROGHEADER_IMPORT_START] = impstart; v->data[2 + PROGHEADER_IMPORT_START + 1] = impstart >> 8; v->data[2 + PROGHEADER_SECTION_TABLE_START] = sectstart; v->data[2 + PROGHEADER_SECTION_TABLE_START + 1] = sectstart >> 8; v->data[2 + PROGHEADER_SECTION_TABLE_END] = sectend; v->data[2 + PROGHEADER_SECTION_TABLE_END + 1] = sectend >> 8; v->data[0] = v->length - 2; v->data[1] = (v->length - 2) >> 8; if (ti8x_file_write(outf, f)) { if (outf != stdout) fclose(outf); return 4; } if (outf != stdout) fclose(outf); ti8x_file_free(f); xfree(outfilename); xfree(varname); for (i = 0; i < nsymbols; i++) xfree(symbols[i].name); xfree(symbols); return status; }