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

  1. /*    AMIGADOS.C:    Operating specific I/O and Spawning functions
  2.             for MicroEMACS 3.10
  3.             (C)Copyright 1988 by Daniel M. Lawrence
  4. */
  5.  
  6. #include        <stdio.h>
  7. #include    "estruct.h"
  8. #if    AMIGA
  9. #include    <exec/types.h>
  10. #include    <exec/io.h>
  11. #include    <intuition/intuition.h>
  12. #include    <devices/console.h>
  13. #include    "eproto.h"
  14. #include        "edef.h"
  15. #include    "elang.h"
  16.  
  17. #define INTUITION_REV    0L
  18. #define    NEW         1006L
  19. #define    CRWIDTH        8
  20. #define    CRHEIGHT    8
  21.  
  22. struct IntuitionBase *IntuitionBase;
  23. struct Window *win;
  24. struct IOStdReq con;        /* ptr to console device driver handle */
  25.  
  26. /*    Intuition Function type declarations    */
  27.  
  28. struct IntuitionBase *OpenLibrary();
  29. struct Window *OpenWindow();
  30. struct IntuiMessage *GetMsg();
  31.  
  32. typedef struct {
  33.     short rw_code;        /* normal keycode to generate */
  34.     short rw_scode;        /* shifted  "  */
  35.     short rw_ccode;        /* control  "  */
  36. } RKEY;
  37.  
  38. /* raw keycode scan code to emacs keycode translation table */
  39.  
  40. RKEY keytrans[0x60] = {
  41.  
  42. /*    CODE    NORM    SHIFT    CTRL */
  43. /*    0x00,*/    '`',    '~',    0,
  44. /*    0x01,*/    '1',    '!',    0,
  45. /*    0x02,*/    '2',    '@',    0,
  46. /*    0x03,*/    '3',    '#',    0,
  47. /*    0x04,*/    '4',    '$',    0,
  48. /*    0x05,*/    '5',    '%',    0,
  49. /*    0x06,*/    '6',    '^',    0,
  50. /*    0x07,*/    '7',    '&',    0,
  51. /*    0x08,*/    '8',    '*',    0,    
  52. /*    0x09,*/    '9',    '(',    0,
  53. /*    0x0a,*/    '0',    ')',    0,
  54. /*    0x0b,*/    '-',    '_',    0,
  55. /*    0x0c,*/    '=',    '+',    0,
  56. /*    0x0d,*/    '\\',    '|',    0,
  57. /*    0x0e,*/    0,    0,    0,
  58. /*    0x0f,*/    0,    0,    0,
  59. /*    0x10,*/    'q',    'Q',    CTRL|'Q',
  60. /*    0x11,*/    'w',    'W',    CTRL|'W',
  61. /*    0x12,*/    'e',    'E',    CTRL|'E',
  62. /*    0x13,*/    'r',    'R',    CTRL|'R',
  63. /*    0x14,*/    't',    'T',    CTRL|'T',
  64. /*    0x15,*/    'y',    'Y',    CTRL|'Y',
  65. /*    0x16,*/    'u',    'U',    CTRL|'U',
  66. /*    0x17,*/    'i',    'I',    CTRL|'I',
  67. /*    0x18,*/    'o',    'O',    CTRL|'O',
  68. /*    0x19,*/    'p',    'P',    CTRL|'P',
  69. /*    0x1a,*/    '[',    '{',    0,
  70. /*    0x1b,*/    ']',    '}',    0,
  71. /*    0x1c,*/    0,    0,    0,
  72. /*    0x1d,*/    '1',    SPEC|'>',    0,
  73. /*    0x1e,*/    '2',    SPEC|'N',    0,
  74. /*    0x1f,*/    '3',    SPEC|'V',    0,
  75. /*    0x20,*/    'a',    'A',    CTRL|'A',
  76. /*    0x21,*/    's',    'S',    CTRL|'S',
  77. /*    0x22,*/    'd',    'D',    CTRL|'D',
  78. /*    0x23,*/    'f',    'F',    CTRL|'F',
  79. /*    0x24,*/    'g',    'G',    CTRL|'G',/*    0x25,*/    'h',    'H',    CTRL|'H',
  80. /*    0x26,*/    'j',    'J',    CTRL|'J',
  81. /*    0x27,*/    'k',    'K',    CTRL|'K',
  82. /*    0x28,*/    'l',    'L',    CTRL|'L',
  83. /*    0x29,*/    ';',    ':',    0,
  84. /*    0x2a,*/    39,    34,    0,
  85. /*    0x2b,*/    0,    0,    0,
  86. /*    0x2c,*/    0,    0,    0,
  87. /*    0x2d,*/    '4',    SPEC|'B',    0,
  88. /*    0x2e,*/    '5',    0,        0,
  89. /*    0x2f,*/    '6',    SPEC|'F',    0,
  90.     /* this key is probably mapped on forign AIMIGA keyboards */
  91. /*    0x30,*/    0,    0,    0,
  92. /*    0x31,*/    'z',    'Z',    CTRL|'Z',
  93. /*    0x32,*/    'x',    'X',    CTRL|'X',
  94. /*    0x33,*/    'c',    'C',    CTRL|'C',
  95. /*    0x34,*/    'v',    'V',    CTRL|'V',
  96. /*    0x35,*/    'b',    'B',    CTRL|'B',
  97. /*    0x36,*/    'n',    'N',    CTRL|'N',
  98. /*    0x37,*/    'm',    'M',    CTRL|'M',
  99. /*    0x38,*/    ',',    '<',    0,
  100. /*    0x39,*/    '.',    '>',    0,
  101. /*    0x3a,*/    '/',    '?',    0,
  102. /*    0x3b,*/    0,    0,    0,
  103. /*    0x3c,*/    '.',    SPEC|'D',    0,
  104. /*    0x3d,*/    '7',    SPEC|'<',    0,
  105. /*    0x3e,*/    '8',    SPEC|'P',    0,
  106. /*    0x3f,*/    '9',    SPEC|'Z',    0,
  107. /*    0x40,*/    ' ',    SHFT|' ',    0,
  108. /*    0x41,*/    CTRL|'H',    SHFT|'D',    0,
  109. /*    0x42,*/    CTRL|'I',    SHFT|'I',    0,
  110. /*    0x43,*/    CTRL|'M', CTRL|'M', CTRL|'M',
  111. /*    0x44,*/    CTRL|'M', CTRL|'M', CTRL|'M',
  112. /*    0x45,*/    CTRL|'[',    0,    0,
  113. /*    0x46,*/    SPEC|'D',    0,    0,
  114. /*    0x47,*/    0,    0,    0,
  115. /*    0x48,*/    0,    0,    0,
  116. /*    0x49,*/    0,    0,    0,
  117. /*    0x4a,*/    '-',    0,    0,
  118. /*    0x4b,*/    0,    0,    0,
  119. /*    0x4c,*/    SPEC|'P',    SHFT|SPEC|'P',    CTRL|SPEC|'P',
  120. /*    0x4d,*/    SPEC|'N',    SHFT|SPEC|'N',    CTRL|SPEC|'N',
  121. /*    0x4e,*/    SPEC|'F',    SHFT|SPEC|'F',    CTRL|SPEC|'F',
  122. /*    0x4f,*/    SPEC|'B',    SHFT|SPEC|'B',    CTRL|SPEC|'B',
  123. /*    0x50,*/    SPEC|'1',    SHFT|SPEC|'1',    CTRL|SPEC|'1',
  124. /*    0x51,*/    SPEC|'2',    SHFT|SPEC|'2',    CTRL|SPEC|'2',
  125. /*    0x52,*/    SPEC|'3',    SHFT|SPEC|'3',    CTRL|SPEC|'3',
  126. /*    0x53,*/    SPEC|'4',    SHFT|SPEC|'4',    CTRL|SPEC|'4',
  127. /*    0x54,*/    SPEC|'5',    SHFT|SPEC|'5',    CTRL|SPEC|'5',
  128. /*    0x55,*/    SPEC|'6',    SHFT|SPEC|'6',    CTRL|SPEC|'6',
  129. /*    0x56,*/    SPEC|'7',    SHFT|SPEC|'7',    CTRL|SPEC|'7',
  130. /*    0x57,*/    SPEC|'8',    SHFT|SPEC|'8',    CTRL|SPEC|'8',
  131. /*    0x58,*/    SPEC|'9',    SHFT|SPEC|'9',    CTRL|SPEC|'9',
  132. /*    0x59,*/    SPEC|'0',    SHFT|SPEC|'0',    CTRL|SPEC|'0',
  133. /*    0x5a,*/    '(',    0,    0,
  134. /*    0x5b,*/    ')',    0,    0,
  135. /*    0x5c,*/    '/',    0,    0,
  136. /*    0x5d,*/    '*',    0,    0,
  137. /*    0x5e,*/    0,    0,    0,
  138. /*    0x5f,*/    SPEC|'?',    0,    0,
  139. };
  140.  
  141. /* some keyboard keys current states */
  142.  
  143. int r_shiftflag;    /* right shift key */
  144. int l_shiftflag;    /* left shift key */
  145. int r_altflag;        /* right alt key */
  146. int l_altflag;        /* left alt key */
  147. int r_amiflag;        /* right amiga key */
  148. int l_amiflag;        /* left amiga key */
  149. int ctrlflag;        /* control key */
  150. int lockflag;        /* shift lock key */
  151.  
  152. /*    output buffers and pointers    */
  153.  
  154. #define OBUFSIZE    1024L
  155. #define    IBUFSIZE    64    /* this must be a power of 2 */
  156.  
  157. char out_buf[OBUFSIZE+1];    /* output character buffer */
  158. int out_ptr = 0;        /* index to next char to put in buffer */
  159.  
  160. /*    input buffers and pointers    */
  161.  
  162. #define    IBUFSIZE    64    /* this must be a power of 2 */
  163.  
  164. unsigned char in_buf[IBUFSIZE];    /* input character buffer */
  165. int in_next = 0;        /* pos to retrieve next input character */
  166. int in_last = 0;        /* pos to place most recent input character */
  167.  
  168. in_init()    /* initialize the input buffer */
  169.  
  170. {
  171.     in_next = in_last = 0;
  172. }
  173.  
  174. in_check()    /* is the input buffer non-empty? */
  175.  
  176. {
  177.     if (in_next == in_last)
  178.         return(FALSE);
  179.     else
  180.         return(TRUE);
  181. }
  182.  
  183. in_put(event)
  184.  
  185. int event;    /* event to enter into the input buffer */
  186.  
  187. {
  188.     in_buf[in_last++] = event;
  189.     in_last &= (IBUFSIZE - 1);
  190. }
  191.  
  192. int in_get()    /* get an event from the input buffer */
  193.  
  194. {
  195.     register int event;    /* event to return */
  196.  
  197.     event = in_buf[in_next++];
  198.     in_next &= (IBUFSIZE - 1);
  199.     return(event);
  200. }
  201.  
  202. /*
  203.  * This function is called once to set up the terminal device streams.
  204.  * On VMS, it translates TT until it finds the terminal, then assigns
  205.  * a channel to it and sets it raw. On CPM it is a no-op.
  206.  */
  207. ttopen()
  208. {
  209.     struct NewWindow new_win;
  210.     int i;
  211. #if    AZTEC
  212.     extern    Enable_Abort;    /* Turn off ctrl-C interrupt */
  213.  
  214.     Enable_Abort = 0;    /* for the Manx compiler */
  215. #endif
  216.  
  217.     /* open the intuition library */
  218.     IntuitionBase = (struct IntuitionBase *)
  219.         OpenLibrary("intuition.library", INTUITION_REV);
  220.     if (IntuitionBase == NULL) {
  221.         printf("%%Can not open Intuition\n");
  222.         exit(-1);
  223.     }
  224.  
  225.     /* initialize the new windows attributes */
  226.     new_win.LeftEdge = 0;
  227.     new_win.TopEdge = 0;
  228.     new_win.Width = 640;
  229.     new_win.Height = 200;
  230.     new_win.DetailPen = 0;
  231.     new_win.BlockPen = 1;
  232.     new_win.Title = (unsigned char *)"MicroEMACS 3.10g/Amiga";
  233.     new_win.Flags = WINDOWCLOSE | SMART_REFRESH | ACTIVATE |
  234.         WINDOWDRAG | WINDOWDEPTH | WINDOWSIZING | SIZEBRIGHT |
  235.         RMBTRAP | NOCAREREFRESH;
  236.     new_win.IDCMPFlags = CLOSEWINDOW | NEWSIZE | MOUSEBUTTONS |
  237.         RAWKEY;
  238.     new_win.Type = WBENCHSCREEN;
  239.     new_win.FirstGadget = NULL;
  240.     new_win.CheckMark = NULL;
  241.     new_win.Screen = NULL;
  242.     new_win.BitMap = NULL;
  243.     new_win.MinWidth = 100;
  244.     new_win.MinHeight = 25;
  245.     new_win.MaxWidth = 640;
  246.     new_win.MaxHeight = 200;
  247.  
  248.     /* open the window! */
  249.     win = (struct Window *)OpenWindow(&new_win);
  250.     if (win == NULL) {
  251.         printf("%%Can not open a window\n");
  252.         exit(-2);
  253.     }
  254.  
  255.     /* and open up the console for output */
  256.     con.io_Data = (APTR)win;
  257.     OpenDevice("console.device", 0, &con, 0);
  258.  
  259.     /* and init all the keyboard flags */
  260.     r_shiftflag = FALSE;
  261.     l_shiftflag = FALSE;    r_altflag = FALSE;
  262.     l_altflag = FALSE;
  263.     r_amiflag = FALSE;
  264.     l_amiflag = FALSE;
  265.     ctrlflag = FALSE;
  266.     lockflag = FALSE;
  267.  
  268.     /* initialize our private event queue */
  269.     in_init();
  270.  
  271.     /* set the current sizes */
  272.     newwidth(TRUE, 77);
  273.     newsize(TRUE, 23);
  274.  
  275.     /* on all screens we are not sure of the initial position
  276.        of the cursor                    */
  277.     ttrow = 999;
  278.     ttcol = 999;
  279. }
  280.  
  281. /*
  282.  * This function gets called just before we go back home to the command
  283.  * interpreter. On VMS it puts the terminal back in a reasonable state.
  284.  * Another no-operation on CPM.
  285.  */
  286. ttclose()
  287.  
  288. {
  289.     /* make sure there is no pending output */
  290.     ttflush();
  291.  
  292.     /* and now close up shop */
  293.     CloseDevice(&con);
  294.     CloseWindow(win);
  295.     OpenWorkBench();
  296. }
  297.  
  298. /*
  299.  * Write a character to the display. On VMS, terminal output is buffered, and
  300.  * we just put the characters in the big array, after checking for overflow.
  301.  * On CPM terminal I/O unbuffered, so we just write the byte out. Ditto on
  302.  * MS-DOS (use the very very raw console output routine).
  303.  */
  304.  
  305. ttputc(c)
  306.  
  307. char c;
  308.  
  309. {
  310.     /* add the character to the output buffer */
  311.         out_buf[out_ptr++] = c;
  312.  
  313.         /* send the buffer out if we are at the limit */
  314.         if (out_ptr >= OBUFSIZE)
  315.                 ttflush();
  316. }
  317.  
  318. /*
  319.  * Flush terminal buffer. Does real work where the terminal output is buffered
  320.  * up. A no-operation on systems where byte at a time terminal I/O is done.
  321.  */
  322.  
  323. ttflush()
  324.  
  325. {
  326.     /* if there are any characters waiting to display... */
  327.         if (out_ptr) {
  328.             out_buf[out_ptr] = 0;    /* terminate the buffer string */
  329.             sendcon(out_buf);    /* send them out */
  330.             out_ptr = 0;        /* and reset the buffer */
  331.     }
  332. }
  333.  
  334. /*
  335.  * Read a character from the terminal.
  336.  */
  337.  
  338. ttgetc()
  339.  
  340. {
  341.     /* make sure there is no pending output */
  342. nxtchr:    ttflush();
  343.  
  344.     /* if it is already buffered up, get it */
  345.     if (in_check())
  346.         return(in_get());
  347.  
  348.     /* process an INTUITION event (possibly loading the input buffer) */
  349.     doevent();
  350.     goto nxtchr;
  351. }
  352.  
  353. #if    TYPEAH
  354. /* typahead:    Check to see if any characters are already in the
  355.         keyboard buffer
  356. */
  357.  
  358. typahead()
  359.  
  360. {
  361. tcheck:    /* if type ahead is already pending... */
  362.     if (in_check())
  363.         return(TRUE);
  364.  
  365.     /* check the signal for IDCMP events pending */
  366.     if ((1 << win->UserPort->mp_SigBit) != 0)
  367.         return(TRUE);
  368.  
  369.     /* no event in queue... no typeahead ready */
  370.     return(FALSE);
  371. }
  372. #endif
  373.  
  374. doevent()
  375.  
  376. {
  377.     register int eventX, eventY;    /* local copies of the event info */
  378.     struct IntuiMessage *event;    /* current event to repond to */
  379.     ULONG class;    /* class of event */
  380.     USHORT code;    /* data code */
  381.     SHORT x,y;    /* mouse x/y position at time of event */
  382.     char buf[128];    /*temp buff*/
  383.  
  384.     /* wait for an event to occur */
  385.     Wait(1 << win->UserPort->mp_SigBit);
  386.  
  387.     /* get the event and parse it up */
  388.     while (event = GetMsg(win->UserPort)) {
  389.         class = event->Class;
  390.         code = event->Code;
  391.         eventX = event->MouseX;
  392.         eventY = event->MouseY;
  393.         ReplyMsg(event);
  394.  
  395.         /* a normal keystroke? */
  396.         if (class == RAWKEY) {            dokey(code);
  397.             continue;
  398.         }
  399.  
  400.         /* User clicked on the close gadget! */
  401.         if (class == CLOSEWINDOW) {
  402.             quit(FALSE, 0);
  403.             stuffibuf(255, 0, 0);    /* fake a char to force quit to work */
  404.         }
  405.  
  406.         /* resolve the mouse address (border adjusted) */
  407.         if (class == NEWSIZE) {
  408.             x = (win->Width - 5) / CRWIDTH;
  409.             y = (win->Height - 10) / CRHEIGHT;
  410.         } else {
  411.             x = (eventX - 5) / CRWIDTH;
  412.             y = (eventY - 10) / CRHEIGHT;
  413.         }
  414.         if (x > 77)
  415.             x = 77;
  416.         if (y > 23)
  417.             y = 23;
  418.  
  419.         /* are we resizing the window? */
  420.         if (class == NEWSIZE) {
  421.             stuffibuf(MOUS | '1', x, y);
  422.             continue;
  423.         }
  424.  
  425.         /* and lastly, a mouse button press */
  426.         switch (code) {
  427.             case 104:    stuffibuf(MOUS | mod('a'), x, y);
  428.                     break;
  429.             case 232:    stuffibuf(MOUS | mod('b'), x, y);
  430.                     break;
  431.             case 105:    stuffibuf(MOUS | mod('e'), x, y);
  432.                     break;
  433.             case 233:    stuffibuf(MOUS | mod('f'), x, y);
  434.                     break;
  435.         }
  436.     }
  437.     return;
  438. }
  439.  
  440. int mod(c)    /* modify a character by the current shift and control flags */
  441.  
  442. int c;        /* original character */
  443.  
  444. {
  445.     /* first apply the shift and control modifiers */
  446.     if (l_shiftflag || r_shiftflag || lockflag)
  447.         c -= 32;
  448.     if (ctrlflag)
  449.         c |= CTRL;
  450.     return(c);
  451. }
  452.  
  453. sendcon(buf)    /* send a string to the console */
  454.  
  455. char *buf;    /* buffer to write out */
  456.  
  457. {
  458.     /* initialize the IO request */
  459.     con.io_Data = (APTR)buf;
  460.     con.io_Length = strlen(buf);
  461.     con.io_Command = CMD_WRITE;
  462.  
  463.     /* and perform the I/O */
  464.     SendIO(&con);
  465. }
  466.  
  467.  
  468. /* process an incomming keyboard code */
  469.  
  470. dokey(code)
  471.  
  472. int code;    /* raw keycode to convert */
  473.  
  474. {
  475.     register int ekey;    /* translate emacs key */
  476.     register int dir;    /* key direction (up/down) */
  477.     char buf[NSTRING];
  478.  
  479.     /* decode the direction of the key */
  480.     dir = TRUE;
  481.     if (code > 127) {
  482.         code = code & 127;
  483.         dir = FALSE;
  484.     }
  485.  
  486.     /* process various shift keys */
  487.     if (code >= 0x60) {
  488.         switch (code) {
  489.  
  490.             case 0x60:    l_shiftflag = dir;    break;
  491.             case 0x61:    r_shiftflag = dir;    break;
  492.             case 0x62:    lockflag    = dir;    break;
  493.             case 0x63:    ctrlflag    = dir;    break;
  494.             case 0x64:    l_altflag   = dir;    break;
  495.             case 0x65:    r_altflag   = dir;    break;
  496.             case 0x66:    l_amiflag   = dir;    break;
  497.             case 0x67:    r_amiflag   = dir;    break;
  498.  
  499.         }
  500.         return;
  501.     }
  502.  
  503.     /* up keystrokes are ignored for the rest of these */
  504.     if (dir == FALSE)
  505.         return;
  506.  
  507.     /* first apply the shift and control modifiers */
  508.     if (ctrlflag)
  509.         ekey = keytrans[code].rw_ccode;
  510.     else if (l_shiftflag || r_shiftflag || lockflag)
  511.         ekey = keytrans[code].rw_scode;
  512.     else
  513.         ekey = keytrans[code].rw_code;
  514.  
  515.     /* now apply the ALTD modifier */
  516.     if (r_altflag || l_altflag)
  517.         ekey |= ALTD;
  518.  
  519.     /* apply the META prefix */
  520.     if (r_amiflag || l_amiflag) {
  521.         if ('a' <= ekey && ekey <= 'z')
  522.             ekey -= 32;
  523.         ekey |= META;
  524.     }
  525.  
  526.     /* and place it in the input buffer */
  527.     stuffibuf(ekey, 0, 0);
  528. }
  529.  
  530. stuffibuf(key, x, y)    /* stuff a key in the input buffer */
  531.  
  532. int key;    /* extended keystroke to remember */
  533. int x, y;    /* mouse position to record */
  534.  
  535. {
  536.     register int upper;    /* upper extended bits of key */
  537.  
  538.     /* split the extended keystroke */
  539.     upper = key >> 8;
  540.     key = key & 255;
  541.  
  542.     /* if it is JUST control... encode it in! */
  543.     if (upper == (CTRL >> 8)) {
  544.         in_put(key - 64);
  545.         return;
  546.     }
  547.  
  548.     /* if it is normal, just place it inqueue */
  549.     if (upper == 0) {
  550.         in_put(key);
  551.         return;
  552.     }
  553.  
  554.     /* queue up an extended escape sequence */
  555.     in_put(0);        /* escape indicator */
  556.     in_put(upper);        /* event type */
  557.     if (upper & (MOUS >> 8)) {
  558.         in_put(x);    /* x position */
  559.         in_put(y);    /* y position */
  560.     }
  561.     in_put(key);        /* event code */
  562.     return;
  563. }
  564.  
  565. /*
  566.  * Create a subjob with a copy of the command intrepreter in it. When the
  567.  * command interpreter exits, mark the screen as garbage so that you do a full
  568.  * repaint. Bound to "^X C". The message at the start in VMS puts out a newline.
  569.  * Under some (unknown) condition, you don't get one free when DCL starts up.
  570.  */
  571. spawncli(f, n)
  572. {
  573.         long newcli;
  574.  
  575.     /* don't allow this command if restricted */
  576.     if (restflag)
  577.         return(resterr());
  578.  
  579.         mlwrite(TEXT1);
  580. /*              "[Starting new CLI]" */
  581.         sgarbf = TRUE;
  582.         Execute("NEWCLI \"CON:0/0/640/200/MicroEMACS Subprocess\"", 0L, 0L);
  583.         return(TRUE);
  584. }
  585.  
  586. /*
  587.  * Run a one-liner in a subjob. When the command returns, wait for a single
  588.  * character to be typed, then mark the screen as garbage so a full repaint is
  589.  * done. Bound to "C-X !".
  590.  */
  591. spawn(f, n)
  592. {
  593.         register int    s;
  594.         char            line[NLINE];
  595.  
  596.         long newcli;
  597.  
  598.     /* don't allow this command if restricted */
  599.     if (restflag)
  600.         return(resterr());
  601.  
  602.         if ((s=mlreply("!", line, NLINE)) != TRUE)
  603.                 return (s);
  604.         newcli = Open("CON:0/0/640/200/MicroEMACS Subprocess", NEW);
  605.         Execute(line, 0L, newcli);
  606.         Close(newcli);
  607.         tgetc();     /* Pause.               */
  608.         sgarbf = TRUE;
  609.         return(TRUE);
  610. }
  611.  
  612. /*
  613.  * Run an external program with arguments. When it returns, wait for a single
  614.  * character to be typed, then mark the screen as garbage so a full repaint is
  615.  * done. Bound to "C-X $".
  616.  */
  617.  
  618. execprg(f, n)
  619.  
  620. {
  621.         register int    s;
  622.         char            line[NLINE];
  623.  
  624.         long newcli;
  625.  
  626.     /* don't allow this command if restricted */
  627.     if (restflag)
  628.         return(resterr());
  629.  
  630.         if ((s=mlreply("!", line, NLINE)) != TRUE)
  631.                 return (s);
  632.         newcli = Open("CON:0/0/640/200/MicroEMACS Subprocess", NEW);
  633.         Execute(line, 0L, newcli);
  634.         Close(newcli);
  635.         tgetc();     /* Pause.               */
  636.         sgarbf = TRUE;
  637.         return(TRUE);
  638. }
  639.  
  640. /*
  641.  * Pipe a one line command into a window
  642.  * Bound to ^X @
  643.  */
  644. pipecmd(f, n)
  645. {
  646.         register int    s;    /* return status from CLI */
  647.     register WINDOW *wp;    /* pointer to new window */
  648.     register BUFFER *bp;    /* pointer to buffer to zot */
  649.         char    line[NLINE];    /* command line send to shell */
  650.     static char bname[] = "command";
  651.  
  652.     static char filnam[] = "ram:command";
  653.         long newcli;
  654.  
  655.     /* don't allow this command if restricted */
  656.     if (restflag)
  657.         return(resterr());
  658.  
  659.     /* get the command to pipe in */
  660.         if ((s=mlreply("@", line, NLINE)) != TRUE)
  661.                 return(s);
  662.  
  663.     /* get rid of the command output buffer if it exists */
  664.         if ((bp=bfind(bname, FALSE, 0)) != FALSE) {
  665.         /* try to make sure we are off screen */
  666.         wp = wheadp;
  667.         while (wp != NULL) {
  668.             if (wp->w_bufp == bp) {
  669.                 onlywind(FALSE, 1);
  670.                 break;
  671.             }
  672.             wp = wp->w_wndp;
  673.         }
  674.         if (zotbuf(bp) != TRUE)
  675.  
  676.             return(FALSE);
  677.     }
  678.  
  679.         newcli = Open("CON:0/0/640/200/MicroEMACS Subprocess", NEW);
  680.     strcat(line, " >");
  681.     strcat(line, filnam);
  682.         Execute(line, 0L, newcli);
  683.     s = TRUE;
  684.         Close(newcli);
  685.         sgarbf = TRUE;
  686.  
  687.     if (s != TRUE)
  688.         return(s);
  689.  
  690.     /* split the current window to make room for the command output */
  691.     if (splitwind(FALSE, 1) == FALSE)
  692.             return(FALSE);
  693.  
  694.     /* and read the stuff in */
  695.     if (getfile(filnam, FALSE) == FALSE)
  696.         return(FALSE);
  697.  
  698.     /* make this window in VIEW mode, update all mode lines */
  699.     curwp->w_bufp->b_mode |= MDVIEW;
  700.     wp = wheadp;
  701.     while (wp != NULL) {
  702.         wp->w_flag |= WFMODE;
  703.         wp = wp->w_wndp;
  704.     }
  705.  
  706.     /* and get rid of the temporary file */
  707.     unlink(filnam);
  708.     return(TRUE);
  709. }
  710.  
  711. /*
  712.  * filter a buffer through an external DOS program
  713.  * Bound to ^X #
  714.  */
  715. filter(f, n)
  716.  
  717. {
  718.         register int    s;    /* return status from CLI */
  719.     register BUFFER *bp;    /* pointer to buffer to zot */
  720.         char line[NLINE];    /* command line send to shell */
  721.     char tmpnam[NFILEN];    /* place to store real file name */
  722.     static char bname1[] = "fltinp";
  723.  
  724.     static char filnam1[] = "ram:fltinp";
  725.     static char filnam2[] = "ram:fltout";
  726.         long newcli;
  727.  
  728.     /* don't allow this command if restricted */
  729.     if (restflag)
  730.         return(resterr());
  731.  
  732.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  733.         return(rdonly());    /* we are in read only mode    */
  734.  
  735.     /* get the filter name and its args */
  736.         if ((s=mlreply("#", line, NLINE)) != TRUE)
  737.                 return(s);
  738.  
  739.     /* setup the proper file names */
  740.     bp = curbp;
  741.     strcpy(tmpnam, bp->b_fname);    /* save the original name */
  742.     strcpy(bp->b_fname, bname1);    /* set it to our new one */
  743.  
  744.     /* write it out, checking for errors */
  745.     if (writeout(filnam1, "w") != TRUE) {
  746.         mlwrite(TEXT2);
  747. /*                      "[Cannot write filter file]" */
  748.         strcpy(bp->b_fname, tmpnam);
  749.         return(FALSE);
  750.     }
  751.  
  752.         newcli = Open("CON:0/0/640/200/MicroEMACS Subprocess", NEW);
  753.     strcat(line, " <ram:fltinp >ram:fltout");
  754.         Execute(line,0L,newcli);
  755.     s = TRUE;
  756.         Close(newcli);
  757.         sgarbf = TRUE;
  758.  
  759.     /* on failure, escape gracefully */
  760.     if (s != TRUE || (readin(filnam2,FALSE) == FALSE)) {
  761.         mlwrite(TEXT3);
  762. /*                      "[Execution failed]" */
  763.         strcpy(bp->b_fname, tmpnam);
  764.         unlink(filnam1);
  765.         unlink(filnam2);
  766.         return(s);
  767.     }
  768.  
  769.     /* reset file name */
  770.     strcpy(bp->b_fname, tmpnam);    /* restore name */
  771.     bp->b_flag |= BFCHG;        /* flag it as changed */
  772.  
  773.     /* and get rid of the temporary file */
  774.     unlink(filnam1);
  775.     unlink(filnam2);
  776.     return(TRUE);
  777. }
  778.  
  779. /* return a system dependant string with the current time */
  780.  
  781. char *PASCAL NEAR timeset()
  782.  
  783. {
  784.     return(errorm);
  785. }
  786.  
  787. #if    AZTEC
  788. /*    FILE Directory routines        */
  789.  
  790. char path[NFILEN];    /* path of file to find */
  791. char rbuf[NFILEN];    /* return file buffer */
  792. extern char *scdir();
  793.  
  794. /*    do a wild card directory search (for file name completion) */
  795.  
  796. char *PASCAL NEAR getffile(fspec)
  797.  
  798. char *fspec;    /* pattern to match */
  799.  
  800. {
  801.     register int index;        /* index into various strings */
  802.     char fname[NFILEN];        /* file/path for DOS call */
  803.  
  804.     /* first parse the file path off the file spec */
  805.     strcpy(path, fspec);
  806.     index = strlen(path) - 1;
  807.     while (index >= 0 && (path[index] != '/' &&
  808.                 path[index] != '\\' && path[index] != ':'))
  809.         --index;
  810.     path[index+1] = 0;
  811.  
  812.     /* construct the composite wild card spec */
  813.     strcpy(fname, path);
  814.     strcat(fname, &fspec[index+1]);
  815.     strcat(fname, "*.*");
  816.  
  817.     /* save the path/wildcard off */
  818.     strcpy(path, fname);
  819.  
  820.     /* and call for the first file */
  821.     return(getnfile());
  822. }
  823.  
  824. char *PASCAL NEAR getnfile()
  825.  
  826. {
  827.     register char *sp;    /* return from scdir */
  828.  
  829.     /* and call for the next file */
  830.     sp = scdir(path);
  831.     if (sp == NULL)
  832.         return(NULL);
  833.  
  834.     /* return the next file name! */
  835.     strcpy(rbuf, sp);
  836.     return(rbuf);
  837. }
  838. #else
  839. char *PASCAL NEAR getffile(fspec)
  840.  
  841. char *fspec;    /* file to match */
  842.  
  843. {
  844.     return(NULL);
  845. }
  846.  
  847. char *PASCAL NEAR getnfile()
  848.  
  849. {
  850.     return(NULL);
  851. }
  852. #endif
  853.  
  854. #if    AZTEC
  855.  
  856. /*    Big flame..... AZTEC C documents, but seems to be missing the
  857.     standard library realloc() function.  A quick replacement is
  858.     below.  Note that this ALWAYS copies to a new block, and is
  859.     thus inherently less efficient than a native one would be.
  860. */
  861.  
  862. char *realloc(ptr, size)
  863.  
  864. char *ptr;    /* original pointer */
  865. int size;    /* # of bytes for newly allocated block */
  866.  
  867. {
  868.     char *src, *dest;    /* ptrs for byte copying */
  869.     char *nptr;        /* newly allocated pointer */
  870.  
  871.     /* allocate the new memory block */
  872.     nptr = malloc(size);
  873.     if (nptr == NULL)
  874.         return(NULL);
  875.  
  876.     /* copy the bytes from the old one */
  877.     src = ptr;
  878.     dest = nptr;
  879.     while (size--)
  880.         *dest++ = *src++;
  881.  
  882.     /* and free the old one */
  883.     free(ptr);
  884.     return(nptr);
  885. }
  886.  
  887. #else
  888. adoshello()
  889. {
  890. }
  891. #endif
  892.