home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 5 Edit
/
05-Edit.zip
/
me34src.zip
/
me3
/
util
/
canonize.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-01-14
|
8KB
|
241 lines
/*
* Name: canonize
* Purpose:
* Calculate a file's unique (canonical) pathname, suitable for comparing
* with other canonical names.
* Usage: char *canonize(fname,cname, current_directory);
* Input:
* char *fname; Pointer to file name to canonize.
* char *cname; Where to put the canonical name.
* char *current_directory;
* Pointer to the name of the current directory
* (canonized). Pass in (char *)NULL if you want me to
* query the OS for this info (the normal case).
* Returns:
* Pointer to canonical name, or NULL if file name was illegal.
* Notes:
* On Unix, getcwd() is VERY slow. If you call canonize() very often,
* you'll want to call getcwd() once, save the dir and pass it in via
* current_directory. Make sure current_directory is canonized.
* No wildcards in fname - see fxpand().
* MS-DOS
* "A:" => "A:<current directory>"
* The canonical name will only contain "/"s. No "\"s.
* Will parse both "\" and "/".
* The drive letter is uppercase, everything else is lowercase.
* ATARIST (from jwahar r. bammi (bammi@cadence.com))
* Usage just like Unix. The library getcwd will canonize, and will be
* consistent (especially) inspite of unixmode. Also getcwd() is not
* expensive on the atari, so we use it.
* Every file has exactly one, unique canonical name. Canonical names may
* be compared to determine if two names specify the same file.
* The format for canonical names is: C:/path/FILE.EXT or C:/path/FILE
* for files lacking an extension. Note that the drive name is
* always included, a complete path name (starting at the root) is
* provided and references to "." and ".." are removed.
* Leading blanks in file name are ignored and dropped from the
* canonical name.
* On Domain/OS (Apollo), 2 leading slashes (//foo) is very different
* from a single leading slash. Yech. "Normal" Unix doesn't care if
* there is one or more leading slashes. Also, "//foo/.." => "//".
* "/.." => "//" but I don't know if I care enough to make this
* work.
* Defects:
* Character device names are not recognized, and so they are treated
* like ordinary files.
* Error checking is not very robust.
* WARNING
* This routine is a classic bomb waiting to go off. It fills a fixed
* length string (of unknown length) with text of unknown lengths. One
* of these days it will write off the end.
* Also, the routine getcwd() is used poorly. I should do getter error
* checking and give it a better chance of working with a long path name.
* The real fix for this is to use dynamic strings. Until then, pass in a
* big buffer.
* System:
* MS-DOS 2.1 and up. Lattice C
* With minor mods: Microsoft C
* Unix
* Domain/OS (mostly)
* Author: Jim Conrad 06/08/86
* Rewritten: Craig Durland 9/86, 6/89
* Modified: 11/91
*/
/* Copyright 1986 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.
*/
#include <stdio.h>
#include <os.h>
#include <const.h>
#include <char.h> /* <char.h> or <ctype.h> */
extern char *getcwd();
static char *fnptr, *cnptr; /* !!! not reentrent */
static int get_dpart();
/* flags for get_dpart() */
#define TEXT 0
#define PARENT 1
#define DONE 2
#define ZILCH 3
#if MSDOZ
#include <dos.h>
#ifdef LATTICE /* from dos.h */
#define GET_DRIVE() getdsk()
#define GET_CURRENT_DIRECTORY(drive, path) getcd(drive, path)
#else /* JPI Topspeed C, Turbo C, hopefully others */
#include <dir.h>
#define GET_DRIVE() getdisk()
#define GET_CURRENT_DIRECTORY(drive, path) getcurdir(drive, path)
#endif /* LATTICE */
#endif /* MSDOZ */
/* convert fname to a full file spec */
char *canonize(fname,cname, current_directory)
char *fname; char *cname, *current_directory;
{
register char *first_slash;
fnptr = fname; cnptr = cname;
while (isspace(*fnptr)) fnptr++; /* Ignore leading white space */
/* Ensure file name is not empty ie contains at least "c\0" */
if (*fnptr == '\0') return NULL;
#if MSDOZ
if (fnptr[1] == ':') /* if drive provided, use it */
{ *cnptr++ = toupper(*fnptr); fnptr += 2; }
else *cnptr++ = 'A' + GET_DRIVE(); /* drive missing: use current drive */
*cnptr++ = ':';
#endif /* MSDOZ */
first_slash = cnptr; /* point to opening slash */
if (ISSLASH(*fnptr))
{
*cnptr++ = U_SLASH;
#if DOMAIN_OS /* just for Domain/OS. Yech */
{
char c;
/* Check to see if fname starts with // (and only //) */
if (ISSLASH(fnptr[1]))
if ((c = fnptr[2]) == '\0' || !ISSLASH(c))
{ fnptr++; *cnptr++ = U_SLASH; first_slash++; }
}
#endif /* DOMAIN_OS */
}
else /* No leading "/" => path name not anchored */
{ /* so fname is relative to current directory */
#if MSDOZ
*cnptr++ = U_SLASH; /* tack on a leading slash */
if (GET_CURRENT_DIRECTORY(*cname - 'A' + 1, cnptr)) return NULL;
if (*cnptr) /* if current dir != "" (ie the root) */
{ /* skip over dir, switching slashes as we go along */
for (; *cnptr; cnptr++) if (*cnptr == M_SLASH) *cnptr = U_SLASH;
*cnptr++ = U_SLASH;
}
#else
#if UX_OS
if (current_directory) /* better be canonized */
strcpy(cnptr,current_directory);
else if (getcwd(cnptr,250) == NULL) return NULL; /* at least a "/" */
while (*cnptr) cnptr++; /* move to end of current directory */
if (cnptr[-1] != U_SLASH) *cnptr++ = U_SLASH; /* in case cd is "/" */
#else
#if ATARI
if (getcwd(cnptr,250) == NULL) return NULL; /* at least a "/" */
#if defined(__MINT__) /* just in case */
for (; *cnptr; cnptr++) if (*cnptr == M_SLASH) *cnptr = U_SLASH;
#else
while (*cnptr) cnptr++; /* move to end of current directory */
#endif /* __MINT__ */
if (cnptr[-1] != U_SLASH) *cnptr++ = U_SLASH; /* in case cd is "/" */
#else
/* Nothing defined, nuke the compile */
Need_to_define = Something;
#endif /* ATARI */
#endif /* UX_OS */
#endif /* MSDOZ */
}
while (TRUE)
{
switch (get_dpart())
{
case DONE: *cnptr = '\0'; goto done;
case PARENT:
if (--cnptr != first_slash) while (*--cnptr != U_SLASH) ;
/* now tack on a slash after the name */
case TEXT: *cnptr++ = U_SLASH; break;
}
}
done:
if (--cnptr != first_slash) *cnptr = '\0'; /* get rid of trailing slash */
#if MSDOZ
lowercase(first_slash); /* lowercase all but drive */
#endif /* MSDOZ */
return cname;
}
/* know: cnptr[-1] == slash */
static int get_dpart()
{
register char *ptr = cnptr;
register char c1, c2;
if (*fnptr == '.') /* check for /. or /.. */
{
fnptr++; /* point to "/", "." or "" */
c1 = fnptr[0];
if (!(ISSLASH(c1) || c1 == '\0')) /* ignore "/./" or "/." */
{
c2 = fnptr[1];
if (c1 == '.' && (ISSLASH(c2) || c2 == '\0')) /* "/../" or "/.." */
{ fnptr++; return PARENT; }
*cnptr++ = '.'; /* false alarm */
}
}
while (*fnptr)
{
if (ISSLASH(*fnptr)) { fnptr++; break; }
*cnptr++ = *fnptr++;
}
if (cnptr != ptr) return TEXT;
if (*fnptr == '\0') return DONE;
return ZILCH; /* probably something like multiple slashes */
}
#ifdef TEST
/* ******************************************************************** */
/* *************** Test *********************************************** */
/* ******************************************************************** */
main()
{
char buf[80], cname[512];
printf("File name to canonize: "); gets(buf);
if (NULL == canonize(buf,cname, (char *)NULL)) printf("Bleech\n");
else printf(">%s<\n>%s<\n",buf,cname);
}
#endif