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

  1. /*
  2.  *    (c) Copyright 1990, Kim Fabricius Storm.  All rights reserved.
  3.  *
  4.  *    Variable setting and display
  5.  */
  6.  
  7. #include "config.h"
  8. #include "keymap.h"
  9. #include "regexp.h"
  10. #include "chset.h"
  11.  
  12. /* variable.c */
  13.  
  14. static struct variable_defs *lookup_variable __APROTO((char *variable));
  15. static char escaped_char __APROTO((int c));
  16. static void adjust __APROTO((register char *str));
  17. static char *var_value __APROTO((register struct variable_defs *var, char *tag));
  18. static var_on_stack __APROTO((register struct variable_defs *var));
  19.  
  20. extern int prompt_length, prompt_line;
  21. extern regexp *pg_regexp;
  22. extern int pg_new_regexp;
  23.  
  24.  
  25. /*
  26.  * Variable types and variants
  27.  *
  28.  * Boolean: type 'int'.
  29.  *
  30.  *    BOOL 0        Ordinary boolean variable.
  31.  *    BOOL 1        As 0 + redraw screen on return.
  32.  *    BOOL 2        Special: reorder menu according to new value.
  33.  *    BOOL 4        Inverse boolean varible ("set" clears internal var).
  34.  *
  35.  * Numeric: type 'int'.
  36.  *
  37.  *    INT 0        Ordinary numeric variable ("unset" set var to 0).
  38.  *    INT 1        As 0 + redraw screen on return.
  39.  *    INT 2        As 0, but "unset" set var to -1.
  40.  *    INT 3        As 2 + redraw screen on return.
  41.  *
  42.  * Strings: type 'char *'
  43.  *
  44.  *    STR 0        Ordinary string ("unset" set var to NULL).
  45.  *    STR 2        (home relative) file name or full path.
  46.  *            Automatically expanded.  ("unset" set var to NULL).
  47.  *    STR 3        Ordinary string, but cannot be "unset".
  48.  *    STR 4        (Expanded) file name - cannot be unset.
  49.  *    STR 5        Ordinary string ("unset" set var to "").
  50.  *
  51.  *    CODES n        String initialized by list of key names.
  52.  *            A maximum of 16 CODES variables (n = 0 - 15) exist.
  53.  *
  54.  * Strings: type 'char []'
  55.  *
  56.  *    STR 1        Ordinary string saved in static array.
  57.  *            "unset" set array to empty string.
  58.  *            Warning: no bounds checking!
  59.  *            Notice: Variable address is "(char **)var"  (no &).
  60.  *
  61.  * Keys: type 'key_type'
  62.  *
  63.  *    KEY 0        Ordinary key.
  64.  *
  65.  * Pseudo variables:
  66.  *
  67.  *    SPEC n        Treated by V_SPECIAL 'case n'.
  68.  *
  69.  * Modifiers:
  70.  *
  71.  *    INIT        Can only be set in init file.
  72.  *    SAFE        Cannot be changed if "shell-restrictions" is set.
  73.  */
  74.  
  75. import in_init;
  76.  
  77. import char            /* string variables */
  78.     *backup_folder_path,
  79.     *bak_suffix,
  80.     *bug_address,
  81.     *counter_delim_left,
  82.     *counter_delim_right,
  83.     *decode_header_file,
  84.     *default_distribution,
  85.     *default_save_file,
  86.     *distribution_follow,
  87.     *distribution_post,
  88.     *editor_program,
  89.     *extra_mail_headers,
  90.     *extra_news_headers,
  91.     *folder_save_file,
  92.     *header_lines,
  93.     *folder_directory,
  94.     included_mark[],
  95.     *inews_program,
  96.     *initial_newsrc_path,
  97.     *mail_alias_expander,
  98.     *mail_box,
  99.     *mail_record,
  100.     *mail_script,
  101.     *mailer_program,
  102.     attributes[],
  103.     *newsrc_file,
  104.     *news_record,
  105.     *news_script,
  106.     *pager,
  107.     patch_command[],
  108.     printer[],
  109.     *print_header_lines,
  110.     *response_dflt_answer,
  111.     *save_counter_format,
  112.     *save_header_lines,
  113.     *saved_header_escape,
  114.     *shade_on_attr,
  115.     *shade_off_attr,
  116.     *spell_checker,
  117.     *trusted_escapes,
  118.     unshar_command[],
  119.     *unshar_header_file,
  120.     *user_shell;
  121.  
  122. import int            /* boolean variables */
  123.     also_cross_postings,
  124.     also_full_digest,
  125.     also_subgroups,
  126.     append_sig_mail,
  127.     append_sig_post,
  128.     auto_junk_seen,
  129.     auto_select_rw,
  130.     auto_select_subject,
  131.     auto_preview_mode,
  132.     body_search_header,
  133.     case_fold_search,
  134.     check_group_access,
  135.     compress_mode,
  136.     conf_append,
  137.     conf_auto_quit,
  138.     conf_create,
  139.     conf_dont_sleep,
  140.     conf_group_entry,
  141.     conf_junk_seen,
  142.     consolidated_manual,
  143.     consolidated_menu,
  144.     counter_padding,
  145.     delay_redraw,
  146.     dflt_kill_select,
  147.     do_kill_handling,
  148.     dont_sort_articles,
  149.     dont_sort_folders,
  150.     dont_split_digests,
  151.     echo_prefix_key,
  152.     edit_patch_command,
  153.     edit_print_command,
  154.     edit_unshar_command,
  155.     empty_answer_check,
  156.     enter_last_read_mode,
  157.     flow_control,
  158.     flush_typeahead,
  159.     fmt_rptsubj,
  160.     folder_format_check,
  161.     folder_rewrite_trace,
  162.     guard_double_slash,
  163.     ignore_formfeed,
  164.     ignore_xon_xoff,
  165.     ignore_re,
  166.     include_art_id,
  167.     include_full_header,
  168.     include_mark_blanks,
  169.     inews_pipe_input,
  170.     keep_backup_folder,
  171.     keep_rc_backup,
  172.     keep_unsubscribed,
  173.     keep_unsub_long,
  174.     long_menu,
  175.     macro_debug,
  176.     mailer_pipe_input,
  177.     mark_overlap,
  178.     mark_overlap_shading,
  179.     match_parts_equal,
  180.     match_parts_begin,
  181.     monitor_mode,
  182.     new_read_prompt,
  183.     novice,
  184.     prev_also_read,
  185.     preview_mark_read,
  186.     query_signature,
  187.     quick_save,
  188.     quick_unread_count,
  189.     read_ret_next_page,
  190.     repeat_group_query,
  191.     report_cost_on_exit,
  192.     retain_seen_status,
  193.     save_report,
  194.     scroll_clear_page,
  195.     select_leave_next,
  196.     select_on_sender,
  197.     seq_cross_filtering,
  198.     shell_restrictions,
  199.     show_article_date,
  200.     show_current_time,
  201.     show_motd_on_entry,
  202.     silent,
  203.     slow_mode,
  204.     suggest_save_file,
  205.     tidy_newsrc,
  206.     use_mail_folders,
  207.     use_mmdf_folders,
  208.     use_path_in_from,
  209.     use_selections,
  210.     use_visible_bell;
  211.  
  212. import int            /* integer variables */
  213.     also_read_articles,
  214.     article_limit,
  215.     auto_read_limit,
  216.     auto_select_closed,
  217.     check_db_update,
  218.     conf_entry_limit,
  219.     collapse_subject,
  220.     Columns,
  221.     data_bits,
  222.     Debug,
  223.     decode_skip_prefix,
  224.     entry_message_limit,
  225.     expired_msg_delay,
  226.     first_page_lines,
  227.     fmt_linenum,
  228.     kill_debug,
  229.     kill_ref_count,
  230.     Lines,
  231.     match_skip_prefix,
  232.     mark_next_group,
  233.     mark_read_return,
  234.     mark_read_skip,
  235.     menu_spacing,
  236.     merge_report_rate,
  237.     message_history,
  238.     min_pv_window,
  239.     mouse_usage,
  240.     multi_key_guard_time,
  241.     new_group_action,
  242.     newsrc_update_freq,
  243.     orig_to_include_mask,
  244.     overlap,
  245.     preview_continuation,
  246.     preview_window,
  247.     print_header_type,
  248.     re_layout,
  249.     re_layout_more,
  250.     response_check_pause,
  251.     retry_on_error,
  252.     save_closed_mode,
  253.     save_counter_offset,
  254.     scroll_last_lines,
  255.     show_purpose_mode,
  256.     slow_speed,
  257.     strict_from_parse,
  258.     sort_mode,
  259.     subject_match_limit,
  260.     wrap_headers;
  261.  
  262. #ifdef NNTP
  263. import char *nntp_cache_dir;
  264. import int nntp_cache_size, nntp_debug;
  265. #endif
  266.  
  267. import key_type            /* key strokes */
  268.     comp1_key,
  269.     comp2_key,
  270.     help_key,
  271.     erase_key,
  272.     delword_key,
  273.     kill_key;
  274.  
  275. #undef STR
  276. #undef BOOL
  277. #undef INT
  278. #undef KEY
  279. #undef SPEC
  280. #undef SAFE
  281. #undef INIT
  282. #undef CODES
  283.  
  284.  
  285. #define    V_STRING    0x1000
  286. #define V_BOOLEAN    0x2000
  287. #define    V_INTEGER    0x3000
  288. #define V_KEY        0x4000
  289. #define    V_SPECIAL    0x5000
  290. #define V_CODES        0x6000
  291.  
  292. #define V_SAFE        0x0100
  293. #define V_INIT        0x0200
  294.  
  295. #define V_LOCKED    0x0800
  296. #define V_MODIFIED    0x8000
  297.  
  298. #define    STR        V_STRING |
  299. #define BOOL        V_BOOLEAN |
  300. #define    INT        V_INTEGER |
  301. #define KEY        V_KEY |
  302. #define    SPEC        V_SPECIAL |
  303. #define    CODES        V_CODES |
  304.  
  305. #define SAFE        V_SAFE |
  306. #define INIT        V_INIT |
  307.  
  308. static char *code_strings[16] = {
  309.     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  310.     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
  311. };
  312.  
  313. static int var_on_stack();
  314.  
  315. struct variable_defs {
  316.     char *var_name;
  317.     int  var_flags;
  318.     char **var_addr;
  319. } variables[] = {
  320.     "also-full-digest",        BOOL 0,        (char **)&also_full_digest,
  321.     "also-subgroups",        BOOL INIT 0,    (char **)&also_subgroups,
  322.     "append-signature-mail",     BOOL 0,        (char **)&append_sig_mail,
  323.     "append-signature-post",     BOOL 0,        (char **)&append_sig_post,
  324.     "attributes",        STR 1,        (char **)attributes,
  325.     "auto-junk-seen",        BOOL 0,        (char **)&auto_junk_seen,
  326.     "auto-preview-mode",    BOOL 0,        (char **)&auto_preview_mode,
  327.     "auto-read-mode-limit",    INT 0,        (char **)&auto_read_limit,
  328.     "auto-select-closed",    INT 0,        (char **)&auto_select_closed,
  329.     "auto-select-rw",        BOOL 0,        (char **)&auto_select_rw,
  330.     "auto-select-subject",    BOOL 0,        (char **)&auto_select_subject,
  331.     "backup",            BOOL 0,        (char **)&keep_rc_backup,
  332.     "backup-folder-path",    STR 4,        (char **)&backup_folder_path,
  333.     "backup-suffix",        STR 0,        (char **)&bak_suffix,
  334.     "body-search-header",    BOOL 0,        (char **)&body_search_header,
  335.     "bug-report-address",     STR 0,        (char **)&bug_address,
  336.     "case-fold-search",        BOOL 0,        (char **)&case_fold_search,
  337.     "charset",            SPEC 3,        (char **)NULL,
  338.     "check-db-update-time",    INT 0,        (char **)&check_db_update,
  339.     "check-group-access",    BOOL 0,        (char **)&check_group_access,
  340.     "collapse-subject",        INT 3,        (char **)&collapse_subject,
  341.     "columns",            INT 1,        (char **)&Columns,
  342.     "comp1-key",        KEY 0,        (char **)&comp1_key,
  343.     "comp2-key",        KEY 0,        (char **)&comp2_key,
  344.     "compress",            BOOL 0,        (char **)&compress_mode,
  345.     "confirm-append",        BOOL 0,        (char **)&conf_append,
  346.     "confirm-auto-quit",    BOOL 0,        (char **)&conf_auto_quit,
  347.     "confirm-create",        BOOL 0,        (char **)&conf_create,
  348.     "confirm-entry",        BOOL 0,        (char **)&conf_group_entry,
  349.     "confirm-entry-limit",    INT 0,        (char **)&conf_entry_limit,
  350.     "confirm-junk-seen",     BOOL 0,        (char **)&conf_junk_seen,
  351.     "confirm-messages",        BOOL 0,        (char **)&conf_dont_sleep,
  352.     "consolidated-manual",    BOOL 0,        (char **)&consolidated_manual,
  353.     "consolidated-menu",    BOOL 1,        (char **)&consolidated_menu,
  354.     "counter-delim-left",    STR 5,        (char **)&counter_delim_left,
  355.     "counter-delim-right",    STR 5,        (char **)&counter_delim_right,
  356.     "counter-padding",        INT 1,        (char **)&counter_padding,
  357.     "cross-filter-seq",        BOOL 0,        (char **)&seq_cross_filtering,
  358.     "cross-post",        BOOL 0,        (char **)&also_cross_postings,
  359.     "data-bits",        INT 0,        (char **)&data_bits,
  360.     "date",            BOOL 0,        (char **)&show_article_date,
  361.     "debug",            INT 0,        (char **)&Debug,
  362.     "decode-header-file",    STR 0,        (char **)&decode_header_file,
  363.     "decode-skip-prefix",    INT 0,        (char **)&decode_skip_prefix,
  364.     "default-distribution",    STR 0,        (char **)&default_distribution,
  365.     "default-kill-select",    INT 0,        (char **)&dflt_kill_select,
  366.     "default-save-file",    STR 3,        (char **)&default_save_file,
  367.     "delay-redraw",        BOOL 0,        (char **)&delay_redraw,
  368.     "echo-prefix-key",         BOOL 0,        (char **)&echo_prefix_key,
  369.     "edit-patch-command",     BOOL 0,        (char **)&edit_patch_command,
  370.     "edit-print-command",     BOOL 0,        (char **)&edit_print_command,
  371.     "edit-response-check",     BOOL 0,        (char **)&empty_answer_check,
  372.     "edit-unshar-command",     BOOL 0,        (char **)&edit_unshar_command,
  373.     "editor",            STR 0,        (char **)&editor_program,
  374.     "embedded-header-escape",    STR 0,        (char **)&saved_header_escape,
  375.     "enter-last-read-mode",    INT 0,        (char **)&enter_last_read_mode,
  376.     "entry-report-limit",     INT 0,        (char **)&entry_message_limit,
  377.     "erase-key",        KEY 0,        (char **)&erase_key,
  378.     "expert",            BOOL 4,        (char **)&novice,
  379.     "expired-message-delay",    INT 0,        (char **)&expired_msg_delay,
  380.     "flow-control",        BOOL 0,        (char **)&flow_control,
  381.     "flush-typeahead",        BOOL 0,        (char **)&flush_typeahead,
  382.     "folder",            STR 2,        (char **)&folder_directory,
  383.     "folder-format-check",    BOOL 0,        (char **)&folder_format_check,
  384.     "folder-save-file",        STR 3,        (char **)&folder_save_file,
  385.     "follow-distribution",    STR 0,        (char **)&distribution_follow,
  386.     "from-line-parsing",    INT 0,        (char **)&strict_from_parse,
  387.     "fsort",            BOOL 2,        (char **)&dont_sort_folders,
  388.     "guard-double-slash",    BOOL 0,        (char **)&guard_double_slash,
  389.     "header-lines",        STR 0,        (char **)&header_lines,
  390.     "help-key",            KEY 0,        (char **)&help_key,
  391.     "ignore-formfeed",        BOOL 0,        (char **)&ignore_formfeed,
  392.     "ignore-re",        BOOL 0,        (char **)&ignore_re,
  393.     "ignore-xon-xoff",        BOOL 0,        (char **)&ignore_xon_xoff,
  394.     "include-art-id",        BOOL 0,        (char **)&include_art_id,
  395.     "include-full-header",    BOOL 0,        (char **)&include_full_header,
  396.     "include-mark-blank-lines",    BOOL 0,        (char **)&include_mark_blanks,
  397.     "included-mark",        STR 1,        (char **)included_mark,
  398.     "inews",            STR 0,        (char **)&inews_program,
  399.     "inews-pipe-input",        BOOL 0,        (char **)&inews_pipe_input,
  400.     "initial-newsrc-file",    STR 0,        (char **)&initial_newsrc_path,
  401.     "keep-backup-folder",     BOOL 0,        (char **)&keep_backup_folder,
  402.     "keep-unsubscribed",     BOOL 0,        (char **)&keep_unsubscribed,
  403.     "kill",            BOOL 0,        (char **)&do_kill_handling,
  404.     "kill-debug",        BOOL 0,        (char **)&kill_debug,
  405.     "kill-key",            KEY 0,        (char **)&kill_key,
  406.     "kill-reference-count",    INT 0,        (char **)&kill_ref_count,
  407.     "layout",            INT 1,        (char **)&fmt_linenum,
  408.     "limit",            INT 2,        (char **)&article_limit,
  409.     "lines",            INT 1,        (char **)&Lines,
  410.     "long-menu",        BOOL 1,        (char **)&long_menu,
  411.     "macro-debug",        BOOL 0,        (char **)¯o_debug,
  412.     "mail",            STR 2,        (char **)&mail_box,
  413.     "mail-alias-expander",    STR 0,        (char **)&mail_alias_expander,
  414.     "mail-format",        BOOL 0,        (char **)&use_mail_folders,
  415.     "mail-header",        STR 0,        (char **)&extra_mail_headers,
  416.     "mail-record",        STR 2,        (char **)&mail_record,
  417.     "mail-script",        STR SAFE 2,    (char **)&mail_script,
  418.     "mailer",            STR 0,        (char **)&mailer_program,
  419.     "mailer-pipe-input",    BOOL 0,        (char **)&mailer_pipe_input,
  420.     "mark-overlap",        BOOL 0,        (char **)&mark_overlap,
  421.     "mark-overlap-shading",    BOOL 0,        (char **)&mark_overlap_shading,
  422.     "marked-by-next-group",    INT 0,        (char **)&mark_next_group,
  423.     "marked-by-read-return",    INT 0,        (char **)&mark_read_return,
  424.     "marked-by-read-skip",    INT 0,        (char **)&mark_read_skip,
  425.     "menu-spacing",        INT 1,        (char **)&menu_spacing,
  426.     "merge-report-rate",    INT 0,        (char **)&merge_report_rate,
  427.     "message-history",        INT 0,        (char **)&message_history,
  428.     "min-window",        INT 1,        (char **)&min_pv_window,
  429.     "mmdf-format",        BOOL 0,        (char **)&use_mmdf_folders,
  430.     "monitor",            BOOL 0,        (char **)&monitor_mode,
  431.     "motd",            BOOL 0,        (char **)&show_motd_on_entry,
  432.     "mouse-usage",        INT 0,        (char **)&mouse_usage,
  433.     "multi-key-guard-time",    INT 0,        (char **)&multi_key_guard_time,
  434.     "new-group-action",        INT 0,        (char **)&new_group_action,
  435.     "new-style-read-prompt",    BOOL 0,        (char **)&new_read_prompt,
  436.     "news-header",        STR 0,        (char **)&extra_news_headers,
  437.     "news-record",        STR 2,        (char **)&news_record,
  438.     "news-script",        STR SAFE 2,    (char **)&news_script,
  439.     "newsrc",            STR 2,        (char **)&newsrc_file,
  440. #ifdef NNTP
  441.     "nntp-cache-dir",        STR INIT 0,    (char **)&nntp_cache_dir,
  442.     "nntp-cache-size",        INT INIT 0,    (char **)&nntp_cache_size,
  443.     "nntp-debug",        BOOL 0,        (char **)&nntp_debug,
  444. #endif
  445. /*  "no....."  -- cannot have variable names starting with "no" */
  446.     "old",            SPEC 2,        (char **)NULL,
  447.     "orig-to-include-mask",    INT 0,        (char **)&orig_to_include_mask,
  448.     "overlap",            INT 0,        (char **)&overlap,
  449.     "pager",            STR SAFE 3,    (char **)&pager,
  450.     "patch-command",        STR SAFE 1,    (char **)patch_command,
  451.     "post-distribution",    STR 0,        (char **)&distribution_post,
  452.     "preview-continuation",     INT 0,        (char **)&preview_continuation,
  453.     "preview-mark-read",    BOOL 0,        (char **)&preview_mark_read,
  454.     "previous-also-read",    BOOL 0,        (char **)&prev_also_read,
  455.     "print-header-lines",    STR 0,        (char **)&print_header_lines,
  456.     "print-header-type",    INT 0,        (char **)&print_header_type,
  457.     "printer",            STR SAFE 1,    (char **)printer,
  458.     "query-signature",        BOOL 0,        (char **)&query_signature,
  459.     "quick-count",        BOOL 0,        (char **)&quick_unread_count,
  460.     "quick-save",        BOOL 0,        (char **)&quick_save,
  461.     "re-layout",        INT 0,        (char **)&re_layout,
  462.     "re-layout-read",        INT 0,        (char **)&re_layout_more,
  463.     "read-return-next-page",    BOOL 0,        (char **)&read_ret_next_page,
  464.     "record",            SPEC 1,        (char **)NULL,
  465.     "repeat",            BOOL 0,        (char **)&fmt_rptsubj,
  466.     "repeat-group-query",    BOOL 0,        (char **)&repeat_group_query,
  467.     "report-cost",        BOOL 0,        (char **)&report_cost_on_exit,
  468.     "response-check-pause",    INT 0,        (char **)&response_check_pause,
  469.     "response-default-answer",    STR 0,        (char **)&response_dflt_answer,
  470.     "retain-seen-status",     BOOL 0,        (char **)&retain_seen_status,
  471.     "retry-on-error",        INT 0,        (char **)&retry_on_error,
  472.     "save-closed-mode",        INT 0,        (char **)&save_closed_mode,
  473.     "save-counter",        STR 3,        (char **)&save_counter_format,
  474.     "save-counter-offset",    INT 0,        (char **)&save_counter_offset,
  475.     "save-header-lines",    STR 0,        (char **)&save_header_lines,
  476.     "save-report",        BOOL 0,        (char **)&save_report,
  477.     "scroll-clear-page",    BOOL 0,        (char **)&scroll_clear_page,
  478.     "scroll-last-lines",    INT 0,        (char **)&scroll_last_lines,
  479.     "select-leave-next",    BOOL 0,        (char **)&select_leave_next,
  480.     "select-on-sender",        BOOL 0,        (char **)&select_on_sender,
  481.     "shading-off",        CODES 0,    (char **)&shade_off_attr,
  482.     "shading-on",        CODES 1,    (char **)&shade_on_attr,
  483.     "shell",            STR SAFE 0,    (char **)&user_shell,
  484.     "shell-restrictions",     BOOL INIT 0,    (char **)&shell_restrictions,
  485.     "show-purpose-mode",    INT 0,        (char **)&show_purpose_mode,
  486.     "silent",            BOOL 0,        (char **)&silent,
  487.     "slow-mode",        BOOL 0,        (char **)&slow_mode,
  488.     "slow-speed",        INT 0,        (char **)&slow_speed,
  489.     "sort",            BOOL 2,        (char **)&dont_sort_articles,
  490.     "sort-mode",        INT 0,        (char **)&sort_mode,
  491.     "spell-checker",        STR 0,        (char **)&spell_checker,
  492.     "split",            BOOL 4,        (char **)&dont_split_digests,
  493.     "stop",            INT 0,        (char **)&first_page_lines,
  494.     "subject-match-limit",     INT 0,        (char **)&subject_match_limit,
  495.     "subject-match-minimum",    INT 0,        (char **)&match_parts_begin,
  496.     "subject-match-offset",    INT 0,        (char **)&match_skip_prefix,
  497.     "subject-match-parts",    BOOL 0,        (char **)&match_parts_equal,
  498.     "suggest-default-save",     BOOL 0,        (char **)&suggest_save_file,
  499.     "tidy-newsrc",        BOOL 0,        (char **)&tidy_newsrc,
  500.     "time",            BOOL 0,        (char **)&show_current_time,
  501.     "trace-folder-packing",    BOOL 0,        (char **)&folder_rewrite_trace,
  502.     "trusted-escape-codes",    STR 0,        (char **)&trusted_escapes,
  503.     "unshar-command",        STR SAFE 1,    (char **)unshar_command,
  504.     "unshar-header-file",    STR 0,        (char **)&unshar_header_file,
  505.     "unsubscribe-mark-read",    BOOL 4,        (char **)&keep_unsub_long,
  506.     "update-frequency",        INT 0,        (char **)&newsrc_update_freq,
  507.     "use-path-in-from",        BOOL 0,        (char **)&use_path_in_from,
  508.     "use-selections",         BOOL 0,        (char **)&use_selections,
  509.     "visible-bell",         BOOL 0,        (char **)&use_visible_bell,
  510.     "window",            INT 1,        (char **)&preview_window,
  511.     "word-key",            KEY 0,        (char **)&delword_key,
  512.     "wrap-header-margin",    INT 2,        (char **)&wrap_headers
  513. };
  514.  
  515. #define TABLE_SIZE    (sizeof(variables)/sizeof(struct variable_defs))
  516.  
  517. #define INT_VAR        (*((int *)(var->var_addr)))
  518. #define BOOL_VAR    (*((int *)(var->var_addr)))
  519. #define STR_VAR        (*(var->var_addr))
  520. #define CBUF_VAR    ((char *)(var->var_addr))
  521. #define KEY_VAR        (*((key_type *)(var->var_addr)))
  522.  
  523. #define VAR_TYPE    (var->var_flags & 0x7000)
  524. #define VAR_OP        (var->var_flags & 0x000f)
  525.  
  526. static struct variable_defs *lookup_variable(variable)
  527. char *variable;
  528. {
  529.     register struct variable_defs *var;
  530.     register i, j, k, t;
  531.  
  532.     i = 0; j = TABLE_SIZE - 1;
  533.  
  534.     while (i <= j) {
  535.     k = (i + j) / 2;
  536.     var = &variables[k];
  537.  
  538.     if ( (t=strcmp(variable, var->var_name)) > 0)
  539.         i = k+1;
  540.     else
  541.     if (t < 0)
  542.         j = k-1;
  543.     else
  544.         return var;
  545.     }
  546.  
  547.     init_message("unknown variable: %s", variable);
  548.     return NULL;
  549. }
  550.  
  551.  
  552. static char escaped_char(c)
  553. char c;
  554. {
  555.     switch (c) {
  556.      case 'a':
  557.     return 007;
  558.      case 'b':
  559.     return BS;
  560.      case 'e':
  561.     return 033;
  562.      case 'f':
  563.     return '\f';
  564.      case 'n':
  565.     return NL;
  566.      case 'r':
  567.     return CR;
  568.      case 't':
  569.     return TAB;
  570.     }
  571.     return c;
  572. }
  573.  
  574. static void
  575. adjust(str)
  576. register char *str;
  577. {
  578.     register char *s, *t;
  579.  
  580.     if ((s = t = str) == NULL) return;
  581.     while (*s && *s != '#') {
  582.     if (*s == '\\' && s[1] != NUL) {
  583.         s++;
  584.         *str++ = escaped_char(*s++);
  585.     } else
  586.     if (str == s) {
  587.         str++;
  588.         if (isspace(*s++)) continue;
  589.     } else
  590.         if (isspace(*str++ = *s++)) continue;
  591.     t = str;
  592.     }
  593.     *t = NUL;
  594. }
  595.  
  596. int
  597. set_variable(variable, on, val_string)
  598. char *variable;
  599. int on;
  600. char *val_string;
  601. {
  602.     int value;
  603.     register struct variable_defs *var;
  604.  
  605.     if (strncmp(variable, "no", 2) == 0) {
  606.     on = !on;
  607.     variable += 2;
  608.     if (variable[0] == '-') variable++;
  609.     }
  610.  
  611.     if ((var = lookup_variable(variable)) == NULL)
  612.     return 0;
  613.  
  614.     if (!in_init && (var->var_flags & (V_INIT | V_SAFE))) {
  615.     if (var->var_flags & V_INIT) {
  616.         msg("'%s' can only be set in the init file", variable);
  617.         return 0;
  618.     }
  619.     if (shell_restrictions) {
  620.         msg("Restricted operation - cannot change");
  621.         return 0;
  622.     }
  623.     }
  624.  
  625.     if (var->var_flags & V_LOCKED) {
  626.     msg("Variable '%s' is locked", variable);
  627.     return 0;
  628.     }
  629.  
  630.     if (!on || val_string == NULL)
  631.     value = 0;
  632.     else
  633.     value = atoi(val_string);
  634.  
  635.     var->var_flags |= V_MODIFIED;
  636.  
  637.     switch (VAR_TYPE) {
  638.  
  639.      case V_STRING:
  640.  
  641.     if (on) adjust(val_string);
  642.  
  643.     switch (VAR_OP) {
  644.      case 0:
  645.         STR_VAR = (on && val_string) ? copy_str(val_string) : (char *)NULL;
  646.         break;
  647.  
  648.      case 1:
  649.         strcpy(CBUF_VAR, (on && val_string) ? val_string : "");
  650.         break;
  651.  
  652.      case 2:
  653.         if (on) {
  654.         char exp_buf[FILENAME];
  655.  
  656.         if (val_string) {
  657.             if (expand_file_name(exp_buf, val_string, 1))
  658.             STR_VAR = home_relative(exp_buf);
  659.         }
  660.         } else
  661.         STR_VAR = (char *)NULL;
  662.         break;
  663.  
  664.      case 3:
  665.      case 4:
  666.         if (!on || val_string == NULL) {
  667.         msg("Cannot unset string `%s'", variable);
  668.         break;
  669.         }
  670.         if (VAR_OP == 4) {
  671.         char exp_buf[FILENAME];
  672.         if (expand_file_name(exp_buf, val_string, 1)) {
  673.             STR_VAR = copy_str(exp_buf);
  674.             break;
  675.         }
  676.         }
  677.         STR_VAR = copy_str(val_string);
  678.         break;
  679.      case 5:
  680.         STR_VAR = (on && val_string) ? copy_str(val_string) : "";
  681.         break;
  682.  
  683.     }
  684.     break;
  685.  
  686.      case V_BOOLEAN:
  687.  
  688.     adjust(val_string);
  689.     if (val_string && *val_string != NUL)
  690.         if (val_string[0] == 'o')
  691.         on = val_string[1] == 'n'; /* on */
  692.         else
  693.         on = val_string[0] == 't'; /* true */
  694.  
  695.     switch (VAR_OP) {
  696.      case 0:
  697.         BOOL_VAR = on;
  698.         break;
  699.  
  700.      case 1:
  701.         BOOL_VAR = on;
  702.         return 1;
  703.  
  704.      case 2:
  705.         if (BOOL_VAR) {    /* don't change if already ok */
  706.         if (!on) break;
  707.         } else
  708.         if (on) break;
  709.  
  710.         BOOL_VAR = !on;
  711.         if (!in_init) {
  712.         sort_articles(BOOL_VAR ? 0 : -1);
  713.         return 1;
  714.         }
  715.         break;
  716.  
  717.      case 4:
  718.         BOOL_VAR = !on;
  719.         break;
  720.     }
  721.     break;
  722.  
  723.      case V_INTEGER:
  724.  
  725.     switch (VAR_OP) {
  726.      case 0:
  727.      case 1:
  728.         INT_VAR = value;
  729.         break;
  730.  
  731.      case 2:
  732.      case 3:
  733.         if (!on) value = -1;
  734.         INT_VAR = value;
  735.         break;
  736.     }
  737.     return (VAR_OP & 1);
  738.  
  739.      case V_KEY:
  740.     switch (VAR_OP) {
  741.      case 0:
  742.         if (val_string) {
  743.         if (*val_string) adjust(val_string + 1); /* #N is valid */
  744.         KEY_VAR = parse_key(val_string);
  745.         }
  746.         break;
  747.     }
  748.     break;
  749.  
  750.      case V_SPECIAL:
  751.  
  752.     switch (VAR_OP) {
  753.      case 1:
  754.         if (val_string) {
  755.         adjust(val_string);
  756.         news_record = home_relative(val_string);
  757.         mail_record = news_record;
  758.         var->var_flags &= ~V_MODIFIED;
  759.         lookup_variable("mail-record")->var_flags |= V_MODIFIED;
  760.         lookup_variable("news-record")->var_flags |= V_MODIFIED;
  761.         }
  762.         break;
  763.  
  764.      case 2:
  765.         also_read_articles = on;
  766.         article_limit = (on && value > 0) ? value : -1;
  767.         break;
  768.  
  769.      case 3:
  770.         {
  771.         struct chset *csp;
  772.             struct variable_defs *dbvar;
  773.  
  774.         dbvar = lookup_variable("data-bits");
  775.  
  776.             if (on && val_string) {
  777.             if ((csp = getchset(val_string)) == NULL)
  778.                 msg("Illegal value for `%s' variable", variable);
  779.             else {
  780.                 curchset = csp;
  781.             data_bits = csp->cs_width ? csp->cs_width : 7;
  782.             dbvar->var_flags &= ~V_MODIFIED;
  783.             }
  784.             } else
  785.             msg("Cannot unset special `%s' variable", variable);
  786.         }
  787.         break;
  788.     }
  789.     break;
  790.  
  791.      case V_CODES:
  792.     {
  793.         char codes[80], code[16], *sp, *cp, *vs;
  794.  
  795.         if (val_string == NULL) on = 0;
  796.         if (on) {
  797.         adjust(val_string);
  798.         if (val_string[0] == NUL) on = 0;
  799.         }
  800.  
  801.         if (on) {
  802.         sp = codes;
  803.         vs = val_string;
  804.         while (*vs) {
  805.             while (*vs && (!isascii(*vs) || isspace(*vs)))
  806.             vs++;
  807.             if (*vs == NUL) break;
  808.             cp = code;
  809.             while (*vs && isascii(*vs) && !isspace(*vs))
  810.             *cp++ = *vs++;
  811.             *cp = NUL;
  812.             *sp++ = parse_key(code);
  813.         }
  814.         *sp = NUL;
  815.         if (codes[0] == NUL) on = 0;
  816.         }
  817.  
  818.         freeobj(code_strings[VAR_OP]);
  819.         code_strings[VAR_OP] = on ? copy_str(val_string) : NULL;
  820.         STR_VAR = on ? copy_str(codes) : (char *)NULL;
  821.         break;
  822.     }
  823.     break;
  824.     }
  825.     return 0;
  826. }
  827.  
  828. void
  829. toggle_variable(variable)
  830. char *variable;
  831. {
  832.     register struct variable_defs *var;
  833.  
  834.     if ((var = lookup_variable(variable)) == NULL) return;
  835.     if (VAR_TYPE != V_BOOLEAN) {
  836.     init_message("variable %s is not boolean", variable);
  837.     return;
  838.     }
  839.  
  840.     BOOL_VAR = !BOOL_VAR;
  841. }
  842.  
  843. void
  844. lock_variable(variable)
  845. char *variable;
  846. {
  847.     register struct variable_defs *var;
  848.  
  849.     if ((var = lookup_variable(variable)) != NULL)
  850.     var->var_flags |= V_LOCKED;
  851. }
  852.  
  853.  
  854. static char *var_value(var, tag)
  855. register struct variable_defs *var;
  856. char *tag;
  857. {
  858.     static char ival[16];
  859.     register char *str = NULL;
  860.     register int b;
  861.  
  862.     if (tag != NULL)
  863.     *tag = var_on_stack(var) ? '>' :
  864.     (var->var_flags & V_LOCKED) ? '!' :
  865.     (var->var_flags & V_MODIFIED) ? '*' : ' ';
  866.  
  867.     switch (VAR_TYPE) {
  868.      case V_STRING:
  869.     str = (VAR_OP == 1) ? CBUF_VAR : STR_VAR;
  870.     break;
  871.  
  872.      case V_BOOLEAN:
  873.     b = BOOL_VAR;
  874.     if (VAR_OP == 2 || VAR_OP == 4) b = !b;
  875.     str = b ? "on" : "off";
  876.     break;
  877.  
  878.      case V_INTEGER:
  879.     sprintf(ival, "%d", INT_VAR);
  880.     str = ival;
  881.     break;
  882.     
  883.      case V_KEY:
  884.     str = key_name(KEY_VAR);
  885.     break;
  886.  
  887.      case V_SPECIAL:
  888.     str = "UNDEF";
  889.     switch (VAR_OP) {
  890.      case 2:
  891.         if (!also_read_articles) break;
  892.         sprintf(ival, "%d", article_limit);
  893.         str = ival;
  894.         break;
  895.      case 3:
  896.         str = curchset->cs_name;
  897.         break;
  898.     }
  899.     break;
  900.  
  901.      case V_CODES:
  902.     str = code_strings[VAR_OP];
  903.     break;
  904.     }
  905.     if (str == NULL) str = "NULL";
  906.     return str;
  907. }
  908.  
  909. int
  910. test_variable(expr)
  911. char *expr;
  912. {
  913.     char *variable;
  914.     register struct variable_defs *var;
  915.     int res = -1;
  916.  
  917.     variable = expr;
  918.     if ((expr = strchr(variable, '=')) == NULL)
  919.     goto err;
  920.  
  921.     *expr++ = NUL;
  922.  
  923.     if ((var = lookup_variable(variable)) == NULL) {
  924.     msg("testing unknown variable %s=%s", variable, expr);
  925.     goto out;
  926.     }
  927.  
  928.     switch (VAR_TYPE) {
  929.  
  930.      case V_BOOLEAN:
  931.     res = BOOL_VAR;
  932.  
  933.     if (strcmp(expr, "on") == 0 || strcmp(expr, "true") == 0) break;
  934.     if (strcmp(expr, "off") == 0 || strcmp(expr, "false") == 0) {
  935.         res = !res;
  936.         break;
  937.     }
  938.     msg("boolean variables must be tested =on or =off");
  939.     break;
  940.  
  941.      case V_INTEGER:
  942.     res = (INT_VAR == atoi(expr)) ? 1 : 0;
  943.     break;
  944.  
  945.      default:
  946.     msg("%s: cannot only test boolean and integer variables", variable);
  947.     break;
  948.     }
  949.  out:
  950.     *--expr = '=';
  951.  err:
  952.     return res;
  953. }
  954.  
  955. static int vc_column;
  956.  
  957. void
  958. var_compl_opts(col)
  959. int col;
  960. {
  961.     vc_column = col;
  962. }
  963.  
  964. int
  965. var_completion(path, index)
  966. char *path;
  967. int index;
  968. {
  969.     static char *head, *tail = NULL;
  970.     static int len;
  971.     static struct variable_defs *var, *help_var;
  972.  
  973.     if (index < 0) {
  974.     clrmsg(-(index + 1));
  975.     return 1;
  976.     }
  977.  
  978.     if (path) {
  979.     head = path;
  980.     tail = path + index;
  981.     while (*head && isspace(*head)) head++;
  982.     if (strncmp(head, "no", 2) == 0) {
  983.         head += 2;
  984.         if (*head == '-') head++;
  985.     }
  986.  
  987.     help_var = var = variables;
  988.     len = tail - head;
  989.  
  990.     return 1;
  991.     }
  992.  
  993.     if (index) {
  994.     list_completion((char *)NULL);
  995.  
  996.     for (;; help_var++) {
  997.         if (help_var >= &variables[TABLE_SIZE]) {
  998.         help_var = variables;
  999.         break;
  1000.         }
  1001.  
  1002.         index = strncmp(help_var->var_name, head, len);
  1003.         if (index < 0) continue;
  1004.         if (index > 0) {
  1005.         help_var = variables;
  1006.         break;
  1007.         }
  1008.         if (list_completion(help_var->var_name) == 0) break;
  1009.     }
  1010.     fl;
  1011.     return 1;
  1012.     }
  1013.  
  1014.     for (; var < &variables[TABLE_SIZE]; var++) {
  1015.     if (len == 0)
  1016.         index = 0;
  1017.     else
  1018.         index = strncmp(var->var_name, head, len);
  1019.     if (index < 0) continue;
  1020.     if (index > 0) break;
  1021.     sprintf(tail, "%s ", var->var_name + len);
  1022.     msg("%.70s", var_value(var, (char *)NULL));
  1023.     gotoxy(prompt_length + vc_column, prompt_line);
  1024.     var++;
  1025.     return 1;
  1026.     }
  1027.     clrmsg(vc_column);
  1028.     return 0;
  1029. }
  1030.  
  1031. static struct var_stack {
  1032.     struct var_stack *next;
  1033.     struct variable_defs *v;
  1034.     int mod_flag;
  1035.     union {
  1036.     int ivar;
  1037.     int bool;
  1038.     char key;
  1039.     char *str;
  1040.     } value;
  1041. } *var_stack = NULL, *vs_pool = NULL;
  1042.  
  1043. void
  1044. mark_var_stack()
  1045. {
  1046.     register struct var_stack *vs;
  1047.  
  1048.     if (vs_pool) {
  1049.     vs = vs_pool;
  1050.     vs_pool = vs->next;
  1051.     } else
  1052.     vs = newobj(struct var_stack, 1);
  1053.  
  1054.     vs->next = var_stack;
  1055.     var_stack = vs;
  1056.     vs->v = NULL;
  1057. }
  1058.  
  1059. int
  1060. push_variable(variable)
  1061. char *variable;
  1062. {
  1063.     register struct variable_defs *var;
  1064.     register struct var_stack *vs;
  1065.  
  1066.     if (strncmp(variable, "no", 2) == 0) {
  1067.     variable += 2;
  1068.     if (variable[0] == '-') variable++;
  1069.     }
  1070.  
  1071.     if ((var = lookup_variable(variable)) == NULL) {
  1072.     msg("pushing unknown variable %s", variable);
  1073.     return 0;
  1074.     }
  1075.  
  1076.     mark_var_stack();
  1077.     vs = var_stack;
  1078.     vs->v = var;
  1079.     vs->mod_flag = var->var_flags & V_MODIFIED;
  1080.  
  1081.     switch (VAR_TYPE) {
  1082.  
  1083.      case V_STRING:
  1084.  
  1085.     switch (VAR_OP) {
  1086.      case 0:    /* if we update one of these variables,    */
  1087.      case 2:    /* new storage will be allocated for it */
  1088.      case 3:    /* so it is ok just to save the pointer */
  1089.      case 4:
  1090.         vs->value.str = STR_VAR;
  1091.         break;
  1092.  
  1093.      case 1:    /* we free this memory when restored    */
  1094.         vs->value.str = copy_str(CBUF_VAR);
  1095.         break;
  1096.     }
  1097.     break;
  1098.  
  1099.      case V_BOOLEAN:
  1100.     vs->value.bool = BOOL_VAR;
  1101.     break;
  1102.  
  1103.      case V_INTEGER:
  1104.     vs->value.ivar = INT_VAR;
  1105.     break;
  1106.  
  1107.      case V_KEY:
  1108.     vs->value.key = KEY_VAR;
  1109.     break;
  1110.  
  1111.      case V_SPECIAL:
  1112.     msg("Cannot push pseudo variable %s", var->var_name);
  1113.     break;
  1114.  
  1115.      case V_CODES:
  1116.     msg("Cannot push code string variable %s", var->var_name);
  1117.     break;
  1118.     }
  1119.  
  1120.     return 1;
  1121. }
  1122.  
  1123. void
  1124. restore_variables()
  1125. {
  1126.     register struct variable_defs *var;
  1127.     register struct var_stack *vs, *vs1;
  1128.  
  1129.     vs = var_stack;
  1130.  
  1131.     while (vs != NULL) {
  1132.     if ((var = vs->v) == NULL) {
  1133.         var_stack = vs->next;
  1134.         vs->next = vs_pool;
  1135.         vs_pool = vs;
  1136.         return;
  1137.     }
  1138.  
  1139.     var->var_flags &= ~V_MODIFIED;
  1140.     var->var_flags |= vs->mod_flag;
  1141.  
  1142.     switch (VAR_TYPE) {
  1143.  
  1144.      case V_STRING:
  1145.         switch (VAR_OP) {
  1146.          case 0:    /* only restore the string if changed; then we    */
  1147.          case 2:    /* can also free the memory occupied by the    */
  1148.          case 3:    /* 'new' value (if not NULL)            */
  1149.          case 4:
  1150.         if (STR_VAR != vs->value.str) {
  1151.             if (STR_VAR != NULL) freeobj(STR_VAR);
  1152.             STR_VAR = vs->value.str;
  1153.         }
  1154.         break;
  1155.  
  1156.          case 1:    /* it fitted before, so it will fit againg */
  1157.         strcpy(CBUF_VAR, vs->value.str);
  1158.         freeobj(vs->value.str);
  1159.         break;
  1160.         }
  1161.         break;
  1162.  
  1163.      case V_BOOLEAN:
  1164.         BOOL_VAR = vs->value.bool;
  1165.         break;
  1166.  
  1167.      case V_INTEGER:
  1168.         INT_VAR = vs->value.ivar;
  1169.         break;
  1170.  
  1171.      case V_KEY:
  1172.         KEY_VAR = vs->value.key;
  1173.         break;
  1174.  
  1175.      case V_SPECIAL:    /* these are not saved, so... */
  1176.         break;
  1177.  
  1178.      case V_CODES:
  1179.         break;
  1180.     }
  1181.  
  1182.     vs1 = vs->next;
  1183.     vs->next = vs_pool;
  1184.     vs_pool = vs;
  1185.     vs = vs1;
  1186.     }
  1187.     var_stack = NULL;
  1188. }
  1189.  
  1190. static int
  1191. var_on_stack(var)
  1192. register struct variable_defs *var;
  1193. {
  1194.     register struct var_stack *vs;
  1195.  
  1196.     for (vs = var_stack; vs; vs = vs->next)
  1197.     if (vs->v == var) return 1;
  1198.     return 0;
  1199. }
  1200.  
  1201. void
  1202. disp_variables(all, rexp)
  1203. int all;
  1204. char *rexp;
  1205. {
  1206.     char *str, pushed;
  1207.     register struct variable_defs *var;
  1208.  
  1209.     if (in_init) return;
  1210.  
  1211.     clrdisp();
  1212.     if (novice && !all && rexp == NULL) {
  1213.     msg("Use `:set all' to see all variable settings");
  1214.     home();
  1215.     }
  1216.  
  1217.     so_printxy(0, 0, "Variable settings");
  1218.     pg_init(1, 1);
  1219.     if (rexp) {
  1220.     pg_regexp = regcomp(rexp + 1);
  1221.     all = 1;
  1222.     }
  1223.  
  1224.     for (var = variables; var < &variables[TABLE_SIZE]; var++) {
  1225.     if (pg_regexp != NULL && regexec(pg_regexp, var->var_name) == 0)
  1226.         continue;
  1227.     str = var_value(var, &pushed);
  1228.     if (!all && pushed == ' ') continue;
  1229.     if (pg_next() < 0) break;
  1230.     if (pg_new_regexp) {
  1231.         pg_new_regexp = 0;
  1232.         var = variables;
  1233.         var--;
  1234.         continue;
  1235.     }
  1236.     if (VAR_TYPE == V_STRING)
  1237.         tprintf("%c %-25.25s = \"%s\"\n", pushed, var->var_name, str);
  1238.     else
  1239.         tprintf("%c %-25.25s = %s\n", pushed, var->var_name, str);
  1240.     }
  1241.  
  1242.     pg_end();
  1243. }
  1244.  
  1245. void
  1246. print_variable_config(f, all)
  1247. FILE *f;
  1248. int all;
  1249. {
  1250.     register struct variable_defs *var;
  1251.     char *str, tag[2];
  1252.     
  1253.     tag[1] = NUL;
  1254.     for (var = variables; var < &variables[TABLE_SIZE]; var++) {
  1255.     if (!all && (var->var_flags & V_MODIFIED) == 0) continue;
  1256.     str = var_value(var, tag);
  1257.     fprintf(f, "%s%s='%s'\n", all ? tag : "", var->var_name, str);
  1258.     }
  1259. }
  1260.  
  1261. /*
  1262.  *    var_options(string_var *, options, result *)
  1263.  *
  1264.  *    test whether "string_var" contains any of the options
  1265.  *    listed in "options" (NUL-separated list of names ended with 
  1266.  *    double NUL).  On return, string_var is advanced over all
  1267.  *    recognized options and the result will have the bits corresponding
  1268.  *    to the recognized options set.
  1269.  */
  1270.  
  1271. void
  1272. var_options(str, options, res)
  1273. char **str;
  1274. register char *options;
  1275. flag_type *res;
  1276. {
  1277.     char word[128];
  1278.     char *optab[32];
  1279.     register char **op, *wp, c;
  1280.     register int n;
  1281.     
  1282.     for (op = optab; *options != NUL; op++, options++) {
  1283.     *op = options;
  1284.     while (*options) options++;
  1285.     }
  1286.     *op = NULL;
  1287.     
  1288.     *res = 0;
  1289.  
  1290.     options = *str;
  1291.     while (*options) {
  1292.     for (wp = word; (c = *options) != NUL; *wp++ = c, options++)
  1293.         if (isascii(c) && isspace(c)) break;
  1294.     while ((c = *options) && isascii(c) && isspace(c)) options++;
  1295.     *wp = NUL;
  1296.  
  1297.     for (op = optab, n = 1; *op != NULL; op++, n++) {
  1298.         if (strcmp(word, *op)) continue;
  1299.         *res |= FLAG(n);
  1300.         *str = options;
  1301.         break;
  1302.     }
  1303.     if (*op == NULL) break;
  1304.     }
  1305. }
  1306.