1 /* Copyright (c) 1992, 1998 John E. Davis
2  * This file is part of JED editor library source.
3  *
4  * You may distribute this file under the terms the GNU General Public
5  * License.  See the file COPYING for more information.
6  */
7 /* ///////////////////////////////////////////////////////////////////
8 //  File:	dos_os2.c
9 //
10 //  Descript:	routines that are common to dos & os/2 and `fairly'
11 //		compiler independent
12 //		included by i386.c, ibmpc.c, os2.c
13 //
14 //  Public:
15 //		sys_delete_file();
16 //		sys_suspend();
17 //		sys_System();
18 //
19 //  Private:	discover_shell();
20 //		parse_command_line();
21 //
22 //  Public:	NumLock_Is_Gold, PC_Alt_Char
23 //
24 //  Private:	---
25 //
26 //  Revisions:
27 //   - --- --	---	---
28 /////////////////////////////////////////////////////////////////// */
29 #ifndef __DOS_OS2_CODE_INCLUDED
30 #define __DOS_OS2_CODE_INCLUDED
31 
32 #include "config.h"
33 #include "jed-feat.h"
34 
35 #ifdef __GO32__
36 # include <fcntl.h>
37 # include <sys/types.h>
38 # include <sys/stat.h>
39 # include <sys/file.h>
40 #endif
41 
42 #ifdef __os2__
43 #include <fcntl.h>
44 #include <io.h>
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #endif
48 
49 #ifdef __MSDOS__
50 #include <fcntl.h>
51 #include <io.h>
52 #include <sys/stat.h>
53 #endif
54 
55 #ifdef UNIXSLASH
56 const char SlashChar[2] = "/";
57 #else
58 const char SlashChar[2] = "\\";
59 #endif
60 extern char *get_cwd (void);
61 
62 int NumLock_Is_Gold = 0;	       /* map numlock key to F1 */
63 int PC_Alt_Char = 27;
64 
65 
66 /* Delete the file NAME.  returns 0 on failure, 1 on sucess
67  * Under OS/2 and DOS, unlink()[UNIX] and remove()[ANSI] are equivalent.
68  */
69 
sys_delete_file(char * name)70 int sys_delete_file(char *name)
71 {
72     return(1 + remove(name));
73 }
74 
75 
76 /* find shell (once only) */
77 static char *shell = NULL, *shell_switch = NULL;
discover_shell(void)78 static void discover_shell(void)
79 {
80    if ( shell != NULL )  return;
81 #ifdef SH_SHELL			       /* maybe some day ... */
82    shell_switch = "-c";
83    if ( (shell = getenv("SHELL")) != NULL )  return;
84 #endif
85    shell_switch = "/c";
86    if ( (shell = getenv("COMSPEC")) != NULL ) return;
87 #ifdef __os2__
88    shell = "cmd.exe";		       /* absolute last resort! */
89 #else
90    shell = "command.com";	       /* absolute last resort! */
91 #endif
92 }
93 
94 
95 
96 /* ///////////////////////////////////////////////////////////////////
97 //  Function:   static int parse_command_line( int *argc, char ***argv,
98 //					       char **fname,
99 //					       char *command_line );
100 //  Descript:	parse command_line
101 //
102 //  Returns:	the handles to redirect
103 //
104 //  Caveat:	requires spaces to separate each argument
105 //		ie., args>filename	will NOT work
106 ///////////////////////////////////////////////////////////////////// */
107 #define DIRECT_SPAWN 0x1000	       /* some arbitrary number */
108 static int
parse_command_line(int * argc,char *** argv,char ** fname,char * command_line)109 parse_command_line( int *argc, char ***argv, char **fname, char *command_line )
110 {
111    int count, handles = 0;
112    char *pt;
113 
114    discover_shell();		       /* find which shell to use */
115    while ( (*command_line != '\0') && (*command_line == ' '))
116      command_line++;		       /* start on 1st non-space */
117 
118    if ( *command_line == '!' ) {
119       handles = DIRECT_SPAWN;
120       command_line++;		       /* advance past '!' */
121       while ((*command_line != '\0') && (*command_line == ' '))
122       	command_line++;		       /* start on next non-space */
123    }
124 
125    pt = command_line;
126    count = 0;
127    while ( *pt != '\0' ) {
128       count++;			       /* this is an argument */
129       while ((*pt != '\0') && (*pt != ' '))
130 	{
131 	   if ( *pt == '|' )	       /* cannot spawn directly */
132 	     handles = 0;		       /* need shell for pipes */
133 	   pt++;			       /* advance until a space */
134       }
135       while ( *pt == ' '  )
136       	pt++;			       /* advance until a non-space */
137    }
138 
139    *argv = (char **) SLmalloc ( (count+3) * sizeof(char *) );
140    if ( *argv == NULL )
141      return 0;			       /* malloc error */
142 
143    *argc = 0;
144    if ( !(handles & DIRECT_SPAWN) ) {
145       (*argv)[ *argc ] = shell;
146       (*argc)++;
147       if ( count > 0 )  {
148 	 (*argv)[ *argc ] = shell_switch;
149 	 (*argc)++;
150       }
151       count += (*argc);
152    }
153 
154    pt = command_line;
155    while ((*argc < count) && (*pt != '\0')) {
156       (*argv)[ *argc ] = pt;
157       (*argc)++;
158       while ( *pt != '\0' && *pt != ' ' )
159       	pt++;			/* advance until a space */
160       if ( *pt != '\0' )
161       	*(pt++) = '\0';		/* parse argument here */
162       while ( *pt == ' ')
163       	pt++;		        /* advance until a non-space */
164    }
165    (*argv) [ *argc ] = (char *) NULL;	/* NULL terminated list */
166 
167 /*  now examine the arguments for '>' redirect */
168 
169    for ( count = 0; count < *argc; count++ ) {
170       for ( pt = (*argv)[count]; *pt && *pt != '>'; pt++ )
171 	 /* find '>' char */;
172       if ( *pt == '>' ) {
173 	 if ( pt == (*argv)[count] ) {
174 	    handles |= 0x01;
175 	 } else {
176 	    switch ( *(--pt) ) {
177 	     case '1':
178 	       handles |= 0x01;
179 	       break;
180 	     case '2':
181 	       handles |= 0x02;
182 	       break;
183 	     case '&':
184 	       handles |= 0x03;
185 	       break;
186 	    }
187 	 }
188 	 (*argv)[count] = NULL;		/* remove from the list */
189 	 count++;			/* file name follows '>' */
190 	 if ( (*argv)[count] != NULL )
191 	   *fname = (*argv)[count];
192       }
193    }
194    if ((*fname == NULL) || (**fname == '\0' ))
195      handles = 0x00;		/* don't redirect if there is no name */
196 
197    return handles;
198 }
199 
200 
201 /* ///////////////////////////////////////////////////////////////////
202 //  Function:   int sys_System(char *command_line);
203 //
204 //  Descript:	shell wrapper that understands some common redirection syntax
205 //		command args  > filename		; stdout
206 //		command args 1> filename		; stdout
207 //		command args 2> filename		; stderr
208 //		command args &> filename		; stdout+stderr
209 //		command args  > filename 2>&1		; stdout+stderr
210 //
211 // additionally, if command is prefixed by a '!', then the command is
212 // spawned directly without invoking the shell
213 //
214 //  Returns:	returns error codes as per spawn*()
215 //
216 //  Caveat:	requires spaces to separate each argument
217 //		ie., command args>filename	will NOT work
218 ///////////////////////////////////////////////////////////////////// */
219 
220 static int execute_the_command (char **, int, char *);
221 
222 int
sys_System(char * command_line1)223 sys_System(char *command_line1)
224 {
225    int ret = -1, handles, argc = 0;
226    char *fname = NULL, **argv = NULL, *command_line;
227 
228    if (NULL == (command_line = SLmake_string (command_line1)))
229      return -1;
230 
231    handles = parse_command_line( &argc, &argv, &fname, command_line );
232    /* Note: The argc that is passed bacl has nothing to do with the
233     * actual number of arguments in argv if there are redirections involved.
234     * However, if it is non-zero then argv was malloced.
235     */
236    if (argc)
237      {
238 	ret = execute_the_command (argv, handles, fname);
239 	SLfree((char *)argv);
240      }
241 
242    SLfree (command_line);
243    return ret;
244 }
245 
246 
sys_suspend(void)247 void sys_suspend(void)
248 {
249    sys_System( "" );
250 }
251 
252 
execute_the_command(char ** argv,int handles,char * file)253 static int execute_the_command (char **argv, int handles, char *file)
254 {
255    int ret = 0;
256    int fd1 = -1, fd2 = -1;
257    int fd_err = -1, fd_out = -1;
258 
259 
260    if (handles & 1)
261      {
262 	/* save stdout file handle */
263 	fd1 = dup (fileno (stdout));
264 
265 	if (fd1 == -1)
266 	  {
267 	     msg_error ("Unable to dup stdout");
268 	     return -1;
269 	  }
270 
271 	fd_out = open (file,
272 		       O_CREAT | O_TRUNC | O_TEXT | O_WRONLY | O_APPEND,
273 		       S_IREAD | S_IWRITE);
274 
275 	if ((fd_out == -1) || (-1 == dup2 (fd_out, fileno (stdout))))
276 	  {
277 	     msg_error ("Unable to redirect stdout!");
278 	     ret = -1;
279 	  }
280      }
281 
282    if (handles & 0x2)		       /* stderr */
283      {
284 	/* save stderr file handle */
285 	fd2 = dup (fileno (stderr));
286 
287 	if (fd2 == -1)
288 	  {
289 	     msg_error ("Unable to dup stderr");
290 	     return -1;
291 	  }
292 
293 	if (fd_out == -1)
294 	  {
295 	     fd_err = open (file,
296 			    O_CREAT | O_TRUNC | O_TEXT | O_RDWR | O_APPEND,
297 			    S_IREAD | S_IWRITE);
298 	  }
299 	else fd_err = fd_out;
300 
301 	if ((fd_err == -1) || (-1 == dup2 (fd_err, fileno (stderr))))
302 	  {
303 	     msg_error ("Unable to redirect stderr!");
304 	     ret = -1;
305 	  }
306      }
307 
308    if (fd_out != -1) close (fd_out);
309    if ((fd_err != -1) && (fd_err != fd_out)) close (fd_err);
310 
311 
312    if (ret == 0)
313      {
314 	ret = spawnvp(P_WAIT, argv[0], (void *) argv);
315 
316 	if (-1 == ret )
317 	  {
318 	     switch(errno)
319 	       {
320 		case ENOENT:
321 		  if (handles & DIRECT_SPAWN ) msg_error("Command not found.");
322 		  else msg_error("Shell not found.");
323 		  break;
324 		case ENOMEM:
325 		  msg_error("Insufficient Memory.");
326 		  break;
327 		default:
328 		  msg_error("Unknown Error.");
329 	       }
330 	  }
331      }
332 
333    if (fd1 != -1)
334      {
335 	if (-1 == dup2 (fd1, fileno (stdout)))
336 	  {
337 	     msg_error ("Unable to reattach stdout");
338 	  }
339 	close (fd1);
340      }
341 
342    if (fd2 != -1)
343      {
344 	if (-1 == dup2 (fd2, fileno (stderr)))
345 	  {
346 	     msg_error ("Unable to reattach stderr");
347 	  }
348 	close (fd2);
349      }
350 
351    return ret;
352 }
353 
354 #endif	/* whole file */
355