1 /*	FMRDOS.C:	Operating specific I/O and Spawning functions
2 			under the MSDOS/FMR operating system
3 			for MicroEMACS 4.00
4 			(C)Copyright 1995 by Daniel M. Lawrence
5 */
6 
7 #include        <stdio.h>
8 #include	"estruct.h"
9 #include	"eproto.h"
10 
11 #ifdef	MSDOS
12 #include        "edef.h"
13 #include	"elang.h"
14 
15 /* The Mouse driver only works with typeahead defined */
16 #if	MOUSE
17 #undef	TYPEAH
18 #define	TYPEAH	1
19 #endif
20 
21 #if  TURBO
22 #include <conio.h>
23 #include <dir.h>
24 #include <dos.h>
25 #include <bios.h>
26 
27 struct ffblk fileblock;	/* structure for directory searches */
28 #endif
29 #if	MSC | IC
30 #include <dos.h>
31 
32 struct find_t fileblock;	/* structure for directory searches */
33 #endif
34 
35 #if     LATTICE | MSC | TURBO | IC | MWC
36 union REGS rg;		/* cpu register for use of DOS calls */
37 struct SREGS segreg;	/* cpu segment registers	     */
38 int nxtchar = -1;	/* character held from type ahead    */
39 #endif
40 
41 #if	MSC | TURBO | IC
42 #include	<process.h>
43 #endif
44 
45 /*	Some global variable	*/
46 #define INBUFSIZ	40
47 static int mexist;	/* is the mouse driver installed? */
48 static int nbuttons;	/* number of buttons on the mouse */
49 static int oldbut;	/* Previous state of mouse buttons */
50 static int oldcol;	/* previous x position of mouse */
51 static int oldrow;	/* previous y position of mouse */
52 
53 PASCAL NEAR execprog(char *cmd);
54 
55 /*	input buffers and pointers	*/
56 
57 #define	IBUFSIZE	64	/* this must be a power of 2 */
58 
59 unsigned char in_buf[IBUFSIZE];	/* input character buffer */
60 int in_next = 0;		/* pos to retrieve next input character */
61 int in_last = 0;		/* pos to place most recent input character */
62 
in_init()63 in_init()	/* initialize the input buffer */
64 
65 {
66 	in_next = in_last = 0;
67 }
68 
in_check()69 in_check()	/* is the input buffer non-empty? */
70 
71 {
72 	if (in_next == in_last)
73 		return(FALSE);
74 	else
75 		return(TRUE);
76 }
77 
in_put(event)78 in_put(event)
79 
80 int event;	/* event to enter into the input buffer */
81 
82 {
83 	in_buf[in_last++] = event;
84 	in_last &= (IBUFSIZE - 1);
85 }
86 
in_get()87 int in_get()	/* get an event from the input buffer */
88 
89 {
90 	register int event;	/* event to return */
91 
92 	event = in_buf[in_next++];
93 	in_next &= (IBUFSIZE - 1);
94 	return(event);
95 }
96 
97 /*
98  * This function is called once to set up the terminal device streams.
99  */
100 
ttopen()101 PASCAL NEAR ttopen()
102 
103 {
104 #if	MOUSE
105 	long miaddr;	/* mouse interupt routine address */
106 #endif
107 	strcpy(os, "MSDOS");
108 
109 	/* on all screens we are not sure of the initial position
110 	   of the cursor					*/
111 	ttrow = 999;
112 	ttcol = 999;
113 
114 #if	MOUSE
115 	/* check if the mouse drive exists first */
116 	rg.x.ax = 0x3599;	/* look at the interrupt 99 address */
117 
118 #if	MSC | TURBO | IC | LATTICE | MWC
119 	int86x(0x21, &rg, &rg, &segreg);
120 	miaddr = (((long)segreg.es) << 16) + (long)rg.x.bx;
121 	if (miaddr == 0 || *(char * far)miaddr == 0xcf) {
122 #endif
123 		mexist = FALSE;
124 		return;
125 	}
126 
127 	/* and then check for the mouse itself */
128 	rg.x.ax = 0;		/* mouse status flag */
129 	int86(0x99, &rg, &rg);	/* check for the mouse interupt */
130 	mexist = (rg.x.ax == 0);
131 	nbuttons = 3;		/* it COULD have 3 buttons?? */
132 
133 	/* initialize our character input queue */
134 	in_init();
135 	if (mexist == FALSE)
136 		return;
137 
138 	/* if the mouse exists.. get it in the upper right corner */
139 	rg.h.ah = 4;		/* set mouse cursor position */
140 	oldcol = (term.t_ncol - 1);
141 	rg.x.dx = 559;		/* last col of display */
142 	oldrow = 0;
143 	rg.x.bx = oldrow;		/* top row */
144 	oldbut = 0;
145 	int86(0x99, &rg, &rg);
146 #else	/* !MOUSE */
147 	mexist = 0;
148 #endif	/* !MOUSE */
149 }
150 
maxlines(lines)151 maxlines(lines)		/* set number of vertical rows for mouse */
152 
153 int lines;	/* # of vertical lines */
154 
155 {
156 #if	MOUSE
157 	if (mexist) {
158 		/* nothing yet! */
159 	}
160 #endif
161 }
162 
163 /*
164  * This function gets called just before we go back home to the command
165  * interpreter. On VMS it puts the terminal back in a reasonable state.
166  * Another no-operation on CPM.
167  */
ttclose()168 PASCAL NEAR ttclose()
169 {
170 }
171 
172 /*
173  * Write a character to the display. On VMS, terminal output is buffered, and
174  * we just put the characters in the big array, after checking for overflow.
175  * On CPM terminal I/O unbuffered, so we just write the byte out. Ditto on
176  * MS-DOS (use the very very raw console output routine).
177  */
178 
ttputc(c)179 PASCAL NEAR ttputc(c)
180 
181 int c;
182 
183 {
184 #if     MWC
185         putcnb(c);
186 #endif
187 
188 #if	(LATTICE | TURBO | IC | MSC)
189 	bdos(6, c, 0);
190 #endif
191 }
192 
193 /*
194  * Flush terminal buffer. Does real work where the terminal output is buffered
195  * up. A no-operation on systems where byte at a time terminal I/O is done.
196  */
ttflush()197 PASCAL NEAR ttflush()
198 {
199 }
200 
doschar()201 int doschar()	/* call the dos to get a char */
202 
203 {
204 
205 	register unsigned int c;	/* extended character to return */
206 
207 	rg.h.ah = 7;		/* dos Direct Console Input call */
208 	intdos(&rg, &rg);
209 	return(rg.h.al & 255);
210 }
211 
212 /*
213  * Read a character from the terminal, performing no editing and doing no echo
214  * at all. Also mouse events are forced into the input stream here.
215  */
ttgetc()216 PASCAL NEAR ttgetc()
217 
218 {
219 	register int c;		/* character read */
220 
221 ttc:	/* return any keystrokes waiting in the
222 	   type ahead buffer */
223 	if (in_check())
224 		return(in_get());
225 
226 #if	TYPEAH
227 	if (typahead())
228 		return(doschar());
229 
230 	/* with no mouse, this is a simple get char routine */
231 	if (mexist == FALSE || mouseflag == FALSE)
232 		return(doschar());
233 
234 #if	MOUSE
235 	/* turn the mouse cursor on */
236 	rg.x.ax = 0x0200;	/* Show Cursor */
237 	int86(0x99, &rg, &rg);
238 
239 	/* loop waiting for something to happen */
240 	while (TRUE) {
241 		if (typahead())
242 			break;
243 		if (checkmouse())
244 			break;
245 	}
246 
247 	/* turn the mouse cursor back off */
248 	rg.x.ax = 0x0201;	/* erase Cursor */
249 	int86(0x99, &rg, &rg);
250 
251 	goto ttc;
252 #endif	/* MOUSE */
253 #else	/* TYPEAH */
254 	return(doschar());
255 #endif	/* TYPEAH */
256 }
257 
258 #if	MOUSE
checkmouse()259 checkmouse()
260 
261 {
262 	register int k;		/* current bit/button of mouse */
263 	register int etype;	/* event type byte */
264 	register int event;	/* encoded mouse event */
265 	int mousecol;		/* current mouse column */
266 	int mouserow;		/* current mouse row */
267 	int sstate;		/* current shift key status */
268 	int newbut;		/* new state of the mouse buttons */
269 
270 	/* check to see if any mouse buttons are different */
271 	rg.h.ah = 3;	/* Get button status and mouse position */
272 	int86(0x99, &rg, &rg);
273 	newbut   = rg.h.ch & 0x07;
274 	mousecol = rg.x.dx /14;
275 	mouserow = rg.x.bx /30;
276 
277 	/* only notice changes */
278 	if ((oldbut == newbut) && (mousecol == oldcol)
279 	    && (mouserow == oldrow))
280 		return(FALSE);
281 
282 	/* get the shift key status as well */
283 	etype = MOUS >> 8;
284 	sstate = 0;
285 	rg.h.ah = 8;	/* return current shift status */
286 	int86(0x90, &rg, &rg);
287 	sstate = rg.h.al;
288 	if (sstate & (4|32|64))		/* shifted? */
289 		etype |= (SHFT >> 8);
290 	if (sstate & 16)		/* controled? */
291 		etype |= (CTRL >> 8);
292 
293 	/* no buttons changes */
294 	if (oldbut == newbut) {
295 
296 		/* generate a mouse movement */
297 		if (((mouse_move == 1) && (mmove_flag == TRUE)) ||
298 		    (mouse_move == 2)) {
299 			in_put(0);
300 			in_put(etype);
301 			in_put(mousecol);
302 			in_put(mouserow);
303 			in_put('m');
304 		}
305 		oldcol = mousecol;
306 		oldrow = mouserow;
307 		return(TRUE);
308 	}
309 
310 	/* only on screen presses are legit! */
311 	if (mousecol < 0)
312 		mousecol = 0;
313 	if (mouserow < 0)
314 		mouserow = 0;
315 
316 	for (k=1; k != (1 << nbuttons); k = k<<1) {
317 
318 		/* For each button on the mouse */
319 		if ((oldbut&k) != (newbut&k)) {
320 
321 			/* This button changed, generate an event */
322 			in_put(0);
323 			in_put(etype);
324 			in_put(mousecol);
325 			in_put(mouserow);
326 
327 			event = ((newbut&k) ? 0 : 1);	/* up or down? */
328 			if (k == 2)			/* center button? */
329 				event += 4;
330 			if (k == 4)			/* right button? */
331 				event += 2;
332 			event += 'a';		/* plain */
333 			in_put(event);
334 			oldbut = newbut;
335 			oldcol = mousecol;
336 			oldrow = mouserow;
337 			return(TRUE);
338 		}
339 	}
340 	return(FALSE);
341 }
342 #endif
343 
344 #if	TYPEAH
345 /* typahead:	Check to see if any characters are already in the
346 		keyboard buffer
347 */
348 
typahead()349 PASCAL NEAR typahead()
350 
351 {
352 	int flags;	/* cpu flags from dos call */
353 
354 #if	TURBO | IC  /* This conditional portion added 9/13/89 by DRK. */
355 	if (bioskey(1) == 0)
356 		return FALSE;
357 	else
358 		return TRUE;
359 #else
360 	rg.x.ax = 0x4406;	/* IOCTL input status */
361 	rg.x.bx = 0;		/* File handle = stdin */
362 #if	MSC
363 	int86(0x21,&rg,&rg);
364 	flags = rg.h.al;
365 #else
366 #if	LATTICE | TURBO | IC
367 	flags = intdos(&rg, &rg);
368 #else
369 	intcall(&rg, &rg, 0x21);
370 	flags = rg.x.flags;
371 #endif
372 #endif
373 	if (flags & 1)		/* AL = 0xFF if ready */
374 		return(TRUE);
375 	else
376 		return(FALSE);
377 #endif
378 }
379 #endif
380 
381 /*
382  * Create a subjob with a copy of the command intrepreter in it. When the
383  * command interpreter exits, mark the screen as garbage so that you do a full
384  * repaint. Bound to "^X C".
385  */
386 
spawncli(f,n)387 PASCAL NEAR spawncli(f, n)
388 
389 int f, n;
390 
391 {
392 	/* don't allow this command if restricted */
393 	if (restflag)
394 		return(resterr());
395 
396         movecursor(term.t_nrow, 0);             /* Seek to last line.   */
397         TTflush();
398 	TTkclose();
399 	shellprog("");
400 	TTkopen();
401         sgarbf = TRUE;
402         return(TRUE);
403 }
404 
405 /*
406  * Run a one-liner in a subjob. When the command returns, wait for a single
407  * character to be typed, then mark the screen as garbage so a full repaint is
408  * done. Bound to "C-X !".
409  */
spawn(f,n)410 PASCAL NEAR spawn(f, n)
411 
412 int f, n;
413 
414 {
415         register int s;
416         char line[NLINE];
417 
418 	/* don't allow this command if restricted */
419 	if (restflag)
420 		return(resterr());
421 
422         if ((s=mlreply("!", line, NLINE)) != TRUE)
423                 return(s);
424 	movecursor(term.t_nrow - 1, 0);
425 	TTkclose();
426         shellprog(line);
427 	TTkopen();
428 	/* if we are interactive, pause here */
429 	if (clexec == FALSE) {
430 	        mlputs(TEXT6);
431 /*                     "\r\n\n[End]" */
432         	tgetc();
433         }
434         sgarbf = TRUE;
435         return (TRUE);
436 }
437 
438 /*
439  * Run an external program with arguments. When it returns, wait for a single
440  * character to be typed, then mark the screen as garbage so a full repaint is
441  * done. Bound to "C-X $".
442  */
443 
execprg(f,n)444 PASCAL NEAR execprg(f, n)
445 
446 {
447         register int s;
448         char line[NLINE];
449 
450 	/* don't allow this command if restricted */
451 	if (restflag)
452 		return(resterr());
453 
454         if ((s=mlreply("$", line, NLINE)) != TRUE)
455                 return(s);
456 	movecursor(term.t_nrow - 1, 0);
457 	TTkclose();
458         execprog(line);
459 	TTkopen();
460 	/* if we are interactive, pause here */
461 	if (clexec == FALSE) {
462 	        mlputs(TEXT6);
463 /*                     "\r\n\n[End]" */
464         	tgetc();
465         }
466         sgarbf = TRUE;
467         return (TRUE);
468 }
469 
470 /*
471  * Pipe a one line command into a window
472  * Bound to ^X @
473  */
pipecmd(f,n)474 PASCAL NEAR pipecmd(f, n)
475 
476 int f, n;
477 
478 {
479 	register EWINDOW *wp;	/* pointer to new window */
480 	register BUFFER *bp;	/* pointer to buffer to zot */
481 	register char *tmp;	/* ptr to TMP DOS environment variable */
482 	FILE *fp;
483         char line[NLINE];	/* command line send to shell */
484 	static char bname[] = "command";
485 	static char filnam[NSTRING] = "command";
486 	FILE *fopen();
487 
488 	/* don't allow this command if restricted */
489 	if (restflag)
490 		return(resterr());
491 
492 	if ((tmp = getenv("TMP")) == NULL)
493 		filnam[0] = 0;
494 	else {
495 		strcpy(filnam, tmp);
496 		if (filnam[strlen(filnam) - 1] != '\\')
497 			strcat(filnam, "\\");
498         }
499 	strcat(filnam,"command");
500 
501 	/* get the command to pipe in */
502         if (mlreply("@", line, NLINE) != TRUE)
503                 return(FALSE);
504 
505 	/* get rid of the command output buffer if it exists */
506         if ((bp=bfind(bname, FALSE, 0)) != FALSE) {
507 		/* try to make sure we are off screen */
508 		wp = wheadp;
509 		while (wp != NULL) {
510 			if (wp->w_bufp == bp) {
511 				onlywind(FALSE, 1);
512 				break;
513 			}
514 			wp = wp->w_wndp;
515 		}
516 		/* get rid of the existing command buffer */
517 		if (zotbuf(bp) != TRUE)
518 			return(FALSE);
519 	}
520 
521 	/* redirect the command output to the output file */
522 	strcat(line, " >>");
523 	strcat(line, filnam);
524 	movecursor(term.t_nrow - 1, 0);
525 
526 	/* execute the command */
527 	TTkclose();
528         shellprog(line);
529 	TTkopen();
530         sgarbf = TRUE;
531 
532         /* did the output file get generated? */
533 	if ((fp = fopen(filnam, "r")) == NULL)
534 		return(FALSE);
535 	fclose(fp);
536 
537 	/* split the current window to make room for the command output */
538 	if (splitwind(FALSE, 1) == FALSE)
539 			return(FALSE);
540 
541 	/* and read the stuff in */
542 	if (getfile(filnam, FALSE) == FALSE)
543 		return(FALSE);
544 
545 	/* make this window in VIEW mode, update all mode lines */
546 	curwp->w_bufp->b_mode |= MDVIEW;
547 	wp = wheadp;
548 	while (wp != NULL) {
549 		wp->w_flag |= WFMODE;
550 		wp = wp->w_wndp;
551 	}
552 
553 	/* and get rid of the temporary file */
554 	unlink(filnam);
555 	return(TRUE);
556 }
557 
558 /*
559  * filter a buffer through an external DOS program
560  * Bound to ^X #
561  */
filter(f,n)562 PASCAL NEAR filter(f, n)
563 
564 int f, n;
565 
566 {
567         register int    s;	/* return status from CLI */
568 	register BUFFER *bp;	/* pointer to buffer to zot */
569         char line[NLINE];	/* command line send to shell */
570 	char tmpnam[NFILEN];	/* place to store real file name */
571 	static char bname1[] = "fltinp";
572 
573 	static char filnam1[] = "fltinp";
574 	static char filnam2[] = "fltout";
575 
576 	/* don't allow this command if restricted */
577 	if (restflag)
578 		return(resterr());
579 
580 	if (curbp->b_mode&MDVIEW)	/* don't allow this command if	*/
581 		return(rdonly());	/* we are in read only mode	*/
582 
583 	/* get the filter name and its args */
584         if ((s=mlreply("#", line, NLINE)) != TRUE)
585                 return(s);
586 
587 	/* setup the proper file names */
588 	bp = curbp;
589 	strcpy(tmpnam, bp->b_fname);	/* save the original name */
590 	strcpy(bp->b_fname, bname1);	/* set it to our new one */
591 
592 	/* write it out, checking for errors */
593 	if (writeout(filnam1, "w") != TRUE) {
594 		mlwrite(TEXT2);
595 /*                      "[Cannot write filter file]" */
596 		strcpy(bp->b_fname, tmpnam);
597 		return(FALSE);
598 	}
599 
600 	strcat(line," <fltinp >fltout");
601 	movecursor(term.t_nrow - 1, 0);
602 	TTkclose();
603         shellprog(line);
604 	TTkopen();
605         sgarbf = TRUE;
606 	s = TRUE;
607 
608 	/* on failure, escape gracefully */
609 	if (s != TRUE || (readin(filnam2,FALSE) == FALSE)) {
610 		mlwrite(TEXT3);
611 /*                      "[Execution failed]" */
612 		strcpy(bp->b_fname, tmpnam);
613 		unlink(filnam1);
614 		unlink(filnam2);
615 		return(s);
616 	}
617 
618 	/* reset file name */
619 	strcpy(bp->b_fname, tmpnam);	/* restore name */
620 	bp->b_flag |= BFCHG;		/* flag it as changed */
621 
622 	/* and get rid of the temporary file */
623 	unlink(filnam1);
624 	unlink(filnam2);
625 	return(TRUE);
626 }
627 
628 #if	LATTICE
629 extern int _oserr;
630 #endif
631 
632 #if	MWC
633 extern int errno;
634 #endif
635 
636 #if	MSC
637 extern int _doserrno;
638 #endif
639 
640 /*	SHELLPROG: Execute a command in a subshell		*/
641 
shellprog(cmd)642 PASCAL NEAR shellprog(cmd)
643 
644 char *cmd;	/*  Incoming command line to execute  */
645 
646 {
647 	char *shell;		/* Name of system command processor */
648 	char swchar;		/* switch character to use */
649 	union REGS regs;	/* parameters for dos call */
650 	char comline[NSTRING];	/* constructed command line */
651 
652 	/*  detect current switch character and set us up to use it */
653 	regs.h.ah = 0x37;	/*  get setting data  */
654 	regs.h.al = 0x00;	/*  get switch character  */
655 	intdos(&regs, &regs);
656 	swchar = (char)regs.h.dl;
657 
658 	/*  get name of system shell  */
659 	if ((shell = getenv("COMSPEC")) == NULL) {
660 		return(FALSE);		/*  No shell located  */
661 	}
662 
663 	/* trim leading whitespace off the command */
664 	while (*cmd == ' ' || *cmd == '\t')	/*  find out if null command */
665 		cmd++;
666 
667 	/**  If the command line is not empty, bring up the shell  **/
668 	/**  and execute the command.  Otherwise, bring up the     **/
669 	/**  shell in interactive mode.   **/
670 
671 	if (*cmd) {
672 		strcpy(comline, shell);
673 		strcat(comline, " ");
674 		comline[strlen(comline) + 1] = 0;
675 		comline[strlen(comline)] = swchar;
676 		strcat(comline, "c ");
677 		strcat(comline, cmd);
678 		return(execprog(comline));
679 	} else
680 		return(execprog(shell));
681 }
682 
683 /*	EXECPROG:	A function to execute a named program
684 			with arguments
685 */
686 
687 #if	LATTICE | MWC
688 #define	CFLAG	1
689 #endif
690 
execprog(cmd)691 PASCAL NEAR execprog(cmd)
692 
693 char *cmd;	/*  Incoming command line to execute  */
694 
695 {
696 	char *sp;		/* temporary string pointer */
697 	int rv;			/* numeric return value from subprocess */
698 	char f1[38];		/* FCB1 area (not initialized */
699 	char f2[38];		/* FCB2 area (not initialized */
700 	char prog[NSTRING];	/* program filespec */
701 	char tail[NSTRING];	/* command tail with length byte */
702 	union REGS regs;	/* parameters for dos call  */
703 #if	MWC == 0
704 	struct SREGS segreg;	/* segment registers for dis call */
705 #endif
706 	struct Pblock {		/* EXEC parameter block */
707 		short envptr;	/* 2 byte pointer to environment string */
708 		char *cline;	/* 4 byte pointer to command line */
709 		char *fcb1;	/* 4 byte pointer to FCB at PSP+5Ch */
710 		char *fcb2;	/* 4 byte pointer to FCB at PSP+6Ch */
711 	} pblock;
712 
713 	/* parse the command name from the command line */
714 	sp = prog;
715 	while (*cmd && (*cmd != ' ') && (*cmd != '\t'))
716 		*sp++ = *cmd++;
717 	*sp = 0;
718 
719 	/* and parse out the command tail */
720 	while (*cmd && ((*cmd == ' ') || (*cmd == '\t')))
721 		++cmd;
722 	*tail = (char)(strlen(cmd)); /* record the byte length */
723 	strcpy(&tail[1], cmd);
724 	strcat(&tail[1], "\r");
725 
726 	/* look up the program on the path trying various extentions */
727 	if ((sp = flook(prog, TRUE)) == NULL)
728 		if ((sp = flook(strcat(prog, ".exe"), TRUE)) == NULL) {
729 			strcpy(&prog[strlen(prog)-4], ".com");
730 			if ((sp = flook(prog, TRUE)) == NULL)
731 				return(FALSE);
732 		}
733 	strcpy(prog, sp);
734 
735 #if	MWC == 0
736 	/* get a pointer to this PSPs environment segment number */
737 	segread(&segreg);
738 #endif
739 
740 	/* set up the EXEC parameter block */
741 	pblock.envptr = 0;	/* make the child inherit the parents env */
742 	pblock.fcb1 = f1;		/* point to a blank FCB */
743 	pblock.fcb2 = f2;		/* point to a blank FCB */
744         pblock.cline = tail;		/* parameter line pointer */
745 
746 	/* and make the call */
747 	regs.h.ah = 0x4b;	/* EXEC Load or Execute a Program */
748 	regs.h.al = 0x00;	/* load end execute function subcode */
749 #if	MWC
750 	regs.x.ds = ((unsigned long)(prog) >> 16);	/* program name ptr */
751 	regs.x.dx = (unsigned int)(prog);
752 	regs.x.es = regs.x.ds;
753 	/*regs.x.es = ((unsigned long)(&pblock) >> 16);	* set up param block ptr */
754 	regs.x.bx = (unsigned int)(&pblock);
755 #endif
756 #if	LATTICE | MSC | TURBO | IC
757 	segreg.ds = ((unsigned long)(prog) >> 16);	/* program name ptr */
758 	regs.x.dx = (unsigned int)(prog);
759 	segreg.es = ((unsigned long)(&pblock) >> 16);	/* set up param block ptr */
760 	regs.x.bx = (unsigned int)(&pblock);
761 #endif
762 
763 #if	NOVELL
764 	rv = execpr(prog, &pblock);
765 #endif
766 
767 #if	LATTICE && (NOVELL == 0)
768 	if ((intdosx(&regs, &regs, &segreg) & CFLAG) == 0) {
769 		regs.h.ah = 0x4d;	/* get child process return code */
770 		intdos(&regs, &regs);	/* go do it */
771 		rv = regs.x.ax;		/* save child's return code */
772 	} else
773 		rv = -_oserr;		/* failed child call */
774 #endif
775 #if	MWC && (NOVELL == 0)
776 	intcall(&regs, &regs, DOSINT);
777 	if ((regs.x.flags & CFLAG) == 0) {
778 		regs.h.ah = 0x4d;	/* get child process return code */
779 		intcall(&regs, &regs, DOSINT);	/* go do it */
780 		rv = regs.x.ax;		/* save child's return code */
781 	} else
782 		rv = -errno;		/* failed child call */
783 #endif
784 #if	(TURBO | IC | MSC) && (NOVELL == 0)
785 	intdosx(&regs, &regs, &segreg);
786 	if (regs.x.cflag == 0) {
787 		regs.h.ah = 0x4d;	/* get child process return code */
788 		intdos(&regs, &regs);	/* go do it */
789 		rv = regs.x.ax;		/* save child's return code */
790 	} else
791 		rv = -_doserrno;	/* failed child call */
792 #endif
793 	strcpy(rval, int_asc(rv));
794 	return((rval < 0) ? FALSE : TRUE);
795 }
796 
797 /* return a system dependant string with the current time */
798 
timeset()799 char *PASCAL NEAR timeset()
800 
801 {
802 #if	MWC | TURBO | IC | MSC
803 	register char *sp;	/* temp string pointer */
804 	char buf[16];		/* time data buffer */
805 	extern char *ctime();
806 
807 	time(buf);
808 	sp = ctime(buf);
809 	sp[strlen(sp)-1] = 0;
810 	return(sp);
811 #else
812 	return(errorm);
813 #endif
814 }
815 
816 #if	TURBO | IC
817 /*	FILE Directory routines		*/
818 
819 char path[NFILEN];	/* path of file to find */
820 char rbuf[NFILEN];	/* return file buffer */
821 
822 /*	do a wild card directory search (for file name completion) */
823 
getffile(fspec)824 char *PASCAL NEAR getffile(fspec)
825 
826 char *fspec;	/* pattern to match */
827 
828 {
829 	register int index;		/* index into various strings */
830 	register int point;		/* index into other strings */
831 	register int extflag;		/* does the file have an extention? */
832 	char fname[NFILEN];		/* file/path for DOS call */
833 
834 	/* first parse the file path off the file spec */
835 	strcpy(path, fspec);
836 	index = strlen(path) - 1;
837 	while (index >= 0 && (path[index] != '/' &&
838 				path[index] != '\\' && path[index] != ':'))
839 		--index;
840 	path[index+1] = 0;
841 
842 	/* check for an extension */
843 	point = strlen(fspec) - 1;
844 	extflag = FALSE;
845 	while (point > index) {
846 		if (fspec[point] == '.') {
847 			extflag = TRUE;
848 			break;
849 		}
850 		point--;
851 	}
852 
853 	/* construct the composite wild card spec */
854 	strcpy(fname, path);
855 	strcat(fname, &fspec[index+1]);
856 	strcat(fname, "*");
857 	if (extflag == FALSE)
858 		strcat(fname, ".*");
859 
860 	/* and call for the first file */
861 	if (findfirst(fname, &fileblock, FA_DIREC) == -1)
862 		return(NULL);
863 
864 	/* return the first file name! */
865 	strcpy(rbuf, path);
866 	strcat(rbuf, fileblock.ff_name);
867 	mklower(rbuf);
868 	if (fileblock.ff_attrib == 16)
869 		strcat(rbuf, DIRSEPSTR);
870 	return(rbuf);
871 }
872 
getnfile()873 char *PASCAL NEAR getnfile()
874 
875 {
876 	register int index;		/* index into various strings */
877 	register int point;		/* index into other strings */
878 	register int extflag;		/* does the file have an extention? */
879 	char fname[NFILEN];		/* file/path for DOS call */
880 
881 	/* and call for the first file */
882 	if (findnext(&fileblock) == -1)
883 		return(NULL);
884 
885 	/* return the first file name! */
886 	strcpy(rbuf, path);
887 	strcat(rbuf, fileblock.ff_name);
888 	mklower(rbuf);
889 	if (fileblock.ff_attrib == 16)
890 		strcat(rbuf, DIRSEPSTR);
891 	return(rbuf);
892 }
893 #else
894 #if	MSC
895 /*	FILE Directory routines		*/
896 
897 char path[NFILEN];	/* path of file to find */
898 char rbuf[NFILEN];	/* return file buffer */
899 
900 /*	do a wild card directory search (for file name completion) */
901 
getffile(fspec)902 char *PASCAL NEAR getffile(fspec)
903 
904 char *fspec;	/* pattern to match */
905 
906 {
907 	register int index;		/* index into various strings */
908 	register int point;		/* index into other strings */
909 	register int extflag;		/* does the file have an extention? */
910 	char fname[NFILEN];		/* file/path for DOS call */
911 
912 	/* first parse the file path off the file spec */
913 	strcpy(path, fspec);
914 	index = strlen(path) - 1;
915 	while (index >= 0 && (path[index] != '/' &&
916 				path[index] != '\\' && path[index] != ':'))
917 		--index;
918 	path[index+1] = 0;
919 
920 	/* check for an extension */
921 	point = strlen(fspec) - 1;
922 	extflag = FALSE;
923 	while (point > index) {
924 		if (fspec[point] == '.') {
925 			extflag = TRUE;
926 			break;
927 		}
928 		point--;
929 	}
930 
931 	/* construct the composite wild card spec */
932 	strcpy(fname, path);
933 	strcat(fname, &fspec[index+1]);
934 	strcat(fname, "*");
935 	if (extflag == FALSE)
936 		strcat(fname, ".*");
937 
938 	/* and call for the first file */
939 	if (_dos_findfirst(fname, _A_NORMAL|_A_SUBDIR, &fileblock) != 0)
940 		return(NULL);
941 
942 	/* return the first file name! */
943 	strcpy(rbuf, path);
944 	strcat(rbuf, fileblock.name);
945 	mklower(rbuf);
946 	if (fileblock.attrib == 16)
947 		strcat(rbuf, DIRSEPSTR);
948 	return(rbuf);
949 }
950 
getnfile()951 char *PASCAL NEAR getnfile()
952 
953 {
954 	register int index;		/* index into various strings */
955 	register int point;		/* index into other strings */
956 	register int extflag;		/* does the file have an extention? */
957 	char fname[NFILEN];		/* file/path for DOS call */
958 
959 	/* and call for the first file */
960 	if (_dos_findnext(&fileblock) != 0)
961 		return(NULL);
962 
963 	/* return the first file name! */
964 	strcpy(rbuf, path);
965 	strcat(rbuf, fileblock.name);
966 	mklower(rbuf);
967 	if (fileblock.attrib == 16)
968 		strcat(rbuf, DIRSEPSTR);
969 	return(rbuf);
970 }
971 #else
getffile(fspec)972 char *PASCAL NEAR getffile(fspec)
973 
974 char *fspec;	/* file to match */
975 
976 {
977 	return(NULL);
978 }
979 
getnfile()980 char *PASCAL NEAR getnfile()
981 
982 {
983 	return(NULL);
984 }
985 #endif
986 #endif
987 #endif
988