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