home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / UE311C.ZIP / FMRDOS.C < prev    next >
C/C++ Source or Header  |  1990-08-16  |  23KB  |  968 lines

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