home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / CMDS / memacs400_src.lzh / MEMACS400 / SRC / fmrdos.c < prev    next >
Text File  |  1996-04-25  |  23KB  |  988 lines

  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.  
  63. in_init()    /* initialize the input buffer */
  64.  
  65. {
  66.     in_next = in_last = 0;
  67. }
  68.  
  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.  
  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.  
  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.  
  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.  
  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.  */
  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.  
  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.  */
  197. PASCAL NEAR ttflush()
  198. {
  199. }
  200.  
  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.  */
  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
  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.  
  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.  
  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.  */
  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.  
  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.  */
  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.  */
  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.  
  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.  
  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.  
  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.  
  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.  
  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.  
  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.  
  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
  972. char *PASCAL NEAR getffile(fspec)
  973.  
  974. char *fspec;    /* file to match */
  975.  
  976. {
  977.     return(NULL);
  978. }
  979.  
  980. char *PASCAL NEAR getnfile()
  981.  
  982. {
  983.     return(NULL);
  984. }
  985. #endif
  986. #endif
  987. #endif
  988.