[comp.sys.ibm.pc] Directory manipulation under Turbo-C.

naughton@sun.soe.clarkson.edu (Patrick Naughton) (02/11/88)

I saw some comment about getting directories under turbo-c on
comp.sys.ibm.pc.digest.  I wrote this years ago for Turbo-Pascal
and converted it to Turbo-C recently.  There are limited docs in
the form of a comment in the header file, dir.h.  The test program
dirtest.c should be enough to show how to use the routines in dir.c.

Have fun...
-Patrick
(naughton@sun.soe.clarkson.edu)

#!/bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #!/bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	dir.c
#	dir.h
#	dirtest.c
# This archive created: Thu Feb 11 02:18:10 1988
export PATH; PATH=/bin:$PATH
if test -f 'dir.c'
then
	echo shar: over-writing existing file "'dir.c'"
fi
cat << \SHAR_EOF > 'dir.c'
/*
 *
 * DIR.C - Directory manipulation routines.
 *
 * Copyright (c) 1988 - Patrick Naughton - (naughton@sun.soe.clarkson.edu)
 *    23 Pleasant Street, #3  -  Potsdam, NY  13676  -  (315) 265-2853
 *
 * This code may be freely copied and distributed without charge.
 * If you change and redistribute it please make a note below.
 *
 * Revision history:
 *   8-Feb-88: (PJN) Created.
 *
 */

#include <stdio.h>
#include <string.h>
#include <alloc.h>
#include <dos.h>
#include <dir.h>

#include "dir.h"

typedef	int	boolean;

#define	TRUE	1
#define	FALSE	0


char	getDrive(void)
{
	return((char) getdisk() + 'A');
}


void	setDrive(char drive)
{
	setdisk((int) (drive - 'A'));
}


long	diskSpace(char drive)
{
struct	dfree	d;

	getdfree((int) (drive - 'A') + 1, &d);
	return((long) d.df_avail * d.df_bsec * d.df_sclus);
}


void	volumeLabel(char drive, char *vl)
{
struct	ffblk	dtArea;
boolean	done;
char	*path = "x:\\*.*";

	path[0] = drive;
	done = findfirst(path, &dtArea, FA_LABEL);
	while (!done) {
	    if ((dtArea.ff_attrib & FA_LABEL)) {
		strcpy(vl, dtArea.ff_name);
		if (strlen(vl) > 8) strcpy(&vl[8], &vl[9]);
		return;
	    }
	    done = findnext(&dtArea);
	}
	vl = "missing";
}


void	getEntry(struct fStruct **this1,
		 struct dStruct *d,
		 struct	ffblk *dtArea)
{
struct fStruct *f;

	f = (struct fStruct *) malloc(sizeof(struct fStruct));

	strcpy(f->filename, dtArea->ff_name);

	if (dtArea->ff_attrib & FA_DIREC) {
		f->subDir = TRUE;
		f->size = 0;
		d->dirCount++;
	}
	else {
		f->subDir = FALSE;
		f->size = dtArea->ff_fsize;
		d->fileCount++;
		d->totalSize = d->totalSize + f->size;
	}
	f->hours = dtArea->ff_ftime >> 11;

	if (f->hours > 11)
		f->pm = TRUE;
	else
		f->pm = FALSE;

	if (f->hours > 12) f->hours -= 12;

	f->minutes = (dtArea->ff_ftime >> 5) & 0x3f;
	f->seconds = (dtArea->ff_ftime << 1) & 0x3f;
	f->mm = (dtArea->ff_fdate >> 5) & 0xf;
	f->dd = dtArea->ff_fdate & 0x1f;
	f->yy = 80 + (dtArea->ff_fdate >> 9);
	f->next = NULL;

	*this1 = f;
}


boolean	getDir(char *pattern, struct dStruct *d)
{
struct	ffblk	dtArea;
struct	fStruct	*entryPtr;
int	i;
boolean	done;
char	*drive = "x:";
char	dir[MAXPATH];
char	*name = "????????";
char	*ext = ".???";

	strcpy(d->path, pattern);

	strupr(d->path);

	i = fnsplit(d->path, drive, dir, name, ext);

	if (!(i & DRIVE))	drive[0] = getDrive();
	if (!(i & DIRECTORY))	{
		getcurdir(1 + (int) (drive[0] - 'A'), &dir[1]);
		dir[0] = '\\';
		dir[strlen(dir) + 1] = '\0';
		dir[strlen(dir)] = '\\';
	}
	if (!(i & FILENAME))	name = "*";
	if (!(i & EXTENSION))	ext = ".*";

	fnmerge(d->path, drive, dir, name, ext);

	volumeLabel(drive[0], d->volume);
	d->freespace = diskSpace(drive[0]);
	d->totalSize = 0;
	d->fileCount = 0;
	d->dirCount = 0;

	done = findfirst(d->path, &dtArea, FA_DIREC);
	if (done) return(FALSE);

	getEntry(&(d->entries), d, &dtArea);

	entryPtr = d->entries;

	while (!done) {
		done = findnext(&dtArea);
		if (!done) {
			getEntry(&(entryPtr->next), d, &dtArea);
			entryPtr = entryPtr->next;
		}
	};
	return(TRUE);
}



void	 dumpEntry(struct fStruct *f)
{
	if (f->next != NULL) dumpEntry(f->next);
	free(f);
}

void	 dumpDir(struct dStruct *d)
{
	if (d->entries != NULL) dumpEntry(d->entries);
	d->entries = NULL;
	d->volume[0] = '\0';
	d->freespace = 0;
	d->totalSize = 0;
	d->dirCount = 0;
	d->fileCount = 0;
	d->path[0] = '\0';
}


boolean	getNiceDir(char *pattern, struct dStruct *d)
{
boolean	i;
struct	fStruct	*temp;

	i = getDir(pattern, d);
	if (i) {
	    if (!strcmp(d->entries->filename, ".")) {
		temp = d->entries->next;
		free(d->entries);
		d->entries = temp;
		d->dirCount--;
	    }
	    if (!strcmp(d->entries->filename, ".."))
		strcpy(d->entries->filename, "<parent>");
	}
	return(i);
}

SHAR_EOF
if test -f 'dir.h'
then
	echo shar: over-writing existing file "'dir.h'"
fi
cat << \SHAR_EOF > 'dir.h'
/*
 *
 * DIR.H - Directory manipulation declarations.
 *
 * Copyright (c) 1988 - Patrick Naughton - (naughton@sun.soe.clarkson.edu)
 *    23 Pleasant Street, #3  -  Potsdam, NY  13676  -  (315) 265-2853
 *
 * This code may be freely copied and distributed without charge.
 * If you change and redistribute it please make a note below.
 *
 * Revision history:
 *   8-Feb-88: (PJN) Created.
 *
 * getDrive() returns a char for the current drive (i.e. A, B, C...)
 * setDrive('A') would set the current drive to A:.
 * diskSpace('C') would return the number of bytes remaining on C:
 * volumeLabel('C', vl) puts the volume lable from C: in the string vl.
 * getDir("C:\*.c", &d) puts the directory of all .c files in the root of C:.
 * dumpDir(&d) cleans up the dynamic memory used by getDir().
 * getNiceDir() deletes "." and replaces ".." with "<parent>".
 *
 */

struct fStruct {
	char	filename[13];
	int	subDir, pm;
	int	hours, minutes, seconds, dd, mm, yy;
	long	size;
struct	fStruct	*next;
	};

struct dStruct {
	char	volume[13];
	char	path[80];
	long	freespace, totalSize;
	int	dirCount, fileCount;
struct	fStruct	*entries;
	};

char	getDrive(void);
void	setDrive(char drive);
long	diskSpace(char drive);
void	volumeLabel(char drive, char *vl);
int	getDir(char *pattern, struct dStruct *d);
void	dumpDir(struct dStruct *d);
int	getNiceDir(char *pattern, struct dStruct *d);


SHAR_EOF
if test -f 'dirtest.c'
then
	echo shar: over-writing existing file "'dirtest.c'"
fi
cat << \SHAR_EOF > 'dirtest.c'
/*
 *
 * DIRTEST.C - Test the directory manipulation routines.
 *
 * Copyright (c) 1988 - Patrick Naughton - (naughton@sun.soe.clarkson.edu)
 *    23 Pleasant Street, #3  -  Potsdam, NY  13676  -  (315) 265-2853
 *
 * This code may be freely copied and distributed without charge.
 * If you change and redistribute it please make a note below.
 *
 * Revision history:
 *   8-Feb-88: (PJN) Created.
 *
 */

#include <stdio.h>
#include <string.h>
#include <alloc.h>
#include <dos.h>
#include <dir.h>

#include "dir.h"

typedef	int	boolean;

#define	TRUE	1
#define	FALSE	0


void	showDir(struct dStruct *d)
{
struct fStruct *nextPtr;

	printf("Volume %s\n", d->volume);
	printf("Directory of %s\n", d->path);

	nextPtr = d->entries;
	while(nextPtr) {
		printf("%14s	", nextPtr->filename);
		if (nextPtr->subDir) puts("  <dir>");
		else {
			printf("%7ld ", nextPtr->size);

			if (nextPtr->mm < 10) printf(" ");
			printf("%d/", nextPtr->mm);
			if (nextPtr->dd < 10) printf("0");
			printf("%d/", nextPtr->dd);
			if (nextPtr->yy < 10) printf("0");
			printf("%d ", nextPtr->yy);

			if (nextPtr->hours < 10) printf(" ");
			printf("%d:", nextPtr->hours);
			if (nextPtr->minutes < 10) printf("0");
			printf("%d:", nextPtr->minutes);
			if (nextPtr->seconds < 10) printf("0");
			printf("%d", nextPtr->seconds);
			if (nextPtr->pm) puts("p");
			    else puts("a");
		}
		nextPtr = nextPtr->next;
	}
	printf("%d files and %d directories using %ld bytes out of %ld remaining.\n",
		d->fileCount, d->dirCount, d->totalSize, d->freespace);
}


main(int argc, char *argv[])
{
struct	dStruct	dir;
char	*path = "                                          ";

	if (argc == 1) path = "*.*";
	else path = argv[1];

	if (!getNiceDir(path, &dir)) {
		puts(path);
		puts("Path not found!");
	}
	else {
		showDir(&dir);
		dumpDir(&dir);
	}
}

SHAR_EOF
#	End of shell archive
exit 0