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

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