ARC for BSD4.2 (optional part 5 of 5)

turner at imagen.UUCP turner at imagen.UUCP
Tue Aug 5 08:44:55 AEST 1986


This is my hacked version of the arc program that was posted to the net, I
have modified it to run under Unix BSD4.2. if you want it to run under 
SVR2 you probably will have to change the opendir, scandir, and closedir
calls, I don't really know System 5. IMPORTANT: this is a BETA test version
i doubt severly that there are no bugs, please report any that you find to me.

1) I don't have a PC handy so i have no idea if it still works on the PC; to
	compile it for the PC edit arc.h and arcs.c and change the #defines,
	the define ST is for the Atari 520ST and with luck that will be done
	shortly. If you compile it for the PC you will need the routines for 
	opendir etc. that are in shar part 5, otherwise you can ignore that 
	shar file.
2) the Makefile is configured to compile for debugging (-g) (shows ya what 
	kind of faith i have in my code (:-)
3) everything seems to work for both arc files created on the PC and on BSD4.2
	with the exception of the t (test) option which gives strange results,
	i suspect the problem is in the code not the archive
4) there is one bug that i know of, if you archive a 0 length file, arc will
	blow up (floating point exception) when you try to extract it; the
	question is should the check happen when you add the file, extract
	it, or should if create a 0 length file ? you decide.
5) send flames etc. to me, because of the way postnews works here my signature
	will probably be at the end of each shar file, if not its:
----
Name:	James M. Turner
Mail:	Imagen Corp. 2650 San Tomas Expressway, P.O. Box 58101
        Santa Clara, CA 95052-8101
AT&T:	(408) 986-9400
UUCP:	...{decvax,ucbvax}!decwrl!imagen!turner
CompuServe: 76327,1575
GEnie     : D-ARCANGEL
----

#! /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:
#	dir.h
#	dir.c
#	fmatch.c
#	scandir.c
# This archive created: Mon Aug  4 14:48:52 1986
# By:	D'arc Angel (The Houses of the Holy)
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'dir.h'
then
	echo shar: "will not over-write existing file 'dir.h'"
else
cat << \SHAR_EOF > 'dir.h'
/*
 * $Header: dir.h,v 1.1 86/07/04 08:31:37 turner Exp $
 */

/*
 * $Log:	dir.h,v $
 * Revision 1.1  86/07/04  08:31:37  turner
 * Initial revision
 * 
 * 
 */

#ifndef	DIRSIZ
#define	DIRSIZ	13
#endif

/*
 *	Structure returned by search calls
 */
struct	direct
{
	char	rsvd[21];		/* reserved for dos */
	char	d_attr;			/* file attribute */
	long	d_time;			/* modified time */
	long	d_size;			/* file size */
	char	d_name[DIRSIZ];		/* directory entry name */
};

typedef struct _dirdesc
{
	int	d_magic;		/* magic number 1234 */
	int	d_length;		/* number of directory entries */
	int	d_pos;			/* current position */
	struct direct **namelist;	/* list of directory entries */
} DIR;

#define DMAGIC 0x1234

DIR *opendir();
struct direct *readdir();
long telldir();
SHAR_EOF
fi
if test -f 'dir.c'
then
	echo shar: "will not over-write existing file 'dir.c'"
else
cat << \SHAR_EOF > 'dir.c'
static char *RCSid = "$Header: dir.c,v 1.1 86/07/04 08:31:25 turner Exp $";

/*
 * $Log:	dir.c,v $
 * Revision 1.1  86/07/04  08:31:25  turner
 * Initial revision
 * 
 * 
 */

/*
 *	dir.c - contains routines which behave (hopefully) like the
 *		similar versions on 4.2 BSD.
 *
 */
#include <errno.h>
#include "dir.h"

extern int errno;
extern char *calloc();

/*
 *	opendir - opens given directory and reads its contents into memory.
 *	Other functions use this data or the DIR structure to do their work.
 */
DIR *
opendir(dirname)
char *dirname;
{
	struct direct **namelist;
	DIR *dirptr;

	dirptr = (DIR *)calloc(1, sizeof(DIR));
	if(dirptr == (DIR *)0)
	{
		errno = ENOMEM;
		return((DIR *)0);
	}
	dirptr->d_magic = DMAGIC;
	dirptr->d_pos = 0;
	dirptr->d_length = scandir(dirname, &(dirptr->namelist),
		(int (*)())0, (int (*)())0);
	if(dirptr->d_length < 0)
	{
		free((char *)dirptr);
		return((DIR *)0);
	}
	return(dirptr);
}

/*
 *	readdir - returns the next directory structure from the list and
 *	updates values in the DIR structure.
 */
struct direct *
readdir(dirptr)
DIR *dirptr;
{
	if(dirptr->d_magic != DMAGIC)
	{
		errno = ENOTDIR;
		return((struct direct *)0);
	}
	if(dirptr->d_pos >= dirptr->d_length)
	{
		errno = ENFILE;
		return((struct direct *)0);
	}
	return(dirptr->namelist[dirptr->d_pos++]);
}

/*
 *	telldir - return the current position of the directory.
 */
long
telldir(dirptr)
DIR *dirptr;
{
	if(dirptr->d_magic != DMAGIC)
	{
		errno = ENOTDIR;
		return(-1L);
	}
	return((long)dirptr->d_pos);
}

/*
 *	seekdir - position the given DIR stream to position given.
 */
seekdir(dirptr, loc)
DIR *dirptr;
long loc;
{
	if(dirptr->d_magic != DMAGIC)
	{
		errno = ENOTDIR;
		return(-1);
	}
	if(loc > (long)dirptr->d_length)
	{
		errno = EINVAL;
		return(-1);
	}
	dirptr->d_pos = (int)loc;
	return(0);
}

/*
 *	rewinddir - rewind given DIR to beginning
 */
rewinddir(dirptr)
DIR *dirptr;
{
	if(dirptr->d_magic != DMAGIC)
	{
		errno = ENOTDIR;
		return(-1);
	}
	dirptr->d_pos = 0;
	return(0);
}

/*
 *	closedir - close given directory. destroy given DIR struct so we
 *	know it is closed.
 */
closedir(dirptr)
DIR *dirptr;
{
	if(dirptr->d_magic != DMAGIC)
	{
		errno = ENOTDIR;
		return(-1);
	}
	dirptr->d_magic = ~DMAGIC;	/* mess it up a little */
	freedir(dirptr->namelist);
	free(dirptr);
	return(0);
}
SHAR_EOF
fi
if test -f 'fmatch.c'
then
	echo shar: "will not over-write existing file 'fmatch.c'"
else
cat << \SHAR_EOF > 'fmatch.c'
static char *RCSid = "$Header: fmatch.c,v 1.1 86/07/04 08:31:47 turner Exp $";

/*
 * $Log:	fmatch.c,v $
 * Revision 1.1  86/07/04  08:31:47  turner
 * Initial revision
 * 
 * 
 */

#include <stdio.h>

#define ASTERISK '*'		/* The '*' metacharacter */
#define QUESTION '?'		/* The '?' metacharacter */
#define LEFT_BRACKET '['	/* The '[' metacharacter */
#define RIGHT_BRACKET ']'	/* The ']' metacharacter */

#define IS_OCTAL(ch) (ch >= '0' && ch <= '7')

typedef int BOOLEAN;
#define VOID int
#define TRUE 1
#define FALSE 0
#define EOS '\000'

static BOOLEAN do_list ();
static char nextch ();
static VOID list_parse ();


/*
 *  FUNCTION
 *
 *	match   test string for wildcard match
 *
 *  SYNOPSIS
 *
 *	BOOLEAN match (string, pattern)
 *	register char *string;
 *	register char *pattern;
 *
 *  DESCRIPTION
 *
 *	Test string for match using pattern.  The pattern may
 *	contain the normal shell metacharacters for pattern
 *	matching.  The '*' character matches any string,
 *	including the null string.  The '?' character matches
 *	any single character.  A list of characters enclosed
 *	in '[' and ']' matches any character in the list.
 *	If the first character following the beginning '['
 *	is a '!' then any character not in the list is matched.
 *
 */


/*
 *  PSEUDO CODE
 *
 *	Begin match
 *	    Switch on type of pattern character
 *		Case ASTERISK:
 *		    Attempt to match asterisk
 *		    Break
 *		Case QUESTION MARK:
 *		    Attempt to match question mark
 *		    Break
 *		Case EOS:
 *		    Match is result of EOS on string test
 *		    Break
 *		Case default:
 *		    If explicit match then
 *			Match is result of submatch
 *		    Else
 *			Match is FALSE
 *		    End if
 *		    Break
 *	    End switch
 *	    Return result of match test
 *	End match
 *
 */

static BOOLEAN match (string, pattern)
register char *string;
register char *pattern;
{
    register BOOLEAN ismatch;

    ismatch = FALSE;
    switch (*pattern) {
	case ASTERISK:
	    pattern++;
	    do {
		ismatch = match (string, pattern);
	    } while (!ismatch && *string++ != EOS);
	    break;
	case QUESTION:
	    if (*string != EOS) {
		ismatch = match (++string, ++pattern);
	    }
	    break;
	case EOS:
	    if (*string == EOS) {
		ismatch = TRUE;
	    }
	    break;
	case LEFT_BRACKET:
	    if (*string != EOS) {
		ismatch = do_list (string, pattern);
	    }
	    break;
	default:
	    if (tolower(*string) == tolower(*pattern))
	    {
	    	string++;
	    	pattern++;
		ismatch = match (string, pattern);
	    } else {
		ismatch = FALSE;
	    }
	    break;
    }
    return (ismatch);
}


/*
 *  FUNCTION
 *
 *	do_list    process a list and following substring
 *
 *  SYNOPSIS
 *
 *	static BOOLEAN do_list (string, pattern)
 *	register char *string;
 *	register char *pattern;
 *
 *  DESCRIPTION
 *
 *	Called when a list is found in the pattern.  Returns
 *	TRUE if the current character matches the list and
 *	the remaining substring matches the remaining pattern.
 *
 *	Returns FALSE if either the current character fails to
 *	match the list or the list matches but the remaining
 *	substring and subpattern's don't.
 *
 *  RESTRICTIONS
 *
 *	The mechanism used to match characters in an inclusive
 *	pair (I.E. [a-d]) may not be portable to machines
 *	in which the native character set is not ASCII.
 *
 *	The rules implemented here are:
 *
 *		(1)	The backslash character may be
 *			used to quote any special character.
 *			I.E.  "\]" and "\-" anywhere in list,
 *			or "\!" at start of list.
 *
 *		(2)	The sequence \nnn becomes the character
 *			given by nnn (in octal).
 *
 *		(3)	Any non-escaped ']' marks the end of list.
 *
 *		(4)	A list beginning with the special character
 *			'!' matches any character NOT in list.
 *			The '!' character is only special if it
 *			is the first character in the list.
 *
 */


/*
 *  PSEUDO CODE
 *
 *	Begin do_list
 *	    Default result is no match
 *	    Skip over the opening left bracket
 *	    If the next pattern character is a '!' then
 *		List match gives FALSE
 *		Skip over the '!' character
 *	    Else
 *		List match gives TRUE
 *	    End if
 *	    While not at closing bracket or EOS
 *		Get lower and upper bounds
 *		If character in bounds then
 *		    Result is same as sense flag.
 *		    Skip over rest of list
 *		End if
 *	    End while
 *	    If match found then
 *		If not at end of pattern then
 *		    Call match with rest of pattern
 *		End if
 *	    End if
 *	    Return match result
 *	End do_list
 *
 */

static BOOLEAN do_list (string, pattern)
register char *string;
char *pattern;
{
    register BOOLEAN ismatch;
    register BOOLEAN if_found;
    register BOOLEAN if_not_found;
    auto char lower;
    auto char upper;

    pattern++;
    if (*pattern == '!') {
	if_found = FALSE;
	if_not_found = TRUE;
	pattern++;
    } else {
	if_found = TRUE;
	if_not_found = FALSE;
    }
    ismatch = if_not_found;
    while (*pattern != ']' && *pattern != EOS) {
	list_parse (&pattern, &lower, &upper);
	if (*string >= lower && *string <= upper) {
	    ismatch = if_found;
	    while (*pattern != ']' && *pattern != EOS) {pattern++;}
	}
    }
    if (*pattern++ != ']') {
	fprintf (stderr, "warning - character class error\n");
    } else {
	if (ismatch) {
	    ismatch = match (++string, pattern);
	}
    }
    return (ismatch);
}


/*
 *  FUNCTION
 *
 *	list_parse    parse part of list into lower and upper bounds
 *
 *  SYNOPSIS
 *
 *	static VOID list_parse (patp, lowp, highp)
 *	char **patp;
 *	char *lowp;
 *	char *highp;
 *
 *  DESCRIPTION
 *
 *	Given pointer to a pattern pointer (patp), pointer to
 *	a place to store lower bound (lowp), and pointer to a
 *	place to store upper bound (highp), parses part of
 *	the list, updating the pattern pointer in the process.
 *
 *	For list characters which are not part of a range,
 *	the lower and upper bounds are set to that character.
 *
 */

static VOID list_parse (patp, lowp, highp)
char **patp;
char *lowp;
char *highp;
{
    *lowp = nextch (patp);
    if (**patp == '-') {
	(*patp)++;
	*highp = nextch (patp);
    } else {
	*highp = *lowp;
    }
}


/*
 *  FUNCTION
 *
 *	nextch    determine next character in a pattern
 *
 *  SYNOPSIS
 *
 *	static char nextch (patp)
 *	char **patp;
 *
 *  DESCRIPTION
 *
 *	Given pointer to a pointer to a pattern, uses the pattern
 *	pointer to determine the next character in the pattern,
 *	subject to translation of backslash-char and backslash-octal
 *	sequences.
 *
 *	The character pointer is updated to point at the next pattern
 *	character to be processed.
 *
 */

static char nextch (patp)
char **patp;
{
    register char ch;
    register char chsum;
    register int count;

    ch = *(*patp)++;
    if (ch == '\\') {
	ch = *(*patp)++;
	if (IS_OCTAL (ch)) {
	    chsum = 0;
	    for (count = 0; count < 3 && IS_OCTAL (ch); count++) {
		chsum *= 8;
		chsum += ch - '0';
		ch = *(*patp)++;
	    }
	    (*patp)--;
	    ch = chsum;
	}
    }
    return (ch);
}

/*
 *	Filename match - here, *.* matches everything
 */

BOOLEAN fmatch (string, pattern)
char *string;
char *pattern;
{
    char *ptr;

    if(*string && !strcmp(pattern, "*.*"))
    	return(TRUE);
    return(match(string, pattern));
}
SHAR_EOF
fi
if test -f 'scandir.c'
then
	echo shar: "will not over-write existing file 'scandir.c'"
else
cat << \SHAR_EOF > 'scandir.c'
static char *RCSid = "$Header: scandir.c,v 1.1 86/07/04 08:31:49 turner Exp $";

/*
 * $Log:	scandir.c,v $
 * Revision 1.1  86/07/04  08:31:49  turner
 * Initial revision
 * 
 * 
 */

#include <dos.h>
#include <errno.h>
#include "dir.h"
#define NULL (char *)0

static struct direct buffer;
extern int errno;

extern char *calloc(), *malloc(), *realloc();

scandir(dirname, namelist, select, compar)
char *dirname;
struct direct *(*namelist[]);
int (*select)();
int (*compar)();
{
	register struct direct **names;
	register int dirno;
	union REGS sregs, oregs;
	struct SREGS segregs;
	char *ptr, *paths;

	names = (struct direct **)calloc(1, sizeof(struct direct *));
	paths = calloc(128, 1);
	if(names == (struct direct **)0 || paths == NULL)
	{
		errno = ENOMEM;
		return(-1);
	}
	strcpy(paths, dirname);
	ptr = &paths[strlen(paths) - 1];
	if(*ptr == '/' || *ptr == '\\')
		*ptr = '\0';
	strcat(paths, "/*.*");

	segread(&segregs);		/* set up segment registers */
	ptr = (char *)&buffer;
	sregs.h.ah = 0x1a;		/* set DTA to buffer */
	sregs.x.dx = FP_OFF(ptr);	/* offset */
#ifdef	M_I86LM
	segregs.ds = FP_SEG(ptr);	/* pointer in large model */
#endif	M_I86LM
	intdosx(&sregs, &oregs, &segregs);
	sregs.x.ax = 0x4e00;		/* search for first */
	sregs.x.cx = 0x1f;		/* include all attributes */
	sregs.x.dx = FP_OFF(paths);	/* offset to path */
#ifdef	M_I86LM
	segregs.ds = FP_SEG(paths);	/* segment for large model */
#endif	M_I86LM
	intdosx(&sregs, &oregs, &segregs);
	if(oregs.x.cflag)
	{
		errno = ENOTDIR;
		return(-1);
	}
	sregs.x.ax = 0x4f00;		/* search for next */
	for(dirno = 0; oregs.x.cflag == 0; intdosx(&sregs, &oregs, &segregs))
	{
		for(ptr = buffer.d_name; *ptr; ptr++)
			*ptr = tolower(*ptr);
		if(select == (int (*)())0 || (*select)(&buffer))
		{
			names = (struct direct **)realloc((char *)names,
				(dirno + 2)*sizeof(struct direct *));
			if(names == (struct direct **)0)
			{
				errno = ENOMEM;
				return(-1);
			}
			names[dirno] = (struct direct *)calloc(1,
				sizeof(struct direct));
			if(names[dirno] == (struct direct *)0)
			{
				errno = ENOMEM;
				return(-1);
			}
			*names[dirno] = buffer;
			names[++dirno] = (struct direct *)0;
		}
	}

	if(compar != (int (*)())0)
		qsort((char *)names, dirno, sizeof(char *), compar);

	*namelist = names;
	free(paths);			/* free temp space */
	return(dirno);
}

freedir(dirs)
register struct direct **dirs;
{
	register int ii;

	if(dirs == (struct direct **)0)
		return(-1);
	for(ii = 0; dirs[ii] != (struct direct *)0; ii++)
		free(dirs[ii]);
	free(dirs);
	return(0);
}

alphasort(dirptr1, dirptr2)
struct direct **dirptr1, **dirptr2;
{
	return(strcmp((*dirptr1)->d_name, (*dirptr2)->d_name));
}
SHAR_EOF
fi
exit 0
#	End of shell archive
-- 
----
	"I ain't gay, but there are sure times when i wish i could say
		that i wasn't straight"

Name:	James M. Turner
Mail:	Imagen Corp. 2650 San Tomas Expressway, P.O. Box 58101
        Santa Clara, CA 95052-8101
AT&T:	(408) 986-9400
UUCP:	...{decvax,ucbvax}!decwrl!imagen!turner
CompuServe: 76327,1575
GEnie     : D-ARCANGEL



More information about the Comp.sources.unix mailing list