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