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.
- * 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 command. If the
- * ASSIGN command 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 3.0 (C)Copyright Blaise Computing Inc. 1986
- *
- **/
-
- #include <ctype.h>
- #include <string.h>
-
- #include <bdirect.h>
- #include <bfile.h>
- #include <bstring.h>
-
- #define MAXNAME (MAX_FLEN - 1) /* Maximum length of result */
-
- static int norm(char *); /* Internal functions (see */
- static int dodot(char *); /* below). */
- static int isfc(char);
-
- int flnorm(pfile,pnorm,plast)
- register char *pfile;
- char *pnorm;
- int *plast;
- {
- int result;
- register int j;
- int drive;
-
- /* Macro to quit immediately (perhaps because of error). */
-
- #define EXIT {pnorm[j] = '\0'; return result;}
-
- /* Macro to add one character to pnorm. */
-
- #define ADDCHAR(c) {if (j >= MAXNAME) {EXIT} else pnorm[j++] = c;}
-
- /* Macro to add trailing NUL to pnorm. */
-
- #define ENDNORM {pnorm[j] = '\0';}
-
- /* Macro to step to next character in pfile. */
-
- #define NEXT {pfile++;}
-
- result = 1; /* In case of premature exit. */
- j =
- *plast = 0;
-
- if (strlen(pfile) <= 0)
- EXIT
-
- if (isalpha(*pfile) && *(pfile+1) == ':')
- { /* A disk drive was named. */
- drive = tolower((int) *pfile) - (int) 'a';
- NEXT /* Step past disk drive. */
- NEXT
- }
- else
- {
- drive = drretdrv(); /* Infer current drive. */
- }
- ADDCHAR((char) (drive + 'a'))
- ADDCHAR(':')
-
- if (*pfile == '\\' || *pfile == '/')
- { /* Name starts from root. */
- ADDCHAR('\\')
- NEXT
- }
- else
- { /* Get start of path from system*/
- if ( drcurdir(drive + 1,pnorm)
- || norm(pnorm + 2))
- EXIT
- *pnorm = tolower(*pnorm);
- j = (int) strlen(pnorm);
- if (pnorm[j-1] != '\\')
- ADDCHAR('\\')
- }
-
- 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] != '\\';
- (*plast)--)
- ;
-
- result = 0; /* Success. */
- EXIT
- }
-
- #undef EXIT
- #undef ADDCHAR
- #undef NEXT
-
- /**
- *
- * 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 == '\\' || *pfile == '/')
- {
- ADDCHAR('\\')
- NEXT
- }
-
- while (*pfile != 0)
- {
- size = 0;
- while ( *pfile != '.' /* Step through filename, */
- && *pfile != '\\' /* saving up to 8 characters. */
- && *pfile != '/'
- && *pfile != ':'
- && *pfile != '\0')
- {
- if (!isfc(*pfile))
- EXIT
- if (size < 8)
- {
- ADDCHAR(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 != '\\' /* Save first 3 chars of */
- && *pfile != '/' /* extension. */
- && *pfile != ':'
- && *pfile != '\0')
- {
- if (!isfc(*pfile))
- EXIT
- if (size < 3)
- {
- ADDCHAR(tolower(*pfile))
- size++;
- }
- NEXT
- }
- if (size <= 0)
- BACKCHAR /* Drop unneeded period ('.'). */
- }
-
- if (*pfile == '\\' || *pfile == '/')
- {
- NEXT
- if (*pfile == '\0')
- EXIT /* Error: trailing slash or */
- /* backslash after filename. */
- ADDCHAR('\\')
- }
- 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 == '\\' || *pfrom == '/')
- {
- ADDCHAR('\\')
- 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] != '\\');
- if (j < start)
- EXIT /* Error: went too far. */
- }
- else
- {
- /* Do nothing: just discard the lone dot. */
- }
- if (*pfrom == '\\' || *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 != '\\'
- && *pfrom != '/'
- && *pfrom != '\0')
- {
- ADDCHAR(*pfrom)
- NEXT
- }
- if (*pfrom == '\\' || *pfrom == '/')
- {
- ADDCHAR('\\')
- NEXT
- }
- }
- }
-
- if (j > start && pfile[j-1] == '\\')
- 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,"$@!%`'()-_^~")));
- }