/*
ascii2map - Simple ASCII map converter aimed at retro code
Copyright (C) 2003-2015 Ian Cowburn (ianc@noddybox.co.uk)
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 .
-------------------------------------------------------------------------
Main
*/
#include
#include
#include
/* ---------------------------------------- VERSION INFO
*/
static const char *usage =
"Version 0.2\n"
"\n"
"This program is distributed in the hope that it will be useful,\n"
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
"GNU General Public License (Version 3) for more details.\n"
"\n"
"usage: ascii2map [-a|-b|-c] [-d directive] [input-file [output-file]]\n";
/* ---------------------------------------- TYPES
*/
typedef unsigned char uchar;
typedef enum
{
Assembly,
Binary,
CSource
} Mode;
/* ---------------------------------------- GLOBALS
*/
static int code_point = 'A';
static uchar point[256];
static uchar used[256];
static const char *directive = "byte";
static Mode mode = Assembly;
/* ---------------------------------------- PRIVATE FUNCTIONS
*/
static void Chomp(char *p)
{
size_t l = strlen(p);
while(l && (p[l-1] == '\n' || p[l-1] == '\r'))
{
p[--l] = 0;
}
}
static void StartOutput(FILE *fp)
{
switch(mode)
{
case CSource:
fprintf(fp, "int map[] =\n{\n");
break;
default:
break;
}
}
static void EndOutput(FILE *fp)
{
switch(mode)
{
case Assembly:
fprintf(fp, "\n");
break;
case CSource:
fprintf(fp, "\n};\n");
break;
default:
break;
}
}
static unsigned CodePoint(char c)
{
int offset = c - code_point;
if (offset < 0)
{
offset = 0;
}
if (offset > 255)
{
offset = 255;
}
return (unsigned)offset;
}
static void Output(FILE *fp, char c)
{
static int column;
static int first = 1;
if (c < 0 || c > 255)
{
return;
}
switch(mode)
{
case Assembly:
if (column == 0)
{
if (!first)
{
fprintf(fp, "\n");
}
fprintf(fp, "\t%s\t", directive);
}
else
{
fprintf(fp, ", ");
}
if (used[c])
{
fprintf(fp, "%u", point[c]);
}
else
{
fprintf(fp, "%u", CodePoint(c));
}
break;
case Binary:
if (used[c])
{
putc(point[c], fp);
}
else
{
putc(CodePoint(c), fp);
}
break;
case CSource:
if (!first)
{
fprintf(fp, ", ");
}
if (column == 0)
{
if (!first)
{
fprintf(fp, "\n");
}
fprintf(fp, "\t");
}
if (used[c])
{
fprintf(fp, "%u", point[c]);
}
else
{
fprintf(fp, "%u", CodePoint(c));
}
break;
}
column = (column + 1) % 8;
if (first)
{
first = 0;
}
}
/* ---------------------------------------- MAIN
*/
int main(int argc, char *argv[])
{
FILE *in;
FILE *out;
char line[1024];
int f;
int in_map = 0;
size_t len = 0;
int warned = 0;
f = 1;
/* Process switches
*/
while(argv[f] && argv[f][0] == '-')
{
int handled = 1;
switch(argv[f][1])
{
case 'a':
mode = Assembly;
break;
case 'b':
mode = Binary;
break;
case 'c':
mode = CSource;
break;
case 'd':
if (argv[f+1])
{
directive = argv[++f];
}
else
{
handled = 0;
}
break;
default:
handled = 0;
break;
}
if (!handled)
{
fprintf(stderr,"%s\n", usage);
exit(EXIT_FAILURE);
}
f++;
}
/* Handle file args
*/
if (argv[f])
{
in = fopen(argv[f], "r");
if (!in)
{
fprintf(stderr,"Failed to open %s\n", argv[f]);
exit(EXIT_FAILURE);
}
f++;
}
else
{
in = stdin;
}
if (argv[f])
{
if (mode == Binary)
{
out = fopen(argv[f], "wb");
}
else
{
out = fopen(argv[f], "w");
}
if (!in)
{
fprintf(stderr,"Failed to open %s\n", argv[f]);
exit(EXIT_FAILURE);
}
}
else
{
out = stdout;
}
/* Process input
*/
used[' '] = 1;
while(fgets(line, sizeof line, in))
{
Chomp(line);
if (in_map)
{
char *p;
if (len == 0)
{
len = strlen(line);
}
else
{
if (!warned && len != strlen(line))
{
fprintf(stderr, "WARNING: Lines of different length\n");
warned = 1;
}
}
p = line;
while(*p)
{
Output(out, *p++);
}
}
else
{
if (strcmp(line, "~") == 0)
{
StartOutput(out);
in_map = 1;
}
if (line[0] == '!')
{
code_point = atoi(line + 1);
}
if (line[0] && line[1] == ':' && line[2])
{
char c;
int i;
c = line[0];
i = atoi(line + 2);
if (c >= 0 && c <= 255)
{
point[c] = i;
used[c] = 1;
}
}
}
}
EndOutput(out);
return EXIT_SUCCESS;
}
/*
vim: ai sw=4 ts=8 expandtab
*/