home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / UE311C.ZIP / UNIX.C < prev    next >
C/C++ Source or Header  |  1991-07-24  |  36KB  |  1,576 lines

  1. /***
  2.     UNIX driver/Microemacs 3.10b/3.10k,
  3.     Copyright 1989/1991 D. Lawrence, C. Smith
  4.  ***/
  5.  
  6. /**
  7.     New features:
  8.  
  9.     1. Timeouts waiting on a function key have been changed from
  10.     35000 to 500000 microseconds.
  11.  
  12.     2. Additional keymapping entries can be made from the command
  13.     language by issuing a 'set $palette xxx'.  The format of
  14.     xxx is a string as follows:
  15.         "KEYMAP keybinding escape-sequence".
  16.     To add "<ESC><[><A>" as a keybinding of FNN, issue:
  17.         "KEYMAP FNN ^[[A".
  18.     Note that the escape character!  It is a read escape character
  19.     and it's pretty difficult to enter.
  20.  
  21.     3. Colors are supported.  Under AIX the colors will be pulled
  22.     in automaticly.  For other environments, you can either add
  23.     the termcap entries, C0 to D7.  Or the colors may be defined
  24.     using the command language by issuing a 'set $palette xxx'
  25.     command.  The format of xxx is a string as follows:
  26.         "CLRMAP # escape-sequence".
  27.     The number is a number from 0 to 15, where 0 to 7 is the
  28.     foreground colors, and 8 to 15 as background colors.
  29.     To add foreground color 0 for ansi terminals, issue:
  30.         "CLRMAP 0 ^[[30m".
  31.     
  32.     'Porting notes:
  33.  
  34.     I have tried to create this file so that it should work
  35.     as well as possible without changes on your part.
  36.  
  37.     However, if something does go wrong, read the following
  38.     helpful hints:
  39.  
  40.     1. On SUN-OS4, there is a problem trying to include both
  41.     the termio.h and ioctl.h files.  I wish Sun would get their
  42.     act together.  Even though you get lots of redefined messages,
  43.     it shouldn't cause any problems with the final object.
  44.  
  45.     2. In the type-ahead detection code, the individual UNIX
  46.     system either has a FIONREAD or a FIORDCHK ioctl call.
  47.     Hopefully, your system uses one of them and this be detected
  48.     correctly without any intervention.
  49.  
  50.     3. Also lookout for directory handling.  The SCO Xenix system
  51.     is the weirdest I've seen, requiring a special load file
  52.     (see below).  Some machine call the result of a readdir() call
  53.     a "struct direct" or "struct dirent".  Includes files are
  54.     named differently depending of the O/S.  If your system doesn't
  55.     have an opendir()/closedir()/readdir() library call, then
  56.     you should use the public domain utility "ndir".
  57.  
  58.     To compile:
  59.         Compile all files normally.
  60.     To link:
  61.         Select one of the following operating systems:
  62.             SCO Xenix:
  63.                 use "-ltermcap" and "-lx";
  64.             SUN 3 and 4:
  65.                 use "-ltermcap";
  66.             IBM-RT, IBM-AIX, ATT UNIX, Altos UNIX, Interactive:
  67.                 use "-lcurses".
  68. **/
  69.  
  70. /** Include files **/
  71. #include <stdio.h>            /* Standard I/O definitions    */
  72. #include "estruct.h"            /* Emacs definitions        */
  73.  
  74. /** Do nothing routine **/
  75. int scnothing()
  76. {
  77.     return(0);
  78. }
  79.  
  80. /** Only compile for UNIX machines **/
  81. #if BSD || USG || SMOS || HPUX || SUN || XENIX || AVIION
  82.  
  83. /** Include files **/
  84. #include "eproto.h"            /* Function definitions        */
  85. #include "edef.h"            /* Global variable definitions    */
  86. #include "elang.h"            /* Language definitions        */
  87.  
  88. /** Kill predefined **/
  89. #undef CTRL                /* Problems with CTRL        */
  90.  
  91. /** Overall include files **/
  92. #include <sys/types.h>            /* System type definitions    */
  93. #include <sys/stat.h>            /* File status definitions    */
  94. #include <sys/ioctl.h>            /* I/O control definitions    */
  95.  
  96. /** Additional include files **/
  97. #if BSD
  98. #include <sys/time.h>            /* Timer definitions        */
  99. #endif /* BSD */
  100. #if BSD || SUN || HPUX || AVIION
  101. #include <signal.h>            /* Signal definitions        */
  102. #endif /* BSD || SUN || HPUX || AVIION */
  103. #if USG || SMOS || HPUX || SUN || XENIX
  104. #include <termio.h>            /* Terminal I/O definitions    */
  105. #endif /* USG || SMOS || HPUX || SUN || XENIX */
  106. #if AVIION
  107. #include <termios.h>            /* Terminal I/O definitions    */
  108. #endif /* AVIION */
  109. #if CURSES
  110. #include <curses.h>            /* Curses screen output        */
  111. #undef WINDOW                /* Oh no!            */
  112. #endif /* CURSES */
  113.  
  114. /** Completion include files **/
  115. /** Directory accessing: Try and figure this out... if you can! **/
  116. #if BSD
  117. #include <sys/dir.h>            /* Directory entry definitions    */
  118. #define DIRENTRY    direct
  119. #endif /* BSD */
  120. #if XENIX
  121. #include <sys/ndir.h>            /* Directory entry definitions    */
  122. #define DIRENTRY    direct
  123. #endif /* XENIX */
  124. #if USG || SMOS || HPUX || SUN || AVIION
  125. #include <dirent.h>            /* Directory entry definitions    */
  126. #define DIRENTRY    dirent
  127. #endif /* USG || SMOS || HPUX || SUN || AVIION */
  128.  
  129. /** Restore predefined definitions **/
  130. #undef CTRL                /* Restore CTRL            */
  131. #define CTRL 0x0100
  132.  
  133. /** Parameters **/
  134. #define NKEYENT        300        /* Number of keymap entries    */
  135. #define NINCHAR        64        /* Input buffer size        */
  136. #define NOUTCHAR    256        /* Output buffer size        */
  137. #if TERMCAP
  138. #define NCAPBUF        1024        /* Termcap storage size        */
  139. #endif /* TERMCAP */
  140. #define MARGIN        8        /* Margin size            */
  141. #define SCRSIZ        64        /* Scroll for margin        */
  142. #define NPAUSE        10        /* # times thru update to pause */
  143.  
  144. /** CONSTANTS **/
  145. #define TIMEOUT        255        /* No character available    */
  146.  
  147. /** Type definitions **/
  148. struct keyent {                /* Key mapping entry        */
  149.     struct keyent * samlvl;        /* Character on same level    */
  150.     struct keyent * nxtlvl;        /* Character on next level    */
  151.     unsigned char ch;        /* Character            */
  152.     int code;            /* Resulting keycode        */
  153. };
  154. #if TERMCAP
  155. struct capbind {            /* Capability binding entry    */
  156.     char * name;            /* Termcap name            */
  157.     char * store;            /* Storage variable        */
  158. };
  159. struct keybind {            /* Keybinding entry        */
  160.     char * name;            /* Termcap name            */
  161.     int value;            /* Binding value        */
  162. };
  163. #endif /* TERMCAP */
  164.  
  165. /** Local variables **/
  166. #if BSD
  167. static struct sgttyb cursgtty;        /* Current modes        */
  168. static struct sgttyb oldsgtty;        /* Original modes        */
  169. static struct tchars oldtchars;        /* Current tchars        */
  170. static struct ltchars oldlchars;    /* Current ltchars        */
  171. static char blank[6] =            /* Blank out character set    */
  172.     { -1, -1, -1, -1, -1, -1 };
  173. #endif /* BSD */
  174. #if USG || SMOS || HPUX || SUN || XENIX
  175. static struct termio curterm;        /* Current modes        */
  176. static struct termio oldterm;        /* Original modes        */
  177. #endif /* USG || SMOS || HPUX || SUN || XENIX */
  178. #if AVIION
  179. static struct termios curterm;        /* Current modes        */
  180. static struct termios oldterm;        /* Original modes        */
  181. #endif /* AVIION */
  182. #if TERMCAP
  183. static char tcapbuf[NCAPBUF];        /* Termcap character storage    */
  184. #define CAP_CL        0        /* Clear to end of page        */
  185. #define CAP_CM        1        /* Cursor motion        */
  186. #define CAP_CE        2        /* Clear to end of line        */
  187. #define CAP_SE        3        /* Standout ends        */
  188. #define CAP_SO        4        /* Standout (reverse video)    */
  189. #define CAP_IS        5        /* Initialize screen        */
  190. #define CAP_KS        6        /* Keypad mode starts        */
  191. #define CAP_KE        7        /* Keypad mode ends        */
  192. #define CAP_VB        8        /* Visible bell            */
  193. #if COLOR
  194. #define CAP_C0        9        /* Foreground color #0        */
  195. #define CAP_C1        10        /* Foreground color #1        */
  196. #define CAP_C2        11        /* Foreground color #2        */
  197. #define CAP_C3        12        /* Foreground color #3        */
  198. #define CAP_C4        13        /* Foreground color #4        */
  199. #define CAP_C5        14        /* Foreground color #5        */
  200. #define CAP_C6        15        /* Foreground color #6        */
  201. #define CAP_C7        16        /* Foreground color #7        */
  202. #define CAP_D0        17        /* Background color #0        */
  203. #define CAP_D1        18        /* Background color #1        */
  204. #define CAP_D2        19        /* Background color #2        */
  205. #define CAP_D3        20        /* Background color #3        */
  206. #define CAP_D4        21        /* Background color #4        */
  207. #define CAP_D5        22        /* Background color #5        */
  208. #define CAP_D6        23        /* Background color #6        */
  209. #define CAP_D7        24        /* Background color #7        */
  210. #endif /* COLOR */
  211. static struct capbind capbind[] = {    /* Capability binding list    */
  212.     { "cl" },            /* Clear to end of page        */
  213.     { "cm" },            /* Cursor motion        */
  214.     { "ce" },            /* Clear to end of line        */
  215.     { "se" },            /* Standout ends        */
  216.     { "so" },            /* Standout (reverse video)    */
  217.     { "is" },            /* Initialize screen        */
  218.     { "ks" },            /* Keypad mode starts        */
  219.     { "ke" },            /* Keypad mode ends        */
  220.     { "vb" },            /* Visible bell            */
  221. #if COLOR
  222.     { "c0" },            /* Foreground color #0        */
  223.     { "c1" },            /* Foreground color #1        */
  224.     { "c2" },            /* Foreground color #2        */
  225.     { "c3" },            /* Foreground color #3        */
  226.     { "c4" },            /* Foreground color #4        */
  227.     { "c5" },            /* Foreground color #5        */
  228.     { "c6" },            /* Foreground color #6        */
  229.     { "c7" },            /* Foreground color #7        */
  230.     { "d0" },            /* Background color #0        */
  231.     { "d1" },            /* Background color #1        */
  232.     { "d2" },            /* Background color #2        */
  233.     { "d3" },            /* Background color #3        */
  234.     { "d4" },            /* Background color #4        */
  235.     { "d5" },            /* Background color #5        */
  236.     { "d6" },            /* Background color #6        */
  237.     { "d7" }            /* Background color #7        */
  238. #endif /* COLOR */
  239. };
  240. #if COLOR
  241. static int cfcolor = -1;        /* Current forground color    */
  242. static int cbcolor = -1;        /* Current background color    */
  243. #endif /* COLOR */
  244. static struct keybind keybind[] = {    /* Keybinding list        */
  245.     { "bt", SHFT|CTRL|'i' },    /* Back-tab key            */
  246.     { "k1", SPEC|'1' },        /* F1 key            */
  247.     { "k2", SPEC|'2' },        /* F2 key            */
  248.     { "k3", SPEC|'3' },        /* F3 key            */
  249.     { "k4", SPEC|'4' },        /* F4 key            */
  250.     { "k5", SPEC|'5' },        /* F5 key            */
  251.     { "k6", SPEC|'6' },        /* F6 key            */
  252.     { "k7", SPEC|'7' },        /* F7 key            */
  253.     { "k8", SPEC|'8' },        /* F8 key            */
  254.     { "k9", SPEC|'9' },        /* F9 key            */
  255.     { "k0", SPEC|'0' },        /* F0 or F10 key        */
  256.     { "kA", CTRL|'O' },        /* Insert line key        */
  257.     { "kb", CTRL|'H' },        /* Backspace key        */
  258.     { "kC", CTRL|'L' },        /* Clear screen key        */
  259.     { "kD", SPEC|'D' },        /* Delete character key        */
  260.     { "kd", SPEC|'N' },        /* Down arrow key        */
  261.     { "kE", CTRL|'K' },        /* Clear to end of line key    */
  262.     { "kF", CTRL|'V' },        /* Scroll forward key        */
  263.     { "kH", SPEC|'>' },        /* Home down key        */
  264.     { "kh", SPEC|'<' },        /* Home key            */
  265.     { "kI", SPEC|'C' },        /* Insert character key        */
  266.     { "kL", CTRL|'K' },        /* Delete line key        */
  267.     { "kl", SPEC|'B' },        /* Left arrow key        */
  268.     { "kN", SPEC|'V' },        /* Next page key        */
  269.     { "kP", SPEC|'Z' },        /* Previous page key        */
  270.     { "kR", CTRL|'Z' },        /* Scroll backward key        */
  271.     { "kr", SPEC|'F' },        /* Right arrow key        */
  272.     { "ku", SPEC|'P' }        /* Up arrow key            */
  273. };
  274. #endif /* TERMCAP */
  275. static int inbuf[NINCHAR];        /* Input buffer            */
  276. static int * inbufh =            /* Head of input buffer        */
  277.     inbuf;
  278. static int * inbuft =            /* Tail of input buffer        */
  279.     inbuf;
  280. #if TERMCAP
  281. static unsigned char outbuf[NOUTCHAR];    /* Output buffer        */
  282. static unsigned char * outbuft =     /* Output buffer tail        */
  283.     outbuf;
  284. #endif /* TERMCAP */
  285. static unsigned char keyseq[256];    /* Prefix escape sequence table    */
  286. static struct keyent keymap[NKEYENT];    /* Key map            */
  287. static struct keyent * nxtkey =        /* Next free key entry        */
  288.     keymap;
  289. static DIR *dirptr = NULL;        /* Current directory stream    */
  290. static char path[NFILEN];        /* Path of file to find        */
  291. static char rbuf[NFILEN];        /* Return file buffer        */
  292. static char *nameptr;            /* Ptr past end of path in rbuf    */
  293.  
  294. /** Terminal definition block **/
  295. int scopen(), scclose(), ttgetc(), ttputc(), ttflush();
  296. int scmove(), sceeol(), sceeop(), scbeep(), screv();
  297. #if COLOR
  298. int scfcol(), scbcol();
  299. #endif /* COLOR */
  300. TERM term = {
  301.     60,                /* Maximum number of rows    */
  302.     0,                /* Current number of rows    */
  303.     132,                /* Maximum number of columns    */
  304.     0,                /* Current number of columns    */
  305.     MARGIN,                /* Margin for extending lines    */
  306.     SCRSIZ,                /* Scroll size for extending    */
  307.     NPAUSE,                /* # times thru update to pause    */
  308.     scopen,                /* Open terminal routine    */
  309.     scclose,            /* Close terminal routine    */
  310.     scnothing,            /* Open keyboard routine    */
  311.     scnothing,            /* Close keyboard routine    */
  312.     ttgetc,                /* Get character routine    */
  313.     ttputc,                /* Put character routine    */
  314.     ttflush,            /* Flush output routine        */
  315.     scmove,                /* Move cursor routine        */
  316.     sceeol,                /* Erase to end of line routine    */
  317.     sceeop,                /* Erase to end of page routine    */
  318.     scbeep,                /* Beep! routine        */
  319.     screv,                /* Set reverse video routine    */
  320.     scnothing,            /* Set resolution routine    */
  321. #if COLOR
  322.     scfcol,                /* Set forground color routine    */
  323.     scbcol                /* Set background color routine    */
  324. #endif /* COLOR */
  325. };
  326.  
  327. /** Open terminal device **/
  328. int ttopen()
  329. {
  330. #if BSD
  331.     /* Get tty modes */
  332.     if (ioctl(0, TIOCGETP, &oldsgtty) ||
  333.         ioctl(0, TIOCGETC, &oldtchars) ||
  334.         ioctl(0, TIOCGLTC, &oldlchars))
  335.         return(-1);
  336.  
  337.     /* Save to original mode variables */
  338.     cursgtty = oldsgtty;
  339.  
  340.     /* Set new modes */
  341.     cursgtty.sg_flags |= CBREAK;
  342.     cursgtty.sg_flags &= ~(ECHO|CRMOD);
  343.  
  344.     /* Set tty modes */
  345.     if (ioctl(0, TIOCSETP, &cursgtty) ||
  346.         ioctl(0, TIOCSETC, blank) ||
  347.         ioctl(0, TIOCSLTC, blank))
  348.         return(-1);
  349. #endif /* BSD */
  350. #if USG || SMOS || HPUX || SUN || XENIX
  351.  
  352. #if SMOS
  353.     /* Extended settings; 890619mhs A3 */
  354.     set_parm(0,-1,-1);
  355. #endif /* SMOS */
  356.  
  357.     /* Get modes */
  358.     if (ioctl(0, TCGETA, &oldterm)) {
  359.         perror("Cannot TCGETA");
  360.         return(-1);
  361.     }
  362.  
  363.     /* Save to original mode variable */
  364.     curterm = oldterm;
  365.  
  366.     /* Set new modes */
  367.     curterm.c_iflag &= ~(INLCR|ICRNL|IGNCR);
  368.     curterm.c_lflag &= ~(ICANON|ISIG|ECHO);
  369.     curterm.c_cc[VMIN] = 1;
  370.     curterm.c_cc[VTIME] = 0;
  371.  
  372. #if SMOS
  373.     /****THIS IS A BIG GUESS ON MY PART... the code changed
  374.       too much between versions for me to be sure this will work - DML */
  375.  
  376.     /* Allow multiple (dual) sessions if already enabled */
  377.     curterm.c_lflag = oldterm.c_lflag & ISIG;
  378.  
  379.     /* Use old SWTCH char if necessary */
  380.     if (curterm.c_lflag != 0)
  381.         curterm.c_cc[VSWTCH] = oldterm.c_cc[VSWTCH];
  382.  
  383.     /* Copy VTI settings    */
  384.     curterm.c_cc[VTBIT] = oldterm.c_cc[VTBIT];
  385.  
  386.     /* Extended settings; 890619mhs A3 */
  387.     set_parm(0,-1,-1);
  388. #endif /* SMOS */
  389.  
  390.     /* Set tty mode */
  391.     if (ioctl(0, TCSETA, &curterm)) {
  392.         perror("Cannot TCSETA");
  393.         return(-1);
  394.     }
  395. #endif /* USG || SMOS || HPUX || SUN || XENIX */
  396. #if AVIION
  397.     /* Get modes */
  398.     if (tcgetattr(0, &oldterm)) {
  399.         perror("Cannot tcgetattr");
  400.         return(-1);
  401.     }
  402.  
  403.     /* Save to original mode variable */
  404.     curterm = oldterm;
  405.  
  406.     /* Set new modes */
  407.     curterm.c_iflag &= ~(INLCR|ICRNL|IGNCR);
  408.     curterm.c_lflag &= ~(ICANON|ISIG|ECHO);
  409.     curterm.c_cc[VMIN] = 1;
  410.     curterm.c_cc[VTIME] = 0;
  411.  
  412. #if AVIION
  413.     /* Set line discipline for Data General */
  414.     curterm.c_line = 0;
  415. #endif /* AVIION */
  416.  
  417.     /* Set tty mode */
  418.     if (tcsetattr(0, TCSANOW, &curterm)) {
  419.         perror("Cannot tcsetattr");
  420.         return(-1);
  421.     }
  422. #endif /* AVIION */
  423.  
  424.     /* Success */
  425.     return(0);
  426. }
  427.  
  428. /** Close terminal device **/
  429. int ttclose()
  430. {
  431.     /* Restore original terminal modes */
  432. #if BSD
  433.     if (ioctl(0, TIOCSETP, &oldsgtty) ||
  434.         ioctl(0, TIOCSETC, &oldtchars) ||
  435.         ioctl(0, TIOCSLTC, &oldlchars))
  436.         return(-1);
  437. #endif /* BSD */
  438.  
  439. #if USG || SMOS || HPUX || SUN || XENIX
  440. #if SMOS
  441.     /* Extended settings; 890619mhs A3 */
  442.     set_parm(0,-1,-1);
  443. #endif /* SMOS */
  444.     if (ioctl(0, TCSETA, &oldterm))
  445.         return(-1);
  446. #endif /* USG || SMOS || HPUX || SUN || XENIX */
  447.  
  448. #if AVIION
  449.     /* Set tty mode */
  450.     if (tcsetattr(0, TCSANOW, &oldterm))
  451.         return(-1);
  452. #endif /* AVIION */
  453.  
  454.     /* Success */
  455.     return(0);
  456. }
  457.  
  458. /** Flush output buffer to display **/
  459. int ttflush()
  460. {
  461. #if TERMCAP
  462.     int len;
  463.  
  464.     /* Compute length of write */
  465.     len = outbuft - outbuf;
  466.     if (len == 0)
  467.         return(0);
  468.  
  469.     /* Reset buffer position */
  470.     outbuft = outbuf;
  471.  
  472.     /* Perform write to screen */
  473.     return(write(1, outbuf, len) != len);
  474. #endif /* TERMCAP */
  475.  
  476. #if CURSES
  477.     refresh();
  478. #endif /* CURSES */
  479.  
  480.     return(0);
  481. }
  482.  
  483. /** Put character onto display **/
  484. int ttputc(ch)
  485. char ch;                /* Character to display        */
  486. {
  487. #if TERMCAP
  488.     /* Check for buffer full */
  489.     if (outbuft == &outbuf[sizeof(outbuf)])
  490.         ttflush();
  491.  
  492.     /* Add to buffer */
  493.     *outbuft++ = ch;
  494. #endif /* TERMCAP */
  495.  
  496. #if CURSES
  497.     /* Put character on screen */
  498.     addch(ch);
  499. #endif /* CURSES */
  500.  
  501.     return(0);
  502. }
  503.  
  504. /** Add character sequence to keycode entry **/
  505. void addkey(seq, fn)
  506. unsigned char * seq;            /* Character sequence        */
  507. int fn;                    /* Resulting keycode        */
  508. {
  509.     int first;
  510.     struct keyent * cur, * nxtcur;
  511.  
  512.     /* Skip on null sequences */
  513.     if (!seq)
  514.         return;
  515.  
  516.     /* Skip single character sequences */
  517.     if (strlen(seq) < 2)
  518.         return;
  519.  
  520.     /* If no keys defined, go directly to insert mode */
  521.     first = 1;
  522.     if (nxtkey != keymap) {
  523.         
  524.         /* Start at top of key map */
  525.         cur = keymap;
  526.         
  527.         /* Loop until matches exhast */
  528.         while (*seq) {
  529.             
  530.             /* Do we match current character */
  531.             if (*seq == cur->ch) {
  532.                 
  533.                 /* Advance to next level */
  534.                 seq++;
  535.                 cur = cur->nxtlvl;
  536.                 first = 0;
  537.             } else {
  538.                 
  539.                 /* Try next character on same level */
  540.                 nxtcur = cur->samlvl;
  541.                 
  542.                 /* Stop if no more */
  543.                 if (nxtcur)
  544.                     cur = nxtcur;
  545.                 else
  546.                     break;
  547.             }
  548.         }
  549.     }
  550.     
  551.     /* Check for room in keymap */
  552.     if (strlen(seq) > NKEYENT - (nxtkey - keymap))
  553.         return;
  554.         
  555.     /* If first character in sequence is inserted, add to prefix table */
  556.     if (first)
  557.         keyseq[*seq] = 1;
  558.         
  559.     /* If characters are left over, insert them into list */
  560.     for (first = 1; *seq; first = 0) {
  561.         
  562.         /* Make new entry */
  563.         nxtkey->ch = *seq++;
  564.         nxtkey->code = fn;
  565.         
  566.         /* If root, nothing to do */
  567.         if (nxtkey != keymap) {
  568.             
  569.             /* Set first to samlvl, others to nxtlvl */
  570.             if (first)
  571.                 cur->samlvl = nxtkey;
  572.             else
  573.                 cur->nxtlvl = nxtkey;
  574.         }
  575.  
  576.         /* Advance to next key */
  577.         cur = nxtkey++;
  578.     }
  579. }
  580.  
  581. /** Grab input characters, with wait **/
  582. unsigned char grabwait()
  583. {
  584. #if BSD
  585.     unsigned char ch;
  586.  
  587.     /* Perform read */
  588.     if (read(0, &ch, 1) != 1) {
  589.         puts("** Horrible read error occured **");
  590.         exit(1);
  591.     }
  592.     return(ch);
  593. #endif /* BSD */
  594. #if USG || SMOS || HPUX || SUN || XENIX || AVIION
  595.     unsigned char ch;
  596.  
  597.     /* Change mode, if necessary */
  598.     if (curterm.c_cc[VTIME]) {
  599.         curterm.c_cc[VMIN] = 1;
  600.         curterm.c_cc[VTIME] = 0;
  601. #if USG || SMOS || HPUX || SUN || XENIX
  602.         ioctl(0, TCSETA, &curterm);
  603. #endif /* USG || SMOS || HPUX || SUN || XENIX */
  604. #if AVIION
  605.         tcsetattr(0, TCSANOW, &curterm);
  606. #endif /* AVIION */        
  607.     }
  608.  
  609.     /* Perform read */
  610.     if (read(0, &ch, 1) != 1) {
  611.         puts("** Horrible read error occured **");
  612.         exit(1);
  613.     }
  614.  
  615.     /* Return new character */
  616.     return(ch);
  617. #endif /* USG || SMOS || HPUX || SUN || XENIX || AVIION */
  618. }
  619.  
  620. /** Grab input characters, short wait **/
  621. unsigned char grabnowait()
  622. {
  623. #if BSD
  624.     static struct timeval timout = { 0, 500000L };
  625.     int count, r;
  626.  
  627.     /* Select input */
  628.     r = 1;
  629.     count = select(1, &r, NULL, NULL, &timout);
  630.     if (count == 0)
  631.         return(TIMEOUT);
  632.     if (count < 0) {
  633.         puts("** Horrible select error occured **");
  634.         exit(1);
  635.     }
  636.  
  637.     /* Perform read */
  638.     return(grabwait());
  639. #endif /* BSD */
  640. #if USG || SMOS || HPUX || SUN || XENIX || AVIION
  641.     int count;
  642.     unsigned char ch;
  643.  
  644.     /* Change mode, if necessary */
  645.     if (curterm.c_cc[VTIME] == 0) {
  646.         curterm.c_cc[VMIN] = 0;
  647.         curterm.c_cc[VTIME] = 5;
  648. #if USG || SMOS || HPUX || SUN || XENIX
  649.         ioctl(0, TCSETA, &curterm);
  650. #endif /* USG || SMOS || HPUX || SUN || XENIX */
  651. #if AVIION
  652.         tcsetattr(0, TCSANOW, &curterm);
  653. #endif /* AVIION */        
  654.     }
  655.  
  656.     /* Perform read */
  657.     count = read(0, &ch, 1);
  658.     if (count < 0) {
  659.         puts("** Horrible read error occured **");
  660.         exit(1);
  661.     }
  662.     if (count == 0)
  663.         return(TIMEOUT);
  664.  
  665.     /* Return new character */
  666.     return(ch);
  667. #endif /* USG || SMOS || HPUX || SUN || XENIX || AVIION */
  668. }
  669.  
  670. /** Queue input character **/
  671. void qin(ch)
  672. int ch;                    /* Character to add        */
  673. {
  674.     /* Check for overflow */
  675.     if (inbuft == &inbuf[sizeof(inbuf)]) {
  676.         
  677.         /* Annoy user */
  678.         scbeep();
  679.         return;
  680.     }
  681.     
  682.     /* Add character */
  683.     *inbuft++ = ch;
  684. }
  685.  
  686. /** Cook input characters **/
  687. void cook()
  688. {
  689.     unsigned char ch;
  690.     struct keyent * cur;
  691.     
  692.     /* Get first character untimed */
  693.     ch = grabwait();
  694.     qin(ch);
  695.     
  696.     /* Skip if the key isn't a special leading escape sequence */
  697.     if (keyseq[ch] == 0)
  698.         return;
  699.  
  700.     /* Start at root of keymap */
  701.     cur = keymap;
  702.  
  703.     /* Loop until keymap exhasts */
  704.     while (cur) {
  705.  
  706.         /* Did we find a matching character */
  707.         if (cur->ch == ch) {
  708.  
  709.             /* Is this the end */
  710.             if (cur->nxtlvl == NULL) {
  711.  
  712.                 /* Replace all character with new sequence */
  713.                 inbuft = inbuf;
  714.                 qin(cur->code);
  715.                 return;
  716.             } else {
  717.                 /* Advance to next level */
  718.                 cur = cur->nxtlvl;
  719.             
  720.                 /* Get next character, timed */
  721.                 ch = grabnowait();
  722.                 if (ch == TIMEOUT)
  723.                     return;
  724.  
  725.                 /* Queue character */
  726.                 qin(ch);
  727.             }
  728.         } else
  729.             /* Try next character on same level */
  730.             cur = cur->samlvl;
  731.     }
  732. }
  733.  
  734. /** Return cooked characters **/
  735. int ttgetc()
  736. {
  737.     int ch;
  738.  
  739.     /* Loop until character found */
  740.     while (1) {
  741.     
  742.         /* Get input from buffer, if available */
  743.         if (inbufh != inbuft) {
  744.             ch = *inbufh++;
  745.             if (inbufh == inbuft)
  746.                 inbufh = inbuft = inbuf;
  747.             break;
  748.         } else
  749.  
  750.             /* Fill input buffer */
  751.             cook();
  752.     }
  753.     
  754.     /* Return next character */
  755.     return(ch);
  756. }
  757.  
  758. #if TYPEAH
  759. int typahead()
  760. {
  761.     int count;
  762.  
  763.     /* See if internal buffer is non-empty */
  764.     if (inbufh != inbuft)
  765.         return(1);
  766.  
  767.     /* Now check with system */
  768. #ifdef FIONREAD  /* Watch out!  This could bite you! */
  769.     /* Get number of pending characters */
  770.     if (ioctl(0, FIONREAD, &count))
  771.         return(0);
  772.     return(count);
  773. #else /* not FIONREAD */
  774.     /* Ask hardware for count */
  775.     count = ioctl(0, FIORDCHK, 0);
  776.     if (count < 0)
  777.         return(0);
  778.     return(count);
  779. #endif /* FIONREAD */
  780. }
  781. #endif /* TYPEAH */
  782.  
  783. #if TERMCAP
  784. /** Put out sequence, with padding **/
  785. void putpad(seq)
  786. char * seq;                /* Character sequence        */
  787. {
  788.     /* Check for null */
  789.     if (!seq)
  790.         return;
  791.  
  792.     /* Call on termcap to send sequence */
  793.     tputs(seq, 1, ttputc);
  794. }
  795. #endif /* TERMCAP */
  796.  
  797. /** Initialize screen package **/
  798. int scopen()
  799. {
  800. #if TERMCAP
  801.     char * cp, tcbuf[1024];
  802.     int status;
  803.     struct capbind * cb;
  804.     struct keybind * kp;
  805.  
  806.     char * getenv(), * tgetstr();
  807. #if HPUX
  808.     /* HP-UX doesn't seem to have these in the termcap library */
  809.     char PC, * UP;
  810.     short ospeed;
  811. #else /* not HPUX */
  812.     extern char PC, * UP;
  813.     extern short ospeed;
  814. #endif /* HPUX */
  815.  
  816.     /* Get terminal type */
  817.     cp = getenv("TERM");
  818.     if (!cp) {
  819.         puts("Environment variable \"TERM\" not define!");
  820.         exit(1);
  821.     }
  822.  
  823.     /* Try to load termcap */
  824.     status = tgetent(tcbuf, cp);
  825.     if (status == -1) {
  826.         puts("Cannot open termcap file");
  827.         exit(1);
  828.     }
  829.     if (status == 0) {
  830.         printf("No entry for terminal type \"%s\"\n", cp);
  831.         exit(1);
  832.     }
  833.  
  834.     /* Get size from termcap */
  835.     term.t_nrow = tgetnum("li") - 1;
  836.     term.t_ncol = tgetnum("co");
  837.     if (term.t_nrow < 3 || term.t_ncol < 3) {
  838.         puts("Screen size is too small!");
  839.         exit(1);
  840.     }
  841.  
  842.     /* Start grabbing termcap commands */
  843.     cp = tcapbuf;
  844.  
  845.     /* Get the pad character */
  846.     if (tgetstr("pc", &cp))
  847.         PC = tcapbuf[0];
  848.  
  849.     /* Get up line capability */
  850.     UP = tgetstr("up", &cp);
  851.  
  852.     /* Get other capabilities */
  853.     cb = capbind;
  854.     while (cb < &capbind[sizeof(capbind)/sizeof(*capbind)]) {
  855.         cb->store = tgetstr(cb->name, &cp);
  856.         cb++;
  857.     }
  858.  
  859.     /* Check for minimum */
  860.     if (!capbind[CAP_CL].store && (!capbind[CAP_CM].store || !UP)) {
  861.         puts("This terminal doesn't have enough power to run microEmacs!");
  862.         exit(1);
  863.     }
  864.  
  865.     /* Set reverse video and erase to end of line */
  866.     if (capbind[CAP_SO].store && capbind[CAP_SE].store)
  867.         revexist = TRUE;
  868.     if (!capbind[CAP_CE].store)
  869.         eolexist = FALSE;
  870.  
  871.     /* Get keybindings */
  872.     kp = keybind;
  873.     while (kp < &keybind[sizeof(keybind)/sizeof(*keybind)]) {
  874.         addkey(tgetstr(kp->name, &cp), kp->value);
  875.         kp++;
  876.     }
  877.  
  878.     /* Open terminal device */
  879.     if (ttopen()) {
  880.         puts("Cannot open terminal");
  881.         exit(1);
  882.     }
  883.  
  884.     /* Set speed for padding sequences */
  885. #if BSD
  886.     ospeed = cursgtty.sg_ospeed;
  887. #endif /* BSD */
  888. #if USG || SMOS || HPUX || SUN || XENIX
  889.     ospeed = curterm.c_cflag & CBAUD;
  890. #endif /* USG || SMOS || HPUX || SUN || XENIX */
  891. #if AVIION
  892.     ospeed = cfgetospeed(&curterm);
  893. #endif /* AVIION */
  894.     
  895.     /* Send out initialization sequences */
  896.     putpad(capbind[CAP_IS].store);
  897.     putpad(capbind[CAP_KS].store);
  898. #endif /* TERMCAP */
  899.  
  900. #if CURSES
  901.     /* Initialize screen */
  902.     initscr();
  903.  
  904.     /* Set size of screen */
  905.     term.t_nrow = LINES - 1;
  906.     term.t_ncol = COLS;
  907.  
  908.     /* Open terminal device */
  909.     if (ttopen()) {
  910.         puts("Cannot open terminal");
  911.         exit(1);
  912.     }
  913. #endif /* CURSES */
  914.  
  915.     /* Success */
  916.     return(0);
  917. }
  918.  
  919. /** Close screen package **/
  920. int scclose()
  921. {
  922. #if TERMCAP
  923.     /* Turn off keypad mode */
  924.     putpad(capbind[CAP_KE].store);
  925.  
  926.     /* Close terminal device */
  927.     ttclose();
  928. #endif /* TERMCAP */
  929.  
  930. #if CURSES
  931.     /* Turn off curses */
  932.     endwin();
  933.  
  934.     /* Close terminal device */
  935.     ttclose();
  936. #endif /* CURSES */
  937.     /* Success */
  938.     return(0);
  939. }
  940.  
  941. /** Move cursor **/
  942. int scmove(row, col)
  943. int row;                /* Row number            */
  944. int col;                /* Column number        */
  945. {
  946. #if TERMCAP
  947.     /* Call on termcap to create move sequence */
  948.     putpad(tgoto(capbind[CAP_CM].store, col, row));
  949. #endif /* TERMCAP */
  950.  
  951. #if CURSES
  952.     move(row, col);
  953. #endif /* CURSES */
  954.  
  955.     /* Success */
  956.     return(0);
  957. }
  958.  
  959. /** Erase to end of line **/
  960. int sceeol()
  961. {
  962. #if TERMCAP
  963.     /* Send erase sequence */
  964.     putpad(capbind[CAP_CE].store);
  965. #endif /* TERMCAP */
  966.  
  967. #if CURSES
  968.     clrtoeol();
  969. #endif /* CURSES */
  970.  
  971.     /* Success */
  972.     return(0);
  973. }
  974.  
  975. /** Clear screen **/
  976. int sceeop()
  977. {
  978. #if TERMCAP
  979. #if COLOR
  980.     scfcol(gfcolor);
  981.     scbcol(gbcolor);
  982. #endif /* COLOR */
  983.     /* Send clear sequence */
  984.     putpad(capbind[CAP_CL].store);
  985. #endif /* TERMCAP */
  986.  
  987. #if CURSES
  988.     erase();
  989. #endif /* CURSES */
  990.  
  991.  
  992.     /* Success */
  993.     return(0);
  994. }
  995.  
  996. /** Set reverse video state **/
  997. int screv(state)
  998. int state;                /* New state            */
  999. {
  1000. #if TERMCAP
  1001. #if COLOR
  1002.     int ftmp, btmp;        /* temporaries for colors */
  1003. #endif /* COLOR */
  1004.  
  1005.     /* Set reverse video state */
  1006.     putpad(state ? capbind[CAP_SO].store : capbind[CAP_SE].store);
  1007.  
  1008. #if COLOR
  1009.     if (state == FALSE) {
  1010.         ftmp = cfcolor;
  1011.         btmp = cbcolor;
  1012.         cfcolor = -1;
  1013.         cbcolor = -1;
  1014.         scfcol(ftmp);
  1015.         scbcol(btmp);
  1016.     }
  1017. #endif /* COLOR */
  1018. #endif /* TERMCAP */
  1019.  
  1020. #if CURSES
  1021.     if (state)
  1022.         standout();
  1023.     else
  1024.         standend();
  1025. #endif /* CURSES */
  1026.  
  1027.     /* Success */
  1028.     return(0);
  1029. }
  1030.  
  1031. /** Beep **/
  1032. scbeep()
  1033. {
  1034. #if TERMCAP
  1035. #if !NOISY
  1036.     /* Send out visible bell, if it exists */
  1037.     if (capbind[CAP_VB].store)
  1038.         putpad(capbind[CAP_VB].store);
  1039.     else
  1040. #endif /* not NOISY */
  1041.         /* The old standby method */
  1042.         ttputc('\7');
  1043. #endif /* TERMCAP */
  1044.  
  1045. #if CURSES
  1046.     addch('\7');        /* FIX THIS! beep() and flash comes up undefined */
  1047. #endif /* CURSES */
  1048.  
  1049.     /* Success */
  1050.     return(0);
  1051. }
  1052.  
  1053. #if COLOR
  1054. /** Set foreground color **/
  1055. int scfcol(color)
  1056. int color;        /* Color to set            */
  1057. {
  1058. #if TERMCAP
  1059.     /* Skip if already the correct color */
  1060.     if (color == cfcolor)
  1061.         return(0);
  1062.  
  1063.     /* Skip if color isn't defined */
  1064.     if (!capbind[CAP_C0].store)
  1065.         return(0);
  1066.  
  1067.     /* Send out color sequence */
  1068.     putpad(capbind[CAP_C0 + (color & 7)].store);
  1069.  
  1070.     /* Set current color */
  1071.     cfcolor = color;
  1072. #endif /* TERMCAP */
  1073.  
  1074. #if CURSES
  1075.     /* ? */
  1076. #endif /* CURSES */
  1077.     return(0);
  1078. }
  1079.  
  1080. /** Set background color **/
  1081. int scbcol(color)
  1082. int color;            /* Color to set            */
  1083. {
  1084. #if TERMCAP
  1085.     /* Skip if already the correct color */
  1086.     if (color == cbcolor)
  1087.         return(0);
  1088.  
  1089.     /* Skip if color isn't defined */
  1090.     if (!capbind[CAP_C0].store)
  1091.         return(0);
  1092.  
  1093.     /* Send out color sequence */
  1094.     putpad(capbind[CAP_D0 + (color & 7)].store);
  1095.  
  1096.     /* Set current color */
  1097.         cbcolor = color;
  1098. #endif /* TERMCAP */
  1099.  
  1100. #if CURSES
  1101.     /* ? */
  1102. #endif /* CURSES */
  1103.     return(0);
  1104. }
  1105. #endif /* COLOR */
  1106.  
  1107. /** Set palette **/
  1108. int spal(cmd)
  1109. char * cmd;                /* Palette command        */
  1110. {
  1111.     int code, dokeymap;
  1112.     char * cp;
  1113.  
  1114.     /* Check for keymapping command */
  1115.     if (strncmp(cmd, "KEYMAP ", 7) == 0)
  1116.         dokeymap = 1;
  1117.     else
  1118. #if TERMCAP
  1119. #if COLOR
  1120.     if (strncmp(cmd, "CLRMAP ", 7) == 0)
  1121.         dokeymap = 0;
  1122.     else
  1123. #endif /* COLOR */
  1124. #endif /* TERMCAP */
  1125.         return(0);
  1126.     cmd += 7;
  1127.  
  1128.     /* Look for space */
  1129.     for (cp = cmd; *cp != '\0'; cp++)
  1130.         if (*cp == ' ') {
  1131.             *cp++ = '\0';
  1132.             break;
  1133.         }
  1134.     if (*cp == '\0')
  1135.         return(1);
  1136.  
  1137.     /* Perform operation */
  1138.     if (dokeymap) {
  1139.  
  1140.         /* Convert to keycode */
  1141.         code = stock(cmd);
  1142.  
  1143.         /* Add to tree */
  1144.         addkey(cp, code);
  1145.     }
  1146. #if TERMCAP
  1147. #if COLOR
  1148.     else {
  1149.  
  1150.         /* Convert to color number */
  1151.         code = atoi(cmd);
  1152.         if (code < 0 || code > 15)
  1153.             return(1);
  1154.  
  1155.         /* Move color code to capability structure */
  1156.         capbind[CAP_C0 + code].store = malloc(strlen(cp) + 1);
  1157.         if (capbind[CAP_C0 + code].store)
  1158.             strcpy(capbind[CAP_C0 + code].store, cp);
  1159.     }
  1160. #endif /* COLOR */
  1161. #endif /* TERMCAP */
  1162.     return(0);
  1163. }
  1164.  
  1165. #if BSD || SUN || HPUX || AVIION
  1166. /* Surely more than just BSD systems do this */
  1167.  
  1168. /** Perform a stop signal **/
  1169. int bktoshell(f, n)
  1170. {
  1171.     /* Reset the terminal and go to the last line */
  1172.     vttidy();
  1173.     
  1174.     /* Okay, stop... */
  1175.     kill(getpid(), SIGTSTP);
  1176.  
  1177.     /* We should now be back here after resuming */
  1178.  
  1179.     /* Reopen the screen and redraw */
  1180.     scopen();
  1181.     curwp->w_flag = WFHARD;
  1182.     sgarbf = TRUE;
  1183.  
  1184.     /* Success */
  1185.     return(0);
  1186. }
  1187.  
  1188. #endif /* BSD || SUN || HPUX || AVIION */
  1189.  
  1190. /** Get time of day **/
  1191. char * timeset()
  1192. {
  1193.     long int buf; /* Should be time_t */
  1194.     char * sp, * cp;
  1195.  
  1196.     char * ctime();
  1197.  
  1198.     /* Get system time */
  1199.     time(&buf);
  1200.  
  1201.     /* Pass system time to converter */
  1202.     sp = ctime(&buf);
  1203.  
  1204.     /* Eat newline character */
  1205.     for (cp = sp; *cp; cp++)
  1206.         if (*cp == '\n') {
  1207.             *cp = '\0';
  1208.             break;
  1209.         }
  1210.     return(sp);
  1211. }
  1212.  
  1213. #if USG || SMOS || HPUX || XENIX
  1214. /** Rename a file **/
  1215. int rename(file1, file2)
  1216. char * file1;                /* Old file name        */
  1217. char * file2;                /* New file name        */
  1218. {
  1219.     struct stat buf1;
  1220.     struct stat buf2;
  1221.  
  1222.     /* No good if source file doesn't exist */
  1223.     if (stat(file1, &buf1))
  1224.         return(-1);
  1225.  
  1226.     /* Check for target */
  1227.     if (stat(file2, &buf2) == 0) {
  1228.  
  1229.         /* See if file is the same */
  1230.         if (buf1.st_dev == buf2.st_dev &&
  1231.             buf1.st_ino == buf2.st_ino)
  1232.  
  1233.             /* Not necessary to rename file */
  1234.             return(0);
  1235.     }
  1236.  
  1237.     /* Get rid of target */
  1238.     unlink(file2);
  1239.  
  1240.     /* Link two files together */
  1241.     if (link(file1, file2))
  1242.         return(-1);
  1243.  
  1244.     /* Unlink original file */
  1245.     return(unlink(file1));
  1246. }
  1247. #endif /* USG || SMOS || HPUX || XENIX */
  1248.  
  1249. /** Callout to system to perform command **/
  1250. int callout(cmd)
  1251. char * cmd;                /* Command to execute        */
  1252. {
  1253.     int status;
  1254.  
  1255.     /* Close down */
  1256.     scmove(term.t_nrow, 0);
  1257.     ttflush();
  1258.     ttclose();
  1259.  
  1260.     /* Do command */
  1261.     status = system(cmd) == 0;
  1262.  
  1263.     /* Restart system */
  1264.         sgarbf = TRUE;
  1265.     if (ttopen()) {
  1266.         puts("** Error reopening terminal device **");
  1267.         exit(1);
  1268.     }
  1269.  
  1270.     /* Success */
  1271.         return(status);
  1272. }
  1273.  
  1274. /** Create subshell **/
  1275. int spawncli(f, n)
  1276. int f;                    /* Flags            */
  1277. int n;                    /* Argument count        */
  1278. {
  1279.     char * sh;
  1280.  
  1281.     char * getenv();
  1282.  
  1283.     /* Don't allow this command if restricted */
  1284.     if (restflag)
  1285.         return(resterr());
  1286.  
  1287.     /* Get shell path */
  1288.     sh = getenv("SHELL");
  1289.     if (!sh)
  1290. #if BSD || SUN
  1291.         sh = "/bin/csh";
  1292. #endif /* BSD || SUN */
  1293. #if USG || SMOS || HPUX || XENIX || AVIION
  1294.         sh = "/bin/sh";
  1295. #endif /* USG || SMOS || HPUX || XENIX || AVIION */
  1296.  
  1297.     /* Do shell */
  1298.     return(callout(sh));
  1299. }
  1300.  
  1301. /** Spawn a command **/
  1302. int spawn(f, n)
  1303. int f;                    /* Flags            */
  1304. int n;                    /* Argument count        */
  1305. {
  1306.     char line[NLINE];
  1307.     int s;
  1308.  
  1309.     /* Don't allow this command if restricted */
  1310.     if (restflag)
  1311.         return(resterr());
  1312.  
  1313.     /* Get command line */
  1314.     s = mlreply("!", line, NLINE);
  1315.     if (!s)
  1316.         return(s);
  1317.  
  1318.     /* Perform the command */
  1319.     s = callout(line);
  1320.  
  1321.     /* if we are interactive, pause here */
  1322.     if (clexec == FALSE) {
  1323.             mlwrite("[End]");
  1324.         ttflush();
  1325.         ttgetc();
  1326.         }
  1327.         return(s);
  1328. }
  1329.  
  1330. /** Execute program **/
  1331. int execprg(f, n)
  1332. int f;                    /* Flags            */
  1333. int n;                    /* Argument count        */
  1334. {
  1335.     /* Same as spawn */
  1336.     return(spawn(f, n));
  1337. }
  1338.  
  1339. /** Pipe output of program to buffer **/
  1340. int pipecmd(f, n)
  1341. int f;                    /* Flags            */
  1342. int n;                    /* Argument count        */
  1343. {
  1344.     char line[NLINE];
  1345.     int s;
  1346.     BUFFER * bp;
  1347.     WINDOW * wp;
  1348.     static char filnam[] = "command";
  1349.  
  1350.     /* Don't allow this command if restricted */
  1351.     if (restflag)
  1352.         return(resterr());
  1353.  
  1354.     /* Get pipe-in command */
  1355.     s = mlreply("@", line, NLINE);
  1356.     if (!s)
  1357.         return(s);
  1358.  
  1359.     /* Get rid of the command output buffer if it exists */
  1360.     bp = bfind(filnam, FALSE, 0);
  1361.     if (bp) {
  1362.         /* Try to make sure we are off screen */
  1363.         wp = wheadp;
  1364.         while (wp) {
  1365.             if (wp->w_bufp == bp) {
  1366.                 onlywind(FALSE, 1);
  1367.                 break;
  1368.             }
  1369.             wp = wp->w_wndp;
  1370.         }
  1371.         if (!zotbuf(bp))
  1372.             return(0);
  1373.     }
  1374.  
  1375.     /* Add output specification */
  1376.     strcat(line, ">");
  1377.     strcat(line, filnam);
  1378.  
  1379.     /* Do command */
  1380.     s = callout(line);
  1381.     if (!s)
  1382.         return(s);
  1383.  
  1384.     /* Split the current window to make room for the command output */
  1385.     if (!splitwind(FALSE, 1))
  1386.         return(0);
  1387.  
  1388.     /* ...and read the stuff in */
  1389.     if (!getfile(filnam, FALSE))
  1390.         return(0);
  1391.  
  1392.     /* Make this window in VIEW mode, update all mode lines */
  1393.     curwp->w_bufp->b_mode |= MDVIEW;
  1394.     wp = wheadp;
  1395.     while (wp) {
  1396.         wp->w_flag |= WFMODE;
  1397.         wp = wp->w_wndp;
  1398.     }
  1399.  
  1400.     /* ...and get rid of the temporary file */
  1401.     unlink(filnam);
  1402.     return(1);
  1403. }
  1404.  
  1405. /** Filter buffer through command **/
  1406. int filter(f, n)
  1407. int f;                    /* Flags            */
  1408. int n;                    /* Argument count        */
  1409. {
  1410.     char line[NLINE], tmpnam[NFILEN];
  1411.     int s;
  1412.     BUFFER * bp;
  1413.     static char bname1[] = "fltinp";
  1414.     static char filnam1[] = "fltinp";
  1415.     static char filnam2[] = "fltout";
  1416.  
  1417.     /* Don't allow this command if restricted */
  1418.     if (restflag)
  1419.         return(resterr());
  1420.  
  1421.     /* Don't allow filtering of VIEW mode buffer */
  1422.     if (curbp->b_mode & MDVIEW)
  1423.         return(rdonly());
  1424.  
  1425.     /* Get the filter name and its args */
  1426.     s = mlreply("#", line, NLINE);
  1427.     if (!s)
  1428.         return(s);
  1429.  
  1430.     /* Setup the proper file names */
  1431.     bp = curbp;
  1432.     strcpy(tmpnam, bp->b_fname);    /* Save the original name */
  1433.     strcpy(bp->b_fname, bname1);    /* Set it to our new one */
  1434.  
  1435.     /* Write it out, checking for errors */
  1436.     if (!writeout(filnam1, "w")) {
  1437.         mlwrite("[Cannot write filter file]");
  1438.         strcpy(bp->b_fname, tmpnam);
  1439.         return(0);
  1440.     }
  1441.  
  1442.     /* Setup input and output */
  1443.     strcat(line," <fltinp >fltout");
  1444.  
  1445.     /* Perform command */
  1446.     s = callout(line);
  1447.  
  1448.     /* If successful, read in file */
  1449.     if (s) {
  1450.         s = readin(filnam2, FALSE);
  1451.         if (s)
  1452.             /* Mark buffer as changed */
  1453.             bp->b_flag |= BFCHG;
  1454.     }
  1455.             
  1456.  
  1457.     /* Reset file name */
  1458.     strcpy(bp->b_fname, tmpnam);
  1459.  
  1460.     /* and get rid of the temporary file */
  1461.     unlink(filnam1);
  1462.     unlink(filnam2);
  1463.  
  1464.     /* Show status */
  1465.     if (!s)
  1466.         mlwrite("[Execution failed]");
  1467.     return(s);
  1468. }
  1469.  
  1470. /** Get first filename from pattern **/
  1471. char *getffile(fspec)
  1472. char *fspec;                /* Filename specification    */
  1473. {
  1474.     int index, point, extflag;
  1475.  
  1476.     /* First parse the file path off the file spec */
  1477.     strcpy(path, fspec);
  1478.     index = strlen(path) - 1;
  1479.     while (index >= 0 && (path[index] != '/' &&
  1480.         path[index] != '\\' && path[index] != ':'))
  1481.         --index;
  1482.     path[index+1] = '\0';
  1483.  
  1484.  
  1485.     /* Check for an extension */
  1486.     point = strlen(fspec) - 1;
  1487.     extflag = FALSE;
  1488.     while (point >= 0) {
  1489.         if (fspec[point] == '.') {
  1490.             extflag = TRUE;
  1491.             break;
  1492.         }
  1493.         point--;
  1494.     }
  1495.  
  1496.     /* Open the directory pointer */
  1497.     if (dirptr) {
  1498.         closedir(dirptr);
  1499.         dirptr = NULL;
  1500.     }
  1501.  
  1502.     dirptr = opendir((path[0] == '\0') ? "./" : path);
  1503.  
  1504.     if (!dirptr)
  1505.         return(NULL);
  1506.  
  1507.     strcpy(rbuf, path);
  1508.     nameptr = &rbuf[strlen(rbuf)];
  1509.  
  1510.     /* ...and call for the first file */
  1511.     return(getnfile());
  1512. }
  1513.  
  1514. /** Get next filename from pattern **/
  1515. char *getnfile()
  1516. {
  1517.     int index;
  1518.     struct DIRENTRY * dp;
  1519.     struct stat fstat;
  1520.  
  1521.     /* ...and call for the next file */
  1522.     do {
  1523.         dp = readdir(dirptr);
  1524.         if (!dp)
  1525.             return(NULL);
  1526.  
  1527.         /* Check to make sure we skip all weird entries except directories */
  1528.         strcpy(nameptr, dp->d_name);
  1529.  
  1530.     } while (stat(rbuf, &fstat) &&
  1531.         ((fstat.st_mode & S_IFMT) && (S_IFREG || S_IFDIR)) == 0);
  1532.  
  1533.     /* if this entry is a directory name, say so */
  1534.     if ((fstat.st_mode & S_IFMT) == S_IFDIR)
  1535.         strcat(rbuf, DIRSEPSTR);
  1536.  
  1537.     /* Return the next file name! */
  1538.     return(rbuf);
  1539. }
  1540.  
  1541. #if FLABEL
  1542. int fnclabel(f, n)    /* label a function key */
  1543. int f,n;    /* default flag, numeric argument [unused] */
  1544. {
  1545.     /* on machines with no function keys...don't bother */
  1546.     return(TRUE);
  1547. }
  1548. #endif /* FLABEL */
  1549.  
  1550. #if XENIX && FILOCK
  1551. int mkdir(name, mode)
  1552. char *name;    /* name of directory to create */
  1553. int mode;    /* umask for creation (which we blissfully ignore...) */
  1554. {
  1555.     char buf[80];
  1556.  
  1557.     strcpy(buf, "mkdir ");
  1558.     strcat(buf, name);
  1559.     strcat(buf, " > /dev/null 2>&1");
  1560.     return(system(buf));
  1561. }
  1562.  
  1563. int rmdir(name)
  1564. char *name;    /* name of directory to delete */
  1565. {
  1566.     char buf[80];
  1567.  
  1568.     strcpy(buf,"rmdir ");
  1569.     strcat(buf, name);
  1570.     strcat(buf, " > /dev/null 2>&1");
  1571.     return(system(buf));
  1572. }
  1573. #endif /* XENIX & FILOCK */
  1574.  
  1575. #endif /* BSD || USG || SMOS || HPUX || SUN || XENIX || AVIION */
  1576.