home *** CD-ROM | disk | FTP | other *** search
/ Unix System Administration Handbook 1997 October / usah_oct97.iso / news / nn.tar / nn-6.5.1 / macro.c < prev    next >
C/C++ Source or Header  |  1995-04-29  |  15KB  |  815 lines

  1. /*
  2.  *    (c) Copyright 1990, Kim Fabricius Storm.  All rights reserved.
  3.  *
  4.  *    Macro parsing and execution.
  5.  */
  6.  
  7. #include "config.h"
  8. #include "keymap.h"
  9. #include "menu.h"
  10. #include "nn_term.h"
  11.  
  12. /* macro.c */
  13.  
  14. static void m_error __APROTO((char *fmt, char *arg));
  15. static void m_new __APROTO((int t));
  16. static parse_word __APROTO((char *w));
  17. static parse_line __APROTO((char *lp));
  18. static struct macro *m_call __APROTO((int who));
  19.  
  20. export int in_menu_mode = 0;
  21. export int get_from_macro = 0;
  22. export int macro_debug = 0;
  23. export char *dflt_enter_macro = NULL;
  24. export char *start_up_macro = NULL;
  25.  
  26. #ifdef M_BREAK
  27. #undef M_BREAK
  28. #endif
  29.  
  30. #define M_DUMMY        0    /* do nothing (end of branch)     */
  31.  
  32. #define    M_COMMAND    1    /* a command (get_c())          */
  33. #define M_KEY        2    /* a key stroke (get_c())      */
  34. #define M_STRING    3    /* a string (get_s())         */
  35.  
  36. #define M_INPUT        4    /* take input from keyboard (get_c/get_s) */
  37.  
  38. #define M_YES        5    /* answer yes to confirmation     */
  39. #define M_NO        6    /* answer no to confirmation and break */
  40.                 /* -- if neither are present, take input */
  41.  
  42. #define M_PUTS        7    /* puts "..."             */
  43. #define M_PROMPT    8    /* prompt(...)              */
  44. #define M_ECHO        9    /* msg(...)             */
  45.  
  46. #define M_IS_MENU    10    /* in menu mode ?         */
  47. #define M_IS_SHOW    11    /* in reading mode ?         */
  48. #define M_IS_GROUP    12    /* are we in a news group ?     */
  49. #define M_IS_FOLDER    13    /* are we in a folder ?         */
  50. #define M_CONFIRM    14    /* ask for confirmation to procede     */
  51. #define M_REJECT    15    /* ask for !confirmation to procede     */
  52. #define M_VARTEST    16    /* test value of variable     */
  53. #define M_BREAK        17    /* exit from macroes         */
  54. #define    M_RETURN    18    /* return from this macro     */
  55.  
  56. #define    M_SET_COMMAND    19    /* set/unset command         */
  57.  
  58.  
  59. struct macro {
  60.     int            m_type;        /* entry type */
  61.     union {
  62.     int         mu_int;        /* command or char */
  63.     char         *mu_string;    /* string for get_s */
  64.     struct macro     *mu_branch;    /* false conditional */
  65.     } m_value;
  66.     struct macro *m_next;        /* next macro element */
  67. };
  68.  
  69. #define m_int        m_value.mu_int
  70. #define m_string    m_value.mu_string
  71. #define m_branch    m_value.mu_branch
  72.  
  73. #define NUM_MACRO 101        /* numbered macros */
  74. #define ANON_MACRO 100        /* anonymous macroes */
  75. #define NMACRO (NUM_MACRO + ANON_MACRO)
  76.  
  77. #define MSTACK 5        /* max nesting level */
  78.  
  79. static struct macro *macro[NMACRO + 1];     /* macro table */
  80.                 /* the extra slot is for entry macroes */
  81.  
  82. static struct macro *mstack[MSTACK];    /* macro stack */
  83. static int cstack[MSTACK + 1];
  84. static int m_level = 0;
  85.  
  86. static struct macro *m = NULL;        /* current macro */
  87. static int no_advance = 0;
  88. static int changed_prompt = 0;
  89.  
  90. static int cur_m;
  91.  
  92. #define MERROR ((struct macro *)1)
  93.  
  94. static void
  95. m_error(fmt, arg)
  96. char *fmt, *arg;
  97. {
  98.     char buf[80];
  99.  
  100.    if (arg) {
  101.        sprintf(buf, fmt, arg);
  102.        fmt = buf;
  103.    }
  104.  
  105.    init_message("Error in macro %d: %s", cur_m, fmt);
  106. }
  107.  
  108. void
  109. init_macro()
  110. {
  111.     int n;
  112.  
  113.     for (n = 0; n <= NMACRO; n++)
  114.     macro[n] = NULL;
  115. }
  116.  
  117. static void
  118. m_new(t)
  119. int t;
  120. {
  121.     struct macro *m1;
  122.  
  123.     m1 = newobj(struct macro, 1);
  124.  
  125.     if (m == NULL)
  126.     m = macro[cur_m] = m1;
  127.     else {
  128.     m->m_next = m1;
  129.     m = m1;
  130.     }
  131.     m->m_type = t;
  132.     m->m_next = NULL;
  133. }
  134.  
  135.  
  136. /*
  137.  *    Define macro "id" reading from file f until "end"
  138.  *
  139.  *    Macro definition syntax:
  140.  *        define <id>
  141.  *           <body>
  142.  *        end
  143.  *
  144.  *    Id string interpretation:
  145.  *    NULL         use next free numbered macro
  146.  *            Return: pointer to macro
  147.  *    "nnn" nnn>=0    Numbered macro nnn
  148.  *            Return: pointer to macro
  149.  *    "-1"        entry macro
  150.  *            Return: pointer to macro
  151.  *    "-2"        anonymous macro
  152.  *            Return: K_MACRO code or K_UNBOUND on error
  153.  */
  154.  
  155. static int initial_set_commands;
  156.  
  157. static int
  158. parse_word(w)
  159. char *w;
  160. {
  161.     int cmd;
  162.     register struct macro *m1;
  163.  
  164.     if (m && m->m_type == M_COMMAND && m->m_int == (GETC_COMMAND | K_MACRO)) {
  165.     if (isdigit(*w)) {
  166.         m->m_int |= atoi(w);
  167.         goto ok;
  168.     }
  169.     m_error("macro number missing", (char *)NULL);
  170.     return 1;
  171.     }
  172.  
  173.     if (*w == '"') {
  174.     if (m == NULL || (m->m_type != M_PROMPT && m->m_type != M_ECHO && m->m_type != M_PUTS))
  175.         m_new(M_STRING);
  176.     m->m_string = copy_str(w + 1);
  177.     goto ok;
  178.     }
  179.  
  180.     if (*w == '\'') {
  181.     m_new(M_KEY);
  182.     m->m_int = parse_key(w + 1);
  183.     goto ok;
  184.     }
  185.  
  186.     if (*w == '?') {
  187.     if (strchr(w, '=')) {
  188.         m->m_type = M_VARTEST;
  189.         m1 = m;
  190.         m_new(M_DUMMY);
  191.         m->m_branch = m1->m_branch;
  192.         m1->m_string = copy_str(w + 1);
  193.         goto ok;
  194.     }
  195.  
  196.     switch (w[1]) {
  197.      case 'f': /* ?folder */
  198.         cmd = M_IS_FOLDER;
  199.         break;
  200.      case 'g': /* ?group */
  201.         cmd = M_IS_GROUP;
  202.         break;
  203.      case 'm': /* ?menu */
  204.         cmd = M_IS_MENU;
  205.         break;
  206.      case 'n': /* ?no */
  207.         cmd = M_REJECT;
  208.         break;
  209.      case 's': /* ?show */
  210.         cmd = M_IS_SHOW;
  211.         break;
  212.      case 'y': /* ?yes */
  213.         cmd = M_CONFIRM;
  214.         break;
  215.      default:
  216.         m_error("unknown conditional %s", w - 1);
  217.         return 1;
  218.     }
  219.     m->m_type = cmd;
  220.     goto ok;
  221.     }
  222.  
  223.     if ((cmd = lookup_command(w, (K_ONLY_MENU | K_ONLY_MORE))) > K_INVALID) {
  224.     m_new(M_COMMAND);
  225.     m->m_int = GETC_COMMAND | cmd;
  226.     goto ok;
  227.     }
  228.  
  229.     if (strcmp(w, "prompt") == 0) {
  230.     m_new(M_PROMPT);
  231.     m->m_string = "?";
  232.     goto ok;
  233.     }
  234.     if (strcmp(w, "echo") == 0) {
  235.     m_new(M_ECHO);
  236.     m->m_string = "ups";
  237.     goto ok;
  238.     }
  239.     if (strcmp(w, "puts") == 0) {
  240.     m_new(M_PUTS);
  241.     m->m_string = "";
  242.     goto ok;
  243.     }
  244.     if (strcmp(w, "input") == 0) {
  245.     m_new(M_INPUT);
  246.     goto ok;
  247.     }
  248.     if (strcmp(w, "yes") == 0) {
  249.     m_new(M_YES);
  250.     goto ok;
  251.     }
  252.     if (strcmp(w, "no") == 0) {
  253.     m_new(M_NO);
  254.     goto ok;
  255.     }
  256.     if (strcmp(w, "break") == 0) {
  257.     m_new(M_BREAK);
  258.     goto ok;
  259.     }
  260.     if (strcmp(w, "return") == 0) {
  261.     m_new(M_RETURN);
  262.     goto ok;
  263.     }
  264.  
  265.     m_error("Unknown word >>%s<<", w);
  266.     return 1;
  267.  
  268.  ok:
  269.     return 0;
  270. }
  271.  
  272. static int
  273. parse_line(lp)
  274. char *lp;
  275. {
  276.     char *word;
  277.     struct macro *m1, *branch = NULL;
  278.  
  279.     while (*lp) {
  280.     if (*lp == '#') break;
  281.  
  282.     if (*lp == ':') {
  283.         lp++;
  284.         if (initial_set_commands) {
  285. #ifdef REL_640_COMPAT
  286.         if (strncmp(lp, "local",  5) == 0 ||
  287.             strncmp(lp, "set",    3) == 0 ||
  288.             strncmp(lp, "unset",  5) == 0) {
  289. #else
  290.             if (lp[0] == ':')
  291.             lp++;
  292.         else {
  293. #endif
  294.             m_new(M_SET_COMMAND);
  295.             m->m_string = copy_str(lp);
  296.             break;
  297.         }
  298.         initial_set_commands = 0;
  299.         }
  300.         m_new(M_COMMAND);
  301.         m->m_int = GETC_COMMAND | K_EXTENDED_CMD;
  302.         m_new(M_STRING);
  303.         m->m_string = copy_str(lp);
  304.         break;
  305.     }
  306.     initial_set_commands = 0;
  307.  
  308.     if (*lp == '?') {
  309.         m_new(M_IS_MENU);
  310.         if (branch == NULL) {
  311.         m1 = m;
  312.         m_new(M_DUMMY);
  313.         branch = m;
  314.         m = m1;
  315.         }
  316.         m->m_branch = branch;
  317.     }
  318.  
  319.     word = lp;
  320.     if (*lp == '"')
  321.         do lp++;
  322.         while (*lp && *lp != '"');
  323.     else
  324.     if (*lp == '\'')
  325.         do lp++;
  326.         while (*lp && *lp != '\'');
  327.     else
  328.         while (*lp && !isspace(*lp)) lp++;
  329.     if (*lp) {
  330.         *lp++ = NUL;
  331.         while (*lp && isspace(*lp)) lp++;
  332.     }
  333.     if (parse_word(word)) return 1;
  334.     }
  335.  
  336.     if (branch) {
  337.     m->m_next = branch;
  338.     m = branch;
  339.     }
  340.     return 0;
  341. }
  342.  
  343. char *m_define(id, f)
  344. char *id;
  345. FILE *f;
  346. {
  347.     char line[1024], *lp, skip;
  348.     int type = 0;
  349.  
  350.     if (id) {
  351.     cur_m = atoi(id);
  352.     if (cur_m == -1) {
  353.         cur_m = NMACRO;    /* special slot for this purpose */
  354.     } else if (cur_m == -2) {
  355.         for (cur_m = NUM_MACRO; cur_m < NMACRO; cur_m++)
  356.         if (macro[cur_m] == NULL) break;
  357.         if (cur_m == NMACRO) {
  358.         init_message("No unused macro slots");
  359.         return (char *)K_UNBOUND;
  360.         }
  361.         type = 1;
  362.     } else if (cur_m < 0 || cur_m >= NUM_MACRO) {
  363.         m_error("macro number out of range\n", id);
  364.         return (char *)0;
  365.     }
  366.     } else {
  367.     for (cur_m = 0; cur_m < NUM_MACRO; cur_m++)
  368.         if (macro[cur_m] == NULL) break;
  369.     if (cur_m == NUM_MACRO) {
  370.         init_message("No unused macro numbers");
  371.         return (char *)0;
  372.     }
  373.     }
  374.  
  375.     if (f == NULL) {
  376.     clrdisp();
  377.     tprintf("DEFINE %sMACRO %d -- END WITH 'end'\n\n\r",
  378.            cur_m >= NUM_MACRO ? "ANONYMOUS " : "",
  379.            cur_m >= NUM_MACRO ? cur_m - NUM_MACRO : cur_m);
  380.     unset_raw();
  381.     f = stdin;
  382.     }
  383.  
  384.     m = NULL;
  385.     skip = 0;
  386.     initial_set_commands = (cur_m == NMACRO);
  387.  
  388.     while (fgets_multi(line, 1024, f)) {
  389.     for (lp = line; *lp && isspace(*lp); lp++);
  390.     if (*lp == NUL) continue;
  391.     if (*lp == ')' || strncmp(lp, "end", 3) == 0) goto out;
  392.     if (!skip && parse_line(lp)) {
  393.         macro[cur_m] = NULL;
  394.         skip++;
  395.     }
  396.     }
  397.  
  398.     if (f != stdin)
  399.     m_error("end missing", (char *)NULL);
  400.  
  401.  out:
  402.     if (f == stdin) nn_raw();
  403.     m = NULL;
  404.     return type == 0 ? (char *)macro[cur_m] : (char *)(K_MACRO | cur_m);
  405. }
  406.  
  407. char *m_get_macro(id)
  408. char *id;
  409. {
  410.     if (id) {
  411.     cur_m = atoi(id);
  412.     if (cur_m < 0 || cur_m >= NMACRO) {
  413.         m_error("macro number out of range\n", id);
  414.         return (char *)0;
  415.     }
  416.     }
  417.     return (char *)macro[cur_m];
  418. }
  419.  
  420. char *parse_enter_macro(f, c)
  421. FILE *f;
  422. register int c;
  423. {
  424.     register char *gp;
  425.     char other[FILENAME];
  426.     group_header *gh;
  427.     static char *last_defined = NULL;
  428.  
  429.     while (c != EOF && c != NL && (!isascii(c) || isspace(c))) c = getc(f);
  430.  
  431.     if (c == ')') return last_defined;
  432.  
  433.     if (c == EOF) return (char *)NULL;
  434.  
  435.     if (c == NL) return last_defined = m_define("-1", f);
  436.  
  437.     gp = other;
  438.     do {
  439.     *gp++ = c;
  440.     c = getc(f);
  441.     } while (c != EOF && c != ')' && isascii(c) && !isspace(c));
  442.  
  443.     *gp = NUL;
  444.     if ((gh = lookup(other))) return gh->enter_macro;
  445.  
  446.     return m_get_macro(other);
  447. }
  448.  
  449. /*
  450.  *    Invoke macro # N
  451.  */
  452.  
  453. void
  454. m_invoke(n)
  455. int n;
  456. {
  457.     if (n == -2) {
  458.     n = NMACRO;
  459.     if ((macro[n] = (struct macro *)start_up_macro) == NULL)
  460.         return;
  461.     } else
  462.     if (n < 0) {
  463.     n = NMACRO;
  464.     if ((macro[n] = (struct macro *)(current_group->enter_macro)) == NULL)
  465.         if ((macro[n] = (struct macro *)dflt_enter_macro) == NULL)
  466.         return;
  467.     } else
  468.     if (n >= NMACRO || macro[n] == NULL) {
  469.     msg("undefined macro %d", n);
  470.     return;
  471.     }
  472.  
  473.     if (m_level == 0)
  474.     no_advance = 0;
  475.     else if (m == NULL)
  476.     m_level--;
  477.     else {
  478.     if (m_level > MSTACK) {
  479.         msg("Macro stack overflow");
  480.         m_break();
  481.         return;
  482.     }
  483.     mstack[m_level] = m;
  484.     cstack[m_level] = cur_m;
  485.     }
  486.     m_level++;
  487.  
  488.     cur_m = n;
  489.     m = macro[cur_m];
  490.     while (m && m->m_type == M_SET_COMMAND) {
  491.     char buffer[128];
  492.     strcpy(buffer, m->m_string);
  493.     if (macro_debug) { msg(":%s", buffer); user_delay(1); }
  494.     parse_command(buffer, AC_UNCHANGED, (FILE *)NULL);
  495.     m = m->m_next;
  496.     }
  497. }
  498.  
  499. void
  500. m_startinput()
  501. {
  502.     no_advance = 1;
  503. }
  504.  
  505. void
  506. m_endinput()
  507. {
  508.     if (no_advance) {
  509.     no_advance = 0;
  510.     if (m && m->m_type == M_INPUT)
  511.         m = m->m_next;
  512.     }
  513. }
  514.  
  515. void
  516. m_advinput()
  517. {
  518.     if (m && m->m_type == M_INPUT)
  519.     m = m->m_next;
  520. }
  521.  
  522. static struct macro *m_call(who)
  523. int who;
  524. {
  525.     struct macro *m1;
  526.  
  527.     for (;;) {
  528.     while (m == NULL && m_level > 1) {
  529.         m_level--;
  530.         m = mstack[m_level];
  531.         cur_m = cstack[m_level];
  532.     }
  533.     if (m == NULL) {
  534.         if (macro_debug) msg("end");
  535.         m_break();
  536.         return NULL;
  537.     }
  538.  
  539.     if (macro_debug)
  540.         macro_dbg();
  541.  
  542.     if (who == 3) {
  543.         if (m->m_type == M_YES || m->m_type == M_NO) goto out;
  544.         return NULL;
  545.     }
  546.  
  547.     switch (m->m_type) {
  548.      case M_COMMAND:
  549.         if (m->m_int == (GETC_COMMAND | K_REDRAW))
  550.         changed_prompt = 0;
  551.  
  552.         /*FALLTHRU*/
  553.      case M_KEY:
  554.         if (who == 1) goto out;
  555.         goto err;
  556.  
  557.      case M_STRING:
  558.         if (who == 2) goto out;
  559.         goto err;
  560.  
  561.      case M_INPUT:
  562.         if (no_advance) return m;
  563.         goto out;
  564.  
  565.      case M_YES:
  566.      case M_NO:
  567.      case M_DUMMY:
  568.         break;
  569.  
  570.      case M_PUTS:
  571.         tprintf("%s", m->m_string); fl;
  572.         break;
  573.  
  574.      case M_PROMPT:
  575.         if (m->m_string[0] == NUL) {
  576.         changed_prompt = 0;
  577.         break;
  578.         }
  579.         if (!changed_prompt) prompt(P_SAVE);
  580.         changed_prompt = 1;
  581.         prompt("\1%s\1 ", m->m_string);
  582.         break;
  583.  
  584.      case M_ECHO:
  585.         msg(m->m_string);
  586.         restore_xy();
  587.         break;
  588.  
  589.      case M_IS_MENU:
  590.         if (!in_menu_mode) m = m->m_branch;
  591.         break;
  592.      case M_IS_SHOW:
  593.         if (in_menu_mode) m = m->m_branch;
  594.         break;
  595.      case M_IS_GROUP:
  596.         if (current_group->group_flag & G_FOLDER) m = m->m_branch;
  597.         break;
  598.      case M_IS_FOLDER:
  599.         if ((current_group->group_flag & G_FOLDER) == 0) m = m->m_branch;
  600.         break;
  601.      case M_CONFIRM:
  602.         if (yes(0) == 0) m = m->m_branch;
  603.         break;
  604.      case M_REJECT:
  605.         if (yes(0) == 1) m = m->m_branch;
  606.         break;
  607.  
  608.      case M_VARTEST:
  609.         m1 = m;
  610.         m = m->m_next;
  611.  
  612.         switch (test_variable(m1->m_string)) {
  613.          case 0:
  614.         m = m->m_branch;
  615.         break;
  616.          case -1:
  617.         goto err1;
  618.         }
  619.         break;
  620.  
  621.      case M_RETURN:
  622.         m = NULL;
  623.         continue;
  624.  
  625.      case M_BREAK:
  626.         goto term;
  627.     }
  628.  
  629.     if (m) m = m->m_next;
  630.     }
  631.  
  632.  out:
  633.     m1 = m;
  634.     m = m->m_next;
  635.     no_advance = 0;
  636.     return m1;
  637.  
  638.  err:
  639.     msg("Error in macro %d", cur_m);
  640.  err1:
  641.     user_delay(1);
  642.     m_break();
  643.     return MERROR;
  644.  
  645.  term:
  646.     m_break();
  647.     return NULL;
  648. }
  649.  
  650. void
  651. m_break_entry()
  652. {
  653.     if (current_group->enter_macro || dflt_enter_macro)
  654.     m = NULL;
  655. }
  656.  
  657. void
  658. m_break()
  659. {
  660.     if (changed_prompt) prompt(P_RESTORE);
  661.     changed_prompt = 0;
  662.     m = NULL;
  663.     m_level = 0;
  664. }
  665.  
  666. void
  667. macro_dbg()
  668. {
  669.     char *name = NULL;
  670.  
  671.     switch (m->m_type) {
  672.      case M_COMMAND:
  673.     msg("COMMAND: %s", command_name(m->m_int));
  674.     goto delay;
  675.  
  676.      case M_KEY:
  677.     msg("KEY: %s", key_name((key_type)(m->m_int)));
  678.     goto delay;
  679.  
  680.      case M_STRING:
  681.     msg("STRING: %s", m->m_string);
  682.     goto delay;
  683.  
  684.      case M_INPUT:
  685.     name = "input";
  686.     break;
  687.  
  688.      case M_YES:
  689.     name = "yes";
  690.     break;
  691.  
  692.      case M_NO:
  693.     name = "no";
  694.     break;
  695.  
  696.      case M_DUMMY:
  697.     name = "dummy";
  698.     break;
  699.  
  700.      case M_PROMPT:
  701.     msg("PROMPT: %s", m->m_string);
  702.     goto delay;
  703.  
  704.      case M_ECHO:
  705.     msg("ECHO: %s", m->m_string);
  706.     goto delay;
  707.  
  708.      case M_IS_MENU:
  709.     msg("?menu => %d", in_menu_mode);
  710.     goto delay;
  711.  
  712.      case M_IS_SHOW:
  713.     msg("?show => %d", !in_menu_mode);
  714.     goto delay;
  715.  
  716.      case M_IS_GROUP:
  717.     msg("?group => %d", (current_group->group_flag & G_FOLDER) == 0);
  718.     goto delay;
  719.  
  720.      case M_IS_FOLDER:
  721.     msg("?group => %d", (current_group->group_flag & G_FOLDER));
  722.     goto delay;
  723.  
  724.      case M_CONFIRM:
  725.     name = "?yes";
  726.     break;
  727.  
  728.      case M_REJECT:
  729.     name = "?no";
  730.     break;
  731.  
  732.      case M_VARTEST:
  733.     msg("?%s => %d", m->m_string, test_variable(m->m_string));
  734.     goto delay;
  735.  
  736.      case M_RETURN:
  737.     name = "return";
  738.     break;
  739.  
  740.      case M_BREAK:
  741.     name = "break";
  742.     break;
  743.     }
  744.     msg(name);
  745.  
  746.  delay:
  747.     user_delay(1);
  748. }
  749.  
  750. /*
  751.  *    Macro processing for get_c()
  752.  */
  753.  
  754. int
  755. m_getc(cp)
  756. int *cp;
  757. {
  758.     struct macro *m1;
  759.  
  760.     get_from_macro = 0;
  761.     if (m_level && (m1 = m_call(1))) {
  762.     if (m1 == MERROR) return 2;
  763.     if (m1->m_type == M_INPUT) return 0;
  764.     *cp = m1->m_int;
  765.     get_from_macro = 1;
  766.     return 1;
  767.     }
  768.     return 0;
  769. }
  770.  
  771. /*
  772.  *    Macro processing for get_s()
  773.  */
  774.  
  775. int
  776. m_gets(s)
  777. char *s;
  778. {
  779.     struct macro *m1;
  780.  
  781.     get_from_macro = 0;
  782.     if (m_level && (m1 = m_call(2))) {
  783.     if (m1 == MERROR) return 2;
  784.     if (m1->m_type == M_INPUT) return 0;
  785.     strcpy(s, m1->m_string);
  786.     get_from_macro = 1;
  787.     return 1;
  788.     }
  789.     return 0;
  790. }
  791.  
  792. /*
  793.  *    Macro processing for yes()
  794.  */
  795.  
  796. int
  797. m_yes()
  798. {
  799.     struct macro *m1;
  800.  
  801.     if (m)
  802.     if (m->m_type == M_CONFIRM || m->m_type == M_REJECT) return 3;
  803.  
  804.     if (m_level) {
  805.     if ((m1 = m_call(3)))
  806.         if (m1->m_type == M_NO)
  807.         return 1;
  808.         else
  809.         return 2;
  810.     else
  811.         return 3;
  812.     }
  813.     return 0;
  814. }
  815.