💾 Archived View for mirrors.apple2.org.za › archive › ground.icaen.uiowa.edu › Mirrors › ms.uky › fi… captured on 2024-12-18 at 01:44:40.

View Raw

More Information

-=-=-=-=-=-=-

/* @(#) sciibin.c       1.20 1 Nov 89  */
/*************************************************************************
 **                                                                     **
 **  Name    :  sciibin                                                 **
 **  Author  :  Marcel J.E. Mol                                         **
 **  Date    :  6 Mar 89              (first release)                   **
 **  Version :  1.20                                                    **
 **  Files   :  sciibin.c       Main source file                        **
 **                                                                     **
 **  ------------------------- Revision List -------------------------  **
 **  Ver   Date       Name                   Remarks                    **
 **  1.00  06 Mar 89   Marcel Mol            First release              **
 **  1.10  27 Mar 89   Marcel Mol            Finished things up, error  **
 **                                          routine, linecount,        **
 **                                          all info fields filled in, **
 **                                          changed info layout.       **
 **  1.20  01 Nov 89   Dave Whitney          Fixed a bug that caused it **
 **                                          to not process more than 1 **
 **                                          segment in any file.       **
 **                                          Also fixed CRE/MOD order.  **
 **  =================================================================  **
 **                                                                     **
 **  Compile as follows: cc sciibin.c -O -s -o sciibin                  **
 **                                                                     **
 **  Usage: sciibin [-hvtc] [-o<outputfile>] <infiles>                  **
 **                                                                     **
 **           -v show only info on file, do not create output.          **
 **           -t test file, do not create output.                       **
 **           -c do not check checksums.                                **
 **           -o create given filename instead of the one in            **
 **              binscii file. Use this only if the input files         **
 **              contain only one output file.                          **
 **           -h help.                                                  **
 **                                                                     **
 **                                                                     **
 **    Defining DEBUG gives some debug information.                     **
 **    Defining DEBUGALL gives input and output of the decode           **
 **    routine.                                                         **
 **                                                                     **
 **   This software is freeware. I can not be held responsible to       **
 **   any damage this program may cause you or anyone or anything else. **
 **                                                                     **
 ************************************************************************/

#include <sys/types.h>
#include <sys/stat.h>

#define BUFLEN 256

/*
 * Global variables
 */
char buf[BUFLEN+1];
unsigned char dec[BUFLEN+1];
char alphabet[BUFLEN+1];
char outfilename[BUFLEN+1];

int outflag = 0;                /* the -o option                    */
int crcflag = 0;                /* the -c option                    */
int infoflag = 0;               /* the -v option                    */
int testflag = 0;               /* the -t option                    */
int makeoutput;                 /*  !-t & !-v                       */
int crcok;                      /* -t | -c                          */
FILE *outfp;                    /* output file                      */

int namlen, filetype, numblocks;
long filesize, startbyte, segmentlen;
int modyear, modmonth, modday, modhour, modmin;
int creyear, cremonth, creday, crehour, cremin;
int auxtype, stortype, access;
char * infilename;
int linecount;

char * progname;

/*
 * updcrc macro derived from article Copyright (C) 1986 Stephen Satchell.
 *  NOTE: First argument must be in range 0 to 255.
 *        Second argument is referenced twice.
 *
 * Programmers may incorporate any or all code into their programs,
 * giving proper credit within the source. Publication of the
 * source routines is permitted so long as proper credit is given
 * to Stephen Satchell, Satchell Evaluations and Chuck Forsberg,
 * Omen Technology.
 */

/* #define updcrc(cp, crc) ( crctab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp) */
#define updcrc(cp, crc) ( (crctab[((crc >> 8) & 0xFF) ^ cp] ^ (crc << 8)) & 0xFFFF)

/* crctab calculated by Mark G. Mendel, Network Systems Corporation */
static unsigned short crctab[256] = {
  0x0000,  0x1021,  0x2042,  0x3063,  0x4084,  0x50a5,  0x60c6,  0x70e7,
  0x8108,  0x9129,  0xa14a,  0xb16b,  0xc18c,  0xd1ad,  0xe1ce,  0xf1ef,
  0x1231,  0x0210,  0x3273,  0x2252,  0x52b5,  0x4294,  0x72f7,  0x62d6,
  0x9339,  0x8318,  0xb37b,  0xa35a,  0xd3bd,  0xc39c,  0xf3ff,  0xe3de,
  0x2462,  0x3443,  0x0420,  0x1401,  0x64e6,  0x74c7,  0x44a4,  0x5485,
  0xa56a,  0xb54b,  0x8528,  0x9509,  0xe5ee,  0xf5cf,  0xc5ac,  0xd58d,
  0x3653,  0x2672,  0x1611,  0x0630,  0x76d7,  0x66f6,  0x5695,  0x46b4,
  0xb75b,  0xa77a,  0x9719,  0x8738,  0xf7df,  0xe7fe,  0xd79d,  0xc7bc,
  0x48c4,  0x58e5,  0x6886,  0x78a7,  0x0840,  0x1861,  0x2802,  0x3823,
  0xc9cc,  0xd9ed,  0xe98e,  0xf9af,  0x8948,  0x9969,  0xa90a,  0xb92b,
  0x5af5,  0x4ad4,  0x7ab7,  0x6a96,  0x1a71,  0x0a50,  0x3a33,  0x2a12,
  0xdbfd,  0xcbdc,  0xfbbf,  0xeb9e,  0x9b79,  0x8b58,  0xbb3b,  0xab1a,
  0x6ca6,  0x7c87,  0x4ce4,  0x5cc5,  0x2c22,  0x3c03,  0x0c60,  0x1c41,
  0xedae,  0xfd8f,  0xcdec,  0xddcd,  0xad2a,  0xbd0b,  0x8d68,  0x9d49,
  0x7e97,  0x6eb6,  0x5ed5,  0x4ef4,  0x3e13,  0x2e32,  0x1e51,  0x0e70,
  0xff9f,  0xefbe,  0xdfdd,  0xcffc,  0xbf1b,  0xaf3a,  0x9f59,  0x8f78,
  0x9188,  0x81a9,  0xb1ca,  0xa1eb,  0xd10c,  0xc12d,  0xf14e,  0xe16f,
  0x1080,  0x00a1,  0x30c2,  0x20e3,  0x5004,  0x4025,  0x7046,  0x6067,
  0x83b9,  0x9398,  0xa3fb,  0xb3da,  0xc33d,  0xd31c,  0xe37f,  0xf35e,
  0x02b1,  0x1290,  0x22f3,  0x32d2,  0x4235,  0x5214,  0x6277,  0x7256,
  0xb5ea,  0xa5cb,  0x95a8,  0x8589,  0xf56e,  0xe54f,  0xd52c,  0xc50d,
  0x34e2,  0x24c3,  0x14a0,  0x0481,  0x7466,  0x6447,  0x5424,  0x4405,
  0xa7db,  0xb7fa,  0x8799,  0x97b8,  0xe75f,  0xf77e,  0xc71d,  0xd73c,
  0x26d3,  0x36f2,  0x0691,  0x16b0,  0x6657,  0x7676,  0x4615,  0x5634,
  0xd94c,  0xc96d,  0xf90e,  0xe92f,  0x99c8,  0x89e9,  0xb98a,  0xa9ab,
  0x5844,  0x4865,  0x7806,  0x6827,  0x18c0,  0x08e1,  0x3882,  0x28a3,
  0xcb7d,  0xdb5c,  0xeb3f,  0xfb1e,  0x8bf9,  0x9bd8,  0xabbb,  0xbb9a,
  0x4a75,  0x5a54,  0x6a37,  0x7a16,  0x0af1,  0x1ad0,  0x2ab3,  0x3a92,
  0xfd2e,  0xed0f,  0xdd6c,  0xcd4d,  0xbdaa,  0xad8b,  0x9de8,  0x8dc9,
  0x7c26,  0x6c07,  0x5c64,  0x4c45,  0x3ca2,  0x2c83,  0x1ce0,  0x0cc1,
  0xef1f,  0xff3e,  0xcf5d,  0xdf7c,  0xaf9b,  0xbfba,  0x8fd9,  0x9ff8,
  0x6e17,  0x7e36,  0x4e55,  0x5e74,  0x2e93,  0x3eb2,  0x0ed1,  0x1ef0
  };

char * filetypes[] = {
  "$00", "bad", "pcd", "ptx", "txt", "pda", "bin", "fnt",
  "fot", "ba3", "da3", "wpf", "sos", "$0D", "$0E", "dir",
  "rpd", "rpi", "$12", "$13", "$14", "$15", "$16", "$17",
  "$18", "adb", "awp", "asp", "$1C", "$1D", "$1E", "$1F",
  "$20", "$21", "$22", "$23", "$24", "$25", "$26", "$27",
  "$28", "$29", "$2A", "$2B", "$2C", "$2D", "$2E", "$2F",
  "$30", "$31", "$32", "$33", "$34", "$35", "$36", "$37",
  "$38", "$39", "$3A", "$3B", "$3C", "$3D", "$3E", "$3F",
  "$40", "$41", "$42", "$43", "$44", "$45", "$46", "$47",
  "$48", "$49", "$4A", "$4B", "$4C", "$4D", "$4E", "$4F",
  "$50", "$51", "$52", "$53", "$54", "$55", "$56", "$57",
  "$58", "$59", "$5A", "$5B", "$5C", "$5D", "$5E", "$5F",
  "$60", "$61", "$62", "$63", "$64", "$65", "$66", "$67",
  "$68", "$69", "$6A", "$6B", "$6C", "$6D", "$6E", "$6F",
  "$70", "$71", "$72", "$73", "$74", "$75", "$76", "$77",
  "$78", "$79", "$7A", "$7B", "$7C", "$7D", "$7E", "$7F",
  "$80", "$81", "$82", "$83", "$84", "$85", "$86", "$87",
  "$88", "$89", "$8A", "$8B", "$8C", "$8D", "$8E", "$8F",
  "$90", "$91", "$92", "$93", "$94", "$95", "$96", "$97",
  "$98", "$99", "$9A", "$9B", "$9C", "$9D", "$9E", "$9F",
  "$A0", "$A1", "$A2", "$A3", "$A4", "$A5", "$A6", "$A7",
  "$A8", "$A9", "$AA", "$AB", "$AC", "$AD", "$AE", "$AF",
  "src", "obj", "lib", "s16", "rtl", "exe", "str", "tsf",
  "nda", "cda", "tol", "drv", "$BC", "$BD", "$BE", "doc",
  "pnt", "pic", "$C2", "$C3", "$C4", "$C5", "$C6", "$C7",
  "fon", "$C9", "$CA", "$CB", "$CC", "$CD", "$CE", "$CF",
  "$D0", "$D1", "$D2", "$D3", "$D4", "$D5", "$D6", "$D7",
  "$D8", "$D9", "$DA", "$DB", "$DC", "$DD", "$DE", "$DF",
  "$E0", "$E1", "$E2", "$E3", "$E4", "$E5", "$E6", "$E7",
  "$E8", "$E9", "$EA", "$EB", "$EC", "$ED", "$EE", "pas",
  "cmd", "$F1", "$F2", "$F3", "$F4", "$F5", "$F6", "$F7",
  "$F8", "p16", "int", "ivr", "bas", "var", "rel", "sys",
};

/*
  ProDOS Filetypes

  Num	Name	OS	Meaning
  $00			typeless
  $01	BAD	both	BAD blocks file
  $02	PCD	SOS	Pascal CoDe file
  $03	PTX	SOS	Pascal TeXt file
  $04	TXT	both	ASCII text file
  $05	PDA	SOS	Pascal DAta file
  $06	BIN	both	BINary file
  $07	CHR	SOS	CHaRacter font file
  $08	PIC	both	PICture file
  $09	BA3	SOS	Business BASIC (SOS) program file
  $0A	DA3	SOS	Business BASIC (SOS) data file
  $0B	WPD	SOS	Word Processor Document
  $0C		SOS	SOS system file
  $0D		SOS	SOS reserved file type
  $0E		SOS	SOS reserved file type
  $0F	DIR	Both	subDIRectory file
  $10	RPD	SOS	RPS data file
  $11	RPI	SOS	RPS index file
  $12		SOS	Applefile diskcard file
  $13		SOS	Applefile model file
  $14		SOS	Applefile report format file
  $15		SOS	Screen library file
  $16		SOS	SOS reserved file type
  $17		SOS	SOS reserved file type
  $18		SOS	SOS reserved file type
  $19	ADB	ProDOS	AppleWorks Database file
  $1A	AWP	ProDOS	AppleWorks WordProcessing file
  $1B	ASP	ProDOS	AppleWorks Spreadsheet file
  $1C-$5F			Reserved
  $60-$6F		ProDOS	PC Transporter (Applied Engineering) reserved filetypes
  $60	PRE	ProDOS	ProDOS preboot driver
  $61-$6A	ProDOS	Reserved
  $6B	NIO	ProDOS	PC Transporter BIOS and drivers
  $6C		ProDOS	Reserved
  $6D	DVR	ProDOS	PC Transporter device drivers
  $6E		ProDOS	Reserved
  $6F	HDV	ProDOS	MSDOS HardDisk Volume
  $70-$9F			Reserved
  $A0	WPF	ProDOS	WordPerfect document file
  $A1	MAC	ProDOS	Macrofile
  $A2	HLP	ProDOS	Help File
  $A3	DAT	ProDOS	Data File
  $A4			Reserved
  $A5	LEX	ProDOS	Spelling dictionary
  $A6-$AB			Reserved
  $AC	ARC	ProDOS	General Purpose Archive file
  $AD-$AF			Reserved
  $B0	SRC	ProDOS	ORCA/M & APW source file
  $B1	OBJ	ProDOS	ORCA/M & APW object file
  $B2	LIB	ProDOS	ORCA/M & APW library file
  $B3	S16	ProDOS	ProDOS16 system file
  $B4	RTL	ProDOS	ProDOS16 runtime library
  $B5	EXE	ProDOS	APW shell command file
  $B6	STR	ProDOS	ProDOS16 startup init file
  $B7	TSF	ProDOS	ProDOS16 temporary init file
  $B8	NDA	ProDOS	ProDOS16 new desk accessory
  $B9	CDA	ProDOS	ProDOS16 classic desk accessory
  $BA	TOL	ProDOS	ProDOS16 toolset file
  $BB	DRV	ProDOS	ProDOS16 driver file
  $BC-$BE			Reserved for ProDOS16 load file
  $BF	DOC	ProDOS	document file
  $C0	PNT	ProDOS	//gs paint document
  $C1	SCR	ProDOS	//gs screen file
  $C2-$C7			Reserved
  $C8	FNT	ProDOS	Printer font file
  $C9		ProDOS	finder files
  $CA		ProDOS	finder icons
  $CB-$DF			Reserved
  $E0	LBR	ProDOS	Apple archive library file
  $E1			Unknown (unlisted)
  $E2	ATI	ProDOS	Appletalk init file
  $E3-$EE			Reserved
  $EF	PAS	ProDOS	ProDOS Pascal file
  $F0	CMD	ProDOS	added command file
  $F1-$F8		ProDOS	User defined filetypes (popular ones include:)
  $F1	OVL	ProDOS	Overlay file
  $F2	DBF	ProDOS	Database file
  $F3	PAD	ProDOS	MouseWrite file
  $F4	MCR	ProDOS	AE Pro macro file
  $F5	ECP	ProDOS	ECP batch file
  $F6	DSC	ProDOS	description file
  $F7	TMP	ProDOS	temporary work file
  $F8	RSX	ProDOS	linkable object module
  $F9	IMG	ProDOS	ProDOS image file
  $FA	INT	ProDOS	Integer BASIC program
  $FB	IVR	ProDOS	Integer BASIC variables file
  $FC	BAS	ProDOS	AppleSoft BASIC program
  $FD	VAR	ProDOS	AppleSoft BASIC variables file
  $FE	REL	ProDOS	ProDOS EDASM relocatable object module file
  $FF	SYS	ProDOS	ProDOS8 system file
  */


/*
 * function declarations
 */
sciibin();
getheader();
decode();
decodestring();
char *myfgets();
void usage();
void error();

char * copyright = "@(#) sciibin.c  1.1 27/03/89  (c) M.J.E. Mol";

     main(argc, argv)
     int argc;
     char **argv;
{
  FILE *fp;
  int c;
  extern int optind;	        	/* For getopt */
  extern char *optarg;                  /* For getopt */
  int  flag;				/* Flag for getopt */

  progname = *argv;

  while ((flag = getopt(argc, argv, "hvcto:")) != EOF) { /* Process options */
    switch (flag) {
    case 'v': infoflag = 1;	/* Want only info of file */
      break;
    case 'h': usage();		/* Give help */
      exit(0);
    case 'c': crcflag = 1;
      break;
    case 't': testflag = 1;
      break;
    case 'o': strcpy(outfilename, optarg);
      outflag = 1;
      break;
      default : fprintf(stderr, "%s: skipping unkown flag %c, use -h.\n",
			progname, flag);
      break;
    }
  }

  makeoutput = !(testflag | infoflag);
  crcok = testflag | crcflag;
#if defined(DEBUG)
  fprintf(stderr, "make output: %d, crcok: %d\n", makeoutput, crcok);
#endif

  if (optind >= argc) {		/* No files given, use stdin */
    infilename = "stdin";
    linecount = 0;
    sciibin(stdin);
  }
  else
    while (optind < argc) {
      infilename = argv[optind];
      optind++;
      if ((fp = fopen(infilename, "r")) == NULL) {
	perror(infilename);
	continue;
      }
      linecount = 0;
      sciibin(fp);
      fclose(fp);
    }

  exit(0);
} /* main */

/*
 * Walk over the file processing all segments in it
 */
sciibin(fp)
     FILE *fp;
{
  int processed = 0;          /* number of processed binscii segments     */
  int status = 0;             /* return codes of calls to decode          */

  while (myfgets(buf, BUFLEN, fp) != NULL) {
#if defined(DEBUG)
    fprintf(stderr, "(%s) get start:%s", infilename, buf);
#endif
    if (!strncmp(buf, "FiLeStArTfIlEsTaRt",18)) {
      if (!getheader(fp) && !infoflag) /* if header ok and not -v flag */
	status |= decode(fp);
      processed++;
    }
  }

  if (processed == 0) {
    error("not a binscii file");
    return 1;
  }

  return status;
} /* sciibin */

/*
 * Build the alphabet, get the output file info and open output file
 * if necessary.
 * Still contains lots of debug code to find out the header structure.
 *   (every bit is known now...)
 */
getheader(fp)
     FILE *fp;
{
  register int i, j;
  register int crc = 0;
  struct stat statbuf;            /* must know if file exists         */
  char *iomod;                    /* write or readwrite a file        */

  /*
   * Get the alphabet
   */
  if (myfgets(buf, BUFLEN, fp) == NULL) {
    error("reading alphabet: unexpected end of file");
    return 1;
  }
#if defined(DEBUG)
  fprintf(stderr, "(%s) alphabet:%s", infilename, buf);
#endif
  if (strlen(buf) != 65) {
    error("alphabet corrupted");
    return 1;
  }

  /*
   * Process the alphabet
   */
  for (i = 0; i < 255; i++)
    alphabet[i] = 0x7f;
  for (i = 0; i < 64; i++) {
    j = buf[i];
    if (alphabet[j] != 0x7f)
      error("Warning: double character in alphabet");
    alphabet[j] = i;
  }
#if defined(DEBUG)
  for (i = 0; i < BUFLEN; i+=16) {
    fprintf(stderr, "(%s) alphabet[%3d] =", infilename, i);
    for (j = 0; j < 16; j++)
      fprintf(stderr, " %02X", alphabet[i+j]);
    putc('\n', stderr);
  }
#endif

  /*
   * Get the file header
   */
  if (myfgets(buf, BUFLEN, fp) == NULL) {
    error("reading fileheader: unexpected end of file");
    return 1;
  }
#if defined(DEBUG)
  fprintf(stderr, "(%s) fileheader:%s", infilename, buf);
#endif

  /*
   * Strip output filename if needed
   */
  if (!outflag) {
    namlen = *buf - 'A' + 1;
    strncpy(outfilename, buf+1, namlen);
    outfilename[namlen] = '\0';
  }
#if defined(DEBUG)
  fprintf(stderr, "(%s) filename:**%s**\n", infilename, outfilename);
  fprintf(stderr, "(%s) fileinfo:**%s**", infilename, buf+16);
#endif

  /*
   * Decode and process the file header information
   */
  if ((i = decodestring(buf+16, dec)) != 27)
    error("warning: corrupted file header length");
  for (i = 0; i < 24; i++)
    crc = updcrc(dec[i], crc);
  if (crc != (dec[24] | (dec[25] << 8))) {
    if (crcok)
      error("warning: CRC error in file header");
    else {
      error("error: CRC error in file header");
      return 1;
    }
  }
  filesize   = dec[0] + (dec[1]<<8) + (dec[2]<<16);/* Calculate file length */
  startbyte  = dec[3] + (dec[4]<<8) + (dec[5]<<16);
  access     = dec[6];
  filetype   = dec[7];
  auxtype    = dec[8] + (dec[9] << 8);
  stortype   = dec[10];
  numblocks  = dec[11] + (dec[12]<<8);

#define MOD 13
#define CRE 17

  creday     = dec[CRE] & 0x1f;
  cremonth   = ((dec[CRE+1] & 0x01) << 3) | (dec[CRE] >> 5);
  creyear    = dec[CRE+1] >>1;
  cremin     = dec[CRE+2] & 0x3f;
  crehour    = dec[CRE+3] & 0x1f;

  modday     = dec[MOD] & 0x1f;
  modmonth   = ((dec[MOD+1] & 0x01) << 3) | (dec[MOD] >> 5);
  modyear    = dec[MOD+1] >>1;
  modmin     = dec[MOD+2] & 0x3f;
  modhour    = dec[MOD+3] & 0x1f;

  segmentlen = dec[21] + (dec[22]<<8) + (dec[23]<<16);

#define READ    0x01
#define WRITE   0x02
#define BACKUP  0x20
#define RENAME  0x40
#define DESTROY 0x80

  if (infoflag) {
    printf("%-15s : %4d of %4d : ", outfilename,startbyte / 0x3000 + 1,
	(filesize + 0x2FFF) / 0x3000);
    printf("%s (%d)\n",infilename,linecount);
  }

  if (makeoutput) {
    iomod = (stat(outfilename, &statbuf) == 0) ? "r+" : "w";
    if ((outfp = fopen(outfilename, iomod)) == NULL) {
      error("unable to open output file");
      perror(outfilename);
      return 1;
    }
    fseek(outfp, startbyte, 0);
  }

  return 0;
} /* getheader */

/*
 * Do the actual decoding of the bin data.
 */
decode(fp)
     FILE *fp;
{
  register int i;
  register int crc = 0;
  int len;

  crc = 0;
  while (segmentlen > 0) {
    if (myfgets(buf, BUFLEN, fp) == NULL) {
      error("reading file: unexpected end of file");
      return 1;
    }
#if defined(DEBUG)
    fprintf(stderr, "(%s) data:%s", infilename, buf);
#endif
    if ((len = decodestring(buf, dec)) != 48)
      error("warning: corrupted line length");
    for (i = 0; i < 48; i++)
      crc = updcrc(dec[i], crc);
    if (makeoutput)
      for (i = 0; (i < len) && (segmentlen > 0); i++, segmentlen--)
	putc(dec[i], outfp);        /* COULD CR/NL TXT FILES */
    else
      segmentlen -= len;
#if defined(DEBUG)
    fprintf(stderr, "(%s) still need %d bytes\n", infilename, segmentlen);
#endif
  }

  /*
   * must be at end of segment now, with one remaining line containing
   * the crc check.
   */

  if (myfgets(buf, BUFLEN, fp) == NULL) {
    error("reading file crc: unexpected end of file");
    return 1;
  }
#if defined(DEBUG)
  fprintf(stderr, "(%s) crc:%s", infilename, buf);
#endif
  if ((len = decodestring(buf, dec)) != 3)
    error("warning: corrupted crc length");
  if (crc != (dec[0] | (dec[1] << 8))) {
    if (crcok)
      error("warning: CRC error in file data");
    else {
      error("error: CRC error in file data");
      return 1;
    }
  }

  fclose(outfp);

  return 0;
} /* decode */

/*
 * Decode one string off scii characters to binary data, meanwhile
 * calculating crc.
 */
decodestring(in, out)
     register char *in;
     register unsigned char *out;
{
  register int len = 0;

#if defined(DEBUGALL)
  char *b;

  fprintf(stderr, "(%s) decode in: %s\n", infilename, in);
  b = in;
  while (*b) fprintf(stderr, ".%02X", alphabet[*b++]);
  putc('\n', stderr);
  b = out;
#endif
  while (strlen(in) > 3) {
    *out++ = ((alphabet[in[3]] << 2) | (alphabet[in[2]] >> 4)) & 0xFF;
    *out++ = ((alphabet[in[2]] << 4) | (alphabet[in[1]] >> 2)) & 0xFF;
    *out++ = ((alphabet[in[1]] << 6) | (alphabet[in[0]]))      & 0xFF;
    len += 3;
    in += 4;
  }
  *out = '\0';
  if (*in != '\0' && *in != '\n')
    error("warning: line not ended by NULL or NEWLINE");
#if defined(DEBUGALL)
  fprintf(stderr, "(%s) decode out:\n", infilename);
  while (b != out)
    fprintf(stderr, ".%02X", *b++);
  putc('\n', stderr);
#endif

  return len;
} /* decodestring */

char *myfgets(buf, len, fp)
     char *buf;
     int len;
     FILE *fp;
{
  linecount++;
  return fgets(buf, len, fp);
} /* myfgets */

void usage()
{
  fprintf(stderr, "Usage: sciibin [-vtc] [-o<outputfile>] <infiles>\n\n");
  fprintf(stderr, "      -v show only info on file, do not create output.\n");
  fprintf(stderr, "      -t test file, do not create output.\n");
  fprintf(stderr, "      -c do not check checksums.\n");
  fprintf(stderr, "      -o create given filename instead of the one in\n");
  fprintf(stderr, "         binscii file. Use this only if the input files\n");
  fprintf(stderr, "         contain only one output file.\n");
  fprintf(stderr, "      -h this help message.\n");
} /* usage */

void error(str)
     char *str;
{
  fprintf(stderr, "%s (%s, %d): %s\n", progname, infilename, linecount, str);
} /* error */