home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d3xx / d352 / mg.lha / MG / src.LZH / mg / echo.c < prev    next >
C/C++ Source or Header  |  1990-05-23  |  14KB  |  755 lines

  1. /*
  2.  * Echo line reading and writing. 
  3.  *
  4.  * Common routines for reading and writing characters in the echo line area of
  5.  * the display screen. Used by the entire known universe. 
  6.  */
  7. #include    "no_macro.h"
  8.  
  9. #include    "def.h"
  10. #include    "key.h"
  11. #ifdef        ANSI
  12. #include    <stdarg.h>
  13. #else
  14. #include    "varargs.h"
  15. #endif
  16. #include    "line.h"
  17. #include    "buffer.h"
  18. #include    "no_metakey.h"
  19. #ifndef NO_MACRO
  20. #  include    "macro.h"
  21. #endif
  22.  
  23. int             epresf = FALSE;    /* Stuff in echo line flag.     */
  24. #ifdef    LATTICE_50
  25. static char     a;        /* Sigh */
  26. #endif
  27.  
  28. #ifdef    ANSI
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #else
  32. VOID            ewprintf();
  33. #endif
  34.  
  35. static int veread 
  36. PROTO((char *fp, char *buf, int nbuf, int flag, va_list * ap));
  37. static int complt 
  38. PROTO((int flags, int c, char *buf, int cpos));
  39. static VOID eformat 
  40. PROTO((char *fp, va_list * ap));
  41. static VOID eputi 
  42. PROTO((int i, int r));
  43. static VOID eputl 
  44. PROTO((long l, int r));
  45. static VOID eputs 
  46. PROTO((char *s));
  47. static VOID eputc 
  48. PROTO((int c));
  49. static int      complete_list
  50. PROTO((struct list * lh, int c, char *buf, int cpos));
  51. static int      getxtra
  52. PROTO((register struct list *, register struct list *, int, register int));
  53.  
  54. /*
  55.  * Erase the echo line. 
  56.  */
  57. VOID
  58. eerase()
  59. {
  60. #ifndef    NO_MACRO
  61.     if (inmacro)
  62.         return;
  63. #endif
  64.     ttcolor(CTEXT);
  65.     ttmove(nrow - 1, 0);
  66.     tteeol();
  67.     ttflush();
  68.     epresf = FALSE;
  69. }
  70.  
  71. /*
  72.  * Ask "yes" or "no" question. Return ABORT if the user answers the question
  73.  * with the abort ("^G") character. Return FALSE for "no" and TRUE for "yes".
  74.  * No formatting services are available. No newline required. 
  75.  */
  76. eyorn(sp)
  77.     char           *sp;
  78. {
  79.     register int    s;
  80.  
  81.     ewprintf("%s? (y or n) ", sp);
  82.     for (;;) {
  83.         s = getkey(DISSCR);
  84.         if (s == 'y' || s == 'Y')
  85.             return TRUE;
  86.         if (s == 'n' || s == 'N')
  87.             return FALSE;
  88.         if (s == CCHR('G'))
  89.             return ctrlg(FFRAND, 1);
  90.         ewprintf("Please answer y or n.  %s? (y or n) ", sp);
  91.     }
  92.     /* NOTREACHED */
  93. }
  94.  
  95. /*
  96.  * Like eyorn, but for more important question. User must type either all of
  97.  * "yes" or "no", and the trainling newline. 
  98.  */
  99. eyesno(sp)
  100.     char           *sp;
  101. {
  102.     register int    s;
  103.     char            buf[64];
  104.  
  105.     s = ereply("%s? (yes or no) ", buf, sizeof(buf), sp);
  106.     for (;;) {
  107.         if (s == ABORT)
  108.             return ABORT;
  109.         if (s != FALSE) {
  110.             if ((buf[0] == 'y' || buf[0] == 'Y')
  111.                 && (buf[1] == 'e' || buf[1] == 'E')
  112.                 && (buf[2] == 's' || buf[2] == 'S')
  113.                 && (buf[3] == '\0'))
  114.                 return TRUE;
  115.             if ((buf[0] == 'n' || buf[0] == 'N')
  116.                 && (buf[1] == 'o' || buf[0] == 'O')
  117.                 && (buf[2] == '\0'))
  118.                 return FALSE;
  119.         }
  120.         s = ereply("Please answer yes or no.  %s? (yes or no) ",
  121.                buf, sizeof(buf), sp);
  122.     }
  123.     /* NOTREACHED */
  124. }
  125. /*
  126.  * Write out a prompt, and read back a reply. The prompt is now written out
  127.  * with full "ewprintf" formatting, although the arguments are in a rather
  128.  * strange place. This is always a new message, there is no auto completion,
  129.  * and the return is echoed as such. 
  130.  */
  131. #ifndef ANSI
  132. /* VARARGS 0 */
  133. ereply(va_alist)
  134. va_dcl
  135. {
  136.     va_list         pvar;
  137.     register char  *fp, *buf;
  138.     register int    nbuf;
  139.     register int    i;
  140.  
  141.     va_start(pvar);
  142.     fp = va_arg(pvar, char *);
  143.     buf = va_arg(pvar, char *);
  144.     nbuf = va_arg(pvar, int);
  145.     i = veread(fp, buf, nbuf, EFNEW | EFCR, &pvar);
  146.     va_end(pvar);
  147.     return i;
  148. }
  149. #else
  150.  
  151. int
  152. #ifdef    LATTICE
  153.                 __stdargs
  154. #endif
  155. ereply(char *fp, char *buf, int nbuf,...)
  156. {
  157.     va_list         pvar;
  158.     register int    i;
  159.  
  160.     va_start(pvar, nbuf);
  161.     i = veread(fp, buf, nbuf, EFNEW | EFCR, &pvar);
  162.     va_end(pvar);
  163.     return i;
  164. }
  165. #endif
  166. /*
  167.  * This is the general "read input from the echo line" routine. The basic
  168.  * idea is that the prompt string "prompt" is written to the echo line, and a
  169.  * one line reply is read back into the supplied "buf" (with maximum length
  170.  * "len"). The "flag" contains EFNEW (a new prompt), an EFFUNC
  171.  * (autocomplete), or EFCR (echo the carriage return as CR). 
  172.  */
  173. #ifndef    ANSI
  174. /* VARARGS 0 */
  175. eread(va_alist)
  176. va_dcl
  177. {
  178.     va_list         pvar;
  179.     char           *fp, *buf;
  180.     int             nbuf, flag, i;
  181.     va_start(pvar);
  182.     fp = va_arg(pvar, char *);
  183.     buf = va_arg(pvar, char *);
  184.     nbuf = va_arg(pvar, int);
  185.     flag = va_arg(pvar, int);
  186.     i = veread(fp, buf, nbuf, flag, &pvar);
  187.     va_end(pvar);
  188.     return i;
  189. }
  190. #else
  191. int
  192. #ifdef    LATTICE
  193.                 __stdargs
  194. #endif
  195. eread(char *fp, char *buf, int nbuf, int flag,...)
  196. {
  197.     va_list         pvar;
  198.     int             i;
  199.  
  200.     va_start(pvar, flag);
  201.     i = veread(fp, buf, nbuf, flag, &pvar);
  202.     va_end(pvar);
  203.     return i;
  204. }
  205. #endif
  206. static
  207. veread(fp, buf, nbuf, flag, ap)
  208.     char           *fp;
  209.     char           *buf;
  210.     va_list        *ap;
  211. {
  212.     register int    cpos;
  213.     register int    i;
  214.     register int    c;
  215. #ifndef    NO_METAKEY
  216.     extern int      use_metakey;
  217.     int             save_metakey = use_metakey;
  218.  
  219.     use_metakey = FALSE;
  220. #endif
  221.  
  222.     cpos = 0;
  223. #ifndef    NO_MACRO
  224.     if (!inmacro) {
  225. #endif
  226.         if ((flag & EFNEW) == 0 && ttrow == nrow - 1)
  227.             eputc(' ');
  228.         else {
  229.             ttcolor(CTEXT);
  230.             ttmove(nrow - 1, 0);
  231.             epresf = TRUE;
  232.         }
  233.         eformat(fp, ap);
  234.         tteeol();
  235.         ttflush();
  236. #ifndef    NO_MACRO
  237.     }
  238. #endif
  239.     for (;;) {
  240.         c = getkey(FALSE);
  241.         if ((flag & EFAUTO) != 0 && (c == ' ' || c == CCHR('I'))) {
  242.             cpos += complt(flag, c, buf, cpos);
  243.             continue;
  244.         }
  245.         switch (c) {
  246.         case CCHR('J'):
  247.             c = CCHR('M');    /* and continue         */
  248.         case CCHR('M'):/* Return, done.     */
  249.             if ((flag & EFFORCE) == 0)
  250.                 buf[cpos] = '\0';
  251.             else if ((i = complt(flag, c, buf, cpos)) >= 0) {
  252.                 cpos += i;
  253.                 continue;
  254.             }
  255.             if ((flag & EFCR) != 0
  256. #ifndef    NO_MACRO
  257.                 && inmacro
  258. #endif
  259.                 ) {
  260.                 ttputc(CCHR('M'));
  261.                 ttflush();
  262.             }
  263. #ifndef    NO_METAKEY
  264.             use_metakey = save_metakey;
  265. #endif
  266.             return buf[0] != '\0';
  267.  
  268.         case CCHR('G'):/* Bell, abort.         */
  269. #ifndef    NO_METAKEY
  270.             use_metakey = save_metakey;
  271. #endif
  272. #ifndef    NO_MACRO
  273.             if (inmacro)
  274.                 return ABORT;
  275. #endif
  276.             eputc(CCHR('G'));
  277.             (VOID) ctrlg(FFRAND, 0);
  278.             ttflush();
  279.             return ABORT;
  280.  
  281.         case CCHR('H'):
  282.         case CCHR('?'):/* Rubout, erase.     */
  283.             if (cpos != 0) {
  284. #ifndef    NO_MACRO
  285.                 if (inmacro) {
  286.                     cpos -= 1;
  287.                     break;
  288.                 }
  289. #endif
  290.                 ttputc('\b');
  291.                 ttputc(' ');
  292.                 ttputc('\b');
  293.                 --ttcol;
  294.                 if (ISCTRL(buf[--cpos]) != FALSE) {
  295.                     ttputc('\b');
  296.                     ttputc(' ');
  297.                     ttputc('\b');
  298.                     --ttcol;
  299.                 }
  300.                 ttflush();
  301.             }
  302.             break;
  303.  
  304.         case CCHR('X'):/* C-X             */
  305.         case CCHR('U'):/* C-U, kill line.     */
  306. #ifndef NO_MACRO
  307.             if (inmacro) {
  308.                 cpos = 0;
  309.                 break;
  310.             }
  311. #endif
  312.             while (cpos != 0) {
  313.                 ttputc('\b');
  314.                 ttputc(' ');
  315.                 ttputc('\b');
  316.                 --ttcol;
  317.                 if (ISCTRL(buf[--cpos]) != FALSE) {
  318.                     ttputc('\b');
  319.                     ttputc(' ');
  320.                     ttputc('\b');
  321.                     --ttcol;
  322.                 }
  323.             }
  324.             ttflush();
  325.             break;
  326.  
  327.         case CCHR('W'):/* C-W, kill to beginning of */
  328.             /* previous word     */
  329.             /* back up to first word character or beginning */
  330.             while ((cpos > 0) && !ISWORD(buf[cpos - 1])) {
  331. #ifndef    NO_MACRO
  332.                 if (inmacro) {
  333.                     cpos -= 1;
  334.                     continue;
  335.                 }
  336. #endif
  337.                 ttputc('\b');
  338.                 ttputc(' ');
  339.                 ttputc('\b');
  340.                 --ttcol;
  341.                 if (ISCTRL(buf[--cpos]) != FALSE) {
  342.                     ttputc('\b');
  343.                     ttputc(' ');
  344.                     ttputc('\b');
  345.                     --ttcol;
  346.                 }
  347.             }
  348.             while ((cpos > 0) && ISWORD(buf[cpos - 1])) {
  349. #ifndef    NO_MACRO
  350.                 if (inmacro) {
  351.                     cpos -= 1;
  352.                     continue;
  353.                 }
  354. #endif
  355.                 ttputc('\b');
  356.                 ttputc(' ');
  357.                 ttputc('\b');
  358.                 --ttcol;
  359.                 if (ISCTRL(buf[--cpos]) != FALSE) {
  360.                     ttputc('\b');
  361.                     ttputc(' ');
  362.                     ttputc('\b');
  363.                     --ttcol;
  364.                 }
  365.             }
  366. #ifndef NO_MACRO
  367.             if (!inmacro)
  368. #endif
  369.                 ttflush();
  370.             break;
  371.  
  372.         case CCHR('\\'):
  373.         case CCHR('Q'):/* C-Q, quote next     */
  374.             c = getkey(FALSE);    /* and continue         */
  375.         default:    /* All the rest.     */
  376.             if (cpos < nbuf - 1) {
  377.                 buf[cpos++] = (char) c;
  378. #ifndef    NO_MACRO
  379.                 if (inmacro)
  380.                     break;
  381. #endif
  382.                 eputc((char) c);
  383.                 ttflush();
  384.             }
  385.         }
  386.     }
  387. }
  388. /*
  389.  * do completion for veread. The completion routines return: >= 0 number of
  390.  * characters we can complete by -1    no match at all -2 ambiguous -3    match
  391.  * is correct & complete as it is, used only if c = C-m 
  392.  */
  393. static int
  394. complt(flags, c, buf, cpos)
  395.     register char  *buf;
  396.     register int    cpos;
  397. {
  398.     register int    i, j;
  399.     int             msglen, nshown;
  400.     char           *msg;
  401. #ifndef    NO_MACRO
  402.     register int    xtra;
  403.     char        macbuf[NMACN];
  404.     extern struct macro kbdmacro;
  405. #endif
  406.  
  407.     if (flags & EFBUF)
  408.         i = complete_list(&(bheadp->b_list), c, buf, cpos);
  409. #ifndef    NO_MACRO
  410.     else if (flags & EFMACRO)
  411.         i = complete_list(&(kbdmacro.m_list), c, buf, cpos);
  412. #endif
  413.     else if (flags & EFFUNC) {
  414.         buf[cpos] = '\0';
  415.         i = complete_function(buf, c);
  416. #ifndef    NO_MACRO
  417.         strncpy(macbuf, buf, NMACN);
  418.         j = complete_list(&(kbdmacro.m_list), c, macbuf, cpos);
  419.         if (i == -3 || j == -3)
  420.             i = -3;
  421.         else if (i == -2 || j == -2)
  422.             i = -2;
  423.         else if (i == -1) {
  424.             if (j > 0)
  425.                 bcopy(macbuf + cpos, buf + cpos, j + 1);
  426.             i = j;
  427.         } else if (j >= 0) {
  428.             for (xtra = 0; xtra < i & xtra < j; xtra += 1)
  429.                 if (buf[cpos + xtra] != macbuf[cpos + xtra])
  430.                     break;
  431.             i = xtra == 0 ? -2 : xtra;
  432.             buf[cpos + xtra + 1] = '\0';
  433.         }
  434. #endif
  435.     } else
  436.         panic("broken complt call: flags");
  437.  
  438. #ifndef    NO_MACRO
  439.     if (inmacro)
  440.         return i;
  441. #endif
  442.  
  443.     if (i > 0) {
  444.         eputs(&buf[cpos]);
  445.         ttflush();
  446.         return i;
  447.     }
  448.     switch (i) {
  449.     case -1:
  450.         msg = " [No match]";
  451.         break;
  452.     case -2:
  453.         msg = " [Ambiguous]";
  454.         break;
  455.     case -3:
  456.     case 0:
  457.         return i;
  458.     default:
  459.         msg = " [Internal error]";
  460.         break;
  461.     }
  462.     /* Set up backspaces, etc., being mindful of echo line limit */
  463.     msglen = strlen(msg);
  464.     nshown = (ttcol + msglen + 2 > ncol) ?
  465.         ncol - ttcol - 2 : msglen;
  466.     eputs(msg);
  467.     ttcol -= (j = nshown);    /* update ttcol!         */
  468.     while (j--)        /* move back before msg         */
  469.         ttputc('\b');
  470.     ttflush();        /* display to user         */
  471.     j = nshown;
  472.     while (j--)        /* blank out    on next flush     */
  473.         eputc(' ');
  474.     ttcol -= (j = nshown);    /* update ttcol on BS's         */
  475.     while (j--)
  476.         ttputc('\b');    /* update ttcol again!         */
  477.     return 0;
  478. }
  479.  
  480.  
  481. /*
  482.  * do completion on a list of objects 
  483.  */
  484. static int
  485. complete_list(lh, c, buf, cpos)
  486.     register struct list *lh;
  487.     register char  *buf;
  488.     register int    cpos;
  489. {
  490.     register struct list *lh2;
  491.     register int    i;
  492.     int             nhits, nxtra, bxtra;
  493.     int             match = FALSE;
  494.  
  495.     nhits = 0;
  496.     nxtra = HUGE;
  497.  
  498.     while (lh != NULL) {
  499.         for (i = 0; i < cpos; i += 1) {
  500.             if (buf[i] != lh->l_name[i])
  501.                 break;
  502.         }
  503.         if (i == cpos) {
  504.             if (nhits == 0)
  505.                 lh2 = lh;
  506.             nhits += 1;
  507.             if (lh->l_name[i] == '\0')
  508.                 match = TRUE;
  509.             bxtra = getxtra(lh, lh2, cpos, c == ' ');
  510.             if (bxtra < nxtra)
  511.                 nxtra = bxtra;
  512.             lh2 = lh;
  513.         }
  514.         lh = lh->l_next;
  515.     }
  516.     if (match && c == CCHR('M'))
  517.         return -3;    /* complete match */
  518.     if (nhits == 0)
  519.         return -1;    /* No match */
  520.     if (nhits > 1 && nxtra == 0)
  521.         return -2;    /* Ambiguous */
  522.  
  523.     /* Match; copy it out and return the count */
  524.     for (i = 0; i < nxtra; i += 1) {
  525.         buf[cpos + i] = lh2->l_name[cpos + i];
  526.     }
  527.     buf[cpos + i] = '\0';
  528.     return nxtra;
  529. }
  530.  
  531. /*
  532.  * The "lp1" and "lp2" point to list structures. The "cpos" is a horizontal
  533.  * position in the name. Return the longest block of characters that can be
  534.  * autocompleted at this point. Sometimes the two symbols are the same, but
  535.  * this is normal. 
  536.  */
  537. static int
  538. getxtra(lp1, lp2, cpos, wflag)
  539.     register struct list *lp1, *lp2;
  540.     register int    wflag;
  541. {
  542.     register int    i;
  543.  
  544.     i = cpos;
  545.     for (;;) {
  546.         if (lp1->l_name[i] != lp2->l_name[i])
  547.             break;
  548.         if (lp1->l_name[i] == '\0')
  549.             break;
  550.         i += 1;
  551.         if (wflag && !ISWORD(lp1->l_name[i - 1]))
  552.             break;
  553.     }
  554.     return (i - cpos);
  555. }
  556.  
  557. /*
  558.  * Special "printf" for the echo line. Each call to "ewprintf" starts a new
  559.  * line in the echo area, and ends with an erase to end of the echo line. The
  560.  * formatting is done by a call to the standard formatting routine. 
  561.  */
  562. /* VARARGS 0 */
  563. VOID
  564. #ifndef    ANSI
  565. ewprintf(va_alist)
  566. va_dcl
  567. #else
  568. #ifdef    LATTICE
  569. __stdargs
  570. #endif
  571. ewprintf(char *fp,...)
  572. #endif
  573. {
  574.     va_list         pvar;
  575. #ifndef    ANSI
  576.     register char  *fp;
  577. #endif
  578.  
  579. #ifndef NO_MACRO
  580.     if (inmacro)
  581.         return;
  582. #endif
  583. #ifndef    ANSI
  584.     va_start(pvar);
  585.     fp = va_arg(pvar, char *);
  586. #else
  587.     va_start(pvar, fp);
  588. #endif
  589.     ttcolor(CTEXT);
  590.     ttmove(nrow - 1, 0);
  591.     eformat(fp, &pvar);
  592.     va_end(pvar);
  593.     tteeol();
  594.     ttflush();
  595.     epresf = TRUE;
  596. }
  597.  
  598. /*
  599.  * Printf style formatting. This is called by both "ewprintf" and "ereply" to
  600.  * provide formatting services to their clients. They move to the start of
  601.  * the echo line, and the erase to the end of the echo line, is done by the
  602.  * caller. Note: %c works, and prints the "name" of the character. %k prints
  603.  * the name of a key (and takes no arguments). 
  604.  */
  605. static          VOID
  606. eformat(fp, ap)
  607.     register char  *fp;
  608.     register va_list *ap;
  609. {
  610.     register int    c;
  611.     char            kname[NKNAME];
  612.     char           *keyname();
  613.     char           *cp;
  614.  
  615. #ifndef    NO_MACRO
  616.     if (inmacro)
  617.         return;
  618. #endif
  619.     while ((c = *fp++) != '\0') {
  620.         if (c != '%')
  621.             eputc(c);
  622.         else {
  623.             c = *fp++;
  624.             switch (c) {
  625.             case 'c':
  626.                 (VOID) keyname(kname, va_arg(*ap, int));
  627.                 eputs(kname);
  628.                 break;
  629.  
  630.             case 'k':
  631.                 cp = kname;
  632.                 for (c = 0; c < key.k_count; c++) {
  633.                     cp = keyname(cp, key.k_chars[c]);
  634.                     *cp++ = ' ';
  635.                 }
  636.                 *--cp = '\0';
  637.                 eputs(kname);
  638.                 break;
  639.  
  640.             case 'd':
  641.                 eputi(va_arg(*ap, int), 10);
  642.                 break;
  643.  
  644.             case 'o':
  645.                 eputi(va_arg(*ap, int), 8);
  646.                 break;
  647.  
  648.             case 's':
  649.                 eputs(va_arg(*ap, char *));
  650.                 break;
  651.  
  652.             case 'l':    /* explicit longword */
  653.                 c = *fp++;
  654.                 switch (c) {
  655.                 case 'd':
  656.                     eputl((long) va_arg(*ap, long), 10);
  657.                     break;
  658.                 default:
  659.                     eputc(c);
  660.                     break;
  661.                 }
  662.                 break;
  663.  
  664.             default:
  665.                 eputc(c);
  666.             }
  667.         }
  668.     }
  669. }
  670.  
  671. /*
  672.  * Put integer, in radix "r". 
  673.  */
  674. static          VOID
  675. eputi(i, r)
  676.     register int    i;
  677.     register int    r;
  678. {
  679.     register int    q;
  680.  
  681. #ifndef    NO_MACRO
  682.     if (inmacro)
  683.         return;
  684. #endif
  685.     if (i < 0) {
  686.         eputc('-');
  687.         i = -i;
  688.     }
  689.     if ((q = i / r) != 0)
  690.         eputi(q, r);
  691.     eputc(i % r + '0');
  692. }
  693.  
  694. /*
  695.  * Put long, in radix "r". 
  696.  */
  697. static          VOID
  698. eputl(l, r)
  699.     register long   l;
  700.     register int    r;
  701. {
  702.     register long   q;
  703.  
  704. #ifndef    NO_MACRO
  705.     if (inmacro)
  706.         return;
  707. #endif
  708.     if (l < 0) {
  709.         eputc('-');
  710.         l = -l;
  711.     }
  712.     if ((q = l / r) != 0)
  713.         eputl(q, r);
  714.     eputc(l % r + '0');
  715. }
  716.  
  717. /*
  718.  * Put string. 
  719.  */
  720. static          VOID
  721. eputs(s)
  722.     register char  *s;
  723. {
  724.     register int    c;
  725.  
  726. #ifndef    NO_MACRO
  727.     if (inmacro)
  728.         return;
  729. #endif
  730.     while ((c = *s++) != '\0')
  731.         eputc(c);
  732. }
  733.  
  734. /*
  735.  * Put character. Watch for control characters, and for the line getting too
  736.  * long. 
  737.  */
  738. static          VOID
  739. eputc(c)
  740.     register int    c;
  741. {
  742. #ifndef    NO_MACRO
  743.     if (inmacro)
  744.         return;
  745. #endif
  746.     if (ttcol + 2 < ncol) {
  747.         if (ISCTRL(c)) {
  748.             eputc('^');
  749.             c = CCHR(c);
  750.         }
  751.         ttputc((char) c);
  752.         ++ttcol;
  753.     }
  754. }
  755.