This is osdir.c in view mode; [Download] [Up]
/* unix/osdir.c */
/* This file contains functions that deal with filenames. The structure of
* this file is a little unusual, because some of the support programs also
* use functions from this file. To minimize the size of those support
* programs, this file may be compiled with JUST_DIRFIRST or JUST_DIRPATH
* defined to exclude the unused functions. If neither of those names is
* defined then the whole file is compiled.
*/
char id_osdir[] = "$Id: osdir.c,v 2.16 1996/09/20 23:56:25 steve Exp $";
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <dirent.h>
#ifndef S_ISREG
# define S_ISREG(mode) (((mode) & 0070000) == 0)
#endif
#if !defined(JUST_DIRFIRST) && !defined(JUST_DIRPATH)
# include "elvis.h"
#endif
#ifndef JUST_DIRPATH
# if USE_PROTOTYPES
static BOOLEAN wildcmp(char *fname, char *wild);
# endif
#endif
#ifndef NAME_MAX
# ifdef MAXNAMLEN
# define NAME_MAX MAXNAMLEN
# else
# define NAME_MAX 1024
# endif
#endif
#ifndef JUST_DIRPATH
/* This is the wildcard expression used by dirfirst() and dirnext() */
static char *wildfile;
/* This is the name of the directory being scanned by dirfirst() and dirnext() */
static char *wilddir;
/* This is the directory stream used by dirfirst() and dirnext() */
static DIR *dirfp;
/* This variable is True if the wildcard expression only needs to match the
* beginning of the name, or False if it must match the entire filename.
*/
static BOOLEAN partial;
/* This recursive function checks a filename against a wildcard expression.
* Returns True for match, False for mismatch.
*/
static BOOLEAN wildcmp(fname, wild)
char *fname; /* an actual filename */
char *wild; /* a wildcard expression */
{
int i, match;
TailRecursion:
switch (*wild)
{
case '\\':
/* character after \ must match exactly, except \0 and / */
if (*fname == '/' || !*fname || *fname != wild[1])
{
return False;
}
fname++;
wild += 2;
goto TailRecursion;
case '?':
/* match any single character except \0 and / */
if (*fname == '/' || !*fname)
{
return False;
}
fname++;
wild++;
goto TailRecursion;
case '[':
/* if no matching ], then compare [ as literal character;
* else next char in fname must be in brackets
*/
match = 0;
for (i = 1; wild[i] && (i == 1 || wild[i] != ']'); i++)
{
if (*fname == wild[i])
{
match = i;
}
}
if (wild[i] != ']' ? *fname != '[' : match == 0)
{
return False;
}
fname++;
wild += i + 1;
goto TailRecursion;
case '*':
/* The * should match as much text as possible. Start by
* trying to make it match all of the name, and if that doesn't
* work then back off until it does match or no match is
* possible.
*/
for (i = strlen(fname);
i >= 0 && !wildcmp(fname + i, wild + 1);
i--)
{
}
return (BOOLEAN)(i >= 0);
case '\0':
return ((*fname && !partial) ? False : True);
default:
if (*fname != *wild)
{
return False;
}
fname++;
wild++;
goto TailRecursion;
}
/*NOTREACHED*/
}
/* Return the first filename (in a static buffer) that matches wildexpr,
* or wildexpr itself if none matches. If wildexpr contains no wildcards,
* then just return wildexpr without checking for files.
*/
char *dirfirst(wildexpr, ispartial)
char *wildexpr; /* a wildcard expression to search for */
BOOLEAN ispartial; /* is this just the front part of a name? */
{
char *found;
/* If no wildcard characters, just return the expression */
if (!diriswild(wildexpr) && !ispartial)
{
dirfp = (DIR *)0;
return wildexpr;
}
/* If a previous dirfirst()/dirnext() was left unfinished, then
* abandon it now.
*/
if (dirfp)
{
closedir(dirfp);
}
/* Open the directory for scanning. If can't open, then return
* the wildexpr unchanged.
*/
wilddir = dirdir(wildexpr);
dirfp = opendir(wilddir);
if (!dirfp)
{
return wildexpr;
}
/* Use dirnext to do most of the dirty work */
wildfile = dirfile(wildexpr);
partial = ispartial;
found = dirnext();
return (found ? found : wildexpr);
}
/* Return the next filename (in a static buffer) that matches the
* wildexpr of the previous dirfirst(), or NULL if no more files match.
*/
char *dirnext()
{
struct dirent *dent;
/* if no directory is open, then fail immediately */
if (!dirfp)
{
return (char *)0;
}
/* loop until we find a matching entry, or end of directory.
* Note that we're careful about not allowing the ? and * wildcards
* match a . at the start of a filename; those files are supposed to
* be hidden.
*/
while ((dent = readdir(dirfp)) != NULL
&& ((dent->d_name[0] == '.' && (wildfile[0] != '.' || wildfile[0] != '['))
|| !wildcmp(dent->d_name, wildfile)))
{
}
/* if no entries matched, return NULL */
if (!dent)
{
closedir(dirfp);
dirfp = NULL;
return NULL;
}
/* combine the found name with the wilddir */
return dirpath(wilddir, dent->d_name);
}
#ifndef JUST_DIRFIRST
/* Return True if wildexpr contains any wildcards; else False */
BOOLEAN diriswild(wildexpr)
char *wildexpr; /* either a filename or a wildcard expression */
{
#if 0
char *quote = '\0';
while (*wildexpr)
{
if (!quote && strchr("?*[", *wildexpr))
{
return True;
}
else if (quote == '\\' || *wildexpr == quote)
{
quote = '\0';
}
else if (!quote && strchr("\"'`\\", *wildexpr))
{
quote = *wildexpr;
}
}
#else
if (strpbrk(wildexpr, "?*[\\"))
{
return True;
}
#endif
return False;
}
/* Check a the type & permissions of a file. Return one of the
* following to describe the file's type & permissions:
* DIR_INVALID malformed filename (can't happen with UNIX)
* DIR_BADPATH unable to check file
* DIR_NOTFILE directory or other non-file
* DIR_NEW file doesn't exist yet
* DIR_UNREADABLE file exists but is unreadable
* DIR_READONLY file is readable but not writable
* DIR_READWRITE file is readable and writable.
*/
DIRPERM dirperm(filename)
char *filename; /* name of file to check */
{
struct stat st;
if (stat(filename, &st) < 0)
{
if (errno == ENOENT)
return DIR_NEW;
else
return DIR_BADPATH;
}
if (!S_ISREG(st.st_mode))
{
return DIR_NOTFILE;
}
else if (access(filename, 4) < 0)
{
return DIR_UNREADABLE;
}
else if (access(filename, 2) < 0)
{
return DIR_READONLY;
}
else
{
return DIR_READWRITE;
}
}
/* return the file part of a pathname. This particular implementation doesn't
* use an internal buffer; it simply returns a pointer to the filename at the
* end of the pathname.
*/
char *dirfile(pathname)
char *pathname;
{
char *slash;
slash = strrchr(pathname, '/');
if (slash)
{
return slash + 1;
}
else
{
return pathname;
}
}
#endif /* !JUST_DIRFIRST */
#endif /* !JUST_DIRPATH */
/* return the directory part of a pathname */
char *dirdir(pathname)
char *pathname;
{
static char dir[NAME_MAX + 1];
char *slash;
strncpy(dir, pathname, sizeof dir);
slash = strrchr(dir, '/');
if (slash == dir)
{
return "/";
}
else if (slash)
{
*slash = '\0';
return dir;
}
else
{
return ".";
}
}
#ifndef JUST_DIRFIRST
/* combine a directory name and a filename, yielding a pathname. */
char *dirpath(dir, file)
char *dir; /* directory name */
char *file; /* filename */
{
static char path[NAME_MAX + 1];
int len;
if (*file == '/' || !strcmp(dir, "."))
{
strcpy(path, file);
}
else
{
len = strlen(dir);
if (len > 0 && dir[len - 1] == '/')
len--;
sprintf(path, "%.*s/%s", len, dir, file);
}
return path;
}
#ifndef JUST_DIRPATH
/* return the pathname of the current working directory */
char *dircwd()
{
static char cwd[NAME_MAX + 1];
if (getcwd(cwd, sizeof cwd))
{
return cwd;
}
else
{
return ".";
}
}
/* change the current directory, and return True if successful (else False) */
BOOLEAN dirchdir(pathname)
char *pathname; /* new directory */
{
return (BOOLEAN)(chdir(pathname) >= 0);
}
#endif /* !JUST_DIRPATH */
#endif /* !JUST_DIRFIRST */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.