/****************************************************************************** ** @source AJAX system functions ** ** Copyright (c) Alan Bleasby 1999 ** @version 1.0 ** @@ ** ** This library is free software; you can redistribute it and/or ** modify it under the terms of the GNU Library General Public ** License as published by the Free Software Foundation; either ** version 2 of the License, or (at your option) any later version. ** ** This library is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ** Library General Public License for more details. ** ** You should have received a copy of the GNU Library General Public ** License along with this library; if not, write to the ** Free Software Foundation, Inc., 59 Temple Place - Suite 330, ** Boston, MA 02111-1307, USA. ******************************************************************************/ #include "ajax.h" #ifndef WIN32 #ifndef __VMS #include #endif #include #include #include #include #include #include #include #else #include "win32.h" #include #define open _open #define close _close #define read _read #define write _write #define strnicmp _strnicmp #define fdopen _fdopen #define rmdir _rmdir #pragma warning(disable:4142) /* benign redefinition of type */ #include #include #endif #include static AjPStr sysTname = NULL; static AjPStr sysFname = NULL; static AjPStr sysTokRets = NULL; static AjPStr sysTokSou = NULL; static const char *sysTokp = NULL; static AjPStr sysUserPath = NULL; #ifndef WIN32 static void sysTimeoutAbort(int sig); #else static void CALLBACK sysTimeoutAbort(LPVOID arg, DWORD low, DWORD high); #endif /* @filesection ajutil ******************************************************** ** ** @nam1rule aj Function belongs to the AJAX library. ** */ /* @datasection [none] System utility functions ******************************* ** ** @nam2rule Sys Function belongs to the AJAX ajsys library. ** */ /* @section Argument list manipulation functions ****************************** ** ** Function for manipulating argument list. ** ** @fdata [none] ** ** @nam3rule Arglist Function for manipulating argument list. ** @nam4rule ArglistBuild Generates a program name and argument list from a ** command line string. ** @nam4rule ArglistFree Free memory in an argument list allocated by ** ajSysArglistBuild. ** @suffix C Accept C character string parameters ** @suffix S Accept string object parameters ** ** @argrule C cmdlinetxt [const char*] Original command line ** @argrule S cmdline [const AjPStr] Original command line ** @argrule Build Pname [char**] Returned program name ** @argrule Arglist PParglist [char***] Returns argument array ** ** @valrule Build [AjBool] True on success ** @valrule Free [void] ** ** @fcategory misc ** ******************************************************************************/ /* @func ajSysArglistBuildC **************************************************** ** ** Generates a program name and argument list from a command line string. ** ** @param [r] cmdlinetxt [const char*] Command line. ** @param [w] Pname [char**] Program name. ** @param [w] PParglist [char***] Argument list. ** @return [AjBool] ajTrue on success. ** @@ ******************************************************************************/ AjBool ajSysArglistBuildC(const char* cmdlinetxt, char** Pname, char*** PParglist) { static AjPRegexp argexp = NULL; AjPStr tmpline = NULL; const char* cp; ajint ipos = 0; ajint iarg = 0; ajint ilen = 0; ajint i; char** al; AjPStr argstr = NULL; if(!argexp) argexp = ajRegCompC("^[ \t]*(\"([^\"]*)\"|'([^']*)'|([^ \t]+))"); ajDebug("ajSysArglistBuildC '%s'\n", cmdlinetxt); ajStrAssignC(&tmpline, cmdlinetxt); cp = cmdlinetxt; ipos = 0; while(ajRegExecC(argexp, &cp[ipos])) { ipos += ajRegLenI(argexp, 0); iarg++; } AJCNEW(*PParglist, iarg+1); al = *PParglist; ipos = 0; iarg = 0; while(ajRegExecC(argexp, &cp[ipos])) { ilen = ajRegLenI(argexp, 0); ajStrDelStatic(&argstr); for(i=2;i<5;i++) { if(ajRegLenI(argexp, i)) { ajRegSubI(argexp, i, &argstr); ajDebug("parsed [%d] '%S'\n", i, argstr); break; } } ipos += ilen; if(!iarg) *Pname = ajCharNewS(argstr); al[iarg] = ajCharNewS(argstr); iarg++; } al[iarg] = NULL; ajRegFree(&argexp); argexp = NULL; ajStrDel(&tmpline); ajStrDel(&argstr); ajDebug("ajSysArglistBuildC %d args for '%s'\n", iarg, *Pname); return ajTrue; } /* @func ajSysArglistBuildS **************************************************** ** ** Generates a program name and argument list from a command line string. ** ** @param [r] cmdline [const AjPStr] Command line. ** @param [w] Pname [char**] Program name. ** @param [w] PParglist [char***] Argument list. ** @return [AjBool] ajTrue on success. ** @@ ******************************************************************************/ AjBool ajSysArglistBuildS(const AjPStr cmdline, char** Pname, char*** PParglist) { return ajSysArglistBuildC(MAJSTRGETPTR(cmdline), Pname, PParglist); } /* @obsolete ajSysArglistBuild ** @rename ajSysArglistBuildS */ __deprecated AjBool ajSysArglistBuild(const AjPStr cmdline, char** Pname, char*** PParglist) { return ajSysArglistBuildS(cmdline, Pname, PParglist); } /* @obsolete ajSysArglist ** @rename ajSysArglistBuildS */ __deprecated AjBool ajSysArglist(const AjPStr cmdline, char** Pname, char*** PParglist) { return ajSysArglistBuildS(cmdline, Pname, PParglist); } /* @func ajSysArglistFree ***************************************************** ** ** Free memory in an argument list allocated by ajSysArgList ** ** @param [w] PParglist [char***] Argument list. ** @return [void] ** @@ ******************************************************************************/ void ajSysArglistFree(char*** PParglist) { char** ca; ajint i; ca = *PParglist; i = 0; while(ca[i]) { AJFREE(ca[i]); ++i; } AJFREE(*PParglist); return; } /* @obsolete ajSysArgListFree ** @rename ajSysArglistFree */ __deprecated void ajSysArgListFree(char*** PParglist) { ajSysArglistFree(PParglist); return; } /* @section System cast functions ********************************************* ** ** Function for casting one datatype to another. ** ** @fdata [none] ** @fcategory misc ** ** @nam3rule Cast Function for casting one datatype to another. ** @nam4rule CastItoc Convert Int to Char (for fussy compilers) ** @nam4rule CastItouc Convert Int to Unsigned Char (for fussy compilers). ** ** @argrule * v [ajint] Character as an integer ** ** @valrule *Itoc [char] Character ** @valrule *Itouc [unsigned char] Unsigned character ** ******************************************************************************/ /* @func ajSysCastItoc ******************************************************** ** ** Convert Int to Char ** Needed for very fussy compilers i.e. Digital C ** ** @param [r] v [ajint] integer ** @return [char] Character cast ** @@ ******************************************************************************/ char ajSysCastItoc(ajint v) { char c; c = (char) v; return c; } /* @obsolete ajSysItoC ** @rename ajSysCastItoC */ __deprecated char ajSysItoC(ajint v) { return ajSysCastItoc(v); } /* @func ajSysCastItouc ******************************************************* ** ** Convert Int to Unsigned Char ** Needed for very fussy compilers i.e. Digital C ** ** @param [r] v [ajint] integer ** @return [unsigned char] Unsigned character cast ** @@ ******************************************************************************/ unsigned char ajSysCastItouc(ajint v) { char c; c = (unsigned char) v; return c; } /* @obsolete ajSysItoUC ** @rename ajSysCastItouc */ __deprecated unsigned char ajSysItoUC(ajint v) { return ajSysCastItouc(v); } /* @section System functions for files **************************************** ** ** System functions for files. ** ** @fdata [none] ** @fcategory misc ** ** @nam3rule File System functions for files. ** @nam4rule FileRmrf Recursively deletes a directory tree ** @nam4rule FileWhich Searches $PATH sequentially for a user-EXECUTABLE ** file. ** @nam5rule FileWhichEnv Uses environment to extract the PATH list. ** @nam4rule FileUnlink Deletes a file or link ** @nam3rule Get Return attribute ** @nam4rule GetHomedir Return home directory ** @nam5rule GetHomedirFrom Get home directory from parameter ** @nam6rule FromName Get home directory for a named user ** ** @suffix C Accept C character string parameters ** @suffix S Accept string object parameters ** ** @argrule RmrfC path [const char*] File name ** @argrule UnlinkC filename [const char*] File name ** @argrule UnlinkS filename [const AjPStr] File name ** @argrule Which Pfilename [AjPStr*] File name (updated when found) ** @argrule Env env [char* const[]] File name (updated when found) ** @argrule FromName username [const char*] Username ** ** @valrule Homedir [char*] Home directory name ** @valrule File [AjBool] True if operation is successful. ** ******************************************************************************/ /* @func ajSysFileRmrfC ****************************************************** ** ** Forcibly delete a directory tree ** ** @param [r] path [const char*] Directory path ** @return [AjBool] true if deleted false otherwise ** @@ ******************************************************************************/ AjBool ajSysFileRmrfC(const char *path) { AjPList flist = NULL; AjPStr wild = NULL; AjPStr fname = NULL; AjPStr dirpath = NULL; const char *pdir = NULL; AjBool ret; if(ajCharMatchC(path,".") || ajCharMatchC(path,"..")) return ajFalse; flist = ajListNew(); wild = ajStrNewC("*"); dirpath = ajStrNewC(path); ret = ajTrue; if(!ajFilenameExistsDir(dirpath)) { ajListFree(&flist); ajStrDel(&wild); ajStrDel(&dirpath); return ajFalse; } ajFilelistAddPathWildDir(flist, dirpath, wild); while(ajListPop(flist, (void **) &fname)) { if(ajFilenameExistsDir(fname)) { pdir = ajStrGetPtr(fname); ret = ajSysFileRmrfC(pdir); if(!ret) break; } else { ret = ajSysFileUnlinkS(fname); if(!ret) break; } ajStrDel(&fname); } if(!(ajCharMatchC(path,".") || ajCharMatchC(path,".."))) if(rmdir(path)) ret = ajFalse; while(ajListPop(flist, (void **) &fname)) ajStrDel(&fname); ajStrDel(&wild); ajStrDel(&dirpath); ajListFree(&flist); return ret; } /* @func ajSysFileUnlinkC ****************************************************** ** ** Deletes a file or link ** ** @param [r] filename [const char*] Filename in AjStr. ** @return [AjBool] true if deleted false otherwise ** @@ ******************************************************************************/ AjBool ajSysFileUnlinkC(const char* filename) { ajDebug("ajSysFileUnlinkC '%s'\n", filename); #ifndef WIN32 if(!unlink(filename)) return ajTrue; ajErr("File '%s' remove failed, error:%d '%s'", filename, errno, strerror(errno)); #else if(DeleteFile(filename)) return ajTrue; #endif ajDebug("ajSysFileUnlinkC failed to delete '%s'\n", filename); return ajFalse; } /* @func ajSysFileUnlinkS ****************************************************** ** ** Deletes a file or link ** ** @param [r] filename [const AjPStr] Filename in AjStr. ** @return [AjBool] true if deleted false otherwise ** @@ ******************************************************************************/ AjBool ajSysFileUnlinkS(const AjPStr filename) { return ajSysFileUnlinkC(MAJSTRGETPTR(filename)); } /* @obsolete ajSysFileUnlink ** @rename ajSysFileUnlinkS */ __deprecated AjBool ajSysFileUnlink(const AjPStr s) { return ajSysFileUnlinkS(s); } /* @obsolete ajSysUnlink ** @rename ajSysFileUnlinkS */ __deprecated AjBool ajSysUnlink(const AjPStr s) { return ajSysFileUnlinkS(s); } /* @func ajSysFileWhich ******************************************************* ** ** Gets the Basename of a file then searches $PATH sequentially until it ** finds a user-EXECUTABLE file of the same name. ** ** @param [u] Pfilename [AjPStr*] Filename in AjStr, replaced by full pathname ** @return [AjBool] True if executable found, false otherwise ** @@ ******************************************************************************/ AjBool ajSysFileWhich(AjPStr *Pfilename) { char *p; if(!ajStrGetLen(sysUserPath)) ajStrAssignC(&sysUserPath, getenv("PATH")); if(!ajStrGetLen(sysUserPath)) return ajFalse; p = ajStrGetuniquePtr(&sysUserPath); if(!ajNamGetValueS(*Pfilename, &sysTname)) ajStrAssignS(&sysTname, *Pfilename); if(ajFilenameExistsExec(sysTname)) { ajStrAssignS(Pfilename,sysTname); ajStrDelStatic(&sysTname); return ajTrue; } if(!sysFname) sysFname = ajStrNew(); p=ajSysFuncStrtok(p,PATH_SEPARATOR); if(p==NULL) { ajStrDelStatic(&sysFname); ajStrDelStatic(&sysTname); return ajFalse; } while(1) { #if !defined(WIN32) && !defined(__CYGWIN__) ajFmtPrintS(&sysFname,"%s%s%S",p,SLASH_STRING,sysTname); #else ajFmtPrintS(&sysFname,"%s%s%S.exe",p,SLASH_STRING,sysTname); #endif if(ajFilenameExistsExec(sysFname)) { ajStrAssignS(Pfilename,sysFname); break; } if((p = ajSysFuncStrtok(NULL,PATH_SEPARATOR))==NULL) { ajStrDelStatic(&sysFname); ajStrDelStatic(&sysTname); return ajFalse; } } ajStrDelStatic(&sysFname); ajStrDelStatic(&sysTname); return ajTrue; } /* @obsolete ajSysWhich ** @rename ajSysFileWhich */ __deprecated AjBool ajSysWhich(AjPStr *s) { return ajSysFileWhich(s); } /* @func ajSysFileWhichEnv **************************************************** ** ** Gets the Basename of a file then searches $PATH sequentially until it ** finds a user-EXECUTABLE file of the same name. Reentrant. ** ** @param [u] Pfilename [AjPStr*] Filename in AjStr, replaced by full pathname ** @param [r] env [char* const[]] Environment ** @return [AjBool] True if executable found, false otherwise ** @@ ******************************************************************************/ AjBool ajSysFileWhichEnv(AjPStr *Pfilename, char * const env[]) { ajint count; char *p = NULL; const char *cp; AjPStr tname = NULL; AjPStr fname = NULL; AjPStr path = NULL; const char *save = NULL; AjPStr buf = NULL; AjPStr tmp = NULL; buf = ajStrNew(); tname = ajStrNew(); tmp = ajStrNew(); ajStrAssignS(&tname,*Pfilename); fname = ajStrNew(); path = ajStrNew(); ajFilenameTrimPath(&tname); #ifdef WIN32 ajStrAppendC(&tname,".exe"); #endif ajDebug("ajSysFileWhichEnv '%S' => %S\n", *Pfilename, tname); count = 0; while(env[count]!=NULL) { if(!(*env[count])) break; /*ajDebug(" env[%d] '%s'\n", count, env[count]);*/ #ifndef WIN32 if(!strncmp("PATH=",env[count],5)) #else if(!strnicmp("PATH=",env[count],5)) #endif break; ++count; } /* ajDebug("PATH env[%d] '%s'\n", count, env[count]);*/ if(env[count]==NULL || !(*env[count])) { ajStrDel(&fname); ajStrDel(&tname); ajStrDel(&path); ajStrDel(&buf); ajStrDel(&tmp); return ajFalse; } ajStrAssignC(&path, env[count]); cp = ajStrGetPtr(path); cp += 5; ajStrAssignC(&tmp,cp); /*ajDebug("tmp '%S' save '%S' buf '%S'\n", tmp, save, buf);*/ p = ajSysFuncStrtokR(ajStrGetuniquePtr(&tmp),PATH_SEPARATOR,&save,&buf); if(p==NULL) { ajStrDel(&fname); ajStrDel(&tname); ajStrDel(&path); ajStrDel(&buf); ajStrDel(&tmp); return ajFalse; } ajFmtPrintS(&fname,"%s%s%S",p,SLASH_STRING,tname); while(!ajFilenameExistsExec(fname)) { if((p = ajSysFuncStrtokR(NULL,PATH_SEPARATOR,&save,&buf))==NULL) { ajStrDel(&fname); ajStrDel(&tname); ajStrDel(&path); ajStrDel(&buf); ajStrDel(&tmp); return ajFalse; } ajFmtPrintS(&fname,"%s%s%S",p,SLASH_STRING,tname); } ajStrAssignS(Pfilename,fname); ajDebug("ajSysFileWhichEnv returns '%S'\n", *Pfilename); ajStrDel(&fname); ajStrDel(&tname); ajStrDel(&path); ajStrDel(&buf); ajStrDel(&tmp); return ajTrue; } /* @obsolete ajSysWhichEnv ** @rename ajSysFileWhichEnv */ __deprecated AjBool ajSysWhichEnv(AjPStr *Pfilename, char * const env[]) { return ajSysFileWhichEnv(Pfilename, env); } /* @func ajSysGetHomedir ************************************************* ** ** Get the home directory of the current user ** ** @return [char*] Home directory or NULL ** @@ ******************************************************************************/ char* ajSysGetHomedir(void) { char *hdir = NULL; #ifndef WIN32 char *p = NULL; if(!(p = getenv("HOME"))) return NULL; hdir = ajCharNewC(p); #else TCHAR wpath[MAX_PATH]; HRESULT ret; /* Replace with SHGetKnownFolderPath when XP is no longer supported */ ret = SHGetFolderPath(NULL,CSIDL_PROFILE,NULL,0,wpath); if(ret != S_OK) return NULL; hdir = ajCharNewC(wpath); #endif return hdir; } /* @func ajSysGetHomedirFromName ********************************************* ** ** Get a home directory location from a username ** ** @param [r] username [const char*] Username ** @return [char*] Home directory or NULL ** @@ ******************************************************************************/ char* ajSysGetHomedirFromName(const char *username) { char *hdir = NULL; #ifndef WIN32 struct passwd *pass = NULL; pass = getpwnam(username); if(!pass) return NULL; hdir = ajCharNewC(pass->pw_dir); #else LPTSTR domainname = NULL; LPTSTR localsvr = NULL; DWORD dnsize = 0; PSID psid = NULL; DWORD sidsize = 0; SID_NAME_USE sidtype; LPTSTR strsid = NULL; AjPStr subkey = NULL; DWORD hdbuffsize = MAX_PATH; char hdbuff[MAX_PATH]; LONG ret; HKEY hkey = NULL; if(!LookupAccountName(localsvr, username, psid, &sidsize, domainname, &dnsize, &sidtype)) { if(GetLastError() == ERROR_NONE_MAPPED) { ajWarn("No Windows username found for '%s'", username); return NULL; } else if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) { psid = (LPTSTR) LocalAlloc(LPTR,sidsize * sizeof(TCHAR)); if(!psid) { ajWarn("ajSysLookupAccount: SID allocation failure"); return NULL; } domainname = (LPTSTR) LocalAlloc(LPTR, dnsize * sizeof(TCHAR)); if(!domainname) { ajWarn("ajSysLookupAccount: Domain allocation failure"); LocalFree(psid); return NULL; } if(!LookupAccountName(localsvr, username, psid, &sidsize, domainname, &dnsize, &sidtype)) { ajWarn("LookupAccountName failed with %d", GetLastError()); LocalFree(psid); LocalFree(domainname); return NULL; } } else { ajWarn("General LookupAccountName failure with %d", GetLastError()); return NULL; } } if(!ConvertSidToStringSid(psid, &strsid)) { LocalFree(psid); return NULL; } LocalFree(psid); subkey = ajStrNew(); ajFmtPrintS(&subkey,"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\" "ProfileList\\%s",strsid); LocalFree(strsid); ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE,ajStrGetPtr(subkey),(DWORD) 0, KEY_QUERY_VALUE,&hkey); ajStrDel(&subkey); if(ret != ERROR_SUCCESS) return NULL; ret = RegQueryValueEx(hkey,"ProfileImagePath",NULL,NULL,(LPBYTE)hdbuff, &hdbuffsize); if(ret != ERROR_SUCCESS) return NULL; ret = RegCloseKey(hkey); if(ret != ERROR_SUCCESS) return NULL; hdir = ajCharNewC(hdbuff); #endif return hdir; } /* @section Wrappers to commands ********************************************** ** ** Functions for invoking commands ** ** @fdata [none] ** @fcategory misc ** ** @nam3rule Command Execute the equivalent of a command ** @nam4rule CommandClear Execute a clear screen command ** @nam4rule CommandCopy Execute a copy command ** @nam4rule CommandMakedir Execute a make directory command ** @nam4rule CommandRemove Execute a remove file command ** @nam4rule CommandRemovedir Execute a remove directory command ** @nam4rule CommandRename Execute a fle rename command ** @suffix C Accept C character string parameters ** @suffix S Accept string object parameters ** ** @argrule C name [const char*] Filename or directory name ** @argrule S strname [const AjPStr] Filename or directory name ** @argrule CopyC name2 [const char*] Destination filename ** @argrule CopyS strname2 [const AjPStr] Destination filename ** @argrule RenameC name2 [const char*] Destination filename ** @argrule RenameS strname2 [const AjPStr] Destination filename ** ** @valrule * [AjBool] True on success ** ******************************************************************************/ /* @func ajSysCommandCopyC ************************************************** ** ** Copy a file ** ** @param [r] name [const char*] Source filename ** @param [r] name2 [const char*] Target filename ** @return [AjBool] True on success ** ******************************************************************************/ AjBool ajSysCommandCopyC(const char* name, const char* name2) { int from; int to; int n; int nw; char cbuf[1024]; char *buf; from = open(name, O_RDONLY); if(from < 0) { ajErr("Unable to copy '%s' error %d: %s", name, errno, strerror(errno)); return ajFalse; } to = open(name2, O_WRONLY|O_CREAT, 0644); if(to < 0) { ajErr("Unable to copy to '%s' error %d: %s", name2, errno, strerror(errno)); return ajFalse; } while((n = read(from, cbuf, sizeof(cbuf))) > 0) { buf = cbuf; do { nw = write(to, buf, n); if(nw == n) break; if(nw > 0) { buf += nw; n -= nw; } } while (nw >= 0 || errno == EINTR); if(nw < 0) { ajErr("Write to %s failed, error:%d %s", name2, errno, strerror(errno)); return ajFalse; } } close(from); close(to); return ajTrue; } /* @func ajSysCommandCopyS ************************************************** ** ** Copy a file ** ** @param [r] strname [const AjPStr] Source filename ** @param [r] strname2 [const AjPStr] Target filename ** @return [AjBool] True on success ** ******************************************************************************/ AjBool ajSysCommandCopyS(const AjPStr strname, const AjPStr strname2) { return ajSysCommandCopyC(MAJSTRGETPTR(strname), MAJSTRGETPTR(strname2)); } /* @func ajSysCommandMakedirC ************************************************* ** ** Delete a file ** ** @param [r] name [const char*] Directory ** @return [AjBool] True on success ** ******************************************************************************/ AjBool ajSysCommandMakedirC(const char* name) { #ifndef WIN32 if(!mkdir(name, 0775)) return ajTrue; #else if(!_mkdir(name)) return ajTrue; #endif ajErr("Unable to make directory '%s' (%d): %s", name, errno, strerror(errno)); return ajFalse; } /* @func ajSysCommandMakedirS ************************************************* ** ** Delete a file ** ** @param [r] strname [const AjPStr] Directory ** @return [AjBool] True on success ** ******************************************************************************/ AjBool ajSysCommandMakedirS(const AjPStr strname) { return ajSysCommandMakedirC(MAJSTRGETPTR(strname)); } /* @func ajSysCommandRemoveC ************************************************** ** ** Delete a file ** ** @param [r] name [const char*] Filename ** @return [AjBool] True on success ** ******************************************************************************/ AjBool ajSysCommandRemoveC(const char* name) { return ajSysFileUnlinkC(name); } /* @func ajSysCommandRemoveS ************************************************** ** ** Delete a file ** ** @param [r] strname [const AjPStr] Filename ** @return [AjBool] True on success ** ******************************************************************************/ AjBool ajSysCommandRemoveS(const AjPStr strname) { return ajSysFileUnlinkC(MAJSTRGETPTR(strname)); } /* @func ajSysCommandRemovedirC *********************************************** ** ** Delete a file ** ** @param [r] name [const char*] Directory ** @return [AjBool] True on success ** ******************************************************************************/ AjBool ajSysCommandRemovedirC(const char* name) { AjPStr cmdstr = NULL; AjBool ret; ret = ajTrue; cmdstr = ajStrNewC(name); if(!ajFilenameExistsDir(cmdstr)) { if(!ajFilenameExists(cmdstr)) ajErr("Unable to remove directory '%S' not found", cmdstr); else ajErr("Unable to remove directory '%S' not a directory", cmdstr); return ajFalse; } ret = ajSysFileRmrfC(name); ajStrDel(&cmdstr); return ret; } /* @func ajSysCommandRemovedirS *********************************************** ** ** Delete a file ** ** @param [r] strname [const AjPStr] Directory ** @return [AjBool] True on success ** ******************************************************************************/ AjBool ajSysCommandRemovedirS(const AjPStr strname) { return ajSysCommandRemovedirC(MAJSTRGETPTR(strname)); } /* @func ajSysCommandRenameC ************************************************ ** ** Rename a file ** ** @param [r] name [const char*] Source filename ** @param [r] name2 [const char*] Target filename ** @return [AjBool] True on success ** ******************************************************************************/ AjBool ajSysCommandRenameC(const char* name, const char* name2) { if(!rename(name, name2)) return ajTrue; ajErr("File rename failed (%d): %s", errno, strerror(errno)); return ajFalse; } /* @func ajSysCommandRenameS ************************************************** ** ** Rename a file ** ** @param [r] strname [const AjPStr] Source filename ** @param [r] strname2 [const AjPStr] Target filename ** @return [AjBool] True on success ** ******************************************************************************/ AjBool ajSysCommandRenameS(const AjPStr strname, const AjPStr strname2) { return ajSysCommandRenameC(MAJSTRGETPTR(strname), MAJSTRGETPTR(strname2)); } /* @section Wrappers to C functions ******************************************* ** ** Functions for calling or substituting C-functions. ** ** @fdata [none] ** @fcategory misc ** ** @nam3rule Func Replacement for C-function. ** @nam4rule FuncSocket A socket function for UNIX and Windows ** @nam4rule FuncStrtok strtok that doesn't corrupt the source string ** @nam5rule FuncStrtokR Reentrant version. ** @nam4rule FuncFgets An fgets replacement that will cope with Mac OSX ** files ** @nam4rule FuncFopen An fopen replacement to cope with cygwin and windows ** @nam4rule FuncFdopen Calls non-ANSI fdopen. ** @nam4rule FuncSocket A socket function fore UNIX and Windows ** @nam4rule FuncStrdup Duplicate BSD strdup function for very strict ANSI ** @nam3rule System Execute a command line as if from the C shell ** @nam4rule SystemEnv Execute command line and pass the environment ** received from main to extract the PATH list ** @nam4rule SystemOut Execute command line and write standard output to ** a named file ** @suffix C Accept C character string parameters ** @suffix S Accept string object parameters ** ** @argrule Fdopen filedes [ajint] file descriptor ** @argrule Fdopen mode [const char*] file mode ** @argrule Fgets buf [char*] buffer ** @argrule Fgets size [int] maximum length to read ** @argrule Fgets fp [FILE*] stream ** @argrule Fopen name [const char*] Name of file to open ** @argrule Fopen flags [const char*] Read/write/append flags ** @argrule Socket domain [int] Domain ** @argrule Socket type [int] Type ** @argrule Socket protocol [int] Protocol ** @argrule Strdup dupstr [const char*] String to duplicate ** @argrule Strtok srcstr [const char*] source string ** @argrule Strtok delimstr [const char*] delimiter string ** @argrule R ptrptr [const char**] Saved pointer ** @argrule R buf [AjPStr*] Independent buffer provided by caller ** @argrule System cmdline [const AjPStr] The command line ** @argrule SystemEnv env [char* const[]] Environment variables and values ** @argrule SystemOut outfname [const AjPStr] The output file name ** ** @valrule Fdopen [FILE*] C open file ** @valrule Fgets [char*] Buffer on success ** @valrule Fopen [FILE*] C open file ** @valrule Strdup [char*] New string ** @valrule Strtok [char*] New string ** @valrule Socket [SOCKRET] Socketvoid] ** @valrule System [void] ** ******************************************************************************/ /* @func ajSysFuncFdopen ****************************************************** ** ** Place non-ANSI fdopen here ** ** @param [r] filedes [ajint] file descriptor ** @param [r] mode [const char*] file mode ** @return [FILE*] file pointer ** @@ ******************************************************************************/ FILE* ajSysFuncFdopen(ajint filedes, const char *mode) { FILE *ret; ret = fdopen(filedes,mode); if(ret) errno = 0; /* set to "Illegal seek" on some systems */ return ret; } /* @obsolete ajSysFdopen ** @rename ajSysFuncFdopen */ __deprecated FILE* ajSysFdopen(ajint filedes, const char *mode) { return ajSysFuncFdopen(filedes, mode); } /* @func ajSysFuncFgets ******************************************************* ** ** An fgets replacement that will cope with Mac OSX files ** ** @param [w] buf [char*] buffer ** @param [r] size [int] maximum length to read ** @param [u] fp [FILE*] stream ** ** @return [char*] buf or NULL ** @@ ******************************************************************************/ char* ajSysFuncFgets(char *buf, int size, FILE *fp) { #ifdef __ppc__ int c = 0; char *p; int cnt; p = buf; if(!size || size<0) return NULL; cnt = 0; while(cnt!=size-1) { c = getc(fp); if(c==EOF || c=='\r' || c=='\n') break; *(p++) = c; ++cnt; } *p ='\0'; if(c==EOF && !cnt) return NULL; if(cnt == size-1) return buf; if(c=='\r' || c=='\n') { if(c=='\r' && cntsa.sa_mask ); ts->sa.sa_flags = 0; ts->sa.sa_handler = sysTimeoutAbort; ret = sigaction( SIGALRM, &ts->sa, NULL ); alarm(ts->seconds); #else PTIMERAPCROUTINE ptim = NULL; ts->wtime.QuadPart = -10000000LL; ts->wtime.QuadPart *= ts->seconds; ts->thandle = CreateWaitableTimer(NULL, TRUE, NULL); if(!ts->thandle) return -1; ptim = (PTIMERAPCROUTINE) sysTimeoutAbort; if (!SetWaitableTimer(ts->thandle, &ts->wtime, 0, ptim, NULL, 0)) ret = -1; #endif return ret; } /* @func ajSysTimeoutUnset *************************************************** ** ** Unsets an alarm abort timeout for UNIX and Windows ** ** @param [u] ts [struct AJTIMEOUT*] AJAX timeout structure ** @return [int] 0 = success -1 = error ** @@ ******************************************************************************/ int ajSysTimeoutUnset(struct AJTIMEOUT *ts) { int ret = 0; #ifndef WIN32 ret = sigemptyset(&ts->sa.sa_mask); alarm(0); #else if(!CancelWaitableTimer(ts->thandle)) return -1; if(!CloseHandle(ts->thandle)) ret = -1; #endif return ret; } #ifndef WIN32 /* @funcstatic sysTimeoutAbort ******************************************** ** ** Fatal error if a socket read hangs ** ** @param [r] sig [int] Signal code - always SIGALRM but required by the ** signal call ** @return [void] ** @@ ******************************************************************************/ static void sysTimeoutAbort(int sig) { (void) sig; ajDie("Alarm timeout"); return; } #else static void CALLBACK sysTimeoutAbort(LPVOID arg, DWORD low, DWORD high) { (void) arg; (void) low; (void) high; ajDie("Timer timeout"); return; } #endif /* @obsolete ajSysBasename ** @rename ajFilenameTrimPath */ __deprecated void ajSysBasename(AjPStr *s) { ajFilenameTrimPath(s); return; } /* @obsolete ajSysIsDirectory ** @remove use ajFileDir instead */ __deprecated AjBool ajSysIsDirectory(const char *s) { AjBool ret; AjPStr tmpstr = NULL; tmpstr = ajStrNewC(s); ret = ajDirnameFixExists(&tmpstr); ajStrDel(&tmpstr); return ret; } /* @obsolete ajSysIsRegular ** @remove use ajFileNameValid instead */ __deprecated AjBool ajSysIsRegular(const char *s) { AjBool ret; AjPStr tmpstr; tmpstr = ajStrNewC(s); ret = ajFilenameExistsRead(tmpstr); ajStrDel(&tmpstr); return ret; } /* @section piped commands **************************************************** ** ** system command lines piped to a file ** ** @fdata [none] ** @fcategory misc ** ** @nam3rule Create Create a new input ** @nam4rule Inpipe Create a new input ** ** @suffix C C character string arguments ** @suffix S String object arguments ** ** @argrule C cmdlinetxt [const char*] Command line ** @argrule S command [const AjPStr] Command line ** @valrule *Inpipe [AjPFile] ** ******************************************************************************/ /* @func ajSysCreateInpipeC *************************************************** ** ** Return a new file object from which to read the output from a command. ** ** @param [r] cmdlinetxt [const char*] Command string. ** The string may end with a trailing pipe character. ** @return [AjPFile] New file object. ** @@ ******************************************************************************/ AjPFile ajSysCreateInpipeC(const char* cmdlinetxt) { AjPFile thys; AjPStr cmdstr = NULL; #ifndef WIN32 ajint pipefds[2]; /* file descriptors for a pipe */ char** arglist = NULL; char* pgm; #else HANDLE cstdinr = NULL; HANDLE cstdinw = NULL; HANDLE cstdoutr = NULL; HANDLE cstdoutw = NULL; HANDLE svstdout = NULL; HANDLE cstdoutrdup = NULL; SECURITY_ATTRIBUTES sa; PROCESS_INFORMATION pinf; STARTUPINFO sinf; BOOL ret = FALSE; int fd; #endif cmdstr = ajStrNew(); AJNEW0(thys); ajStrAssignC(&cmdstr, cmdlinetxt); ajDebug("ajSysCreateInpipeC: '%s'\n", cmdlinetxt); /* pipe character at end */ if(ajStrGetCharLast(cmdstr) == '|') ajStrCutEnd(&cmdstr, 1); #ifndef WIN32 if(pipe(pipefds) < 0) ajFatal("ajSysCreateInpipeC: pipe create failed"); /* negative return indicates failure */ thys->Pid = fork(); if(thys->Pid < 0) ajFatal("ajSysCreateInpipeC: fork create failed"); /* pid is zero in the child, but is the child PID in the parent */ if(!thys->Pid) { /* this is the child process */ close(pipefds[0]); dup2(pipefds[1], 1); close(pipefds[1]); ajSysArglistBuildS(cmdstr, &pgm, &arglist); ajDebug("ajSysCreateInpipeC: execvp ('%S', NULL)\n", cmdstr); execvp(pgm, arglist); ajErr("ajSysCreateInpipeC: execvp ('%S', NULL) failed: '%s'\n", cmdstr, strerror(errno)); ajExitAbort(); } ajDebug("ajSysCreateInpipeC: pid %d, pipe '%d', '%d'\n", thys->Pid, pipefds[0], pipefds[1]); /* fp is what we read from the pipe */ thys->fp = ajSysFuncFdopen(pipefds[0], "r"); close(pipefds[1]); #else sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.bInheritHandle = TRUE; sa.lpSecurityDescriptor = NULL; svstdout = GetStdHandle(STD_OUTPUT_HANDLE); if(!CreatePipe(&cstdoutr, &cstdoutw, &sa, 0)) ajFatal("ajSysCreateInpipeC: pipe create failed"); if(!SetHandleInformation(cstdoutr, HANDLE_FLAG_INHERIT, 0)) ajFatal("ajSysCreateInpipeC: Can't set no-inherit on child stdout " "read handle"); if(!SetStdHandle(STD_OUTPUT_HANDLE, cstdoutw)) ajFatal("ajSysCreateInpipeC: redirecting of STDOUT failed"); ret = DuplicateHandle(GetCurrentProcess(), cstdoutr, GetCurrentProcess(), &cstdoutrdup , 0, FALSE, DUPLICATE_SAME_ACCESS); if(!ret) ajFatal("ajSysCreateInpipeC: Could not duplicate stdout read handle"); CloseHandle(cstdoutr); /* Create Process here */ ZeroMemory(&pinf, sizeof(PROCESS_INFORMATION)); ZeroMemory(&sinf, sizeof(STARTUPINFO)); sinf.cb = sizeof(STARTUPINFO); ret = CreateProcess(NULL, (char *)ajStrGetPtr(cmdstr), NULL, NULL, TRUE, 0, NULL, NULL, &sinf, &pinf); if(!ret) ajFatal("ajSysCreateInpipeC: CreateProcess failed: %S", cmdstr); thys->Process = pinf.hProcess; thys->Thread = pinf.hThread; if(!SetStdHandle(STD_OUTPUT_HANDLE, svstdout)) ajFatal("restoring stdout failed\n"); CloseHandle(cstdoutw); fd = _open_osfhandle((intptr_t) cstdoutrdup, _O_RDONLY); thys->fp = ajSysFuncFdopen(fd, "r"); #endif ajStrDel(&cmdstr); if(!thys->fp) { thys->Handle = 0; ajFileClose(&thys); return NULL; } return thys; } /* @func ajSysCreateInpipeS *************************************************** ** ** Return a new file object from which to read the output from a command. ** ** @param [r] command [const AjPStr] Command string. ** The string may end with a trailing pipe character. ** @return [AjPFile] New file object. ** @@ ******************************************************************************/ AjPFile ajSysCreateInpipeS(const AjPStr command) { return ajSysCreateInpipeC(MAJSTRGETPTR(command)); } /* @section exit ************************************************************** ** ** Functions called on exit from the program by ajExit to do ** any necessary cleanup and to report internal statistics to the debug file ** ** @fdata [none] ** @fnote general exit functions, no arguments ** ** @nam3rule Exit Cleanup and report on exit ** ** @valrule * [void] ** ** @fcategory misc */ /* @func ajSysExit ************************************************************ ** ** Cleans up system internals memory ** ** @return [void] ** @@ ******************************************************************************/ void ajSysExit(void) { ajStrDel(&sysFname); ajStrDel(&sysTname); ajStrDel(&sysTokSou); ajStrDel(&sysTokRets); ajStrDel(&sysUserPath); return; }