[comp.sources.apple2] v001SRC024: Directory Listing For DOS 3.3

jac@paul.rutgers.edu (Jonathan A. Chandross) (02/11/91)

Submitted-by: NONE
Posting-number: Volume 1, Source:24
Archive-name: util/dir.c
Architecture: ANY_2
Version-number: 1.00

 This program runs on the AZTEC APPLE 'C' system.  It looks at the
 diskette VTOC to determine how many free tracks there are on the
 current diskette (er...directory).  It will then print out a sorted
 sorted list of files (in default 2 column format with 80 column
 screen).  If an optional mask or masks are specified, they will
 be used to limit the search on the specified diskette. 


=dir.c
-/*
- *
- * dir.c
- *
- * This program runs on the AZTEC APPLE 'C' system.  It looks at the
- * diskette VTOC to determine how many free tracks there are on the
- * current diskette (er...directory).  It will then print out a sorted
- * sorted list of files (in default 2 column format with 80 column
- * screen).  If an optional mask or masks are specified, they will
- * be used to limit the search on the specified diskette. 
- *
- * NOTE: DOS 3.3
- *
- * Usage:
- * 	dir [-l] [-1] [-p] [-d<number>] [-s<number>]
- *
- * 	Options:
- *		-l	Long listing. Like catalog, but print total/free
- * 			sectors as well.
- *		-dn	Drive to search (default slot)
- *		-sn 	Use slot 'n' instead of default slot
- *		-1	Use single column format (default if not 80
- *			column screen)
- *		-p  	DON'T pause at the end of each screen (default
- *			if not outputting to screen)
- *
- *	If no slot or drive is specified, the current drive/slot will be used.
- *
- * John Duncan
- * November 1983
- * Version 1.00
- *
- */
-
-#include <kbctl.h>
-
-#define LINES 21
-#define STDIN 0
-#define STDOUT 1
-#define STDERR 2
-
-/* Default DOS Value locations */
-
-#define DRIVE	0xB7F8	/* Last drive accessed */
-#define SLOT	0xB7F7	/* Last slot accessed */
-#define VTRACK	17	/* VTOC Track */
-#define VSEC	0	/* VTOC Map Sector */
-
-/* RWTS Definitions */
-
-#define SEEK 0
-#define READ 1
-#define WRITE 2
-#define FORMAT 4
-
-struct vtoc {
-	char xvtoc1;		/* 00    not used */
-	char ctrack1;		/* 01    Track number of first catalog sector */
-	char csec1;		/* 02    Sector num of first catalog sector */
-	char release;		/* 03    Release num of DOS used to INIT disk */
-	char xvtoc2[2];		/* 04-05 not used */
-	char volume;		/* 06    Diskette volume number */
-	char xvtoc3[32];	/* 07-26 not used */
-	char tsec;	/* Max. t/s pairs which fit in 1 file t/s list sec */
-	char xvtoc4[8];		/* 28-2F not used */
-	char ltrack;	/* 30    Last track where sectors were allocated */
-	char whichway;	/* 31    Direction of track allocation +1 or -1 */
-	char xvtoc5[2];		/* 32-33 not used */
-	char tpd;		/* 34    Tracks per diskette */
-	char spt;		/* 35	 Sectors per track */
-	int bps;		/* 36-37 Bytes per sector */
-	struct bitmap {
-		char tmap[4];	/*       Bit map of track */
-	} bmap [50];        /* Bit maps */
-};
-
-struct catalog {
-	char xxcat1;		/* 00    not used */
-	char tnext;		/* 01    Track number of next catalog sector */
-	char snext;		/* 02    Sector number of next catalog sector */
-	char xxcat2[8];		/* 03-0A not used */
-	struct fdesc {		/* File Descriptions */
-		char ts_t;	/* 00    Track of first t/s list, FF if none */
-		char ts_s;	/* 01    Sector of above track */
-		char ftype;	/* 02    File type, hi bit = locked */
-#define		TEXT 0x80		/* TEXT file */
-#define		INT  0x81		/* INTEGER BASIC file */
-#define		FP	 0x82		/* APPLESOFT BASIC file */
-#define		BIN	 0x84		/* BINARY file */
-#define		STYP 0x88		/* S type file */
-#define		REL	 0x90		/* RELOCATABLE object module file */
-#define		ATYP 0xA0		/* A type file */
-#define		BTYP 0xC0		/* B type file */
-		char fname[30];		/* 03-20 File name */
-		unsigned flen;		/* lo byte of file len is OK */
-	} fd [7];
-};
-static char tcode[] = {
-	TEXT, 'T',
-	INT,  'I',
-	FP,   'A',
-	BIN,  'B',
-	STYP, 'S',
-	REL,  'R',
-	ATYP, 'a',
-	BTYP, 'b',
-	0 };
-static struct dir {
-	char *fname;
-	unsigned flen;
-	char ftype;
-} dlist[200];	/* Pointers to entries */
-static int dcnt;		/* How many entries were found */
-static char drdef;		/* 0=use current drive, 1=use argument */
-static char sldef;		/* 0=use current slot, 1=use argument */
-static int dtot;		/* How many entries in total */
-static char drive, slot;
-static int dir_t1;		/* First directory track */
-static int dir_s1;		/* First directory sector */
-static int free_secs;		/* Free Sectors on diskette */
-static char lflag;		/* Long Listing flag */
-static int lcnt;		/* Lines on screen so far */
-static char oneflag;		/* 0=2 column, 1=1 column */
-static char pflag;		/* Pause after each screen */
-static long int bps;		/* Bytes per sector */
-static char spaces[41] =
-	"                                        ";
-static int spt;			/* Sectors per track */
-static int tpd;			/* Tracks per disk */
-static int vol;			/* Volume number */
-static char **mask;		/* Pointer to first mask */
-static int maskc;		/* Count of masks */
-static char lbuf[100];		/* Buffer for line output */
-
-main( argc, argv )
-	int argc;
-	char *argv[];
-{
-	register int i,j;
-	register char *targ;
-	register char ch;
-
-	/* Initialize here so we can 'run' it again if desired */
-
-	dcnt = -1;
-	lflag = oneflag = dtot = drdef = sldef = 0;
-	pflag = 1;
-
-	while( --argc ) {
-		if( **++argv != '-' ) break;
-		targ = *argv;
-		while(ch = *(++targ)) {
-			switch( ch ) {
-			case 'd':			/* which drive */
-				++targ;
-				if( *targ > '0' && *targ < '3') {
-					drive = *targ - '0';
-					drdef = 1;
-					break;
-				}
-				else {
-					errmesg( "dir: Drive number must be 1 or 2\n" );
-					exit( 1 );
-				}
-			case 'l':			/* long listing */
-				++lflag;
-			case '1':			/* single column listing */
-				oneflag = 1;
-				break;
-			case 'p':
-				pflag = 0;
-				break;
-			case 's':			/* which slot */
-				++targ;
-				if( *targ > '0' && *targ < '8') {
-					slot = *targ - '0';
-					sldef = 1;
-					break;
-				}
-				else {
-					errmesg( "dir: Slot number must be 1-7\n" );
-					exit( 1 );
-				}
-			default:
-				strcpy( lbuf, "Unknown flag -X\n" );
-				lbuf[14] = *targ;
-				errmesg( lbuf );
-				errmesg("Usage: dir [-1lp] [-sn] [-dn] [mask1] [mask2] ...\n");
-				exit( 1 );
-			}
-			if( ! *targ ) break;
-		}
-	}
-	maskc = argc;
-	mask = argv;
-
-	/* If not dealing with output to the terminal, turn off the pause */
-
-	i = ioctl( 1, KB_WID, 0);
-	if( i < 0 )		/* not the screen, turn off pauses */
-		pflag = 0;
-	if( i < 80 )	/* turn off double column mode */
-		oneflag = 1;
-
-	/* If no drive or slot was specified, we have to figure out which
-	 * one is wanted.  This is not easy since there is no system call
-	 * to find out the current slot and drive, so we just try to open
-	 * for reading a file with a ridiculous name and when it fails, we
-	 * take a peek into DOS to see which drive/slot it used.  It also
-	 * has the side effect of positioning the head to the VTOC, but
-	 * its a small consolation for all of the hassle.
-	 */
-
-	if( drdef == 0 || sldef == 0 ) {		/* here we go */
-		open( "$$unlikely @@", 0 );
-		if( drdef == 0 ) drive = *DRIVE;
-		if( sldef == 0 ) {
-			slot = *SLOT;
-			slot >>= 4;
-		}
-	}
-
-	/* Convert all masks to upper case since supposedly the only file
-	* names that will be encountered will be in upper case.
-	*/
-
-	while( argc ) {
-		targ = *argv;
-		while( *targ ) {
-			*targ = toupper(*targ);
-			++targ;
-		}
-		--argc; ++argv;
-	}
-	getvtoc();
-	getnames();
-	if( lflag ) header();
-	else lcnt = 0;
-	if( dcnt == -1 ) exit( 3 );
-	sortnames();
-	output();
-}
-
-
-/* getvtoc()
- *   Get the VTOC sector from the current drive, or the drive specified
- * on the command line.  If the '-t' or '-l' flags are set, print out
- * statistics on total sectors and available sectors.
- */
-getvtoc()
-{
-	struct vtoc buf;
-	register int cmap;
-	register char *mptr, *mend;
-	register int fs = 0;
-	static int rc;
-
-	if ( rc=rwts( VTRACK, VSEC, &buf, READ, slot, drive, 0) )
-		vtocerr( VTRACK, VSEC, rc );
-	if ( buf.bps < 128 ) buf.bps = 256;		/* sanity patch */
-	bps = buf.bps;
-	dir_t1 = buf.ctrack1;
-	dir_s1 = buf.csec1;
-	tpd = buf.tpd;
-	spt = buf.spt;
-	vol = buf.volume;
-
-	/* we have the map in memory, interpret it */
-
-	mend = buf.bmap;
-	mend += tpd << 2;		/* multiply by 4 the fast way */
-	for( mptr=buf.bmap; mptr<mend; ++mptr ) {
-		cmap = *mptr;
-		while( cmap ) {
-			if( cmap & 1 ) ++fs;
-			cmap >>= 1;
-		}
-	}
-	free_secs = fs;
-}
-
-
-/* getnames()
- *	 Search the directory and pick out all file names found.  Allocate
- * memory to hold the names and set up the array to point to them. 
- * Check the masks given before accepting an entry.
- */
-getnames()
-{
-	register int ctrack, csec;		/* Current track and sector */
-	register int i,j, mcnt;
-	register char  *sptr, *tptr, **fmask;	/* Temporary pointers */
-	int ttype, tlen;				/* temporaries */
-	struct catalog dbuf;			/* Space for directory block */
-	int rc;
-
-	ctrack = dir_t1;
-	csec = dir_s1;
-
-	while( ctrack ) {
-		if ( rc=rwts( ctrack, csec, &dbuf, READ, slot, drive, 0) )
-			vtocerr( ctrack, csec, rc );
-		for( i=0; i<7; i++ ) {
-			j = dbuf.fd[i].ts_t;
-			if( j == 0 ) return;	/* virgin entry, done with VTOC */
-			if( j != 0xFF ) {		/* its a good entry */
-
-				/* Save file length before we maybe clobber with NULL */
-
-				++dtot;
-				tlen = dbuf.fd[i].flen;
-				ttype = dbuf.fd[i].ftype;
-
-				/* Convert buffer to NULL terminated format */
-
-				sptr = dbuf.fd[i].fname;
-				for( tptr = sptr + 29; *tptr == 0xA0; tptr-- );
-				*(++tptr) = 0;
-
-				/* Turn off all hi bits */
-
-				for( tptr=sptr; *tptr; tptr++ ) *tptr &= 0x7F;
-
-				/* Check filename against all masks to see if we want it */
-
-				if( maskc == 0 ) goto gotone;
-				mcnt = maskc;
-				fmask = mask;
-				while( mcnt-- ) {
-					if( match( *fmask, sptr )) goto gotone;
-					++fmask;
-				}
-				continue;
-
-				/* we want it, save everything */
-
-		gotone:
-				dlist[++dcnt].ftype = ttype;
-				dlist[dcnt].flen = tlen;
-				if( !(tptr = malloc( tptr - sptr + 1))) {
-					errmesg( "dir: Out of memory\n" );
-					exit( 2 );
-				}
-				strcpy( tptr, sptr );
-				dlist[dcnt].fname = tptr;
-			}
-		}
-		ctrack = dbuf.tnext;
-		csec = dbuf.snext;
-	}
-}
-
-/* sortnames
- *		Just a little bubble sort since this won't take too long anyway.
- */
-sortnames()
-{
-	register int i, j;
-	struct dir tmp;
-
-	for( i=0; i<dcnt; i++ ) {
-		for( j=i+1; j<=dcnt; j++ ) {
-			if( strcmp( dlist[i].fname, dlist[j].fname ) > 0 ) {
-				tmp = dlist[i];
-				dlist[i] = dlist[j];
-				dlist[j] = tmp;
-			}
-		}
-	}
-}
-
-/* output()
- *		Print out the file names found.
- */
-output()
-{
-	register int i, j;
-	register char *tptr, *bptr, ch;
-
-	for( i=0; i<=dcnt; i++) {
-		bptr = lbuf;
-		if( lflag ) {
-			ch = dlist[i].ftype;
-			*lbuf = (ch & 0x80) ? '*' : ' ' ;
-			lbuf[1] = '?';
-			if( tptr = index( tcode, ch | 0x80))	lbuf[1] = *++tptr;
-			sprintf( lbuf+2, " %6ld ", bps * (long int) dlist[i].flen );
-			bptr = lbuf + 10;
-		}
-		for( tptr = dlist[i].fname; ; tptr++ ) {
-			if( *tptr < 0x20 ) {
-				if( *tptr == 0 ) break;
-				*bptr++ = '^';
-				*bptr = *tptr | 0x40;
-			}
-			else
-				*bptr = *tptr;
-			++bptr;
-		}
-		if( ((i & 1) == 0) && (oneflag == 0) && ((j = bptr - lbuf) < 40)) {
-			strcpy( bptr, spaces + j );
-			bptr = lbuf + 40;
-		}
-		else {
-			*bptr++ = '\n';
-			*bptr = 0;
-			++lcnt;
-		}
-		write( STDOUT, lbuf, bptr - lbuf );
-		if( pflag && (lcnt > LINES) ) {
-			mesg( "\n(more...)" );
-			read( STDIN, lbuf, 1 );
-			mesg( "\n" );
-			lcnt = 0;
-		}
-	}
-	if( ((i & 1) == 1) && (oneflag == 0)) mesg("\n");
-}
-
-
-/* match
- *		This routine will match a pattern 'mask' against a string 'str'.
- * The pattern may consist of any characters plus the meta-characters
- * '?' (match any one character), '*' (match any number of characters),
- * [...] (match any character in the class).  Return 0 for fail, 1 for match.
- */
-match( mask, str )
-	register char *mask;
-	register char *str;
-{
-	register char flush;
-
-	while( *mask ) {
-		if( ! *str ) return( 0 );
-		switch( *mask ) {
-		case '*':
-			if( *(++mask) == 0 ) return( 1 );		/* trailing '*' match */
-			while( *str ) {
-				if( match( mask, str )) return( 1 );
-				++str;
-			}
-			return( 0 );
-		case '[':			/* character class */
-			++mask;
-			flush = 0;
-			while( *mask && (*mask != ']') ) {
-				if( !flush )
-					if( (*mask == *str) ||
-						(( *mask == '-' ) &&
-							 (*(mask-1) <= *str) && (*(mask+1) >= *str)))
-						flush = 1;
-				++mask;
-			}
-			if( (! *mask) || (! flush) ) return( 0 );
-		case '?':			/* match any single character */
-			goto bump;
-		case '\\':			/* quote the single character */
-			++mask;
-		}
-		if( *mask != *str ) return( 0 );
-bump:
-		++mask;
-		++str;
-	}
-	if( *str ) return( 0 );		/* str has chars unmatched, no good */
-	return( 1 );
-}
-
-/* mesg
- *	write out a message to STDOUT.
- */
-mesg( str )
-	char *str;
-{
-	write( STDOUT, str, strlen( str ) );
-}
-
-/* errmesg
- *	write out a message to STDERR
- */
-errmesg( str )
-	char *str;
-{
-	write( STDERR, str, strlen( str ) );
-}
-
-/* vtocerr
- *	Print out the error indicating where the error occurred and exit
- */
-vtocerr( vtrack, vsec, vrc )
-	int vtrack, vsec, vrc;
-{
-	sprintf( lbuf,
-		 "I/O error on VTOC, slot %d, drive %d, track %d, sector %d, rc=%d\n",
-		slot, drive, vtrack, vsec, 0 - vrc );
-	errmesg( lbuf );
-	exit( 1 );
-}
-
-/* header
- *		Print out the header message if this is a long listing.
- */
-header()
-{
-	sprintf( lbuf, "Slot %d, Drive %d, Volume %d:  %d files\n",
-		slot, drive, vol, dtot );
-	mesg( lbuf );
-	sprintf( lbuf, "Total sectors: %d, free: %d = %ldK\n",
-		tpd * spt, free_secs, ((long) free_secs * bps)/1024 );
-	mesg( lbuf );
-	lcnt = 2;
-}
-
+ END OF ARCHIVE