home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / k / ksh48.zip / sh / edit.c < prev    next >
C/C++ Source or Header  |  1992-09-01  |  10KB  |  531 lines

  1. /*
  2.  * Command line editing - common code
  3.  *
  4.  */
  5.  
  6. #include "config.h"
  7. #if defined(EMACS) || defined(VI)
  8.  
  9. #ifndef lint
  10. static char *RCSid = "$Id: edit.c,v 1.5 1992/08/10 12:02:25 sjg Exp $";
  11. #endif
  12.  
  13. #include "stdh.h"
  14. #include <unistd.h>
  15. #include <signal.h>
  16. #include <fcntl.h>
  17. #include <errno.h>
  18. #include <setjmp.h>
  19. #ifndef NOSTDHDRS
  20. # include <string.h>
  21. #endif
  22. #include "sh.h"
  23. #include "tty.h"
  24. #define EXTERN
  25. #include "edit.h"
  26. #undef EXTERN
  27.  
  28. #ifdef _CRAY2
  29. extern unsigned    sleep();
  30. #endif
  31.  
  32.  
  33. static int    x_noecho = 0;
  34.  
  35. /*
  36.  * read an edited command line
  37.  */
  38. int
  39. x_read(fd, buf, len)
  40.     int fd;            /* not used */
  41.     char *buf;
  42.     size_t len;
  43. {
  44.   static int setup_done = 0;
  45.     int    i;
  46.  
  47.   if (setup_done != 42)
  48.   {
  49.     setup_done = 42;        /* these get done once only */
  50.     x_do_init = 1;
  51.     x_col = 0;
  52.     ed_erase = -1, ed_kill = -1, ed_werase = -1, ed_intr = -1, ed_quit = -1;
  53.     x_adj_ok = 1;
  54.     x_adj_done = 0;
  55.   }
  56.     if (x_do_init)
  57.         x_init();
  58.  
  59.     if (x_noecho)
  60.         return(read(ttyfd, buf, len));
  61.  
  62.     (void)x_mode(TRUE);
  63. #ifdef EMACS
  64.     if (flag[FEMACS])
  65.         i = x_emacs(buf, len);
  66.     else
  67. #endif
  68. #ifdef VI
  69.     if (flag[FVI])
  70.         i = x_vi(buf, len);
  71.     else
  72. #endif
  73.         i = -1;        /* internal error */
  74.     (void) x_mode(FALSE);
  75.     if (i > 4 && strstr(buf, "stty"))
  76.         x_do_init = 1;
  77.     if (i < 0 && errno == EINTR)
  78.         trapsig(SIGINT);
  79.     return i;
  80. }
  81.  
  82. /* tty I/O */
  83.  
  84. int
  85. x_getc()
  86. {
  87. #ifdef OS2
  88.   char c = _read_kbd(0, 1, 0);
  89.   return c == 0 ? 0xE0 : c;
  90. #else
  91.   char c;
  92.  
  93.   /*
  94.    * This allows the arival of a SIGCHLD to not disturb us until
  95.    * we are ready.
  96.    * BSD and other systems that automatically rety a read after
  97.    * an interrupt don't need this but it doesn't do any harm
  98.    * either.
  99.    */
  100.  retry:
  101.     if (read(ttyfd, &c, 1) != 1)
  102.     {
  103.       if (sigchld_caught)        /* just a SIGCHLD ? */
  104.       {
  105.         goto retry;
  106.       }
  107.       return -1;
  108.     }
  109.     return c & 0x7F;
  110. #endif
  111. }
  112.  
  113. void
  114. x_flush()
  115. {
  116.     fflush(stdout);
  117. }
  118.  
  119.  
  120. /* NAME:
  121.  *      x_adjust - redraw the line adjusting starting point etc.
  122.  *
  123.  * DESCRIPTION:
  124.  *      This function is called when we have exceeded the bounds
  125.  *      of the edit window.  It increments x_adj_done so that
  126.  *      functions like x_ins and x_delete know that we have been
  127.  *      called and can skip the x_bs() stuff which has already
  128.  *      been done by x_redraw.
  129.  *
  130.  * RETURN VALUE:
  131.  *      None
  132.  */
  133.  
  134. void
  135. x_adjust()
  136. {
  137.   x_adj_done++;            /* flag the fact that we were called. */
  138. #ifdef EMACS
  139.   /*
  140.    * we had a promblem if the prompt length > x_cols / 2
  141.    */
  142.   if ((xbp = xcp - (x_displen / 2)) < xbuf)
  143.     xbp = xbuf;
  144.   xlp_valid = FALSE;
  145.   x_redraw(x_cols);
  146. #endif
  147.   x_flush();
  148. }
  149.  
  150. void
  151. x_putc(c)
  152.     int c;
  153. {
  154.   if (c == '\r' || c == '\n')
  155.     x_col = 0;
  156.   if (x_col < x_cols)
  157.   {
  158.     putc(c, stdout);
  159.     switch(c)
  160.     {
  161.     case BEL:
  162.       break;
  163.     case '\r':
  164.     case '\n':
  165.     break;
  166.     case '\b':
  167.       x_col--;
  168.       break;
  169.     default:
  170.       x_col++;
  171.       break;
  172.     }
  173.   }
  174.   if (x_adj_ok && (x_col < 0 || x_col >= (x_cols - 2)))
  175.   {
  176.     x_adjust();
  177.   }
  178. }
  179.  
  180. #ifdef DEBUG
  181. int
  182. x_debug_info()
  183. {
  184.   x_flush();
  185.   printf("\nksh debug:\n");
  186.   printf("\tx_col == %d,\t\tx_cols == %d,\tx_displen == %d\n",
  187.      x_col, x_cols, x_displen);
  188.   printf("\txcp == 0x%lx,\txep == 0x%lx\n", (long) xcp, (long) xep);
  189.   printf("\txbp == 0x%lx,\txbuf == 0x%lx\n", (long) xbp, (long) xbuf);
  190.   printf("\txlp == 0x%lx\n", (long) xlp);
  191.   printf("\txlp == 0x%lx\n", (long) x_lastcp());
  192.   printf("\n");
  193.   x_redraw(-1);
  194.   return 0;
  195. }
  196. #endif
  197.  
  198. void
  199. x_puts(s)
  200.     register char *s;
  201. {
  202.   register int    adj = x_adj_done;
  203.  
  204.   while (*s && adj == x_adj_done)
  205.     x_putc(*s++);
  206. }
  207.  
  208. #ifdef _BSD
  209. static    struct sgttyb cb, cborig;
  210. #ifdef TIOCGATC
  211. static struct ttychars lchars, lcharsorig;
  212. #else
  213. static struct tchars tchars, tcharsorig;
  214. #ifdef TIOCGLTC
  215. static struct ltchars ltchars, ltcharsorig;
  216. #endif
  217. #endif
  218. #else
  219. #ifdef _POSIX_TERM
  220. static    struct termios cb, cborig;
  221. #else
  222. static    struct termio cb, cborig;
  223. #endif
  224. #endif
  225.  
  226. /* initialize editing mode */
  227. void
  228. x_init()
  229. {
  230.     x_do_init = 0;
  231. #ifdef _BSD
  232.     (void)ioctl(ttyfd, TIOCGETP, &cborig);
  233.     if ((cborig.sg_flags & ECHO) == 0)
  234.         x_noecho = 1;
  235.     cb = cborig;
  236.     ed_erase = cb.sg_erase;
  237.     ed_kill = cb.sg_kill;
  238.     cb.sg_flags &= ~ECHO;
  239.     cb.sg_flags |= CBREAK;
  240. #ifdef TIOCGATC
  241.     (void)ioctl(ttyfd, TIOCGATC, &lcharsorig);
  242.     lchars = lcharsorig;
  243.     ed_werase = lchars.tc_werasc;
  244.     lchars.tc_suspc = -1;
  245.     lchars.tc_dsuspc = -1;
  246.     lchars.tc_lnextc = -1;
  247.     lchars.tc_statc = -1;
  248.     lchars.tc_intrc = -1;
  249.     lchars.tc_quitc = -1;
  250.     lchars.tc_rprntc = -1;
  251. #else
  252.     (void)ioctl(ttyfd, TIOCGETC, &tcharsorig);
  253. #ifdef TIOCGLTC
  254.     (void)ioctl(ttyfd, TIOCGLTC, <charsorig);
  255. #endif
  256.     tchars = tcharsorig;
  257. #ifdef TIOCGLTC
  258.     ltchars = ltcharsorig;
  259.     ed_werase = ltchars.t_werasc;
  260.     ltchars = ltcharsorig;
  261.     ltchars.t_suspc = -1;
  262.     ltchars.t_dsuspc = -1;
  263.     ltchars.t_lnextc = -1;
  264. #endif
  265.     tchars.t_intrc = -1;
  266.     tchars.t_quitc = -1;
  267. #ifdef TIOCGLTC
  268.     ltchars.t_rprntc = -1;
  269. #endif
  270. #endif
  271. #else /* !_BSD */
  272. #ifdef _POSIX_TERM
  273.     (void) tcgetattr(ttyfd, &cborig);
  274. #else
  275.     (void)ioctl(ttyfd, TCGETA, &cborig);
  276. #endif
  277.     if ((cborig.c_lflag & ECHO) == 0)
  278.         x_noecho = 1;
  279.     cb = cborig;
  280.     ed_erase = cb.c_cc[VERASE]; /* TODO */
  281.     ed_kill = cb.c_cc[VKILL]; /* TODO */
  282.     ed_intr = cb.c_cc[VINTR];
  283.     ed_quit = cb.c_cc[VQUIT];
  284. #ifdef _CRAY2        /* brain-damaged terminal handler */
  285.     cb.c_lflag &= ~(ICANON|ECHO);
  286.     /* rely on print routine to map '\n' to CR,LF */
  287. #else
  288.     cb.c_iflag &= ~(INLCR|ICRNL);
  289. #ifdef _BSD_SYSV    /* need to force CBREAK instead of RAW (need CRMOD on output) */
  290.     cb.c_lflag &= ~(ICANON|ECHO);
  291. #else
  292. #ifdef SWTCH    /* need CBREAK to handle swtch char */
  293.     cb.c_lflag &= ~(ICANON|ECHO);
  294.     cb.c_lflag |= ISIG;
  295.     cb.c_cc[VINTR] = 0377;
  296.     cb.c_cc[VQUIT] = 0377;
  297. #else
  298.     cb.c_lflag &= ~(ISIG|ICANON|ECHO);
  299. #endif
  300. #endif
  301.     cb.c_cc[VTIME] = 0;
  302.     cb.c_cc[VMIN] = 1;
  303. #endif    /* _CRAY2 */
  304. #endif
  305. #ifdef EMACS
  306.     x_emacs_keys(ed_erase, ed_kill, ed_werase, ed_intr, ed_quit);
  307. #endif
  308. }
  309.  
  310. static    bool_t    x_cur_mode = FALSE;
  311.  
  312. /* set/clear tty cbreak mode */
  313.  
  314. #ifdef _BSD
  315. bool_t
  316. x_mode(onoff)
  317.     bool_t    onoff;
  318. {
  319.     bool_t    prev;
  320.  
  321.     if (x_cur_mode == onoff) return x_cur_mode;
  322.     prev = x_cur_mode;
  323.     x_cur_mode = onoff;
  324.     if (onoff)  {
  325.         (void)ioctl(ttyfd, TIOCSETN, &cb);
  326. #ifdef TIOCGATC
  327.         (void)ioctl(ttyfd, TIOCSATC, &lchars);
  328. #else
  329.         (void)ioctl(ttyfd, TIOCSETC, &tchars);
  330. #ifdef TIOCGLTC
  331.         (void)ioctl(ttyfd, TIOCSLTC, <chars);
  332. #endif
  333. #endif
  334.     }
  335.     else {
  336.         (void)ioctl(ttyfd, TIOCSETN, &cborig);
  337. #ifdef TIOCGATC
  338.         (void)ioctl(ttyfd, TIOCSATC, &lcharsorig);
  339. #else
  340.         (void)ioctl(ttyfd, TIOCSETC, &tcharsorig);
  341. #ifdef TIOCGLTC
  342.         (void)ioctl(ttyfd, TIOCSLTC, <charsorig);
  343. #endif
  344. #endif
  345.     }
  346.     return prev;
  347. }
  348.  
  349. #else    /* !_BSD */
  350.  
  351. #ifdef OS2
  352.  
  353. bool_t
  354. x_mode(onoff)
  355.     bool_t          onoff;
  356. {
  357.     bool_t          prev;
  358.     if (x_cur_mode == onoff)
  359.         return x_cur_mode;
  360.     prev = x_cur_mode;
  361.     x_cur_mode = onoff;
  362.  
  363.     /* setkbdmode(onoff); */
  364.  
  365.     return prev;
  366. }
  367.  
  368. #else
  369.  
  370. bool_t
  371. x_mode(onoff)
  372. bool_t    onoff;
  373. {
  374.     bool_t    prev;
  375.  
  376.     if (x_cur_mode == onoff) return x_cur_mode;
  377.     prev = x_cur_mode;
  378.     x_cur_mode = onoff;
  379.  
  380.     if (onoff)  {
  381. #ifdef _POSIX_TERM
  382.         (void) tcsetattr(ttyfd, TCSADRAIN, &cb);
  383. #else
  384. #ifndef TCSETAW                /* e.g. Cray-2 */
  385.         /* first wait for output to drain */
  386. #ifdef TCSBRK
  387.         (void)ioctl(ttyfd, TCSBRK, 1);
  388. #else    /* the following kludge is minimally intrusive, but sometimes fails */
  389.         (void)sleep((unsigned)1);    /* fake it */
  390. #endif
  391. #endif
  392. #if defined(_BSD_SYSV) || !defined(TCSETAW)
  393. /* _BSD_SYSV needs to force TIOCSETN instead of TIOCSETP (preserve type-ahead) */
  394.         (void)ioctl(ttyfd, TCSETA, &cb);
  395. #else
  396.         (void)ioctl(ttyfd, TCSETAW, &cb);
  397. #endif
  398. #endif
  399.     }
  400.     else {
  401. #ifdef _POSIX_TERM
  402.         (void) tcsetattr(ttyfd, TCSADRAIN, &cborig);
  403. #else
  404. #ifndef TCSETAW                /* e.g. Cray-2 */
  405.         /* first wait for output to drain */
  406. #ifdef TCSBRK
  407.         (void)ioctl(ttyfd, TCSBRK, 1);
  408. #else
  409. /* doesn't seem to be necessary when leaving xmode */
  410. /*        (void)sleep((unsigned)1);    /* fake it */
  411. #endif
  412. #endif
  413. #if defined(_BSD_SYSV) || !defined(TCSETAW)
  414. /* _BSD_SYSV needs to force TIOCSETN instead of TIOCSETP (preserve type-ahead) */
  415.         (void)ioctl(ttyfd, TCSETA, &cborig);
  416. #else
  417.         (void)ioctl(ttyfd, TCSETAW, &cborig);
  418. #endif
  419. #endif
  420.     }
  421.     return prev;
  422. }
  423. #endif  /* OS2 */
  424. #endif    /* _BSD */
  425.  
  426.  
  427. /* NAME:
  428.  *      promptlen - calculate the length of PS1 etc.
  429.  *
  430.  * DESCRIPTION:
  431.  *      This function is based on a fix from guy@demon.co.uk
  432.  *      It fixes a bug in that if PS1 contains '!', the length
  433.  *      given by strlen() is probably wrong.
  434.  *
  435.  * RETURN VALUE:
  436.  *      length
  437.  */
  438.  
  439. int
  440. promptlen(cp)
  441.   register char  *cp;
  442. {
  443.   register int count = 0;
  444.  
  445.   while (*cp)
  446.   {
  447.     if ( *cp++ != '!' )
  448.       count++;
  449.     else
  450.       if ( *cp == '!' )
  451.       {
  452.     cp++;
  453.     count++;
  454.       }
  455.       else if ( *cp == '.' )
  456.       {
  457.     cp++;
  458.     count += strlen(strval(global("PWD")));
  459.       }
  460.       else
  461.       {
  462.     register int i = source->line;
  463.  
  464.     do
  465.     {
  466.       count ++;
  467.     }
  468.     while( ( i /= 10 ) > 0 );
  469.       }
  470.   }
  471.   return count;
  472. }
  473.  
  474.  
  475. /*
  476.  * this function check the environment
  477.  * for FCEDIT,EDITOR or VISUAL
  478.  * as a hint to what edit mode is desired.
  479.  */
  480. init_editmode()
  481. {
  482.   static char *ev[] = { "FCEDIT", "EDITOR", "VISUAL", NULL };
  483.   register int i;
  484.   register char *rcp;
  485.  
  486.   for (i = 0; ev[i]; i++)
  487.   {
  488. #ifdef DEBUG
  489.     (void) fprintf(stderr, "check %s\n", ev[i]);
  490. #endif
  491.     if ((rcp = strval(global(ev[i]))) && *rcp)
  492.       break;
  493.   }
  494.   if (ev[i] && rcp)
  495.   {
  496.     set_editmode(rcp);
  497.   }
  498.   return 0;
  499. }
  500.  
  501. void
  502. set_editmode(ed)
  503.   char *ed;
  504. {
  505.   register char *rcp;
  506.   
  507. #ifdef DEBUG
  508.   (void) fprintf(stderr, "set_editmode(%s)\n", ed);
  509. #endif
  510.   if (rcp = strrchr(ed, '/'))
  511.     ed = ++rcp;
  512. #ifdef EMACS
  513.   if (strstr(ed, "emacs"))
  514.   {
  515.     flag[FVI] = 0;
  516.     flag[FEMACS] = 1;
  517.   }
  518. #endif
  519. #if defined(EMACS) && defined(VI)
  520.   else
  521. #endif
  522. #ifdef VI
  523.     if (strstr(ed, "vi"))
  524.     {
  525.       flag[FVI] = 1;
  526.       flag[FEMACS] = 0;
  527.     }
  528. #endif
  529. }
  530. #endif
  531.