[comp.sources.amiga] v02i005: Portable Directory Library

mwm@violet.berkeley.edu (Mike Meyer) (07/22/87)

[moderators note:  These were actually sent to me by Rich Salz (moderator
of comp.sources.unix) who got them from Mike.  This was in response to
a call from Rich for portable directory libraries for all machines...
   thanx Mike!]

Here's what I did. This is built to reflect the 4BSD manual pages, not
the SysV/dpANS manual pages.

I now know how to get the telldir/seekdir pair to work correctly with
multiple tell()s, but don't have much motivation to do so. If someone
out there does it, or is interested in doing it, I'd be interested in
the results or willing to help.

Final note: as with many micros, there's more than one C compiler.
This was written for the Lattice compiler, and uses features known
not to exist in other Amiga compilers. Fixing it should be trivial.

Oh, yeah - sorry for the delay in getting these two you.

	<mike

#! /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
#	ndir.c
# This archive created: Mon Jul 13 21:45:37 1987
# By:	Mike (My watch has windows) Meyer (Missionaria Phonibalonica)
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'dir.h'" '(1708 characters)'
if test -f 'dir.h'
then
	echo shar: "will not over-write existing file 'dir.h'"
else
sed 's/^	X//' << \SHAR_EOF > 'dir.h'
	X#ifndef DIR_H
	X#define DIR_H
	X
	X#ifndef	EXEC_TYPES_H
	X#include "exec/types.h"
	X#endif
	X
	X#ifndef	LIBRARIES_DOS_H
	X#include "libraries/dos.h"
	X#endif
	X
	X#ifndef	LIBRARIES_DOSEXTENS_H
	X#include "libraries/dosextens.h"
	X#endif
	X/*
	X * MAXNAMELEN is the maximum length a file name can be. The direct structure
	X * is lifted form 4BSD, and has not been changed so that code which uses
	X * it will be compatable with 4BSD code. d_ino and d_reclen are unused,
	X * and will probably be set to some non-zero value.
	X */
	X#define	MAXNAMLEN	31		/* AmigaDOS file max length */
	X
	Xstruct	direct {
	X	ULONG	d_ino ;			/* unused - there for compatability */
	X	USHORT	d_reclen ;		/* ditto */
	X	USHORT	d_namlen ;		/* length of string in d_name */
	X	char	d_name[MAXNAMLEN + 1] ;	/* name must be no longer than this */
	X};
	X/*
	X * The DIRSIZ macro gives the minimum record length which will hold
	X * the directory entry.  This requires the amount of space in struct direct
	X * without the d_name field, plus enough space for the name with a terminating
	X * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
	X */
	X
	X#undef DIRSIZ
	X#define DIRSIZ(dp) \
	X    ((sizeof(struct direct) - (MAXNAMLEN+1)) + (((dp) -> d_namlen+1 + 3) &~ 3))
	X/*
	X * The DIR structure holds the things that AmigaDOS needs to know about
	X * a file to keep track of where it is and what it's doing.
	X */
	X
	Xtypedef struct {
	X	struct FileInfoBlock	d_info ,	/* Default info block */
	X				d_seek ;	/* Info block for seeks */
	X	struct FileLock		*d_lock ;	/* Lock on directory */
	X	} DIR ;
	X	
	Xextern	DIR *opendir(char *) ;
	Xextern	struct direct *readdir(DIR *) ;
	Xextern	long telldir(DIR *) ;
	Xextern	void seekdir(DIR *, long) ;
	Xextern	void rewinddir(DIR *) ;
	Xextern	void closedir(DIR *) ;
	X#endif	DIR_H
SHAR_EOF
if test 1708 -ne "`wc -c < 'dir.h'`"
then
	echo shar: "error transmitting 'dir.h'" '(should have been 1708 characters)'
fi
fi
echo shar: "extracting 'ndir.c'" '(2486 characters)'
if test -f 'ndir.c'
then
	echo shar: "will not over-write existing file 'ndir.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'ndir.c'
	X/*
	X * ndir - routines to simulate the 4BSD new directory code for AmigaDOS.
	X */
	X#include <dir.h>
	X
	XDIR *
	Xopendir(dirname) char *dirname; {
	X	register DIR	*my_dir, *AllocMem(int, int) ;
	X	struct FileLock	*Lock(char *, int), *CurrentDir(struct FileLock *) ;
	X
	X	if ((my_dir = AllocMem(sizeof(DIR), 0)) == NULL) return NULL ;
	X
	X
	X	if (((my_dir -> d_lock = Lock(dirname, ACCESS_READ)) == NULL)
	X	/* If we can't examine it */
	X	||  !Examine(my_dir -> d_lock, &(my_dir -> d_info))
	X	/* Or it's not a directory */
	X	||  (my_dir -> d_info . fib_DirEntryType < 0)) {
	X		FreeMem(my_dir, sizeof(DIR)) ;
	X		return NULL ;
	X		}
	X	return my_dir ;
	X	}
	X
	Xstruct direct *
	Xreaddir(my_dir) DIR *my_dir; {
	X	static struct direct	result ;
	X
	X	if (!ExNext(my_dir -> d_lock, &(my_dir -> d_info))) return NULL ;
	X
	X	result . d_reclen = result . d_ino = 1 ;	/* Not NULL! */
	X	(void) strcpy(result . d_name, my_dir -> d_info . fib_FileName) ;
	X	result . d_namlen = strlen(result . d_name) ;
	X	return &result ;
	X	}
	X
	Xvoid
	Xclosedir(my_dir) DIR *my_dir; {
	X
	X	UnLock(my_dir -> d_lock) ;
	X	FreeMem(my_dir, sizeof(DIR)) ;
	X	}
	X/*
	X * telldir and seekdir don't work quite right. The problem is that you have
	X * to save more than a long's worth of stuff to indicate position, and it's
	X * socially unacceptable to alloc stuff that you don't free later under
	X * AmigaDOS. So we fake it - you get one level of seek, and dat's all.
	X * As of now, these things are untested.
	X */
	X#define DIR_SEEK_RETURN		((long) 1)	/* Not 0! */
	Xlong
	Xtelldir(my_dir) DIR *my_dir; {
	X
	X	my_dir -> d_seek = my_dir -> d_info ;
	X	return (long) DIR_SEEK_RETURN ;
	X	}
	X
	Xvoid
	Xseekdir(my_dir, where) DIR *my_dir; long where; {
	X
	X	if (where == DIR_SEEK_RETURN)
	X		my_dir -> d_info = my_dir -> d_seek ;
	X	else	/* Makes the next readdir fail */
	X		setmem((char *) my_dir, sizeof(DIR), 0) ;
	X	}
	X
	Xvoid
	Xrewinddir(my_dir) DIR *my_dir; {
	X
	X	if (!Examine(my_dir -> d_lock, &(my_dir -> d_info)))
	X		setmem((char *) my_dir, sizeof(DIR), 0) ;
	X	}
	X#ifdef	TEST
	X/*
	X * Simple code to list the files in the argument directory,
	X *	lifted straight from the man page.
	X */
	X#include <stdio.h>
	Xvoid
	Xmain(argc, argv) int argc; char **argv; {
	X	register DIR		*dirp ;
	X	register struct direct	*dp ;
	X	register char		*name ;
	X
	X	if (argc < 2) name = "" ;
	X	else name = argv[1] ;
	X
	X	if ((dirp = opendir(name)) == NULL) {
	X		fprintf(stderr, "Bogus! Can't opendir %s\n", name) ;
	X		exit(1) ;
	X		}
	X
	X	for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp))
	X		printf("%s ", dp -> d_name) ;
	X	closedir(dirp);
	X	putchar('\n') ;
	X	}
	X#endif	TEST
	X
SHAR_EOF
if test 2486 -ne "`wc -c < 'ndir.c'`"
then
	echo shar: "error transmitting 'ndir.c'" '(should have been 2486 characters)'
fi
fi
exit 0
#	End of shell archive