root/trunk/txlib/txextcmd.c

Revision 11, 14.6 kB (checked in by jvw, 3 years ago)

DFSee 8.01 level; fix crash on huge PATH; History-popup improved (4OS2 compatible)

Line 
1//
2//                     TxWin, Textmode Windowing Library
3//
4//   Original code Copyright (c) 1995-2005 Fsys Software and Jan van Wijk
5//
6// ==========================================================================
7//
8// This file contains Original Code and/or Modifications of Original Code as
9// defined in and that are subject to the GNU Lesser General Public License.
10// You may not use this file except in compliance with the License.
11// BY USING THIS FILE YOU AGREE TO ALL TERMS AND CONDITIONS OF THE LICENSE.
12// A copy of the License is provided with the Original Code and Modifications,
13// and is also available at http://www.dfsee.com/txwin/lgpl.htm
14//
15// This library is free software; you can redistribute it and/or modify
16// it under the terms of the GNU Lesser General Public License as published
17// by the Free Software Foundation; either version 2.1 of the License,
18// or (at your option) any later version.
19//
20// This library is distributed in the hope that it will be useful,
21// but WITHOUT ANY WARRANTY; without even the implied warranty of
22// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
23// See the GNU Lesser General Public License for more details.
24//
25// You should have received a copy of the GNU Lesser General Public License
26// along with this library; (lgpl.htm) if not, write to the Free Software
27// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28//
29// Questions on TxWin licensing can be directed to: txwin@fsys.nl
30//
31// ==========================================================================
32//
33// TX external command execution
34//
35// Author: J. van Wijk
36//
37// 24-07-2005  Restyled for TXWIN open version
38
39#include <malloc.h>
40#include <process.h>
41
42#include <txlib.h>                              // TX library interface
43#include <txwpriv.h>                            // TX private interfaces
44
45#ifndef DEV32
46
47#define TXC_TEMP_FILE_NAME "_-!TX!-_.TMP"
48
49// Execute, using FILE redirected stdout/stderr to TxPrint
50static ULONG txcExecStdOutFile
51(
52   char               *cmd                      // IN    command to execute
53);
54
55#else                                           // OS/2
56
57// temporary hack to het KBD handle (move IOCTl to txwmsg.c later)
58extern HFILE   txw_hkeyboard;
59
60
61#define TXC_PIPE_SIZE      16384                // size of output pipe
62#define TXC_NEW_HANDLE     0xFFFFFFFF           // new from DosDup...
63#define TXC_MAX_TIMEOUTS   9                    // max nr of receive timeouts
64#define TXC_EOF            ((char) 0x1a)        // end-of-file indicator
65#define TXC_CR             ((char) 0x0d)        // carriage return
66#define TXC_LF             ((char) 0x0a)        // linefeed
67
68#define STDIN              0
69#define STDOUT             1
70#define STDERR             2
71
72
73typedef struct txc_io_handles
74{
75   TXHFILE             read;
76   TXHFILE             write;
77   TXHFILE             save;
78   char                ind;                     // progress indicator
79} TXC_IO_HANDLES;                               // end of struct
80
81
82// Execute an external command, using PIPE redirected stdout/stderr to TxPrint
83ULONG txcExecStdOutPipe
84(
85   char               *cmd                      // IN    command to execute
86);
87
88// TXC child-stdout thread, waiting for output by child-process; to TxPrint
89static void txcPipeOutputPump
90(
91   void               *p                        // IN    pointer parameter
92);
93
94// Write to stream (redirected stdout) with logfile (TEE) and output hooks
95static void TxWriteStream
96(
97   TXHFILE             stream,                  // IN    stream to write to
98   char               *text                     // IN    string to write
99);
100
101#endif
102
103#if defined (LINUX)
104static char txcTrustedExternals[] = " LS LL CD RM CHMOD CAT CLEAR CP SU MV DU DF MOUNT UMOUNT ";
105#else
106static char txcTrustedExternals[] = " DIR CD DEL REN RENAME ATTRIB SET TYPE MODE CLS CHCP"
107#if defined (DOS32)
108                                    " MEM KEYB "
109#else
110                                    " HELP MOVE"
111#endif
112                                    " COPY ";
113#endif
114
115
116
117#define TXCM_HELPREG        0xffff0240          // base help-id registration
118
119#if defined (USEWINDOWING)
120static BOOL txc_help_registred = FALSE;
121
122static  char       *confirmhelp[] =
123{
124   "",
125   " Untrusted external command!",
126   "",
127   " This is to acknowledge that you want the displayed command to",
128   " be executed, knowing it is not in the list of trusted commands.",
129   "",
130   " It is likely that you just made a typing error ...",
131   "",
132   "",
133   "",
134   "",
135   "",
136   NULL
137};
138#endif
139
140
141/*****************************************************************************/
142// Execute an external command, redirect stdout/stderr to TxPrint
143/*****************************************************************************/
144ULONG TxExternalCommand
145(
146   char               *cmd                      // IN    command to execute
147)
148{
149   ULONG               rc  = NO_ERROR;
150   TXTS                first;                   // first word
151   char               *s;
152
153   ENTER();
154
155   #if defined (USEWINDOWING)
156      if (!txc_help_registred)
157      {
158         txwRegisterHelpText( TXCM_HELPREG, "External command confirmation", confirmhelp);
159         txc_help_registred = TRUE;
160      }
161   #endif                                       // USEWINDOWING
162
163   memset( first, ' ',    TXMAXTS);
164   TxCopy( first +1, cmd, TXMAXTS -1);
165   if ((s = strchr( first +1, ' ')) != NULL)
166   {
167      *(s+1) = 0;
168   }
169   strupr( first);                              // uppercased first word
170
171   TRACES(( "first: '%s' for cmd: '%s'\n", first, cmd));
172
173   if ((TxaExeSwitch('b')) || (TxaOption('B'))       ||
174       (strstr( txcTrustedExternals, first) != NULL) ||
175       (TxConfirm( TXCM_HELPREG + 00, "%s%s%s is not a trusted command!\nAre you "
176                   "sure you want to have :\n\n%s%s%s\n\nexecuted as an external "
177                   "command ? [Y/N] : ", CBR, first +1, CNN, CBG, cmd, CNN)))
178   {
179      #if defined (DEV32)
180         #if defined (USEWINDOWING)
181            txwa->KbdKill = TRUE;               // hack to quit KBD thread
182
183            #if defined (TRY_KBD_HACK)          // JvW: causes PM-wide KBD hang
184               {
185                  BYTE  kbdMode  = 2;
186                  ULONG ParamLen = sizeof(kbdMode);
187
188                  //- Use mode IOCtl, may unblock KBD subsystem from KbdCharIn()
189                  DosDevIOCtl( txw_hkeyboard, IOCTL_KEYBOARD, KBD_SETINPUTMODE,
190                               &kbdMode, ParamLen, &ParamLen, NULL, 0, NULL);
191
192                  kbdMode = 0;                  // back to ASCII mode
193                  DosDevIOCtl( txw_hkeyboard, IOCTL_KEYBOARD, KBD_SETINPUTMODE,
194                               &kbdMode, ParamLen, &ParamLen, NULL, 0, NULL);
195               }
196            #else
197               TxPrint( "\nPress ENTER to execute: '%s'\n", cmd);
198            #endif
199
200            rc = txcExecStdOutPipe( cmd);
201            TxInputDesktopInit();               // restart KBD thread
202         #else
203            rc = txcExecStdOutPipe( cmd);       // simple KBD IO used
204         #endif
205      #else
206         rc = txcExecStdOutFile( cmd);
207      #endif
208   }
209   #if defined (USEWINDOWING)
210      if (txwIsWindow( TXHWND_DESKTOP))
211      {
212         txwInvalidateAll();                    // repaint windows, in case
213      }                                         // the screen was 'damaged'
214   #endif                                       // USEWINDOWING
215   RETURN (rc);
216}                                               // end 'TxExternalCommand'
217/*---------------------------------------------------------------------------*/
218
219#ifndef DEV32
220
221/*****************************************************************************/
222// Execute an external command, using FILE redirected stdout/stderr to TxPrint
223/*****************************************************************************/
224static ULONG txcExecStdOutFile
225(
226   char               *cmd                      // IN    command to execute
227)
228{
229   ULONG               rc  = NO_ERROR;
230   TXLN                command;                 // redirected command
231   FILE               *so;                      // std output file
232
233   ENTER();
234
235   strcpy( command, cmd);                       // command to execute
236   strcat( command, " > ");
237   strcat( command, TXC_TEMP_FILE_NAME);
238   #if defined (WIN32)                          // redirect stderr too
239      strcat( command, " 2>&1");
240   #endif
241
242   TxDeleteFile( TXC_TEMP_FILE_NAME);
243   TRACES(( "External command: '%s'\n", command));
244   rc = (ULONG) system( command);               // execute the command
245
246   if ((so = fopen( TXC_TEMP_FILE_NAME, "r" TXFMODE)) != NULL)
247   {
248      while (!TxAbort() && !feof(so) && !ferror(so))
249      {
250         if (fgets( command, TXMAXLN, so) != NULL)
251         {
252            TxPrint( "%s", command);
253         }
254      }
255      fclose( so);
256   }
257   TxDeleteFile( TXC_TEMP_FILE_NAME);
258   RETURN (rc);
259}                                               // end 'txcExecStdOutFile'
260/*---------------------------------------------------------------------------*/
261
262
263#else                                           // OS/2
264
265/*****************************************************************************/
266// Execute an external command, using PIPE redirected stdout/stderr to TxPrint
267/*****************************************************************************/
268ULONG txcExecStdOutPipe
269(
270   char               *cmd                      // IN    command to execute
271)
272{
273   ULONG               rc  = NO_ERROR;
274   TXC_IO_HANDLES      ho;                      // handles stdout
275   HFILE               wt;                      // temp write-handle
276   TID                 tidout;                  // Thread-id stdout reader
277   TXLN                command;
278
279   ENTER();
280
281   if ((rc = DosCreatePipe( &(ho.read),
282                            &(ho.write),
283                            TXC_PIPE_SIZE)) == NO_ERROR)
284   {
285      ho.save = TXC_NEW_HANDLE;
286      if ((rc = DosDupHandle(  STDOUT, &(ho.save))) == NO_ERROR)
287      {
288         if (ho.write != STDOUT)                // unless we got right value
289         {
290            wt = STDOUT;                        // duplicate it to handle
291            rc = DosDupHandle( ho.write, &wt);  // with correct value
292            if (rc == NO_ERROR)
293            {
294               TxClose( ho.write);              // close original pipe wh
295               ho.write = wt;
296            }
297         }
298         if (rc == NO_ERROR)
299         {
300            tidout = TxBeginThread( txcPipeOutputPump, 16384, &ho);
301
302            strcpy( command, cmd);
303            strcat( command, " < NUL");
304            if ((strstr(command, "2>") == NULL) &&
305                (strstr(command, "&2") == NULL) )
306            {                                   // let CMD.EXE combine stderr
307               strcat( command, " 2>&1");       // with stdout, resulting in
308            }                                   // better ordering of output
309            TRACES(( "External command: '%s'\n", command));
310            rc = (ULONG) system( command);
311
312            fprintf( stdout, "%c", TXC_EOF);    // end stdout
313            fflush(  stdout);
314
315            DosWaitThread( &tidout, DCWW_WAIT); // wait for pump to complete
316
317            wt = STDOUT;                        // reconnect stdout
318            if (DosDupHandle( ho.save, &wt) == NO_ERROR)
319            {
320               TxClose( ho.save);               // close original save-handle
321            }
322         }
323      }
324      TxClose( ho.read);                        // close the pipe-handle
325   }
326   RETURN (rc);
327}                                               // end 'txcExecStdOutPipe'
328/*---------------------------------------------------------------------------*/
329
330
331/*****************************************************************************/
332// TXC child-stdout thread, waiting for output by child-process; to TXPRINT
333/*****************************************************************************/
334void txcPipeOutputPump
335(
336   void               *p                        // IN    pointer parameter
337)
338{
339   TXC_IO_HANDLES     *sh = (TXC_IO_HANDLES *) p;
340   char                ch = 0;                  // temporary char
341   ULONG               nr;                      // nr of chars read
342   ULONG               i;
343   TX1K                buf;
344
345   ENTER();
346   while (ch != TXC_EOF)
347   {
348      for ( i = 0, ch = '\0';
349           (i < TXMAX1K -1) && (ch != TXC_EOF) && (ch != '\n');
350          )
351      {
352         if ((TxRead( sh->read, &ch, 1, &nr) == NO_ERROR) && nr)
353         {
354            switch (ch)
355            {
356               case TXC_EOF:                    // end of stream
357               case TXC_CR:
358                  break;
359
360               case TXC_LF:                     // end of line
361                  ch = '\n';                    // fall through
362               default:
363                  buf[i++] = ch;
364                  break;
365            }
366         }
367         else
368         {
369            ch = TXC_EOF;                       // terminate on errors
370         }
371      }
372      if (i > 0)                                // anything to redirect ?
373      {
374         buf[i]  = '\0';                        // terminate string
375         TxWriteStream( sh->save, buf);
376      }
377   }
378   VRETURN();
379}                                               // end 'txcPipeOutputPump'
380/*---------------------------------------------------------------------------                    */
381
382
383/*****************************************************************************/
384// Write to stream (redirected stdout) with logfile (TEE) and output hooks
385/*****************************************************************************/
386static void TxWriteStream
387(
388   TXHFILE             stream,                  // IN    stream to write to
389   char               *text                     // IN    string to write
390)
391{
392   ULONG               size = strlen(text);
393
394   TxPrint( "%s", text);                        // output to logfile/hooks
395
396   if (((TxScreenState(DEVICE_TEST)) == DEVICE_ON) &&  //- screen active
397       (txwa->desktop == NULL))                        //- and not windowed!
398   {                                                   //- direct to stdout
399      if (text[size-1] == '\n')
400      {
401         text[--size]   = '\0';
402         TxWrite( stream, text, size, &size);
403         TxWrite( stream, "\r\n",  2, &size);
404      }
405      else
406      {
407         TxWrite( stream, text, size, &size);
408      }
409   }
410}                                               // end 'TxWriteStream'
411/*---------------------------------------------------------------------------*/
412#endif
Note: See TracBrowser for help on using the browser.