home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume1
/
8707
/
46
< prev
next >
Wrap
Internet Message Format
|
1990-07-13
|
21KB
From: root@hobbes.UUCP
Newsgroups: comp.sources.misc
Subject: "glob" in C for MS-DOS (sources)
Message-ID: <2915@ncoast.UUCP>
Date: 16 Jul 87 00:21:54 GMT
Sender: allbery@ncoast.UUCP
Organization: U of Wisconsin - Madison Spanish Department
Lines: 747
Approved: allbery@ncoast.UUCP
X-Archive: comp.sources.misc/8707/46
[There were uuencodes with this. I have split them off; they are in
comp.binaries.ibm.pc. ++bsa]
Here is a routine which does wildcard expansion for MS-DOS.
The shar which follows contains:
glob.c glob.h - the actual wildcard expansion routines
example.c - a very simple example of its usage
chd.c - a more complex example - implements chdir
Have fun, mail me if you have problems...
John Plocher UUCP: <backbone>!uwvax!geowhiz!uwspan!plocher
============== Internet: plocher%uwspan.UUCP@uwvax.cs.Wisc.EDU
FidoNet: 121/0 BITNET: uwvax!geowhiz!uwspan!plocher@psuvax1
*-----*-----*-----*-----*-----*-----*-----*-----*-----*-----*
#!/bin/sh
# This is a shell archive created by yasa (1.72jmp).
# Run the following text with /bin/sh to extract.
#
# Archive: /usr/src/new/dos/cd/wildcard.shar
#
# This archive is a complete distribution by itself.
#
# Packed under system5 by plocher@hobbes (John Plocher)
# Packed on Tue Jul 14 20:13:11 1987
#
YASASTART=`pwd`
echo x - README
if [ -s README ] # exists & size>0
then
echo "shar: will not overwrite 'README'"
else
sed "s/^X//" << \!SHAR-EOF! > README
X Here is a routine which does wildcard expansion for MS-DOS.
XIt could be spiffed up by using the regex routines by Henry Spencer, but
Xfor now it expands DOS style wildcards (*,?): (This is also found in
Xthe file example.c)
X
X #include "glob.h"
X main() {
X char **names;
X names = glob("*.c");
X if (names)
X printf("The first file which matches the wildcard: %s\n",names[0]);
X else
X printf("glob() error number %d\n",globerror);
X }
X
XIt also handles the case of "/usr/pl*/bin/*.exe" where "/usr/pl*/bin" is unique.
XUnfortunately, the code does not handle "/*/*/*.c" type expansions. This is
Xan arbitrary limitation which is left to the student to implement. :-)))))
X
XIt also does not handle "C:/bin/*.exe" - the drive spec fouls it up,
XMS-DOS seems to have problems with the find first/next functions in the
Xroot directory so "/*.c" may give you problems.
X
XThe shar which follows contains:
X glob.c glob.h - the actual wildcard expansion routines
X example.c - a very simple example of its usage
X chd.c - a more complex example - implements chdir
X chd.exe (uuencoded) - compiled version of chd.c
X glob.obj (uuencoded) - linkable module containing glob()
X
XHave fun, mail me if you have problems...
X
X(PS I am not actively using MS-DOS for now, so this code has been sitting
X"on the shelf" for a bit. I saw a few comments in comp.sys.ibm.pc concerning
XTurbo C and its lack of wildcard support, so I figured I'd send this out.)
X
X John Plocher UUCP: <backbone>!uwvax!geowhiz!uwspan!plocher
X============== Internet: plocher%uwspan.UUCP@uwvax.cs.Wisc.EDU
XFidoNet: 121/0 BITNET: uwvax!geowhiz!uwspan!plocher@psuvax1
!SHAR-EOF!
if [ "`wc -c README`" != " 1638 README" ]
then
echo ' README may be bad'
fi
echo x - chd.c
if [ -s chd.c ] # exists & size>0
then
echo "shar: will not overwrite 'chd.c'"
else
sed "s/^X//" << \!SHAR-EOF! > chd.c
X
X/*
X * chd.c change directory
X * John Plocher
X *
X * usage: chd [new directory]
X *
X * [new directory] may contain wildcards; it may not be ambiguous
X * If no arguments, use $HOME variable in environment
X *
X * C:\BIN > set HOME=/usr/plocher
X * C:\BIN > chd \u*\lo*
X * C:\USR\LOCAL > chd
X * C:\USR\PLOCHER >
X *
X * uses glob() to expand wildcards in pathname
X *
X * returns (ERRORLEVEL)
X *
X * 0 No error
X * 1 could not find directory
X * 2 ambiguous pathname
X * 3 directoryname expected, you gave a filename
X * 4 internal error
X *
X * Change log
X *
X * Version Date Who Comments
X * ------- ---- --- --------
X * 1.00 16-Jan-86 jmp Initially coded
X * 1.01 21-Jan-86 jmp Expanded help menu (-?), fixed glob()
X */
X
X#include <stdio.h>
X#include "glob.h"
X
X#define VERSION "1.01 21-Jan-86"
X/* #define DEBUG */
X
Xchar *sccsid = "21-Jan-86 (Plocher) @(#)chd.c 1.01";
X
Xextern char *strchr();
Xextern char *getenv();
Xextern char *strdup();
Xextern void usage();
X
Xextern char *filename();
Xextern char *fixslash();
Xextern void recover();
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X char **names; /* array of pointers to names returned by glob() */
X char *progname; /* name of program (either argv[0] or hardcoded) */
X char *p; /* temp string pointer */
X char errstring[150];/* for usage() errors */
X char path[127]; /* workspace for getting starting (un-globbed) path */
X
X if (argv[0]) /* if there is something here, use it (DOS 3.xx+) */
X progname = filename(argv[0]);
X else /* hardcode the program name */
X progname = "chd";
X
X if (argc > 2) { /* must have less than 2 arguments */
X usage(progname,"Too many arguments");
X exit(1);
X }
X if (argc == 1) { /* need to get HOME */
X p = getenv("HOME"); /* p == NULL if not found ... */
X if (p != NULL)
X strcpy(path,p);
X else {
X usage(progname,"Environment variable HOME not found\n");
X exit(1);
X }
X } else { /* we have a pathspec from command line */
X if (argv[1][0] == '-') { /* if invoked chd -anything, just */
X usage(progname,NULL); /* explain ourselves */
X exit(0);
X }
X strcpy(path,argv[1]);
X }
X
X fixslash(path); /* convert all '\'s into '/'s */
X
X names = glob(path); /* get files which match */
X
X if (names == NULL && globerror == GE_BADPATH) {
X sprintf(errstring,"Path not found: \"%s\"",path);
X usage(progname, errstring);
X recover(names);
X exit(1);
X }
X if ((names == NULL && globerror == GE_AMBIGUOUS) || names[1] != NULL) {
X sprintf(errstring,"Ambiguous pathname \"%s\"",path);
X usage(progname, errstring);
X recover(names);
X exit(2);
X }
X if (chdir(names[0])) { /* do the actual chdir */
X usage(progname,"You must specify a DIRECTORY path");
X recover(names);
X exit(3);
X }
X if (names == NULL && (globerror == GE_MAXFILES || globerror == GE_NOMEM)) {
X sprintf(errstring,"Internal error: %s",
X globerror == GE_MAXFILES ? "Too many files" : "Out of memory");
X usage(progname, errstring);
X recover(names);
X exit(4);
X }
X recover(names); /* free memory used by *names[] */
X
X exit(0); /* no errors */
X}
X
X/*
X * usage tell the workd about this program
X */
Xvoid usage(progname, error)
Xchar *progname;
X{
Xfprintf(stderr,"%s version %s by John Plocher on FidoNet 121/90\n",
X progname,VERSION);
Xif (error)
X fprintf(stderr,"\nERROR: %s\n",error);
Xelse {
X fprintf(stderr,"\n%s - a replacement for MS-DOS's chdir & cd commands\n",
X progname);
X fprintf(stderr,"%s is Copyright 1986 by John Plocher\n\n",progname);
X fprintf(stderr,"%s is released to the NON PROFIT, NON COMMERCIAL public.\n",
X progname);
X fprintf(stderr,"Commercial rights to %s reserved by John Plocher\n", progname);
X fprintf(stderr,"%s has some features which the DOS version lacks:\n",progname);
X fprintf(stderr,"\t1) ALL wildcards (* and ?) are expanded, no matter where\n");
X fprintf(stderr,"\t they are in the path.\n");
X fprintf(stderr,"\t\tC:\\ >%s \\u*\\p*\\w*\\?\n",progname);
X fprintf(stderr,"\t\tC:\\USR\\PLOCHER\\WORK\\C >\n");
X fprintf(stderr,"\t2) If %s is invoked without arguments, it will try to\n",progname);
X fprintf(stderr,"\t change to the directory found in the environment\n");
X fprintf(stderr,"\t variable HOME.\n");
X fprintf(stderr,"\t\tC:\\ >SET HOME=\\usr\\plocher -or-\n");
X fprintf(stderr,"\t\tC:\\ >SET HOME=\\u*\\p*\n");
X fprintf(stderr,"\t3) If %s fails, it leaves an indication in ERRORLEVEL.\n",progname);
X fprintf(stderr,"\t This exit code can be tested in batch files:\n");
X fprintf(stderr,"\t ERRORLEVEL Meaning\n");
X fprintf(stderr,"\t ---------- -------\n");
X fprintf(stderr,"\t\t0 No error\n");
X fprintf(stderr,"\t\t1 could not find directory\n");
X fprintf(stderr,"\t\t2 ambiguous pathname\n");
X fprintf(stderr,"\t\t3 directoryname expected, you gave a filename\n");
X fprintf(stderr,"\t\t4 internal error (let me know about this!)\n\n");
X}
Xfprintf(stderr,"usage: %s <directory name> change to directory\n",progname);
Xfprintf(stderr," %s change to HOME\n",progname);
Xfprintf(stderr," %s -? help screen\n",progname);
X}
X
X/*
X * filename extract the filename from a pathname
X * ie C:\usr\plocher\chd.exe results in chd
X */
Xchar *filename(path)
Xchar *path;
X
X{
X register char *p, *pd;
X
X p = strchr(path,'\0'); /* work from the back... */
X while (--p != path && *p != ':' && *p != '\\' && *p != '/');
X if (*p == '\\' || *p == '/' || *p == ':')
X p++;
X pd = strchr(p,'.'); /* we don't want the .EXE */
X if (pd != NULL)
X *pd = '\0';
X strlwr(p);
X return (p);
X}
X
X/*
X * fixslash convert all '\'s to '/'s
X */
Xchar *fixslash(s)
Xchar *s;
X{
X register int x;
X
X if (s == NULL) return;
X for (x=0; x < strlen(s); x++)
X if (s[x] == '\\')
X s[x] = '/';
X}
X
X/*
X * recover free up the space malloc()'d in *names[] by glob()
X */
Xvoid recover(names)
Xchar **names;
X{
X register int i;
X
X i = 0;
X while (names[i] != (char *)0) {
X free(names[i]);
X i++;
X }
X free(names);
X}
X
!SHAR-EOF!
if [ "`wc -c chd.c`" != " 5981 chd.c" ]
then
echo ' chd.c may be bad'
fi
echo x - example.c
if [ -s example.c ] # exists & size>0
then
echo "shar: will not overwrite 'example.c'"
else
sed "s/^X//" << \!SHAR-EOF! > example.c
X/* Example program demonstrating the use of glob() */
X
X#include "glob.h"
X
X main() {
X char **names;
X names = glob("*.?");
X if (names) {
X printf("expansion of *.? is:\n");
X print(names);
X } else
X printf("glob() error number %d (see glob.h)\n",globerror);
X recover(names);
X }
X
X recover(names) /* free() all the space used up by **names; */
X char **names;
X {
X int i = 0;
X while (names[i] != (char *)0) {
X free(names[i]);
X i++;
X }
X free(names);
X }
X
X print(names) /* print out all the filenames returned by glob() */
X char **names;
X {
X int i;
X i = 0;
X while (names[i] != (char *)0) {
X printf("%s\n",names[i]);
X i++;
X }
X }
!SHAR-EOF!
if [ "`wc -c example.c`" != " 681 example.c" ]
then
echo ' example.c may be bad'
fi
echo x - glob.c
if [ -s glob.c ] # exists & size>0
then
echo "shar: will not overwrite 'glob.c'"
else
sed "s/^X//" << \!SHAR-EOF! > glob.c
X
X/*
X * Copyright 1985, 1986 by John Plocher Non-commercial use approved
X *
X * glob expand a given pathname with wildcards into
X * an argv[] type array of 'strings' which are
X * the files (directories) which result from the
X * expansion of the pathname. (All characters in
X * the returned list of filenames are in lower case)
X *
X * usage: char **glob(pathname) char *pathname;
X *
X * pathname is an absolute or relative pathname which may
X * contain DOS type wildcards wherever desired:
X *
X * names = glob("\\usr\\pl*\\*.c");
X *
X * It requires an externally declared int in the main function
X * named globerror:
X *
X * extern int globerror;
X *
X * to be used to return an error indication if glob() fails.
X * If glob() fails, it returns NULL with
X *
X * globerror set to GE_BADPATH invalid path - directory not found
X * globerror set to GE_AMBIGUOUS ambiguous directory spec
X * globerror set to GE_MAXFILES too many files found (MAXFILES)
X * globerror set to GE_NOMEM out of memory
X *
X * else it returns a pointer to a NULL terminated array of pointers
X * to 'strings':
X *
X * +-[ MAIN.C ]----------------------------------------------------+
X * | |
X * | #include "glob.h" |
X * | main() { |
X * | char **glob(); |
X * | char **names; |
X * | names = glob("/u??/p*"); |
X * | if (names) |
X * | printf("the first name returned is %s\n",names[0]); |
X * | else |
X * | printf("glob() error number %d\n",globerror); |
X * | recover(names); |
X * | } |
X * | |
X * +---------------------------------------------------------------+
X *
X * ALL strings and the array *names[] are made with calls to
X * malloc(). Thus, be sure to free() *names[x] AND names when done!
X *
X * +-[sample routines]---------------------------------------------+
X * | |
X * | (* free() all the space used up by **names; *) |
X * | recover(names) |
X * | char **names; |
X * | { |
X * | int i = 0; |
X * | |
X * | while (names[i] != (char *)0) { |
X * | free(names[i]); |
X * | i++; |
X * | } |
X * | free(names); |
X * | } |
X * | |
X * | (* print out all the filenames returned by glob() *) |
X * | print(names) |
X * | char **names; |
X * | { |
X * | int i; |
X * | i = 0; |
X * | while (names[i] != (char *)0) { |
X * | printf("%s\n",names[i]); |
X * | i++; |
X * | } |
X * | } |
X * +---------------------------------------------------------------+
X *
X * Compile as follows: (Structures MUST be packed in order for
X * the program to interface correctly with DOS)
X * cl -c -Zp glob.c ** Microsoft C v3 or 4 **
X *
X * Using the example given above, compile and link main program:
X * cl main.c glob
X *
X * Written December, 1985 by John Plocher with MicroSoft C 3.0
X * Change log:
X *
X * version date who comments
X * ------- ---- --- --------
X * 1.0 10-Dec-85 jmp Orig. coding
X * 1.1 16-Jan-86 jmp added globerror
X * 1.2 05-Feb-86 jmp added comments and doccumentation
X *
X */
X
Xstatic char *scssid = "5-Feb-86 (Plocher) @(#)glob.c 1.2";
Xstatic char *copyright =
X "Copyright 1985, 1986 John Plocher. Non-commercial use approved";
X
X#include <stdio.h>
X#include <dos.h>
X#include <memory.h>
X#include <direct.h>
X#include <string.h>
X#include "glob.h"
X
X/* Change the following if you might have more than this many */
X/* files returned by glob() */
X
X#define MAXFILES 256 /* max files returned by glob() */
X
Xstatic char *list[MAXFILES]; /* MAXFILES entries per sub-dir */
X
Xextern char *strlwr();
Xextern int getdir();
Xextern char *pos();
X
Xint globerror; /* PUBLIC - global error number */
X
X/*
X * glob()
X */
Xchar **
Xglob(proposed)
Xchar *proposed;
X{
X int i,j,k,needdir,n;
X char *end, filename[128], newpath[127], tmppath[127];
X char *f, *p1, *p2;
X char **names;
X
X strcpy(filename, proposed);
X
X /* add on current directory if first char is not '/' or '\' */
X if (*filename != '/' && *filename != '\\') {
X getcwd(tmppath,128);
X p2 = strchr(tmppath,'\0');
X p2--;
X if (*p2 != '/' && *p2 != '\\')
X strcat(tmppath,"/");
X strcat(tmppath,filename);
X strcpy(filename, tmppath);
X }
X for (i=strlen(filename); i; i--)
X if (filename[i] == '\\')
X filename[i] = '/';
X i = 0; j = 0;
X p2 = strchr(filename,'\0');
X p2--;
X if (*p2 == '.')
X strcat(filename,"/");
X while ((p1 = pos("/./",filename)) != NULL) {
X memccpy(p1+1, p1+3, '\0',strlen(p1));
X }
X while ((p1 = pos("../",filename)) != NULL) {
X char tmp;
X tmp = *(p1 - 1);
X *(p1 - 1) = '\0';
X p2 = strrchr(filename,'/');
X if (p2 == NULL) {
X globerror = GE_BADFILE;
X return(NULL);
X }
X *(p1 - 1) = tmp;
X memccpy(p2+1, p1+3, '\0',strlen(p1));
X }
X p2 = strchr(filename,'\0');
X p2--;
X if (*p2 == '/')
X *p2 = '\0';
Xloop:
X while (filename[i] != 0 && /* copy till hit a wildcard */
X filename[i] != '*' &&
X filename[i] != '?') {
X tmppath[j++] = filename[i++];
X }
X if (filename[i] != 0) /* wildcard found */
X while (filename[i] != 0 &&
X filename[i] != '/')
X tmppath[j++] = filename[i++];
X if (filename[i] != 0) /* need directory here */
X needdir = 1;
X else /* any file will do */
X needdir = 0;
X tmppath[j] = 0;
X strcpy(newpath,tmppath);
X end = strrchr(newpath,'/');
X if (end != NULL)
X *end = '\0';
X
X n = getdir(tmppath,needdir);
X
X if (n == -2) { /* out of dynamic memory */
X globerror = GE_NOMEM;
X return(NULL);
X }
X if (n == -1) { /* exceeded filecount */
X globerror = GE_MAXFILES;
X return(NULL);
X }
X if (n == 0) { /* file not found */
X globerror = GE_BADFILE;
X return(NULL);
X }
X if (needdir && n != 1) { /* ambiguous directory reference */
X for (i = 0; i < n; i++) /* This is an arbitrary limit */
X free(list[i]); /* one could follow all paths */
X globerror = GE_AMBIGUOUS; /* and not just the first... */
X return(NULL);
X }
X if (needdir) {
X strcpy(tmppath,newpath);
X strcat(tmppath,"/");
X strcat(tmppath,list[0]);
X free(list[0]);
X j = strlen(tmppath);
X goto loop;
X }
X
X names = (char **)malloc((n+1) * sizeof(char *));
X for (i = 0; i < n; i++) {
X sprintf(tmppath,"%s/%s", newpath, list[i]);
X names[i] = strdup(tmppath);
X free(list[i]);
X }
X names[n] = (char *)0;
X
X return(names);
X}
X
X/*
X * pos(target, src)
X * find target string within src
X */
Xstatic char *pos(s1,s2)
Xchar *s1, *s2;
X{
X int temploc, dist;
X char *tp;
X
X if (*s1) {
X for (;;) {
X tp = strchr(s2, *s1);
X if (tp == NULL) { /* couldn't even find first char */
X return(NULL);
X }
X if (!strncmp(s1,tp,strlen(s1))) /* match */ {
X return(tp);
X }
X s2 = tp + 1;
X }
X }
X}
X
X/*
X * File attributes
X */
X
X#define AT_RO 0x01 /* Read Only */
X#define AT_HIDDEN 0x02 /* hidden file */
X#define AT_SYSTEM 0x04 /* System file */
X#define AT_LABEL 0x08 /* volume label */
X#define AT_DIR 0x10 /* sub directory */
X#define AT_ARCH 0x20 /* archive bit */
X
Xstatic struct REGS rregs;
Xstatic struct SREGS sregs;
X
Xstatic struct DMA { /* For reading directory entry */
X char res[21];
X char attr;
X unsigned sec : 5, min : 6, hour : 5;
X unsigned day : 5, mon : 4, year : 7;
X long size;
X char name[13];
X} dma;
X
X/*
X * getdir gather all the files found in this directory
X */
Xstatic int
Xgetdir(path, needdir) /* return number of 'files' found in this path */
Xchar *path; /* this is where to look */
Xint needdir; /* 1 = we want ONLY AT_DIR type entries */
X /* 0 = we will take EVERYTHING */
X{
X int i, j, n;
X char *entry;
X
X bdos(0x1a, &dma,0);
X
X n = 0;
X rregs.h.ah = 0x4e;
X rregs.x.cx = AT_RO | AT_HIDDEN | AT_SYSTEM | AT_DIR;
X rregs.x.dx = (unsigned int) path;
X j = intdos(&rregs, &rregs); /* Search for first */
X while(j == 0) {
X strlwr(dma.name);
X if (needdir && (dma.attr & AT_DIR != AT_DIR)){ /* skip this entry */
X rregs.h.ah = 0x4f; /* wes needs dirs, and this ain't one */
X j = intdos(&rregs, &rregs);/* Search for next */
X continue;
X }
X entry = strdup(dma.name);
X if (entry == NULL) { /* out of memory */
X for (i = 0; i < n; i++)
X free(list[i]);
X return (-2);
X }
X if (n >= MAXFILES) /* too many files found */
X return(-1);
X for (i = n++; i > 0; --i) { /* alphabetize */
X if (strcmp(entry, list[i - 1]) >= 0)
X break;
X list[i] = list[i - 1];
X }
X list[i] = entry;
X rregs.h.ah = 0x4f;
X j = intdos(&rregs, &rregs); /* Search for next */
X }
X return(n);
X}
X
!SHAR-EOF!
if [ "`wc -c glob.c`" != " 8494 glob.c" ]
then
echo ' glob.c may be bad'
fi
echo x - glob.h
if [ -s glob.h ] # exists & size>0
then
echo "shar: will not overwrite 'glob.h'"
else
sed "s/^X//" << \!SHAR-EOF! > glob.h
X/*
X * Header file for wildcard routines
X */
X
X#define GE_BADPATH -1 /* invalid path - directory not found */
X#define GE_AMBIGUOUS -2 /* ambiguous directory spec */
X#define GE_MAXFILES -3 /* too many files found (MAXFILES) */
X#define GE_NOMEM -4 /* out of memory */
X
Xextern int globerror; /* PUBLIC - global error number */
Xextern char **glob( char * );
X
!SHAR-EOF!
if [ "`wc -c glob.h`" != " 362 glob.h" ]
then
echo ' glob.h may be bad'
fi
echo x - make.bat
if [ -s make.bat ] # exists & size>0
then
echo "shar: will not overwrite 'make.bat'"
else
sed "s/^X//" << \!SHAR-EOF! > make.bat
XREM makefile for glob routines by John Plocher
XREM glob is a routine which expands DOS style wildcards into an argv array
X
XREM Microsoft C 3.0 and 4.0 -Must pack structures in glob.c-
X
Xcl -O -c -Zp glob.c
Xcl -O chd.c glob -o chd
X
!SHAR-EOF!
if [ "`wc -c make.bat`" != " 231 make.bat" ]
then
echo ' make.bat may be bad'
fi
exit