home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Unix / Shells / zsh / Source / src / zle_misc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-07  |  19.4 KB  |  1,125 lines

  1. /*
  2.  *
  3.  * zle_misc.c - miscellaneous editor routines
  4.  *
  5.  * This file is part of zsh, the Z shell.
  6.  *
  7.  * This software is Copyright 1992 by Paul Falstad
  8.  *
  9.  * Permission is hereby granted to copy, reproduce, redistribute or otherwise
  10.  * use this software as long as: there is no monetary profit gained
  11.  * specifically from the use or reproduction of this software, it is not
  12.  * sold, rented, traded or otherwise marketed, and this copyright notice is
  13.  * included prominently in any copy made.
  14.  *
  15.  * The author make no claims as to the fitness or correctness of this software
  16.  * for any use whatsoever, and it is provided as is. Any use of this software
  17.  * is at the user's own risk.
  18.  *
  19.  */
  20.  
  21. #define ZLE
  22. #include "zsh.h"
  23.  
  24. void selfinsert()
  25. {                /**/
  26.     int ncs = cs + mult;
  27.  
  28.     if (complexpect && isset(AUTOPARAMKEYS)) {
  29.     if (complexpect == 2 && c == '}') {
  30.         spaceinline(1);
  31.         line[cs - 1] = c;
  32.         line[cs++] = ' ';
  33.         return;
  34.     } else if (complexpect == 1 &&
  35.            (c == '[' || c == ':' || c == '#' || c == '%' ||
  36.             c == '-' || c == '?' || c == '+')) {
  37.         line[cs - 1] = c;
  38.         return;
  39.     }
  40.     }
  41.     if (mult < 0) {
  42.     mult = -mult;
  43.     ncs = cs;
  44.     }
  45.     if (insmode || ll == cs)
  46.     spaceinline(mult);
  47.     else if (mult + cs > ll)
  48.     spaceinline(ll - (mult + cs));
  49.     while (mult--)
  50.     line[cs++] = c;
  51.     cs = ncs;
  52. }
  53.  
  54. void selfinsertunmeta()
  55. {                /**/
  56.     c &= 0x7f;
  57.     if (c == '\r')
  58.         c = '\n';
  59.     selfinsert();
  60. }
  61.  
  62. void deletechar()
  63. {                /**/
  64.     if (mult < 0) {
  65.     mult = -mult;
  66.     backwarddeletechar();
  67.     return;
  68.     }
  69.     if (!(cs + mult > ll || line[cs] == '\n')) {
  70.     cs += mult;
  71.     backdel(mult);
  72.     } else
  73.     feep();
  74. }
  75.  
  76. void backwarddeletechar()
  77. {                /**/
  78.     if (mult < 0) {
  79.     mult = -mult;
  80.     deletechar();
  81.     return;
  82.     }
  83.     if (mult > cs)
  84.     mult = cs;
  85.     backdel(mult);
  86. }
  87.  
  88. void vibackwarddeletechar()
  89. {                /**/
  90.     if (mult < 0) {
  91.     mult = -mult;
  92.     videletechar();
  93.     return;
  94.     }
  95.     if (mult > cs)
  96.     mult = cs;
  97.     if (cs - mult < viinsbegin) {
  98.     feep();
  99.     return;
  100.     }
  101.     backkill(mult, 1);
  102. }
  103.  
  104. void vikillline()
  105. {                /**/
  106.     if (viinsbegin > cs) {
  107.     feep();
  108.     return;
  109.     }
  110.     backdel(cs - viinsbegin);
  111. }
  112.  
  113. void killwholeline()
  114. {                /**/
  115.     int i, fg;
  116.  
  117.     if (mult < 0)
  118.     return;
  119.     while (mult--) {
  120.     if ((fg = (cs && cs == ll)))
  121.         cs--;
  122.     while (cs && line[cs - 1] != '\n')
  123.         cs--;
  124.     for (i = cs; i != ll && line[i] != '\n'; i++);
  125.     forekill(i - cs + (i != ll), fg);
  126.     }
  127. }
  128.  
  129. void killbuffer()
  130. {                /**/
  131.     cs = 0;
  132.     forekill(ll, 0);
  133. }
  134.  
  135. void backwardkillline()
  136. {                /**/
  137.     int i = 0;
  138.  
  139.     if (mult < 0) {
  140.     mult = -mult;
  141.     killline();
  142.     return;
  143.     }
  144.     while (mult--) {
  145.     if (cs && line[cs - 1] == '\n')
  146.         cs--, i++;
  147.     else
  148.         while (cs && line[cs - 1] != '\n')
  149.         cs--, i++;
  150.     }
  151.     forekill(i, 1);
  152. }
  153.  
  154. void gosmacstransposechars()
  155. {                /**/
  156.     int cc;
  157.  
  158.     if (cs < 2 || line[cs - 1] == '\n' || line[cs - 2] == '\n') {
  159.     if (line[cs] == '\n' || line[cs + 1] == '\n') {
  160.         feep();
  161.         return;
  162.     }
  163.     cs += (cs == 0 || line[cs - 1] == '\n') ? 2 : 1;
  164.     }
  165.     cc = line[cs - 2];
  166.     line[cs - 2] = line[cs - 1];
  167.     line[cs - 1] = cc;
  168. }
  169.  
  170. void transposechars()
  171. {                /**/
  172.     int cc, ct;
  173.     int neg = mult < 0;
  174.  
  175.     if (neg)
  176.     mult = -mult;
  177.     while (mult--) {
  178.     if (!(ct = cs) || line[cs - 1] == '\n') {
  179.         if (ll == cs || line[cs] == '\n') {
  180.         feep();
  181.         return;
  182.         }
  183.         if (!neg)
  184.         cs++;
  185.         ct++;
  186.     }
  187.     if (neg) {
  188.         if (cs && line[cs - 1] != '\n') {
  189.         cs--;
  190.         if (ct > 1 && line[ct - 2] != '\n')
  191.             ct--;
  192.         }
  193.     } else {
  194.         if (cs != ll && line[cs] != '\n')
  195.         cs++;
  196.     }
  197.     if (ct == ll || line[ct] == '\n')
  198.         ct--;
  199.     if (ct < 1 || line[ct - 1] == '\n') {
  200.         feep();
  201.         return;
  202.     }
  203.     cc = line[ct - 1];
  204.     line[ct - 1] = line[ct];
  205.     line[ct] = cc;
  206.     }
  207. }
  208.  
  209. void poundinsert()
  210. {                /**/
  211.     if (*line != '#') {
  212.     cs = 0;
  213.     spaceinline(1);
  214.     *line = '#';
  215.     } else {
  216.     cs = 0;
  217.     foredel(1);
  218.     }
  219.     done = 1;
  220. }
  221.  
  222. void acceptline()
  223. {                /**/
  224.     done = 1;
  225. }
  226.  
  227. void acceptandhold()
  228. {                /**/
  229.     pushnode(bufstack, ztrdup((char *)line));
  230.     stackcs = cs;
  231.     done = 1;
  232. }
  233.  
  234. void killline()
  235. {                /**/
  236.     int i = 0;
  237.  
  238.     if (mult < 0) {
  239.     mult = -mult;
  240.     backwardkillline();
  241.     return;
  242.     }
  243.     while (mult--) {
  244.     if (line[cs] == '\n')
  245.         cs++, i++;
  246.     else
  247.         while (cs != ll && line[cs] != '\n')
  248.         cs++, i++;
  249.     }
  250.     backkill(i, 0);
  251. }
  252.  
  253. void killregion()
  254. {                /**/
  255.     if (mark > ll)
  256.     mark = ll;
  257.     if (mark > cs)
  258.     forekill(mark - cs, 0);
  259.     else
  260.     backkill(cs - mark, 1);
  261. }
  262.  
  263. void copyregionaskill()
  264. {                /**/
  265.     if (mark > ll)
  266.     mark = ll;
  267.     if (mark > cs)
  268.     cut(cs, mark - cs, 0);
  269.     else
  270.     cut(mark, cs - mark, 1);
  271. }
  272.  
  273. static int kct, yankb, yanke;
  274.  
  275. void yank()
  276. {                /**/
  277.     int cc;
  278.     char *buf = cutbuf;
  279.  
  280.     if (!cutbuf) {
  281.     feep();
  282.     return;
  283.     }
  284.     if (mult < 0)
  285.     return;
  286.     if (vibufspec) {
  287.     if (!(buf = vibuf[vibufspec])) {
  288.         feep();
  289.         vibufspec = 0;
  290.         return;
  291.     }
  292.     vibufspec = 0;
  293.     }
  294.     yankb = cs;
  295.     while (mult--) {
  296.     kct = kringnum;
  297.     cc = strlen(buf);
  298.     spaceinline(cc);
  299.     strncpy((char *)line + cs, buf, cc);
  300.     cs += cc;
  301.     yanke = cs;
  302.     }
  303. }
  304.  
  305. void viputafter()
  306. {                /**/
  307.     int cc;
  308.     char *buf = cutbuf;
  309.  
  310.     if (!cutbuf) {
  311.     feep();
  312.     return;
  313.     }
  314.     if (mult < 0)
  315.     return;
  316.     if (vibufspec) {
  317.     if (!(buf = vibuf[vibufspec])) {
  318.         feep();
  319.         vibufspec = 0;
  320.         return;
  321.     }
  322.     vibufspec = 0;
  323.     }
  324.     if (strchr(buf, '\n')) {
  325.     cs = findeol();
  326.     if (cs == ll) {
  327.         spaceinline(1);
  328.         line[cs] = '\n';
  329.     }
  330.     }
  331.     if (cs != ll)
  332.     cs++;
  333.     yankb = cs;
  334.     while (mult--) {
  335.     kct = kringnum;
  336.     cc = strlen(buf);
  337.     spaceinline(cc);
  338.     strncpy((char *)line + cs, buf, cc);
  339.     cs += cc;
  340.     yanke = cs;
  341.     }
  342.     cs = yankb;
  343. }
  344.  
  345. void yankpop()
  346. {                /**/
  347.     int cc;
  348.  
  349.     if (!(lastcmd & ZLE_YANK) || !kring[kct]) {
  350.     feep();
  351.     return;
  352.     }
  353.     cs = yankb;
  354.     foredel(yanke - yankb);
  355.     cc = strlen(kring[kct]);
  356.     spaceinline(cc);
  357.     strncpy((char *)line + cs, kring[kct], cc);
  358.     cs += cc;
  359.     yanke = cs;
  360.     kct = (kct - 1) & (KRINGCT - 1);
  361. }
  362.  
  363. void overwritemode()
  364. {                /**/
  365.     insmode ^= 1;
  366. }
  367.  
  368. void undefinedkey()
  369. {                /**/
  370.     feep();
  371. }
  372.  
  373. void quotedinsert()
  374. {                /**/
  375. #ifndef HAS_TIO
  376.     struct sgttyb sob;
  377.  
  378.     sob = shttyinfo.sgttyb;
  379.     sob.sg_flags = (sob.sg_flags | RAW) & ~ECHO;
  380.     ioctl(SHTTY, TIOCSETN, &sob);
  381. #endif
  382.     c = getkey(0);
  383. #ifndef HAS_TIO
  384.     setterm();
  385. #endif
  386.     if (c > 0)
  387.     selfinsert();
  388.     else
  389.     feep();
  390. }
  391.  
  392. void digitargument()
  393. {                /**/
  394.     int sign = (mult < 0 || (lastcmd & ZLE_NEGARG)) ? -1 : 1;
  395.  
  396.     if ((lastcmd & (ZLE_ARG | ZLE_NEGARG)) != ZLE_ARG)
  397.     mult = 0;
  398.     mult = mult * 10 + sign * (c & 0xf);
  399. }
  400.  
  401. void negargument()
  402. {                /**/
  403.     if (lastcmd & ZLE_ARG)
  404.     feep();
  405.     mult = -1;
  406. }
  407.  
  408. void universalargument()
  409. {                /**/
  410.     if (!(lastcmd & ZLE_ARG))
  411.     mult = 4;
  412.     else
  413.     mult *= 4;
  414. }
  415.  
  416. void copyprevword()
  417. {                /**/
  418.     int len, t0;
  419.  
  420.     for (t0 = cs - 1; t0 >= 0; t0--)
  421.     if (iword(line[t0]))
  422.         break;
  423.     for (; t0 >= 0; t0--)
  424.     if (!iword(line[t0]))
  425.         break;
  426.     if (t0)
  427.     t0++;
  428.     len = cs - t0;
  429.     spaceinline(len);
  430.     strncpy((char *)line + cs, (char *)line + t0, len);
  431.     cs += len;
  432. }
  433.  
  434. void sendbreak()
  435. {                             /**/
  436.     errflag = 1;
  437. }
  438.  
  439. void undo()
  440. {                /**/
  441.     char *s;
  442.     struct undoent *ue;
  443.  
  444.     ue = undos + undoct;
  445.     if (!ue->change) {
  446.     feep();
  447.     return;
  448.     }
  449.     line[ll] = '\0';
  450.     s = ztrdup((char *)line + ll - ue->suff);
  451.     sizeline((ll = ue->pref + ue->suff + ue->len) + 1);
  452.     strncpy((char *)line + ue->pref, ue->change, ue->len);
  453.     strcpy((char *)line + ue->pref + ue->len, s);
  454.     zsfree(s);
  455.     ue->change = NULL;
  456.     undoct = (undoct - 1) & (UNDOCT - 1);
  457.     cs = ue->cs;
  458. }
  459.  
  460. void quoteregion()
  461. {                /**/
  462.     char *s, *t;
  463.     int x, y;
  464.  
  465.     if (mark > ll)
  466.     mark = ll;
  467.     if (mark < cs) {
  468.     x = mark;
  469.     mark = cs;
  470.     cs = x;
  471.     }
  472.     s = (char *)hcalloc((y = mark - cs) + 1);
  473.     strncpy(s, (char *)line + cs, y);
  474.     s[y] = '\0';
  475.     foredel(mark - cs);
  476.     t = makequote(s);
  477.     spaceinline(x = strlen(t));
  478.     strncpy((char *)line + cs, t, x);
  479.     mark = cs;
  480.     cs += x;
  481. }
  482.  
  483. void quoteline()
  484. {                /**/
  485.     char *s;
  486.  
  487.     line[ll] = '\0';
  488.     s = makequote((char *)line);
  489.     setline(s);
  490. }
  491.  
  492. char *makequote(s)        /**/
  493. char *s;
  494. {
  495.     int qtct = 0;
  496.     char *l, *ol;
  497.  
  498.     for (l = s; *l; l++)
  499.     if (*l == '\'')
  500.         qtct++;
  501.     l = ol = (char *)halloc((qtct * 3) + 3 + strlen(s));
  502.     *l++ = '\'';
  503.     for (; *s; s++)
  504.     if (*s == '\'') {
  505.         *l++ = '\'';
  506.         *l++ = '\\';
  507.         *l++ = '\'';
  508.         *l++ = '\'';
  509.     } else
  510.         *l++ = *s;
  511.     *l++ = '\'';
  512.     *l = '\0';
  513.     return ol;
  514. }
  515.  
  516. #define NAMLEN 70
  517.  
  518. int executenamedcommand()
  519. {                /**/
  520.     char buf[NAMLEN], *ptr;
  521.     int len, cmd, t0;
  522.  
  523.     strcpy(buf, "execute: ");
  524.     ptr = buf + 9;
  525.     len = 0;
  526.     statusline = buf;
  527.     refresh();
  528.     for (; ; refresh()) {
  529.     if ((cmd = getkeycmd()) < 0 || cmd == z_sendbreak) {
  530.         statusline = NULL;
  531.         return z_undefinedkey;
  532.     }
  533.     switch (cmd) {
  534.       case z_backwarddeletechar:
  535.       case z_vibackwarddeletechar:
  536.         if (len) {
  537.         len--;
  538.         *--ptr = '\0';
  539.         }
  540.         break;
  541.       case z_killregion:
  542.       case z_backwardkillword:
  543.       case z_vibackwardkillword:
  544.         while (len && (len--, *--ptr != '-'))
  545.         *ptr = '\0';
  546.         break;
  547.       case z_killwholeline:
  548.       case z_vikillline:
  549.       case z_backwardkillline:
  550.         len = 0;
  551.         ptr = buf + 9;
  552.         *ptr = '\0';
  553.         break;
  554.       case z_acceptline:
  555.         for (t0 = 0; t0 != ZLECMDCOUNT; t0++)
  556.         if (!strcmp(buf + 9, zlecmds[t0].name))
  557.             break;
  558.         if (t0 != ZLECMDCOUNT) {
  559.         lastnamed = t0;
  560.         statusline = NULL;
  561.         return t0;
  562.         } else {
  563.         feep();
  564.         break;
  565.         }
  566.       default:
  567.         if (cmd == z_listchoices || cmd == z_deletecharorlist ||
  568.         c == ' ' || c == '\t') {
  569.         Lklist cmdll;
  570.         int ambig = 100;
  571.  
  572.         heapalloc();
  573.         cmdll = newlist();
  574.         for (t0 = 0; t0 != ZLECMDCOUNT; t0++)
  575.             if (strpfx(buf + 9, zlecmds[t0].name)) {
  576.             int xx;
  577.  
  578.             addnode(cmdll, zlecmds[t0].name);
  579.             xx = pfxlen(peekfirst(cmdll), zlecmds[t0].name);
  580.             if (xx < ambig)
  581.                 ambig = xx;
  582.             }
  583.         permalloc();
  584.         if (empty(cmdll))
  585.             feep();
  586.         else if (cmd == z_listchoices ||
  587.              cmd == z_deletecharorlist)
  588.             listlist(cmdll);
  589.         else if (!nextnode(firstnode(cmdll))) {
  590.             strcpy(buf + 9, peekfirst(cmdll));
  591.             ptr = buf + (len = strlen(buf));
  592.         } else {
  593.             strcpy(buf + 9, peekfirst(cmdll));
  594.             len = ambig;
  595.             ptr = buf + 9 + len;
  596.             *ptr = '\0';
  597.             feep();
  598.             if (isset(AUTOLIST))
  599.             listlist(cmdll);
  600.         }
  601.         } else {
  602.         if (len == NAMLEN - 10 || icntrl(c))
  603.             feep();
  604.         else
  605.             *ptr++ = c, *ptr = '\0', len++;
  606.         }
  607.     }
  608.     }
  609. }
  610.  
  611. void vijoin()
  612. {                /**/
  613.     int x;
  614.  
  615.     if ((x = findeol()) == ll) {
  616.     feep();
  617.     return;
  618.     }
  619.     cs = x + 1;
  620.     for (x = 1; cs != ll && iblank(line[cs]); cs++, x++);
  621.     backdel(x);
  622.     spaceinline(1);
  623.     line[cs] = ' ';
  624. }
  625.  
  626. void viswapcase()
  627. {                /**/
  628.     if (cs < ll) {
  629.     int ch = line[cs];
  630.  
  631.     if (islower(ch))
  632.         ch = tuupper(ch);
  633.     else if (isupper(ch))
  634.         ch = tulower(ch);
  635.     line[cs] = ch;
  636.     if (cs != ll - 1)
  637.         cs++;
  638.     }
  639. }
  640.  
  641. void vicapslockpanic()
  642. {                /**/
  643.     char ch;
  644.  
  645.     statusline = "press a lowercase key to continue";
  646.     refresh();
  647.     do
  648.     ch = getkey(0);
  649.     while (!islower(ch));
  650. }
  651.  
  652. int owrite;
  653.  
  654. void visetbuffer()
  655. {                /**/
  656.     int ch;
  657.  
  658.     ch = getkey(0);
  659.     if (!isalnum(ch)) {
  660.     feep();
  661.     return;
  662.     }
  663.     if (ch >= 'A' && ch <= 'Z')    /* needed in cut() */
  664.     owrite = 0;
  665.     else
  666.     owrite = 1;
  667.     vibufspec = tolower(ch) + (idigit(ch)) ? -'1' + 26 : -'a';
  668. }
  669.  
  670. static char *bp;
  671. static int lensb, countp;
  672.  
  673. void stradd(d)            /**/
  674. char *d;
  675. {
  676.     while ((*bp++ = *d++));
  677.     bp--;
  678. }
  679.  
  680. int putstr(d)            /**/
  681. int d;
  682. {
  683.     *bp++ = d;
  684.     if (countp)
  685.     lensb++;
  686.     return 0;
  687. }
  688.  
  689. void tstradd(X)    /**/
  690. char *X;
  691. {
  692.     int t0;
  693.  
  694.     if (termok && unset(SINGLELINEZLE)) {
  695. #ifdef _IBMR2
  696.     /* AIX tgetstr() ignores second argument */
  697.     char *tbuf;
  698.  
  699.     if (tbuf = tgetstr(X, &tbuf))
  700. #else
  701.     char tbuf[2048], *tptr = tbuf;
  702.     if (tgetstr(X, &tptr))
  703. #endif
  704.         tputs(tbuf, 1, putstr);
  705.     if (*X == 's' && (X[1] == 'o' || X[1] == 'e') &&
  706.         (t0 = tgetnum("sg")) > - 1)
  707.         lensb -= t0;
  708.     }
  709. }
  710.  
  711. /* get a prompt string */
  712.  
  713. static char *buf, *bl0, *fm;
  714. static int bracepos;
  715.  
  716. char *putprompt(fmin, lenp, isspell)    /**/
  717. char *fmin;
  718. int *lenp;
  719. int isspell;
  720. {
  721.     static char buf0[256], buf1[256], buf2[256];
  722.  
  723.     bracepos = 0;
  724.     lensb = 0;
  725.     countp = 1;
  726.     fm = fmin;
  727.     if (!fm) {
  728.     *lenp = 0;
  729.     return "";
  730.     }
  731. /* KLUDGE ALERT!  What we have here are three buffers:
  732.      *  buf1 and buf2 alternate between PS1 and PS2, though which is
  733.      *   which is indeterminate depending on spellchecking, "select",
  734.      *   etc. -- those operations also share these two buffers.
  735.      *  buf0 is used for any prompting that manages to happen while
  736.      *   zleread() is in progress (signal traps, etc.), because
  737.      *   zleread() re-uses the pointers returned to buf1 and buf2
  738.      *   and will be confused if either of those is overwritten.
  739.      */
  740.     buf = zleactive ? buf0 : ((buf == buf1) ? buf2 : buf1);
  741.     bp = bl0 = buf;
  742.     if (!columns)
  743.     columns = 80;
  744.     clearerr(stdin);
  745.  
  746.     putpromptchar(isspell == -1 ? 0 : isspell, 1, '\0');
  747.   
  748.     if ( isspell != -1 ){
  749.       *lenp = (bp - bl0) - lensb;
  750.       *lenp %= columns;
  751.       if (*lenp == columns - 1) {
  752.         *lenp = 0;
  753.         *bp++ = ' ';
  754.         }
  755.      }
  756.     else
  757.     *lenp = (bp - bl0);
  758.       *bp = '\0';
  759.  
  760.     *bp = '\0';
  761.     return buf;
  762. }
  763.  
  764. int putpromptchar(isspell, doprint, endchar)    /**/
  765. int isspell;
  766. int doprint;
  767. int endchar;
  768. {
  769.     char buf3[MAXPATHLEN], *ss;
  770.     int t0, arg, test, sep;
  771.     struct tm *tm;
  772.     time_t timet;
  773.  
  774.     if (isset(PROMPTSUBST)) {
  775.     char *sss;
  776.  
  777.     fm = dupstring(fm);
  778.     for (ss = fm; *ss; ss++)
  779.         if (*ss == '$' && ss[1] && (ss == fm || ss[-1] != '%')) {
  780.         *ss = String;
  781.         if (ss[1] == '[') {
  782.             ss[1] = Inbrack;
  783.             for (t0 = 0, sss = ss + 2; *sss && (t0 || *sss != ']'); sss++) {
  784.             if (*sss == '[')
  785.                 t0++;
  786.             if (*sss == ']')
  787.                 t0--;
  788.             if (*sss == '\\' && sss[1])
  789.                 sss++;
  790.             }
  791.             if (*sss == ']')
  792.             *sss = Outbrack, ss = sss;
  793.         } else if (ss[1] == '(') {
  794.             ss[1] = Inpar;
  795.             for (t0 = 0, sss = ss + 2; *sss && (t0 || *sss != ')'); sss++) {
  796.             if (*sss == '(')
  797.                 t0++;
  798.             if (*sss == ')')
  799.                 t0--;
  800.             if (*sss == '\\' && sss[1])
  801.                 sss++;
  802.             }
  803.             if (*sss == ')')
  804.             *sss = Outpar, ss = sss;
  805.         }
  806.         }
  807.     lexsave();
  808.     singsub(&fm);
  809.     lexrestore();
  810.     }
  811.     for (; *fm && *fm != endchar; fm++) {
  812.     if (bp - buf >= 220)
  813.         break;
  814.     arg = 0;
  815.     if (*fm == '%') {
  816.         if (idigit(*++fm)) {
  817.         arg = zstrtol(fm, &fm, 10);
  818.         }
  819.         if (*fm == '(') {
  820.         int tc;
  821.  
  822.         if (idigit(*++fm)) {
  823.             arg = zstrtol(fm, &fm, 10);
  824.         }
  825.         test = 0;
  826.         ss = pwd;
  827.         switch (tc = *fm) {
  828.         case 'c':
  829.         case '.':
  830.         case '~':
  831.             t0 = finddir(ss);
  832.             if (t0 != -1) {
  833.             arg--;
  834.             ss += namdirs[t0].len;
  835.             }
  836.         case '/':
  837.         case 'C':
  838.             for (; *ss; ss++)
  839.             if (*ss == '/')
  840.                 arg--;
  841.             if (arg <= 0)
  842.             test = 1;
  843.             break;
  844.         case 't':
  845.         case 'T':
  846.         case 'd':
  847.         case 'D':
  848.         case 'w':
  849.             timet = time(NULL);
  850.             tm = localtime(&timet);
  851.             switch (tc) {
  852.             case 't':
  853.             test = (arg == tm->tm_min);
  854.             break;
  855.             case 'T':
  856.             test = (arg == tm->tm_hour);
  857.             break;
  858.             case 'd':
  859.             test = (arg == tm->tm_mday);
  860.             break;
  861.             case 'D':
  862.             test = (arg == tm->tm_mon);
  863.             break;
  864.             case 'w':
  865.             test = (arg == tm->tm_wday);
  866.             break;
  867.             }
  868.             break;
  869.         case '?':
  870.             if (lastval == arg)
  871.             test = 1;
  872.             break;
  873.         case '#':
  874.             if (geteuid() == arg)
  875.             test = 1;
  876.             break;
  877.         case 'g':
  878.             if (getegid() == arg)
  879.             test = 1;
  880.             break;
  881.         case 'L':
  882.             if (shlvl >= arg)
  883.             test = 1;
  884.             break;
  885.         case 'S':
  886.             if (time(NULL) - shtimer.tv_sec >= arg)
  887.             test = 1;
  888.             break;
  889.         case 'v':
  890.             if (arrlen(psvar) >= arg)
  891.             test = 1;
  892.             break;
  893.         case '_':
  894.             test = (cmdsp >= arg);
  895.             break;
  896.         default:
  897.             test = -1;
  898.             break;
  899.         }
  900.         if (!*fm || !(sep = *++fm))
  901.             return 0;
  902.         fm++;
  903.         if (!putpromptchar(isspell, test == 1 && doprint, sep) || !*++fm ||
  904.             !putpromptchar(isspell, test == 0 && doprint, ')')) {
  905.             return 0;
  906.         }
  907.         continue;
  908.         }
  909.         if (!doprint)
  910.         continue;
  911.         switch (*fm) {
  912.         case '~':
  913.         t0 = finddir(pwd);
  914.         if (t0 != -1) {
  915.             *bp++ = '~';
  916.             stradd(namdirs[t0].name);
  917.             stradd(pwd + namdirs[t0].len);
  918.             break;
  919.         }
  920.         case 'd':
  921.         case '/':
  922.         stradd(pwd);
  923.         break;
  924.         case 'c':
  925.         case '.':
  926.         t0 = finddir(pwd);
  927.         if (t0 != -1) {
  928.             sprintf(buf3, "~%s%s", namdirs[t0].name,
  929.                 pwd + namdirs[t0].len);
  930.         } else {
  931.             strcpy(buf3, pwd);
  932.         }
  933.         if (!arg)
  934.             arg++;
  935.         for (ss = buf3 + strlen(buf3); ss > buf3; ss--)
  936.             if (*ss == '/' && !--arg) {
  937.             ss++;
  938.             break;
  939.             }
  940.         if (*ss == '/' && ss[1] && (ss != buf3))
  941.             ss++;
  942.         stradd(ss);
  943.         break;
  944.         case 'C':
  945.         strcpy(buf3, pwd);
  946.         if (!arg)
  947.             arg++;
  948.         for (ss = buf3 + strlen(buf3); ss > buf3; ss--)
  949.             if (*ss == '/' && !--arg) {
  950.             ss++;
  951.             break;
  952.             }
  953.         if (*ss == '/' && ss[1] && (ss != buf3))
  954.             ss++;
  955.         stradd(ss);
  956.         break;
  957.         case 'h':
  958.         case '!':
  959.         sprintf(bp, "%d", curhist);
  960.         bp += strlen(bp);
  961.         break;
  962.         case 'M':
  963.         stradd(hostnam);
  964.         break;
  965.         case 'm':
  966.         if (!arg)
  967.             arg++;
  968.         for (ss = hostnam; *ss; ss++)
  969.             if (*ss == '.' && !--arg)
  970.             break;
  971.         t0 = *ss;
  972.         *ss = '\0';
  973.         stradd(hostnam);
  974.         *ss = t0;
  975.         break;
  976.         case 'S':
  977.         tstradd("so");
  978.         break;
  979.         case 's':
  980.         tstradd("se");
  981.         break;
  982.         case 'B':
  983.         tstradd("md");
  984.         break;
  985.         case 'b':
  986.         tstradd("me");
  987.         break;
  988.         case 'U':
  989.         tstradd("us");
  990.         break;
  991.         case 'u':
  992.         tstradd("ue");
  993.         break;
  994.         case '{':
  995.         bracepos = bp - buf;
  996.         countp = 0;
  997.         break;
  998.         case '}':
  999.         lensb += (bp - buf) - bracepos;
  1000.         countp = 1;
  1001.         break;
  1002.         case 't':
  1003.         case '@':
  1004.         case 'T':
  1005.         case '*':
  1006.         case 'w':
  1007.         case 'W':
  1008.         case 'D':
  1009.         {
  1010.             char *tmfmt, *dd;
  1011.  
  1012.             switch (*fm) {
  1013.             case 'T':
  1014.             tmfmt = "%k:%M";
  1015.             break;
  1016.             case '*':
  1017.             tmfmt = "%k:%M:%S";
  1018.             break;
  1019.             case 'w':
  1020.             tmfmt = "%a %e";
  1021.             break;
  1022.             case 'W':
  1023.             tmfmt = "%m/%d/%y";
  1024.             break;
  1025.             case 'D':
  1026.             tmfmt = "%y-%m-%d";
  1027.             if (fm[1] == '{') {
  1028.                 for (ss = fm + 2, dd = buf3; *ss && *ss != '}'; ++ss, ++dd)
  1029.                 *dd = *((*ss == '\\' && ss[1]) ? ++ss : ss);
  1030.                 if (*ss == '}') {
  1031.                 *dd = '\0';
  1032.                 fm = ss;
  1033.                 tmfmt = buf3;
  1034.                 }
  1035.             }
  1036.             break;
  1037.             default:
  1038.             tmfmt = "%l:%M%p";
  1039.             break;
  1040.             }
  1041.             timet = time(NULL);
  1042.             tm = localtime(&timet);
  1043.             ztrftime(bp, buf + 220 - bp, tmfmt, tm);
  1044.             if (*bp == ' ')
  1045.             chuck(bp);
  1046.             bp += strlen(bp);
  1047.             break;
  1048.         }
  1049.         case 'n':
  1050.         stradd(username);
  1051.         break;
  1052.         case 'l':
  1053.         if (*ttystrname)
  1054.             stradd((strncmp(ttystrname, "/dev/tty", 8) ?
  1055.                 ttystrname + 5 : ttystrname + 8));
  1056.         else
  1057.             stradd("()");
  1058.         break;
  1059.         case '?':
  1060.         sprintf(bp, "%ld", (long) lastval);
  1061.         bp += strlen(bp);
  1062.         break;
  1063.         case '%':
  1064.         *bp++ = '%';
  1065.         break;
  1066.         case '#':
  1067.         *bp++ = (geteuid())? '%' : '#';
  1068.         break;
  1069.         case 'v':
  1070.         if (!arg)
  1071.             arg++;
  1072.         /* The number 35 here comes from 256-220-1, where 256 is
  1073.            sizeof(buf), 220 is from the overflow test made at the
  1074.            top of the loop, and 1 is for the \0 byte at the end. */
  1075.  
  1076.         if (arrlen(psvar) >= arg && (int) strlen(psvar[arg - 1]) < 35)
  1077.             stradd(psvar[arg - 1]);
  1078.         else
  1079.             stradd("");
  1080.         break;
  1081.         case 'E':
  1082.         tstradd("ce");
  1083.         break;
  1084.         case '_':
  1085.         if (cmdsp) {
  1086.             if (arg <= 0)
  1087.             arg = 1;
  1088.             if (arg > cmdsp)
  1089.             arg = cmdsp;
  1090.             for (t0 = cmdsp - arg; arg--; t0++) {
  1091.             stradd(cmdnames[cmdstack[t0]]);
  1092.             if (arg)
  1093.                 stradd(" ");
  1094.             }
  1095.         }
  1096.         break;
  1097.         case 'r':
  1098.         if (isspell) {
  1099.             stradd(rstring);
  1100.             break;
  1101.         }
  1102.         case 'R':
  1103.         if (isspell) {
  1104.             stradd(Rstring);
  1105.             break;
  1106.         }
  1107.         default:
  1108.         *bp++ = '%';
  1109.         *bp++ = *fm;
  1110.         break;
  1111.         }
  1112.     } else if (*fm == '!' && doprint) {
  1113.         sprintf(bp, "%d", curhist);
  1114.         bp += strlen(bp);
  1115.     } else {
  1116.         if (fm[0] == '\\' && fm[1])
  1117.         fm++;
  1118.         if (doprint && (*bp++ = *fm) == '\n')
  1119.         bl0 = bp, lensb = 0;
  1120.     }
  1121.     }
  1122.  
  1123.     return *fm;
  1124. }
  1125.