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