home *** CD-ROM | disk | FTP | other *** search
- static char rcsid[] = "$Id: fxpand.c,v 1.1 1992/09/06 19:31:32 mike Exp $";
-
- /* $Log: fxpand.c,v $
- * Revision 1.1 1992/09/06 19:31:32 mike
- * Initial revision
- *
- */
-
- #if 0 /* there are star-slashes in the comment below */
- /* fxpand.c : fxpand(): expand file names
- * Input:
- * name: A file name which can contain: ?, \, [], [^] and *
- * If name ends with "." (eg *.) then only names with no extensions will
- * be matched.
- * If name beings with ~ then: "~/" expands to "$(HOME)/" and "~name"
- * expands to "<home directory of name>".
- * MS-DOS: \ is same as /. Does not quote.
- * UNIX: \ quotes the next character.
- * ATARI (from jwahar r. bammi (bammi@cadence.com)):
- * Like MS-DOS, \ == /, except that we have the POSIX opendir() etc.
- * onlyone: If TRUE return the first match otherwise all matches are
- * returned. For example, this controls how "*" is expanded.
- * nopath: If TRUE, only return the matching file names. Otherwise
- * return the path and name. For example, "/foo/bar" => "bar".
- * slash_dir: If TRUE, append a slash to the end of a file name if the
- * file is a directory. For example, input of "dir" would generate
- * "dir/".
- * name_heap:
- * NULL: Call process_fname.
- * Pointer to char[]: Stuff the file names in here. The names are
- * separated by a blank and there are no trailing blanks.
- * process_fname: A function which is passed a char *. The string
- * contains the expanded file name.
- * Returns: 0 if all OK, >1 an error to be returned by fxpand().
- * Output:
- * 0: All OK
- * 1: Something screwed up. Most likely the name is bad.
- * n: An error code returned by process_fname().
- *
- * Notes:
- * When compiled on Apollo, this routine also works with the Domain/OS
- * "//" notation. This is mostly luck - I don't collapse "/"s and a
- * relaxed check lets this work.
- * Input error checking is pretty grim.
- * Unix Notes:
- * When wildcard matching, hidden files (those that start with ".") are
- * skipped unless you ask to see them. To match ".fred", you could use
- * ".f*". To match "fred/.sam/geo", you would need something like
- * "fred/.s*/g*".
- * When appending slashes (slash_dir), expanding something like "*" can be
- * very slow. This is because I have to stat() to find out if the file
- * is a directory and stat() can take a long time to stat files over nfs
- * mounts, follow links, etc.
- *
- * Craig Durland
- *
- * Do not delete this double quote! " (You are not expected to understand this)
- */
- #endif
-
- /* Copyright 1989, 1990, 1991 Craig Durland
- * Distributed under the terms of the GNU General Public License.
- * Distributed "as is", without warranties of any kind, but comments,
- * suggestions and bug reports are welcome.
- */
-
- #define _HPUX_SOURCE /* for ANSI C on HP-UX */
- #define _BSD_SOURCE /* for ANSI C on Apollo BSD */
- #define _POSIX_SOURCE /* for ANSI C on IBM AIX */
-
- #include <stdio.h>
- #include "os.h"
- #include "const.h"
-
- extern char *strchr(), *getenv(), *strcpy(), *strcat();
-
- static char *name_list;
- static int prepend_blank;
- static int stuff_name(name) char *name;
- {
- if (prepend_blank) strcat(name_list," ");
- else prepend_blank = TRUE;
-
- strcat(name_list,name);
- return 0;
- }
-
- #if MSDOZ
-
- #define SLASH "/" /* "/" or "\\", your preference */
-
- /* A note about MS-DOS: Its file find routines are brain dead: If you
- * ask for a directory, you will get all file types. Also, since
- * there is a file type==0, you can't just use AND to filter out
- * unwanted types. What a pain in the butt!
- */
-
- #include <dos.h>
- #ifdef __TSC__ /* ibmdir.h has definitions for Lattice C structures */
- #include "ibmdir.h"
- #include "char.h"
- #endif /* __TSC__ */
-
- typedef struct FILEINFO FI; /* in dos.h */
-
- #define FATTR (FA_ARCHIVE | FA_RD_ONLY | FA_DIRECTORY) /* file attributes */
-
-
- fxpand(name, onlyone,nopath,slash_dir, name_heap,process_fname)
- char *name,*name_heap; pfi process_fname;
- {
- char path[128], word[100], *ptr, *qtr, tbuf[128];
- FI de;
- int atend, eval, found, needadot, path_len, s;
-
- if (name_heap) /* store the found file names in name_heap */
- {
- process_fname = stuff_name;
- *(name_list = name_heap) = '\0';
- prepend_blank = FALSE;
- }
-
- *path = '\0';
- if (*name == '~')
- {
- name++;
- if (ptr = getenv("HOME")) strcpy(path,ptr);
- }
- else
- if (name[1] == ':')
- { strncpy(path,name,2); path[2] = '\0'; name += 2; }
-
-
- atend = FALSE; needadot = FALSE;
- while (!atend)
- {
- atend = get_dpart(&name,word,&eval);
- path_len = strlen(path);
- uppercase(word); /* Since the directory entries are uppercase */
- if (eval) /* wildcards in need of expansion */
- {
- if (word[strlen(word)-1] == '.') needadot = TRUE;
- found = FALSE;
- ptr = path +path_len; strcpy(ptr,"*.*");
-
- if (dfind(&de,path,FATTR)) return 1; /* No files found */
- *ptr = '\0'; /* get rid of "*.*" */
- do /* look at all entries in this directory */
- {
- if (!atend) /* only care about directories */
- { if (de.attr != FA_DIRECTORY) continue; }
- else
- if (de.attr && /* if de.attr==0, its a regular old file */
- (de.attr & FATTR) == 0) continue;
-
- ptr = qtr = de.name;
- if (needadot && !strchr(ptr,'.')) ptr = strcat(strcpy(tbuf,ptr),".");
- if (*qtr != '.' && wildmat(ptr,word)) /* ignore . & .. */
- {
- found = TRUE;
- if (!atend) /* something like foo/<you are here>/bar */
- {
- strcat(strcat(path,qtr), SLASH);
- break;
- }
- else /* something like foo/<you are here> */
- {
- strcpy(path +path_len, qtr);
- s = procz(process_fname, slash_dir && (de.attr == FA_DIRECTORY),
- path, nopath ? path_len : 0);
- path[path_len] = '\0';
- if (s) return s;
- if (onlyone) break;
- }
- }
- } while (!dnext(&de));
- if (!found) return 1;
- }
- else
- {
- strcpy(path + path_len, word);
- if (atend) /* all done */
- return procz(process_fname, slash_dir && is_dir(path),
- path, nopath ? path_len : 0);
- /* ??? if (!is_dir(path)) return 1; /* Make sure path is real */
- }
- } /* end while */
- return 0;
- }
-
- static int procz(process_fname, slash_it, path, path_len)
- pfi process_fname; char *path;
- {
- if (slash_it && (path[path_len] != '\0')) strcat(path, "/");
- return (*process_fname)(path + path_len);
- }
-
- /*
- * Notes:
- * For some (unknown to me) reason, FA_DIRECTORY matches everything,
- * not just directories.
- * WARNING:
- * This routine changes the DTA. If you are in the middle of a
- * dfind/dnext loop, this will mess that up.
- */
- static int is_dir(path) char *path;
- {
- FI de;
-
- return (!dfind(&de,path,FA_DIRECTORY) && (de.attr == FA_DIRECTORY));
- }
-
-
-
- /* MS-DOS stuff for get_dpart() */
- #define ASLASH case '/': case '\\'
- #define GOTTA_EVAL case '?': case '[': case '*'
-
- #endif /* MSDOZ */
-
-
- #if ATARI /* Atari has Posix opendir(), etc */
- #undef POSIX_OS
- #define POSIX_OS 1 /* turn on POSIX and UX_OS */
- #endif /* ATARI */
-
-
-
-
-
- #if UX_OS /* and Atari */
-
- #define BADGETPW 1 /* 1 if system getpw... routines are screwed up */
-
- #include <sys/types.h>
- #include <pwd.h>
- #include <sys/stat.h>
-
- /* Posix, SysV: HP-UX, Apollo SysV, DEC, Atari */
- /* defined(POSIX) is a DECism */
- #if POSIX_OS || SYSV_OS || defined(POSIX)
- #include <dirent.h>
- #else /* Pure BSD: Apollo bsd4.3 */
- #include <sys/dir.h>
- #endif
-
-
- static int get_dpart(), getpwhome(), procz(), is_dir();
-
-
- /* cases to check:
- * "~", "~fred", "/", "~/", ""
- */
- fxpand(name, onlyone,nopath,slash_dir, name_heap,process_fname)
- char *name,*name_heap; pfi process_fname;
- {
- char path[512], word[256], *ptr, *qtr, tbuf[256];
- DIR *dir;
- #if POSIX_OS || SYSV_OS || defined(POSIX)
- struct dirent *dtr;
- #else /* Apollo bsd4.3, (some)DEC */
- struct direct *dtr;
- #endif
- int
- atend, needadot,
- eval, found, path_len, s,
- skip_dot_files; /* ignore names starting with "." */
- struct passwd *pd;
-
- if (name_heap) /* store the found file names in name_heap */
- {
- process_fname = stuff_name;
- *(name_list = name_heap) = '\0';
- prepend_blank = FALSE;
- }
-
- *path = '\0';
- if (*name == '~') /* csh/ksh home directory expansion */
- {
- name++;
- if (ISSLASH(*name) || *name == '\0') /* ~/foo/bar or ~ */
- {
- if (ptr = getenv("HOME")) strcpy(path,ptr);
- else /* no $HOME, see if the OS knows */
- {
- #if BADGETPW
- return 1; /* !!! a sleeze */
- #else
- if ((pd = getpwuid(getuid())) == NULL) return 1;
- strcpy(path,pd->pw_dir);
- #endif /* BADGETPW */
- }
- }
- else /* ~fred => user freds' home directory */
- {
- atend = get_dpart(&name,word,&eval);
- if (eval) return 1; /* no wildcards allowed in user name */
- name--;
- if (!atend) word[strlen(word)-1] = '\0'; /* remove "/" from "~fred/" */
- #if BADGETPW
- if (!getpwhome(word)) return 1;
- strcpy(path,word);
- #else
- if ((pd = getpwnam(word)) == NULL) return 1;
- strcpy(path,pd->pw_dir);
- #endif /* BADGETPW */
- }
- }
-
- /* at this point, maybe: strlen(path)!=0 && strlen(name)==0 */
-
- atend = FALSE; needadot = FALSE;
- while (!atend)
- {
- atend = get_dpart(&name,word,&eval);
- skip_dot_files = (*word != '.'); /* ".fred" means look at dot files */
- path_len = strlen(path);
- if (eval) /* wildcards in need of expansion */
- {
- if (word[strlen(word)-1] == '.') needadot = TRUE;
- found = FALSE;
- if ((dir = opendir(path_len == 0 ? "." : path)) == NULL) return 1;
- while (TRUE) /* look at all entries in this directory */
- {
- if ((dtr = readdir(dir)) == NULL) break;
- ptr = qtr = dtr->d_name;
- if (skip_dot_files && *ptr == '.') continue;
- if (needadot && !strchr(ptr,'.')) ptr = strcat(strcpy(tbuf,ptr),".");
- if (wildmat(ptr,word))
- {
- if (!atend) /* something like foo/<you are here>/bar */
- {
- strcpy(path + path_len, qtr);
- /* make sure its a real directory */
- if (is_dir(path)) { strcat(path,"/"); found = TRUE; break; }
- }
- else /* something like foo/<you are here> */
- {
- found = TRUE;
- strcpy(path +path_len, qtr);
- s = procz(process_fname, slash_dir, path, nopath ? path_len : 0);
- path[path_len] = '\0';
- if (s) { closedir(dir); return s; }
- if (onlyone) break;
- }
- }
- } /* end while (TRUE) */
- closedir(dir);
- if (!found) return 1;
- }
- else /* No wildcards: something like: .../bar/... or .../bar */
- { /* word may == "" (for input like "~fred") */
- strcpy(path + path_len, word);
- if (atend) /* all done */
- return procz(process_fname, slash_dir, path, nopath ? path_len : 0);
-
- /* ??? if (!is_dir(path)) return 1; /* Make sure path is real */
- }
- } /* end while */
- return 0;
- }
-
-
- /* Input:
- * process_fname: pointer to function to call
- * slash_dir: TRUE: if path is a directory, append a slash
- * path: Full path name
- * path_len: offset in path. Used if what to pass just part of path
- * to process_fname.
- * Returns:
- * What ever process_fname returns.
- * Notes:
- * Need to check path[path_len] before appending a slash because: if
- * don't want a path (path_len != 0) and no name (eg expanding "~"),
- * would process_fname("/") which is not what is expected.
- */
- static int procz(process_fname, slash_dir, path, path_len)
- pfi process_fname; char *path;
- {
- if (slash_dir && (path[path_len] != '\0') && is_dir(path))
- strcat(path, "/");
- return (*process_fname)(path + path_len);
- }
-
-
- static int is_dir(path) char *path;
- {
- struct stat sbuf;
-
- if (stat(path,&sbuf)) return FALSE;
- /* make sure its a directory */
- #ifdef S_ISDIR
- return S_ISDIR(sbuf.st_mode);
- #else
- return ((sbuf.st_mode & 0170000) == 040000);
- #endif /* S_ISDIR */
- }
-
-
- #if BADGETPW
- /* Get the home directory out of the password file.
- * Only use this if the system getpw... routines are
- * screwed up.
- */
- static int getpwhome(name) char *name;
- {
- char buf[256], *ptr;
- FILE *fptr;
- int n, s = FALSE;
-
- if ((fptr = fopen("/etc/passwd","r")) == NULL) return FALSE;
- while (fgets(buf,255,fptr))
- {
- for (ptr = buf; *ptr != ':'; ptr++) ; *ptr = '\0';
- if (strcmp(name,buf)) continue;
- for (n = 0; n < 4; ptr++) if (*ptr == ':') n++;
- while (*ptr != ':') *name++ = *ptr++; *name = '\0';
- s = TRUE;
- break;
- }
- fclose(fptr);
- return s;
- }
- #endif /* BADGETPW */
-
- #if ATARI /* Atari stuff for get_dpart(), same as MS-DOS */
- #define ASLASH case '/': case '\\'
- #define GOTTA_EVAL case '?': case '[': case '*'
- #else
- /* UNIX stuff for get_dpart() */
- #define ASLASH case '/'
- #define GOTTA_EVAL case '?': case '\\': case '[': case '*'
- #endif /* ATARI */
-
-
- #endif /* UX_OS || ATARI */
-
-
-
-
-
-
-
- /* Get the next part of the filename (ie the stuff between "/"s). The
- * parts of "/foo/*.c" are: "/", "foo", "*.c".
- * Input:
- * Output:
- * eval: TRUE if part contains wildcards needing expansion.
- * word: The part.
- * start: Points after the part (after the "/" or '\0').
- * Returns:
- * TRUE: Hit the end of the filename else FALSE.
- */
- static int get_dpart(start,word,eval) char **start, *word; int *eval;
- {
- register char *ptr = *start;
- int atend = TRUE;
-
- *eval = FALSE;
- while (TRUE)
- {
- switch (*word++ = *ptr++)
- {
- ASLASH:
- atend = FALSE;
- if (*eval) word--; /* remove trailing "/" */
- case '\0': *word = '\0'; *start = ptr; return atend;
- GOTTA_EVAL: *eval = TRUE; break;
- }
- }
- }
-
-
- #ifdef TEST
- /* **************** TEST ******************************************** */
-
- #include "dtable.h"
- declare_and_init_dTable(ntable,char *);
-
- extern char *savestr();
-
- add_to_table(name) char *name;
- {
- static int n = 0;
-
- xpand_dTable(&ntable, 1, 50, 25);
- ntable.table[n++] = savestr(name);
- return 0;
- }
-
- char name_heap[3000];
- main()
- {
- char buf[80], *zim = NULL;
- int j, nopath;
-
- printf("Use name_heap? "); gets(buf); if (atoi(buf)) zim = name_heap;
- printf("No path? "); gets(buf); nopath = atoi(buf);
-
- printf(": "); gets(buf);
- if (fxpand(buf,FALSE,nopath,zim,add_to_table)) puts("blew up");
- else
- {
- if (zim) printf(">%s<\n",zim);
- else
- {
- for (j = 0; j < sizeof_dTable(&ntable); j++)
- printf("table[%d]: %s\n",j,ntable.table[j]);
- }
- }
- }
- #endif
-