From: mdw Date: Mon, 16 Mar 1998 15:21:37 +0000 (+0000) Subject: Files placed under CVS control. X-Git-Tag: 1.2pre1~1 X-Git-Url: https://git.distorted.org.uk/~mdw/bascat/commitdiff_plain/0398bb0da0f0984d63f566fdee7484ac4d4182e6?ds=sidebyside Files placed under CVS control. --- 0398bb0da0f0984d63f566fdee7484ac4d4182e6 diff --git a/.links b/.links new file mode 100644 index 0000000..a91aa32 --- /dev/null +++ b/.links @@ -0,0 +1,6 @@ +COPYING +INSTALL +install-sh +mdwopt.c +mdwopt.h +mkinstalldirs diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..decb861 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,8 @@ +Bascat was written by: + Matthew Wilcox + Mark Wooding + +Thanks to, + Olly Betts for a bug report + Mark Rison for testing with OSF/1 + Dickon Hood for general abuse diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..0b2d725 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,20 @@ +1.1.2 Tue Jul 22 1997 + + * Fixed bug in state machine. Bug reported by Olly Betts. + * Add more warning options to the Makefile. + * Change the bcTok__* to be const. + * Update mdwopt to version 1.4 + * Create ChangeLog + +1.1.1 + * slight tidying up to compile better on OSF/1 + +1.1 + * Rewritten by Mark Wooding. + +1.0.x (x up to 3) + * various bug fixes. Lost in the depths of time. ie before I + started keeping a ChangeLog. + +1.0 + * First release version. diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..9323122 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,40 @@ +## Run `automake' on this file to generate `Makefile.in' +## -*-makefile-*- +## +## $Id: Makefile.am,v 1.1 1998/03/16 15:21:36 mdw Exp $ +## +## Makefile for Bascat +## +## (c) 1997 Matthew Wilcox and Mark Wooding +## + +##----- Licensing notice ---------------------------------------------------- +## +## This file is part of Bascat. +## +## Bascat is free software; you can redistribute it and/or modify it +## under the terms of the GNU Library General Public License as +## published by the Free Software Foundation; either version 2 of the +## License, or (at your option) any later version. +## +## Bascat 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 Library General Public License for more details. +## +## You should have received a copy of the GNU Library General Public +## License along with Bascat; if not, write to the Free Software Foundation, +## Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +##----- Revision history ---------------------------------------------------- +## +## $Log: Makefile.am,v $ +## Revision 1.1 1998/03/16 15:21:36 mdw +## Files placed under CVS control. +## +## Revision 1.1 1997/07/23 01:18:30 mdw +## Initial revision +## + +bin_PROGRAMS = bascat +bascat_SOURCES = bascat.c mdwopt.c mdwopt.h diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..da8ebc5 --- /dev/null +++ b/NEWS @@ -0,0 +1,8 @@ +New for 1.2 + + I've completely GNUified the package. Well, almost. It now uses + GNU autoconf to configure itself, and GNU automake to build the + Makefile. I've redone the licensing notes on the source files, + and churned the main source file through (GNU) `indent'. + + -- [mdw] diff --git a/README b/README new file mode 100644 index 0000000..608c2ee --- /dev/null +++ b/README @@ -0,0 +1,34 @@ +Bascat 1.1.2 Tue Jul 22 1997 + + +Introduction + +bascat is a program that will convert BBC BASIC files to text. It has +been written and tested on Linux with GCC 2.7.2. It has also been +compiled in the past on IRIX, Solaris and OSF/1. If you try it on any +other system, I'd be grateful for your feedback. + + +Copyright + +Both bascat and mdwopt are covered by the GNU General Public Licence. +As such they come with NO WARRANTY, unless this program has been provided +to you by someone willing to provide you with one. + + +Installation + +This should be fairly simple. Edit the Makefile to set the desired +CFLAGS, and possibly change the name of your C compiler. Type 'make'. +You now have a program called 'bascat'. It has no external files and +does not need to be installed into any particular place. Copy it to +somewhere in your path (/usr/local/bin works great for me. If you're +not privileged to install stuff there, try $HOME/bin) + + +Problems + +Let me know. willy@bofh.ai is my current preferred email address. +Other valid addresses are currently willy@odie.barnet.ac.uk, willy@eh.org, +willy@nsict.org and mrw103@york.ac.uk. I also read newsgroups such as +comp.sys.acorn.programmer. diff --git a/bascat.c b/bascat.c new file mode 100644 index 0000000..2401892 --- /dev/null +++ b/bascat.c @@ -0,0 +1,578 @@ +/* -*-c-*- + * + * $Id: bascat.c,v 1.1 1998/03/16 15:21:37 mdw Exp $ + * + * Display BBC BASIC programs more or less anywhere + * + * (c) 1996, 1997 Matthew Wilcox and Mark Wooding + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of Bascat. + * + * Bascat is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * Bascat 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 Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Bascat; if not, write to the Free Software Foundation, + * 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 --- */ + +#include +#include +#include +#include +#include +#include + +/* --- Operating system specific headers --- */ + +#ifdef HAVE_LIBTERMCAP +# include +#endif +#include + +/* --- Private headers --- */ + +#include "mdwopt.h" + +/*----- Version information -----------------------------------------------*/ + +#ifndef NDEBUG +# define D(x) x +#else +# define D(x) +#endif + +/*----- Tokenisation tables -----------------------------------------------* + * + * These tables are from the BBC BASIC guide. Additional verification + * carried out on an A440 with RISC OS 3.1 + */ + +static const char *bcTok__base[] = { + "OTHERWISE", + "AND", "DIV", "EOR", "MOD", "OR", "ERROR", "LINE", "OFF", + "STEP", "SPC", "TAB(", "ELSE", "THEN", "*", "OPENIN", "PTR", + "PAGE", "TIME", "LOMEM", "HIMEM", "ABS", "ACS", "ADVAL", "ASC", + "ASN", "ATN", "BGET", "COS", "COUNT", "DEG", "ERL", "ERR", + "EVAL", "EXP", "EXT", "FALSE", "FN", "GET", "INKEY", "INSTR(", + "INT", "LEN", "LN", "LOG", "NOT", "OPENUP", "OPENOUT", "PI", + "POINT(", "POS", "RAD", "RND", "SGN", "SIN", "SQR", "TAN", + "TO", "TRUE", "USR", "VAL", "VPOS", "CHR$", "GET$", "INKEY$", + "LEFT$(", "MID$(", "RIGHT$(", "STR$", "STRING$(", "EOF", "*", "*", + "*", "WHEN", "OF", "ENDCASE", "ELSE", "ENDIF", "ENDWHILE", "PTR", + "PAGE", "TIME", "LOMEM", "HIMEM", "SOUND", "BPUT", "CALL", "CHAIN", + "CLEAR", "CLOSE", "CLG", "CLS", "DATA", "DEF", "DIM", "DRAW", + "END", "ENDPROC", "ENVELOPE", "FOR", "GOSUB", "GOTO", "GCOL", "IF", + "INPUT", "LET", "LOCAL", "MODE", "MOVE", "NEXT", "ON", "VDU", + "PLOT", "PRINT", "PROC", "READ", "REM", "REPEAT", "REPORT", "RESTORE", + "RETURN", "RUN", "STOP", "COLOUR", "TRACE", "UNTIL", "WIDTH", "OSCLI" +}; + +static const char *bcTok__c6[] = { + "SUM", "BEAT" +}; + +static const char *bcTok__c7[] = { + "APPEND", "AUTO", + "CRUNCH", "DELETE", "EDIT", "HELP", "LIST", "LOAD", "LVAR", "NEW", + "OLD", "RENUMBER", "SAVE", "TEXTLOAD", "TEXTSAVE", "TWIN", "TWINO", + "INSTALL" +}; + +static const char *bcTok__c8[] = { + "CASE", "CIRCLE", + "FILL", "ORIGIN", "POINT", "RECTANGLE", "SWAP", "WHILE", "WAIT", "MOUSE", + "QUIT", "SYS", "INSTALL", "LIBRARY", "TINT", "ELLIPSE", "BEATS", "TEMPO", + "VOICES", "VOICE", "STEREO", "OVERLAY" +}; + +#define ITEMS(array) (sizeof(array) / sizeof((array)[0])) + +/*----- Static variables --------------------------------------------------*/ + +enum { + s_keyword, /* Expecting a keyword next */ + s_normal, /* Normal state, reading input */ + s_comment, /* In a command (or literal *cmd) */ + s_quote, /* Inside a quoted string */ + s_c6, s_c7, s_c8, /* Various shift states */ + s_dummy +}; + +static bc__state = s_normal; /* Current detokenisation state */ + +enum { + f_highlight = 1, /* Highlight keywords and things */ + f_linenumbers = 2, /* Display linenumbers on left */ + f_tty = 4, /* We're writing to TTY (or pager) */ + f_less = 8, /* We're piping through `less' */ + f_dummy +}; + +static int bc__flags; /* Various options flags */ + +#ifdef HAVE_LIBTERMCAP +static char bc__termcap[2048]; /* Terminal capabilities buffer */ +#endif + +static char *bc__pager = 0; /* Pointer to pager to use */ + +/*----- Main code ---------------------------------------------------------*/ + +/* --- @die@ --- * + * + * Arguments: @char *p@ = pointer to a string + * + * Returns: 1 + * + * Use: Reports an error to the user and falls over flat on its face. + */ + +static int die(const char *p) +{ + fprintf(stderr, "%s: %s\n", optprog, p); + return (1); +} + +/* --- @bc__keyword@ --- * + * + * Arguments: @char *s@ = pointer to keyword string + * @FILE *fp@ = stream to write onto + * + * Returns: -- + * + * Use: Displays a keyword in a nice way. There's some nasty hacking + * here to make GNU's `less' work properly. `more' appears to + * cope with highlighting codes OK, so that's fine. `less' + * prefers it if we attempt to `overstrike' the bolded + * characters. What fun... + */ + +static void bc__keyword(const char *s, FILE *fp) +{ +#ifdef HAVE_LIBTERMCAP + if ((~bc__flags & (f_less | f_highlight)) == 0) { + while (*s) { + putc(*s, fp); + putc(8, fp); /* evil... */ + putc(*s, fp); + s++; + } + } else { + static char buff[24]; + static char *hs, *he, *p = buff; + + if (!hs) { + if (bc__flags & f_highlight) { + hs = tgetstr("md", &p); + he = tgetstr("me", &p); + } else + hs = he = ""; + } + fputs(hs, fp); + fputs(s, fp); + fputs(he, fp); + } +#else + fputs(s, fp); +#endif +} + +/* --- @bc__mbtok@ --- * + * + * Arguments: @int byte@ = the current byte + * @const char *t[]@ = pointer to token table + * @int n@ = number of items in token table + * @FILE *fp@ = stream to write onto + * + * Returns: 0 if everything's OK + * + * Use: Decodes multibyte tokens. + */ + +static int bc__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; + return (0); +} + +/* --- @bc__decode@ --- * + * + * Arguments: @int byte@ = byte to decode + * @FILE *fp@ = stream to write onto + * + * Returns: 0 if everything's going OK + * + * Use: Decodes a byte, changing states as necessary. + */ + +static int bc__decode(int byte, FILE * fp) +{ + switch (bc__state) { + case s_keyword: + if (byte == '*') + bc__state = s_comment; + else + bc__state = s_normal; + /* Fall through here */ + case s_normal: + if (byte >= 0x7F) { + switch (byte) { + case 0xC6: + bc__state = s_c6; + break; + case 0xC7: + bc__state = s_c7; + break; + case 0xC8: + bc__state = s_c8; + break; + case 0x8B: /* ELSE */ + case 0x8C: /* THEN */ + case 0xF5: /* REPEAT (a funny one) */ + bc__state = s_keyword; + bc__keyword(bcTok__base[byte - 0x7F], fp); + break; + case 0xDC: /* DATA */ + case 0xF4: /* REM */ + bc__state = s_comment; + /* Fall through here */ + default: + bc__keyword(bcTok__base[byte - 0x7F], fp); + break; + } + } else { + if (byte == '"') + bc__state = s_quote; + fputc(byte, fp); + } + break; + case s_quote: + if (byte == '"') + bc__state = s_normal; + /* Fall through here */ + case s_comment: + fputc(byte, fp); + break; + case s_c6: + return (bc__mbtok(byte, bcTok__c6, ITEMS(bcTok__c6), fp)); + break; + case s_c7: + return (bc__mbtok(byte, bcTok__c7, ITEMS(bcTok__c7), fp)); + break; + case s_c8: + return (bc__mbtok(byte, bcTok__c8, ITEMS(bcTok__c8), fp)); + break; + } + return (0); +} + +/* --- @bc__line@ --- * + * + * Arguments: @FILE *in@ = input stream to read + * @FILE *out@ = output stream to write + * + * Returns: Zero if there's another line after this one. + * + * Use: Decodes a BASIC line into stuff to be written. + */ + +static int bc__line(FILE *in, FILE *out) +{ + /* --- Read the line number --- */ + + { + int a, b; + + a = getc(in); + D( fprintf(stderr, "ln_0 == %i\n", a); ) + if (a == EOF) + goto eof; + if (a == 0xFF) + return (1); + + b = getc(in); + D( fprintf(stderr, "ln_1 == %i\n", b); ) + if (b == EOF) + goto eof; + + if (bc__flags & f_linenumbers) + fprintf(out, "%5i", (a << 8) + b); + } + + { + int len; + int byte; + + len = getc(in); + D( fprintf(stderr, "linelen == %i\n", len); ) + if (len == EOF) + goto eof; + len -= 4; + + bc__state = s_normal; + while (len) { + byte = getc(in); + D( fprintf(stderr, "state == %i, byte == %i\n", \ + bc__state, byte); ) + if (byte == EOF) + goto eof; + bc__decode(byte, out); + len--; + } + putc('\n', out); + + byte = getc(in); + D( fprintf(stderr, "eol == %i\n", byte); ) + if (byte == EOF) + goto eof; + else if (byte != 0x0D) + return (die("Bad program: expected end-of-line delimiter")); + } + + return (0); + +eof: + return (die("Bad program: unexpected end-of-file")); +} + +/* --- @bc__file@ --- * + * + * Arguments: @FILE *in@ = the input stream + * @FILE *out@ = the output stream + * + * Returns: -- + * + * Use: Decodes an entire file. + */ + +static void bc__file(FILE *in, FILE *out) +{ + int byte; + + /* --- Check for the inital newline char --- */ + + byte = getc(in); + if (byte != 0x0D) + die("Bad program: doesn't start with a newline"); + + /* --- Now read the lines in one by one --- */ + + while (!bc__line(in, out)) ; + + /* --- Check that we're really at end-of-file --- */ + + byte = getc(in); + if (byte != EOF) + die("Found data after end of program"); +} + +/* --- @bc__sigPipe@ --- * + * + * Arguments: @int s@ = signal number + * + * Returns: Doesn't + * + * Use: Handles SIGPIPE signals, and gracefully kills the program. + */ + +static void bc__sigPipe(int s) +{ + (void) s; + exit(0); /* Gracefully, oh yes */ +} + +/* --- @bc__options@ --- * + * + * Arguments: @int c@ = number of arguments + * @char *v[]@ = pointer to arguments + * @char *s@ = pointer to short options + * @struct option *o@ = pointer to long options + * + * Returns: -- + * + * Use: Parses lots of arguments. + */ + +static void bc__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); + if (i == -1) + break; + + switch (i) { + case 'v': + case 'h': + printf("%s v. " VERSION " (" __DATE__ ")\n", optprog); + if (i == 'v') + exit(0); + printf("\n" + "%s [-hv] [-n|+n] [-l|+l] [-p PAGER] [file...]\n" + "\n" + "Types BBC BASIC programs in a readable way. Options " + "currently supported are as\n" + "follows:\n" + "\n" + "-h, --help: Displays this evil help message\n" + "-v, --version: Displays the current version number\n" + "-n, --line-numbers: Displays line numbers for each line\n" + "-l, --highlight: Attempts to highlight keywords\n" + "-p, --pager=PAGER: Sets pager to use (default $PAGER)\n" + "\n" + "Prefix long options with `no-' to cancel them. Use `+' to " + "cancel short options.\n" + "Options can also be placed in the `BASCAT' environment " + "variable, if you don't\n" + "like the standard settings.\n", + optprog); + exit(0); + break; + case 'n': + bc__flags |= f_linenumbers; + break; + case 'n' | gFlag_negated: + bc__flags &= ~f_linenumbers; + break; + case 'l': + bc__flags |= f_highlight; + break; + case 'l' | gFlag_negated: + bc__flags &= ~f_highlight; + break; + case 'p': + bc__pager = optarg; + break; + } + } +} + +/* --- @main@ --- * + * + * Arguments: @int argc@ = number of arguments + * @char *argc[]@ = pointer to what the arguments are + * + * Returns: 0 if it all worked + * + * Use: Displays BASIC programs. + */ + +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 } + }; + static char *shortopts = "hvn+l+p:"; + + /* --- Parse the command line options --- */ + + bc__options(argc, argv, shortopts, opts); + + /* --- Now do the job --- */ + + if (optind == argc && isatty(0)) { + fprintf(stderr, + "%s: No filenames given, and standard input is a tty\n" + "To force reading from stdin, use `%s -'. For help, type " + "`%s --help'.\n", + optprog, optprog, optprog); + exit(0); + } + +#ifdef HAVE_LIBTERMCAP + if (bc__flags & f_highlight) + tgetent(bc__termcap, getenv("TERM")); +#endif + + { + FILE *in; + FILE *out; + + /* --- If output is to a terminal, try paging --- * + * + * All programs which spew text should do this ;-) + */ + + 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 (!out) + out = stdout; + else { + bc__flags |= f_tty; + signal(SIGPIPE, bc__sigPipe); + } + } else + out = stdout; + + /* --- Now go through all the files --- */ + + if (optind == argc) + bc__file(stdin, out); + else + while (optind < argc) { + if (strcmp(argv[optind], "-") == 0) + bc__file(stdin, out); + else { + in = fopen(argv[optind], "rb"); + if (!in) { + fprintf(stderr, + "%s: Couldn't open input file: %s\n", + optprog, strerror(errno)); + } else { + bc__file(in, out); + fclose(in); + } + } + optind++; + } + if (bc__flags & f_tty) + pclose(out); + } + + return (0); +} + +/*----- That's all, folks -------------------------------------------------*/ diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..e246192 --- /dev/null +++ b/configure.in @@ -0,0 +1,56 @@ +dnl -*-fundamental-*- +dnl +dnl $Id: configure.in,v 1.1 1998/03/16 15:21:37 mdw Exp $ +dnl +dnl Source for auto configuration for `Bascat' +dnl +dnl (c) 1997 Mark Wooding +dnl + +dnl----- Licensing notice --------------------------------------------------- +dnl +dnl This file is part of Bascat. +dnl +dnl Bascat is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU Library General Public License as +dnl published by the Free Software Foundation; either version 2 of the +dnl License, or (at your option) any later version. +dnl +dnl Bascat is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU Library General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with Bascat; if not, write to the Free Software Foundation, +dnl Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +dnl----- Revision history --------------------------------------------------- +dnl +dnl $Log: configure.in,v $ +dnl Revision 1.1 1998/03/16 15:21:37 mdw +dnl Files placed under CVS control. +dnl +dnl Revision 1.1 1997/07/23 01:18:47 mdw +dnl Initial revision +dnl + +AC_INIT(bascat.c) +PACKAGE=bascat VERSION=1.2-pre +AC_SUBST(PACKAGE) +AC_SUBST(VERSION) +AC_DEFINE(VERSION, "1.2-pre") + +AC_ARG_PROGRAM +AC_PROG_CC +AC_PROG_INSTALL + +mdw_GCC_FLAGS(-pedantic -Wall -W -Wtraditional -Wpointer-arith -Wcast-align) +mdw_CHECK_MANYLIBS(tgetent, termcap ncurses, [AC_DEFINE(HAVE_LIBTERMCAP, 1)]) +mdw_OPT_NDEBUG + +AC_ARG_WITH(pager, +[ --with-pager=PAGER set the default pager (default is \`more')], + [AC_DEFINE(PAGER, "$withval")], [AC_DEFINE(PAGER, "more")]) + +AC_OUTPUT(Makefile)