home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume22 / nn6.4 / part12 / variable.c < prev   
C/C++ Source or Header  |  1990-06-07  |  21KB  |  863 lines

  1. /*
  2.  *    (c) Copyright 1990, Kim Fabricius Storm.  All rights reserved.
  3.  *
  4.  *    Variabel setting and display
  5.  */
  6.  
  7. #include "config.h"
  8. #include "keymap.h"
  9.  
  10. import in_init;
  11.  
  12. import char            /* string variables */
  13.     *bak_suffix,
  14.     *bug_address,
  15.     *decode_header_file,
  16.     *default_distribution,
  17.     *default_save_file,
  18.     *editor_program,
  19.     *extra_mail_headers,
  20.     *extra_news_headers,
  21.     *header_lines,
  22.     *folder_directory,
  23.     included_mark[],
  24.     *mail_box,
  25.     *mail_record,
  26.     *mail_script,
  27.     *mailer_program,
  28.     attributes[],
  29.     *newsrc_file,
  30.     *news_record,
  31.     *news_script,
  32.     *pager,
  33.     patch_command[],
  34.     printer[],
  35.     *response_dflt_answer,
  36.     *save_counter_format,
  37.     *spell_checker,
  38.     unshar_command[],
  39.     *unshar_header_file,
  40.     *user_shell;
  41.  
  42. import int            /* boolean variables */
  43.     also_cross_postings,
  44.     also_subgroups,
  45.     append_sig_mail,
  46.     append_sig_post,
  47.     auto_junk_seen,
  48.     auto_preview_mode,
  49.     case_fold_search,
  50.     compress_mode,
  51.     conf_append,
  52.     conf_auto_quit,
  53.     conf_create,
  54.     conf_dont_sleep,
  55.     conf_group_entry,
  56.     conf_junk_seen,
  57.     delay_redraw,
  58.     do_kill_handling,
  59.     dont_sort_articles,
  60.     dont_sort_folders,
  61.     dont_split_digests,
  62.     edit_patch_command,
  63.     edit_print_command,
  64.     edit_unshar_command,
  65.     empty_answer_check,
  66.     flow_control,
  67.     flush_typeahead,
  68.     fmt_rptsubj,
  69.     include_art_id,
  70.     include_full_header,
  71.     keep_rc_backup,
  72.     keep_unsubscribed,
  73.     keep_unsub_long,
  74.     long_menu,
  75.     macro_debug,
  76.     mailer_pipe_input,
  77.     mark_overlap,
  78.     match_parts_equal,
  79.     monitor_mode,
  80.     novice,
  81.     preview_mark_read,
  82.     query_signature,
  83.     quick_save,
  84.     quick_unread_count,
  85.     repeat_group_query,
  86.     report_cost_on_exit,
  87.     retain_seen_status,
  88.     save_report,
  89.     scroll_clear_page,
  90.     select_leave_next,
  91.     select_on_sender,
  92.     seq_cross_filtering,
  93.     shell_restrictions,
  94.     show_article_date,
  95.     show_current_time,
  96.     silent,
  97.     slow_mode,
  98.     suggest_save_file,
  99.     tidy_newsrc,
  100.     use_mail_folders,
  101.     use_mmdf_folders,
  102.     use_selections,
  103.     use_visible_bell;
  104.  
  105. import int            /* integer variables */
  106.     also_read_articles,
  107.     article_limit,
  108.     conf_entry_limit,
  109.     collapse_subject,
  110.     Columns,
  111.     data_bits,
  112.     Debug,
  113.     decode_skip_prefix,
  114.     entry_message_limit,
  115.     expired_msg_delay,
  116.     first_page_lines,
  117.     fmt_linenum,
  118.     Lines,
  119.     match_skip_prefix,
  120.     min_pv_window,
  121.     new_group_action,
  122.     newsrc_update_freq,
  123.     orig_to_include_mask,
  124.     overlap,
  125.     preview_continuation,
  126.     preview_window,
  127.     re_layout,
  128.     response_check_pause,
  129.     retry_on_error,
  130.     save_counter_offset,
  131.     slow_speed,
  132.     sort_mode,
  133.     subject_match_limit,
  134.     wrap_headers;
  135.  
  136. #ifdef NNTP
  137. import char *nntp_cache_dir;
  138. import int nntp_cache_size, nntp_debug;
  139. #endif
  140.  
  141. import key_type            /* key strokes */
  142.     comp1_key,
  143.     comp2_key,
  144.     help_key,
  145.     erase_key,
  146.     delword_key,
  147.     kill_key;
  148.  
  149. #undef STR
  150. #undef BOOL
  151. #undef INT
  152. #undef KEY
  153. #undef SPEC
  154. #undef SAFE
  155. #undef INIT
  156.  
  157.  
  158. #define    V_STRING    0x1000
  159. #define V_BOOLEAN    0x2000
  160. #define    V_INTEGER    0x3000
  161. #define V_KEY        0x4000
  162. #define    V_SPECIAL    0x5000
  163.  
  164. #define V_SAFE        0x0100
  165. #define V_INIT        0x0200
  166.  
  167. #define V_MODIFIED    0x8000
  168.  
  169. #define    STR        V_STRING |
  170. #define BOOL        V_BOOLEAN |
  171. #define    INT        V_INTEGER |
  172. #define KEY        V_KEY |
  173. #define    SPEC        V_SPECIAL |
  174.  
  175. #define SAFE        V_SAFE |
  176. #define INIT        V_INIT |
  177.  
  178. struct variable_defs {
  179.     char *var_name;
  180.     int  var_flags;
  181.     char **var_addr;
  182. } variables[] = {
  183.     "also-subgroups",        BOOL INIT 0,    (char **)&also_subgroups,
  184.     "append-signature-mail",     BOOL 0,        (char **)&append_sig_mail,
  185.     "append-signature-post",     BOOL 0,        (char **)&append_sig_post,
  186.     "attributes",        STR 1,        (char **)attributes,
  187.     "auto-junk-seen",        BOOL 0,        (char **)&auto_junk_seen,
  188.     "auto-preview-mode",    BOOL 0,        (char **)&auto_preview_mode,
  189.     "backup",            BOOL 0,        (char **)&keep_rc_backup,
  190.     "backup-suffix",        STR 0,        (char **)&bak_suffix,
  191.     "bug-report-address",     STR 0,        (char **)&bug_address,
  192.     "case-fold-search",        BOOL 0,        (char **)&case_fold_search,
  193.     "collapse-subject",        INT 3,        (char **)&collapse_subject,
  194.     "columns",            INT 1,        (char **)&Columns,
  195.     "comp1-key",        KEY 0,        (char **)&comp1_key,
  196.     "comp2-key",        KEY 0,        (char **)&comp2_key,
  197.     "compress",            BOOL 0,        (char **)&compress_mode,
  198.     "confirm-append",        BOOL 0,        (char **)&conf_append,
  199.     "confirm-auto-quit",    BOOL 0,        (char **)&conf_auto_quit,
  200.     "confirm-create",        BOOL 0,        (char **)&conf_create,
  201.     "confirm-entry",        BOOL 0,        (char **)&conf_group_entry,
  202.     "confirm-entry-limit",    INT 0,        (char **)&conf_entry_limit,
  203.     "confirm-junk-seen",     BOOL 0,        (char **)&conf_junk_seen,
  204.     "confirm-messages",        BOOL 0,        (char **)&conf_dont_sleep,
  205.     "cross-filter-seq",        BOOL 0,        (char **)&seq_cross_filtering,
  206.     "cross-post",        BOOL 0,        (char **)&also_cross_postings,
  207.     "data-bits",        INT 0,        (char **)&data_bits,
  208.     "date",            BOOL 0,        (char **)&show_article_date,
  209.     "debug",            INT 0,        (char **)&Debug,
  210.     "decode-header-file",    STR 0,        (char **)&decode_header_file,
  211.     "decode-skip-prefix",    INT 0,        (char **)&decode_skip_prefix,
  212.     "default-distribution",    STR 0,        (char **)&default_distribution,
  213.     "default-save-file",    STR 3,        (char **)&default_save_file,
  214.     "delay-redraw",        BOOL 0,        (char **)&delay_redraw,
  215.     "edit-patch-command",     BOOL 0,        (char **)&edit_patch_command,
  216.     "edit-print-command",     BOOL 0,        (char **)&edit_print_command,
  217.     "edit-response-check",     BOOL 0,        (char **)&empty_answer_check,
  218.     "edit-unshar-command",     BOOL 0,        (char **)&edit_unshar_command,
  219.     "editor",            STR 0,        (char **)&editor_program,
  220.     "entry-report-limit",     INT 0,        (char **)&entry_message_limit,
  221.     "erase-key",        KEY 0,        (char **)&erase_key,
  222.     "expert",            BOOL 4,        (char **)&novice,
  223.     "expired-message-delay",    INT 0,        (char **)&expired_msg_delay,
  224.     "flow-control",        BOOL 0,        (char **)&flow_control,
  225.     "flush-typeahead",        BOOL 0,        (char **)&flush_typeahead,
  226.     "folder",            STR 2,        (char **)&folder_directory,
  227.     "fsort",            BOOL 2,        (char **)&dont_sort_folders,
  228.     "header-lines",        STR 0,        (char **)&header_lines,
  229.     "help-key",            KEY 0,        (char **)&help_key,
  230.     "include-art-id",        BOOL 0,        (char **)&include_art_id,
  231.     "include-full-header",    BOOL 0,        (char **)&include_full_header,
  232.     "included-mark",        STR 1,        (char **)included_mark,
  233.     "keep-unsubscribed",     BOOL 0,        (char **)&keep_unsubscribed,
  234.     "kill",            BOOL 0,        (char **)&do_kill_handling,
  235.     "kill-key",            KEY 0,        (char **)&kill_key,
  236.     "layout",            INT 1,        (char **)&fmt_linenum,
  237.     "limit",            INT 2,        (char **)&article_limit,
  238.     "lines",            INT 1,        (char **)&Lines,
  239.     "long-menu",        BOOL 1,        (char **)&long_menu,
  240.     "macro-debug",        BOOL 0,        (char **)¯o_debug,
  241.     "mail",            STR 2,        (char **)&mail_box,
  242.     "mail-format",        BOOL 0,        (char **)&use_mail_folders,
  243.     "mail-header",        STR 0,        (char **)&extra_mail_headers,
  244.     "mail-record",        STR 2,        (char **)&mail_record,
  245.     "mail-script",        STR SAFE 2,    (char **)&mail_script,
  246.     "mailer",            STR 0,        (char **)&mailer_program,
  247.     "mailer-pipe-input",    BOOL 0,        (char **)&mailer_pipe_input,
  248.     "mark-overlap",        BOOL 0,        (char **)&mark_overlap,
  249.     "min-window",        INT 1,        (char **)&min_pv_window,
  250.     "mmdf-format",        BOOL 0,        (char **)&use_mmdf_folders,
  251.     "monitor",            BOOL 0,        (char **)&monitor_mode,
  252.     "new-group-action",        INT 0,        (char **)&new_group_action,
  253.     "news-header",        STR 0,        (char **)&extra_news_headers,
  254.     "news-record",        STR 2,        (char **)&news_record,
  255.     "news-script",        STR SAFE 2,    (char **)&news_script,
  256.     "newsrc",            STR 2,        (char **)&newsrc_file,
  257. #ifdef NNTP
  258.     "nntp-cache-dir",        STR INIT 0,    (char **)&nntp_cache_dir,
  259.     "nntp-cache-size",        INT INIT 0,    (char **)&nntp_cache_size,
  260.     "nntp-debug",        BOOL 0,        (char **)&nntp_debug,
  261. #endif
  262. /*  "no....."  -- cannot have variable names starting with "no" */
  263.     "old",            SPEC 2,        (char **)NULL,
  264.     "orig-to-include-mask",    INT 0,        (char **)&orig_to_include_mask,
  265.     "overlap",            INT 0,        (char **)&overlap,
  266.     "pager",            STR SAFE 3,    (char **)&pager,
  267.     "patch-command",        STR SAFE 1,    (char **)patch_command,
  268.     "preview-continuation",     INT 0,        (char **)&preview_continuation,
  269.     "preview-mark-read",    BOOL 0,        (char **)&preview_mark_read,
  270.     "printer",            STR SAFE 1,    (char **)printer,
  271.     "query-signature",        BOOL 0,        (char **)&query_signature,
  272.     "quick-count",        BOOL 0,        (char **)&quick_unread_count,
  273.     "quick-save",        BOOL 0,        (char **)&quick_save,
  274.     "re-layout",        INT 0,        (char **)&re_layout,
  275.     "record",            SPEC 1,        (char **)NULL,
  276.     "repeat",            BOOL 0,        (char **)&fmt_rptsubj,
  277.     "repeat-group-query",    BOOL 0,        (char **)&repeat_group_query,
  278.     "report-cost",        BOOL 0,        (char **)&report_cost_on_exit,
  279.     "response-check-pause",    INT 0,        (char **)&response_check_pause,
  280.     "response-default-answer",    STR 0,        (char **)&response_dflt_answer,
  281.     "retain-seen-status",     BOOL 0,        (char **)&retain_seen_status,
  282.     "retry-on-error",        INT 0,        (char **)&retry_on_error,
  283.     "save-counter",        STR 3,        (char **)&save_counter_format,
  284.     "save-counter-offset",    INT 0,        (char **)&save_counter_offset,
  285.     "save-report",        BOOL 0,        (char **)&save_report,
  286.     "scroll-clear-page",    BOOL 0,        (char **)&scroll_clear_page,
  287.     "select-leave-next",    BOOL 0,        (char **)&select_leave_next,
  288.     "select-on-sender",        BOOL 0,        (char **)&select_on_sender,
  289.     "shell",            STR SAFE 0,    (char **)&user_shell,
  290.     "shell-restrictions",     BOOL INIT 0,    (char **)&shell_restrictions,
  291.     "silent",            BOOL 0,        (char **)&silent,
  292.     "slow-mode",        BOOL 0,        (char **)&slow_mode,
  293.     "slow-speed",        INT 0,        (char **)&slow_speed,
  294.     "sort",            BOOL 2,        (char **)&dont_sort_articles,
  295.     "sort-mode",        INT 0,        (char **)&sort_mode,
  296.     "spell-checker",        STR 0,        (char **)&spell_checker,
  297.     "split",            BOOL 4,        (char **)&dont_split_digests,
  298.     "stop",            INT 0,        (char **)&first_page_lines,
  299.     "subject-match-limit",     INT 0,        (char **)&subject_match_limit,
  300.     "subject-match-offset",    INT 0,        (char **)&match_skip_prefix,
  301.     "subject-match-parts",    BOOL 0,        (char **)&match_parts_equal,
  302.     "suggest-default-save",     BOOL 0,        (char **)&suggest_save_file,
  303.     "tidy-newsrc",        BOOL 0,        (char **)&tidy_newsrc,
  304.     "time",            BOOL 0,        (char **)&show_current_time,
  305.     "unshar-command",        STR SAFE 1,    (char **)unshar_command,
  306.     "unshar-header-file",    STR 0,        (char **)&unshar_header_file,
  307.     "unsubscribe-mark-read",    BOOL 4,        (char **)&keep_unsub_long,
  308.     "update-frequency",        INT 0,        (char **)&newsrc_update_freq,
  309.     "use-selections",         BOOL 0,        (char **)&use_selections,
  310.     "visible-bell",         BOOL 0,        (char **)&use_visible_bell,
  311.     "window",            INT 1,        (char **)&preview_window,
  312.     "word-key",            KEY 0,        (char **)&delword_key,
  313.     "wrap-header-margin",    INT 2,        (char **)&wrap_headers
  314. };
  315.  
  316. #define TABLE_SIZE    (sizeof(variables)/sizeof(struct variable_defs))
  317.  
  318. #define INT_VAR        (*((int *)(var->var_addr)))
  319. #define BOOL_VAR    (*((int *)(var->var_addr)))
  320. #define STR_VAR        (*(var->var_addr))
  321. #define CBUF_VAR    ((char *)(var->var_addr))
  322. #define KEY_VAR        (*((key_type *)(var->var_addr)))
  323.  
  324. #define VAR_TYPE    (var->var_flags & 0x7000)
  325. #define VAR_OP        (var->var_flags & 0x000f)
  326.  
  327. static struct variable_defs *lookup_variable(variable)
  328. char *variable;
  329. {
  330.     register struct variable_defs *var;
  331.     register i, j, k, t;
  332.  
  333.     i = 0; j = TABLE_SIZE - 1;
  334.  
  335.     while (i <= j) {
  336.     k = (i + j) / 2;
  337.     var = &variables[k];
  338.  
  339.     if ( (t=strcmp(variable, var->var_name)) > 0)
  340.         i = k+1;
  341.     else
  342.     if (t < 0)
  343.         j = k-1;
  344.     else
  345.         return var;
  346.     }
  347.  
  348.     init_message("unknown variable: %s", variable);
  349.     return NULL;
  350. }
  351.  
  352.  
  353. static adjust(str)
  354. register char *str;
  355. {
  356.     if (str == NULL) return;
  357.     while (*str && !isspace(*str) && *str != '#') str++;
  358.     *str = NUL;
  359. }
  360.  
  361. set_variable(variable, on, val_string)
  362. char *variable;
  363. int on;
  364. char *val_string;
  365. {
  366.     int value;
  367.     register struct variable_defs *var;
  368.  
  369.     if (strncmp(variable, "no", 2) == 0) {
  370.     on = !on;
  371.     variable += 2;
  372.     if (variable[0] == '-') variable++;
  373.     }
  374.  
  375.     if ((var = lookup_variable(variable)) == NULL)
  376.     return 0;
  377.  
  378.     if (!in_init && (var->var_flags & (V_INIT | V_SAFE))) {
  379.     if (var->var_flags & V_INIT) {
  380.         msg("'%s' can only be set in the init file", variable);
  381.         return 0;
  382.     }
  383.     if (shell_restrictions) {
  384.         msg("Restricted operation - cannot change");
  385.         return 0;
  386.     }
  387.     }
  388.  
  389.     if (!on || val_string == NULL)
  390.     value = 0;
  391.     else
  392.     value = atoi(val_string);
  393.  
  394.     var->var_flags |= V_MODIFIED;
  395.  
  396.     switch (VAR_TYPE) {
  397.  
  398.      case V_STRING:
  399.  
  400.     switch (VAR_OP) {
  401.      case 0:
  402.         STR_VAR = (on && val_string) ? copy_str(val_string) : (char *)NULL;
  403.         break;
  404.  
  405.      case 1:
  406.         strcpy(CBUF_VAR, (on && val_string) ? val_string : "");
  407.         break;
  408.  
  409.      case 2:
  410.         if (on) {
  411.         char exp_buf[FILENAME];
  412.  
  413.         adjust(val_string);
  414.         if (val_string) {
  415.             if (expand_file_name(exp_buf, val_string, 1))
  416.             STR_VAR = home_relative(exp_buf);
  417.         }
  418.         } else
  419.         STR_VAR = (char *)NULL;
  420.         break;
  421.  
  422.      case 3:
  423.         if (!on || val_string == NULL) {
  424.         msg("Cannot unset string `%s'", variable);
  425.         break;
  426.         }
  427.         STR_VAR = copy_str(val_string);
  428.         break;
  429.     }
  430.     break;
  431.  
  432.      case V_BOOLEAN:
  433.  
  434.     if (val_string)
  435.         if (val_string[0] == 'o')
  436.         on = val_string[1] == 'n'; /* on */
  437.         else
  438.         on = val_string[0] == 't'; /* true */
  439.  
  440.     switch (VAR_OP) {
  441.      case 0:
  442.         BOOL_VAR = on;
  443.         break;
  444.  
  445.      case 1:
  446.         BOOL_VAR = on;
  447.         return 1;
  448.  
  449.      case 2:
  450.         if (BOOL_VAR == on) {
  451.         BOOL_VAR = !on;
  452.         if (!in_init) {
  453.             sort_articles(BOOL_VAR ? 0 : -1);
  454.             return 1;
  455.         }
  456.         }
  457.         break;
  458.  
  459.      case 4:
  460.         BOOL_VAR = !on;
  461.         break;
  462.     }
  463.     break;
  464.  
  465.      case V_INTEGER:
  466.  
  467.     switch (VAR_OP) {
  468.      case 0:
  469.      case 1:
  470.         INT_VAR = value;
  471.         break;
  472.  
  473.      case 2:
  474.      case 3:
  475.         if (!on) value = -1;
  476.         INT_VAR = value;
  477.         break;
  478.     }
  479.     return (VAR_OP & 1);
  480.  
  481.      case V_KEY:
  482.     switch (VAR_OP) {
  483.      case 0:
  484.         if (val_string) {
  485.         if (*val_string) adjust(val_string + 1); /* #N is valid */
  486.         KEY_VAR = parse_key(val_string);
  487.         }
  488.         break;
  489.     }
  490.     break;
  491.  
  492.      case V_SPECIAL:
  493.  
  494.     switch (VAR_OP) {
  495.      case 1:
  496.         if (val_string) {
  497.         adjust(val_string);
  498.         news_record = home_relative(val_string);
  499.         mail_record = news_record;
  500.         }
  501.         break;
  502.  
  503.      case 2:
  504.         also_read_articles = on;
  505.         article_limit = (on && value > 0) ? value : -1;
  506.         break;
  507.     }
  508.     break;
  509.     }
  510.     return 0;
  511. }
  512.  
  513. toggle_variable(variable)
  514. char *variable;
  515. {
  516.     register struct variable_defs *var;
  517.  
  518.     if ((var = lookup_variable(variable)) == NULL) return;
  519.     if (VAR_TYPE != V_BOOLEAN) {
  520.     init_message("variable %s is not boolean", variable);
  521.     return;
  522.     }
  523.  
  524.     BOOL_VAR = !BOOL_VAR;
  525. }
  526.  
  527.  
  528. test_variable(expr)
  529. char *expr;
  530. {
  531.     char *variable;
  532.     register struct variable_defs *var;
  533.     int res = -1;
  534.  
  535.     variable = expr;
  536.     if ((expr = strchr(variable, '=')) == NULL)
  537.     goto err;
  538.  
  539.     *expr++ = NUL;
  540.  
  541.     if ((var = lookup_variable(variable)) == NULL) {
  542.     msg("testing unknown variable %s=%s", variable, expr);
  543.     goto out;
  544.     }
  545.  
  546.     switch (VAR_TYPE) {
  547.  
  548.      case V_BOOLEAN:
  549.     res = BOOL_VAR;
  550.  
  551.     if (strcmp(expr, "on") == 0 || strcmp(expr, "true") == 0) break;
  552.     if (strcmp(expr, "off") == 0 || strcmp(expr, "false") == 0) {
  553.         res = !res;
  554.         break;
  555.     }
  556.     msg("boolean variables must be tested =on or =off");
  557.     break;
  558.  
  559.      case V_INTEGER:
  560.     res = (INT_VAR == atoi(expr)) ? 1 : 0;
  561.     break;
  562.  
  563.      default:
  564.     msg("%s: cannot only test boolean and integer variables", variable);
  565.     break;
  566.     }
  567.  out:
  568.     *--expr = '=';
  569.  err:
  570.     return res;
  571. }
  572.  
  573.  
  574. var_completion(path, index)
  575. char *path;
  576. int index;
  577. {
  578.     static char *head, *tail = NULL;
  579.     static int len;
  580.     static struct variable_defs *var, *help_var;
  581.  
  582.     if (index < 0) return 0;
  583.  
  584.     if (path) {
  585.     head = path;
  586.     tail = path + index;
  587.     while (*head && isspace(*head)) head++;
  588.     if (strncmp(head, "no", 2) == 0) {
  589.         head += 2;
  590.         if (*head == '-') head++;
  591.     }
  592.  
  593.     help_var = var = variables;
  594.     len = tail - head;
  595.  
  596.     return 1;
  597.     }
  598.  
  599.     if (index) {
  600.     list_completion((char *)NULL);
  601.  
  602.     for (;; help_var++) {
  603.         if (help_var >= &variables[TABLE_SIZE]) {
  604.         help_var = variables;
  605.         break;
  606.         }
  607.  
  608.         index = strncmp(help_var->var_name, head, len);
  609.         if (index < 0) continue;
  610.         if (index > 0) {
  611.         help_var = variables;
  612.         break;
  613.         }
  614.         if (list_completion(help_var->var_name) == 0) break;
  615.     }
  616.     fl;
  617.     return 1;
  618.     }
  619.  
  620.     for (; var < &variables[TABLE_SIZE]; var++) {
  621.     if (len == 0)
  622.         index = 0;
  623.     else
  624.         index = strncmp(var->var_name, head, len);
  625.     if (index < 0) continue;
  626.     if (index > 0) break;
  627.     sprintf(tail, "%s ", var->var_name + len);
  628.     var++;
  629.     return 1;
  630.     }
  631.     return 0;
  632. }
  633.  
  634. static struct var_stack {
  635.     struct var_stack *next;
  636.     struct variable_defs *v;
  637.     int mod_flag;
  638.     union {
  639.     int ivar;
  640.     int bool;
  641.     char key;
  642.     char *str;
  643.     } value;
  644. } *var_stack = NULL, *vs_pool = NULL;
  645.  
  646. mark_var_stack()
  647. {
  648.     register struct var_stack *vs;
  649.  
  650.     if (vs_pool) {
  651.     vs = vs_pool;
  652.     vs_pool = vs->next;
  653.     } else
  654.     vs = newobj(struct var_stack, 1);
  655.  
  656.     vs->next = var_stack;
  657.     var_stack = vs;
  658.     vs->v = NULL;
  659. }
  660.  
  661. push_variable(variable)
  662. char *variable;
  663. {
  664.     register struct variable_defs *var;
  665.     register struct var_stack *vs;
  666.  
  667.     if (strncmp(variable, "no", 2) == 0) {
  668.     variable += 2;
  669.     if (variable[0] == '-') variable++;
  670.     }
  671.  
  672.     if ((var = lookup_variable(variable)) == NULL) {
  673.     msg("pushing unknown variable %s", variable);
  674.     return 0;
  675.     }
  676.  
  677.     mark_var_stack();
  678.     vs = var_stack;
  679.     vs->v = var;
  680.     vs->mod_flag = var->var_flags & V_MODIFIED;
  681.  
  682.     switch (VAR_TYPE) {
  683.  
  684.      case V_STRING:
  685.  
  686.     switch (VAR_OP) {
  687.      case 0:    /* if we update one of these variables,    */
  688.      case 2:    /* new storage will be allocated for it */
  689.      case 3:    /* so it is ok just to save the pointer */
  690.         vs->value.str = STR_VAR;
  691.         break;
  692.  
  693.      case 1:    /* we free this memory when restored    */
  694.         vs->value.str = copy_str(CBUF_VAR);
  695.         break;
  696.     }
  697.     break;
  698.  
  699.      case V_BOOLEAN:
  700.     vs->value.bool = BOOL_VAR;
  701.     break;
  702.  
  703.      case V_INTEGER:
  704.     vs->value.ivar = INT_VAR;
  705.     break;
  706.  
  707.      case V_KEY:
  708.     vs->value.key = KEY_VAR;
  709.     break;
  710.  
  711.      case V_SPECIAL:
  712.     msg("Cannot push pseudo variable %s", var->var_name);
  713.     break;
  714.     }
  715.  
  716.     return 1;
  717. }
  718.  
  719. restore_variables()
  720. {
  721.     register struct variable_defs *var;
  722.     register struct var_stack *vs, *vs1;
  723.  
  724.     vs = var_stack;
  725.  
  726.     while (vs != NULL) {
  727.     if ((var = vs->v) == NULL) {
  728.         var_stack = vs->next;
  729.         vs->next = vs_pool;
  730.         vs_pool = vs;
  731.         return;
  732.     }
  733.  
  734.     var->var_flags &= ~V_MODIFIED;
  735.     var->var_flags |= vs->mod_flag;
  736.  
  737.     switch (VAR_TYPE) {
  738.  
  739.      case V_STRING:
  740.         switch (VAR_OP) {
  741.          case 0:    /* only restore the string if changed; then we    */
  742.          case 2:    /* can also free the memory occupied by the    */
  743.          case 3:    /* 'new' value (if not NULL)            */
  744.         if (STR_VAR != vs->value.str) {
  745.             if (STR_VAR != NULL) freeobj(STR_VAR);
  746.             STR_VAR = vs->value.str;
  747.         }
  748.         break;
  749.  
  750.          case 1:    /* it fitted before, so it will fit againg */
  751.         strcpy(CBUF_VAR, vs->value.str);
  752.         freeobj(vs->value.str);
  753.         break;
  754.         }
  755.         break;
  756.  
  757.      case V_BOOLEAN:
  758.         BOOL_VAR = vs->value.bool;
  759.         break;
  760.  
  761.      case V_INTEGER:
  762.         INT_VAR = vs->value.ivar;
  763.         break;
  764.  
  765.      case V_KEY:
  766.         KEY_VAR = vs->value.key;
  767.         break;
  768.  
  769.      case V_SPECIAL:    /* these are not saved, so... */
  770.         break;
  771.     }
  772.  
  773.     vs1 = vs->next;
  774.     vs->next = vs_pool;
  775.     vs_pool = vs;
  776.     vs = vs1;
  777.     }
  778.     var_stack = NULL;
  779. }
  780.  
  781. static var_on_stack(var)
  782. register struct variable_defs *var;
  783. {
  784.     register struct var_stack *vs;
  785.  
  786.     for (vs = var_stack; vs; vs = vs->next)
  787.     if (vs->v == var) return 1;
  788.     return 0;
  789. }
  790.  
  791. disp_variables(all)
  792. int all;
  793. {
  794.     char *str, pushed;
  795.     int b;
  796.     register struct variable_defs *var;
  797.  
  798.     if (in_init) return;
  799.  
  800.     pg_init(0, 1);
  801.  
  802.     clrdisp();
  803.     if (novice && !all) {
  804.     msg("Use `:set all' to see all variable settings");
  805.     home();
  806.     }
  807.     pg_next();
  808.     so_printf("\1Variable settings:\1");
  809.  
  810.     for (var = variables; var < &variables[TABLE_SIZE]; var++) {
  811.     pushed =
  812.         var_on_stack(var) ? '>' :
  813.         (var->var_flags & V_MODIFIED) ? '*' : ' ';
  814.  
  815.     if (!all && pushed == ' ') continue;
  816.  
  817.     switch (VAR_TYPE) {
  818.      case V_STRING:
  819.         if (pg_next() < 0) goto out;
  820.         str = (VAR_OP == 1) ? CBUF_VAR : STR_VAR;
  821.         if (str == NULL) str = "";
  822.         printf("%c %-20.20s = \"%s\"\n", pushed, var->var_name, str);
  823.         break;
  824.  
  825.      case V_BOOLEAN:
  826.         if (pg_next() < 0) goto out;
  827.         b = BOOL_VAR;
  828.         if (VAR_OP == 2 || VAR_OP == 4) b = !b;
  829.         printf("%c %-20.20s = %s\n",
  830.            pushed, var->var_name, b ? "on" : "off");
  831.         break;
  832.  
  833.      case V_INTEGER:
  834.         if (pg_next() < 0) goto out;
  835.         printf("%c %-20.20s = %d\n", pushed, var->var_name, INT_VAR);
  836.         break;
  837.  
  838.      case V_KEY:
  839.         if (pg_next() < 0) goto out;
  840.         printf("%c %-20.20s = %s\n",
  841.            pushed, var->var_name, key_name(KEY_VAR));
  842.         break;
  843.  
  844.      case V_SPECIAL:
  845.         switch (VAR_OP) {
  846.          case 1:
  847.         break;
  848.          case 2:
  849.         if (also_read_articles) {
  850.             if (pg_next() < 0) goto out;
  851.             printf("%c %-20.20s = %d\n",
  852.                pushed, var->var_name, article_limit);
  853.         }
  854.         break;
  855.         }
  856.         break;
  857.     }
  858.     }
  859.  
  860. out:
  861.     pg_end();
  862. }
  863.