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