diff options
Diffstat (limited to 'setedit/mainsrc/pathtool.cc')
-rw-r--r-- | setedit/mainsrc/pathtool.cc | 880 |
1 files changed, 880 insertions, 0 deletions
diff --git a/setedit/mainsrc/pathtool.cc b/setedit/mainsrc/pathtool.cc new file mode 100644 index 0000000..bc90483 --- /dev/null +++ b/setedit/mainsrc/pathtool.cc @@ -0,0 +1,880 @@ +/* Copyright (C) 1996-2002 by Salvador E. Tropea (SET), + see copyrigh file for details */ +#include <ceditint.h> + +#define Uses_sys_stat +#define Uses_string +#define Uses_fnmatch +#define Uses_stdlib +#define Uses_unistd +#define Uses_limits +#define Uses_fcntl +#define Uses_mkstemp +#define Uses_dirent +#define Uses_stdio +#define Uses_getcwd +#define Uses_HaveLFNs +#ifdef SECompf_djgpp +#include <io.h> // _chmod +#include <dpmi.h> // GetShortNameOf: dpmi_regs, dpmi_int +#include <go32.h> // GetShortNameOf: transfer buffer +#endif +#ifdef TVComp_BCPP +#include <io.h> +#endif +#define Uses_TScreen +#define Uses_TStringCollectionW +#include <settvuti.h> +#include <rhutils.h> +#include <pathtool.h> +#include <pathlist.h> +#include <edspecs.h> + +// Get HIDDEN_DIFFERENT, it should be moved to CLY +#define Uses_SETAppFiles +#define Uses_SETAppProject +#include <setapp.h> + +#ifdef SEOS_Win32 + #define WIN32_LEAN_AND_MEAN + #include <windows.h> + #ifndef SECompf_Cygwin + #define getuid() + #define getgid() + #define chown(file,uid,gid) + #endif +#endif + +static char PathOrig[PATH_MAX]; +static char *PathOrigPos; + +#if !defined(NoHomeOrientedOS) || defined(STANDALONE) +static char FileNameToLoad[PATH_MAX]; +#endif + +int IsADirectory(const char *name); + +int edTestForFile(const char *name, struct stat &st) +{ + if (stat(name,&st)==0) + return S_ISREG(st.st_mode); + return 0; +} + +int edTestForFile(const char *name) +{ + struct stat st; + return edTestForFile(name,st); +} + +char *GetHome(void) +{ + char *s=getenv("HOME"); + if (!s) + { + s=getenv("HOMEDIR"); + if (!s) + s="."; + } + return s; +} + +#ifdef NoHomeOrientedOS +char *ExpandHomeSave(const char *s) +{ + return ExpandHome(s); +} +#else +static +char *ExpandHomeWDir(const char *s, int hidden=0) +{ + static int HiddenDirFailed=0; + char *h=GetHome(); + if (!HiddenDirFailed) + {// Check ~/.setedit/ + strcpy(FileNameToLoad,h); + strcat(FileNameToLoad,"/.setedit"); + if (!IsADirectory(FileNameToLoad)) + {// No? try to create it. 0750 mode + if (mkdir(FileNameToLoad,S_IRWXU | S_IRGRP | S_IXGRP)==-1) + {// Oops! something went wrong + HiddenDirFailed=1; + } + else + {// We are in the start-up so we could be SUID yet + chown(FileNameToLoad,getuid(),getgid()); + } + } + if (!HiddenDirFailed) + {// Ok see if we can write + if (access(FileNameToLoad,W_OK)==0) + { + strcat(FileNameToLoad,"/"); + if (hidden) strcat(FileNameToLoad,"."); + strcat(FileNameToLoad,s); + return FileNameToLoad; + } + // No write access?! + HiddenDirFailed=1; + } + } + return 0; +} + +static +char *ExpandHomeCommon(const char *s) +{ + strcpy(FileNameToLoad,GetHome()); + strcat(FileNameToLoad,"/."); + strcat(FileNameToLoad,s); + return FileNameToLoad; +} + +/**[txh]******************************************************************** + + Description: + This funtion returns a suitable place to write configuration files. Note +it doesn't have to be the same point as where we read it. In UNIX we will +read default values from /usr/share/setedit and store them in +~/.setedit/.file. + + Return: A pointer to a static buffer containing the path+file name. + +***************************************************************************/ + +char *ExpandHomeSave(const char *s) +{ + char *r=ExpandHomeWDir(s); + return r ? r : ExpandHomeCommon(s); +} +#endif + +#ifdef STANDALONE +static +char *ExpandFileNameToUserHomeNoDot(const char *s) +{ + strcpy(FileNameToLoad,GetHome()); + strcat(FileNameToLoad,"/"); + strcat(FileNameToLoad,s); + return FileNameToLoad; +} + +/**[txh]******************************************************************** + + Description: + This routine searchs the desired file in various directories and returns +the full qualified path for the location or the default location if the +file doesn't exist.@* + Linux behavior: (a) The user's home (first in ~/.setedit/?, then ~/.? and +finally ~/?) (b) The SET_FILES directory.@* + DOS behavior: (a) The user's home (b) The SET_FILES directory +(c) The directory where the editor was loaded. Note that (c) shoul not +happend.@* + + Return: + The full path for the file found or the place where the file should be. + +***************************************************************************/ + +char *ExpandFileNameToThePointWhereTheProgramWasLoaded(const char *s) +{ + const char *v; + + #ifndef NoHomeOrientedOS + char *r; + // That's only for UNIX, + // Try in the ~/.setedit dir + r=ExpandHomeWDir(s); + if (r && edTestForFile(r)) + return r; + // Try the same place but a dot-file (hidden) + r=ExpandHomeWDir(s,1); + if (r && edTestForFile(r)) + return r; + r=ExpandHomeCommon(s); + if (edTestForFile(r)) + return r; + #endif + + // Try it in DOS too, so the user can define HOME or HOMEDIR + ExpandFileNameToUserHomeNoDot(s); + if (edTestForFile(FileNameToLoad)) + return FileNameToLoad; + + // The directory where the original files are installed + if ((v=GetVariable("SET_FILES"))!=NULL) + { + strcpy(FileNameToLoad,v); + strcat(FileNameToLoad,"/"); + strcat(FileNameToLoad,s); + return FileNameToLoad; + } + + #ifndef SEOS_UNIX + // The point where the editor was loaded doesn't have any sense in UNIX + if (PathOrigPos!=NULL) + { + *PathOrigPos=0; + strcat(PathOrig,s); + } + else + strcpy(PathOrig,s); + if (edTestForFile(PathOrig)) + return PathOrig; + #endif + + return PathOrig; +} + +int FindFile(const char *name, char *&fullName, const char *reference) +{ + if (strlen(name)>=PATH_MAX) + return 0; + fullName=new char[PATH_MAX]; + if (!fullName) + return 0; + strcpy(fullName,name); + const char *onlyName=strrchr(name,'/'); + if (onlyName) + onlyName++; + else + onlyName=name; + if (!edTestForFile(fullName)) + { + ccIndex i; + int found=0, j; + // Path+name + for (j=0; !found && j<paliLists; j++) + for (i=0; PathListGetItem(i,fullName,j); i++) + { + char *s=fullName+strlen(fullName)-1; + if (!CLY_IsValidDirSep(*s)) + strcat(s,DIRSEPARATOR_); + strcat(s,name); + if (edTestForFile(fullName)) + { + found=1; + break; + } + } + // Path+onlyName + for (j=0; !found && j<paliLists; j++) + for (i=0; PathListGetItem(i,fullName,j); i++) + { + char *s=fullName+strlen(fullName)-1; + if (!CLY_IsValidDirSep(*s)) + strcat(s,DIRSEPARATOR_); + strcat(s,onlyName); + if (edTestForFile(fullName)) + { + found=1; + break; + } + } + if (!found) + { + // Try with the project + char *prjName=GetAbsForNameInPrj(name); + if (!prjName) + prjName=GetAbsForNameInPrj(onlyName); + if (prjName) + strcpy(fullName,prjName); + else + {// Try in the same place as the reference + int found=0; + if (reference) + { + const char *s=strrchr(reference,'/'); + if (s) + { + int l=s-reference+1; + memcpy(fullName,reference,l); + strcpy(fullName+l,name); + //printf("Intentando: %s\n",fullName); + if (edTestForFile(fullName)) + found=1; + else + {// One more try, use only the name + memcpy(fullName,reference,l); + strcpy(fullName+l,onlyName); + if (edTestForFile(fullName)) + found=1; + } + } + } + if (!found) + { + DeleteArray(fullName); + return 0; + } + } + } + } + CLY_fexpand(fullName); + return 1; +} +#endif // STANDALONE + +/**[txh]******************************************************************** + + Description: + Replaces old extension of name by the provided extension. + + Return: + name + +***************************************************************************/ + +char *ReplaceExtension(char *name, const char *ext, const char *old) +{ + char *pos; + pos=strrchr(name,'/'); + if (!pos) + pos=name; + pos=strstr(pos,old); + if (pos) + strcpy(pos,ext); + else + strcat(name,ext); + return name; +} + +/**[txh]******************************************************************** + + Description: + Replaces the extension of name by the provided extension. If none is found +the extension is added and if the file name starts with dot the extension +is added too. + + Return: + name. + +***************************************************************************/ + +char *ReplaceExtension(char *name, const char *ext) +{ + char *dot,*slash; + int flen=strlen(name); + + dot=strrchr(name,'.'); + slash=strrchr(name,'/'); + if (dot<slash) // dot in directories, not in file + dot=0; + if (!dot || dot==slash+1) // .files should be .files.bkp and not .bkp ;-) + dot=name+flen; + strcpy(dot,ext); + + return name; +} + +/**[txh]******************************************************************** + + Description: + That's used to create back-up file names with xxxx~ stile. + + Return: + fname. + +***************************************************************************/ + +char *AddToNameOfFile(char *fname, char *add) +{ + #ifdef SEOS_DOS + // It could fail, but in this case the user should disable the option + if (CLY_HaveLFNs()) + return strcat(fname,add); + // Not so easy boy, 8+3 limitations: + char *dir,*name,*ext; + int lext; + split_fname(fname,dir,name,ext); + lext=strlen(ext); + if (lext==0) + string_cat(ext,".",add,0); + else + if (lext<4) + string_cat(ext,add); + else + { + for (lext=3; lext>1 && ext[lext]==*add; lext--); + ext[lext]=*add; + } + strcpy(fname,dir); + strcat(fname,name); + strcat(fname,ext); + string_free(dir); + string_free(name); + string_free(ext); + return fname; + #else + // In UNIX that's much more easy + return strcat(fname,add); + #endif +} + +int DeleteWildcard(char *mask) +{ + int deleted=0; + DIR *d; + d=opendir("."); + + if (d) + { + struct dirent *de; + while ((de=readdir(d))!=0) + { + if (!fnmatch(mask,de->d_name,0)) + { + unlink(de->d_name); + deleted++; + } + } + closedir(d); + } + return deleted; +} + + +char *GetPathRelativeToRunPoint(char *dest, const char *binReplace, char *file) +{ + char *ret; + + if (PathOrigPos!=NULL) + { + *PathOrigPos=0; + strcpy(dest,PathOrig); + char *s=strstr(dest,"bin"); + if (!s) + s=strstr(dest,"BIN"); + if (s) + strcpy(s,binReplace); + ret=dest+strlen(dest)-1; + } + else + { + *dest=0; + ret=dest; + } + + strcat(dest,file); + + return ret; +} + + +void SetReferencePath(char *orig) +{ + PathOrigPos=strrchr(orig,'/'); + if (PathOrigPos) + { + PathOrigPos++; + char oldVal=*PathOrigPos; + *PathOrigPos=0; + strcpy(PathOrig,orig); + *PathOrigPos=oldVal; + PathOrigPos=PathOrig+(int)(PathOrigPos-orig); + } + else + PathOrig[0]=0; +} + +char *RedirectStdErrToATemp(int &StdErrOri,int &StdErrNew) +{ + char aux[PATH_MAX]; + char *s=ExpandHomeSave(""); + char *ret=0; + + /*#ifdef TVComp_BCPP + sprintf(aux,"%s/",s); + StdErrNew=creattemp(aux, 0); + #elif defined(TVCompf_MinGW) || defined(TVComp_MSC) + sprintf(aux,"%s/erXXXXXX",s); + char *tempName=mktemp(aux); + StdErrNew=open(tempName,O_RDWR | O_CREAT,S_IRUSR | S_IWUSR); + #else + #endif*/ + sprintf(aux,"%serXXXXXX",s); + StdErrNew=mkstemp(aux); + if (StdErrNew>0) + {// In UNIX if the program is suid (needed before starting TV) we are + // at a point where TV wasn't initialized and hence didn't set the + // euid and egid to the real user. So we must ensure the temporal file + // is owned by the real user. + chown(aux,getuid(),getgid()); + ret=strdup(aux); + StdErrOri=dup(fileno(stderr)); + fflush(stderr); + dup2(StdErrNew,fileno(stderr)); + } + return ret; +} + +const int eachRead=16300; + +int FileCopy(const char *orig, const char *dest) +{ + // First I alloc a 16Kb buffer + char *buf=new char[eachRead]; + if (!buf) + return 0; + + // Create destination + FILE *d=fopen(dest,"wb"); + if (!d) + { + delete buf; + return 0; + } + + // Open source + FILE *o=fopen(orig,"rb"); + if (!o) + { + fclose(d); + delete buf; + return 0; + } + + int read; + do + { + read=fread(buf,1,eachRead,o); + fwrite(buf,read,1,d); + } + while (read==eachRead); + + int ret=!(ferror(o) || ferror(d)); + fclose(o); + fclose(d); + delete buf; + + return ret; +} + +/**[txh]******************************************************************** + + Description: + That's a direct replacement for access(name,D_OK) which Linux lacks. + + Return: + 0 not a directory or no access allowed. + +***************************************************************************/ + +int IsADirectory(const char *name) +{ + #ifdef SEOS_UNIX + struct stat s; + return stat(name,&s)==0 && S_ISDIR(s.st_mode) && !access(name,X_OK); + #endif + #ifdef SECompf_djgpp + return !access(name,D_OK); + #endif + #ifdef SEOS_Win32 + return CLY_IsDir(name)==True; + #endif +} + +/**[txh]******************************************************************** + + Description: + Checks if a file is a symbolic link. + + Return: + 0 not a link. + +***************************************************************************/ + +int IsASoftLink(const char *name) +{ + #ifdef S_ISLNK + struct stat s; + return lstat(name,&s)==0 && S_ISLNK(s.st_mode); + #else + return 0; + #endif +} + +/**[txh]******************************************************************** + + Description: + TMPDIR variable could be not defined or pointing to an invalid drive. As +the librhutils assumes TMPDIR is working I must ensure it or the +stderr/stdout could misserably fail. + +***************************************************************************/ + +void CheckForValidTMPDIR() +{ + char *tmp=getenv("TMPDIR"); + + // If the variable is defined && is a directory all is ok + if (!(tmp && IsADirectory(tmp))) + { + // Ok, this system lacks it or worst it point to nowhere + tmp=getenv("TEMP"); + if (!tmp || !IsADirectory(tmp)) + { // No luck with TEMP + tmp=getenv("TMP"); + if (!tmp || !IsADirectory(tmp)) + { // No luck with TMP + tmp="/tmp"; // It should work in UNIX + if (!IsADirectory(tmp)) + { + tmp="c:/"; // It should work in DOS + if (!IsADirectory(tmp)) + { // Hey! nothing is good! + tmp="."; // Well, give up and try in current directory + } + } + } + } + } + + char *b=new char[8+strlen(tmp)]; + sprintf(b,"TMPDIR=%s",tmp); + #if defined(SECompf_djgpp) || defined(TVComp_BCPP) + // Mixing forward and backslashes could produce problems (path\/file is invalid). + char *s=b; + for (; *s; s++) + if (*s=='\\') + *s='/'; + #endif + putenv(b); + //fprintf(stderr,"Using: %s\n",tmp); +} + + +#ifdef HIDDEN_DIFFERENT +char *MakeItHiddenName(char *file) +{ + // Look for the real name: + char *name=strrchr(file,'/'); + if (name) + name++; + else + name=file; + // Already hidden? + if (*name=='.') + return 0; + // Ugh! here UNIX is pretty bad: + int l=strlen(file)+2; + char *s=new char[l]; + strcpy(s,file); + l=name-file; + strcpy(s+l+1,name); + s[l]='.'; + + return s; +} +#else +char *MakeItHiddenName(char *) +{ + return 0; +} +#endif + +/**[txh]******************************************************************** + + Description: + Changes the status of the file to hidden. IMPORTANT! if the OS needs to +change the name of the file to make it hidden (UNIX case) the name provided +will be altered so it should have enough space for it. + + Return: + 0 succes, 1 fail + +***************************************************************************/ + +int MakeFileHidden(char *file) +{ + if (!file) return 0; + int ret=0; + + #ifdef SEOS_Win32 + // At least BC++ 5.5 says _chmod is obsolet and looking in the implementation + // (oh no! reverse eng.! just saw the .obj ;-) it calls Get/SetFileAttributes + // from Win32 API + // Get current status + DWORD mode=GetFileAttributes(file); + if (mode==0xFFFFFFFF) return 1; + // Already hidden? + if (mode & FILE_ATTRIBUTE_HIDDEN) return 0; + // Set the attribute + SetFileAttributes(file,mode | FILE_ATTRIBUTE_HIDDEN); + #endif + #ifdef SEOS_DOS + // Get current status + int mode=_chmod(file,0,0); + if (mode==-1) return 1; + // Already hidden? + if (mode & 2) return 0; + // Set the attribute + _chmod(file,1,mode | 2); + #endif + #ifdef SEOS_UNIX + char *s=MakeItHiddenName(file); + if (!s) return 0; + ret=rename(file,s); + strcpy(file,s); + delete[] s; + #endif + return ret; +} + +int RemoveFileHidden(char *file) +{ + #ifndef SEOS_UNIX + // Hidden files are the same as not hidden files, just an attribute. + return 1; + #else + if (!file) return 0; + int ret=0; + + char *s=MakeItHiddenName(file); + if (!s) return 0; + ret=unlink(s); + delete[] s; + return ret; + #endif +} + + +static TStringCollectionW *filesToKill=0; + +void AddToFilesToKill(char *name) +{ + if (!filesToKill) + filesToKill=new TStringCollectionW(6,4); + + ccIndex i; + if (filesToKill->search(filesToKill->keyOf(name),i)==0) + // A simple insert here will leak memory because the dupped name won't + // be released. + filesToKill->atInsert(i,newStr(name)); +} + +static +void killIt(void *name, void *) +{ + unlink((char *)name); +} + +void KillFilesToKill() +{ + if (!filesToKill) + return; + filesToKill->forEach(killIt,0); +} + +void ReleaseFilesToKill() +{ + destroy0(filesToKill); +} + +TStringCollectionW *GetFilesToKill() +{ + return filesToKill; +} + +void SetFilesToKill(TStringCollectionW *files) +{ + ReleaseFilesToKill(); + filesToKill=files; +} + +/**[txh]******************************************************************** + + Description: + Determines if 2 file names belongs to the same file. The function uses the +inode/device to find it. + + Return: + !=0 if the files are the same. + +***************************************************************************/ + +int CompareFileNames(char *origFile, char *destFile) +{ + struct stat st1,st2; + + if (stat(origFile,&st1) || stat(destFile,&st2)) + return 0; + + return st1.st_dev==st2.st_dev && st1.st_ino==st2.st_ino; +} + +/**[txh]******************************************************************** + + Description: + If the current directory is invalid aborts the execution. + +***************************************************************************/ + +void CheckIfCurDirValid(void) +{ + long *aux=(long *)PathOrig; + *aux=0xFFFEFDFC; + getcwd(PathOrig,PATH_MAX); + if (*aux==(long)0xFFFEFDFC) + { + TScreen::suspend(); + fprintf(stderr,_("\nError! please run the editor from a valid directory\n\n")); + fflush(stderr); + exit(1); + } +} + +#ifdef SECompf_djgpp +/**[txh]******************************************************************** + + Description: + Returns the short file name of the passed file. The shortName pointer must +point to a buffer with at least maxSFNSize bytes. + + Return: + A pointer to the converted name if succesful or the original name if it +fails. + +***************************************************************************/ + +char *GetShortNameOf(char *longName, char *shortName) +{ + __dpmi_regs r; + unsigned long tbuf=__tb; + + r.x.ax=0x7100; + if (_USE_LFN) + { + dosmemput (longName,strlen(longName)+1,tbuf+maxSFNSize); + r.x.ax=0x7160; + r.x.es=r.x.ds=tbuf >> 4; + r.x.di=0; + r.x.si=maxSFNSize; + r.x.cx=0x8001; + __dpmi_int(0x21, &r); + } + if ((r.x.flags & 1)==0 && r.x.ax!=0x7100) + { + dosmemget(tbuf,maxSFNSize,shortName); + return shortName; + } + return longName; +} +#else +char *GetShortNameOf(char *longName, char *) +{ + return longName; +} +#endif + +int CheckIfPathAbsolute(const char *s) +{ + //$todo: implement it for Win32 (SAA) + if (!s) return 0; + #ifndef SEOS_UNIX + return *s=='/' || *s=='\\' || s[1]==':'; + #else + return *s=='/'; + #endif +} + |