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