1/* execdos.c */
2/*****************************************************************************
3					�s�������@�o�����������������@�w�s�q
4
5							�mDOS�R�}���h���s�n
6*****************************************************************************/
7
8#include "xtr.h"
9
10#if defined(__TURBOC__) && __TURBOC__ > 0x0200
11	/* Turbo C++ 1.0, Borland C++ 2.0 �� putenv �́A���̃}�j���A���̋L�q�ɂ�
12	   �����āAputenv �֐����� strdup �ɂ���Ĉ�����������R�s�[����������
13	   environ �ɓo�^���Ă���̂� */
14 #define PutEnv(env)		putenv(env)
15#else
16 #define PutEnv(env)		putenv(DupStr(env))
17#endif
18
19
20static uchar *
21MakeTemp(uchar *buf)
22{
23#if MSDOS || WINNT
24#define TEMPLATE "X$XXXXXX"
25#else
26#define TEMPLATE "xtrXXXXXX"
27#endif
28
29	static const uchar templet[] = TEMPLATE;
30	if (tmppath) {			/* �‹��ϐ� TMP ������� */
31		strcpy((char *)buf, (char *)tmppath);
32		PathCat(buf, templet);
33	} else {
34		strcpy((char *)buf, (const char *)templet);
35	}
36#if __human68k__
37	{
38#if DIRECT_SH
39		extern char *_toslash();
40		_toslash(buf);
41#else /* !DIRECT_SH */
42		extern char *_toslash(), *_tobslash();
43		uchar *shell, *shelltype;
44		enum {
45			SHTYPE_COMMAND,
46			SHTYPE_UNIX,
47			SHTYPE_UNKNOWN
48		} shtype;
49
50		if ((shell = getenv("SYSTEM_SHELL")) != NULL) {
51			shelltype = getenv("SYSTEM_SHELLTYPE");
52		} else {
53			shell = getenv("SHELL");
54			shelltype = getenv("SHELLTYPE");
55		}
56
57		if (shelltype) {
58			if (stricmp(shelltype, "COMMAND") == 0)
59				shtype = SHTYPE_COMMAND;
60			else if (stricmp(shelltype, "UNIX") == 0)
61				shtype = SHTYPE_UNIX;
62			else
63				shtype = SHTYPE_UNKNOWN;
64		} else {
65			if (shell) {
66				int len = strlen(shell);
67				if ((len >= 7 && stricmp(shell + len - 7, "command") == 0) ||
68				    (len >= 9 && stricmp(shell + len - 9, "command.x") == 0))
69					shtype = SHTYPE_COMMAND;
70				else
71					shtype = SHTYPE_UNIX;
72			} else {
73				shtype = SHTYPE_COMMAND;
74			}
75		}
76
77		switch (shtype) {
78		case SHTYPE_COMMAND:
79			_tobslash(buf);
80			break;
81		case SHTYPE_UNIX:
82		case SHTYPE_UNKNOWN:
83		default:
84			_toslash(buf);
85			break;
86		}
87#endif /* !DIRECT_SH */
88	}
89#endif /* __human68k__ */
90	return (uchar *)mktemp((char *)buf);
91}
92
93#if DIRECT_SH
94#if UNIX
95
96#ifndef FILENAME_MAX
97#define FILENAME_MAX 1024
98#endif
99
100#if !HAVE_PUTENV
101extern int putenv ARGS((const char *));
102#endif
103extern void include_fd ARGS((int));
104static int open_file ARGS((const uchar *, int));
105static int exec_and_include ARGS((int, const uchar *cmd));
106static void write_here_doc ARGS((int));
107static const uchar *copy_filename ARGS((uchar *, const uchar *));
108static int simple_output ARGS((const uchar *, int, int));
109static int simple_include ARGS((const uchar *, int, int));
110static int cmd_exec ARGS((const uchar *, int));
111
112#if !HAVE_DUP2
113int
114dup2(int old_fd, int new_fd)
115{
116	close(new_fd);
117	return dup(old_fd) != new_fd ? -1 : 0 ;
118}
119#endif
120
121#define READ_MODE 0
122#define CREATE_MODE 1
123#define APPEND_MODE 2
124
125static int
126open_file(const uchar *fname, int mode)
127{
128	uchar *fn, *errmsg;
129	int open_mode;
130	int fd;
131
132	if (fname == NULL || fname[0] == '\0') {
133		errmsg = "Can't create temporary file.";
134		fn = (uchar *)alloca(FILENAME_MAX);
135		if (!MakeTemp(fn))
136			Error(errmsg);
137	} else {
138		errmsg = "Can't create file: %s";
139		fn = (uchar *)fname;
140	}
141
142	if (mode == 0)
143		open_mode = O_RDONLY;
144	else if (mode == 1)
145		open_mode = O_RDWR | O_CREAT | O_TRUNC;
146	else
147		open_mode = O_WRONLY | O_CREAT | O_APPEND;
148
149	if ((fd = open((char *)fn, open_mode, 0644)) < 0)
150		Error(errmsg, fn);
151
152	if (fname == NULL || fname[0] == '\0')
153		unlink((char *)fn);
154
155	return fd;
156}
157
158#ifdef SIGCHLD
159static RETSIGTYPE reap_children ARGS((int));
160static RETSIGTYPE
161reap_children(int sig)
162{
163	int status;
164	wait(&status);
165}
166#endif
167
168static int
169exec_and_include(int fd, const uchar *cmd)
170{
171	if (cmd[0] != '\0') {
172#ifdef __human68k__
173		uchar fname[FILENAME_MAX];
174		int save_fds[2];
175		int pipe_fd;
176
177		if (fd != 0) {
178			save_fds[0] = dup(0);
179			dup2(fd, 0);
180		}
181
182		MakeTemp(fname);
183		save_fds[1] = dup(1);
184		pipe_fd = open_file(fname, CREATE_MODE);
185		dup2(pipe_fd, 1);
186		close(pipe_fd);
187
188		spawnl(P_WAIT, "/bin/sh", "sh", "-c", cmd, (char *)NULL);
189
190		if (fd != 0) {
191			dup2(save_fds[0], 0);
192			close(save_fds[0]);
193			close(fd);
194		}
195
196		dup2(save_fds[1], 1);
197		close(save_fds[1]);
198
199		fd = open_file(fname, READ_MODE);
200		unlink(fname);
201#else /* !__human68k__ */
202		int pipefds[2];
203		pid_t child;
204
205		if (pipe(pipefds) < 0)
206			return 1;
207#ifdef SIGCHLD
208		signal(SIGCHLD, reap_children);
209#endif
210		if ((child = fork()) < 0)
211			return 1;
212
213		if (child == 0) {
214			if (fd != 0) {
215				dup2(fd, 0);
216				close(fd);
217			}
218			dup2(pipefds[1], 1);
219			close(pipefds[0]);
220			close(pipefds[1]);
221
222			execl("/bin/sh", "sh", "-c", cmd, (char *)NULL);
223
224			_exit(127);
225		}
226
227		if (fd != 0)
228			close(fd);
229		close(pipefds[1]);
230
231		fd = pipefds[0];
232#endif /* !__human68k__ */
233	}
234
235	if (fd != 0) {
236		int save_tmpincludeflag = tmpincludeflag;
237		tmpincludeflag = 1;
238		include_fd(fd);
239		tmpincludeflag = save_tmpincludeflag;
240	}
241
242	return 0;
243}
244
245static void
246write_here_doc(int fd)
247{
248	int len, n, buflen;
249	uchar *buf, *mbbuf;
250	int contlnflag;
251
252	contlnflag = 0;
253	while ((len = GetLine()) != 0) {
254		ILineNoCount();
255		if (contlnflag ||
256		    *ibuf == cmddot_mchar ||
257		    cmddot_char && *ibuf == cmddot_char) {
258			n = CommandLineEnd(ibuf + 1, contlnflag) - ibuf;
259			if (!contlnflag &&
260			    CheckBlockEnd(ibuf + 1, n - 1, contlnflag, (const uchar **)NULL))
261				break;
262			contlnflag = ibuf[n] == '\\';
263		}
264		buf = AEvalStringN(&buflen, ibuf, len);
265		mbbuf = (uchar *)alloca(buflen * 2 + 1);
266		sjis2mbstring((char *)mbbuf, (char *)buf);
267		write(fd, (char *)mbbuf, strlen((char *)mbbuf));
268		XFree((voidstar)buf);
269	}
270}
271
272static const uchar *
273copy_filename(uchar *dst, const uchar *src)
274{
275	int c;
276
277	while ((c = *src) != '\0' && !isspace(c)) {
278		*dst++ = c;
279		src++;
280	}
281	*dst = '\0';
282
283	return src;
284}
285
286/* !>ofile */
287/* !>ofile { */
288static int
289simple_output(const uchar *cmd, int block_mode, int open_mode)
290{
291	uchar fname[FILENAME_MAX];
292	int fd;
293
294	copy_filename(fname, SkipSpace(cmd + open_mode));
295	fd = open_file(fname, open_mode);
296	if (block_mode)
297		write_here_doc(fd);
298	close(fd);
299
300	return 0;
301}
302
303/* !<ifile >ofile */
304/* !<ifile */
305static int
306simple_include(const uchar *cmd, int block_mode, int open_mode)
307{
308	uchar src_fname[FILENAME_MAX];
309	const uchar *p;
310
311	p = copy_filename(src_fname, SkipSpace(cmd + open_mode));
312	p = SkipSpace(p);
313	if (*p == '>') {
314		uchar dst_fname[FILENAME_MAX];
315		char buffer[4096];
316		int read_fd, write_fd;
317		int n;
318
319		n = 0;
320		while (*p == '>') {
321			p++;
322			n++;
323		}
324		p = SkipSpace(p);
325		if (*p == '\0')
326			return 1;
327
328		copy_filename(dst_fname, p);
329
330		read_fd = open_file(src_fname, READ_MODE);
331		write_fd = open_file(dst_fname, n);
332#ifdef __human68k__
333		setmode(read_fd, O_BINARY);
334		setmode(write_fd, O_BINARY);
335#endif
336		while ((n = read(read_fd, buffer, sizeof(buffer))) > 0)
337			write(write_fd, buffer, n);
338		close(write_fd);
339		close(read_fd);
340	} else {
341		int save_tmpincludeflag = tmpincludeflag;
342		tmpincludeflag = 0;
343		Include(src_fname, 1);
344		tmpincludeflag = save_tmpincludeflag;
345	}
346
347	return 0;
348}
349
350/* !{ */
351/* ! cmd { */
352/* ! cmd >ofile { */
353/* ! */
354/* ! cmd */
355/* ! cmd >ofile */
356static int
357cmd_exec(const uchar *cmd, int block_mode)
358{
359	int ret = 0;
360	int fd = 0;
361	const uchar *p;
362	int c;
363
364	if (block_mode) {
365		fd = open_file((uchar *)NULL, CREATE_MODE);
366		write_here_doc(fd);
367		lseek(fd, (off_t)0, 0);
368	}
369
370	p = cmd;
371	while ((c = *p) != '\0' && c != '=' && !isspace(c))
372		p++;
373	if (c == '=') {
374		putenv((char *)cmd);
375	} else if (c != '\0' &&
376		   strnicmp("SET", (const char *)cmd, p - cmd) == 0 &&
377		   (p = SkipSpace(p)) != NULL &&
378		   *p != '\0') {
379		uchar *buf, *bp;
380
381		bp = buf = (uchar *)alloca(strlen((const char *)p) + 1);
382		while ((c = *p) != '\0' && c != '=' && !isspace(c))
383			*bp++ = c;
384		*bp++ = '=';
385		strcpy((char *)bp, (char *)(*p == '=' ? p + 1 : p));
386		putenv((char *)buf);
387	} else
388		ret = exec_and_include(fd, cmd);
389
390	return ret;
391}
392
393static void
394exec_sh_command(const uchar *src)
395{
396	int block_mode = 0;
397	int ret = 0;
398	int len, buflen, n;
399	uchar *buf, *cmd;
400
401	src = CutSpace(src);
402	len = strlen((const char *)src);
403	if (StrNthE(src, len - 1) == '{') {
404		block_mode = 1;
405		len--;
406	}
407
408	buf = AEvalStringN(&buflen, src, len);
409	cmd = SkipSpace(buf);
410
411	if ((n = strspn((char *)cmd, ">")) > 0) {
412		ret = simple_output(cmd, block_mode, n);
413	} else if ((n = strspn((char *)cmd, "<")) > 0) {
414		ret = simple_include(cmd, block_mode, n);
415	} else {
416		ret = cmd_exec(cmd, block_mode);
417	}
418
419	XFree((voidstar)buf);
420
421	buf = (uchar *)alloca(32);
422	WtNum(buf, ret);
423	SetRetValue(DupStr(buf), strlen((char *)buf));
424}
425#endif /* UNIX */
426#endif /* DIRECT_SH */
427
428void
429ExecDosCommand(const uchar *src)
430/* src: <dos-command-line> ['{']*/
431{
432#if UNIX && DIRECT_SH
433	exec_sh_command(src);
434#else /* !(UNIX && DIRECT_SH) */
435
436#ifndef FILENAME_MAX
437#if MSDOS || WINNT
438#define FILENAME_MAX 80
439#else
440#define FILENAME_MAX 1024
441#endif
442#endif
443	const uchar *srcp = CutSpace(src);
444	uchar fname1[FILENAME_MAX];
445	uchar fname2[FILENAME_MAX];
446	FILE  *fp = NULL;
447#if UNIX
448	uchar *cmdbuf;
449#else
450	uchar cmdbuf[160];
451#endif
452	uchar *vbuf = NULL;
453	uchar *cmdp;
454	uchar *p;
455	uchar *argp;
456	int   len;
457	int   ret = 0;
458	int   block_mode = 0;
459	int   output_include = 0;
460	int   simple_output = 0;
461	int   simple_include = 0;
462	int   void_cmd = 0;
463
464#if UNIX
465#define ALLOCA(p,n) p = (uchar *)alloca((n))
466	fname1[0] = fname2[0] = '\0';
467	cmdbuf = "";
468#else
469#define ALLOCA(p,n)
470	fname1[0] = fname2[0] = cmdbuf[0] = '\0';
471#endif
472
473	len = strlen((const char *)srcp);
474	if (StrNthE(srcp, len-1) == '{') {
475		block_mode = 1;
476		--len;
477	}
478	vbuf = AEvalStringN(&len, srcp, len);
479	cmdp = SkipSpace(vbuf);
480
481	if (!*cmdp) {
482		void_cmd = 1;
483	} else if (simple_output = strspn(cmdp, ">")) {
484		strcpy(fname1, SkipSpace(cmdp + simple_output));
485		if ((fp = fopen(fname1, simple_output == 1 ? WRITE_TEXT : APPEND_TEXT)) == NULL)
486			Error("Can't create file: %s", fname1);
487	} else if (simple_include = strspn(cmdp, "<")) {
488		strcpy(fname2, SkipSpace(cmdp + simple_include));
489	}
490	if (!simple_output && !(p = strrchr(cmdp, '>')) || strchr(p, '\"')) {
491		/* �o�̓��_�C���N�g�w��i>...�j������������o�͂���荞�ރ��[�h */
492		output_include = 1;
493	}
494
495	if (block_mode) {
496		/* �u���b�N���� */
497		int   contlnflag = 0;
498
499		if (!simple_output) {
500			if (!MakeTemp(fname1) ||
501				(fp = fopen(fname1, WRITE_TEXT)) == NULL ||
502				(output_include && !MakeTemp(fname2)))
503			Error("Can't create temporary file.");
504		}
505		if (output_include) {
506			if (void_cmd) {
507				/* !{ */
508				strcpy(fname2, fname1);
509			} else {
510				/* ! cmd { */
511				ALLOCA(cmdbuf,
512				       strlen(cmdp) + strlen(fname1) + strlen(fname2) + 5);
513				sprintf(cmdbuf, "%s <%s >%s", cmdp, fname1, fname2);
514			}
515		} else if (simple_output) {
516			/* !>ofile { */
517			;
518		} else {
519			/* ! cmd >ofile { */
520			ALLOCA(cmdbuf, strlen(cmdp) + strlen(fname1) + 3);
521			sprintf(cmdbuf, "%s <%s", cmdp, fname1);
522		}
523		for ( ; ; ) {
524			uchar *buf;
525
526			if (!(len = GetLine()))			/* �P�s�ǂ�� ibuf �Ɋi�[ */
527				break;						/* EOF �Ȃ�I�� */
528			ILineNoCount();
529			if (contlnflag || *ibuf==cmddot_mchar ||
530							cmddot_char && *ibuf==cmddot_char) {
531				int n = CommandLineEnd(ibuf+1, contlnflag) - ibuf;
532				if (!contlnflag &&
533						CheckBlockEnd(ibuf+1, n-1, contlnflag, (uchar **)NULL))
534					break;					/* ".}" �ŏI�� */
535				contlnflag = ibuf[n] == '\\';
536			}
537			buf = AEvalStringN(&len, ibuf, len);
538			fwrite(buf, 1, len, fp); 	/* �ǂ��s���t�@�C���ɏ��� */
539			XFree((voidstar)buf);
540		}
541
542	} else {
543		/* �u���b�N�Ȃ� */
544		if (output_include) {
545			if (void_cmd) {
546				/* ! */
547			} else if (simple_include) {
548				/* !<ifile */
549				;
550			} else {
551				/* ! cmd */
552				if (!MakeTemp(fname2))
553					Error("Can't create temporary file.");
554				ALLOCA(cmdbuf, strlen(cmdp) + strlen(fname2) + 3);
555				sprintf(cmdbuf, "%s >%s", cmdp, fname2);
556			}
557		} else if (simple_output) {
558			/* !>ofile */
559			;
560		} else if (simple_include) {
561			/* !<ifile >ofile */
562#if UNIX
563# if __human68k__
564#   define BINCAT "cat %s"
565# else
566#   define BINCAT "/bin/cat %s"
567# endif
568#else
569# define BINCAT "TYPE %s"
570#endif
571			ALLOCA(cmdbuf, strlen(cmdp + 1) + 10);
572			sprintf(cmdbuf, BINCAT, cmdp + 1);
573		} else {
574			/* ! cmd >ofile */
575			ALLOCA(cmdbuf, strlen(cmdp) + 1);
576			strcpy(cmdbuf, cmdp);
577		}
578	}
579	if (fp)
580		fclose(fp);
581
582	if (!simple_output) {
583		for (argp = cmdp; *argp && *argp != '=' && !isspace(*argp); argp++) ;
584		p = NULL;
585		if (*argp) {
586			if (*argp == '=') {		/* �‹��ϐ��ݒ� */
587				p = argp;
588				argp = cmdp;
589			} else {
590				*argp++ = '\0';
591				CutSpace(argp);
592			}
593		}
594		if (!cmdbuf[0]) {
595			;
596		} else if (p || !stricmp(cmdp, "SET") && (p = strchr(argp, '='))) {
597			/*
598			 * �‹��ϐ��̃Z�b�g
599			 *  envvar=value
600			 *  SET envvar=value
601			 */
602#ifndef UNIX
603			*p = '\0';
604			StrUpper(argp, argp);
605#endif
606			*p = '=';
607			PutEnv(argp);			/* SET�R�}���h�́A����ɕϊ� */
608			output_include = 0;
609		} else {
610			ret = system(cmdbuf);			/* DOS �R�}���h���s */
611		}
612		if (output_include &&
613				(simple_include || FileExists(fname2))) {
614			int tmpincludeflag0 = tmpincludeflag;
615			tmpincludeflag = !simple_include;
616			Include(fname2, 1);			/* �o�͂���荞�� */
617			if (!simple_include)
618				remove(fname2);				/* �e���|�����t�@�C�������� */
619			tmpincludeflag = tmpincludeflag0;
620		}
621		if (block_mode)
622			remove(fname1);
623	}
624	XFree((voidstar)vbuf);
625
626	/* ���^�[���R�[�h���Z�b�g */
627	ALLOCA(cmdbuf, 32);
628	WtNum(cmdbuf, ret);
629	vbuf = DupStr(cmdbuf);
630	SetRetValue(vbuf, strlen(vbuf));
631#endif /* !(UNIX && DIRECT_SH) */
632}
633
634/*
635 * Local variables:
636 * mode: c
637 * c-indent-level: 4
638 * c-continued-statement-offset: 4
639 * c-brace-offset: -4
640 * c-argdecl-indent: 4
641 * c-label-offset: -4
642 * tab-width: 4
643 * tab-stop-list: (4 8 12 16 20 24 28 32 36 40 44 48 52 56 60 64 68 72 76 80)
644 * End:
645 */
646