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