1 /* $Id: xsystem.c,v 1.13 1992/02/24 06:59:13 serow Exp serow $
2  *	like system("cmd") but return with exit code of "cmd"
3  *	for Turbo-C/MS-C/LSI-C
4  *  This code is in the public domain.
5  *
6  * $Log: xsystem.c,v $
7  * Revision 1.13  1992/02/24  06:59:13  serow
8  * *** empty log message ***
9  *
10  * Revision 1.12  1991/04/09  08:48:20  serow
11  * ignore new line at command line tail
12  *
13  * Revision 1.11  1991/03/12  07:12:50  serow
14  * CMDLINE
15  *
16  * Revision 1.10  91/02/24  05:10:14  serow
17  * 2>&1
18  *
19  * Revision 1.9  91/02/22  07:01:17  serow
20  * NEAR for ms-c
21  *
22  */
23 /* modified for djgpp v2.01 1997.1.29 by K.Okabe */
24 /* Last modified 2000.1.29 by K.Okabe */
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <fcntl.h>
29 #include <io.h>
30 #include <process.h>
31 #include <dos.h>
32 /* patch 1997.1.27 by K.Okabe */
33 #include <limits.h>
34 #include <errno.h>
35 #ifdef __GO32__
36 #include <dpmi.h>
37 #include <go32.h>
38 #include <sys/farptr.h>
39 #include <unistd.h>
40 #endif
41 /* end of patch */
42 /* patch 1998.8.4 by K.Okabe */
43 #ifdef WIN32
44 #include <mbctype.h>
45 #endif
46 /* end of patch */
47 
48 
49 #ifndef USECMDLINE
50 #define USECMDLINE	0
51 #endif
52 
53 /* patch 1997.1.27 by K.Okabe */
54 #ifndef PATH_MAX
55 #define PATH_MAX 128
56 #endif
57 /* end of patch */
58 
59 extern char *mktemp(char *);
60 
61 #define UCH(c)   ((unsigned char)(c))
62 #if 1 /* patch 1997.1.28 by K.Okabe */
63 #define isk1(c)  dbcs_bitset_member(UCH(c))
64 #else
65 #define isk1(c)  ((0x81<=UCH(c)&&UCH(c)<=0x9F)||(0xE0<=UCH(c)&&UCH(c)<=0xFC))
66 #endif
67 #define isq(c)   ((c) == '"')
68 #define isspc(c) ((c) == ' ' || (c) == '\t')
69 #define issep(c) (isspc(c) || (c) == '"' || (c) == '\'' || (c) == '<' || (c) == '>' || (c) == '\0')
70 #define issep2(c) (issep(c) || (c) == '.' || (c) == '\\' || (c) == '/')
71 #define isdeg(c) ('0' <= (c) && (c) <= '9')
72 
73 #if (defined (_MSC_VER) || defined (__TURBOC__)) && !defined (WIN32)
74 /* MS-C */
75 #define NEAR	_near
76 #else
77 #define NEAR
78 #endif
79 
80 /* patch 1997.4.2 by K.Okabe */
81 #if defined (GAWK) && !defined (__GO32__) && !defined(WIN32)
82 extern int os_open (const char *, int, ...);
83 #define open os_open
84 #endif
85 /* end of patch */
86 
87 /* patch 1997.1.27 by K.Okabe */
88 #ifdef __GNUC__
89 #define ALLOCA(n) __builtin_alloca((n))
90 #define FREE(p)
91 #else
92 #define ALLOCA(n) xmalloc((n))
93 #define FREE(p) free((p))
94 #endif
95 
96 #if defined(DJGPP) && ((DJGPP > 2) || (DJGPP == 2 && DJGPP_MINOR >= 1))
97 #define SPAWN(cmd,arg) djgpp201_spawn((cmd), (arg))
98 #define CMDLEN_LIMIT 125
99 
100 extern char **environ;
101 
102 static int NEAR
djgpp201_spawn(const char * cmd,const char * arg)103 djgpp201_spawn(const char *cmd, const char *arg)
104 {
105     if (strlen(arg) > CMDLEN_LIMIT) {
106 	errno = E2BIG;
107 	return -1;
108     }
109     return _dos_exec(cmd, arg, environ);
110 }
111 #else
112 #define SPAWN(cmd,arg) spawnl(P_WAIT, (cmd), (cmd), (arg), (char *) 0)
113 #endif
114 
115 #if defined(DJGPP) && DJGPP >= 2
116 #define REGS __dpmi_regs
117 #define INTDOS(regs) __dpmi_int(0x21, &(regs))
118 #define INTDOSX(regs,segs) __dpmi_int(0x21, &(regs))
119 #else
120 #define REGS union REGS
121 #define INTDOS(regs) intdos(&(regs), &(regs))
122 #define INTDOSX(regs,segs) intdosx(&(regs), &(regs), &(segs))
123 #endif
124 #ifdef __GO32__
125 #define OFFSET unsigned
126 #define MAKE_OFFSET(seg,off) ((OFFSET) (((seg) << 4) + (off)))
127 #define PEEKB(off) _farpeekb(_go32_info_block.selector_for_linear_memory, (off))
128 #else
129 #define OFFSET unsigned char far *
130 #define MAKE_OFFSET(seg,off) \
131   ((OFFSET) (((unsigned long) ((seg) + ((unsigned) (off) >> 4)) << 16) | (unsigned) ((off) & 15)))
132 #define PEEKB(off) (*(off))
133 #endif
134 
135 #define CHARBITS 8
136 
137 #define dbcs_bitset_access(n,op) \
138   (dbcs_table[(unsigned) (n) / CHARBITS] op (1 << ((n) & (CHARBITS - 1))))
139 
140 #define dbcs_bitset_member(n) dbcs_bitset_access(n, &)
141 #define dbcs_bitset_enjoin(n) dbcs_bitset_access(n, |=)
142 
143 static unsigned char dbcs_table[(1 << CHARBITS) / CHARBITS];
144 
145 static void NEAR
init_dbcs()146 init_dbcs()
147 {
148 /* patch 1998.8.5 by K.Okabe */
149 #if defined(WIN32)
150     int c;
151 
152     static int done = 0;
153 
154     if (done)
155 	return;
156 
157     done = 1;
158     memset(dbcs_table, 0, sizeof(dbcs_table));
159     for (c = 0; c < 256; c++)
160 	if (_ismbblead(c))
161 	    dbcs_bitset_enjoin(c);
162 #else
163 /* end of patch */
164 #if defined(DJGPP) && DJGPP >= 2
165 #define SEG_DS regs.x.ds
166 #else
167 #define SEG_DS segs.ds
168     struct SREGS segs;
169 #endif
170     REGS regs;
171     OFFSET offset;
172 
173     static int done = 0;
174 
175     if (done)
176 	return;
177 
178     done = 1;
179     memset(dbcs_table, 0, sizeof(dbcs_table));
180     SEG_DS = regs.x.si = 0;
181     regs.x.ax = 0x6300;
182     INTDOSX(regs, segs);
183     offset = MAKE_OFFSET(SEG_DS, regs.x.si);
184     if (offset == (OFFSET) 0)
185 	return;
186 
187     for (;;) {
188 	int lo, hi, c;
189 
190 	lo = (unsigned char) PEEKB(offset);
191 	offset++;
192 	hi = (unsigned char) PEEKB(offset);
193 	offset++;
194 	if (lo == 0 && hi == 0)
195 	    break;
196 
197 	for (c = lo; c <= hi; c++)
198 	    dbcs_bitset_enjoin(c);
199     }
200 #endif
201 }
202 /* end of patch */
203 
204 typedef struct _proc {
205     struct _proc *next;
206     char *line;
207     char *cmd;
208     char *arg;
209     char *inf;
210     int infmod;
211     char *outf;
212     int outfmod;
213     /* patch 1997.1.27 by K.Okabe */
214     char *errf;
215     int errfmod;
216     /* end of patch */
217     int ored[10];
218     int sred[10];
219 } PRO;
220 
221 static PRO *p1 = 0;
222 
223 static char *NEAR
xmalloc(size_t n)224 xmalloc(size_t n)
225 {
226     char *bp;
227 
228     if ((bp = calloc(1, n)) == (char *) 0) {
229 	write(2, "xsystem: Out of memory.!\n", 25);
230 	exit(1);
231     }
232     return bp;
233 }
234 
235 static char *NEAR
xrealloc(void * p,size_t n)236 xrealloc(void *p, size_t n)
237 {
238     char *bp;
239 
240     if ((bp = realloc(p, n)) == (char *) 0) {
241 	write(2, "xsystem: Out of memory!.\n", 25);
242 	exit(1);
243     }
244     return bp;
245 }
246 
247 static int NEAR
iscommandcommand(char * s)248 iscommandcommand(char *s)
249 {
250     static char *cmdtab[]=
251     {
252 	"dir", "type", "rem", "ren", "rename", "erase", "del",
253 	"copy", "pause", "date", "time", "ver", "vol",
254 	"cd", "chdir", "md", "mkdir", "rd", "rmdir", "break",
255 	"verify", "set", "prompt", "path", "exit", "ctty", "echo",
256 	"if", "for", "cls", "goto", "shift"
257     };
258     int i, l, lc;
259 
260     l = strlen(s);
261     for (i = 0; i < sizeof(cmdtab) / sizeof(cmdtab[0]); i++) {
262 	if (stricmp(s, cmdtab[i]) == 0)
263 	    return 1;
264 	lc = strlen(cmdtab[i]);
265 	if (lc < l && strnicmp(s, cmdtab[i], lc) == 0 && issep2(s[lc]))
266 	    return 1;
267     }
268     return 0;
269 }
270 
271 static int NEAR
getswchar(void)272 getswchar(void)
273 {
274 #ifdef WIN32
275     return '/';
276 #else
277     REGS reg;
278 
279     reg.x.ax = 0x3700;
280     INTDOS(reg);
281     return reg.h.dl;
282 #endif
283 }
284 
285 static int NEAR
csystem(PRO * p)286 csystem(PRO * p)
287 {
288     char *cmp;
289     char SW[3];
290     int rc;
291 
292 #ifdef GAWK /* patch 1997.1.27 by K.Okabe */
293     cmp = getenv("SHELL");
294     if (! cmp)
295 	cmp = getenv("COMSPEC");
296     if (! cmp)
297 	return -2;
298 #else
299     if ((cmp = getenv("COMSPEC")) == 0)
300 	return -2;
301 #endif
302     SW[0] = getswchar();
303     SW[1] = 'c';
304     SW[2] = 0;
305 #if 1 /* patch 1997.1.27 by K.Okabe */
306     {
307 	char *cmdline = (char *) ALLOCA(strlen(p->cmd) + strlen(p->arg) + 4);
308 	if (strpbrk(p->cmd, "\t ")) {
309 	    cmdline[0] = '"';
310 	    strcat(strcpy(cmdline + 1, p->cmd), "\"");
311 	} else
312 	    strcpy(cmdline, p->cmd);
313 	strcat(strcat(cmdline, " "), p->arg);
314 	rc = spawnl(P_WAIT, cmp, cmp, SW, cmdline, (char *) 0);
315 	FREE(cmdline);
316     }
317 #else
318     rc = spawnl(P_WAIT, cmp, cmp, SW, p->cmd, p->arg, (char *) 0);
319 #endif
320     return rc < 0 ? -2 : rc;
321 }
322 
323 static PRO *NEAR
pars1c(char * s)324 pars1c(char *s)
325 {
326     PRO *pp;
327     char *fnp;
328     int ms, mi;
329     int fs, fi, inpf;
330     int q;
331 
332     pp = (PRO *) xmalloc(sizeof(PRO));
333     for (q = 0; q < sizeof(pp->ored) / sizeof(pp->ored[0]); q++)
334 	pp->ored[q] = q;
335     while (isspc(*s))
336 	s++;
337     pp->line = strdup(s);
338     pp->cmd = xmalloc(ms = 8);
339     mi = 0;
340 #if 1 /* patch 1997.1.28 by K.Okabe */
341     if ((q = *s == '"'))
342 	s++;
343     while (q ? *s != '"' && *s != '\0' : ! issep(*s)) {
344 	if (mi >= ms - 1)
345 	    pp->cmd = xrealloc(pp->cmd, ms += 8);
346 	pp->cmd[mi++] = *s++;
347     }
348     if (q && *s == '"')
349 	s++;
350 #else
351     while (!issep(*s)) {
352 	if (mi >= ms - 1)
353 	    pp->cmd = xrealloc(pp->cmd, ms += 8);
354 	pp->cmd[mi++] = *s++;
355     }
356 #endif
357     pp->cmd[mi] = '\0';
358     q = 0;
359     pp->arg = xmalloc(ms = 32);
360     if (isspc(*s))
361 	s++;
362     mi = 0;
363     while (*s) {
364 	if (mi >= ms - 1) {
365 	    pp->arg = xrealloc(pp->arg, ms += 32);
366 	}
367 	if (q == 0) {
368 	    /* patch 1997.1.28 by K.Okabe */
369 	    int errf = 0;
370 	    /* end of patch */
371 	    inpf = 0;
372 	    if ((mi == 0 || isspc(s[-1])) &&
373 		isdeg(s[0]) && s[1] == '>' &&
374 		s[2] == '&' && isdeg(s[3])) {
375 
376 		pp->ored[s[0] & 15] = s[3] & 15;
377 		s += 4;
378 		continue;
379 	    } else if (s[0] == '<') {
380 		if (pp->inf == 0) {
381 		    pp->infmod = O_RDONLY;
382 		}
383 		inpf = 1;
384 	    } else if (s[0] == '>' && s[1] == '>') {
385 		if (pp->outf == 0) {
386 		    pp->outfmod = O_WRONLY | O_CREAT | O_APPEND;
387 		}
388 		s++;
389 	    } else if (s[0] == '>') {
390 		if (pp->outf == 0) {
391 		    pp->outfmod = O_WRONLY | O_CREAT | O_TRUNC;
392 		}
393 	    /* patch 1997.1.28 by K.Okabe */
394 	    } else if ((mi == 0 || isspc(s[-1])) && s[0] == '1' && s[1] == '>') {
395 		if (s[2] == '>') {
396 		    if (pp->outf == 0) {
397 			pp->outfmod = O_WRONLY | O_CREAT | O_APPEND;
398 		    }
399 		    s += 2;
400 		} else {
401 		    if (pp->outf == 0) {
402 			pp->outfmod = O_WRONLY | O_CREAT | O_TRUNC;
403 		    }
404 		    s++;
405 		}
406 	    } else if ((mi == 0 || isspc(s[-1])) && s[0] == '2' && s[1] == '>') {
407 		if (s[2] == '>') {
408 		    if (pp->errf == 0) {
409 			pp->errfmod = O_WRONLY | O_CREAT | O_APPEND;
410 		    }
411 		    s += 2;
412 		} else {
413 		    if (pp->errf == 0) {
414 			pp->errfmod = O_WRONLY | O_CREAT | O_TRUNC;
415 		    }
416 		    s++;
417 		}
418 		errf = 1;
419 	    /* end of patch */
420 	    } else {
421 		if (*s == '"')
422 		    q = !q;
423 		pp->arg[mi++] = *s++;
424 		continue;
425 	    }
426 	    fnp = xmalloc(fs = 16);
427 	    fi = 0;
428 	    s++;
429 	    while (isspc(*s))
430 		s++;
431 	    while (!issep(*s)) {
432 		if (fi >= fs - 1)
433 		    fnp = xrealloc(fnp, fs += 16);
434 		fnp[fi++] = *s++;
435 	    }
436 	    fnp[fi] = 0;
437 	    if (inpf) {
438 		if (pp->inf == 0)
439 		    pp->inf = fnp;
440 	    /* patch 1997.1.28 by K.Okabe */
441 	    } else if (errf) {
442 		if (pp->errf == 0)
443 		    pp->errf = fnp;
444 	    /* end of patch */
445 	    } else {
446 		if (pp->outf == 0)
447 		    pp->outf = fnp;
448 	    }
449 	} else if (s[0] == '"') {
450 	    q = !q;
451 	    pp->arg[mi++] = *s++;
452 	} else {
453 	    pp->arg[mi++] = *s++;
454 	}
455     }
456     /* patch 1997.1.28 by K.Okabe */
457     while (mi > 0 && isspc(pp->arg[mi - 1]))
458 	mi--;
459     /* end of patch */
460     pp->arg[mi] = '\0';
461     return pp;
462 }
463 
464 static PRO *NEAR
pars(char * s)465 pars(char *s)
466 {
467     char *lb;
468     int li, ls, q;
469     int c;
470     PRO *pp;
471 
472     lb = xmalloc(ls = 128);	/* about */
473     li = q = 0;
474     p1 = 0;
475 
476     for (;;) {
477 	c = *s++;
478 	if (li >= ls - 3)
479 	    lb = xrealloc(lb, ls += 128);
480 	if (isk1(c) && *s) {
481 	    lb[li++] = c;
482 	    lb[li++] = *s++;
483 	} else if ((!q && c == '|') || c == '\0' || (c == '\n' && *s == '\0')) {
484 	    lb[li++] = '\0';
485 	    if (p1 == 0) {
486 		pp = p1 = pars1c(lb);
487 	    } else {
488 		pp->next = pars1c(lb);
489 		pp = pp->next;
490 	    }
491 	    li = 0;
492 	    if (c == '\0' || (c == '\n' && *s == '\0'))
493 		break;
494 #if 0 /* patch 1997.1.27 by K.Okabe */
495 	} else if (c == '\\') {
496 	    lb[li++] = c;
497 	    if (*s) {
498 		if (isk1(*s))
499 		    lb[li++] = *s++;
500 		lb[li++] = *s++;
501 	    }
502 #endif
503 	} else if (c == '"') {
504 	    q = !q;
505 	    lb[li++] = c;
506 	} else {
507 	    lb[li++] = c;
508 	}
509     }
510     free(lb);
511     return p1;
512 }
513 
514 static int NEAR
try3(char * cnm,PRO * p)515 try3(char *cnm, PRO * p)
516 {
517     char cmdb[PATH_MAX];
518     int rc;
519 
520     strcat(strcpy(cmdb, cnm), ".com");
521     if ((rc = open(cmdb, O_RDONLY)) >= 0) {
522 	close(rc);
523 	return SPAWN(cmdb, p->arg);
524     }
525     strcat(strcpy(cmdb, cnm), ".exe");
526     if ((rc = open(cmdb, O_RDONLY)) >= 0) {
527 	close(rc);
528 	return SPAWN(cmdb, p->arg);
529     }
530     strcat(strcpy(cmdb, cnm), ".bat");
531     if ((rc = open(cmdb, O_RDONLY)) >= 0) {
532 	close(rc);
533 	return csystem(p);
534     }
535     return -1;
536 }
537 
538 static int NEAR
pgo(PRO * p)539 pgo(PRO * p)
540 {
541     char *s;
542     char *extp = 0;
543     char cmdb[PATH_MAX];
544     char *ep;
545     int rc, lc;
546 
547     s = p->cmd + strlen(p->cmd) - 1;
548     while (p->cmd <= s && *s != '\\' && *s != '/' && *s != ':') {
549 	if (*s == '.')
550 	    extp = s;
551 	s--;
552     }
553     if (iscommandcommand(p->cmd) || (extp && stricmp(extp, ".bat") == 0))
554 	return csystem(p);
555 
556     if (s < p->cmd) {		/* cmd has no PATH nor Drive */
557 	ep = getenv("PATH");
558 	strcpy(cmdb, p->cmd);
559 	for (;;) {
560 	    if (extp) {		/* has extention */
561 		if ((rc = open(cmdb, O_RDONLY)) >= 0) {
562 		    close(rc);
563 		    rc = SPAWN(cmdb, p->arg);
564 		}
565 	    } else {
566 		rc = try3(cmdb, p);
567 	    }
568 	    if (rc >= 0)
569 		return rc;
570 
571 	    if (ep && *ep) {
572 		int i;
573 		for (i = 0; *ep != ';' && *ep != '\0'; ep++, i++)
574 		    lc = cmdb[i] = *ep;
575 		if (*ep == ';')
576 		    ep++;
577 		if (i > 0 && lc != ':' && lc != '\\' && lc != '/')
578 		    cmdb[i++] = '\\';
579 		cmdb[i] = 0;
580 		strcat(cmdb, p->cmd);
581 	    } else {
582 		if (rc == -2)
583 		    return rc;
584 		return -1;
585 	    }
586 	}
587     } else {			/* has PATH or Drive */
588 	if (extp) {		/* has extention */
589 	    if ((rc = open(p->cmd, O_RDONLY)) >= 0) {
590 		close(rc);
591 		return SPAWN(p->cmd, p->arg);
592 	    }
593 	    return -1;
594 	} else {
595 	    return try3(p->cmd, p);
596 	}
597     }
598 }
599 
600 static char *NEAR
tmpf(char * tp)601 tmpf(char *tp)
602 {
603     char tplate[PATH_MAX];
604     char *ev;
605     int i;
606 
607 #ifdef __GO32__
608     ev = getenv("TMPDIR");
609     if (! ev)
610         ev = getenv("TMP");
611 #else
612     ev = getenv("TMP");
613 #endif
614     if (ev != 0) {
615 	strcpy(tplate, ev);
616 	i = strlen(ev);
617 	if (i && ev[i - 1] != '\\' && ev[i - 1] != '/')
618 	    strcat(tplate, "\\");
619     } else {
620 	tplate[0] = 0;
621     }
622     strcat(tplate, tp);
623     return strdup(mktemp(tplate));
624 }
625 
626 static int NEAR
redopen(char * fn,int md,int sfd)627 redopen(char *fn, int md, int sfd)
628 {
629     int rc;
630     int fd;
631 
632     if ((fd = open(fn, md, 0666)) != -1) {
633 	if (md & O_APPEND)
634 	    lseek(fd, 0L, SEEK_END);
635 	rc = dup(sfd);
636 	if (fd != sfd) {
637 	    dup2(fd, sfd);
638 	    close(fd);
639 	}
640 	return rc;
641     }
642     return -1;
643 }
644 
645 static int NEAR
redclose(int fd,int sfd)646 redclose(int fd, int sfd)
647 {
648     if (fd != -1) {
649 	dup2(fd, sfd);
650 	close(fd);
651     }
652     return -1;
653 }
654 
655 static void NEAR
redswitch(PRO * p)656 redswitch(PRO * p)
657 {
658     int d;
659 
660     for (d = 0; d < sizeof(p->ored) / sizeof(p->ored[0]); d++) {
661 	if (d != p->ored[d]) {
662 	    p->sred[d] = dup(d);
663 	    dup2(p->ored[d], d);
664 	}
665     }
666 }
667 static void NEAR
redunswitch(PRO * p)668 redunswitch(PRO * p)
669 {
670     int d;
671 
672     for (d = 0; d < sizeof(p->ored) / sizeof(p->ored[0]); d++) {
673 	if (d != p->ored[d]) {
674 	    dup2(p->sred[d], d);
675 	    close(p->sred[d]);
676 	}
677     }
678 }
679 
680 /* patch 1997.1.31 by K.Okabe */
681 static int
is_unixy_shell(const char * shell)682 is_unixy_shell(const char *shell)
683 {
684     static const char *shells[] = {
685 	"SH",
686 	"SH16",
687 	"SH32",
688 	"KSH",
689 	"ZSH",
690 	"BASH",
691 	0
692     };
693     char shellexe[16];
694     const char *p;
695     int i;
696 
697     for (p = shell; *p != '\0'; p++)
698 	if (*p == ':' || *p == '/' || *p == '\\')
699 	    shell = p + 1;
700     for (i = 0; shells[i]; i++) {
701 	if (stricmp(shell, shells[i]) == 0)
702 	    return 1;
703 	strcpy(shellexe, shells[i]);
704 	strcat(shellexe, ".EXE");
705 	if (stricmp(shell, shellexe) == 0)
706 	  return 1;
707     }
708     return 0;
709 }
710 /* end of patch */
711 
712 int
xsystem(char * cmd)713 xsystem(char *cmd)
714 {
715     PRO *p, *pn;
716     char *pof, *pif, *pxf;
717     int psstdin, psstdout;
718     int rdstdin, rdstdout;
719     /* patch 1997.1.27 by K.Okabe */
720     int rdstderr;
721     /* end of patch */
722     int rc = 0;
723 #if USECMDLINE
724     static char *cmdline = 0;
725     char *oldcmdline;
726 #endif
727 
728 #if defined(GAWK) && defined(OS2) && (_MSC_VER != 510) /* patch 1997.2.20 by K.Okabe */
729     if (_osmode == OS2_MODE)
730 	return system(cmd);
731 #endif
732 
733     /* patch 1997.1.31 by K.Okabe */
734     {
735 	char *shell = (char *) 0;
736 #ifdef GAWK
737 	shell = getenv("AWKSHELL");
738 	if (! shell)
739 	    shell = getenv("SHELL");
740 #endif
741 	if (! shell)
742 	    shell = getenv("COMSPEC");
743 	if (shell && is_unixy_shell(shell)) {
744 #if defined(DJGPP) && ((DJGPP > 2) || (DJGPP == 2 && DJGPP_MINOR >= 1))
745 	    rc = spawnl(P_WAIT, shell, shell, "-c", cmd, (char *) 0);
746 #else
747 	    char *quoted_cmd, *p;
748 	    quoted_cmd = (char *) ALLOCA(strlen(cmd) * 2 + 3);
749 	    p = quoted_cmd;
750 	    *p++ = '"';
751 	    while (*cmd != '\0') {
752 		if (*cmd == '"')
753 		    *p++ = '\\';
754 		*p++ = *cmd++;
755 	    }
756 	    *p++ = '"';
757 	    *p = '\0';
758 	    rc = spawnl(P_WAIT, shell, shell, "-c", quoted_cmd, (char *) 0);
759 	    FREE(quoted_cmd);
760 #endif
761 	    return rc < 0 ? 0xff00 : (rc << 8) & 0xff00 ;
762 	}
763     }
764     init_dbcs();
765     /* end of patch */
766 
767     pof = pif = pxf = 0;
768     p = pars(cmd);
769     pof = tmpf("p1XXXXXX");
770     pif = tmpf("p2XXXXXX");
771     psstdin = psstdout = rdstdin = rdstdout = -1;
772     /* patch 1997.1.27 by K.Okabe */
773     rdstderr = -1;
774     /* end of patch */
775     while (p) {
776 #if USECMDLINE
777 	if (!getenv("NOCMDLINE")) {
778 	    oldcmdline = cmdline;
779 	    cmdline = xmalloc(strlen(p->cmd) + strlen(p->arg) + 10);
780 	    strcat(strcat(strcat(strcpy(cmdline, "CMDLINE="), p->cmd), " "), p->arg);
781 	    putenv(cmdline);
782 	    if (oldcmdline)
783 		free(oldcmdline);
784 	}
785 #endif
786 	if (p->next)
787 	    psstdout = redopen(pof, O_WRONLY | O_CREAT | O_TRUNC, 1);
788 	if (p->inf)
789 	    rdstdin = redopen(p->inf, p->infmod, 0);
790 	if (p->outf)
791 	    rdstdout = redopen(p->outf, p->outfmod, 1);
792 	/* patch 1997.1.27 by K.Okabe */
793 	if (p->errf)
794 	    rdstderr = redopen(p->errf, p->errfmod, 2);
795 	/* end of patch */
796 	redswitch(p);
797 	rc = pgo(p);
798 	redunswitch(p);
799 	rdstdin = redclose(rdstdin, 0);
800 	rdstdout = redclose(rdstdout, 1);
801 	/* patch 1997.1.27 by K.Okabe */
802 	rdstderr = redclose(rdstderr, 2);
803 	/* end of patch */
804 	psstdout = redclose(psstdout, 1);
805 	psstdin = redclose(psstdin, 0);
806 	if ((p = p->next) != 0) {
807 	    pxf = pif;
808 	    pif = pof;
809 	    pof = pxf;
810 	    psstdin = redopen(pif, O_RDONLY, 0);
811 	}
812     }
813     unlink(pif);
814     free(pif);
815     unlink(pof);
816     free(pof);
817     for (pn = p = p1; p; p = pn) {
818 	pn = p->next;
819 	if (p->line)
820 	    free(p->line);
821 	if (p->cmd)
822 	    free(p->cmd);
823 	if (p->arg)
824 	    free(p->arg);
825 	if (p->inf)
826 	    free(p->inf);
827 	if (p->outf)
828 	    free(p->outf);
829 	free(p);
830     }
831     if (rc == -2)
832 	return 127;
833     return rc < 0 ? 0xFF00 : (rc << 8) & 0xFF00;
834 }
835 
836 #ifdef TEST
837 #include <stdio.h>
838 
839 void
main()840 main()
841 {
842     char lb[128];
843     while (gets(lb)) {
844 	printf("\nreturn %04X\n", xsystem(lb));
845     }
846 }
847 #endif	/* TEST */
848