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(®s, ®s);
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(®s, ®s, &segreg) & CFLAG) == 0) {
782 regs.h.ah = 0x4d; /* get child process return code */
783 intdos(®s, ®s); /* 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(®s, ®s, DOSINT);
790 if ((regs.x.flags & CFLAG) == 0) {
791 regs.h.ah = 0x4d; /* get child process return code */
792 intcall(®s, ®s, 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(®s, ®s, &segreg);
799 if (regs.x.cflag == 0) {
800 regs.h.ah = 0x4d; /* get child process return code */
801 intdos(®s, ®s); /* 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