1 /*	XVTDOS.C:	Operating specific I/O and Spawning functions
2 			under the XVT portability 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	XVT
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 
109 	/* on all screens we are not sure of the initial position
110 	   of the cursor					*/
111 	ttrow = 999;
112 	ttcol = 999;
113 	strcpy(os, "XVT");
114 
115 	mexist = TRUE;
116 	nbuttons = 3;
117 
118 	/* initialize our character input queue */
119 	in_init();
120 
121 }
122 
123 /*
124  * This function gets called just before we go back home to the command
125  * interpreter. On VMS it puts the terminal back in a reasonable state.
126  * Another no-operation on CPM.
127  */
ttclose()128 int PASCAL NEAR ttclose()
129 {
130 	/* nothing here! */
131 }
132 
133 /*
134  * Flush terminal buffer. Does real work where the terminal output is buffered
135  * up. A no-operation on systems where byte at a time terminal I/O is done.
136  */
ttflush()137 int PASCAL NEAR ttflush()
138 {
139 }
140 
141 /* typahead:	Check to see if any characters are already in the
142 		keyboard buffer
143 */
144 
typahead()145 int PASCAL NEAR typahead()
146 
147 {
148 	return(in_check());
149 }
150 
151 /*
152  * Create a subjob with a copy of the command intrepreter in it. When the
153  * command interpreter exits, mark the screen as garbage so that you do a full
154  * repaint. Bound to "^X C".
155  */
156 
spawncli(f,n)157 int PASCAL NEAR spawncli(f, n)
158 
159 int f, n;
160 
161 {
162 	/* don't allow this command if restricted */
163 	if (restflag)
164 		return(resterr());
165 
166         movecursor(term.t_nrow, 0);             /* Seek to last line.   */
167         TTflush();
168 	TTkclose();
169 	shellprog("");
170 #if	WINDOW_TEXT
171 	refresh_screen(first_screen);
172 #endif
173 	TTkopen();
174         sgarbf = TRUE;
175         return(TRUE);
176 }
177 
178 /*
179  * Run a one-liner in a subjob. When the command returns, wait for a single
180  * character to be typed, then mark the screen as garbage so a full repaint is
181  * done. Bound to "C-X !".
182  */
spawn(f,n)183 int PASCAL NEAR spawn(f, n)
184 
185 int f, n;
186 
187 {
188         register int s;
189         char line[NLINE];
190 
191 	/* don't allow this command if restricted */
192 	if (restflag)
193 		return(resterr());
194 
195         if ((s=mlreply("!", line, NLINE)) != TRUE)
196                 return(s);
197 	movecursor(term.t_nrow - 1, 0);
198 	TTkclose();
199         shellprog(line);
200 	TTkopen();
201 
202 	/* if we are interactive, pause here */
203 	if (clexec == FALSE) {
204 #if	XVT == 0
205 		printf(TEXT227);
206 /*			"\n--- Press any key to Continue ---" */
207 #endif
208 		tgetc();
209         }
210 #if	WINDOW_TEXT
211 	refresh_screen(first_screen);
212 #endif
213         sgarbf = TRUE;
214         return (TRUE);
215 }
216 
217 /*
218  * Run an external program with arguments. When it returns, wait for a single
219  * character to be typed, then mark the screen as garbage so a full repaint is
220  * done. Bound to "C-X $".
221  */
222 
execprg(f,n)223 int PASCAL NEAR execprg(f, n)
224 
225 {
226         register int s;
227         char line[NLINE];
228 
229 	/* don't allow this command if restricted */
230 	if (restflag)
231 		return(resterr());
232 
233         if ((s=mlreply("$", line, NLINE)) != TRUE)
234                 return(s);
235 	movecursor(term.t_nrow - 1, 0);
236 	TTkclose();
237         execprog(line);
238 #if	WINDOW_TEXT
239 	refresh_screen(first_screen);
240 #endif
241 	TTkopen();
242 	/* if we are interactive, pause here */
243 	if (clexec == FALSE) {
244 	        mlputs(TEXT6);
245 /*                     "\r\n\n[End]" */
246         	tgetc();
247         }
248         sgarbf = TRUE;
249         return (TRUE);
250 }
251 
252 /*
253  * Pipe a one line command into a window
254  * Bound to ^X @
255  */
pipecmd(f,n)256 int PASCAL NEAR pipecmd(f, n)
257 
258 int f, n;
259 
260 {
261 	register EWINDOW *wp;	/* pointer to new window */
262 	register BUFFER *bp;	/* pointer to buffer to zot */
263 	register char *tmp;	/* ptr to TMP DOS environment variable */
264 	FILE *fp;
265         char line[NLINE];	/* command line send to shell */
266 	static char bname[] = "command";
267 	static char filnam[NSTRING] = "command";
268 
269 	/* don't allow this command if restricted */
270 	if (restflag)
271 		return(resterr());
272 
273 	if ((tmp = getenv("TMP")) == NULL)
274 		filnam[0] = 0;
275 	else {
276 		strcpy(filnam, tmp);
277 		if (filnam[strlen(filnam) - 1] != '\\')
278 			strcat(filnam, "\\");
279         }
280 	strcat(filnam,"command");
281 
282 	/* get the command to pipe in */
283         if (mlreply("@", line, NLINE) != TRUE)
284                 return(FALSE);
285 
286 	/* get rid of the command output buffer if it exists */
287         if ((bp=bfind(bname, FALSE, 0)) != FALSE) {
288 		/* try to make sure we are off screen */
289 		wp = wheadp;
290 		while (wp != NULL) {
291 			if (wp->w_bufp == bp) {
292 				onlywind(FALSE, 1);
293 				break;
294 			}
295 			wp = wp->w_wndp;
296 		}
297 		/* get rid of the existing command buffer */
298 		if (zotbuf(bp) != TRUE)
299 			return(FALSE);
300 	}
301 
302 	/* redirect the command output to the output file */
303 	strcat(line, " >>");
304 	strcat(line, filnam);
305 	movecursor(term.t_nrow - 1, 0);
306 
307 	/* execute the command */
308 	TTkclose();
309         shellprog(line);
310 #if	WINDOW_TEXT
311 	refresh_screen(first_screen);
312 #endif
313 	TTkopen();
314         sgarbf = TRUE;
315 
316         /* did the output file get generated? */
317 	if ((fp = fopen(filnam, "r")) == NULL)
318 		return(FALSE);
319 	fclose(fp);
320 
321 	/* split the current window to make room for the command output */
322 	if (splitwind(FALSE, 1) == FALSE)
323 			return(FALSE);
324 
325 	/* and read the stuff in */
326 	if (getfile(filnam, FALSE) == FALSE)
327 		return(FALSE);
328 
329 	/* make this window in VIEW mode, update all mode lines */
330 	curwp->w_bufp->b_mode |= MDVIEW;
331 	wp = wheadp;
332 	while (wp != NULL) {
333 		wp->w_flag |= WFMODE;
334 		wp = wp->w_wndp;
335 	}
336 
337 	/* and get rid of the temporary file */
338 	unlink(filnam);
339 	return(TRUE);
340 }
341 
342 /*
343  * filter a buffer through an external DOS program
344  * Bound to ^X #
345  */
filter(f,n)346 int PASCAL NEAR filter(f, n)
347 
348 int f, n;
349 
350 {
351         register int    s;	/* return status from CLI */
352 	register BUFFER *bp;	/* pointer to buffer to zot */
353         char line[NLINE];	/* command line send to shell */
354 	char tmpnam[NFILEN];	/* place to store real file name */
355 	static char bname1[] = "fltinp";
356 
357 	static char filnam1[] = "fltinp";
358 	static char filnam2[] = "fltout";
359 
360 	/* don't allow this command if restricted */
361 	if (restflag)
362 		return(resterr());
363 
364 	if (curbp->b_mode&MDVIEW)	/* don't allow this command if	*/
365 		return(rdonly());	/* we are in read only mode	*/
366 
367 	/* get the filter name and its args */
368         if ((s=mlreply("#", line, NLINE)) != TRUE)
369                 return(s);
370 
371 	/* setup the proper file names */
372 	bp = curbp;
373 	strcpy(tmpnam, bp->b_fname);	/* save the original name */
374 	strcpy(bp->b_fname, bname1);	/* set it to our new one */
375 
376 	/* write it out, checking for errors */
377 	if (writeout(filnam1, "w") != TRUE) {
378 		mlwrite(TEXT2);
379 /*                      "[Cannot write filter file]" */
380 		strcpy(bp->b_fname, tmpnam);
381 		return(FALSE);
382 	}
383 
384 	strcat(line," <fltinp >fltout");
385 	movecursor(term.t_nrow - 1, 0);
386 	TTkclose();
387         shellprog(line);
388 #if	WINDOW_TEXT
389 	refresh_screen(first_screen);
390 #endif
391 	TTkopen();
392         sgarbf = TRUE;
393 	s = TRUE;
394 
395 	/* on failure, escape gracefully */
396 	if (s != TRUE || (readin(filnam2,FALSE) == FALSE)) {
397 		mlwrite(TEXT3);
398 /*                      "[Execution failed]" */
399 		strcpy(bp->b_fname, tmpnam);
400 		unlink(filnam1);
401 		unlink(filnam2);
402 		return(s);
403 	}
404 
405 	/* reset file name */
406 	strcpy(bp->b_fname, tmpnam);	/* restore name */
407 	bp->b_flag |= BFCHG;		/* flag it as changed */
408 
409 	/* and get rid of the temporary file */
410 	unlink(filnam1);
411 	unlink(filnam2);
412 	return(TRUE);
413 }
414 
415 #if	LATTICE
416 extern int _oserr;
417 #endif
418 
419 #if	MWC
420 extern int errno;
421 #endif
422 
423 #if	MSC
424 extern int _doserrno;
425 #endif
426 
427 /*	SHELLPROG: Execute a command in a subshell		*/
428 
shellprog(cmd)429 int PASCAL NEAR shellprog(cmd)
430 
431 char *cmd;	/*  Incoming command line to execute  */
432 
433 {
434 	char *shell;		/* Name of system command processor */
435 	char swchar;		/* switch character to use */
436 	union REGS regs;	/* parameters for dos call */
437 	char comline[NSTRING];	/* constructed command line */
438 
439 	/*  detect current switch character and set us up to use it */
440 	regs.h.ah = 0x37;	/*  get setting data  */
441 	regs.h.al = 0x00;	/*  get switch character  */
442 	intdos(&regs, &regs);
443 	swchar = (char)regs.h.dl;
444 
445 	/*  get name of system shell  */
446 	if ((shell = getenv("COMSPEC")) == NULL) {
447 		return(FALSE);		/*  No shell located  */
448 	}
449 
450 	/* trim leading whitespace off the command */
451 	while (*cmd == ' ' || *cmd == '\t')	/*  find out if null command */
452 		cmd++;
453 
454 	/**  If the command line is not empty, bring up the shell  **/
455 	/**  and execute the command.  Otherwise, bring up the     **/
456 	/**  shell in interactive mode.   **/
457 
458 	if (*cmd) {
459 		strcpy(comline, shell);
460 		strcat(comline, " ");
461 		comline[strlen(comline) + 1] = 0;
462 		comline[strlen(comline)] = swchar;
463 		strcat(comline, "c ");
464 		strcat(comline, cmd);
465 		return(execprog(comline));
466 	} else
467 		return(execprog(shell));
468 }
469 
470 /*	EXECPROG:	A function to execute a named program
471 			with arguments
472 */
473 
474 #if	LATTICE | MWC
475 #define	CFLAG	1
476 #endif
477 
execprog(cmd)478 int PASCAL NEAR execprog(cmd)
479 
480 char *cmd;	/*  Incoming command line to execute  */
481 
482 {
483 	char *sp;		/* temporary string pointer */
484 	int rv;			/* numeric return value from subprocess */
485 	char f1[38];		/* FCB1 area (not initialized */
486 	char f2[38];		/* FCB2 area (not initialized */
487 	char prog[NSTRING];	/* program filespec */
488 	char tail[NSTRING];	/* command tail with length byte */
489 	union REGS regs;	/* parameters for dos call  */
490 #if	MWC == 0
491 	struct SREGS segreg;	/* segment registers for dis call */
492 #endif
493 	struct Pblock {		/* EXEC parameter block */
494 		short envptr;	/* 2 byte pointer to environment string */
495 		char *cline;	/* 4 byte pointer to command line */
496 		char *fcb1;	/* 4 byte pointer to FCB at PSP+5Ch */
497 		char *fcb2;	/* 4 byte pointer to FCB at PSP+6Ch */
498 	} pblock;
499 
500 	/* parse the command name from the command line */
501 	sp = prog;
502 	while (*cmd && (*cmd != ' ') && (*cmd != '\t'))
503 		*sp++ = *cmd++;
504 	*sp = 0;
505 
506 	/* and parse out the command tail */
507 	while (*cmd && ((*cmd == ' ') || (*cmd == '\t')))
508 		++cmd;
509 	*tail = (char)(strlen(cmd)); /* record the byte length */
510 	strcpy(&tail[1], cmd);
511 	strcat(&tail[1], "\r");
512 
513 	/* look up the program on the path trying various extentions */
514 	if ((sp = flook(prog, TRUE)) == NULL)
515 		if ((sp = flook(strcat(prog, ".exe"), TRUE)) == NULL) {
516 			strcpy(&prog[strlen(prog)-4], ".com");
517 			if ((sp = flook(prog, TRUE)) == NULL)
518 				return(FALSE);
519 		}
520 	strcpy(prog, sp);
521 
522 #if	MWC == 0
523 	/* get a pointer to this PSPs environment segment number */
524 #if	IC
525 	_segread(&segreg);
526 #else /* IC */
527 	segread(&segreg);
528 #endif /* IC */
529 #endif /* MWC == 0 */
530 
531 	/* set up the EXEC parameter block */
532 	pblock.envptr = 0;	/* make the child inherit the parents env */
533 	pblock.fcb1 = f1;		/* point to a blank FCB */
534 	pblock.fcb2 = f2;		/* point to a blank FCB */
535         pblock.cline = tail;		/* parameter line pointer */
536 
537 	/* and make the call */
538 	regs.h.ah = 0x4b;	/* EXEC Load or Execute a Program */
539 	regs.h.al = 0x00;	/* load end execute function subcode */
540 #if	MWC
541 	regs.x.ds = ((unsigned long)(prog) >> 16);	/* program name ptr */
542 	regs.x.dx = (unsigned int)(prog);
543 	regs.x.es = regs.x.ds;
544 	/*regs.x.es = ((unsigned long)(&pblock) >> 16);	* set up param block ptr */
545 	regs.x.bx = (unsigned int)(&pblock);
546 #endif
547 #if	LATTICE | MSC | TURBO | IC | ZTC
548 	segreg.ds = ((unsigned long)(prog) >> 16);	/* program name ptr */
549 	regs.x.dx = (unsigned int)(prog);
550 	segreg.es = ((unsigned long)(&pblock) >> 16);	/* set up param block ptr */
551 	regs.x.bx = (unsigned int)(&pblock);
552 #endif
553 #if	LATTICE
554 	if ((intdosx(&regs, &regs, &segreg) & CFLAG) == 0) {
555 		regs.h.ah = 0x4d;	/* get child process return code */
556 		intdos(&regs, &regs);	/* go do it */
557 		rv = regs.x.ax;		/* save child's return code */
558 	} else
559 		rv = -_oserr;		/* failed child call */
560 #endif
561 #if	MWC
562 	intcall(&regs, &regs, DOSINT);
563 	if ((regs.x.flags & CFLAG) == 0) {
564 		regs.h.ah = 0x4d;	/* get child process return code */
565 		intcall(&regs, &regs, DOSINT);	/* go do it */
566 		rv = regs.x.ax;		/* save child's return code */
567 	} else
568 		rv = -errno;		/* failed child call */
569 #endif
570 #if	TURBO | IC | MSC | ZTC
571 	intdosx(&regs, &regs, &segreg);
572 	if (regs.x.cflag == 0) {
573 		regs.h.ah = 0x4d;	/* get child process return code */
574 		intdos(&regs, &regs);	/* go do it */
575 		rv = regs.x.ax;		/* save child's return code */
576 	} else
577 #if	IC
578 		rv = -1;
579 #else /* IC */
580 		rv = -_doserrno;	/* failed child call */
581 #endif /* IC */
582 #endif
583 	strcpy(rval, int_asc(rv));
584 	return((rval < 0) ? FALSE : TRUE);
585 }
586 
587 /* return a system dependant string with the current time */
588 
timeset()589 char *PASCAL NEAR timeset()
590 
591 {
592 #if	MWC | TURBO | IC | MSC | ZTC
593 	register char *sp;	/* temp string pointer */
594 	char buf[16];		/* time data buffer */
595 	extern char *ctime();
596 
597 #if	IC
598 	time((time_t *)buf);
599 	sp = ctime((time_t *)buf);
600 #else
601 	time(buf);
602 	sp = ctime(buf);
603 #endif
604 	sp[strlen(sp)-1] = 0;
605 	return(sp);
606 #else
607 	return(errorm);
608 #endif
609 }
610 
611 #if	TURBO
612 /*	FILE Directory routines		*/
613 
614 char path[NFILEN];	/* path of file to find */
615 char rbuf[NFILEN];	/* return file buffer */
616 
617 /*	do a wild card directory search (for file name completion) */
618 
getffile(fspec)619 char *PASCAL NEAR getffile(fspec)
620 
621 char *fspec;	/* pattern to match */
622 
623 {
624 	register int index;		/* index into various strings */
625 	register int point;		/* index into other strings */
626 	register int extflag;		/* does the file have an extention? */
627 	char fname[NFILEN];		/* file/path for DOS call */
628 
629 	/* first parse the file path off the file spec */
630 	strcpy(path, fspec);
631 	index = strlen(path) - 1;
632 	while (index >= 0 && (path[index] != '/' &&
633 				path[index] != '\\' && path[index] != ':'))
634 		--index;
635 	path[index+1] = 0;
636 
637 	/* check for an extension */
638 	point = strlen(fspec) - 1;
639 	extflag = FALSE;
640 	while (point > index) {
641 		if (fspec[point] == '.') {
642 			extflag = TRUE;
643 			break;
644 		}
645 		point--;
646 	}
647 
648 	/* construct the composite wild card spec */
649 	strcpy(fname, path);
650 	strcat(fname, &fspec[index+1]);
651 	strcat(fname, "*");
652 	if (extflag == FALSE)
653 		strcat(fname, ".*");
654 
655 	/* and call for the first file */
656 	if (findfirst(fname, &fileblock, FA_DIREC) == -1)
657 		return(NULL);
658 
659 	/* return the first file name! */
660 	strcpy(rbuf, path);
661 	strcat(rbuf, fileblock.ff_name);
662 	mklower(rbuf);
663 	if (fileblock.ff_attrib == 16)
664 		strcat(rbuf, DIRSEPSTR);
665 	return(rbuf);
666 }
667 
getnfile()668 char *PASCAL NEAR getnfile()
669 
670 {
671 	register int index;		/* index into various strings */
672 	register int point;		/* index into other strings */
673 	register int extflag;		/* does the file have an extention? */
674 	char fname[NFILEN];		/* file/path for DOS call */
675 
676 	/* and call for the first file */
677 	if (findnext(&fileblock) == -1)
678 		return(NULL);
679 
680 	/* return the first file name! */
681 	strcpy(rbuf, path);
682 	strcat(rbuf, fileblock.ff_name);
683 	mklower(rbuf);
684 	if (fileblock.ff_attrib == 16)
685 		strcat(rbuf, DIRSEPSTR);
686 	return(rbuf);
687 }
688 #else
689 #if	MSC | ZTC
690 /*	FILE Directory routines		*/
691 
692 char path[NFILEN];	/* path of file to find */
693 char rbuf[NFILEN];	/* return file buffer */
694 
695 /*	do a wild card directory search (for file name completion) */
696 
getffile(fspec)697 char *PASCAL NEAR getffile(fspec)
698 
699 char *fspec;	/* pattern to match */
700 
701 {
702 	register int index;		/* index into various strings */
703 	register int point;		/* index into other strings */
704 	register int extflag;		/* does the file have an extention? */
705 	char fname[NFILEN];		/* file/path for DOS call */
706 
707 	/* first parse the file path off the file spec */
708 	strcpy(path, fspec);
709 	index = strlen(path) - 1;
710 	while (index >= 0 && (path[index] != '/' &&
711 				path[index] != '\\' && path[index] != ':'))
712 		--index;
713 	path[index+1] = 0;
714 
715 	/* check for an extension */
716 	point = strlen(fspec) - 1;
717 	extflag = FALSE;
718 	while (point > index) {
719 		if (fspec[point] == '.') {
720 			extflag = TRUE;
721 			break;
722 		}
723 		point--;
724 	}
725 
726 	/* construct the composite wild card spec */
727 	strcpy(fname, path);
728 	strcat(fname, &fspec[index+1]);
729 	strcat(fname, "*");
730 	if (extflag == FALSE)
731 		strcat(fname, ".*");
732 
733 	/* and call for the first file */
734 	if (_dos_findfirst(fname, _A_NORMAL|_A_SUBDIR, &fileblock) != 0)
735 		return(NULL);
736 
737 	/* return the first file name! */
738 	strcpy(rbuf, path);
739 	strcat(rbuf, fileblock.name);
740 	mklower(rbuf);
741 	if (fileblock.attrib == 16)
742 		strcat(rbuf, DIRSEPSTR);
743 	return(rbuf);
744 }
745 
getnfile()746 char *PASCAL NEAR getnfile()
747 
748 {
749 	register int index;		/* index into various strings */
750 	register int point;		/* index into other strings */
751 	register int extflag;		/* does the file have an extention? */
752 	char fname[NFILEN];		/* file/path for DOS call */
753 
754 	/* and call for the first file */
755 	if (_dos_findnext(&fileblock) != 0)
756 		return(NULL);
757 
758 	/* return the first file name! */
759 	strcpy(rbuf, path);
760 	strcat(rbuf, fileblock.name);
761 	mklower(rbuf);
762 	if (fileblock.attrib == 16)
763 		strcat(rbuf, DIRSEPSTR);
764 	return(rbuf);
765 }
766 #else
getffile(fspec)767 char *PASCAL NEAR getffile(fspec)
768 
769 char *fspec;	/* file to match */
770 
771 {
772 	return(NULL);
773 }
774 
getnfile()775 char *PASCAL NEAR getnfile()
776 
777 {
778 	return(NULL);
779 }
780 #endif
781 #endif
782 #endif
783