/* -*-c-*-
*
- * $Id: bascat.c,v 1.1 1998/03/16 15:21:37 mdw Exp $
+ * $Id$
*
* Display BBC BASIC programs more or less anywhere
*
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-/*----- Revision history --------------------------------------------------*
- *
- * $Log: bascat.c,v $
- * Revision 1.1 1998/03/16 15:21:37 mdw
- * Files placed under CVS control.
- *
- * Revision 1.1 1997/07/23 01:19:33 mdw
- * Initial revision
- *
- */
-
/*----- Header files ------------------------------------------------------*/
/* --- ANSI library headers --- */
/*----- Version information -----------------------------------------------*/
-#ifndef NDEBUG
+#ifdef DEBUG
# define D(x) x
#else
# define D(x)
* carried out on an A440 with RISC OS 3.1
*/
-static const char *bcTok__base[] = {
+static const char *tok_base[] = {
"OTHERWISE",
"AND", "DIV", "EOR", "MOD", "OR", "ERROR", "LINE", "OFF",
"STEP", "SPC", "TAB(", "ELSE", "THEN", "*", "OPENIN", "PTR",
"RETURN", "RUN", "STOP", "COLOUR", "TRACE", "UNTIL", "WIDTH", "OSCLI"
};
-static const char *bcTok__c6[] = {
+static const char *tok_c6[] = {
"SUM", "BEAT"
};
-static const char *bcTok__c7[] = {
+static const char *tok_c7[] = {
"APPEND", "AUTO",
"CRUNCH", "DELETE", "EDIT", "HELP", "LIST", "LOAD", "LVAR", "NEW",
"OLD", "RENUMBER", "SAVE", "TEXTLOAD", "TEXTSAVE", "TWIN", "TWINO",
"INSTALL"
};
-static const char *bcTok__c8[] = {
+static const char *tok_c8[] = {
"CASE", "CIRCLE",
"FILL", "ORIGIN", "POINT", "RECTANGLE", "SWAP", "WHILE", "WAIT", "MOUSE",
"QUIT", "SYS", "INSTALL", "LIBRARY", "TINT", "ELLIPSE", "BEATS", "TEMPO",
s_comment, /* In a command (or literal *cmd) */
s_quote, /* Inside a quoted string */
s_c6, s_c7, s_c8, /* Various shift states */
+ s_linex, s_liney, s_linez, /* Line number states */
s_dummy
};
-static bc__state = s_normal; /* Current detokenisation state */
+static int state = s_normal; /* Current detokenisation state */
+static unsigned int lineno; /* Line number */
enum {
f_highlight = 1, /* Highlight keywords and things */
f_dummy
};
-static int bc__flags; /* Various options flags */
+static int flags; /* Various options flags */
#ifdef HAVE_LIBTERMCAP
-static char bc__termcap[2048]; /* Terminal capabilities buffer */
+static char termcap[2048]; /* Terminal capabilities buffer */
#endif
-static char *bc__pager = 0; /* Pointer to pager to use */
+static char *pager = 0; /* Pointer to pager to use */
/*----- Main code ---------------------------------------------------------*/
return (1);
}
-/* --- @bc__keyword@ --- *
+/* --- @keyword@ --- *
*
* Arguments: @char *s@ = pointer to keyword string
* @FILE *fp@ = stream to write onto
* characters. What fun...
*/
-static void bc__keyword(const char *s, FILE *fp)
+static void keyword(const char *s, FILE *fp)
{
#ifdef HAVE_LIBTERMCAP
- if ((~bc__flags & (f_less | f_highlight)) == 0) {
+ if ((~flags & (f_less | f_highlight)) == 0) {
while (*s) {
putc(*s, fp);
- putc(8, fp); /* evil... */
+ putc('\b', fp);
putc(*s, fp);
s++;
}
static char *hs, *he, *p = buff;
if (!hs) {
- if (bc__flags & f_highlight) {
+ if (flags & f_highlight) {
hs = tgetstr("md", &p);
he = tgetstr("me", &p);
} else
#endif
}
-/* --- @bc__mbtok@ --- *
+/* --- @mbtok@ --- *
*
* Arguments: @int byte@ = the current byte
* @const char *t[]@ = pointer to token table
* Use: Decodes multibyte tokens.
*/
-static int bc__mbtok(int byte, const char *t[], int n, FILE * fp)
+static int mbtok(int byte, const char *t[], int n, FILE *fp)
{
byte -= 0x8E;
if (byte >= n)
return (die("Bad program: invalid multibyte token"));
- bc__keyword(t[byte], fp);
- bc__state = s_normal;
+ keyword(t[byte], fp);
+ state = s_normal;
return (0);
}
-/* --- @bc__decode@ --- *
+/* --- @decode@ --- *
*
* Arguments: @int byte@ = byte to decode
* @FILE *fp@ = stream to write onto
* Use: Decodes a byte, changing states as necessary.
*/
-static int bc__decode(int byte, FILE * fp)
+static int decode(int byte, FILE *fp)
{
- switch (bc__state) {
+ switch (state) {
+
+ /* --- Tokenised states --- */
+
case s_keyword:
if (byte == '*')
- bc__state = s_comment;
+ state = s_comment;
else
- bc__state = s_normal;
+ state = s_normal;
/* Fall through here */
+
case s_normal:
if (byte >= 0x7F) {
switch (byte) {
case 0xC6:
- bc__state = s_c6;
+ state = s_c6;
break;
case 0xC7:
- bc__state = s_c7;
+ state = s_c7;
break;
case 0xC8:
- bc__state = s_c8;
+ state = s_c8;
+ break;
+ case 0x8D:
+ state = s_linex;
break;
case 0x8B: /* ELSE */
case 0x8C: /* THEN */
case 0xF5: /* REPEAT (a funny one) */
- bc__state = s_keyword;
- bc__keyword(bcTok__base[byte - 0x7F], fp);
+ state = s_keyword;
+ goto keyword;
break;
case 0xDC: /* DATA */
case 0xF4: /* REM */
- bc__state = s_comment;
+ state = s_comment;
/* Fall through here */
default:
- bc__keyword(bcTok__base[byte - 0x7F], fp);
+ keyword:
+ keyword(tok_base[byte - 0x7F], fp);
break;
}
} else {
if (byte == '"')
- bc__state = s_quote;
+ state = s_quote;
fputc(byte, fp);
}
break;
+
+ /* --- Non-tokenised states --- */
+
case s_quote:
if (byte == '"')
- bc__state = s_normal;
+ state = s_normal;
/* Fall through here */
+
case s_comment:
fputc(byte, fp);
break;
+
+ /* --- Double-byte token states --- */
+
case s_c6:
- return (bc__mbtok(byte, bcTok__c6, ITEMS(bcTok__c6), fp));
+ return (mbtok(byte, tok_c6, ITEMS(tok_c6), fp));
break;
+
case s_c7:
- return (bc__mbtok(byte, bcTok__c7, ITEMS(bcTok__c7), fp));
+ return (mbtok(byte, tok_c7, ITEMS(tok_c7), fp));
break;
+
case s_c8:
- return (bc__mbtok(byte, bcTok__c8, ITEMS(bcTok__c8), fp));
+ return (mbtok(byte, tok_c8, ITEMS(tok_c8), fp));
+ break;
+
+ /* --- Encoded line number states --- */
+
+ case s_linex:
+ byte ^= 0x54;
+ lineno = (((byte & 0x30) << 2) |
+ ((byte & 0x0c) << 12) |
+ ((byte & 0x03) << 16));
+ state++;
+ break;
+
+ case s_liney:
+ lineno |= byte & 0x3f;
+ state++;
break;
+
+ case s_linez:
+ lineno |= (byte & 0x3f) << 8;
+ fprintf(fp, "%u", lineno);
+ state = s_normal;
+ break;
+
}
return (0);
}
-/* --- @bc__line@ --- *
+/* --- @line@ --- *
*
* Arguments: @FILE *in@ = input stream to read
* @FILE *out@ = output stream to write
* Use: Decodes a BASIC line into stuff to be written.
*/
-static int bc__line(FILE *in, FILE *out)
+static int line(FILE *in, FILE *out)
{
/* --- Read the line number --- */
if (b == EOF)
goto eof;
- if (bc__flags & f_linenumbers)
+ if (flags & f_linenumbers)
fprintf(out, "%5i", (a << 8) + b);
}
goto eof;
len -= 4;
- bc__state = s_normal;
+ state = s_keyword;
while (len) {
byte = getc(in);
- D( fprintf(stderr, "state == %i, byte == %i\n", \
- bc__state, byte); )
+ D( fprintf(stderr, "state == %i, byte == %i\n",
+ state, byte); )
if (byte == EOF)
goto eof;
- bc__decode(byte, out);
+ decode(byte, out);
len--;
}
putc('\n', out);
return (die("Bad program: unexpected end-of-file"));
}
-/* --- @bc__file@ --- *
+/* --- @file@ --- *
*
* Arguments: @FILE *in@ = the input stream
* @FILE *out@ = the output stream
* Use: Decodes an entire file.
*/
-static void bc__file(FILE *in, FILE *out)
+static void file(FILE *in, FILE *out)
{
int byte;
/* --- Now read the lines in one by one --- */
- while (!bc__line(in, out)) ;
+ while (!line(in, out)) ;
/* --- Check that we're really at end-of-file --- */
die("Found data after end of program");
}
-/* --- @bc__sigPipe@ --- *
+/* --- @sig_pipe@ --- *
*
* Arguments: @int s@ = signal number
*
* Use: Handles SIGPIPE signals, and gracefully kills the program.
*/
-static void bc__sigPipe(int s)
+static void sig_pipe(int s)
{
(void) s;
exit(0); /* Gracefully, oh yes */
}
-/* --- @bc__options@ --- *
+/* --- @options@ --- *
*
* Arguments: @int c@ = number of arguments
* @char *v[]@ = pointer to arguments
* Use: Parses lots of arguments.
*/
-static void bc__options(int c, char *v[], const char *s,
+static void options(int c, char *v[], const char *s,
const struct option *o)
{
int i;
for (;;) {
- i = mdwopt(c, v, s, o, 0, 0, gFlag_negation | gFlag_envVar);
+ i = mdwopt(c, v, s, o, 0, 0, OPTF_NEGATION | OPTF_ENVVAR);
if (i == -1)
break;
switch (i) {
case 'v':
case 'h':
- printf("%s v. " VERSION " (" __DATE__ ")\n", optprog);
+ printf("%s version " VERSION "\n", optprog);
if (i == 'v')
exit(0);
printf("\n"
exit(0);
break;
case 'n':
- bc__flags |= f_linenumbers;
+ flags |= f_linenumbers;
break;
- case 'n' | gFlag_negated:
- bc__flags &= ~f_linenumbers;
+ case 'n' | OPTF_NEGATED:
+ flags &= ~f_linenumbers;
break;
case 'l':
- bc__flags |= f_highlight;
+ flags |= f_highlight;
break;
- case 'l' | gFlag_negated:
- bc__flags &= ~f_highlight;
+ case 'l' | OPTF_NEGATED:
+ flags &= ~f_highlight;
break;
case 'p':
- bc__pager = optarg;
+ pager = optarg;
break;
}
}
int main(int argc, char *argv[])
{
static struct option opts[] = {
- { "help", 0, 0, 'h' },
- { "version", 0, 0, 'v' },
- { "line-numbers", gFlag_negate, 0, 'n' },
- { "highlight", gFlag_negate, 0, 'l' },
- { "pager", gFlag_argReq, 0, 'p' },
- { 0, 0, 0, 0 }
+ { "help", 0, 0, 'h' },
+ { "version", 0, 0, 'v' },
+ { "line-numbers", OPTF_NEGATE, 0, 'n' },
+ { "highlight", OPTF_NEGATE, 0, 'l' },
+ { "pager", OPTF_ARGREQ, 0, 'p' },
+ { 0, 0, 0, 0 }
};
static char *shortopts = "hvn+l+p:";
/* --- Parse the command line options --- */
- bc__options(argc, argv, shortopts, opts);
+ options(argc, argv, shortopts, opts);
/* --- Now do the job --- */
}
#ifdef HAVE_LIBTERMCAP
- if (bc__flags & f_highlight)
- tgetent(bc__termcap, getenv("TERM"));
+ if (flags & f_highlight)
+ tgetent(termcap, getenv("TERM"));
#endif
{
*/
if (isatty(1)) {
- if (!bc__pager)
- bc__pager = getenv("PAGER");
- if (!bc__pager)
- bc__pager = PAGER; /* Worth a try */
- if (strstr(bc__pager, "less"))
- bc__flags |= f_less; /* HACK!!! */
- out = popen(bc__pager, "w");
+ if (!pager)
+ pager = getenv("PAGER");
+ if (!pager)
+ pager = PAGER; /* Worth a try */
+ if (strstr(pager, "less"))
+ flags |= f_less; /* HACK!!! */
+ out = popen(pager, "w");
if (!out)
out = stdout;
else {
- bc__flags |= f_tty;
- signal(SIGPIPE, bc__sigPipe);
+ flags |= f_tty;
+ signal(SIGPIPE, sig_pipe);
}
} else
out = stdout;
/* --- Now go through all the files --- */
if (optind == argc)
- bc__file(stdin, out);
+ file(stdin, out);
else
while (optind < argc) {
if (strcmp(argv[optind], "-") == 0)
- bc__file(stdin, out);
+ file(stdin, out);
else {
in = fopen(argv[optind], "rb");
if (!in) {
"%s: Couldn't open input file: %s\n",
optprog, strerror(errno));
} else {
- bc__file(in, out);
+ file(in, out);
fclose(in);
}
}
optind++;
}
- if (bc__flags & f_tty)
+ if (flags & f_tty)
pclose(out);
}