home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / ue312os2.zip / src / posix.c < prev    next >
C/C++ Source or Header  |  1994-08-26  |  15KB  |  759 lines

  1. /***
  2.     POSIX driver/Microemacs 3.11a,
  3.     Copyright 1989/1991 D. Lawrence, C. Smith
  4.     Copyright 1992 H. Becker
  5.  
  6.  ***/
  7.  
  8. /**
  9.     1. FIONREAD is not defined in POSIX. TYPEAH should be 0.
  10.  
  11. **/
  12.  
  13. /** Include files **/
  14. #include <stdio.h>            /* Standard I/O definitions    */
  15. #include "estruct.h"            /* Emacs definitions        */
  16.  
  17. /** Do nothing routine **/
  18. int scnothing()
  19. {
  20.     return(0);
  21. }
  22.  
  23. /** Include files **/
  24. #include "eproto.h"            /* Function definitions        */
  25. #include "edef.h"            /* Global variable definitions    */
  26. #include "elang.h"            /* Language definitions        */
  27.  
  28. /** Kill predefined **/
  29. #undef CTRL                /* Problems with CTRL        */
  30.  
  31. /** Overall include files **/
  32. #include <sys/types.h>            /* System type definitions    */
  33. #include <sys/stat.h>            /* File status definitions    */
  34. #include <fcntl.h>            /* I/O control definitions    */
  35.  
  36. /** Additional include files **/
  37. #include <signal.h>            /* Signal definitions        */
  38. #include <termios.h>            /* Terminal I/O definitions    */
  39. #include <unistd.h>            /* unix i/o definitions        */
  40.  
  41. /** Completion include files **/
  42. /** Directory accessing: Try and figure this out... if you can! **/
  43. #include <dirent.h>            /* Directory entry definitions    */
  44. #define DIRENTRY    dirent
  45.  
  46. /** Restore predefined definitions **/
  47. #undef CTRL                /* Restore CTRL            */
  48. #define CTRL 0x0100
  49.  
  50. /** Parameters **/
  51. #define NKEYENT        300        /* Number of keymap entries    */
  52. #define NINCHAR        64        /* Input buffer size        */
  53. #define NOUTCHAR    256        /* Output buffer size        */
  54. #define MARGIN        8        /* Margin size            */
  55. #define SCRSIZ        64        /* Scroll for margin        */
  56. #define NPAUSE        10        /* # times thru update to pause */
  57. #define    MAXVTIME    1        /* x/10s max time for i/o delay    */
  58.  
  59. /** CONSTANTS **/
  60. #define TIMEOUT        255        /* No character available    */
  61.  
  62. /** Type definitions **/
  63. struct keyent {                /* Key mapping entry        */
  64.     struct keyent * samlvl;        /* Character on same level    */
  65.     struct keyent * nxtlvl;        /* Character on next level    */
  66.     unsigned char ch;        /* Character            */
  67.     int code;            /* Resulting keycode        */
  68. };
  69.  
  70. char *reset = (char*) NULL;        /* reset string kjc */
  71.  
  72. /** Local variables **/
  73. static struct termios curterm;        /* Current modes        */
  74. static struct termios oldterm;        /* Original modes        */
  75. static int inbuf[NINCHAR];        /* Input buffer            */
  76. static int * inbufh =            /* Head of input buffer        */
  77.     inbuf;
  78. static int * inbuft =            /* Tail of input buffer        */
  79.     inbuf;
  80. static unsigned char keyseq[256];    /* Prefix escape sequence table    */
  81. static struct keyent keymap[NKEYENT];    /* Key map            */
  82. static struct keyent * nxtkey =        /* Next free key entry        */
  83.     keymap;
  84. static DIR *dirptr = NULL;        /* Current directory stream    */
  85. static char path[NFILEN];        /* Path of file to find        */
  86. static char rbuf[NFILEN];        /* Return file buffer        */
  87. static char *nameptr;            /* Ptr past end of path in rbuf    */
  88.  
  89. #if ANSI
  90. #define    ttbeep    ansibeep
  91. #define    ttmove    ansimove
  92. #else /* ANSI */
  93. #if TERMCAP
  94. #define    ttbeep    tcapbeep
  95. #define    ttmove    tcapmove
  96. #endif
  97.  
  98. /** Terminal definition block **/
  99. /*
  100. int scclose(), ttgetc(), ttputc(), ttflush();
  101. int ttmove(), sceeol(), sceeop(), ttbeep(), screv();
  102. */
  103. int ttbeep(), ttmove();
  104.  
  105. #if COLOR
  106. int scfcol(), scbcol();
  107. #endif /* COLOR */
  108.  
  109. /** Open terminal device **/
  110. int ttopen()
  111. {
  112. /* look for LINES, COLUMNS in env, use it */
  113.  
  114.     int    row, col;
  115.     char    *cp;
  116.  
  117.     if (NULL!=(cp=getenv("LINES"))) {
  118.         sscanf (cp, "%d", &row);
  119.         if (row) {
  120.             term.t_mrow= row-1;
  121.             term.t_nrow= row-1;
  122.         }
  123.     }
  124.     if (NULL!=(cp=getenv("COLUMNS"))) {
  125.         sscanf (cp, "%d", &col);
  126.         if (col) {
  127.             term.t_mcol= col;
  128.             term.t_ncol= col;
  129.         }
  130.     }
  131.  
  132.     /* Get modes */
  133.     if (tcgetattr(STDIN_FILENO, &oldterm)) {
  134.         perror("Cannot tcgetattr");
  135.         return(-1);
  136.     }
  137.  
  138.     /* Save to original mode variable */
  139.     curterm = oldterm;
  140.  
  141.     /* Set new modes */
  142.     curterm.c_iflag &= ~(INLCR|ICRNL|IGNCR);
  143. #if    XONXOFF
  144.     curterm.c_iflag |= IXON | IXOFF;
  145. #endif
  146.     curterm.c_lflag &= ~(ICANON|ISIG|ECHO);
  147.     curterm.c_cc[VMIN] = 1;
  148.     curterm.c_cc[VTIME] = 0;
  149.  
  150.     /* Set tty mode */
  151.     if (tcsetattr(STDIN_FILENO, TCSANOW, &curterm)) {
  152.         perror("Cannot tcsetattr");
  153.         return(-1);
  154.     }
  155.  
  156.     /* Success */
  157.     return(0);
  158. }
  159.  
  160. /** Close terminal device **/
  161. int ttclose()
  162. {
  163.     /* Restore original terminal modes */
  164.     if (reset != (char*)NULL)
  165.         write(STDOUT_FILENO, reset, strlen(reset));
  166.  
  167.     /* Set tty mode */
  168.     if (tcsetattr(STDIN_FILENO, TCSANOW, &oldterm))
  169.         return(-1);
  170.  
  171.     /* Success */
  172.     return(0);
  173. }
  174.  
  175. /** Flush output buffer to display **/
  176. int ttflush()
  177. {
  178. /*
  179.     tcflush(STDOUT_FILENO, TCOFLUSH);
  180. */
  181.     fflush (stdout);
  182.  
  183.     return(0);
  184. }
  185.  
  186. /** Put character onto display **/
  187. int ttputc(ch)
  188. char ch;                /* Character to display        */
  189. {
  190. /*
  191.         return(write(STDOUT_FILENO, &ch, 1) != 1);
  192. */
  193.     fputc (ch, stdout);
  194. }
  195.  
  196. /** Add character sequence to keycode entry **/
  197. void addkey(seq, fn)
  198. unsigned char * seq;            /* Character sequence        */
  199. int fn;                    /* Resulting keycode        */
  200. {
  201.     int first;
  202.     struct keyent * cur, * nxtcur;
  203.  
  204.     /* Skip on null sequences */
  205.     if (!seq)
  206.         return;
  207.  
  208.     /* Skip single character sequences */
  209.     if (strlen(seq) < 2)
  210.         return;
  211.  
  212.     /* If no keys defined, go directly to insert mode */
  213.     first = 1;
  214.     if (nxtkey != keymap) {
  215.         
  216.         /* Start at top of key map */
  217.         cur = keymap;
  218.         
  219.         /* Loop until matches exhast */
  220.         while (*seq) {
  221.             
  222.             /* Do we match current character */
  223.             if (*seq == cur->ch) {
  224.                 
  225.                 /* Advance to next level */
  226.                 seq++;
  227.                 cur = cur->nxtlvl;
  228.                 first = 0;
  229.             } else {
  230.                 
  231.                 /* Try next character on same level */
  232.                 nxtcur = cur->samlvl;
  233.                 
  234.                 /* Stop if no more */
  235.                 if (nxtcur)
  236.                     cur = nxtcur;
  237.                 else
  238.                     break;
  239.             }
  240.         }
  241.     }
  242.     
  243.     /* Check for room in keymap */
  244.     if (strlen(seq) > NKEYENT - (nxtkey - keymap))
  245.         return;
  246.         
  247.     /* If first character in sequence is inserted, add to prefix table */
  248.     if (first)
  249.         keyseq[*seq] = 1;
  250.         
  251.     /* If characters are left over, insert them into list */
  252.     for (first = 1; *seq; first = 0) {
  253.         
  254.         /* Make new entry */
  255.         nxtkey->ch = *seq++;
  256.         nxtkey->code = fn;
  257.         
  258.         /* If root, nothing to do */
  259.         if (nxtkey != keymap) {
  260.             
  261.             /* Set first to samlvl, others to nxtlvl */
  262.             if (first)
  263.                 cur->samlvl = nxtkey;
  264.             else
  265.                 cur->nxtlvl = nxtkey;
  266.         }
  267.  
  268.         /* Advance to next key */
  269.         cur = nxtkey++;
  270.     }
  271. }
  272.  
  273. /** Grab input characters, with wait **/
  274. unsigned char grabwait()
  275. {
  276.     unsigned char ch;
  277.  
  278.     /* Change mode, if necessary */
  279.     if (curterm.c_cc[VTIME]) {
  280.         curterm.c_cc[VMIN] = 1;
  281.         curterm.c_cc[VTIME] = 0;
  282.         tcsetattr(STDIN_FILENO, TCSANOW, &curterm);
  283.     }
  284.  
  285.     /* Perform read */
  286.     if (read(0, &ch, 1) != 1) {
  287.         puts("** Horrible read error occured **");
  288.         exit(1);
  289.     }
  290.  
  291.     /* Return new character */
  292.     return(ch);
  293. }
  294.  
  295. /** Grab input characters, short wait **/
  296. unsigned char grabnowait()
  297. {
  298.     int count;
  299.     unsigned char ch;
  300.  
  301.     /* Change mode, if necessary */
  302.     if (curterm.c_cc[VTIME] == 0) {
  303.         curterm.c_cc[VMIN] = 0;
  304.         curterm.c_cc[VTIME] = MAXVTIME;
  305.         tcsetattr(STDIN_FILENO, TCSANOW, &curterm);
  306.     }
  307.  
  308.     /* Perform read */
  309.     count = read(0, &ch, 1);
  310.     if (count < 0) {
  311.         puts("** Horrible read error occured **");
  312.         exit(1);
  313.     }
  314.     if (count == 0)
  315.         return(TIMEOUT);
  316.  
  317.     /* Return new character */
  318.     return(ch);
  319. }
  320.  
  321. /** Queue input character **/
  322. void qin(ch)
  323. int ch;                    /* Character to add        */
  324. {
  325.     /* Check for overflow */
  326.     if (inbuft == &inbuf[sizeof(inbuf)]) {
  327.         
  328.         /* Annoy user */
  329.         ttbeep();
  330.         return;
  331.     }
  332.     
  333.     /* Add character */
  334.     *inbuft++ = ch;
  335. }
  336.  
  337. /** Cook input characters **/
  338. void cook()
  339. {
  340.     unsigned char ch;
  341.     struct keyent * cur;
  342.     
  343.     /* Get first character untimed */
  344.     ch = grabwait();
  345.     qin(ch);
  346.     
  347.     /* Skip if the key isn't a special leading escape sequence */
  348.     if (keyseq[ch] == 0)
  349.         return;
  350.  
  351.     /* Start at root of keymap */
  352.     cur = keymap;
  353.  
  354.     /* Loop until keymap exhasts */
  355.     while (cur) {
  356.  
  357.         /* Did we find a matching character */
  358.         if (cur->ch == ch) {
  359.  
  360.             /* Is this the end */
  361.             if (cur->nxtlvl == NULL) {
  362.  
  363.                 /* Replace all character with new sequence */
  364.                 inbuft = inbuf;
  365.                 qin(cur->code);
  366.                 return;
  367.             } else {
  368.                 /* Advance to next level */
  369.                 cur = cur->nxtlvl;
  370.             
  371.                 /* Get next character, timed */
  372.                 ch = grabnowait();
  373.                 if (ch == TIMEOUT)
  374.                     return;
  375.  
  376.                 /* Queue character */
  377.                 qin(ch);
  378.             }
  379.         } else
  380.             /* Try next character on same level */
  381.             cur = cur->samlvl;
  382.     }
  383. }
  384.  
  385. /** Return cooked characters **/
  386. int ttgetc()
  387. {
  388.     int ch;
  389.  
  390.     /* Loop until character found */
  391.     while (1) {
  392.     
  393.         /* Get input from buffer, if available */
  394.         if (inbufh != inbuft) {
  395.             ch = *inbufh++;
  396.             if (inbufh == inbuft)
  397.                 inbufh = inbuft = inbuf;
  398.             break;
  399.         } else
  400.  
  401.             /* Fill input buffer */
  402.             cook();
  403.     }
  404.     
  405.     /* Return next character */
  406.     return(ch);
  407. }
  408.  
  409. #if TYPEAH
  410. int typahead()
  411. {
  412.     unsigned char ch;
  413.  
  414.     /* See if internal buffer is non-empty */
  415.     if (inbufh != inbuft)
  416.         return(1);
  417.  
  418.     /* Now check with system */
  419.  
  420.     ch= grabnowait();
  421.  
  422.     if (ch==TIMEOUT)
  423.         return 0;
  424.     qin (ch);
  425.     return 1;
  426. }
  427. #endif /* TYPEAH */
  428.  
  429. /* Surely more than just BSD systems do this */
  430.  
  431. /** Perform a stop signal **/
  432. int bktoshell(f, n)
  433. {
  434.     /* Reset the terminal and go to the last line */
  435.     vttidy();
  436.     
  437.     /* Okay, stop... */
  438.     kill(getpid(), SIGTSTP);
  439.  
  440.     /* We should now be back here after resuming */
  441.  
  442.     /* Reopen the screen and redraw */
  443.     ttopen();
  444.     curwp->w_flag = WFHARD;
  445.     sgarbf = TRUE;
  446.  
  447.     /* Success */
  448.     return(0);
  449. }
  450.  
  451. /** Get time of day **/
  452. char * timeset()
  453. {
  454.     long int buf; /* Should be time_t */
  455.     char * sp, * cp;
  456.  
  457.     char * ctime();
  458.  
  459.     /* Get system time */
  460.     time(&buf);
  461.  
  462.     /* Pass system time to converter */
  463.     sp = ctime(&buf);
  464.  
  465.     /* Eat newline character */
  466.     for (cp = sp; *cp; cp++)
  467.         if (*cp == '\n') {
  468.             *cp = '\0';
  469.             break;
  470.         }
  471.     return(sp);
  472. }
  473.  
  474. /** Callout to system to perform command **/
  475. int callout(cmd)
  476. char * cmd;                /* Command to execute        */
  477. {
  478.     int status;
  479.  
  480.     /* Close down */
  481.     ttmove(term.t_nrow, 0);
  482.     ttflush();
  483.     ttclose();
  484.  
  485.     /* Do command */
  486.     status = system(cmd) == 0;
  487.  
  488.     /* Restart system */
  489.         sgarbf = TRUE;
  490.     if (ttopen()) {
  491.         puts("** Error reopening terminal device **");
  492.         exit(1);
  493.     }
  494.  
  495.     /* Success */
  496.         return(status);
  497. }
  498.  
  499. /** Create subshell **/
  500. int spawncli(f, n)
  501. int f;                    /* Flags            */
  502. int n;                    /* Argument count        */
  503. {
  504.     char * sh;
  505.  
  506.     /* Don't allow this command if restricted */
  507.     if (restflag)
  508.         return(resterr());
  509.  
  510.     /* Get shell path */
  511.     sh = getenv("SHELL");
  512.     if (!sh)
  513.         sh = "/bin/sh";
  514.  
  515.     /* Do shell */
  516.     return(callout(sh));
  517. }
  518.  
  519. /** Spawn a command **/
  520. int spawn(f, n)
  521. int f;                    /* Flags            */
  522. int n;                    /* Argument count        */
  523. {
  524.     char line[NLINE];
  525.     int s;
  526.  
  527.     /* Don't allow this command if restricted */
  528.     if (restflag)
  529.         return(resterr());
  530.  
  531.     /* Get command line */
  532.     s = mlreply("!", line, NLINE);
  533.     if (!s)
  534.         return(s);
  535.  
  536.     /* Perform the command */
  537.     s = callout(line);
  538.  
  539.     /* if we are interactive, pause here */
  540.     if (clexec == FALSE) {
  541.             mlwrite("[End]");
  542.         ttflush();
  543.         ttgetc();
  544.         }
  545.         return(s);
  546. }
  547.  
  548. /** Execute program **/
  549. int execprg(f, n)
  550. int f;                    /* Flags            */
  551. int n;                    /* Argument count        */
  552. {
  553.     /* Same as spawn */
  554.     return(spawn(f, n));
  555. }
  556.  
  557. /** Pipe output of program to buffer **/
  558. int pipecmd(f, n)
  559. int f;                    /* Flags            */
  560. int n;                    /* Argument count        */
  561. {
  562.     char line[NLINE];
  563.     int s;
  564.     BUFFER * bp;
  565.     WINDOW * wp;
  566.     static char filnam[] = "command";
  567.  
  568.     /* Don't allow this command if restricted */
  569.     if (restflag)
  570.         return(resterr());
  571.  
  572.     /* Get pipe-in command */
  573.     s = mlreply("@", line, NLINE);
  574.     if (!s)
  575.         return(s);
  576.  
  577.     /* Get rid of the command output buffer if it exists */
  578.     bp = bfind(filnam, FALSE, 0);
  579.     if (bp) {
  580.         /* Try to make sure we are off screen */
  581.         wp = wheadp;
  582.         while (wp) {
  583.             if (wp->w_bufp == bp) {
  584.                 onlywind(FALSE, 1);
  585.                 break;
  586.             }
  587.             wp = wp->w_wndp;
  588.         }
  589.         if (!zotbuf(bp))
  590.             return(0);
  591.     }
  592.  
  593.     /* Add output specification */
  594.     strcat(line, ">");
  595.     strcat(line, filnam);
  596.  
  597.     /* Do command */
  598.     s = callout(line);
  599.     if (!s)
  600.         return(s);
  601.  
  602.     /* Split the current window to make room for the command output */
  603.     if (!splitwind(FALSE, 1))
  604.         return(0);
  605.  
  606.     /* ...and read the stuff in */
  607.     if (!getfile(filnam, FALSE))
  608.         return(0);
  609.  
  610.     /* Make this window in VIEW mode, update all mode lines */
  611.     curwp->w_bufp->b_mode |= MDVIEW;
  612.     wp = wheadp;
  613.     while (wp) {
  614.         wp->w_flag |= WFMODE;
  615.         wp = wp->w_wndp;
  616.     }
  617.  
  618.     /* ...and get rid of the temporary file */
  619.     unlink(filnam);
  620.     return(1);
  621. }
  622.  
  623. /** Filter buffer through command **/
  624. int filter(f, n)
  625. int f;                    /* Flags            */
  626. int n;                    /* Argument count        */
  627. {
  628.     char line[NLINE], tmpnam[NFILEN];
  629.     int s;
  630.     BUFFER * bp;
  631.     static char bname1[] = "fltinp";
  632.     static char filnam1[] = "fltinp";
  633.     static char filnam2[] = "fltout";
  634.  
  635.     /* Don't allow this command if restricted */
  636.     if (restflag)
  637.         return(resterr());
  638.  
  639.     /* Don't allow filtering of VIEW mode buffer */
  640.     if (curbp->b_mode & MDVIEW)
  641.         return(rdonly());
  642.  
  643.     /* Get the filter name and its args */
  644.     s = mlreply("#", line, NLINE);
  645.     if (!s)
  646.         return(s);
  647.  
  648.     /* Setup the proper file names */
  649.     bp = curbp;
  650.     strcpy(tmpnam, bp->b_fname);    /* Save the original name */
  651.     strcpy(bp->b_fname, bname1);    /* Set it to our new one */
  652.  
  653.     /* Write it out, checking for errors */
  654.     if (!writeout(filnam1, "w")) {
  655.         mlwrite("[Cannot write filter file]");
  656.         strcpy(bp->b_fname, tmpnam);
  657.         return(0);
  658.     }
  659.  
  660.     /* Setup input and output */
  661.     strcat(line," <fltinp >fltout");
  662.  
  663.     /* Perform command */
  664.     s = callout(line);
  665.  
  666.     /* If successful, read in file */
  667.     if (s) {
  668.         s = readin(filnam2, FALSE);
  669.         if (s)
  670.             /* Mark buffer as changed */
  671.             bp->b_flag |= BFCHG;
  672.     }
  673.             
  674.  
  675.     /* Reset file name */
  676.     strcpy(bp->b_fname, tmpnam);
  677.  
  678.     /* and get rid of the temporary file */
  679.     unlink(filnam1);
  680.     unlink(filnam2);
  681.  
  682.     /* Show status */
  683.     if (!s)
  684.         mlwrite("[Execution failed]");
  685.     return(s);
  686. }
  687.  
  688. /** Get first filename from pattern **/
  689. char *getffile(fspec)
  690. char *fspec;                /* Filename specification    */
  691. {
  692.     int index, point, extflag;
  693.  
  694.     /* First parse the file path off the file spec */
  695.     strcpy(path, fspec);
  696.     index = strlen(path) - 1;
  697.     while (index >= 0 && (path[index] != '/' &&
  698.         path[index] != '\\' && path[index] != ':'))
  699.         --index;
  700.     path[index+1] = '\0';
  701.  
  702.  
  703.     /* Check for an extension */
  704.     point = strlen(fspec) - 1;
  705.     extflag = FALSE;
  706.     while (point >= 0) {
  707.         if (fspec[point] == '.') {
  708.             extflag = TRUE;
  709.             break;
  710.         }
  711.         point--;
  712.     }
  713.  
  714.     /* Open the directory pointer */
  715.     if (dirptr) {
  716.         closedir(dirptr);
  717.         dirptr = NULL;
  718.     }
  719.  
  720.     dirptr = opendir((path[0] == '\0') ? "./" : path);
  721.  
  722.     if (!dirptr)
  723.         return(NULL);
  724.  
  725.     strcpy(rbuf, path);
  726.     nameptr = &rbuf[strlen(rbuf)];
  727.  
  728.     /* ...and call for the first file */
  729.     return(getnfile());
  730. }
  731.  
  732. /** Get next filename from pattern **/
  733. char *getnfile()
  734. {
  735.     int index;
  736.     struct DIRENTRY * dp;
  737.     struct stat fstat;
  738.  
  739.     /* ...and call for the next file */
  740.     do {
  741.         dp = readdir(dirptr);
  742.         if (!dp)
  743.             return(NULL);
  744.  
  745.         /* Check to make sure we skip all weird entries except directories */
  746.         strcpy(nameptr, dp->d_name);
  747.  
  748.     } while (stat(rbuf, &fstat) ||
  749.         !(S_ISDIR(fstat.st_mode) !! S_ISREG(fstat.st_mode)));
  750.  
  751.     /* if this entry is a directory name, say so */
  752.     if (S_ISDIR(fstat.st_mode))
  753.         strcat(rbuf, DIRSEPSTR);
  754.  
  755.     /* Return the next file name! */
  756.     return(rbuf);
  757. }
  758.  
  759.