home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / UNIX / Shells / zsh-3.0.5-MIHS / src / Src / zle_misc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-06-03  |  24.2 KB  |  1,325 lines

  1. /*
  2.  * $Id: zle_misc.c,v 2.30 1996/10/15 20:16:35 hzoli Exp $
  3.  *
  4.  * zle_misc.c - miscellaneous editor routines
  5.  *
  6.  * This file is part of zsh, the Z shell.
  7.  *
  8.  * Copyright (c) 1992-1996 Paul Falstad
  9.  * All rights reserved.
  10.  *
  11.  * Permission is hereby granted, without written agreement and without
  12.  * license or royalty fees, to use, copy, modify, and distribute this
  13.  * software and to distribute modified versions of this software for any
  14.  * purpose, provided that the above copyright notice and the following
  15.  * two paragraphs appear in all copies of this software.
  16.  *
  17.  * In no event shall Paul Falstad or the Zsh Development Group be liable
  18.  * to any party for direct, indirect, special, incidental, or consequential
  19.  * damages arising out of the use of this software and its documentation,
  20.  * even if Paul Falstad and the Zsh Development Group have been advised of
  21.  * the possibility of such damage.
  22.  *
  23.  * Paul Falstad and the Zsh Development Group specifically disclaim any
  24.  * warranties, including, but not limited to, the implied warranties of
  25.  * merchantability and fitness for a particular purpose.  The software
  26.  * provided hereunder is on an "as is" basis, and Paul Falstad and the
  27.  * Zsh Development Group have no obligation to provide maintenance,
  28.  * support, updates, enhancements, or modifications.
  29.  *
  30.  */
  31.  
  32. #define ZLE
  33. #include "zsh.h"
  34.  
  35. /**/
  36. void
  37. selfinsert(void)
  38. {
  39.     int ncs = cs + zmult;
  40.  
  41.     if (complexpect && isset(AUTOPARAMKEYS)) {
  42.     if (complexpect == 2 && /*{*/ c == '}') {
  43.         if (!menucmp || line[cs-1] == '/' || addedsuffix) {
  44.         int i = 0;
  45.         spaceinline(1);
  46.         do {
  47.             line[cs-i] = line[cs-i-1];
  48.         } while (++i < addedsuffix);
  49.         line[cs-i] = c;
  50.         cs++;
  51.         return;
  52.         }
  53.     } else if (c == ':' || c == '[' || (complexpect == 2 &&
  54.             (c == '#' || c == '%' || c == '-' ||
  55.              c == '?' || c == '+' || c == '='))) {
  56.         if (addedsuffix > 1)
  57.         backdel(addedsuffix - 1);
  58.  
  59.         if (!menucmp || line[cs-1] == '/' || addedsuffix) {
  60.         line[cs - 1] = c;
  61.         return;
  62.         }
  63.     }
  64.     }
  65.     if (zmult < 0) {
  66.     zmult = -zmult;
  67.     ncs = cs;
  68.     }
  69.     if (insmode || ll == cs)
  70.     spaceinline(zmult);
  71.     else if (zmult + cs > ll)
  72.     spaceinline(ll - (zmult + cs));
  73.     while (zmult--)
  74.     line[cs++] = c;
  75.     cs = ncs;
  76. }
  77.  
  78. /**/
  79. void
  80. selfinsertunmeta(void)
  81. {
  82.     c &= 0x7f;
  83.     if (c == '\r')
  84.     c = '\n';
  85.     selfinsert();
  86. }
  87.  
  88. /**/
  89. void
  90. deletechar(void)
  91. {
  92.     if (zmult < 0) {
  93.     zmult = -zmult;
  94.     backwarddeletechar();
  95.     return;
  96.     }
  97.     if (cs + zmult <= ll) {
  98.     cs += zmult;
  99.     backdel(zmult);
  100.     } else
  101.     feep();
  102. }
  103.  
  104. /**/
  105. void
  106. backwarddeletechar(void)
  107. {
  108.     if (zmult < 0) {
  109.     zmult = -zmult;
  110.     deletechar();
  111.     return;
  112.     }
  113.     if (zmult > cs)
  114.     zmult = cs;
  115.     backdel(zmult);
  116. }
  117.  
  118. /**/
  119. void
  120. killwholeline(void)
  121. {
  122.     int i, fg;
  123.  
  124.     if (zmult < 0)
  125.     return;
  126.     while (zmult--) {
  127.     if ((fg = (cs && cs == ll)))
  128.         cs--;
  129.     while (cs && line[cs - 1] != '\n')
  130.         cs--;
  131.     for (i = cs; i != ll && line[i] != '\n'; i++);
  132.     forekill(i - cs + (i != ll), fg);
  133.     }
  134. }
  135.  
  136. /**/
  137. void
  138. killbuffer(void)
  139. {
  140.     cs = 0;
  141.     forekill(ll, 0);
  142. }
  143.  
  144. /**/
  145. void
  146. backwardkillline(void)
  147. {
  148.     int i = 0;
  149.  
  150.     if (zmult < 0) {
  151.     zmult = -zmult;
  152.     killline();
  153.     return;
  154.     }
  155.     while (zmult--) {
  156.     if (cs && line[cs - 1] == '\n')
  157.         cs--, i++;
  158.     else
  159.         while (cs && line[cs - 1] != '\n')
  160.         cs--, i++;
  161.     }
  162.     forekill(i, 1);
  163. }
  164.  
  165. /**/
  166. void
  167. gosmacstransposechars(void)
  168. {
  169.     int cc;
  170.  
  171.     if (cs < 2 || line[cs - 1] == '\n' || line[cs - 2] == '\n') {
  172.     if (cs == ll || line[cs] == '\n' ||
  173.         ((cs + 1 == ll || line[cs + 1] == '\n') &&
  174.          (!cs || line[cs - 1] == '\n'))) {
  175.         feep();
  176.         return;
  177.     }
  178.     cs += (cs == 0 || line[cs - 1] == '\n') ? 2 : 1;
  179.     }
  180.     cc = line[cs - 2];
  181.     line[cs - 2] = line[cs - 1];
  182.     line[cs - 1] = cc;
  183. }
  184.  
  185. /**/
  186. void
  187. transposechars(void)
  188. {
  189.     int cc, ct;
  190.     int neg = zmult < 0;
  191.  
  192.     if (neg)
  193.     zmult = -zmult;
  194.     while (zmult--) {
  195.     if (!(ct = cs) || line[cs - 1] == '\n') {
  196.         if (ll == cs || line[cs] == '\n') {
  197.         feep();
  198.         return;
  199.         }
  200.         if (!neg)
  201.         cs++;
  202.         ct++;
  203.     }
  204.     if (neg) {
  205.         if (cs && line[cs - 1] != '\n') {
  206.         cs--;
  207.         if (ct > 1 && line[ct - 2] != '\n')
  208.             ct--;
  209.         }
  210.     } else {
  211.         if (cs != ll && line[cs] != '\n')
  212.         cs++;
  213.     }
  214.     if (ct == ll || line[ct] == '\n')
  215.         ct--;
  216.     if (ct < 1 || line[ct - 1] == '\n') {
  217.         feep();
  218.         return;
  219.     }
  220.     cc = line[ct - 1];
  221.     line[ct - 1] = line[ct];
  222.     line[ct] = cc;
  223.     }
  224. }
  225.  
  226. /**/
  227. void
  228. poundinsert(void)
  229. {
  230.     cs = 0;
  231.     vifirstnonblank();
  232.     if (line[cs] != '#') {
  233.     spaceinline(1);
  234.     line[cs] = '#';
  235.     cs = findeol();
  236.     while(cs != ll) {
  237.         cs++;
  238.         vifirstnonblank();
  239.         spaceinline(1);
  240.         line[cs] = '#';
  241.         cs = findeol();
  242.     }
  243.     } else {
  244.     foredel(1);
  245.     cs = findeol();
  246.     while(cs != ll) {
  247.         cs++;
  248.         vifirstnonblank();
  249.         if(line[cs] == '#')
  250.         foredel(1);
  251.         cs = findeol();
  252.     }
  253.     }
  254.     done = 1;
  255. }
  256.  
  257. /**/
  258. void
  259. acceptline(void)
  260. {
  261.     done = 1;
  262. }
  263.  
  264. /**/
  265. void
  266. acceptandhold(void)
  267. {
  268.     pushnode(bufstack, metafy((char *)line, ll, META_DUP));
  269.     stackcs = cs;
  270.     done = 1;
  271. }
  272.  
  273. /**/
  274. void
  275. killline(void)
  276. {
  277.     int i = 0;
  278.  
  279.     if (zmult < 0) {
  280.     zmult = -zmult;
  281.     backwardkillline();
  282.     return;
  283.     }
  284.     while (zmult--) {
  285.     if (line[cs] == '\n')
  286.         cs++, i++;
  287.     else
  288.         while (cs != ll && line[cs] != '\n')
  289.         cs++, i++;
  290.     }
  291.     backkill(i, 0);
  292. }
  293.  
  294. /**/
  295. void
  296. killregion(void)
  297. {
  298.     if (mark > ll)
  299.     mark = ll;
  300.     if (mark > cs)
  301.     forekill(mark - cs, 0);
  302.     else
  303.     backkill(cs - mark, 1);
  304. }
  305.  
  306. /**/
  307. void
  308. copyregionaskill(void)
  309. {
  310.     if (mark > ll)
  311.     mark = ll;
  312.     if (mark > cs)
  313.     cut(cs, mark - cs, 0);
  314.     else
  315.     cut(mark, cs - mark, 1);
  316. }
  317.  
  318. static int kct, yankb, yanke;
  319.  
  320. /**/
  321. void
  322. yank(void)
  323. {
  324.     Cutbuffer buf = &cutbuf;
  325.  
  326.     if (zmult < 0)
  327.     return;
  328.     if (gotvibufspec)
  329.     buf = &vibuf[vibufspec];
  330.     if (!buf->buf) {
  331.     feep();
  332.     return;
  333.     }
  334.     mark = cs;
  335.     yankb = cs;
  336.     while (zmult--) {
  337.     kct = kringnum;
  338.     spaceinline(buf->len);
  339.     memcpy((char *)line + cs, buf->buf, buf->len);
  340.     cs += buf->len;
  341.     yanke = cs;
  342.     }
  343. }
  344.  
  345. /**/
  346. void
  347. yankpop(void)
  348. {
  349.     int cc;
  350.  
  351.     if (!(lastcmd & ZLE_YANK) || !kring[kct].buf) {
  352.     feep();
  353.     return;
  354.     }
  355.     cs = yankb;
  356.     foredel(yanke - yankb);
  357.     cc = kring[kct].len;
  358.     spaceinline(cc);
  359.     memcpy((char *)line + cs, kring[kct].buf, cc);
  360.     cs += cc;
  361.     yanke = cs;
  362.     kct = (kct + KRINGCT - 1) % KRINGCT;
  363. }
  364.  
  365. /**/
  366. void
  367. overwritemode(void)
  368. {
  369.     insmode ^= 1;
  370. }
  371.  
  372. /**/
  373. void
  374. undefinedkey(void)
  375. {
  376.     feep();
  377. }
  378.  
  379. /**/
  380. void
  381. quotedinsert(void)
  382. {
  383. #ifndef HAS_TIO
  384.     struct sgttyb sob;
  385.  
  386.     sob = shttyinfo.sgttyb;
  387.     sob.sg_flags = (sob.sg_flags | RAW) & ~ECHO;
  388.     ioctl(SHTTY, TIOCSETN, &sob);
  389. #endif
  390.     c = getkey(0);
  391. #ifndef HAS_TIO
  392.     setterm();
  393. #endif
  394.     if (c < 0)
  395.     feep();
  396.     else
  397.     selfinsert();
  398. }
  399.  
  400. /**/
  401. void
  402. digitargument(void)
  403. {
  404.     int sign = (zmult < 0) ? -1 : 1;
  405.  
  406.     if (!(lastcmd & ZLE_DIGIT))
  407.     zmult = 0;
  408.     zmult = zmult * 10 + sign * (c & 0xf);
  409.     gotmult = 1;
  410. }
  411.  
  412. /**/
  413. void
  414. negargument(void)
  415. {
  416.     if (lastcmd & (ZLE_NEGARG | ZLE_DIGIT))
  417.     feep();
  418.     zmult = -1;
  419.     gotmult = 1;
  420. }
  421.  
  422. /**/
  423. void
  424. universalargument(void)
  425. {
  426.     if (!(lastcmd & ZLE_ARG))
  427.     zmult = 4;
  428.     else
  429.     zmult *= 4;
  430.     gotmult = 1;
  431. }
  432.  
  433. /**/
  434. void
  435. copyprevword(void)
  436. {
  437.     int len, t0;
  438.  
  439.     for (t0 = cs - 1; t0 >= 0; t0--)
  440.     if (iword(line[t0]))
  441.         break;
  442.     for (; t0 >= 0; t0--)
  443.     if (!iword(line[t0]))
  444.         break;
  445.     if (t0)
  446.     t0++;
  447.     len = cs - t0;
  448.     spaceinline(len);
  449.     memcpy((char *)&line[cs], (char *)&line[t0], len);
  450.     cs += len;
  451. }
  452.  
  453. /**/
  454. void
  455. sendbreak(void)
  456. {
  457.     errflag = 1;
  458. }
  459.  
  460. /**/
  461. void
  462. undo(void)
  463. {
  464.     char *s;
  465.     struct undoent *ue;
  466.  
  467.     ue = undos + undoct;
  468.     if (!ue->change) {
  469.     feep();
  470.     return;
  471.     }
  472.     line[ll] = '\0';
  473.     s = zalloc(ue->suff + 1);
  474.     memcpy(s, (char *)&line[ll - ue->suff], ue->suff);
  475.     sizeline(ll = ue->pref + ue->suff + ue->len);
  476.     memcpy((char *)line + ue->pref, ue->change, ue->len);
  477.     memcpy((char *)line + ue->pref + ue->len, s, ue->suff);
  478.     zfree(s, ue->suff + 1);
  479.     ue->change = NULL;
  480.     undoct = (undoct + UNDOCT - 1) % UNDOCT;
  481.     cs = ue->cs;
  482. }
  483.  
  484. /**/
  485. void
  486. quoteregion(void)
  487. {
  488.     char *str;
  489.     size_t len;
  490.  
  491.     if (mark > ll)
  492.     mark = ll;
  493.     if (mark < cs) {
  494.     int tmp = mark;
  495.     mark = cs;
  496.     cs = tmp;
  497.     }
  498.     str = (char *)hcalloc(len = mark - cs);
  499.     memcpy(str, (char *)&line[cs], len);
  500.     foredel(len);
  501.     str = makequote(str, &len);
  502.     spaceinline(len);
  503.     memcpy((char *)&line[cs], str, len);
  504.     mark = cs;
  505.     cs += len;
  506. }
  507.  
  508. /**/
  509. void
  510. quoteline(void)
  511. {
  512.     char *str;
  513.     size_t len = ll;
  514.  
  515.     str = makequote((char *)line, &len);
  516.     sizeline(len);
  517.     memcpy(line, str, len);
  518.     cs = ll = len;
  519. }
  520.  
  521. /**/
  522. char *
  523. makequote(char *str, size_t *len)
  524. {
  525.     int qtct = 0;
  526.     char *l, *ol;
  527.     char *end = str + *len;
  528.  
  529.     for (l = str; l < end; l++)
  530.     if (*l == '\'')
  531.         qtct++;
  532.     *len += 2 + qtct*3;
  533.     l = ol = (char *)halloc(*len);
  534.     *l++ = '\'';
  535.     for (; str < end; str++)
  536.     if (*str == '\'') {
  537.         *l++ = '\'';
  538.         *l++ = '\\';
  539.         *l++ = '\'';
  540.         *l++ = '\'';
  541.     } else
  542.         *l++ = *str;
  543.     *l++ = '\'';
  544.     return ol;
  545. }
  546.  
  547. #define NAMLEN 60
  548.  
  549. /**/
  550. int
  551. executenamedcommand(char *prmt)
  552. {
  553.     int len, cmd, t0, l = strlen(prmt);
  554.     char *ptr, *buf = halloc(l + NAMLEN + 2);
  555.     int *obindtab = bindtab;
  556.  
  557.     strcpy(buf, prmt);
  558.     statusline = buf;
  559.     bindtab = mainbindtab;
  560.     ptr = buf += l;
  561.     len = 0;
  562.     for (;;) {
  563.     *ptr = '_';
  564.     statusll = l + len + 1;
  565.     refresh();
  566.     if ((cmd = getkeycmd()) < 0 || cmd == z_sendbreak) {
  567.         statusline = NULL;
  568.         bindtab = obindtab;
  569.         return -1;
  570.     }
  571.     switch (cmd) {
  572.     case z_sendstring:
  573.         sendstring();
  574.         break;
  575.     case z_clearscreen:
  576.         clearscreen();
  577.         break;
  578.     case z_redisplay:
  579.         redisplay();
  580.         break;
  581.     case z_viquotedinsert:
  582.         *ptr = '^';
  583.         refresh();
  584.         c = getkey(0);
  585.         if(c == EOF || !c || len == NAMLEN)
  586.         feep();
  587.         else
  588.         *ptr++ = c, len++;
  589.         break;
  590.     case z_quotedinsert:
  591.         if((c = getkey(0)) == EOF || !c || len == NAMLEN)
  592.         feep();
  593.         else
  594.         *ptr++ = c, len++;
  595.         break;
  596.     case z_backwarddeletechar:
  597.     case z_vibackwarddeletechar:
  598.         if (len)
  599.         len--, ptr--;
  600.         break;
  601.     case z_killregion:
  602.     case z_backwardkillword:
  603.     case z_vibackwardkillword:
  604.         while (len && (len--, *--ptr != '-'));
  605.         break;
  606.     case z_killwholeline:
  607.     case z_vikillline:
  608.     case z_backwardkillline:
  609.         len = 0;
  610.         ptr = buf;
  611.         break;
  612.     case z_acceptline:
  613.     case z_vicmdmode:
  614.     unambiguous:
  615.         *ptr = 0;
  616.         for (t0 = 0; t0 != ZLECMDCOUNT; t0++)
  617.         if (!strcmp(buf, zlecmds[t0].name))
  618.             break;
  619.         if (t0 != ZLECMDCOUNT) {
  620.         statusline = NULL;
  621.         bindtab = obindtab;
  622.         return t0;
  623.         }
  624.         /* fall through */
  625.     default:
  626.         if(cmd == z_selfinsertunmeta) {
  627.         c &= 0x7f;
  628.         if(c == '\r')
  629.             c = '\n';
  630.         cmd = z_selfinsert;
  631.         }
  632.         if (cmd == z_listchoices || cmd == z_deletecharorlist ||
  633.         cmd == z_expandorcomplete || cmd == z_expandorcompleteprefix ||
  634.         cmd == z_completeword || cmd == z_vicmdmode ||
  635.         cmd == z_acceptline || c == ' ' || c == '\t') {
  636.         LinkList cmdll;
  637.         int ambig = 100;
  638.  
  639.         HEAPALLOC {
  640.             cmdll = newlinklist();
  641.             *ptr = 0;
  642.             for (t0 = 0; t0 != ZLECMDCOUNT; t0++)
  643.             if (strpfx(buf, zlecmds[t0].name)) {
  644.                 int xx;
  645.  
  646.                 addlinknode(cmdll, zlecmds[t0].name);
  647.                 xx = pfxlen(peekfirst(cmdll), zlecmds[t0].name);
  648.                 if (xx < ambig)
  649.                 ambig = xx;
  650.             }
  651.         } LASTALLOC;
  652.         if (empty(cmdll))
  653.             feep();
  654.         else if (cmd == z_listchoices || cmd == z_deletecharorlist) {
  655.             int zmultsav = zmult;
  656.             *ptr = '_';
  657.             statusll = l + len + 1;
  658.             zmult = 1;
  659.             listlist(cmdll);
  660.             zmult = zmultsav;
  661.         } else if (!nextnode(firstnode(cmdll))) {
  662.             strcpy(ptr = buf, peekfirst(cmdll));
  663.             ptr += (len = strlen(ptr));
  664.             if(cmd == z_acceptline || cmd == z_vicmdmode)
  665.             goto unambiguous;
  666.         } else {
  667.             strcpy(buf, peekfirst(cmdll));
  668.             ptr = buf + ambig;
  669.             *ptr = '_';
  670.             if (isset(AUTOLIST) &&
  671.             !(isset(LISTAMBIGUOUS) && ambig > len)) {
  672.             int zmultsav = zmult;
  673.             if (isset(LISTBEEP))
  674.                 feep();
  675.             statusll = l + ambig + 1;
  676.             zmult = 1;
  677.             listlist(cmdll);
  678.             zmult = zmultsav;
  679.             }
  680.             len = ambig;
  681.         }
  682.         } else {
  683.         if (len == NAMLEN || icntrl(c) || cmd != z_selfinsert)
  684.             feep();
  685.         else
  686.             *ptr++ = c, len++;
  687.         }
  688.     }
  689.     }
  690. }
  691.  
  692. static char *bp;
  693. static char *truncstr;
  694. static int dontcount, lensb, trunclen;
  695.  
  696. /* stradd() adds a string to the prompt, in a *
  697.  * visible representation, doing truncation.  */
  698.  
  699. /**/
  700. void
  701. stradd(char *d)
  702. {
  703.     /* dlen is the full length of the string we want to add */
  704.     int dlen = nicestrlen(d);
  705.     char *ps, *pd, *pc, *t;
  706.     int tlen, maxlen;
  707.     addbufspc(dlen);
  708.     /* This loop puts the nice representation of the string into the prompt *
  709.      * buffer.  It might be modified later.  Note that bp isn't changed.    */
  710.     for(ps=d, pd=bp; *ps; ps++)
  711.     for(pc=nicechar(STOUC(*ps)); *pc; pc++)
  712.         *pd++ = *pc;
  713.     if(!trunclen || dlen <= trunclen) {
  714.     /* No truncation is needed, so update bp and return, *
  715.      * leaving the full string in the prompt.            */
  716.     bp += dlen;
  717.     return;
  718.     }
  719.     /* We need to truncate.  t points to the truncation string -- which is *
  720.      * inserted literally, without nice representation.  tlen is its       *
  721.      * length, and maxlen is the amout of the main string that we want to  *
  722.      * keep.  Note that if the truncation string is longer than the        *
  723.      * truncation length (tlen > trunclen), the truncation string is used  *
  724.      * in full.                                                            */
  725.     t = truncstr + 1;
  726.     tlen = strlen(t);
  727.     maxlen = tlen < trunclen ? trunclen - tlen : 0;
  728.     addbufspc(tlen);
  729.     if(*truncstr == '>') {
  730.     /* '>' means truncate at the right.  We just move past the first *
  731.      * maxlen characters of the string, and write the truncation     *
  732.      * string there.                                                 */
  733.     bp += maxlen;
  734.     while(*t)
  735.         pputc(*t++);
  736.     } else {
  737.     /* Truncation at the left: ps is initialised to the start of the *
  738.      * part of the string that we want to keep.  pc points to the    *
  739.      * end of the string.  The truncation string is added to the     *
  740.      * prompt, then the desired part of the string is copied into    *
  741.      * the right place.                                              */
  742.     ps = bp + dlen - maxlen;
  743.     pc = bp + dlen;
  744.     while(*t)
  745.         pputc(*t++);
  746.     while(ps < pc)
  747.         *bp++ = *ps++;
  748.     }
  749. }
  750.  
  751. /**/
  752. int
  753. putstr(int d)
  754. {
  755.     addbufspc(1);
  756.     *bp++ = d;
  757.     if (!dontcount)
  758.     lensb++;
  759.     return 0;
  760. }
  761.  
  762. /**/
  763. void
  764. tsetcap(int cap, int flag)
  765. {
  766.     if (!(termflags & TERM_SHORT) && tcstr[cap]) {
  767.     switch(flag) {
  768.     case -1:
  769.         tputs(tcstr[cap], 1, putraw);
  770.         break;
  771.     case 0:
  772.         tputs(tcstr[cap], 1, putshout);
  773.         break;
  774.     case 1:
  775.         if (!dontcount) {
  776.         int  t0;
  777.  
  778.         if (cap == TCSTANDOUTBEG || cap == TCSTANDOUTEND)
  779.             t0 = tgetnum("sg");
  780.         else if (cap == TCUNDERLINEBEG || cap == TCUNDERLINEEND)
  781.             t0 = tgetnum("ug");
  782.         else
  783.             t0 = 0;
  784.         if (t0 > 0)
  785.             lensb -= t0;
  786.         }
  787.         tputs(tcstr[cap], 1, putstr);
  788.         break;
  789.     }
  790.  
  791.     if (txtisset(TXTDIRTY)) {
  792.         txtunset(TXTDIRTY);
  793.         if (txtisset(TXTBOLDFACE) && cap != TCBOLDFACEBEG)
  794.         tsetcap(TCBOLDFACEBEG, flag);
  795.         if (txtisset(TXTSTANDOUT))
  796.         tsetcap(TCSTANDOUTBEG, flag);
  797.         if (txtisset(TXTUNDERLINE))
  798.         tsetcap(TCUNDERLINEBEG, flag);
  799.     }
  800.     }
  801. }
  802.  
  803. /* get a prompt string */
  804.  
  805. static char *buf, *bp1, *bl0, *fm, *pmpt;
  806. static int bracepos, bufspc, pmpth;
  807.  
  808. /**/
  809. char *
  810. putprompt(char *fmin, int *lenp, int *wp, int cnt)
  811. {
  812.     if (!fmin) {
  813.     *lenp = 0;
  814.     if (wp)
  815.         *wp = 0;
  816.     return ztrdup("");
  817.     }
  818.     pmpth = 1;
  819.  
  820.     if ((termflags & TERM_UNKNOWN) && (unset(INTERACTIVE)))
  821.         init_term();
  822.  
  823.     bracepos = -1;
  824.     fm = fmin;
  825.     lensb = 0;
  826.     pmpt = (dontcount = !cnt) ? NULL : fm;
  827.     bp = bl0 = buf = zalloc(bufspc = 256);
  828.     bp1 = NULL;
  829.  
  830.     clearerr(stdin);
  831.  
  832.     trunclen = 0;
  833.     putpromptchar(1, '\0');
  834.  
  835.     *lenp = bp - buf;
  836.     if (wp) {
  837.     *wp = bp - bl0 - lensb;
  838.     if (pmpt != rpmpt) {
  839.         *wp %= columns;
  840.         if (*wp == columns - 1) {
  841.         addbufspc(1);
  842.         *wp = 0;
  843.         *bp++ = ' ';
  844.         ++*lenp;
  845.         pmpth++;
  846.         }
  847.         if (!*wp && *lenp) {
  848.         addbufspc(1);
  849.         (*wp)++;
  850.             *bp++ = ' ';
  851.         ++*lenp;
  852.         }
  853.     }
  854.     }
  855.     if (pmpt == lpmpt)
  856.     lppth = pmpth;
  857.  
  858.     return buf;
  859. }
  860.  
  861. /**/
  862. int
  863. putpromptchar(int doprint, int endchar)
  864. {
  865.     char buf3[PATH_MAX], *ss;
  866.     int t0, arg, test, sep;
  867.     struct tm *tm;
  868.     time_t timet;
  869.     Nameddir nd;
  870.  
  871.     if (isset(PROMPTSUBST)) {
  872.     int olderr = errflag;
  873.  
  874.     HEAPALLOC {
  875.         fm = dupstring(fm);
  876.         if (!parsestr(fm))
  877.         singsub(&fm);
  878.     } LASTALLOC;
  879.     /* Ignore errors in prompt substitution */
  880.     errflag = olderr;
  881.     }
  882.     for (; *fm && *fm != endchar; fm++) {
  883.     arg = 0;
  884.     if (*fm == '%') {
  885.         if (idigit(*++fm)) {
  886.         arg = zstrtol(fm, &fm, 10);
  887.         }
  888.         if (*fm == '(') {
  889.         int tc;
  890.  
  891.         if (idigit(*++fm)) {
  892.             arg = zstrtol(fm, &fm, 10);
  893.         }
  894.         test = 0;
  895.         ss = pwd;
  896.         switch (tc = *fm) {
  897.         case 'c':
  898.         case '.':
  899.         case '~':
  900.             if ((nd = finddir(ss))) {
  901.             arg--;
  902.             ss += strlen(nd->dir);
  903.             }
  904.         case '/':
  905.         case 'C':
  906.             for (; *ss; ss++)
  907.             if (*ss == '/')
  908.                 arg--;
  909.             if (arg <= 0)
  910.             test = 1;
  911.             break;
  912.         case 't':
  913.         case 'T':
  914.         case 'd':
  915.         case 'D':
  916.         case 'w':
  917.             timet = time(NULL);
  918.             tm = localtime(&timet);
  919.             switch (tc) {
  920.             case 't':
  921.             test = (arg == tm->tm_min);
  922.             break;
  923.             case 'T':
  924.             test = (arg == tm->tm_hour);
  925.             break;
  926.             case 'd':
  927.             test = (arg == tm->tm_mday);
  928.             break;
  929.             case 'D':
  930.             test = (arg == tm->tm_mon);
  931.             break;
  932.             case 'w':
  933.             test = (arg == tm->tm_wday);
  934.             break;
  935.             }
  936.             break;
  937.         case '?':
  938.             if (lastval == arg)
  939.             test = 1;
  940.             break;
  941.         case '#':
  942.             if (geteuid() == arg)
  943.             test = 1;
  944.             break;
  945.         case 'g':
  946.             if (getegid() == arg)
  947.             test = 1;
  948.             break;
  949.         case 'L':
  950.             if (shlvl >= arg)
  951.             test = 1;
  952.             break;
  953.         case 'S':
  954.             if (time(NULL) - shtimer.tv_sec >= arg)
  955.             test = 1;
  956.             break;
  957.         case 'v':
  958.             if (arrlen(psvar) >= arg)
  959.             test = 1;
  960.             break;
  961.         case '_':
  962.             test = (cmdsp >= arg);
  963.             break;
  964.         default:
  965.             test = -1;
  966.             break;
  967.         }
  968.         if (!*fm || !(sep = *++fm))
  969.             return 0;
  970.         fm++;
  971.         if (!putpromptchar(test == 1 && doprint, sep) || !*++fm ||
  972.             !putpromptchar(test == 0 && doprint, ')')) {
  973.             return 0;
  974.         }
  975.         continue;
  976.         }
  977.         if (!doprint)
  978.         switch(*fm) {
  979.           case '[':
  980.             while(idigit(*++fm));
  981.             while(*++fm != ']');
  982.             continue;
  983.           case '<':
  984.             while(*++fm != '<');
  985.             continue;
  986.           case '>':
  987.             while(*++fm != '>');
  988.             continue;
  989.           case 'D':
  990.             if(fm[1]=='{')
  991.             while(*++fm != '}');
  992.             continue;
  993.           default:
  994.             continue;
  995.         }
  996.         switch (*fm) {
  997.         case '~':
  998.         if ((nd = finddir(pwd))) {
  999.             sprintf(buf3, "~%s%s", nd->nam, pwd + strlen(nd->dir));
  1000.             stradd(buf3);
  1001.             break;
  1002.         }
  1003.         case 'd':
  1004.         case '/':
  1005.         stradd(pwd);
  1006.         break;
  1007.         case 'c':
  1008.         case '.':
  1009.         if ((nd = finddir(pwd)))
  1010.             sprintf(buf3, "~%s%s", nd->nam, pwd + strlen(nd->dir));
  1011.         else
  1012.             strcpy(buf3, pwd);
  1013.         if (!arg)
  1014.             arg++;
  1015.         for (ss = buf3 + strlen(buf3); ss > buf3; ss--)
  1016.             if (*ss == '/' && !--arg) {
  1017.             ss++;
  1018.             break;
  1019.             }
  1020.         if (*ss == '/' && ss[1] && (ss != buf3))
  1021.             ss++;
  1022.         stradd(ss);
  1023.         break;
  1024.         case 'C':
  1025.         strcpy(buf3, pwd);
  1026.         if (!arg)
  1027.             arg++;
  1028.         for (ss = buf3 + strlen(buf3); ss > buf3; ss--)
  1029.             if (*ss == '/' && !--arg) {
  1030.             ss++;
  1031.             break;
  1032.             }
  1033.         if (*ss == '/' && ss[1] && (ss != buf3))
  1034.             ss++;
  1035.         stradd(ss);
  1036.         break;
  1037.         case 'h':
  1038.         case '!':
  1039.         addbufspc(DIGBUFSIZE);
  1040.         sprintf(bp, "%d", curhist);
  1041.         bp += strlen(bp);
  1042.         break;
  1043.         case 'M':
  1044.         stradd(hostnam);
  1045.         break;
  1046.         case 'm':
  1047.         if (!arg)
  1048.             arg++;
  1049.         for (ss = hostnam; *ss; ss++)
  1050.             if (*ss == '.' && !--arg)
  1051.             break;
  1052.         t0 = *ss;
  1053.         *ss = '\0';
  1054.         stradd(hostnam);
  1055.         *ss = t0;
  1056.         break;
  1057.         case 'S':
  1058.         txtchangeset(TXTSTANDOUT, TXTNOSTANDOUT);
  1059.         txtset(TXTSTANDOUT);
  1060.         tsetcap(TCSTANDOUTBEG, 1);
  1061.         break;
  1062.         case 's':
  1063.         txtchangeset(TXTNOSTANDOUT, TXTSTANDOUT);
  1064.         txtset(TXTDIRTY);
  1065.         txtunset(TXTSTANDOUT);
  1066.         tsetcap(TCSTANDOUTEND, 1);
  1067.         break;
  1068.         case 'B':
  1069.         txtchangeset(TXTBOLDFACE, TXTNOBOLDFACE);
  1070.         txtset(TXTDIRTY);
  1071.         txtset(TXTBOLDFACE);
  1072.         tsetcap(TCBOLDFACEBEG, 1);
  1073.         break;
  1074.         case 'b':
  1075.         txtchangeset(TXTNOBOLDFACE, TXTBOLDFACE);
  1076.         txtchangeset(TXTNOSTANDOUT, TXTSTANDOUT);
  1077.         txtchangeset(TXTNOUNDERLINE, TXTUNDERLINE);
  1078.         txtset(TXTDIRTY);
  1079.         txtunset(TXTBOLDFACE);
  1080.         tsetcap(TCALLATTRSOFF, 1);
  1081.         break;
  1082.         case 'U':
  1083.         txtchangeset(TXTUNDERLINE, TXTNOUNDERLINE);
  1084.         txtset(TXTUNDERLINE);
  1085.         tsetcap(TCUNDERLINEBEG, 1);
  1086.         break;
  1087.         case 'u':
  1088.         txtchangeset(TXTNOUNDERLINE, TXTUNDERLINE);
  1089.         txtset(TXTDIRTY);
  1090.         txtunset(TXTUNDERLINE);
  1091.         tsetcap(TCUNDERLINEEND, 1);
  1092.         break;
  1093.         case '[':
  1094.                 if (idigit(*++fm))
  1095.                     trunclen = zstrtol(fm, &fm, 10);
  1096.                 else
  1097.                     trunclen = arg;
  1098.                 if (trunclen) {
  1099.             bp1 = bp;
  1100.             while (*fm && *fm != ']') {
  1101.             if (*fm == '\\' && fm[1])
  1102.                 ++fm;
  1103.             addbufspc(1);
  1104.             *bp++ = *fm++;
  1105.             }
  1106.             addbufspc(2);
  1107.             if (bp1 == bp)
  1108.             *bp++ = '<';
  1109.                     *bp = '\0';
  1110.             zsfree(truncstr);
  1111.                     truncstr = ztrdup(bp = bp1);
  1112.             bp1 = NULL;
  1113.                 } else {
  1114.             while (*fm && *fm != ']') {
  1115.             if (*fm == '\\' && fm[1])
  1116.                 fm++;
  1117.             fm++;
  1118.             }
  1119.         }
  1120.         if(!*fm)
  1121.             return 0;
  1122.         break;
  1123.         case '<':
  1124.         case '>':
  1125.         if((trunclen = arg)) {
  1126.             bp1 = bp;
  1127.             addbufspc(1);
  1128.             *bp++ = *fm++;
  1129.             while (*fm && *fm != *bp1) {
  1130.             if (*fm == '\\' && fm[1])
  1131.                 ++fm;
  1132.             addbufspc(1);
  1133.             *bp++ = *fm++;
  1134.             }
  1135.             addbufspc(1);
  1136.                     *bp = '\0';
  1137.             zsfree(truncstr);
  1138.                     truncstr = ztrdup(bp = bp1);
  1139.             bp1 = NULL;
  1140.         } else {
  1141.             char ch = *fm++;
  1142.             while(*fm && *fm != ch) {
  1143.             if (*fm == '\\' && fm[1])
  1144.                 fm++;
  1145.             fm++;
  1146.             }
  1147.         }
  1148.         if(!*fm)
  1149.             return 0;
  1150.         break;
  1151.         case '{':
  1152.         if (!dontcount++)
  1153.             bracepos = bp - buf;
  1154.         break;
  1155.         case '}':
  1156.         if (!--dontcount && bracepos != -1) {
  1157.             lensb += (bp - buf) - bracepos;
  1158.             bracepos = -1;
  1159.         }
  1160.         break;
  1161.         case 't':
  1162.         case '@':
  1163.         case 'T':
  1164.         case '*':
  1165.         case 'w':
  1166.         case 'W':
  1167.         case 'D':
  1168.         {
  1169.             char *tmfmt, *dd;
  1170.  
  1171.             switch (*fm) {
  1172.             case 'T':
  1173.             tmfmt = "%k:%M";
  1174.             break;
  1175.             case '*':
  1176.             tmfmt = "%k:%M:%S";
  1177.             break;
  1178.             case 'w':
  1179.             tmfmt = "%a %e";
  1180.             break;
  1181.             case 'W':
  1182.             tmfmt = "%m/%d/%y";
  1183.             break;
  1184.             case 'D':
  1185.             tmfmt = "%y-%m-%d";
  1186.             if (fm[1] == '{') {
  1187.                 for (ss = fm + 2, dd = buf3; *ss && *ss != '}'; ++ss, ++dd)
  1188.                 *dd = *((*ss == '\\' && ss[1]) ? ++ss : ss);
  1189.                 if (*ss == '}') {
  1190.                 *dd = '\0';
  1191.                 fm = ss;
  1192.                 tmfmt = buf3;
  1193.                 }
  1194.             }
  1195.             break;
  1196.             default:
  1197.             tmfmt = "%l:%M%p";
  1198.             break;
  1199.             }
  1200.             timet = time(NULL);
  1201.             tm = localtime(&timet);
  1202.             addbufspc(80);   /* 80 is arbitrary :-( */
  1203.             ztrftime(bp, 79, tmfmt, tm);
  1204.             if (*bp == ' ')
  1205.             chuck(bp);
  1206.             bp += strlen(bp);
  1207.             break;
  1208.         }
  1209.         case 'n':
  1210.         stradd(get_username());
  1211.         break;
  1212.         case 'l':
  1213.         if (*ttystrname) {
  1214.             ss = (strncmp(ttystrname, "/dev/tty", 8) ?
  1215.                 ttystrname + 5 : ttystrname + 8);
  1216.             stradd(ss);
  1217.         } else
  1218.             stradd("()");
  1219.         break;
  1220.         case '?':
  1221.         addbufspc(DIGBUFSIZE);
  1222.         sprintf(bp, "%ld", (long)lastval);
  1223.         bp += strlen(bp);
  1224.         break;
  1225.         case '%':
  1226.         addbufspc(1);
  1227.         *bp++ = '%';
  1228.         break;
  1229.         case ')':
  1230.         addbufspc(1);
  1231.         *bp++ = ')';
  1232.         break;
  1233.         case '#':
  1234.         addbufspc(1);
  1235.         *bp++ = (geteuid())? '%' : '#';
  1236.         break;
  1237.         case 'v':
  1238.         if (!arg)
  1239.             arg = 1;
  1240.         if (arrlen(psvar) >= arg)
  1241.             stradd(psvar[arg - 1]);
  1242.         break;
  1243.         case 'E':
  1244.                 tsetcap(TCCLEAREOL, 1);
  1245.         break;
  1246.         case '_':
  1247.         if (cmdsp) {
  1248.             if (arg > cmdsp || arg <= 0)
  1249.             arg = cmdsp;
  1250.             for (t0 = cmdsp - arg; arg--; t0++) {
  1251.             stradd(cmdnames[cmdstack[t0]]);
  1252.             if (arg) {
  1253.                 addbufspc(1);
  1254.                 *bp++=' ';
  1255.             }
  1256.             }
  1257.         }
  1258.         break;
  1259.         case 'r':
  1260.         if (pmpt == sprompt) {
  1261.             stradd(rstring);
  1262.             break;
  1263.         }
  1264.         case 'R':
  1265.         if (pmpt == sprompt) {
  1266.             stradd(Rstring);
  1267.             break;
  1268.         }
  1269.         case '\0':
  1270.         return 0;
  1271.         default:
  1272.         addbufspc(2);
  1273.         *bp++ = '%';
  1274.         pputc(*fm);
  1275.         break;
  1276.         }
  1277.     } else if (doprint) {
  1278.         addbufspc(1);
  1279.         pputc(*fm == Meta ? *++fm ^ 32 : *fm);
  1280.     }
  1281.     }
  1282.  
  1283.     return *fm;
  1284. }
  1285.  
  1286. /**/
  1287. void
  1288. pputc(char c)
  1289. {
  1290.     if (!dontcount) {
  1291.     if (pmpt == rpmpt) {
  1292.         if (c == '\t' || c == '\n')
  1293.         c = ' ';
  1294.     } else if (c == '\t') {
  1295.         int t0 = 7 - (7 & (bp - bl0 - lensb));
  1296.         lensb -= t0;
  1297.     } else if (c == '\n') {
  1298.         *bp++ = c;
  1299.         bl0 = bp;
  1300.         lensb = 0;
  1301.         pmpth++;
  1302.         return;
  1303.     }
  1304.     }
  1305.     if (bp - bl0 == columns)
  1306.     pmpth++;
  1307.     *bp++ = c;
  1308. }
  1309.  
  1310. /**/
  1311. void
  1312. addbufspc(int need)
  1313. {
  1314.     if((bp - buf) + need > bufspc) {
  1315.     char *oldbuf = buf;
  1316.     if(need & 255)
  1317.         need = (need | 255) + 1;
  1318.     buf = realloc(buf, bufspc += need);
  1319.     bp = buf + (bp - oldbuf);
  1320.     bl0 = buf + (bl0 - oldbuf);
  1321.     if(bp1)
  1322.         bp1 = buf + (bp1 - oldbuf);
  1323.     }
  1324. }
  1325.