/* @(#)filepath.c 17.1.1.1 (ESO-IPG) 01/25/02 17:26:43 */ /*--------------------------------------------------------------------- * $Date: 93/07/16 19:24:41 $ $Revision: 2.7.6.2 $ *--------------------------------------------------------------------- * * * Copyright (c) 1990, Visual Edge Software Ltd. * * ALL RIGHTS RESERVED. Permission to use, copy, modify, and * distribute this software and its documentation for any purpose * and without fee is hereby granted, provided that the above * copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of Visual Edge Software not be * used in advertising or publicity pertaining to distribution of * the software without specific, written prior permission. The year * included in the notice is the year of the creation of the work. *-------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include #include #include #include #if defined(sco) || defined(motor88) || defined(ncrix86) || defined(linux) || defined(vms) # include #endif #if defined(vms) # include #endif #include "pathlist.h" #include "valloc.h" #include "global.h" #include "vtypes.h" #ifdef MOTIF_WIDGETS #include /* for MAXPATHLEN... */ #ifndef MAXPATHLEN #define MAXPATHLEN 1024 #endif /* MAXPATHLEN */ #endif /* MOTIF_WIDGETS */ /* header files needed for messages */ #include "uimx_cat.h" #include "misc1_ds.h" #define CGETS_MISC(ms,ds_ms) UxCatGets(MC_MISC,ms,ds_ms) #define GETMSG(ms) UXCATGETS(MC_MISC1,MS_MISC1_,ms) /**** This define is the maximum number of characters in a filename **** BEFORE the name is appended with '.rf' or '.c' ****/ #define TRUNC_LENGTH 11 #define MAX_FILE_LEN 14 #define MAX_SUFFIX 10 extern char *getenv(); extern char *UxToLowerString(); char *UxGetDirName(); char *UxTruncateFilename(); /***************************************************************************** NAME: int UxCheckForInvalidCharacters (filename) INPUT: char *filename - filename to check RETURN: int - 0 = ok, 1 = there are invalid characters DESCRIPTION: Scans the filename entered by the user for invalid characters; also checks for '//', which is illegal. An empty filename is also an error. LAST REV: 10 April 1990 -- allow $, it's not invalid -----------------------------------------------------------------------------*/ int UxCheckForInvalidCharacters (filename) char *filename; { static char bad_set[] = "!@%^&*()=|\\`<>?\'\"[]{}; "; /* check for zero length */ if (strlen (filename) == 0) return 1; /* look for any occurence of bad characters */ if (Ux_strpbrk (filename, bad_set) != NULL) return 1; /* filename is ok (or Ux_strpbrk failed!) */ return 0; } /****************************************************************************** NAME: UxShouldTruncate () INPUT: OUTPUT: --- RETURN: int : TRUE / FALSE DESCRIPTION: Checks if the resource "truncateFilenames" is set to TRUE in which case we turn TRUE. EXT REFERENCES: --- EXT EFFECTS: --- LAST REV: October 9 1991 -----------------------------------------------------------------------------*/ int UxShouldTruncate() { static int initialized = FALSE; static int truncate = FALSE; if ( initialized == FALSE ) { char *UxGetUimxDefault(), *UxToLowerString(), *trunc_res; /***********************************************/ /* Find out if filenames need to be truncated */ /* by examining the truncateFilenames */ /* resource. */ /***********************************************/ initialized = TRUE; trunc_res = UxGetUimxDefault ("truncateFilenames", "false"); if (UxStrEqual ( UxToLowerString(trunc_res), "false")) truncate = FALSE; else truncate = TRUE; } return(truncate); } /****************************************************************************** NAME: UxTruncateFilename (fname, suffix_len) INPUT: char *fname : name to truncate int suffix_len : length of suffix to be added OUTPUT: --- RETURN: char * : truncated name DESCRIPTION: returns a filename with its last component truncated to not more than 14 characters including the possible suffix. NB! This function may modify the passed filename. EXT REFERENCES: --- EXT EFFECTS: --- LAST REV: 5 November 1990 IBM Beta1 -- made this function available to OLE and UIM/X. -- Also made the strcmp case insensitive by calling UxToLowerString() -----------------------------------------------------------------------------*/ char* UxTruncateName(fname, slen) char* fname; int slen; { char *name; char str[MAX_FILE_LEN+1]; int len, tail_len, ncaps, ndigits; int max_len, max_tail; int i, j; /*----------------------------------------------------- * Get the file name itself, without path. *-----------------------------------------------------*/ if ((name = strrchr(fname, '/')) != NULL) { name++; } else { name = fname; } /*----------------------------------------------------- * Is name part too long? *-----------------------------------------------------*/ len= strlen(name); if ((len + slen) <= MAX_FILE_LEN) { return fname; } /*------------------------------------------------------- * We shorten the name by sliding digits and capitals * from the whole tail of the original name * into the last max_tail characters of the shorter name. * Count digits and caps so we can compute the tail length. * Keep counting until we've found all the digits we * can use; we'll drop caps in favour of digits. * 'max_len-max_tail' is the first char allowed to change. *-------------------------------------------------------*/ max_tail = (MAX_SUFFIX - slen); max_len = (MAX_FILE_LEN - slen); ncaps = ndigits = 0; for (i = len; i >= max_len-max_tail; i--) { if (ndigits >= max_tail) break; else if (ndigits + ncaps + i < max_len) break; else if (isdigit(name[i])) ndigits++; else if (isupper(name[i])) ncaps++; } /*----------------------------------------------------- * How long a tail of digits and caps? * If there are too many, keep more digits. *-----------------------------------------------------*/ tail_len = ndigits + ncaps; if (tail_len > max_tail) { tail_len = max_tail; ncaps = tail_len - ndigits; } /*----------------------------------------------------- * Shorten the name by moving up digits and caps. * Note we may skip caps, but copy all digits we meet. *-----------------------------------------------------*/ strncpy (str, name, sizeof(str)); for(i = j = (max_len-tail_len); i < len && j < max_len; i++) { if (isdigit(name[i])) { str[j++] = name[i]; } else if (isupper(name[i]) && ncaps-- > 0) { str[j++]= name[i]; } } str[j] = '\0'; /*----------------------------------------------------- * 'name' is a pointer to where the filename part of * the original path starts. str is a shortened name, * so it will surely fit into the end of the original. *-----------------------------------------------------*/ strcpy(name, str); return fname; } /****************************************************************************** NAME: UxTruncateFilename (fname, suffix_len) INPUT: char *fname : name to truncate int suffix_len : length of suffix to be added OUTPUT: --- RETURN: char * : truncated name DESCRIPTION: If the 'truncateFilenames' resource is true, returns a filename with its last component truncated to not more than 14 characters including the possible suffix. NB! This function may modify the passed filename. If the 'truncateFilenames' resource is false, just return the given filename unchanged. EXT REFERENCES: --- EXT EFFECTS: --- LAST REV: 5 November 1990 IBM Beta1 -- made this function available to OLE and UIM/X. -- Also made the strcmp case insensitive by calling UxToLowerString() -----------------------------------------------------------------------------*/ char* UxTruncateFilename(fname, slen) char* fname; int slen; { if(UxShouldTruncate() == FALSE) { return(fname); } return UxTruncateName (fname, slen); } /***************************************************************************** NAME: dstring gethome(username) INPUT: dstring username - user name (with ~) RETURN: home directory DESCRIPTION: return the user 'uname's home directory Accepts a dstring parameter, which it frees. Creates and returns a dstring which should be freed by the calling function. LAST REV: 10 April 1990 -- parameter is a dstring -----------------------------------------------------------------------------*/ static dstring gethome(username) dstring username; { int uid; char *uname; dstring home; char *pntr, hold, *end; struct passwd *pw; uname = dnstr(username); end= uname+1; while(isalnum(*end)) end++; hold= *end; *end= '\0'; if(strcmp(uname, "~") == 0) { pntr= getenv("HOME"); if(pntr != NULL) { home= dcreate(pntr); *end= hold; dappend(home, end); dfree(username); return(home); } if((pntr= getenv("USER")) != NULL) pw= getpwnam(pntr); else { uid= getuid(); pw= getpwuid(uid); } if(pw) { home= dcreate(pw->pw_dir); *end= hold; dappend(home, end); dfree(username); return(home); } dfree(username); return(dcreate(NULL)); } uname++; pw= getpwnam(uname); if(pw) home= dcreate(pw->pw_dir); else home= dcreate(NULL); *end= hold; dappend(home, end); dfree(username); return(home); } /***************************************************************************** NAME: dstring mkname(path, name) INPUT: char *path - path to file *name - name of file RETURN: full filename DESCRIPTION: return the full filename of 'file' in the directory 'path' LAST REV: Feb 19/1989 -----------------------------------------------------------------------------*/ static dstring mkname(path, name) char *path, *name; { dstring rtrn; int len; rtrn= dcreate(path); len = strlen(path); if ( (len > 0) && (path[len-1] != '/') ) dappend(rtrn, "/"); dappend(rtrn, name); return(rtrn); } /***************************************************************************** NAME: dstring expand_macros(ds) INPUT: dstring ds - macros to expand RETURN: expanded macros DESCRIPTION: expand all the macros in 'ds', free it, and return expansion LAST REV: Feb 21/1989 -----------------------------------------------------------------------------*/ static dstring expand_macros(ds) dstring ds; { char *pntr, *start, *end = NULL, endc; dstring rtrn; rtrn= dcreate(NULL); start= dnstr(ds); pntr= strchr(start, '$'); while(pntr) { *(pntr++)= '\0'; dappend(rtrn, start); end= pntr; while(isalnum(*end)) end++; endc= *end; *end= '\0'; if(*pntr != '\0'); dappend(rtrn, getenv(pntr)); *end= endc; start= end; pntr= strchr(start, '$'); } dappend(rtrn, end); dfree(ds); return(rtrn); } /***************************************************************************** NAME: dstring tokenize(ds) INPUT: dstring *ds - dstring to tokenize RETURN: first token in 'ds' DESCRIPTION: return the first token in 'ds' and reset 'ds' to point to the rest of the string LAST REV: July 25 1990 - handle separators at the end of a path. - handle a path consisting of only separators. -----------------------------------------------------------------------------*/ static dstring tokenize(ds) dstring *ds; { char *pntr, *end; dstring rtrn, dsrtrn; pntr= dgetstr(*ds); if(pntr == NULL) return(dcreate(NULL)); while(*pntr && (strchr(": ,\n\t", *pntr) != NULL)) pntr++; end= strpbrk(pntr, ": ,\n\t"); if(end != NULL) *end++ = '\0'; rtrn= dcreate(pntr); if(end != NULL) { while (*end && (strchr(": ,\n\t", *end) != NULL)) end++; if (*end) dsrtrn= dcreate(end); else dsrtrn= dcreate(NULL); } else { dsrtrn= dcreate(NULL); } dfree(*ds); *ds= dsrtrn; return(rtrn); } /****************************************************************************** NAME: dstring expand_name(tok) INPUT: dstring tok - taken to expand RETURN: expanded token (original freed if needed) DESCRIPTION: expand the env vars and ~[uname]'s in tok LAST REV: January 03 1991 bugfix 1116. -----------------------------------------------------------------------------*/ /* * An always-true predicate to pass to XtResolvePath. */ /*ARGSUSED*/ static Boolean AlwaysTrue(file) String file; { return True; } static dstring expand_name(tok) dstring tok; { dstring exp, rtrn; if(strchr(dnstr(tok), '$') != NULL) { exp = expand_macros(tok); /* tok is freed in expand_macros */ return(expand_name(exp)); /* exp is freed in expand_name */ } else if(*(dnstr(tok)) == '~') { exp = gethome(tok); /* tok is freed in gethome */ return(expand_name(exp)); /* exp is freed in expand_name */ } else #ifdef MOTIF_WIDGETS { /* Expand language path character %L (and other toolkit defaults). * Several arguments to XtResolvePathname are NULL so the toolkit * defaults apply. We pass AlwyasTrue because UIM/X builds its * paths piece-by-piece; the partial paths we expand here aren't * meant to name exisiting files. */ char *r; r = XtResolvePathname ( UxDisplay, (String) NULL, /* type o%T e ntion */ (String) getenv("UXAPP"), /* name (app s) for %N */ (String) NULL, /* suffix (none) */ (String) dnstr(tok), /* path */ (Substitution) NULL, /* substitutions */ 0, /* num substitions */ (XtFilePredicate) AlwaysTrue /* file access predicate */ ); if (r) { dfree(tok); rtrn = dcreate(r); XtFree(r); return rtrn; } else rtrn = tok; return rtrn; } #else { return(tok); } #endif /* MOTIF_WIDGETS */ } /***************************************************************************** NAME: int UxFileExists(fname) INPUT: char *fname - filename RETURN: 1: file or directory exists 0: file not found DESCRIPTION: return whether the file or directory 'fname' exists LAST REV: March 18, 1991 Replaced stat call by more efficient access call. -----------------------------------------------------------------------------*/ int UxFileExists(fname) char *fname; { if (access(fname, 0) < 0) return(0); return(1); } /***************************************************************************** NAME: pathlist UxInitPath(str) INPUT: char *str - initial path list RETURN: pathlist object DESCRIPTION: initialize a path list to files. LAST REV: Feb 19/1989 -----------------------------------------------------------------------------*/ pathlist UxInitPath(str) char *str; { pathlist path; path= (pathlist) UxMalloc(sizeof(dstring)); *path= dcreate(NULL); UxAddPath(path, str); return(path); } /***************************************************************************** NAME: void UxAddPath(path, str) INPUT: pathlist path - pathlist char *str - list of dirs to add DESCRIPTION: add the directories in 'str' to the pathlist 'path' LAST REV: Feb 19/1989 -----------------------------------------------------------------------------*/ void UxAddPath(path, str) pathlist path; char *str; { dstring pcopy, tok; if((str == NULL) || (str[0] == '\0')) return; if(path == NULL) return; pcopy= dcreate(str); tok= tokenize(&pcopy); while(dgetstr(tok) != NULL) { tok= expand_name(tok); if(strlen(dnstr(tok)) != 0) { if(dlen(*path) != 0) dappend(*path, ":"); dconcat(*path, tok); } dfree(tok); tok= tokenize(&pcopy); } /* don't need to free tok or pcopy, since they are now null */ } /***************************************************************************** NAME: void UxResetPath(path, str) INPUT: pathlist path - pathlist char *str - new list of paths DESCRIPTION: reset the pathlist 'path' to be 'str' LAST REV: Feb 19/1989 -----------------------------------------------------------------------------*/ void UxResetPath(path, str) pathlist path; char *str; { dfree(*path); UxAddPath(path, str); } /***************************************************************************** NAME: void UxFreePath(path) INPUT: pathlist path - pathlist DESCRIPTION: free the pathlist 'path' LAST REV: Feb 19/1989 -----------------------------------------------------------------------------*/ void UxFreePath(path) pathlist path; { dfree(*path); UxFree(path); } /***************************************************************************** NAME: char *UxGetPath(path) INPUT: pathlist path - pathlist RETURN: pathlist in string form DESCRIPTION: return the pathlist as a string (not to be freed) LAST REV: Feb 19/1989 -----------------------------------------------------------------------------*/ char *UxGetPath(path) pathlist path; { if(path == NULL) return(""); return(dnstr(*path)); } /***************************************************************************** NAME: char *UxExpandFilename(path_list, fname) INPUT: pathlist path_list - pathlist char *fname - filename RETURN: expanded filename DESCRIPTION: Find the expanded name of 'fname' using the dirs in 'path' LAST REV: April 10, 1990 -- free filename at the proper place -----------------------------------------------------------------------------*/ char *UxExpandFilename(path_list, fname) pathlist path_list; char *fname; { static dstring filename= UxEmptyDstring; dstring path, file; char *pntr; file= expand_name(dcreate(fname)); fname= dnstr(file); if(*fname == '\0') return(NULL); if(fname[0] == '/') { dfree(filename); filename= dcreate(fname); dfree(file); if(UxFileExists(dnstr(filename))) return(dnstr(filename)); else return(NULL); } if(path_list == NULL) { dfree(file); return(NULL); } path= dcopy(*path_list); pntr= strtok(dnstr(path), ": ,\n\t"); while(pntr) { dfree(filename); filename= mkname(pntr, fname); if(UxFileExists(dnstr(filename))) { dfree(path); dfree(file); return(dnstr(filename)); } pntr= strtok(NULL, ": ,\n\t"); } dfree(file); dfree(path); return(NULL); } /***************************************************************************** NAME: char *UxExpandAllFilenames(path_list, fname) INPUT: pathlist path_list - pathlist or NULL char *fname - filename RETURN: expanded filename DESCRIPTION: Find the expanded name of 'fname' using the dirs in 'path_list' Remember position in path_list between calls so that subsequent calls can continue in the list where the previous call left off. If path_list is NULL then continue from previous path otherwise start from given path_list. Don't return same expanded name more than once. If fname is NULL then use previous fname. LAST REV: March 13, 1991 See bugfix 2111 -----------------------------------------------------------------------------*/ char *UxExpandAllFilenames(path_list, fname) pathlist path_list; char *fname; { static dstring filename= UxEmptyDstring; static dstring path= UxEmptyDstring, file= UxEmptyDstring; static dstring alreadyReturned= UxEmptyDstring; static char *pntr; if (fname != NULL) { dfree(file); file= expand_name(dcreate(fname)); } fname= dnstr(file); if(*fname == '\0') return(NULL); if(fname[0] == '/') { dfree(filename); filename= dcreate(fname); if (strstr(dnstr(alreadyReturned), fname) == NULL && UxFileExists(dnstr(filename))) { dappend(alreadyReturned, ":"); dconcat(alreadyReturned, filename); return(dnstr(filename)); } else return(NULL); } if (path_list != NULL) { dfree(path); path= dcopy(*path_list); dappend(path, ":"); /* Make sure we end with ':' */ dfree(alreadyReturned); alreadyReturned = dcreate(""); pntr= strtok(dnstr(path), ": ,\n\t"); } /* * Start from where we left off or from beginning if new path_list * was specified. */ while(pntr) { dfree(filename); filename= mkname(pntr, fname); pntr[strlen(pntr)] = ':'; pntr= strtok(NULL, ": ,\n\t"); if (strstr(dnstr(alreadyReturned), dgetstr(filename)) == NULL && UxFileExists(dgetstr(filename))) { /* * Restore path string before returning. */ dappend(alreadyReturned, ":"); /* The UIM/X 2.0 releases mostly have * 'dgetstr(filename)' in the line below, * which is garbage. */ dconcat(alreadyReturned, filename); return(dgetstr(filename)); } } return(NULL); } /****************************************************************************** NAME: char *UxGetFilename(fname) INPUT: char *fname - filename RETURN: expanded filename DESCRIPTION: expand all ~'s and $VAR's in the passed in filename LAST REV: 15 August 1990 OLE MERGE -- removed the call to TruncateFilename now called from cfile.c and save.c -----------------------------------------------------------------------------*/ char *UxGetFilename(fname) char *fname; { static dstring filename= UxEmptyDstring; /* check for invalid characters in supplied filename */ if (UxCheckForInvalidCharacters (fname)) return NULL; dfree(filename); filename= expand_name(dcreate(fname)); if (dnstr (filename)) { char *xname, *CondenseDots(); if (xname = CondenseDots (dnstr(filename))) { dfree (filename); filename = dcreate (xname); UxFree (xname); } } return(dnstr(filename)); } /***************************************************************************** NAME: char *UxExpandEnv(str) INPUT: char *str - string to expand RETURN: expanded string DESCRIPTION: Expand all the environment variables in 'str' until there are no more '$'s in the string: LAST REV: Feb 22/1989 -----------------------------------------------------------------------------*/ char *UxExpandEnv(str) char *str; { static dstring rtrn= UxEmptyDstring; dfree(rtrn); rtrn= dcreate(str); while(strchr(dnstr(rtrn), '$') != NULL) rtrn= expand_macros(rtrn); return(dnstr(rtrn)); } /****************************************************************************** NAME: char * UxGetDirName(path) INPUT: char *path; -- path to extract the directory from RETURN: directory name if the path is not NULL, must be freed. otherwise, returns NULL, nothing should be freed.. DESCRIPTION: Strips the filename from the path. If the path is not valid or is just a filename, the function sets the path to the current directory The return value must be freed. LAST REV: Feb 28 1991 -----------------------------------------------------------------------------*/ char *UxGetDirName(path) char *path; { int len; char *pntr, *dirname; if (path == (char *) NULL) { return (char *) NULL; } len = strlen(path); dirname = (char *) UxMalloc((len + 1) * sizeof(char)); strcpy(dirname, path); pntr = strrchr(dirname, '/'); if (pntr != NULL) { if (pntr == dirname) strcpy(dirname, "/"); *pntr = '\0'; } else { strcpy(dirname, "."); } return dirname; } /****************************************************************************** NAME: int UxWriteAccess(path, error) INPUT: char *path; -- the path to access int *error; -- a return error flag RETURN: Checks if a path can be accessed. The calling function should check the return value from UxWriteAccess(). If it is -1, then it should check for the following error flags: error = EACCES -> file or directory is not writable. error = ENOENT -> file or directory do not exist error = EISDIR -> path is a directory If it is 0, then it should check for the following error flags: error = EEXIST -> file exists already error = ENOENT -> file does not exist DESCRIPTION: Checks for the write permission on path. 7 cases could arise: (a) path is NULL --> return -1. (b) path is a directory --> return -1. (c) directory specified in path is not writable and file does not exist --> return -1. (d) directory specified in path is not writable and file does not exist --> return -1. (e) dir is valid, and file does not exist. --> return 0. (f) path is valid, and file is not writable --> return -1. (g) path is valid, and file is writable --> return 0. LAST REV: Feb 28 1991 -----------------------------------------------------------------------------*/ int UxWriteAccess (path,error) char *path; int *error; { int result; char *dirname; struct stat buf; if ((path == NULL) || (*path == '\0')) { *error = ENOENT; return -1; } /* check if the path points to a filename, or a directory */ result = stat(path, &buf); /* path is not valid, find out why */ if (result == -1) { dirname = UxGetDirName (path); result = access(dirname, W_OK); free (dirname); /* directory is not writable, and file does not exist */ if (result == -1) { *error = EACCES; return result; } /* directory is writable, file does not exist, this is OK */ else { *error = ENOENT; } } /* path is valid */ else { /* path points to a directory */ if (buf.st_mode & S_IFDIR) { *error = EISDIR; return -1; } /* file is not writable */ if (!(buf.st_mode & S_IWRITE)) { *error = EACCES; return -1; } /* file exists already and is writable */ else { *error = EEXIST; } } return 0; } /****************************************************************************** NAME: char *UxGetCurrentDir () INPUT: RETURN: char * -current directory OUTPUT DESCRIPTION: gets the current directory. Returns allocated memory, therefore calling function should free memory. CREATED: Oct 29/91 fix3099 LAST REV: -----------------------------------------------------------------------------*/ char *UxGetCurrentDir () { char *getcwd (), *cwd; if (cwd = (char *) UxMalloc (MAXPATHLEN +1)) { return getcwd (cwd, MAXPATHLEN + 1); } return (char *)NULL; } /****************************************************************************** NAME: char CondenseDots (fname) INPUT: char *fname; -- path to extract the directory from RETURN: expanded path; OUTPUT DESCRIPTION: Expands dots in specified file path. Allocates memory for buffer, therefore, calling function should free return value. The argument is expanded to an absolute name in the process. CREATED: July 25/91 LAST REV: -----------------------------------------------------------------------------*/ char *CondenseDots (fname) char *fname; { char *fstr, *xname = (char *)NULL; if (fname == NULL) { return NULL; } else if (*fname == 0) { return UxCopyString(fname); } /*------------------------------------------------------------- * If fname does not begin with a slash, prepend current path. *------------------------------------------------------------*/ if (fname [0] != '/') { char *cwd; cwd = UxGetCurrentDir (); if (cwd) { xname = (char *) UxMalloc (strlen(cwd) + strlen(fname) + 3); sprintf (xname, "%s/%s/", cwd, fname); UxFree (cwd); } else { xname = (char *) UxMalloc (strlen(fname) + 2); sprintf (xname, "%s/", fname); } } else { /*---------------------------------------------------- * Append a slash to the path, needed for below. *----------------------------------------------------*/ xname = UxMalloc (strlen (fname) + 2); sprintf (xname, "%s/", fname); } /*----------------------------------------------- * Loop until all dots have been condensed out *----------------------------------------------*/ while (1) { char *dots; fstr = UxCopyString (xname); if (dots = strstr(fstr, "/./")) { /*----------------------------- * "/./" -- remove "./" *-----------------------------*/ dots [1] = '\0'; sprintf (xname, "%s%s", fstr, dots +3); } else if (dots = strstr(fstr, "/../")) { /*------------------------------------- * remove /../ and preceding directory *-------------------------------------*/ if (dots == fstr) { /* Path starts in "/../", not much to do. */ break; } else { char *tail = dots + 4; while (*(--dots) != '/') { if (dots == fstr) { break; } } if (*dots == '/') { dots [1] = '\0'; sprintf (xname, "%s%s", fstr, tail); } else { break; /* No leading /name/../ */ } } } else { /*----------------------------------------------- * No more dots. Remove the '/' we appended. *-----------------------------------------------*/ int len; if ((len = strlen (xname)) > 1) xname [len - 1] = '\0'; UxFree (fstr); return xname; } UxFree (fstr); } /*------------------------------------------------------------ * If we failed the normal loop, just use the original. *------------------------------------------------------------*/ UxFree (fstr); UxFree (xname); return UxCopyString(fname); } /****************************************************************************** NAME: int CreateDirectory(path, mode) INPUT: char *path; -- directory to create. ushort mode; -- protection mode. RETURN: error status. DESCRIPTION: Creates a directory with the specified mode, if the directory does not exist, and the parent directory is has write permission. LAST REV: July/31/91 Oct/23/91 fix3074 -----------------------------------------------------------------------------*/ static int CreateDirectory (dir, mode) char *dir; ushort mode; { int status; status = access (dir, 2); if (status == -1) { if (errno == ENOENT) { status = mkdir (dir, mode); } else if (errno == EISDIR) { status = 0; } } return (status == 0 ? NO_ERROR : ERROR); } /****************************************************************************** NAME: int UxGetDirMode(path, mode) INPUT: char *path; -- directory to create. ushort *mode; -- protection mode. RETURN: error status. OUTPUT: protection mode DESCRIPTION: gets the protection mode of the specified directory. LAST REV: July/31/91 Oct 7/91 fix3031 -----------------------------------------------------------------------------*/ int UxGetDirMode (dir, mode) char *dir; ushort *mode; { struct stat out; int status; status = stat (dir, &out); if (status == 0) { *mode = out.st_mode; return NO_ERROR; } return ERROR; } /****************************************************************************** NAME: int UxMakeRelativeDirs (absp, relp) INPUT: char *absp; -- absolute path where to create relative dirs. char *relp; -- relative directories to be created. RETURN: error status. DESCRIPTION: Create all directories in relp if they do not exist, and if their parent directory has write access. Each directory is built with the same access flags as its parent directory. LAST REV: July/31/91 fix2845 Oct 7/91 fix3031 Oct/23/91 fix3074 -----------------------------------------------------------------------------*/ int UxMakeRelativeDirs (absp, relp) char *absp, *relp; { char *token; char *dir; int status = NO_ERROR; if (!absp || !*absp) return ERROR; if (!relp || !*relp) return ERROR; dir = (char *)UxMalloc (strlen (absp) + 1); strcpy (dir, absp); token = strtok (relp, "/"); while (token != NULL) { char *tmp; ushort mode; status = UxGetDirMode (dir, &mode); tmp = UxCopyString (dir); dir = UxRealloc (dir, strlen (tmp) + strlen (token) + 2); sprintf (dir, "%s/%s", tmp, token); UxFree (tmp); if (status == NO_ERROR) status = CreateDirectory (dir, mode); if (status == ERROR) { return ERROR; } token = strtok (NULL, "/"); } return status; } /****************************************************************************** NAME: UxValidateFilenameLength (fname) INPUT: char *fname : name to truncate int suffix_len : length of suffix to be added OUTPUT: --- RETURN: char * : truncated name DESCRIPTION: Check if the passed filename satisfies the length requirements. If the filename is too long, return an error message. Otherwise return NULL. If filenameTruncation is not turned on, then the filename is always valid. EXT REFERENCES: --- EXT EFFECTS: --- LAST REV: -----------------------------------------------------------------------------*/ char *UxValidateFilenameLength (fname) char *fname; { int len; char *name; if (!UxShouldTruncate()) return NULL; /* If filename truncation is turned on, and the file exists, * we will assume that the system can read the file and * the validation is therefore successfull. */ if (UxFileExists(fname)) return NULL; name= strrchr(fname, '/'); if(name == NULL) { name= fname; } else { name++; } len = strlen(name); if (len > MAX_FILE_LEN) { return (GETMSG (LONG_FNAME)); } else { return NULL; } } /*------------------------------------------------------------------------ * NAME: UxAbbreviateFileName * * INPUT: char* fname; * RETURNS: a pointer to some point in 'fname', * possibly fname itself. * DESCRIPTION: * If 'fname' is a full path to somewhere beneath * the current directory, then return a pointer * to the significant portion of the path : * * if pwd is /usr/bill/foo/proj: * * For: /usr/bill/foo/proj/sub/test.i * | return ptr to here * * For: /usr/bill/foo/proj/a.i * | return ptr to here * * For: /usr/bill/foo/other/ * | return whole thing * * This is used to shorten expanded names when we emit messages. * It does nothing fancy, only affecting paths that point inside * the current directory. * * LAST REV: fix3553 Created. *------------------------------------------------------------------------*/ char* UxAbbreviateFileName (fname) char* fname; { char* pwd = UxGetCurrentDir(); int len = pwd ? strlen(pwd) : 0; /*------------------------------------------------------- * Short-circuit of 'if' prevents filename[len] crashing. *-------------------------------------------------------*/ if (pwd && fname && (strncmp(pwd, fname, len) == 0) && fname[len] == '/') { UxFree(pwd); return fname + len + 1; } UxFree(pwd); return fname; }