home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 100-199 / ff195.lzh / MicroEMACS / src.zoo / msdos.c < prev    next >
C/C++ Source or Header  |  1989-03-23  |  24KB  |  971 lines

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