Article-I.D.: osu-eddi.1149
Posted: Sun Jan 19 22:15:39 1986
Date-Received: Mon, 20-Jan-86 06:38:41 EST
Distribution: net
Organization: Ohio State Univ., CIS Dept., Cols, Oh.
Lines: 701
Rick Shaffner asked me to forward his LS program and wildcard routines
here. The routines (used by LS) provide a means of looking up
files using the familiar "?" and "*" wildcard characters. There is also
a jacket routine that handles redirection of output to seperate
files when there are multiple (possibly wildcarded) input files.
I will forward any feedback, suggestions, etc. to Rick.
================================Cut Here================================
#! /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:
# ls.c
# wildexp.c
# wildexp.h
# utilskel.c
# This archive created: Sun Jan 19 21:44:00 1986
export PATH; PATH=/bin:$PATH
echo shar: extracting "'ls.c'" '(3071 characters)'
if test -f 'ls.c'
then
echo shar: will not over-write existing file "'ls.c'"
else
sed 's/^ X//' << \SHAR_EOF > 'ls.c'
X/*
X** ls - List directory using unix style wildcards
X**
X** usage: ls [-l] filename
X**
X** -l is an optional flag which will cause the directory listing to
X** be printed one-up with file size and date included. Otherwise
X** directory listing is printed two-up. The listing is NOT
X** sorted.
X**
X** examples:
X** ls *.c print all files which end in ".c"
X** ls -l a* print all files which begin with "a"
X** ls -l a??b* print all files which begin with "a" followed by any
X** two characters followed by "b" and then any other
X** characters
X**
X** Written by: Rick Schaeffer 1/11/86 and placed in public domain.
X** E. 13611 26th Ave.
X** Spokane, Wa. 99216
X** Compuserve ID: 70120,174
X** Bytenet ID: ricks.
X*/
X
X#include "wildexp.h"
X
Xstruct find fwk;
X
Xint totfiles;
Xlong totsize;
X
Xmain(argc,argv)
Xint argc;
Xchar *argv[];
X{
X char pattern[128];
X int retval,lflag;
X char *fferror();
X
X lflag = 0;
X totfiles = 0;
X totsize = 0;
X if (argc <= 1)
X strcpy(pattern,"*");
X else {
X if (argc == 2) {
X strncpy(pattern,argv[1],120);
X if (strcmp(pattern,"-l") == 0) {
X strcpy(pattern,"*");
X lflag = 1;
X }
X }
X else {
X strncpy(pattern,argv[2],120);
X if (strcmp(argv[1],"-l") == 0)
X lflag = 1;
X }
X }
X if (pattern[strlen(pattern)-1] == ':')
X strcat(pattern,"*");
X retval = findfirst(pattern,&fwk);
X if (retval > 0) {
X printf("ls: Error - %s\n",fferror(retval));
X find_cleanup(&fwk);
X exit(1);
X }
X while (retval <= 0) {
X if (retval < 0)
X break;
X if (lflag)
X print_long(&fwk);
X else
X print_short(&fwk);
X retval = findnext(&fwk);
X }
X printf("\n");
X if (lflag)
X printf("%d Files containing %ld bytes.\n",totfiles,totsize);
X find_cleanup(&fwk);
X}
X
Xchar *dates(s,dss)
Xchar *s;
Xstruct DateStamp *dss;
X{
X int year,month,day;
X static char dpm[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
X
X year = 1978;
X day = dss->ds_Days;
X while (day >= 366) {
X if ((year-1976) % 4 == 0) {
X day -= 366;
X year++;
X }
X else
X if ((year-1976) % 4 != 0 && day >= 365) {
X day -= 365;
X year++;
X }
X }
X if ((year-1976) % 4 == 0) {
X day = day % 366;
X dpm[2] = 29;
X }
X else {
X day = day % 365;
X dpm[2] = 28;
X }
X for (month = 0; day > dpm[month]; month++)
X day -= dpm[month];
X sprintf(s,"%02d/%02d/%04d",month+1,day,year);
X return(s);
X}
X
Xchar *times(s,dss)
Xchar *s;
Xstruct DateStamp *dss;
X{
X int hours,minutes,seconds;
X
X seconds = dss->ds_Tick / 50;
X seconds %= 60;
X minutes = dss->ds_Minute;
X hours = minutes / 60;
X minutes %= 60;
X sprintf(s,"%02d:%02d:%02d",hours,minutes,seconds);
X return(s);
X}
X
Xprint_long(fwk)
Xstruct find *fwk;
X{
X struct FileInfoBlock *f;
X char s[12],t[12];
X
X f = fwk->fp;
X if (f->fib_DirEntryType < 0) {
X printf("%-30s %7d %s %s\n",f->fib_FileName,f->fib_Size,
X dates(s,&f->fib_Date),times(t,&f->fib_Date));
X totsize += f->fib_Size;
X }
X else
X printf("%-30s %s\n",f->fib_FileName,dates(s,&f->fib_Date));
X totfiles++;
X}
X
Xprint_short(fwk)
Xstruct find *fwk;
X{
X static int f=0;
X
X printf("%-30s ",fwk->fname);
X if (f == 0)
X f = 1;
X else {
X printf("\n");
X f = 0;
X }
X}
SHAR_EOF
if test 3071 -ne "`wc -c < 'ls.c'`"
then
echo shar: error transmitting "'ls.c'" '(should have been 3071 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'wildexp.c'" '(8739 characters)'
if test -f 'wildexp.c'
then
echo shar: will not over-write existing file "'wildexp.c'"
else
sed 's/^ X//' << \SHAR_EOF > 'wildexp.c'
X/*
X** The following module contains functions which permit wildcard
X** filename expansion using Unix type wildcard characters. This
X** module can be compiled separately and included in the link for
X** any programs which desire it's support. The following functions
X** are present:
X**
X** findfirst - find the first occurance of a file matching
X** the given name which may contain Unix style
X** wildcards.
X** findnext - find the next occurance of a file. Returns
X** 0 if no more matches remain.
X** find_cleanup - release all storage and locks reserved by findfirst
X** and/or findnext. MUST be called before exit!
X** fferror - given an error code returned by findnext, this
X** function returns a pointer to a descriptive
X** error message string.
X** iswild - given a string, this function returns
X** TRUE if the string contains a wildcard character
X** and FALSE if not.
X** wildexp - given a file name and a pointer to a table of
X** pointers, this function will fill the table
X** with a list of file names in the indicated
X** directory which match the given name.
X**
X**
X** Written by: Rick Schaeffer
X** E. 13611 26th Ave.
X** Spokane, Wa. 99216
X** Compuserve ID: 70120,174
X** Bytenet ID: ricks.
X*/
X
X#include "wexp.h"
X
X/*
X** Return values for findfirst and findnext are:
X** 0 = retval ok, find struct "fname" contains name of file found
X** 1 = file name too long
X** 2 = error in parsing
X** 3 = invalid path name
X** 4 = first Examine failed
X** 5 = not a directory
X*/
X
X/* fferror -- return a meaningful error message for findxxx errors */
X** Parameter:
X** errcd - An integer containing the error code returned by findfirst
X** or findnext.
X**
X** Returns:
X** msgptr - A pointer to a meaningful error message
X*/
Xchar *fferror(errcd)
Xint errcd;
X{
X static char *errmsg[] = {
X "Filename too long",
X "Filename invalid",
X "Pathname invalid",
X "Examine failed",
X "Pathname invalid",
X "Error code invalid"
X };
X
X if (--errcd > 4)
X errcd = 5;
X return(errmsg[errcd]);
X}
X
X/* findfirst -- find the first occurance of a given file name in either
X** the given or the current directory.
X** Parameters:
X** name - A pointer to a filename string. May contain wildcard
X** characters ('?' and/or '*'). May optionally contain
X** a directory path. Example: "df0:c/d*" matches all
X** files in directory "df0:c" which begin with the letter
X** "d".
X** fwk - A pointer to a structure which will be filled in by
X** findfirst and used by findnext. Must NOT be disturbed
X** between calls!
X**
X** Returns:
X** 0 = successful completion. fwk filled in with first matching
X** file.
X** >0 = error code. use fferror to obtain a meaningful description.
X**
X** Example:
X** findfirst("*.c",fwk)
X** The first matching file is in fwk->fname.
X*/
Xfindfirst(name,fwk)
Xchar *name;
Xstruct find *fwk;
X{
X struct Process *tp,*FindTask();
X int pt[16];
X int last;
X char *p1,*strchr();
X
X fwk->fp = (struct FileInfoBlock *) AllocMem(sizeof(struct FileInfoBlock),0);
X /* caller must free this space! */
X fwk->flock = 0;
X
X if (strlen(name) > 128)
X return(1); /* file name too long */
X if ((p1 = strchr(name,':')) != NULL)
X if (strchr(name,'/') == NULL) {
X *p1 = 0;
X strcpy(fwk->path,name);
X strcat(fwk->path,":/");
X strcat(fwk->path,p1+1);
X strcpy(name,fwk->path);
X }
X strcpy(fwk->path,name);
X if (stspfp(name,pt) == -1)
X return(2); /* error in parsing */
X for (last=0; last < 16; last++)
X if (pt[last] == -1)
X break;
X last--; /* now points at file name portion */
X if ((last == 0) && (pt[0] == 0)) { /* no path */
X if (strlen(name) > 32)
X return(1); /* file name too long */
X strcpy(fwk->name,name);
X fwk->path[0] = 0;
X tp = FindTask(NULL);
X fwk->flock = DupLock(tp->pr_CurrentDir);
X bldfull(fwk); /* build full path name */
X }
X else {
X if (strlen(&name[pt[last]]) > 32)
X return(1); /* file name too long */
X strcpy(fwk->name,&name[pt[last]]);
X fwk->path[pt[last] - 1] = 0;
X if ((fwk->flock = Lock(fwk->path,ACCESS_READ)) == 0)
X return(3); /* invalid path name */
X bldfull(fwk);
X }
X if (Examine(fwk->flock,fwk->fp)) { /* get directory name */
X if (fwk->fp->fib_DirEntryType > 0)
X return(findnext(fwk));
X else
X return(5); /* not a directory */
X }
X else
X return(4); /* first examine failed */
X}
X
X/*
X** findnext -- find next occurance of a matching file.
X** Parameter:
X** fwk - pointer to a "find" structure which has been filled in
X** by a call to findfirst.
X**
X** Returns:
X** 0 = Match found. fwk->fname contains the name.
X** -1 = No more matches.
X*/
Xint findnext(fwk)
Xstruct find *fwk;
X{
X while (ExNext(fwk->flock,fwk->fp)) {
X strcpy(fwk->fname,fwk->fp->fib_FileName);
X if (fnmatch(fwk->fname,fwk->name))
X return(0);
X }
X return(-1);
X}
X
Xbldfull()
X{
X}
X
X/* find_cleanup -- release any structures and locks used by findfirst.
X** Parameters:
X** fwk - pointer to a "find" structure which has been previously
X** filled in by findfirst.
X** Returns:
X** nothing
X*/
Xfind_cleanup(fwk)
Xstruct find *fwk;
X{
X if (fwk->flock)
X UnLock(fwk->flock);
X if (fwk->fp)
X FreeMem(fwk->fp,sizeof(struct FileInfoBlock));
X}
X
X/* fnmatch -- perform unix style pattern match on a file name
X** usage: result = fnmatch(name,pattern)
X** returns 1 if "name" matches "pattern", 0 otherwise
X*/
X
Xint fnmatch(name,pattern)
Xregister char *name,*pattern;
X{
X
X while (*pattern) {
X if (*pattern == '*') {
X while (*pattern == '*')
X pattern++;
X while ((*name) && (tolower(*name) != tolower(*pattern)))
X name++;
X if (*name == 0)
X if (*pattern == 0)
X return(1); /* matched */
X else
X return(0);
X }
X if (*pattern == '?') {
X pattern++;
X name++;
X continue;
X }
X if (tolower(*pattern) != tolower(*name))
X return(0); /* not matched */
X pattern++;
X name++;
X }
X if ((*name == 0) && (*pattern == 0))
X return(1); /* matched */
X else
X return(0); /* not matched */
X}
X
X/*
X** wildexp -- expand a wildcard file name
X** Parameters:
X** name - Pointer to the file name to be expanded.
X** adtbl - Pointer to an array of pointers.
X** maxargs - The maximum number of pointers contained in adtbl.
X**
X** Returns:
X** 1 = Successful completion. The adtbl array will contain pointers
X** to all file names found and will be terminated with a NULL
X** pointer. It's use is exactly like use of the standard C
X** argv array except that the first filename argument is in
X** adtbl[0] whereas argv[0] contains a pointer to the name of
X** the function which was invoked.
X** 0 = An error occured.
X*/
Xint wildexp(name,adtbl,maxargs)
Xchar *name;
Xregister char **adtbl;
Xint maxargs;
X{
X struct find f;
X register int i=0;
X char *malloc();
X int retval;
X
X if ((retval = findfirst(name,&f)) > 0) {
X *adtbl = NULL;
X find_cleanup(&f);
X return(0);
X }
X while (retval == 0) {
X if (f.fp->fib_DirEntryType > 0) {
X retval=findnext(&f);
X continue; /* it's a directory */
X }
X *adtbl = malloc(strlen(f.path)+strlen(f.fname)+1);
X if (*adtbl == NULL) {
X find_cleanup(&f);
X return(0); /* arena is full */
X }
X strcpy(*adtbl,f.path);
X if ((f.path[0] != 0) && (f.path[strlen(f.path)-1] != ':'))
X strcat(*adtbl,"/");
X strcat(*adtbl++,f.fname);
X if ((++i) >= maxargs)
X return(0);
X retval=findnext(&f);
X }
X *adtbl = NULL;
X find_cleanup(&f);
X return(1);
X}
X
Xint iswild(s)
Xchar *s;
X{
X while (*s) {
X if ((*s == '*') || (*s == '?'))
X return(1);
X s++;
X }
X return(0);
X}
X
SHAR_EOF
if test 8739 -ne "`wc -c < 'wildexp.c'`"
then
echo shar: error transmitting "'wildexp.c'" '(should have been 8739 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'wildexp.h'" '(1885 characters)'
if test -f 'wildexp.h'
then
echo shar: will not over-write existing file "'wildexp.h'"
else
sed 's/^ X//' << \SHAR_EOF > 'wildexp.h'
X/*
X** The following is an include file for wildexp.c and also
X** for any programs which desire to use findfirst and/or findnext.
X** This file is not needed for programs that are only using
X** iswild and wildexp.
X**
X** Written by: Rick Schaeffer
X** E. 13611 26th Ave
X** Spokane, Wa. 99216
X** Compuserve ID: 70120,174
X** Bytenet ID: ricks.
X*/
X
X#ifndef LIBRARIES_DOS_H
X#include
X#endif
X
X#ifndef LIBRARIES_DOSEXTENS_H
Xstruct Msg { int dummy; }; /* make Lattice shut-up about this */
X#include
X#endif
X
X/*
X** The following is the structure used by findfirst and findnext.
X** A pointer to this structure MUST be passed to findfirst, which
X** fills it in. Subsequent calls to findnext must pass a pointer
X** to the structure which was filled in by findfirst. The actual
X** file name found is in the "fname" element of the structure after
X** each call. NOTE: The last two elements of the structure refer
X** to AmigaDos specific items. Users of findfirst and findnext may,
X** if they choose, define the "find" structure such that the last
X** two elements (flock and fp) are defined as "long". In that fashion,
X** you can eliminate the need to #include the "dos" information. Of
X** course, if access to the FileInfoBlock is desired, you must use
X** the structure as defined below.
X*/
Xstruct find {
X char path[128]; /* path portion of the argument */
X char name[32]; /* name portion of the argument */
X char fpath[128]; /* FULL path to actual file found */
X /* NOTE: fpath is currently not filled in. To
X be added later */
X char fname[32]; /* actual name of file found */
X BPTR flock; /* lock for the directory containing the file */
X struct FileInfoBlock *fp; /* pointer to fib of file */
X };
X
SHAR_EOF
if test 1885 -ne "`wc -c < 'wildexp.h'`"
then
echo shar: error transmitting "'wildexp.h'" '(should have been 1885 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'utilskel.c'" '(4588 characters)'
if test -f 'utilskel.c'
then
echo shar: will not over-write existing file "'utilskel.c'"
else
sed 's/^ X//' << \SHAR_EOF > 'utilskel.c'
X/*
X** The following is a suggested skeleton for utilities which expect
X** to handle a variable number of files with wildcards handled in
X** input files and redirection of output files. This type of application
X** is very common and is difficult to handle...thus this example.
X**
X** The command line syntax for the resulting program is:
X** **name** [-o outputpath] file file file...
X** where the -o parameter is optional and indicates the path to
X** the directory where output files are to be placed.
X**
X** The skeleton handles wild card file names in the following fashion:
X** First, if a "-o" option is detected, the skeleton builds an output
X** file name mask consisting of the path given by the user after the
X** option. Then it reads file names from the command line and uses
X** the "wildexp" function to expand them into a table of existing
X** filenames which match. For each filename in the table, the skeleton
X** opens a file. If a "-o" option was given by the user, it concatenates
X** the input filename to the path obtained above, otherwise it
X** concatenates ".f" to the end of the input filename. These actions
X** are necessary to ensure that the input file and the output file
X** have different names. The skeleton then opens the output file
X** and calls "dowork". If there are errors in opening either the
X** input file or the output file, "dowork" is not called and an
X** appropriate message is printed to stderr.
X**
X** Basically, to use this skeleton, first replace occurances of "**name**"
X** with the name of the utility you are creating. Then, write the
X** "dowork" function. The "dowork" function gets two arguments..."fin"
X** and "fout". For each file the user wants to process, the "main"
X** function opens an input file (fin) and an output file (fout) and
X** then calls "dowork"...which performs whatever processing there is
X** to be done and then returns.
X**
X** Written by: Rick Schaeffer
X** E. 13611 26th Ave.
X** Spokane, Wa. 99216
X** Compuserve ID: 70120,174
X** Bytenet ID: ricks.
X*/
X
X#include
Xextern int Enable_Abort;
X
Xchar *largv[128];
X
Xmain(argc,argv)
Xint argc;
Xchar *argv[];
X{
X char outpath[80];
X char outname[80];
X char *nameonly,*strrchr();
X char *malloc();
X int i,j,begarg;
X FILE *fin,*fout;
X
X Enable_Abort = 1;
X outpath[0] = 0;
X if ((argc < 2) || (strcmp(argv[1],"?") == 0)) {
X printf("**name** -- Usage:\n");
X printf(" **name** [-o outpath] file file\n\n");
X printf("if -o option present, will write files to that path\n");
X printf("Otherwise concatenates '.f' to input file names\n\n");
X exit(1);
X }
X if (strcmp(argv[1],"-o") == 0) {
X strncpy(outpath,argv[2],78);
X begarg = 3;
X }
X else
X begarg = 1;
X for (i=begarg; i %s!\n",argv[i]);
X }
X else {
X largv[0] = malloc(strlen(argv[i])+1);
X strcpy(largv[0],argv[i]);
X largv[1] = NULL;
X }
X j=0;
X while (largv[j] != NULL) {
X if (outpath[0] == 0) {
X strncpy(outname,largv[j],77);
X strcat(outname,".f");
X }
X else {
X strcpy(outname,outpath);
X nameonly = strrchr(largv[j],'/');
X if (nameonly == NULL)
X nameonly = strrchr(largv[j],':');
X if (nameonly == NULL)
X nameonly = largv[j];
X else
X nameonly++;
X if ((strlen(outname) + strlen(nameonly)) > 79) {
X fprintf(stderr,"Pathname+Filename too long\n");
X break;
X }
X strcat(outname,nameonly);
X }
X if ((fin = fopen(largv[j],"r")) == NULL) {
X fprintf(stderr,"Couldn't open input file ==> %s\n",largv[j]);
X break;
X }
X if ((fout = fopen(outname,"w")) == NULL) {
X fprintf(stderr,"Couldn't open output file ==> %s\n",outname);
X fclose(fin);
X break;
X }
X fprintf(stderr,"%s ==> %s\n",largv[j],outname);
X dowork(fin,fout);
X fclose(fin);
X fclose(fout);
X j++;
X }
X }
X}
X
Xdowork(*fin,*fout)
XFILE *fin,*fout;
X{
X}
SHAR_EOF
if test 4588 -ne "`wc -c < 'utilskel.c'`"
then
echo shar: error transmitting "'utilskel.c'" '(should have been 4588 characters)'
fi
fi # end of overwriting check
# End of shell archive
exit 0
--
-----------
George M. Jones cbosgd!osu-eddie!george (uucp)
(614) 885-5102 (home) george@ohio-state.csnet (csnet)
(614) 457-8600 (work) 70003,2443 (CompusServe)