home *** CD-ROM | disk | FTP | other *** search
- /**
- *
- * Name FLNORM -- Check and normalize a path name (convert to
- * standard form)
- *
- * Synopsis ercode = flnorm(pfile,pnorm,plast);
- *
- * int ercode 0 if okay, 1 if error.
- * const char *pfile Path name to normalize
- * char *pnorm Pointer to character buffer to fill
- * with the normalized path name. This
- * should be at least MAX_FLEN bytes
- * long.
- * int *plast Pointer to integer variable in which
- * to return the offset within *pnorm of
- * the first character of the last
- * portion of the normalized path name.
- *
- * Description This function validates a path name and converts it to a
- * standard universal form for comparison with other path
- * names. This includes
- *
- * 1) Detecting all illegal characters, including
- * extra periods ('.'), slashes ('/'), backslashes
- * ('\\'), etc.;
- * 2) Converting all letters to lower case;
- * 3) Converting all slashes to backslashes;
- * 4) Removing the trailing colon (':') from a possible
- * device name;
- * 5) Adding the current disk drive name (if no disk
- * drive is named);
- * 6) Adding the full path from the root directory
- * ("\\") if it is absent;
- * 7) Resolving "." and "..";
- * 8) Truncating each portion of the path name to eight
- * characters + dot + three characters; and
- * 9) Removing the dot from each portion of the path name
- * where it is redundant.
- *
- * This does not include
- *
- * 1) Checking the existence of any portion of the path;
- * or
- * 2) Checking for the presence of a possible device
- * (if a trailing colon is found).
- *
- * Note that unless the path name already begins with a
- * full path from the root directory ("\\"), the actual
- * result will depend (in part) on the current directory on
- * the relevant drive.
- *
- * The value returned in *plast is the index in *pnorm of
- * the last filename in the normalized path name. For
- * example, if the normalized path name is
- *
- * c:\blaise\flnorm.c
- *
- * then *plast will be 10 (the offset of the 'f'). If
- * there is no last filename (i.e., the path name is the
- * root directory on some drive), then *plast will be the
- * offset of the trailing NUL ('\0'). For example, if the
- * normalized path name is
- *
- * d:\
- *
- * then *plast will be 3.
- *
- * If the path name is found to contain illegal characters
- * or syntax or if the normalized version is too long, 1 is
- * returned as the value of the function and the results in
- * *pnorm and *plast are invalid.
- *
- * This routine does not know whether disk drive names have
- * been reassigned with the DOS ASSIGN, JOIN, or SUBST
- * commands. If one of these commands has been used, it is
- * possible for two path names to be normalized to
- * different results using FLNORM but actually to pertain
- * to the same disk file.
- *
- * The calling function must allocate at least MAX_FLEN
- * bytes for the returned full path name.
- *
- * Returns ercode 0 if okay, 1 if error.
- * *pnorm Character buffer filled with the
- * normalized path name.
- * *plast The offset within *pnorm of the first
- * character of the last portion of the
- * normalized path name.
- *
- * Version 6.00 (C)Copyright Blaise Computing Inc. 1986, 1987, 1989
- *
- **/
-
- #include <dos.h>
- #include <ctype.h>
- #include <stdio.h> /* For NULL. */
- #include <string.h>
-
- #include <bfiles.h>
- #include <bstrings.h>
- #include <butil.h>
-
- #define MAXNAME (MAX_FLEN - 1) /* Maximum length of result */
- #define BACKSLASH 92
-
- static int curdir(int,char *); /* Internal functions (see */
- static int norm(char *); /* below). */
- static int dodot(char *);
- static int isfc(char);
- static int retdrv(void);
-
- int flnorm(pfile,pnorm,plast)
- const register char *pfile;
- char *pnorm;
- int *plast;
- {
- int result;
- register int j;
- int drive;
-
- /* Macro to add trailing NUL to pnorm. */
-
- #define ENDNORM {pnorm[j] = '\0';}
-
- /* Macro to quit immediately (perhaps because of error). */
-
- #define EXIT {{ENDNORM;} return result;}
-
- /* Macro to add one character to pnorm. */
-
- #define ADDCHAR(c) {if (j >= MAXNAME) {EXIT;} else pnorm[j++] = (c);}
-
- /* Macro to step to next character in pfile. */
-
- #define NEXT {pfile++;}
-
- result = 1; /* In case of premature exit. */
- j = 0;
- *plast = 0;
-
- if (strlen(pfile) <= 0)
- EXIT
-
- if (isalpha(*pfile) && *(pfile+1) == ':')
- { /* A disk drive was named. */
- drive = tolower(*pfile) - (int) 'a';
- NEXT /* Step past disk drive. */
- NEXT
- }
- else
- {
- drive = retdrv(); /* Infer current drive. */
- }
- ADDCHAR((char) (drive + 'a'))
- ADDCHAR(':')
-
- if (*pfile == BACKSLASH || *pfile == '/')
- { /* Name starts from root. */
- ADDCHAR(BACKSLASH)
- NEXT
- }
- else
- { /* Get start of path from system*/
- if ( curdir(drive + 1,pnorm + 2)
- || norm(pnorm + 2))
- EXIT
- *pnorm = (char) tolower(*pnorm);
- j = (int) strlen(pnorm);
- if (pnorm[j-1] != BACKSLASH)
- ADDCHAR(BACKSLASH)
- }
-
- while (*pfile != '\0') /* Copy remainder of pfile */
- { /* to pnorm. */
- ADDCHAR(*pfile)
- NEXT
- }
- ENDNORM
-
- if ( dodot(pnorm + 2) /* Resolve dot and double dot. */
- || norm(pnorm + 2)) /* Remove extra chars, fold to */
- /* lower case, etc. */
-
- return 1; /* Quit if error. */
-
- for (*plast = (int) strlen(pnorm);
- *plast > 3 && pnorm[(*plast)-1] != BACKSLASH;
- (*plast)--)
- ;
-
- result = 0; /* Success. */
- EXIT
- }
-
- #undef EXIT
- #undef ADDCHAR
- #undef ENDNORM
- #undef NEXT
-
- /**
- *
- * Name curdir -- Report current directory on specified drive.
- *
- * Synopsis ercode = curdir(drive,pdir);
- *
- * int ercode 0 if okay, nonzero if error.
- * int drive Disk drive (0 = default, 1 = A:, etc.)
- * char *pdir Directory path of current directory
- *
- * Description This function returns the full path name (starting from
- * the root directory) of the current directory for the
- * specified drive. The returned path name begins with
- * a backslash character ('\\').
- *
- * The calling function must allocate sufficient space for
- * the returned full path name. Because the path can be 64
- * characters (including the trailing null byte), at least
- * (MAX_FLEN-2) bytes should be allocated by the calling
- * function for pdir. (MAX_FLEN is defined in BFILES.H.)
- *
- * The string returned in pdir may lack a trailing NUL
- * ('\0') if DOS reports an error.
- *
- * Returns ercode DOS function error code
- * *pdir The full path name of the current
- * directory
- *
- **/
-
- static int curdir (drive, pdir)
- int drive;
- char *pdir;
- {
- union REGS regs;
- struct SREGS sregs;
-
- *pdir++ = '\\';
-
- /* Set up to query DOS for the current directory on */
- /* a specified drive. */
- regs.x.ax = 0x4700;
- regs.h.dl = (unsigned char)drive;
- sregs.ds = utseg (pdir);
- regs.x.si = utoff (pdir);
-
- /* Do the call. */
- int86x (FL_DOS_INT, ®s, ®s, &sregs);
-
- /* If error, return it, otherwise return zero. */
- return (regs.x.cflag ? regs.x.ax : 0);
- }
-
- /**
- *
- * Name norm -- Check and normalize a path name (convert to
- * standard form)
- *
- * Synopsis ercode = norm(pfile);
- *
- * int ercode 0 if okay, 1 if error.
- * char *pfile Path name to normalize
- *
- * Description This function validates a path name and partially
- * normalizes it for comparison with other path names.
- * This includes
- *
- * 1) Detecting all illegal characters, including
- * extra periods ('.'), slashes ('/'), backslashes
- * ('\\'), etc.;
- * 2) Converting all letters to lower case;
- * 3) Converting all slashes to backslashes;
- * 4) Removing the trailing colon (':') from a possible
- * device name;
- * 5) Truncating each portion of the path to eight
- * characters + dot + three characters; and
- * 6) Removing the dot from each portion of the path
- * where it is redundant.
- *
- * This does not include
- *
- * 1) Checking the existence of any portion of the path;
- * 2) Checking for the presence of a possible device
- * (if a trailing colon is found);
- * 3) Adding the current disk drive name;
- * 4) Adding the full path from the root directory
- * ("\\"); or
- * 5) Resolving "." and "..".
- *
- * The path name is assumed NOT to specify a disk drive.
- *
- * If the path name is found to contain illegal characters
- * or syntax, 1 is returned as the value of the function
- * and the results in *pfile are invalid.
- *
- * The result is written back to *pfile without increasing
- * the length of the string.
- *
- * Returns ercode 0 if okay, 1 if error.
- * *pfile Character buffer filled with the
- * normalized path name.
- *
- **/
-
- static int norm(pfile)
- register char *pfile;
- {
- int size;
- int result;
-
- register char *ptarget = pfile;
-
- /* Macro to quit immediately (perhaps because of error). */
-
- #define EXIT {*ptarget = '\0'; return result;}
-
- /* Macro to add one character to ptarget. */
-
- #define ADDCHAR(c) {*ptarget++ = (c);}
-
- /* Macro to back up one character in ptarget. */
-
- #define BACKCHAR {ptarget--;}
-
- /* Macro to step to next character in source. */
-
- #define NEXT {pfile++;}
-
- result = 1; /* In case of early exit. */
-
- if (*pfile == BACKSLASH || *pfile == '/')
- {
- ADDCHAR(BACKSLASH)
- NEXT
- }
-
- while (*pfile != 0)
- {
- size = 0;
- while ( *pfile != '.' /* Step through filename, */
- && *pfile != BACKSLASH /* saving up to 8 characters. */
- && *pfile != '/'
- && *pfile != ':'
- && *pfile != '\0')
- {
- if (!isfc(*pfile))
- EXIT
- if (size < 8)
- {
- ADDCHAR((char) tolower(*pfile))
- size++;
- }
- NEXT
- }
- if (size <= 0)
- EXIT /* No filename was found. */
-
- if (*pfile == '.')
- { /* There may be an extension. */
- ADDCHAR('.')
- NEXT
- size = 0;
- while ( *pfile != BACKSLASH /* Save first 3 chars of */
- && *pfile != '/' /* extension. */
- && *pfile != ':'
- && *pfile != '\0')
- {
- if (!isfc(*pfile))
- EXIT
- if (size < 3)
- {
- ADDCHAR((char) tolower(*pfile))
- size++;
- }
- NEXT
- }
- if (size <= 0)
- BACKCHAR /* Drop unneeded period ('.'). */
- }
-
- if (*pfile == BACKSLASH || *pfile == '/')
- {
- NEXT
- if (*pfile == '\0')
- EXIT /* Error: trailing slash or */
- /* backslash after filename. */
- ADDCHAR(BACKSLASH)
- }
- else if (*pfile == ':')
- {
- NEXT
- if (*pfile == '\0')
- result = 0; /* OK -- this may be a device. */
- EXIT
- }
- }
-
- result = 0; /* Success. */
- EXIT
- }
-
- #undef EXIT
- #undef ADDCHAR
- #undef BACKCHAR
- #undef NEXT
-
- /**
- *
- * Name dodot -- Resolve dot (".") and double dot ("..")
- * in a path name.
- *
- * Synopsis ercode = dodot(pfile);
- *
- * int ercode 0 if okay, 1 if error.
- * char *pfile Path name to modify
- *
- * Description This function removes the special file names "." and
- * ".." from a full path name (which begins from the root
- * directory of a drive). Each ".." removes the previous
- * subdirectory from the path; each "." is just removed.
- *
- * This function does not
- *
- * 1) Detect illegal characters, such as
- * extra periods ('.'), slashes ('/'), backslashes
- * ('\\'), etc.;
- * 2) Convert letters to lower case;
- * 3) Remove the trailing colon (':') from a possible
- * device name;
- * 4) Truncate any portion of the path to eight
- * characters + dot + three characters;
- * 5) Remove any redundant dot from a directory name
- * in the path;
- * 6) Check the existence of any portion of the path;
- * 7) Check for the presence of a possible device
- * (if a trailing colon is found);
- * 8) Add the current disk drive name; or
- * 9) Add the full path from the root directory ("\\").
- *
- * The path name is assumed NOT to specify a disk drive.
- *
- * The result is written back to *pfile without increasing
- * the length of the string.
- *
- * Slashes are converted to backslashes.
- *
- * This function detects when too many double dots ("..")
- * have consumed the entire path or when a dot begins an
- * illegal filename. If an error occurs then 1 is returned
- * as the value of the function and the result in *pfile is
- * invalid.
- *
- * Returns ercode 0 if okay, 1 if error.
- * *pfile Character buffer filled with the
- * modified path name.
- *
- **/
-
- static int dodot(pfile)
- register char *pfile;
- {
- int result,start;
- register char *pfrom = pfile;
- register int j;
-
- /* Macro to quit immediately (perhaps because of error). */
-
- #define EXIT {pfile[j] = '\0'; return result;}
-
- /* Macro to add one character to target. */
-
- #define ADDCHAR(c) {pfile[j++] = (c);}
-
- /* Macro to back up one character in target. */
-
- #define BACKCHAR {j--;}
-
- /* Macro to step to next character in source. */
-
- #define NEXT {pfrom++;}
-
- result = 1; /* In case of early exit. */
- j = 0;
-
- if (*pfrom == BACKSLASH || *pfrom == '/')
- {
- ADDCHAR(BACKSLASH)
- NEXT
- }
- start = j;
-
- while (*pfrom != '\0')
- {
- if (*pfrom == '.')
- {
- NEXT
- if (*pfrom == '.')
- { /* Double dot: */
- NEXT
- do /* Strip off last directory */
- { /* name. */
- BACKCHAR
- } while (j > 0 && pfile[j-1] != BACKSLASH);
- if (j < start)
- EXIT /* Error: went too far. */
- }
- else
- {
- /* Do nothing: just discard the lone dot. */
- }
- if (*pfrom == BACKSLASH || *pfrom == '/')
- {
- NEXT
- }
- else if (*pfrom == '\0')
- {
- /* Do nothing. */
- }
- else
- EXIT /* Only slash or backslash may */
- /* follow one or two periods. */
- }
- else
- { /* Just copy to next slash or */
- /* backslash. */
- while ( *pfrom != BACKSLASH
- && *pfrom != '/'
- && *pfrom != '\0')
- {
- ADDCHAR(*pfrom)
- NEXT
- }
- if (*pfrom == BACKSLASH || *pfrom == '/')
- {
- ADDCHAR(BACKSLASH)
- NEXT
- }
- }
- }
-
- if (j > start && pfile[j-1] == BACKSLASH)
- BACKCHAR /* Remove extra trailing */
- /* backslash. */
-
- result = 0;
- EXIT
- }
-
- #undef EXIT
- #undef ADDCHAR
- #undef BACKCHAR
- #undef NEXT
-
- /**
- *
- * Name isfc -- Return whether a character is a valid DOS
- * filename character.
- *
- * Synopsis isokay = isfc(ch);
- *
- * int isokay 1 if okay, 0 if illegal.
- * char ch Character to check.
- *
- * Description This function checks whether a character is a valid DOS
- * filename character and returns 1 if so, 0 if not.
- *
- * Returns isokay 1 if okay, 0 if illegal.
- *
- **/
-
- static int isfc(ch)
- char ch;
- {
- return ( isalpha(ch)
- || isdigit(ch)
- || (-1 != stschind(ch,"$@!%`'()-_^~")));
- }
-
-
-
- /**
- *
- * Name retdrv -- Return default disk drive number.
- *
- * Synopsis drive = retdrv ();
- *
- * int drive 0 for drive A, 1 for B, etc.
- *
- * Description This function returns the current drive.
- *
- * Returns drive Current drive number.
- *
- **/
-
- static int retdrv()
- {
- union REGS regs;
-
- regs.x.ax = 0x1900;
- int86 (FL_DOS_INT, ®s, ®s);
- return (regs.h.al);
- }