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(®s, ®s);
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(®s, ®s, &segreg) & CFLAG) == 0) {
769 regs.h.ah = 0x4d; /* get child process return code */
770 intdos(®s, ®s); /* 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(®s, ®s, DOSINT);
777 if ((regs.x.flags & CFLAG) == 0) {
778 regs.h.ah = 0x4d; /* get child process return code */
779 intcall(®s, ®s, 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(®s, ®s, &segreg);
786 if (regs.x.cflag == 0) {
787 regs.h.ah = 0x4d; /* get child process return code */
788 intdos(®s, ®s); /* 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