sysshellcall.c

Go to the documentation of this file.
00001 
00002 /*  $Id: sysshellcall.c 617 2006-03-10 14:01:11Z andreradke $    */
00003 
00004 /******************************************************************************
00005 
00006     UserLand Frontier(tm) -- High performance Web content management,
00007     object database, system-level and Internet scripting environment,
00008     including source code editing and debugging.
00009 
00010     Copyright (C) 1992-2004 UserLand Software, Inc.
00011 
00012     This program is free software; you can redistribute it and/or modify
00013     it under the terms of the GNU General Public License as published by
00014     the Free Software Foundation; either version 2 of the License, or
00015     (at your option) any later version.
00016 
00017     This program is distributed in the hope that it will be useful,
00018     but WITHOUT ANY WARRANTY; without even the implied warranty of
00019     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020     GNU General Public License for more details.
00021 
00022     You should have received a copy of the GNU General Public License
00023     along with this program; if not, write to the Free Software
00024     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00025 
00026 ******************************************************************************/
00027 
00028 #include "frontier.h"
00029 #include "standard.h"
00030 
00031 #include "memory.h"
00032 #include "strings.h"
00033 #include "threads.h"
00034 #include "error.h"
00035 #include "langinternal.h" /*for error strings*/
00036 #include "resources.h" /*for error strings*/
00037 #include "shell.h"
00038 #include "sysshellcall.h"
00039 
00040 
00041 #if defined(MACVERSION) && (TARGET_API_MAC_CARBON == 1)
00042 
00043 #include "lang.h"
00044 #include "CallMachOFramework.h"
00045 #include <fcntl.h> /* 2006-01-10 creedon */
00046 
00047 /* 2006-01-29 creedon - define the following for CodeWarrior compilation because it doesn't have these defined in its headers, as Xcode does */
00048 #ifdef __MWERKS__
00049     #define F_GETFL     3       /* get file status flags */
00050     #define F_SETFL     4       /* set file status flags */
00051     #define O_NONBLOCK  0x0004  /* no delay */
00052 #endif //__MWERKS__
00053 
00054 /*System.framework functions: popen, pclose, fread, fcntl, feof, and fileno.*/
00055 
00056 typedef FILE* (*popenptr) (const char* command, const char *type);
00057 typedef int (*pcloseptr) (FILE* f);
00058 typedef size_t (*freadptr) (void *ptr, size_t size, size_t nobj, FILE* f);
00059 typedef int (*fcntlptr) (int fd, int cmd, int arg); /* 2006-01-10 creedon */
00060 typedef int (*feofptr) (FILE *f); /* 2006-01-10 creedon */
00061 typedef int (*filenoptr) (FILE *f); /* 2006-01-10 creedon */
00062      
00063 static popenptr popenfunc;
00064 static pcloseptr pclosefunc;
00065 static freadptr freadfunc;
00066 static fcntlptr fcntlfunc; /* 2006-01-10 creedon */
00067 static feofptr feoffunc; /* 2006-01-10 creedon */
00068 static filenoptr filenofunc; /* 2006-01-10 creedon */
00069 
00070 static boolean unixshellcallinited = false;
00071 static CFBundleRef sysBundle = nil;
00072 
00073 
00074 static boolean unixshellcallinit (void) {
00075 
00076     /*
00077     2006-01-10 creedon: added fcntlfunc, feoffunc and filenofunc
00078     
00079     7.0b51 PBS: load the bundle and get the function pointers the first time called.
00080     */
00081     
00082     if (unixshellcallinited) /*already inited*/
00083         return (true);
00084         
00085     if (sysBundle == nil)
00086          if (LoadFrameworkBundle (CFSTR ("System.framework"), &sysBundle) != noErr)
00087             return (false);
00088          
00089     popenfunc = (popenptr) CFBundleGetFunctionPointerForName (sysBundle, CFSTR ("popen"));  
00090 
00091     if (popenfunc == nil)
00092         return (false);
00093         
00094     freadfunc = (freadptr) CFBundleGetFunctionPointerForName (sysBundle, CFSTR ("fread"));
00095     
00096     if (freadfunc == nil)
00097         return (false);
00098     
00099     pclosefunc = (pcloseptr) CFBundleGetFunctionPointerForName (sysBundle, CFSTR ("pclose"));
00100     
00101     if (pclosefunc == nil)
00102         return (false);
00103 
00104     fcntlfunc = (fcntlptr) CFBundleGetFunctionPointerForName (sysBundle, CFSTR ("fcntl"));
00105     
00106     if (fcntlfunc == nil)
00107         return (false);
00108 
00109     feoffunc = (feofptr) CFBundleGetFunctionPointerForName (sysBundle, CFSTR ("feof"));
00110     
00111     if (feoffunc == nil)
00112         return (false);
00113 
00114     filenofunc = (filenoptr) CFBundleGetFunctionPointerForName (sysBundle, CFSTR ("fileno"));
00115     
00116     if (filenofunc == nil)
00117         return (false);
00118 
00119     unixshellcallinited = true;
00120     
00121     return (true);  
00122     } /*unixshellcallinit*/
00123 
00124 
00125 static boolean unixshellcallbackgroundtask (void) {
00126 
00127     /*
00128     2005-10-02 creedon: created, cribbed from OpenTransportNetEvents.c: fwsbackgroundtask
00129     */
00130 
00131     boolean fl = true;
00132 
00133     if (inmainthread ()) {
00134         EventRecord ev;
00135         short mask = osMask|activMask|mDownMask|keyDownMask; // |highLevelEventMask|updateMask
00136         long sleepTime = 6; // 1/10 of a second by default
00137         
00138         if (WaitNextEvent (mask, &ev, sleepTime, nil)) /* might return false to indicate a null event, but that's not an error */
00139             fl = shellprocessevent (&ev);
00140         }
00141     else
00142         fl = langbackgroundtask (true);
00143     
00144     return (fl);
00145     }/* unixshellcallbackgroundtask */
00146 
00147 
00148 boolean unixshellcall (Handle hcommand, Handle hreturn) {
00149 
00150     /*
00151     2006-01-29 creedon: change buf from 32 to 1024 to increase performance of function,
00152         we can do this now because fread is now in non-blocking mode, kernel remains repsonsive
00153     
00154     2006-01-10 creedon: laid down the groundwork for a timeoutsecs parameter, what is a good default?
00155         longinfinity? several minutes? I know that some commands I've done have taken 15 - 30 minutes
00156         fread now reads in non-blocking mode, no error checking
00157     
00158     2005-10-02 creedon: changed buf size from 256 to 32, makes envrionment more responsive
00159         added call to new unixshellcallbackgroundtask function so kernel doesn't lock up
00160         while waiting for a lot of data to be read
00161     
00162     7.0b51: Call the UNIX popen command, which evaluates a string as if it were typed
00163         on the command line. Verb: sys.unixShellCommand.
00164         Code adapted by Timothy Paustian from Apple sample code.
00165         This routine by PBS.
00166     */
00167 
00168     FILE *f;
00169     char buf [1024];
00170     long ct = 0;
00171 
00172     if (!unixshellcallinit ())
00173         return (false);
00174         
00175     if (!enlargehandle (hcommand, 1, "\0"))
00176         return (false);
00177     
00178     lockhandle (hcommand);
00179     
00180     f = popenfunc (*hcommand, "r"); /*popen*/
00181     
00182     unlockhandle (hcommand);
00183     
00184     fcntlfunc (filenofunc (f), F_SETFL, fcntlfunc (filenofunc (f), F_GETFL, 0) | O_NONBLOCK);
00185 
00186     while (true) {
00187     
00188         ct = freadfunc (buf, 1, sizeof buf, f); /*fread*/
00189         
00190         if (ct > 0)
00191             if (!enlargehandle (hreturn, ct, buf))
00192                 break;
00193         
00194         if (feoffunc (f))
00195             break;
00196         
00197         if (!unixshellcallbackgroundtask ())
00198             break;
00199         
00200         } /*while*/
00201     
00202     pclosefunc (f); /*pclose*/
00203     
00204     return (true);  
00205     } /*unixshellcall*/
00206 
00207 #endif //MACVERSION
00208 
00209 
00210 #ifdef WIN95VERSION
00211 
00212 #define CHDOUBLEQUOTE   '"'
00213 #define CHSEMICOLON     ';'
00214 #define CHBACKSLASH     '\\'
00215 #define CHNULL          '\0'
00216 
00217 static boolean getenvironmentvariable (char *name, boolean flwinerror, Handle *hresult) {
00218     
00219     /*
00220     2006-03-09 aradke: utility function for getting a Windows environment variable
00221         as a handle without terminating nil char.
00222     */
00223     
00224     Handle h;
00225     long res;
00226 
00227     res = GetEnvironmentVariable (name, nil, 0); /*get required space*/
00228 
00229     if (res == 0) {
00230         if (flwinerror)
00231             winerror ();
00232         return (false);
00233         }
00234 
00235     if (!newclearhandle (res, &h))
00236         return (false);
00237 
00238     lockhandle (h);
00239 
00240     res = GetEnvironmentVariable (name, *h, res); /*get actual value*/
00241 
00242     unlockhandle (h);
00243     
00244     assert (gethandlesize (h) == res + 1);
00245 
00246     if (!sethandlesize (h, res)) {  /*drop trailing nil char*/
00247         disposehandle (h);
00248         return (false);
00249         }
00250 
00251     *hresult = h;
00252         
00253     return (true);
00254     } /*getenvironmentvariable*/
00255 
00256 
00257 static boolean cmdshellexists (Handle hshell) {
00258 
00259     /*
00260     2006-03-09 aradke: check whether a file exists at the given path
00261     */
00262 
00263     DWORD attr;
00264     
00265     lockhandle (hshell);
00266 
00267     attr = GetFileAttributes (*hshell);
00268 
00269     unlockhandle (hshell);
00270     
00271     return (attr != -1); 
00272     } /*cmdshellexists*/
00273     
00274 
00275 static boolean getcmdshell (Handle *hshell) {
00276 
00277     /*
00278     2006-03-09 aradke: return name or path of command shell in hshell.
00279         check the COMSPEC environment variable first. if it does not exist, resort
00280         to guessing the name of the shell based on the current OS version.
00281         caller is responsible for disposing the handle if we return true.
00282     */
00283     
00284     OSVERSIONINFO osinfo;
00285     bigstring bs;
00286     
00287     if (getenvironmentvariable ("COMSPEC", false, hshell))
00288         return (true);
00289 
00290     osinfo.dwOSVersionInfoSize = sizeof (osinfo);
00291         
00292     if (GetVersionEx (&osinfo) == nil) {
00293         winerror ();
00294         return (false);
00295         }
00296 
00297     if (osinfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
00298         copystring ("\x0b" "command.com", bs); /*Win95/98/ME: actual DOS command interpreter*/
00299         }
00300     else {
00301         copystring ("\x07" "cmd.exe", bs); /*WinNT and successors: DOS emulation*/
00302         }
00303 
00304     return (newtexthandle (bs, hshell));
00305     } /*getcmdshell*/
00306 
00307 
00308 static boolean getnextpath (Handle hpath, long *ixstart, Handle *hitem) {
00309 
00310     /*
00311     2006-03-10 aradke: extract the next item from a string delimited by semicolons
00312     */
00313 
00314     Handle h;
00315     handlestream s;
00316     char ch;
00317     
00318     openhandlestream (hpath, &s);
00319     s.pos = *ixstart;
00320     
00321     /*first pass: locate end of next path item*/
00322     
00323     skiphandlestreamchars (&s, CHSEMICOLON); /*ignore leading semicolons*/
00324     *ixstart = s.pos;
00325     
00326     while (!athandlestreameof (&s)) {
00327         
00328         ch = nexthandlestreamcharacter (&s);
00329         
00330         if (ch == CHSEMICOLON) {
00331             break;
00332             }
00333         else if (ch == CHDOUBLEQUOTE) {
00334             s.pos++;
00335             seekhandlestreamchar (&s, CHDOUBLEQUOTE); /*skip over contents of doublequotes*/
00336             }
00337             
00338         s.pos++;
00339         }/*while*/
00340     
00341     assert (athandlestreameof (&s) || (nexthandlestreamcharacter (&s) == CHSEMICOLON));
00342     
00343     /*extract item*/
00344     
00345     if (!loadfromhandletohandle (s.data, ixstart, min(s.pos, s.eof) - *ixstart, false, &h))
00346         return (false);
00347     
00348     /*second pass: remove included doublequotes*/
00349     
00350     openhandlestream (h, &s);
00351     
00352     while (true) {
00353         
00354         seekhandlestreamchar (&s, CHDOUBLEQUOTE);
00355         
00356         if (athandlestreameof (&s))
00357             break;
00358         
00359         pullfromhandlestream (&s, 1, nil);
00360         }/*while*/
00361     
00362     assert (athandlestreameof (&s));
00363     
00364     if (s.eof == 0)
00365         return (false); /*break out of potential infinite loop at end of path string*/
00366     
00367     if (lasthandlestreamcharacter (&s) != CHBACKSLASH)
00368         if (!writehandlestreamchar (&s, CHBACKSLASH)) {
00369             disposehandlestream (&s);
00370             return (false);
00371             }
00372     
00373     assert (lasthandlestreamcharacter (&s) == CHBACKSLASH);
00374     
00375     *hitem = closehandlestream (&s);
00376     
00377     return (true);
00378     } /*getnextpath*/
00379     
00380 
00381 static void cmdnotfounderror (Handle hshell) {
00382 
00383     /*
00384     2006-03-10 aradke: report missing command shell
00385     */
00386     
00387     bigstring bsshell, bs;
00388     
00389     texthandletostring (hshell, bsshell);
00390     
00391     poptrailingchars (bsshell, CHNULL);
00392     
00393     getstringlist (langerrorlist, cmdshellnotfounderror, bs);
00394     
00395     parsedialogstring (bs, (ptrstring) bsshell, nil, nil, nil, bs);
00396     
00397     shellerrormessage (bs);
00398     } /*cmdnotfounderror*/
00399 
00400     
00401 static boolean searchcmdpath (Handle *hshell) {
00402 
00403     /*
00404     2006-03-09 aradke: get the PATH environment variable and parse it.
00405         see if the command shell is located in any of the directories.
00406         caller is responsible for disposing hshell.
00407     */
00408     
00409     Handle hpath = nil;
00410     Handle h = nil;
00411     long ix = 0;
00412 
00413     /*obtain path environment variable*/
00414 
00415     if (!getenvironmentvariable ("PATH", true, &hpath))
00416         return (false);
00417     
00418     /*parse path*/
00419     
00420     while (getnextpath (hpath, &ix, &h)) {
00421         
00422         if (!pushhandle (*hshell, h))
00423             goto exit;
00424 
00425         if (!pushcharhandle (CHNULL, h))
00426             goto exit;
00427         
00428         if (cmdshellexists (h)) {
00429             disposehandle (*hshell);
00430             *hshell = h;
00431             return (true);
00432             }
00433 
00434         disposehandle (h);
00435         }/*while*/
00436     
00437     cmdnotfounderror (*hshell);
00438     
00439 exit:
00440     disposehandle (hpath);
00441     
00442     return (false);
00443     } /*searchcmdpath*/
00444     
00445     
00446 static boolean runcmdshell (Handle hshell, Handle hcommand, HANDLE *hprocess, HANDLE *hout, HANDLE *herr) {
00447 
00448     /*
00449     2006-03-09 aradke: launch the command shell as a child process.
00450         we consume hshell, but caller is responsible for closing hout if we return true.
00451     */
00452     
00453     Handle hcmdline = nil;
00454     SECURITY_ATTRIBUTES securityinfo;
00455     STARTUPINFO startupinfo;
00456     PROCESS_INFORMATION processinfo;
00457     HANDLE houtread = nil;
00458     HANDLE houtwrite = nil;
00459     HANDLE herrread = nil;
00460     HANDLE herrwrite = nil;
00461     boolean fl;
00462     
00463     *hprocess = nil;
00464     
00465     /*create pipes for reading from command shell*/
00466 
00467     clearbytes (&securityinfo, sizeof (securityinfo));
00468     securityinfo.nLength                = sizeof (securityinfo);
00469     securityinfo.lpSecurityDescriptor   = nil;
00470     securityinfo.bInheritHandle         = true;
00471     
00472     if (hout) { /*caller interested in stdout*/
00473     
00474         if (!CreatePipe (&houtread, &houtwrite, &securityinfo, nil))
00475             goto error;
00476         
00477         if (!SetHandleInformation (houtread, HANDLE_FLAG_INHERIT, 0))
00478             goto error;
00479         }
00480     else
00481         houtwrite = GetStdHandle (STD_OUTPUT_HANDLE);
00482 
00483     if (herr) { /*caller interested in stderr*/
00484 
00485         if (!CreatePipe (&herrread, &herrwrite, &securityinfo, nil))
00486             goto error;
00487         
00488         if (!SetHandleInformation (herrread, HANDLE_FLAG_INHERIT, 0))
00489             goto error;
00490         }
00491     else
00492         herrwrite = GetStdHandle (STD_ERROR_HANDLE);
00493         
00494     /*init structs for creating process*/
00495     
00496     clearbytes (&startupinfo, sizeof (startupinfo));
00497     startupinfo.cb = sizeof (startupinfo);
00498     startupinfo.dwFlags     = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
00499     startupinfo.hStdInput   = GetStdHandle (STD_INPUT_HANDLE);
00500     startupinfo.hStdOutput  = houtwrite;
00501     startupinfo.hStdError   = herrwrite;
00502     startupinfo.wShowWindow = SW_HIDE;
00503     
00504     clearbytes (&processinfo, sizeof (processinfo));
00505     
00506     /*synthesize command string*/
00507     
00508     if (!inserttextinhandle (hcommand, 0, "\x04" " /c "))
00509         goto exit;
00510     
00511     if (!concathandles (hshell, hcommand, &hcmdline))
00512         goto exit;
00513     
00514     if (!pushcharhandle (CHNULL, hshell))
00515         goto exit;
00516 
00517     if (!pushcharhandle (CHNULL, hcmdline))
00518         goto exit;
00519     
00520     /*check whether command shell can be accessed*/
00521     
00522     if (!cmdshellexists (hshell)) {
00523         if (!searchcmdpath (&hshell))   /*do a search path lookup, sets error*/
00524             goto exit;
00525         }
00526         
00527     /*create command shell process*/
00528     
00529     lockhandle (hshell);
00530     lockhandle (hcmdline);
00531     
00532     fl = CreateProcess (
00533             *hshell,        /*IN LPCSTR lpApplicationName*/
00534             *hcmdline,      /*IN LPSTR lpCommandLine*/
00535             nil,            /*IN LPSECURITY_ATTRIBUTES lpProcessAttributes*/
00536             nil,            /*IN LPSECURITY_ATTRIBUTES lpThreadAttributes*/
00537             true,           /*IN BOOL bInheritHandles*/
00538             0,              /*IN DWORD dwCreationFlags*/
00539             nil,            /*IN LPVOID lpEnvironment: use parent's*/
00540             nil,            /*IN LPCSTR lpCurrentDirectory: use parent's*/
00541             &startupinfo,   /*IN LPSTARTUPINFOA lpStartupInfo*/
00542             &processinfo);  /*OUT LPPROCESS_INFORMATION lpProcessInformation*/
00543     
00544     unlockhandle (hshell);
00545     unlockhandle (hcmdline);
00546     
00547     /*handle result*/
00548     
00549     if (!fl)
00550         goto error;
00551     
00552     CloseHandle (houtwrite);    /*now inherited by child process*/
00553     CloseHandle (herrwrite);
00554     
00555     CloseHandle (processinfo.hThread);
00556     
00557     disposehandle (hcmdline);
00558     disposehandle (hshell);
00559     
00560     *hprocess = processinfo.hProcess;
00561     
00562     if (hout)
00563         *hout = houtread;
00564     
00565     if (herr)
00566         *herr = herrread;
00567     
00568     return (true);
00569 
00570 error:
00571     winerror (); /*note fall through*/
00572         
00573 exit:   /*error is already set*/
00574     if (hout && !houtread)
00575         CloseHandle (houtread);
00576     
00577     if (hout && !houtwrite)
00578         CloseHandle (houtwrite);
00579     
00580     if (herr && !herrread)
00581         CloseHandle (herrread);
00582     
00583     if (herr && !herrwrite)
00584         CloseHandle (herrwrite);
00585 
00586     disposehandle (hcmdline);
00587     disposehandle (hshell);
00588     
00589     return (false); 
00590     } /*runcmdshell*/
00591 
00592 
00593 static boolean readcmdpipe (HANDLE hpipe, Handle hdata, boolean *flreadmore) {
00594 
00595     /*
00596     2006-03-10 aradke: read from pipe if data is available
00597     */
00598     
00599     DWORD ctavail, ctread;
00600     DWORD err;
00601     
00602     if (!PeekNamedPipe (hpipe, nil, nil, nil, &ctavail, nil))
00603         goto error;
00604     
00605     if (ctavail > 0) {
00606         
00607         long oldsize, newsize;
00608         
00609         oldsize = gethandlesize (hdata);
00610         
00611         newsize = oldsize + ctavail;
00612         
00613         if (!sethandlesize (hdata, newsize)) {  /*memory error*/
00614             *flreadmore = false;
00615             return (false);
00616             }
00617     
00618         if (!ReadFile (hpipe, &((*hdata)[oldsize]), ctavail, &ctread, nil)) /*should not block*/
00619             goto error;
00620         }
00621     
00622     return (true);
00623 
00624 error:
00625 
00626     *flreadmore = false;
00627 
00628     err = GetLastError ();
00629     
00630     if (err == ERROR_BROKEN_PIPE)
00631         return (true);
00632     
00633     oserror (err);
00634     
00635     return (false);
00636     }/*readcmpipe*/
00637 
00638 
00639 static boolean readcmdresult (HANDLE houtread, HANDLE herrread, Handle houttext, Handle herrtext) {
00640 
00641     /*
00642     2006-03-09 aradke: read data from pipe until eof.
00643         we close our end of the pipe (hread) whether we succeed or not.
00644     */
00645     
00646     boolean flreadout = (houttext != nil);
00647     boolean flreaderr = (herrtext != nil);
00648     boolean fl = true;
00649     
00650     while (flreadout || flreaderr) {
00651         
00652         if (flreadout) {
00653 
00654             fl = readcmdpipe (houtread, houttext, &flreadout);
00655             
00656             if (!fl)
00657                 break; /*error occurred*/
00658             }
00659         
00660         if (flreaderr) {
00661 
00662             fl = readcmdpipe (herrread, herrtext, &flreaderr);
00663             
00664             if (!fl)
00665                 break; /*error occurred*/
00666             }
00667                 
00668         langbackgroundtask (true); /*resting*/
00669         } /*while*/
00670     
00671     if (houtread)
00672         CloseHandle (houtread);
00673     
00674     if (herrread)
00675         CloseHandle (herrread);
00676     
00677     return (fl);
00678     } /*readcmdresult*/
00679 
00680 
00681 static boolean getcmdexitcode (Handle hprocess, long *status) {
00682     
00683     /*
00684     2006-03-10 aradke: wait for child process to exit, then get its exit code
00685     */
00686     
00687     DWORD res;
00688     boolean fl = true;
00689     
00690     *status = 0;
00691     
00692     releasethreadglobals ();
00693     
00694     res = WaitForSingleObject (hprocess, INFINITE);
00695     
00696     grabthreadglobals ();
00697     
00698     if (res != WAIT_OBJECT_0)
00699         goto exit;
00700         
00701     fl = GetExitCodeProcess (hprocess, status);
00702     
00703     if (!fl)
00704         winerror ();
00705 
00706 exit:   
00707     CloseHandle (hprocess);
00708     
00709     return (fl);
00710     } /*getcmdexitcode*/
00711 
00712 
00713 boolean winshellcall (Handle hcommand, Handle houttext, Handle herrtext, long *exitcode) {
00714 
00715     /*
00716     2006-03-09 aradke: call the Windows shell and execute the given command.
00717         our caller owns hcommand and hreturn, whether we succeed or not.
00718         this implementation relies on the win32 api only and does not
00719         require popen etc to be available in the c runtime library.
00720 
00721     2006-03-10 aradke: also read stderr of child process and get its exit code.
00722         caller owns houttext (previously hreturn) and herrtext. if either is nil,
00723         don't create and read respective pipe.
00724     */
00725 
00726     Handle hshell = nil;
00727     HANDLE hprocess = nil;
00728     HANDLE hout = nil;
00729     HANDLE herr = nil;
00730 
00731     if (!getcmdshell (&hshell))
00732         return (false);
00733     
00734     if (!runcmdshell (hshell, hcommand, &hprocess,
00735                         ((houttext != nil) ? &hout : nil),
00736                         ((herrtext != nil) ? &herr : nil))) /*consumes hshell*/
00737         return (false);
00738 
00739     if (!readcmdresult (hout, herr, houttext, herrtext)) { /*consumes hout and herr*/
00740         CloseHandle (hprocess);
00741         return (false);
00742         }
00743     
00744     if (exitcode == nil)
00745         CloseHandle (hprocess);
00746     else if (!getcmdexitcode (hprocess, exitcode)) /*consumes hprocess*/
00747         return (false);
00748         
00749     return (true);
00750     } /*winshellcall*/
00751 
00752 
00753 #if 0 
00754 
00755 #include <stdio.h>
00756 #include <stdlib.h>
00757 
00758 boolean winshellcall (Handle hcommand, Handle hreturn) {
00759 
00760     /*
00761     2006-03-09 aradke: simple version relying on popen to be available
00762         from the c runtime library. that is the case with microsoft's
00763         runtime library, but not with metrowerks. see our own
00764         implementation above using only win32 api calls.
00765     */
00766 
00767     FILE *f;
00768     char buf[1024];
00769     long ct = 0;
00770         
00771     if (!enlargehandle (hcommand, 1, "\0"))
00772         return (false);
00773     
00774     lockhandle (hcommand);
00775     
00776     releasethreadglobals ();
00777 
00778     f = _popen (*hcommand, "r");
00779 
00780     grabthreadglobals ();
00781 
00782     unlockhandle (hcommand);
00783 
00784     while (true) {
00785         
00786         releasethreadglobals ();
00787 
00788         ct = fread (buf, 1, sizeof (buf), f); /*fread*/
00789         
00790         grabthreadglobals ();
00791 
00792         if (ct > 0)             
00793             if (!enlargehandle (hreturn, ct, buf))
00794                 break;
00795         
00796         if (feof (f))
00797             break;
00798 
00799         } /*while*/
00800     
00801     _pclose (f);
00802     
00803     return (true);  
00804     } /*winshellcall*/
00805 
00806 #endif
00807 
00808 #endif //WIN95VERSION
00809 

Generated on Wed May 31 18:20:02 2006 for frontierkernel 10.1.10a by  doxygen 1.4.6