/*
* 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;
}