home *** CD-ROM | disk | FTP | other *** search
/ ftp.freefriends.org / ftp.freefriends.org.tar / ftp.freefriends.org / arnold / Source / mush.rstevens.tar.gz / mush.tar / setopts.c < prev    next >
C/C++ Source or Header  |  1992-10-30  |  23KB  |  886 lines

  1. /* setopts.c    (c) copyright 1986 (Dan Heller) */
  2.  
  3. #include "mush.h"
  4. #include "bindings.h"
  5.  
  6. static void
  7. insert_option(list, opt, order)
  8. struct options **list, *opt;
  9. int order;    /* Insert in sorted order? */
  10. {
  11.     while (*list && (!order || (strcmp((*list)->option, opt->option) < 1)))
  12.     list = &((*list)->next);
  13.     opt->next = *list;
  14.     *list = opt;
  15. }
  16.  
  17. /* add an option indicated by "set option[=value]" or by "alias name alias"
  18.  * function is recursive, so multilists get appended accordingly
  19.  */
  20. add_option(list, argv)
  21. register struct options **list;
  22. register char **argv;
  23. {
  24.     register struct options *tmp;
  25.     register char *option, *value = NULL;
  26.  
  27.     if (!(option = *argv))
  28.     return 1;
  29.     /* check for one of three forms:
  30.      * option=value  option= value  option = value
  31.      */
  32.     if (value = index(option, '=')) {
  33.     if (value == option) {
  34.         print("No variable specified\n");
  35.         return 0;
  36.     }
  37.     /* "option=value" strip into option="option" value="value" */
  38.     *value++ = 0; /* option is now a null terminated `option' */
  39.     if (*value || (value = *++argv)) { /* "option= value" */
  40.         ++argv;
  41.     }
  42.     } else if (*++argv && !strcmp(*argv, "=")) {
  43.     if (value = *++argv) /* "option = value" */
  44.         ++argv;
  45.     }
  46.  
  47.     /* check for internal vars that can't be set this way */
  48.     if (*list == set_options && check_internal(option)) {
  49.     print("You can't change %s with \"set\".\n", option);
  50.     return 0;
  51.     }
  52.  
  53.     /* check to see if option is already set by attempting to unset it */
  54.     if (un_set(list, option) == -1)
  55.     return 0;
  56.  
  57.     /* now make a new option struct and set fields */
  58.     if (!(tmp = (struct options *)calloc((unsigned)1,sizeof(struct options)))) {
  59.     error("calloc");
  60.     return -1;
  61.     }
  62.     tmp->option = savestr(option);
  63.     tmp->value = savestr(value); /* strdup handles the NULL case */
  64.  
  65.     insert_option(list, tmp, (list != &own_hdrs));
  66.  
  67.     /* check for options which must have values or are used frequently */
  68.     if (*list == set_options) {
  69. #if defined(CURSES) || defined(SUNTOOL)
  70.     if (!strcmp(tmp->option, "no_reverse"))
  71.         turnoff(glob_flags, REV_VIDEO);
  72.     else
  73. #endif /* CURSES || SUNTOOL */
  74. #ifdef SUNTOOL
  75.     if (!strcmp(tmp->option, "tool_help"))
  76.         if (tmp->value && *(tmp->value))
  77.         strdup(tool_help, tmp->value);
  78.         else {
  79.         int n = 0;
  80.         char *p = getpath(TOOL_HELP, &n);
  81.         if (n)
  82.             strdup(tool_help, "tool_help");
  83.         else
  84.             strdup(tool_help, p);
  85.         strdup(tmp->value, tool_help);
  86.         }
  87.     else
  88. #endif /* SUNTOOL */
  89.     if (!strcmp(tmp->option, "cmd_help"))
  90.         if (tmp->value && *(tmp->value))
  91.         strdup(cmd_help, tmp->value);
  92.         else {
  93.         int n = 0; /* don't ignore no such file or directory */
  94.         char *p = getpath(COMMAND_HELP, &n);
  95.         if (n)
  96.             strdup(cmd_help, "cmd_help");
  97.         else
  98.             strdup(cmd_help, p);
  99.         strdup(tmp->value, cmd_help);
  100.         }
  101.     else if (!strcmp(tmp->option, "prompt"))
  102.         prompt = (tmp->value)? tmp->value : DEF_PROMPT;
  103.     else if (!strcmp(tmp->option, "warning"))
  104.         turnon(glob_flags, WARNING);
  105.     else if (!strcmp(tmp->option, "mil_time"))
  106.         turnon(glob_flags, MIL_TIME);
  107. #ifndef MSG_SEPARATOR
  108.     else if (!strcmp(tmp->option, "date_received"))
  109.         turnon(glob_flags, DATE_RECV);
  110. #endif /* MSG_SEPARATOR */
  111.     else if (!strcmp(tmp->option, "escape")) {
  112.         escape = (tmp->value)? tmp->value : DEF_ESCAPE;
  113.         escape[1] = 0; /* only one character, please */
  114.     } else if (!strcmp(tmp->option, "hdr_format"))
  115.         hdr_format = (tmp->value)? tmp->value : DEF_HDR_FMT;
  116.     else if (!strcmp(tmp->option, "crt")) {
  117.         if (!istool)
  118.         crt = (tmp->value)? max(atoi(tmp->value), 2): 18;
  119.     }
  120.     else if (!strcmp(tmp->option, "screen")) {
  121.         screen = (tmp->value)? max(atoi(tmp->value), 1): 18;
  122. #ifdef CURSES
  123.         if (iscurses && screen > LINES-2)
  124.         screen = LINES-2;
  125. #endif /* CURSES */
  126.     } else if (!strcmp(tmp->option, "wrapcolumn")) {
  127.         char wval[16];
  128.         wrapcolumn =
  129.         (tmp->value && *(tmp->value))? max(atoi(tmp->value), 0): 78;
  130. #ifdef CURSES
  131.         /* Use COLS-2 because of silly terminals like vt100 */
  132.         if (iscurses && wrapcolumn > COLS - 2)
  133.         wrapcolumn = COLS - 2;
  134. #endif /* CURSES */
  135.         xfree(tmp->value);
  136.         tmp->value = savestr(sprintf(wval, "%d", wrapcolumn));
  137.     } else if (!strcmp(tmp->option, "history"))
  138.         init_history((value && *value)? atoi(value) : 1);
  139.     else if (!strcmp(tmp->option, "realname")) {
  140.         char *new[4];
  141.         new[1] = "NAME";
  142.         new[2] = tmp->value;
  143.         new[3] = NULL;
  144.         (void) Setenv(3, new); /* new[0] is ignored */
  145.     } else if (!strcmp(tmp->option, "known_hosts")) {
  146.         register char *p;
  147.         int n;
  148.         /* in case user separated with commas */
  149.         for (p = index(tmp->value, ','); p; p = index(p+1, ','))
  150.         *p = ' ';
  151.         free_vec(known_hosts);
  152.         known_hosts = mk_argv(tmp->value, &n, FALSE);
  153.     } else if (!strcmp(tmp->option, "hostname")) {
  154.         register char *p;
  155.         int n;
  156.         /* in case user separated with commas */
  157.         for (p = index(tmp->value, ','); p; p = index(p+1, ','))
  158.         *p = ' ';
  159.         free_vec(ourname);
  160.         ourname = mk_argv(tmp->value, &n, FALSE);
  161.     } else if (!strcmp(tmp->option, "complete")) {
  162.         if (value && *value) {
  163.         m_xlate(value); /* use the original, don't change tmp->value */
  164.         complete = value[0];
  165.         complist = value[1];
  166.         } else {
  167.         tmp->value = savestr("\\E\\CD");
  168.         complete = '\033';
  169.         complist = '\004';
  170.         }
  171.     }
  172.     }
  173.  
  174.     if (*argv)
  175.     return add_option(list, argv);
  176.     return 1;
  177. }
  178.  
  179. /*
  180.  * If str is NULL, just print options and their values. Note that numerical
  181.  * values are not converted to int upon return.  If str is not NULL
  182.  * return the string that matched, else return NULL;
  183.  */
  184. char *
  185. do_set(list, str)
  186. register struct options *list;
  187. register char *str;
  188. {
  189.     register struct options *opts;
  190.  
  191.     if (!str)
  192.     (void) do_pager(NULL, TRUE); /* page using internal pager */
  193.  
  194.     for (opts = list; opts; opts = opts->next)
  195.     if (!str) {
  196.         (void) do_pager(opts->option, FALSE);
  197.         if (opts->value && *opts->value) {
  198.         (void) do_pager("     \t", FALSE);
  199.         (void) do_pager(opts->value, FALSE);
  200.         }
  201.         if (do_pager("\n", FALSE) == EOF)
  202.         break;
  203.     } else {
  204.         if (strcmp(str, opts->option))
  205.         continue;
  206.         if (opts->value)
  207.         return opts->value;
  208.         else
  209.         return "";
  210.     }
  211.  
  212.     if (!str)
  213.     (void) do_pager(NULL, FALSE); /* terminate internal pager */
  214.  
  215.     /* if we still haven't matched, check for environment vars */
  216.     if (str && list == set_options) {
  217.     register int N, n;
  218.     for (N = 0; environ[N]; N++) {
  219.         char *p = index(environ[N], '=');
  220.         if (p)
  221.         *p = 0;
  222.         n = lcase_strncmp(str, environ[N], -1);
  223.         if (p)
  224.         *p = '=';
  225.         if (!n)
  226.         return p+1;
  227.     }
  228.     }
  229.     return NULL;
  230. }
  231.  
  232. /*
  233.  * unset the variable described by p in the list "list".
  234.  * if the variable isn't set, then return 0, else return 1.
  235.  */
  236. un_set(list, p)
  237. register struct options **list;
  238. register char *p;
  239. {
  240.     register struct options *opts = *list, *tmp;
  241.  
  242.     if (!list || !*list || !p || !*p)
  243.     return 0;
  244.     if (*list == set_options) {
  245. #if defined(CURSES) || defined(SUNTOOL)
  246.     if (!strcmp(p, "no_reverse"))
  247.         turnon(glob_flags, REV_VIDEO);
  248.     else
  249. #endif /* CURSES || SUNTOOL */
  250.     if (!strcmp(p, "prompt"))
  251.         prompt = DEF_PROMPT;
  252.     else if (!strcmp(p, "warning"))
  253.         turnoff(glob_flags, WARNING);
  254.     else if (!strcmp(p, "mil_time"))
  255.         turnoff(glob_flags, MIL_TIME);
  256. #ifndef MSG_SEPARATOR
  257.     else if (!strcmp(p, "date_received"))
  258.         turnoff(glob_flags, DATE_RECV);
  259. #endif /* MSG_SEPARATOR */
  260.     else if (!strcmp(p, "escape"))
  261.         escape = DEF_ESCAPE;
  262.     else if (!strcmp(p, "hdr_format"))
  263.         hdr_format = DEF_HDR_FMT;
  264.     else if (!strcmp(p, "crt"))
  265.         crt = 18;
  266.     else if (!strcmp(p, "screen")) {
  267.         screen = 18;
  268. #ifdef CURSES
  269.         if (iscurses && screen > LINES-2)
  270.         screen = LINES-2;
  271. #endif /* CURSES */
  272.     } else
  273. #ifdef SUNTOOL
  274.     if (!strcmp(p, "tool_help")) {
  275.         int n = 0;
  276.         char *p2 = getpath(TOOL_HELP, &n);
  277.         if (n)
  278.         strdup(tool_help, "tool_help");
  279.         else
  280.         strdup(tool_help, p2);
  281.     } else
  282. #endif /* SUNTOOL */
  283.     if (!strcmp(p, "cmd_help")) {
  284.         int n = 0; /* don't ignore no such file or directory */
  285.         char *p2 = getpath(COMMAND_HELP, &n);
  286.         if (n)
  287.         strdup(cmd_help, "cmd_help");
  288.         else
  289.         strdup(cmd_help, p2);
  290.     } else if (!strcmp(p, "wrapcolumn"))
  291.         wrapcolumn = 0;
  292.     else if (!strcmp(p, "history"))
  293.         init_history(1);
  294.     else if (!strcmp(p, "known_hosts")) {
  295.         free_vec(known_hosts);
  296.         known_hosts = DUBL_NULL;
  297.     } else if (!strcmp(p, "hostname")) {
  298.         free_vec(ourname);
  299.         ourname = DUBL_NULL;
  300.     } else if (ison(glob_flags, IS_GETTING) && !strcmp(p, "edit_hdrs")) {
  301.         wprint("You must finish this letter first.\n");
  302.         return -1;
  303.     } else if (!strcmp(p, "complete"))
  304.         complete = complist = 0;
  305. #ifdef SUNTOOL
  306.     else if (!strcmp(p, "compose_icon")) {
  307.         if (ison(glob_flags, IS_GETTING)) {
  308.         wprint("You must finish this letter first.\n");
  309.         return -1;
  310.         } else
  311.         /* destroy compose frame so that it is recreated
  312.          * later as the proper type (base frame or subframe).
  313.          */
  314.         if (compose_frame)
  315.             destroy_compose();
  316.     }
  317. #endif
  318.     }
  319.  
  320.     if (!strcmp(p, opts->option)) {
  321.     *list = (*list)->next;
  322.     xfree (opts->option);
  323.     if (opts->value)
  324.         xfree(opts->value);
  325.     xfree((char *)opts);
  326.     return 1;
  327.     }
  328.     for ( ; opts->next; opts = opts->next)
  329.     if (!strcmp(p, opts->next->option)) {
  330.         tmp = opts->next;
  331.         opts->next = opts->next->next;
  332.         xfree (tmp->option);
  333.         if (tmp->value)
  334.         xfree(tmp->value);
  335.         xfree ((char *)tmp);
  336.         return 1;
  337.     }
  338.     return 0;
  339. }
  340.  
  341. /* The functions below return 0 since they don't affect
  342.  * messages.
  343.  */
  344. set(n, argv, list)
  345. register int n;
  346. register char **argv;
  347. char *list;
  348. {
  349.     void list_to_str();
  350.     char firstchar = **argv;
  351.     register char *cmd = *argv;
  352.     register struct options **optlist;
  353.     char buf[BUFSIZ];
  354.  
  355.     if (*cmd == 'u')
  356.     cmd += 2;
  357.     if (*++argv && !strcmp(*argv, "-?"))
  358.     return help(0, (*cmd == 'i')? "ignore": "set", cmd_help);
  359.  
  360.     if (*argv && **argv == '?') {
  361.     int incurses;
  362.     if (!strcmp(*argv, "?all")) {
  363.         if (incurses = iscurses) /* assign and compare to TRUE */
  364.         clr_bot_line(), iscurses = FALSE;
  365.         (void) do_pager(NULL, TRUE); /* start internal pager */
  366.         for (n = 0; variable_stuff(n, NULL, buf); n++)
  367.         if (do_pager(strcat(buf, "\n"), FALSE) == EOF)
  368.             break;
  369.         (void) do_pager(NULL, FALSE); /* terminate pager */
  370.         iscurses = incurses;
  371.     } else {
  372.         /* May return null if variable not set. */
  373.         (void) variable_stuff(0, (*argv)+1, buf);
  374.         print("%s\n", buf);
  375.     }
  376.     return 0;
  377.     }
  378.  
  379.     if (firstchar == 'u') {
  380.     if (!*argv) {
  381.         print("%s what?\n", cmd);
  382.         return -1;
  383.     } else {
  384.         optlist = (*cmd == 'i')? &ignore_hdr : &set_options;
  385.         do  if (!strcmp(*argv, "*")) {
  386.             while (*optlist)
  387.             (void) un_set(optlist, (*optlist)->option);
  388. #ifdef SUNTOOL
  389.             if (*cmd != 'i')
  390.             opts_panel_item(NULL);
  391. #endif /* SUNTOOL */
  392.         } else if (!un_set(optlist, *argv) &&
  393.             do_set(set_options, "warning"))
  394.             print("un%s: %s not set\n",
  395.             (*cmd == 'i')? "ignore" : "set", *argv);
  396. #ifdef SUNTOOL
  397.         else if (*cmd != 'i')
  398.             opts_panel_item(*argv);
  399. #endif /* SUNTOOL */
  400.         while (*++argv);
  401. #ifdef SUNTOOL
  402.         if (*cmd == 'i' && istool > 1)
  403.         update_list_textsw(&ignore_hdr);
  404. #endif /* SUNTOOL */
  405.     }
  406.     return 0;
  407.     }
  408.  
  409.     if (!*argv) {
  410.     (void) do_set((*cmd == 'i')? ignore_hdr: set_options, NULL);
  411.     return 0;
  412.     }
  413.  
  414.     /*
  415.      * Check for input redirection.  If so, set the variable to the ascii
  416.      * value of the current msg_list.
  417.      */
  418.     if (ison(glob_flags, IS_PIPE)) {
  419.     char *newargv[4];
  420.  
  421.     if (*cmd == 'i') {
  422.         print("You can't pipe to the \"%s\" command.\n", cmd);
  423.         return -1;
  424.     }
  425.     if (newargv[0] = index(argv[0], '='))
  426.         *newargv[0] = 0;
  427.     list_to_str(list, buf);
  428.     if (!buf[0] && !do_set(set_options, argv[0])) {
  429.         return 0;
  430.     }
  431.     newargv[0] = argv[0];
  432.     newargv[1] = "=";
  433.     newargv[2] = buf;
  434.     newargv[3] = NULL;
  435.     (void) add_option(&set_options, newargv);
  436.     return 0;
  437.     }
  438.  
  439.     /*
  440.      * finally, just set the variable the user requested.
  441.      */
  442.     (void) add_option((*cmd == 'i')? &ignore_hdr: &set_options, argv);
  443. #ifdef SUNTOOL
  444.     if (istool > 1)
  445.     if (*cmd == 'i')
  446.         update_list_textsw(&ignore_hdr);
  447.     else
  448.         opts_panel_item(argv[0]);
  449. #endif /* SUNTOOL */
  450.     return 0;
  451. }
  452.  
  453. /*
  454.  *   The alts list is a list of hostnames or pathnames where the user
  455.  * has an account.  If he doesn't specify "metoo", then when replying
  456.  * to mail, if his address is listed, it will be removed.  The syntax
  457.  * is compatible with ucb Mail in that just hostnames can be used.
  458.  * However, there is an added feature that mush provides which another
  459.  * login name or path to another login can be specified by preceding the
  460.  * path or login with a !
  461.  * "argv" may be a file pointer to write the data into by use of save_opts()
  462.  */
  463. alts(argc, argv)
  464. register char **argv;
  465. {
  466.     char buf[BUFSIZ], *p;
  467.  
  468.     /* check here first because a 0 argc means to write it to a file */
  469.     if (argc <= 1) {
  470.     int n;
  471.     if (!alternates)
  472.         return 0;
  473.     if (argc == 0)
  474.         (void) fprintf((FILE *)argv, "alts ");
  475.     for (n = 0; alternates[n]; n++) {
  476.         p = 0;
  477.         buf[0] = 0;
  478.         (void) strcpy(&buf[1], alternates[n]);
  479.         if (buf[1] != '*')
  480.         (void) reverse(&buf[1]);
  481.         if ((p = rindex(&buf[1], '!')) && !lcase_strncmp(p+1, login, -1))
  482.         *p = 0;
  483.         else if (buf[1] != '*')
  484.         buf[0] = '!';
  485.         if (argc == 0)
  486.         (void) fprintf((FILE *)argv, "%s ", *buf? buf : &buf[1]);
  487.         else
  488.         wprint("%s ", *buf? buf : &buf[1]);
  489.         if (p)
  490.         *p = '!';
  491.     }
  492.     if (argc == 0)
  493.         (void) fputc('\n', (FILE *)argv);
  494.     else
  495.         wprint("\n");
  496.     return 0;
  497.     }
  498.  
  499.     if (argc-- && *++argv && !strcmp(*argv, "-?"))
  500.     return help(0, "alts", cmd_help);
  501.  
  502.     free_vec(alternates);
  503.     if (alternates = (char **)calloc((unsigned)argc+1, sizeof(char *)))
  504.     while (argc-- > 0) {
  505.         if (argv[argc][0] == '!')
  506.         alternates[argc] = savestr(reverse(&argv[argc][1]));
  507.         else if (argv[argc][0] == '*') {
  508.         alternates[argc] = savestr(argv[argc]);
  509.         } else {
  510.         if (index(argv[argc], '@'))
  511.             bang_form(buf, argv[argc]);
  512.         else {
  513.             p = buf + Strcpy(buf, argv[argc]);
  514.             *p++ = '!', p += Strcpy(p, login);
  515.         }
  516.         alternates[argc] = savestr(reverse(buf));
  517.         }
  518.     }
  519.     return 0;
  520. }
  521.  
  522. save_opts(cnt, argv)
  523. char **argv;
  524. {
  525.     char file[MAXPATHLEN], *tmp;
  526.     register FILE *fp;
  527.  
  528.     if (cnt && *++argv && !strcmp(*argv, "-?"))
  529.     return help(0, "source", cmd_help);
  530.     if (cnt && *argv)
  531.     (void) strcpy(file, *argv);
  532.     else if ((tmp = getenv("MUSHRC")) || (tmp = getenv("MAILRC")))
  533.     (void) strcpy(file, tmp);
  534.     else {
  535.     char *home = do_set(set_options, "home");
  536.     if (!home || !*home)
  537.         home = ALTERNATE_HOME;
  538.     /* if .mushrc doesn't exist, check .mailrc. If neither, force .mushrc */
  539.     if (Access(sprintf(file, "%s/%s", home, MAILRC), F_OK) &&
  540.         Access(sprintf(file, "%s/%s", home, ALTERNATE_RC), F_OK))
  541.         (void) sprintf(file, "%s/%s", home, MAILRC);
  542.     }
  543.  
  544.     cnt = 1;
  545.     tmp = getpath(file, &cnt);
  546.     if (cnt) {
  547.     if (cnt == -1) {
  548.         print("%s: %s\n", file, tmp);
  549.         return -1;
  550.     } else {
  551.         print("%s is a directory.\n", tmp);
  552.         return -2;
  553.     }
  554.     }
  555.     /* See if the file exists and confirm overwrite */
  556.     if (!Access(tmp, F_OK)) {
  557.     int overwrite = TRUE;
  558.     char buf[BUFSIZ];
  559.     if (!istool) {
  560.         print("\"%s\" exists. Overwrite? ", trim_filename(tmp));
  561.         if (Getstr(buf, 3, 0) <= 0 || lower(*buf) != 'y')
  562.         overwrite = FALSE;
  563.     }
  564. #ifdef SUNTOOL
  565.     else {
  566.         sprintf(buf, "\"%s\" exists. Overwrite? ", trim_filename(tmp));
  567.         overwrite = ask(buf);
  568.     }
  569. #endif /* SUNTOOL */
  570.     if (!overwrite) {
  571.         print("\"%s\" unchanged.\n", tmp);
  572.         return -3;
  573.     }
  574.     }
  575.     if (!(fp = fopen(tmp, "w"))) {
  576.     error("Can't open %s", file);
  577.     return -1;
  578.     }
  579.  
  580.     save_list("basic variable settings", set_options, "set", '=', fp);
  581.  
  582.     save_list("mail headers for outgoing mail", own_hdrs, "my_hdr", 0, fp);
  583.  
  584.     save_list("aliases", aliases, "alias", 0, fp);
  585.  
  586.     (void) alts(0, (char **)fp);
  587.  
  588.     save_list("headers to ignore", ignore_hdr, "ignore", ' ', fp);
  589.  
  590.     save_list("command abbreviations", functions, "cmd", ' ', fp);
  591.  
  592.     save_list("command macros for function keys", fkeys, "fkey", ' ', fp);
  593.  
  594. #ifdef CURSES
  595.     save_cmd("curses mode key bindings", cmd_map, "bind", 1, fp);
  596. #endif /* CURSES */
  597.  
  598.     save_cmd("line mode mappings", line_map, "map", 0, fp);
  599.  
  600.     save_cmd("composition mode mappings", bang_map, "map!", 0, fp);
  601.  
  602.     (void) fclose(fp);
  603.     print("All variables and options saved in %s\n", trim_filename(tmp));
  604.     return 0;
  605. }
  606.  
  607. char *
  608. quoteit(str, in_quotes, fix_vars)
  609. char *str;
  610. int in_quotes;    /* Type of quote the string is in, if any */
  611. int fix_vars;    /* Variables will be expanded, so quote $ */
  612. {
  613. #define other_quote(x) ((x == '"')? '\'' : '"')
  614.     static char *buf;
  615.     static int bufsiz;
  616.     char *s = str, *d;
  617.     int len = str? strlen(str) : 0, was_magic = FALSE;
  618.  
  619.     if (!len)
  620.     return str;
  621.     if (bufsiz < 2 * len) {
  622.     xfree(buf);
  623.     buf = malloc(bufsiz = 2 * len);
  624.     }
  625.     if (!buf)
  626.     return NULL;
  627.     for (d = buf; *d = *s; d++, s++) {
  628.     if ((*s == '\'' || *s == '"') &&
  629.         (was_magic || in_quotes != other_quote(*s))) {
  630.         if (was_magic) {
  631.         if (*s == '\'')
  632.             continue;
  633.         /* else '"' */
  634.         ++d;
  635.         was_magic = FALSE;
  636.         }
  637.         if (in_quotes == *s)
  638.         *d++ = *s;
  639.         *d = other_quote(*s);
  640.         *++d = *s;
  641.         *++d = other_quote(*s);
  642.         if (in_quotes == *s)
  643.         *++d = *s;
  644.     } else if (*s == '$' && fix_vars && (was_magic || in_quotes != '\'')) {
  645.        if (was_magic || in_quotes == '"') {
  646.         *d++ = '"';
  647.         was_magic = FALSE;
  648.         }
  649.         *d = '\'';
  650.         *++d = *s;
  651.         *++d = '\'';
  652.         if (in_quotes == '"')
  653.         *++d = in_quotes;
  654.     } else if (fix_vars && isspace(*s)) {
  655.         /* backslash-newline may get stripped when fix_vars */
  656.         if (*s == '\n' || *s == '\r') {
  657.         *d = '\\';
  658.         *++d = *s;
  659.         *++d = ' ';    /* XXX not perfect, but ... */
  660.         } else if (!was_magic && !in_quotes) {
  661.         *d = '"';
  662.         *++d = *s;
  663.         was_magic = TRUE;
  664.         }
  665.     } else if (!in_quotes && index("#;|~", *s)) {
  666.         if (*s == '~' && !fix_vars) {
  667.         /* !fix_vars implies !fix_tildes */
  668.         if (was_magic) {
  669.             *d = '"';
  670.             *++d = *s;
  671.             was_magic = FALSE;
  672.         }
  673.         } else if (!was_magic && (s == str || *s != '~')) {
  674.         *d = '"';
  675.         *++d = *s;
  676.         was_magic = TRUE;
  677.         }
  678.     }
  679.     }
  680.     if (was_magic) {
  681.     *d = '"';
  682.     *++d = '\0';
  683.     }
  684.     return buf;
  685. #undef other_quote
  686. }
  687.  
  688. save_list(title, list, command, equals, fp)
  689. struct options *list;
  690. register char *command, *title, equals;
  691. register FILE *fp;
  692. {
  693.     register struct options *opts;
  694.     register char *p;
  695.  
  696.     if (!list)
  697.     return;
  698.     (void) fprintf(fp, "#\n# %s\n#\n", title);
  699.     for (opts = list; opts; opts = opts->next) {
  700.     if (list == set_options && !strcmp(opts->option, "cwd"))
  701.         continue; /* don't print $cwd */
  702.     (void) fprintf(fp, "%s %s", command, opts->option);
  703.     if (opts->value && *opts->value) {
  704.         register char *quote;
  705.         if (!equals)
  706.         quote = NO_STRING;
  707.         else if (p = any(opts->value, "\"'"))
  708.         if (*p == '\'')
  709.             quote = "\"";
  710.         else
  711.             quote = "'";
  712.         else
  713.         if (!any(opts->value, " \t;|"))
  714.             quote = NO_STRING;
  715.         else
  716.             quote = "'";
  717.         (void) fputc(equals? equals: ' ', fp);
  718.         (void) fprintf(fp, "%s%s%s",
  719.                 quote,
  720.                 quoteit(opts->value, quote, TRUE),
  721.                 quote);
  722.     }
  723.     (void) fputc('\n', fp);
  724.     }
  725. }
  726.  
  727. extern struct cmd_map map_func_names[];
  728.  
  729. save_cmd(title, list, command, equals, fp)
  730. struct cmd_map *list;
  731. register char *command, *title;
  732. register int equals;
  733. register FILE *fp;
  734. {
  735.     register struct cmd_map *opts;
  736.     register char *p;
  737.     char buf[MAX_MACRO_LEN * 2];
  738.  
  739.     if (!list)
  740.     return;
  741.     (void) fprintf(fp, "#\n# %s\n#\n", title);
  742.     for (opts = list; opts; opts = opts->m_next) {
  743.     register char *quote;
  744.     if ((p = any(opts->m_str, "\"'")) && *p == '\'')
  745.         quote = "\"";
  746.     else
  747.         quote = "'";
  748.     (void) fprintf(fp, "%s %s%s%s", command,
  749.             quote,
  750.             quoteit(ctrl_strcpy(buf, opts->m_str, TRUE), quote, TRUE),
  751.             quote);
  752.     if (equals && map_func_names[opts->m_cmd].m_str)
  753.         (void) fprintf(fp, " %s", map_func_names[opts->m_cmd].m_str);
  754.     if (opts->x_str && *opts->x_str) {
  755.         if ((p = any(opts->x_str, "\"'")) && *p == '\'')
  756.         quote = "\"";
  757.         else
  758.         quote = "'";
  759.         (void) fprintf(fp, " %s%s%s",
  760.             quote,
  761.             quoteit(ctrl_strcpy(buf, opts->x_str, TRUE), quote, TRUE),
  762.             quote);
  763.     }
  764.     (void) fputc('\n', fp);
  765.     }
  766. }
  767.  
  768. /*
  769.  * do_alias handles aliases, header settings, functions, and fkeys.
  770.  * since they're all handled in the same manner, the same routine is
  771.  * used. argv[0] determines which to use.
  772.  * alias is given here as an example
  773.  *
  774.  * alias           identify all aliases
  775.  * alias name      identify alias
  776.  * alias name arg1 arg2 arg3... -> name="arg1 arg2 arg3"; call add_option
  777.  * unalias arg1 [arg2 arg3 ... ]        unalias args
  778.  *
  779.  * same is true for dealing with your own headers.
  780.  * (also the expand command)
  781.  */
  782. do_alias(argc, argv)
  783. register char **argv;
  784. {
  785.     register char *cmd = *argv, *p;
  786.     struct options **list;
  787.     char firstchar = *cmd, buf[HDRSIZ];
  788.  
  789.     if (argc == 0)
  790.     return 0 - in_pipe();
  791.     if (firstchar == 'u')
  792.     firstchar = cmd[2];
  793.     if (*++argv && !strcmp(*argv, "-?")) { /* doesn't apply for fkeys */
  794.     register char *help_str;
  795.     if (firstchar == 'a' || firstchar == 'e')
  796.         help_str = "alias";
  797.     else if (firstchar == 'c')
  798.         help_str = "cmd";
  799.     else if (firstchar == 'f')
  800.         help_str = "fkey";
  801.     else
  802.         help_str = "my_hdr";
  803.     return help(0, help_str, cmd_help);
  804.     }
  805.  
  806.     if (firstchar == 'a')
  807.     list = &aliases;
  808.     else if (firstchar == 'c')
  809.     list = &functions;
  810.     else if (firstchar == 'f')
  811.     list = &fkeys;
  812.     else
  813.     list = &own_hdrs;
  814.  
  815.     if (*cmd == 'u') {
  816.     if (!*argv) {
  817.         print("%s what?\n", cmd);
  818.         return -1;
  819.     /* unset a list separated by spaces or ',' */
  820.     } else while (*argv) {
  821.         if (!strcmp(*argv, "*")) /* unset everything */
  822.         while (*list)
  823.             (void) un_set(list, (*list)->option);
  824.         else if (!un_set(list, *argv))
  825.         print("\"%s\" isn't set\n", *argv);
  826.         argv++;
  827.     }
  828. #ifdef SUNTOOL
  829.     if (istool > 1)
  830.         update_list_textsw(list);
  831. #endif /* SUNTOOL */
  832.     return 0;
  833.     }
  834.  
  835.     if (!*argv && *cmd != 'e') {
  836.     /* just type out all the aliases or own_hdrs */
  837.     (void) do_set(*list, NULL);
  838.     return 0;
  839.     }
  840.  
  841.     if (*cmd == 'e') {   /* command was "expand" (aliases only) */
  842.     if (!*argv) {
  843.         print("expand which alias?\n");
  844.         return -1;
  845.     } else
  846.         do  {
  847.         print("%s: ", *argv);
  848.         if (p = alias_to_address(*argv))
  849.             print("%s\n", p);
  850.         } while (*++argv);
  851.     return 0;
  852.     }
  853.  
  854.     /* at this point, *argv now points to a variable name ...
  855.      * check for hdr -- if so, *argv better end with a ':' (check *p)
  856.      */
  857.     if (list == &own_hdrs && !(p = index(*argv, ':'))) {
  858.     print("header labels must end with a ':' (%s)\n", *argv);
  859.     return -1;
  860.     }
  861.     if (!argv[1] && !index(*argv, '='))
  862.     if (p = do_set(*list, *argv))
  863.         print("%s\n", p);
  864.     else
  865.         print("%s is not set\n", *argv);
  866.     else {
  867.     char *tmpargv[2];
  868.     (void) argv_to_string(buf, argv);
  869.     if ((p = any(buf, " \t=")) && *p != '=')
  870.         *p = '=';
  871.     /* if we're setting an alias, enforce the insertion of commas
  872.      * between each well-formed address.
  873.      */
  874.     if (list == &aliases)
  875.         fix_up_addr(p+1);
  876.     tmpargv[0] = buf;
  877.     tmpargv[1] = NULL;
  878.     (void) add_option(list, tmpargv);
  879. #ifdef SUNTOOL
  880.     if (istool > 1)
  881.         update_list_textsw(list);
  882. #endif /* SUNTOOL */
  883.     }
  884.     return 0;
  885. }
  886.