[comp.binaries.apple2] sciibin source code

dcw@goldilocks.lcs.mit.edu (08/27/90)

I've ahd a few requests for this, so here it is. Note that this is not
the latest version to come by here, but it works fine. The newer
version has encoding but it only compiles under APW. This is intended
for Unix boxes and it only decodes. This was not written by me and is
therefore not supported by me. It does appear to work...

/* @(#) 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 <stdio.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  %3s aux: %04X ",
	   outfilename, filetypes[filetype], auxtype);
    putchar(access & READ    ? 'r' : '-');
    putchar(access & WRITE   ? 'w' : '-');
    putchar(access & RENAME  ? 'n' : '-');
    putchar(access & DESTROY ? 'd' : '-');
    putchar(access & BACKUP  ? 'b' : '-');
    switch (stortype) {
    case 0x0F : printf(" voldir"); break;
    case 0x0D : printf(" dir"); break;
    case 0x01 : printf(" seed"); break;
    case 0x02 : printf(" sap"); break;
    case 0x03 : printf(" tree"); break;
      default   : printf(" ???"); break;
    }
    printf(" %02d/%02d/%02d(%02d:%02d) -", modmonth, modday, modyear,
	   modhour, modmin);
    printf(" %02d/%02d/%02d(%02d:%02d)\n", cremonth, creday, creyear,
	   crehour, cremin);
    printf("Part %4d of %4d,", startbyte / 0x3000 + 1,
	   (filesize + 0x2FFF) / 0x3000);
    printf(" bytes %7d to %7d of %7d bytes, %5d blocks\n",
	   startbyte, startbyte+segmentlen, filesize, numblocks);
  }
  
  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 */

--
Dave Whitney			| I wrote Z-Link and BinSCII. Send me bug
MIT 1990 Computer Science	| reports. I need a job. Send me an offer.
dcw@goldilocks.lcs.mit.edu	| My opinions, you hear? MINE!
dcw@athena.mit.edu		| Are you sure you know what you're doing?