home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume14 / mush6.0 / part08 / commands.c next >
Encoding:
C/C++ Source or Header  |  1988-04-12  |  20.8 KB  |  783 lines

  1. /* @(#)cmds.c    (c) copyright 10/18/86 (Dan Heller) */
  2.  
  3. #include "mush.h"
  4.  
  5. /*
  6.  * Note that all of the routines in here act upon and return 0 or -1.
  7.  * if -1, then the main loop will clear message lists.
  8.  */
  9.  
  10. struct cmd cmds[] = {
  11. #ifdef SIGSTOP
  12.     { "stop", stop },
  13. #endif /* SIGSTOP */
  14.     { "?",       question_mark },{ "sh", sh },
  15.     { "alias",       do_alias    },  { "unalias",    do_alias   },
  16.     { "expand",      do_alias    },  { "cmd",     do_alias   },
  17.     { "uncmd",       do_alias    },  { "from",    do_from    },
  18.     { "un_hdr",      do_alias    },  { "my_hdr",      do_alias   },
  19.     { "fkey",       do_alias    },  { "unfkey",     do_alias   },
  20.     { "set",       set         },  { "unset",     set        },
  21.     { "ignore",      set         },  { "unignore", set        },
  22.     { "version",  do_version  },  { "help",    print_help },
  23.     { "pick",       do_pick     },  { "sort",     sort        },
  24.     { "next",      readmsg     },  { "previous", readmsg    },
  25.     { "type",     readmsg     },  { "print",    readmsg    },
  26.     { "history",  disp_hist   },  { "top",    readmsg       },
  27.     { "saveopts", save_opts   },  { "source",   source        },
  28.     { "headers",  do_hdrs     },  { "ls",    ls       },
  29.     { "folder",   folder      },  { "update",   folder     },
  30.     { "cd",       cd          },  { "pwd",    cd        },
  31.     { "exit",      quit        },  { "quit",     quit        },
  32.     { "write",       save_msg    },  { "save",     save_msg   },
  33.     { "copy",       save_msg    },  { "folders",  folders    },
  34. #ifdef CURSES
  35.     { "curses",   curses_init },  { "bind", bind_it   }, { "unbind", bind_it },
  36. #endif /* CURSES */
  37.     { "preserve", preserve    },  { "unpreserve",  preserve   },
  38.     { "replyall", respond     },  { "replysender", respond    },
  39.     { "delete",      delete      },  { "undelete",    delete     },
  40.     { "mail",       do_mail     },  { "echo",       do_echo    },
  41.     { "lpr",      lpr          },  { "alternates",  alts       },
  42.     { NULL, quit }
  43. };
  44.  
  45. struct cmd ucb_cmds[] = {
  46.     { "t",   readmsg   }, { "n",  readmsg  }, { "p", readmsg  },
  47.     { "+",   readmsg   }, { "-",  readmsg  }, { "P", readmsg  },
  48.     { "Print", readmsg }, { "T",  readmsg  }, { "Type", readmsg },
  49.     { "x",   quit      }, { "xit", quit    }, { "q",  quit    },
  50.     { ":a",  do_hdrs   }, { ":d", do_hdrs  }, { ":r", do_hdrs },
  51.     { ":o",  do_hdrs   }, { ":u", do_hdrs  }, { ":n", do_hdrs },
  52.     { "z",   do_hdrs   }, { "z-", do_hdrs  }, { "z+", do_hdrs },
  53.     { "h",   do_hdrs   }, { "H",  do_hdrs  },
  54.     { "f",   do_from   }, { "m",  do_mail  }, { "alts", alts  },
  55.     { "d",   delete    }, { "dt", delete   }, { "dp", delete  },
  56.     { "u",   delete    }, { "fo", folder   },
  57.     { "s",   save_msg  }, { "co", save_msg }, { "w", save_msg },
  58.     { "pre", preserve  }, { "unpre", preserve },
  59.     { "R",   respond   }, { "r",   respond },
  60.     { "reply", respond }, { "respond", respond },
  61.     { NULL, quit }
  62. };
  63.  
  64. struct cmd hidden_cmds[] = {
  65.     { "debug", toggle_debug }, { "open",     nopenfiles },
  66.     { "flags", msg_flags    }, { "stty",    my_stty    },
  67.     { "setenv",    Setenv      }, { "unsetenv",     Unsetenv   },
  68.     { "printenv", Printenv  },
  69.     { NULL, quit }
  70. };
  71.  
  72. toggle_debug(argc, argv)
  73. char **argv;
  74. {
  75.     if (argc < 2) /* no value -- toggle "debug" (off/on) */
  76.     debug = !debug;
  77.     else
  78.     debug = atoi(*++argv);
  79.     print("debugging value: %d\n", debug);
  80.     return -1;
  81. }
  82.  
  83. /* if + was specified, then print messages without headers.
  84.  * n or \n (which will be NULL) will print next unread or undeleted message.
  85.  */
  86. readmsg(x, argv, list)
  87. register char **argv, list[];
  88. {
  89.     register char *p = x? *argv : NULL;
  90.     register long flg = 0;
  91.     extern FILE *ed_fp;
  92.  
  93.     if (x && *++argv && !strcmp(*argv, "-?"))
  94.     return help(0, "readmsg", cmd_help);
  95.     /* View a message as long as user isn't in the editor.  If is_getting
  96.      * is set, then the user is typing in a letter (or something else not
  97.      * threatening in tool mode).  If ed_fp is not null, then we've got the
  98.      * file open for typing.  If it's NULL, then an editor is going.
  99.      */
  100.     if (ison(glob_flags, IS_GETTING) && !ed_fp) {
  101.     print("Not while you're in the editor, you don't.\n");
  102.     return -1;
  103.     }
  104.     if (!msg_cnt) {
  105.     print("No messages.\n");
  106.     return -1;
  107.     }
  108.     if (x)
  109.     if (!strcmp(p, "top"))
  110.         turnon(flg, TOP);
  111.     else if (*p == '+') {
  112.         turnon(flg, NO_PAGE);
  113.         turnon(flg, NO_HEADER);
  114.     } else if (isupper(*p))
  115.         turnon(flg, NO_IGNORE);
  116.  
  117.     if (x && (x = get_msg_list(argv, list)) == -1)
  118.     return -1;
  119.     else if (x == 0) {  /* no arguments were parsed (or given) */
  120.     /* get_msg_list sets current msg on */
  121.     unset_msg_bit(list, current_msg);
  122.     /* most commands move to the "next" message. type and print don't */
  123.     if ((!p || !*p || *p == 'n' || *p == '+') && current_msg < msg_cnt &&
  124.                     isoff(msg[current_msg].m_flags, UNREAD))
  125.         current_msg++;
  126.     if (p && (*p == '-' || !strcmp(p, "previous"))) {
  127.         while (--current_msg >= 0 && ison(msg[current_msg].m_flags, DELETE))
  128.         ;
  129.         if (current_msg < 0) {
  130.         print("No previous message.\n");
  131.         current_msg = 0;
  132.         return -1;
  133.         }
  134.     } else {
  135.         /*
  136.          * To be compatible with ucb-mail, find the next available unread
  137.          * message.  If at the end, only wrap around if "wrap" is set.
  138.          */
  139.         if (current_msg == msg_cnt && do_set(set_options, "wrap"))
  140.         current_msg = 0;
  141.         /* "type" or "print" prints the current only -- "next" goes on.. */
  142.         if (!p || !*p || *p == 'n')
  143.         while (current_msg < msg_cnt &&
  144.             ison(msg[current_msg].m_flags, DELETE))
  145.             current_msg++;
  146.         if (current_msg >= msg_cnt) {
  147.         print("No more messages.\n");
  148.         current_msg = msg_cnt - 1;
  149.         return -1;
  150.         }
  151.     }
  152.     set_msg_bit(list, current_msg);
  153.     }
  154.     /* If we're piping messages, just return the message list */
  155.     if (ison(glob_flags, DO_PIPE))
  156.     return 0;
  157.     current_msg = 0;
  158.     for (x = 0; x < msg_cnt; x++)
  159.     if (msg_bit(list, x)) {
  160.         current_msg = x;
  161. #ifdef SUNTOOL
  162.         if (istool > 1) {
  163.         read_mail(NO_ITEM, 0, NO_EVENT);
  164.         return 0;
  165.         }
  166. #endif /* SUNTOOL */
  167.         display_msg(x, flg);
  168.     }
  169.     return 0;
  170. }
  171.  
  172. preserve(n, argv, list)
  173. register int n;        /* no use for argc, so use space for a local variable */
  174. register char **argv, list[];
  175. {
  176.     register int unpre;
  177.  
  178.     unpre = !strncmp(*argv, "un", 2);
  179.     if (*++argv && !strcmp(*argv, "-?"))
  180.     return help(0, "preserve_help", cmd_help);
  181.     if (get_msg_list(argv, list) == -1)
  182.     return -1;
  183.     for (n = 0; n < msg_cnt; n++)
  184.     if (msg_bit(list, n))
  185.         if (unpre) {
  186.         if (ison(msg[n].m_flags, PRESERVE)) {
  187.             turnoff(msg[n].m_flags, PRESERVE);
  188.             turnon(glob_flags, DO_UPDATE);
  189.         }
  190.         } else {
  191.         if (isoff(msg[n].m_flags, PRESERVE) ||
  192.             ison(msg[n].m_flags, DELETE)) {
  193.             turnon(msg[n].m_flags, PRESERVE);
  194.             turnon(glob_flags, DO_UPDATE);
  195.             turnoff(msg[n].m_flags, DELETE);
  196.         }
  197.         }
  198.     if (istool)
  199.     (void) do_hdrs(0, DUBL_NULL, NULL);
  200.     return 0;
  201. }
  202.  
  203. lpr(n, argv, list)
  204. register int n;  /* no use for argc, so use its address space for a variable */
  205. register char **argv, list[];
  206. {
  207.     register FILE    *pp;
  208.     register long     flags = 0;
  209.     char        print_cmd[128], *printer, c, *cmd;
  210.     int            total = 0, (*oldint)(), (*oldquit)();
  211.  
  212.     turnon(flags, NO_IGNORE);
  213.     if (!(printer = do_set(set_options, "printer")) || !*printer)
  214.     printer = DEF_PRINTER;
  215.     while (argv && *++argv && **argv == '-') {
  216.     n = 1;
  217.     while (c = argv[0][n++])
  218.         switch(c) {
  219.         case 'n': turnon(flags, NO_HEADER);
  220.         when 'h': turnoff(flags, NO_IGNORE);
  221.         when 'P': case 'd':
  222.             if (!argv[0][n]) {
  223.                 print("specify printer!\n");
  224.                 return -1;
  225.             }
  226.             printer = argv[0] + n;
  227.             n += strlen(printer);
  228.         otherwise: return help(0, "lpr", cmd_help);
  229.         }
  230.     }
  231.     if (get_msg_list(argv, list) == -1)
  232.     return -1;
  233.  
  234.     if (cmd = do_set(set_options, "print_cmd"))
  235.     (void) strcpy(print_cmd, cmd);
  236.     else
  237. #ifdef SYSV
  238.     (void) sprintf(print_cmd, "%s -d%s", LPR, printer);
  239. #else
  240.     (void) sprintf(print_cmd, "%s -P%s", LPR, printer);
  241. #endif /* SYSV */
  242.     Debug("print command: %s\n", print_cmd);
  243.     if (!(pp = popen(print_cmd, "w"))) {
  244.     error("cannot print");
  245.     return -1;
  246.     }
  247.     on_intr();
  248.     for (n = 0; isoff(glob_flags, WAS_INTR) && n < msg_cnt; n++) {
  249.     if (msg_bit(list, n)) {
  250.         if (total++)
  251.         fputc('\f', pp); /* send a formfeed for multiple copies */
  252.         print("printing message %d...", n+1);
  253.         print_more("(%d lines)\n", copy_msg(n, pp, flags));
  254.     }
  255.     }
  256.     off_intr();
  257.     (void) pclose(pp);
  258.     print_more("%d message%s printed ", total, (total==1)? "": "s");
  259.     if (cmd)
  260.     print_more("through \"%s\".\n", cmd);
  261.     else
  262.     print_more("at \"%s\".\n", printer);
  263.     return 0;
  264. }
  265.  
  266. /* save [msg_list] [file] */
  267. save_msg(n, argv, list)   /* argc isn't used, so use space for variable 'n' */
  268. register char **argv, list[];
  269. {
  270.     register FILE    *mail_fp;
  271.     register char     *file = NULL, *mode, firstchar = **argv, *tmp;
  272.     int         msg_number, force;
  273.     long         flg = 0;
  274.  
  275.     if (*++argv && !strcmp(*argv, "-?"))
  276.     return help(0, "save_help", cmd_help);
  277.     if (force = (*argv && !strcmp(*argv, "!")))
  278.     argv++;
  279.     if ((n = get_msg_list(argv, list)) == -1)
  280.     return -1;
  281.     argv += n;
  282.     if (*argv && *(file = *argv) == '\\')
  283.     file++;
  284.     else if (!file) {
  285.     /* if no filename specified, save in ~/mbox */
  286.     if (firstchar == 'w') {
  287.         /* mbox should have headers. If he really wants it, specify it */
  288.         print("Must specify file name for 'w'\n");
  289.         return -1;
  290.     }
  291.     if (!(file = do_set(set_options, "mbox")) || !*file)
  292.         file = DEF_MBOX;
  293.     }
  294.     n = 1; /* tell getpath to ignore no such file or directory */
  295.     tmp = getpath(file, &n);
  296.     if (n < 0) {
  297.     print("%s: %s\n", file, tmp);
  298.     return -1;
  299.     } else if (n) {
  300.     print("%s is a directory\n", file);
  301.     return -1;
  302.     }
  303.     file = tmp;
  304.     if (force || Access(file, F_OK))
  305.     mode = "w", force = 0;
  306.     else
  307.     mode = "a";
  308.  
  309.     if (!(mail_fp = fopen(file, mode))) {
  310.     error("cannot save in \"%s\"", file);
  311.     return -1;
  312.     }
  313. #ifdef SUNTOOL
  314.     if (istool)
  315.     lock_cursors();
  316. #endif /* SUNTOOL */
  317.     turnon(flg, NO_IGNORE);
  318.     if (firstchar == 'w')
  319.     turnon(flg, NO_HEADER);
  320.     else
  321.     turnon(flg, UPDATE_STATUS);
  322.     if (do_set(set_options, "keepsave"))
  323.     firstchar = 'c';
  324.     for (n = msg_number = 0; msg_number < msg_cnt; msg_number++)
  325.     if (msg_bit(list, msg_number)) {
  326.             print("%sing msg %d... ",
  327.         (firstchar == 's')? "Sav" : "Writ", msg_number+1);
  328.         print_more("(%d lines)\n", copy_msg(msg_number, mail_fp, flg));
  329.         /* only mark "deleted" if mailfile is /usr/spool/mail and
  330.          * we're not "copying.  If keepsave is set, then firstchar
  331.          * will have already been changed to 'c'
  332.          */
  333.         if (!strcmp(mailfile, spoolfile) && firstchar != 'c' &&
  334.         isoff(glob_flags, READ_ONLY))
  335.         turnon(msg[msg_number].m_flags, DELETE);
  336.         n++;
  337.     }
  338.     fclose(mail_fp);
  339.     print_more("%s %d msg%s to %s\n",
  340.         (*mode == 'a')? "Appended" : "Saved", n, (n != 1)? "s": "", file);
  341.     if (!strcmp(mailfile, spoolfile))
  342.     turnon(glob_flags, DO_UPDATE);
  343. #ifdef SUNTOOL
  344.     if (istool) {
  345.     unlock_cursors();
  346.     (void) do_hdrs(0, DUBL_NULL, NULL);
  347.     add_folder_to_menu(folder_item, 3);
  348.     add_folder_to_menu(save_item, 1);
  349.     }
  350. #endif /* SUNTOOL */
  351.     return 0;
  352. }
  353.  
  354. respond(n, argv, list)
  355. register int n;  /* no use for argc, so use its address space for a variable */
  356. register char **argv, *list;
  357. {
  358.     register char *cmd = *argv;
  359.     char list1[MAXMSGS_BITS];
  360.  
  361.     if (*++argv && !strcmp(*argv, "-?"))
  362.     return help(0, "respond_help", cmd_help);
  363.     if ((n = get_msg_list(argv, list)) == -1)
  364.     return -1;
  365.     /* make into our own list so ~: commands don't overwrite this list */
  366.     bitput(list, list1, MAXMSGS, =);
  367.     /* back up one arg to replace "cmd" in the new argv[0] */
  368.     argv += (n-1);
  369.     if (!strcmp(cmd, "replyall"))
  370.     Upper(*cmd);
  371.     strdup(argv[0], cmd);
  372.     current_msg = -1;
  373.     for (n = 0; n < msg_cnt; n++)
  374.     if (msg_bit(list1, n)) {
  375.         if (current_msg > -1 && istool) {
  376.         print("tool mode can not respond to multiple messages.");
  377.         continue;
  378.         }
  379.         current_msg = n;
  380.         set_isread(n);
  381.         if (do_mail(1 /* ignored */, argv, list) == -1)
  382.         return -1;
  383.         set_replied(n); /* only if mail got delivered */
  384. #ifdef SUNTOOL
  385.         if (istool)
  386.         do_hdrs(0, DUBL_NULL, NULL);
  387. #endif /* SUNTOOL */
  388.     }
  389.     return 0;
  390. }
  391.  
  392. /* cd to a particular directory specified by "p" */
  393. cd(x, argv) /* argc, unused -- use space for a non-register variable */
  394. register char **argv;
  395. {
  396.     char cwd[MAXPATHLEN], buf[MAXPATHLEN];
  397.     register char *path, *p = argv[1], *cdpath = NULL, *p2;
  398. #ifdef SYSV
  399.     char *getcwd();
  400. #else
  401.     char *getwd();
  402. #endif /* SYSV */
  403.     int err = 0;
  404.  
  405.     if (!strcmp(*argv, "pwd") && (p = do_set(set_options, "cwd")) && *p) {
  406.     print("%s\n", p);
  407.     return -1;
  408.     }
  409.     if (!p || !*p) /* if no args, pwd = ".", cd = ~ */
  410.     p = (**argv == 'p')? "." : "~";
  411.     /* if a full path was not specified, loop thru cdpath */
  412.     if (**argv != 'p' && *p != '/' && *p != '~' && *p != '+')
  413.     cdpath = do_set(set_options, "cdpath");
  414.     do  {
  415.     if (cdpath) {
  416.         char c;
  417.         if (p2 = any(cdpath, " \t"))
  418.         c = *p2, *p2 = 0;
  419.         (void) sprintf(buf, "%s/%s", cdpath, p);
  420.         if (cdpath = p2) /* assign and compare to NULL */
  421.         *p2 = c;
  422.         while (cdpath && isspace(*cdpath))
  423.         cdpath++;
  424.     } else
  425.         (void) strcpy(buf, p);
  426.     x = 0;
  427.     path = getpath(buf, &x);
  428.     if (x != 1 || chdir(path) == -1)
  429.         err = errno;
  430.     else
  431.         err = 0;
  432.     } while (err && cdpath && *cdpath);
  433.     if (err)
  434.     error(p);
  435. #ifdef SYSV
  436.     if (getcwd(cwd, 128) == NULL)
  437. #else
  438.     if (getwd(cwd) == NULL)
  439. #endif /* SYSV */
  440.     print("can't get cwd: %s.\n", cwd), err++;
  441.     else {
  442.     char **new_argv;
  443.     (void) sprintf(buf, "set cwd = \"%s\"", cwd);
  444.     Debug("%s\n", buf);
  445.     if (new_argv = mk_argv(buf, &x, 1))
  446.         (void) add_option(&set_options, new_argv), free_vec(new_argv);
  447.     }
  448.     if (istool || iscurses || err) {
  449.     if (err)
  450.         turnon(glob_flags, CONT_PRNT);
  451.     print("Working dir: %s\n", cwd);
  452.     }
  453.     return -1;
  454. }
  455.  
  456. quit(argc, argv)
  457. char **argv;
  458. {
  459.     u_long updated = ison(glob_flags, DO_UPDATE);
  460.  
  461.     if (argc > 1 && !strcmp(argv[1], "-?"))
  462.     return help(0, "quit_help", cmd_help);
  463.     if ((!argc || (*argv && **argv == 'q')) && ison(glob_flags, DO_UPDATE)
  464.     && !copyback())
  465.     return -1;
  466. #ifdef CURSES
  467.     if (iscurses) {
  468.     /* we may already be on the bottom line; some cases won't be */
  469.     move(LINES-1, 0), refresh();
  470.     if (updated)
  471.         putchar('\n');
  472.     }
  473. #endif /* CURSES */
  474.     cleanup(0);
  475. #ifdef lint
  476.     return 0;
  477. #endif /* lint */
  478. }
  479.  
  480. delete(argc, argv, list)
  481. register int argc;
  482. register char **argv, list[];
  483. {
  484.     register int prnt_next, undel = argc && **argv == 'u';
  485.     int old_msg = current_msg;
  486.  
  487.     prnt_next = (argv && (!strcmp(*argv, "dt") || !strcmp(*argv, "dp")));
  488.  
  489.     if (argc && *++argv && !strcmp(*argv, "-?")) {
  490.     print("usage: delete/undelete [msg_list]\n");
  491.     return -1;
  492.     }
  493.  
  494.     if (ison(glob_flags, READ_ONLY)) {
  495.     print("Folder is read-only\n");
  496.     return -1;
  497.     }
  498.  
  499.     if (get_msg_list(argv, list) == -1)
  500.     return -1;
  501.     for (argc = 0; argc < msg_cnt; argc++)
  502.     if (msg_bit(list, argc))
  503.         if (undel)
  504.         turnoff(msg[argc].m_flags, DELETE);
  505.         else
  506.         turnon(msg[argc].m_flags, DELETE);
  507.  
  508.     /* only if current_msg has been affected && not in curses mode */
  509.     if (prnt_next == 0 && !iscurses && msg_bit(list, current_msg))
  510.     prnt_next = !!do_set(set_options, "autoprint"); /* change to boolean */
  511.  
  512.     turnon(glob_flags, DO_UPDATE);
  513.  
  514.     /* goto next available message if current was just deleted.
  515.      * If there are no more messages, turnoff prnt_next.
  516.      */
  517.     if (!iscurses && !undel && ison(msg[current_msg].m_flags, DELETE))
  518.     next_msg();
  519.  
  520.     if (prnt_next && !undel && !iscurses)
  521.     if (old_msg != current_msg && isoff(msg[current_msg].m_flags, DELETE))
  522.         display_msg(current_msg, (long)0);
  523.     else
  524.         print("No more messages.\n"), current_msg = old_msg;
  525. #ifdef SUNTOOL
  526.     if (istool)
  527.     (void) do_hdrs(0, DUBL_NULL, NULL);
  528. #endif /* SUNTOOL */
  529.     return 0;
  530. }
  531.  
  532. /*
  533.  * historically from the "from" command in ucb-mail, this just prints
  534.  * the composed header of the messages set in list or in pipe.
  535.  */
  536. do_from(n, argv, list)
  537. char **argv, list[];
  538. {
  539.     int inc_cur_msg = 0;
  540.  
  541.     if (argv && *++argv && !strcmp(*argv, "-?"))
  542.     return help(0, "from", cmd_help);
  543.     if (argv && *argv && (!strcmp(*argv, "+") || !strcmp(*argv, "-")))
  544.     if (!strcmp(*argv, "+")) {
  545.         if (!*++argv && current_msg < msg_cnt-1)
  546.         current_msg++;
  547.         inc_cur_msg = 1;
  548.     } else if (!strcmp(*argv, "-")) {
  549.         if (!*++argv && current_msg > 0)
  550.         current_msg--;
  551.         inc_cur_msg = -1;
  552.     }
  553.     if (get_msg_list(argv, list) == -1)
  554.     return -1;
  555.     for (n = 0; n < msg_cnt; n++)
  556.     if (msg_bit(list, n)) {
  557.         wprint("%s\n", compose_hdr(n));
  558.         /* if -/+ given, set current message pointer to this message */
  559.         if (inc_cur_msg) {
  560.         current_msg = n;
  561.         /* if - was given, then set to first listed message.
  562.          * otherwise, + means last listed message -- let it go...
  563.          */
  564.         if (inc_cur_msg < 0)
  565.             inc_cur_msg = 0;
  566.         }
  567.     }
  568.     return 0;
  569. }
  570.  
  571. /*
  572.  * Do an ls from the system.
  573.  * Read from a popen and use wprint in case the tool does this command.
  574.  * The folders command uses this command.
  575.  */
  576. ls(x, argv)
  577. char **argv;
  578. {
  579.     register char  *p, *tmp;
  580.     char       buf[128];
  581.     register FILE  *pp;
  582.  
  583.     if (*++argv && !strcmp(*argv, "-?"))
  584.     return help(0, "ls", cmd_help);
  585.     if (!(p = do_set(set_options, "lister")))
  586.     p = "";
  587.     (void) sprintf(buf, "%s -C%s ", LS_COMMAND, p);
  588.     p = buf+strlen(buf);
  589.     for ( ; *argv; ++argv) {
  590.     x = 0;
  591.     if (**argv != '-')
  592.         tmp = getpath(*argv, &x);
  593.     else
  594.         tmp = *argv;
  595.     if (x == -1) {
  596.         wprint("%s: %s\n", *argv, tmp);
  597.         return -1;
  598.     }
  599.     p += strlen(sprintf(p, " %s", tmp));
  600.     }
  601.     if (!(pp = popen(buf, "r"))) {
  602.     error(buf);
  603.     return -1;
  604.     }
  605.     turnon(glob_flags, IGN_SIGS);
  606.     while (fgets(buf, 127, pp))
  607.     wprint(buf);
  608.     (void) pclose(pp);
  609.     turnoff(glob_flags, IGN_SIGS);
  610.     return 0;
  611. }
  612.  
  613. sh(un_used, argv)
  614. char **argv;
  615. {
  616.     register char *p;
  617.     char buf[128];
  618.  
  619.     if (istool > 1 || *++argv && !strcmp(*argv, "-?"))
  620.     return help(0, "shell", cmd_help);
  621.     if (!(p = do_set(set_options, "shell"))
  622.     && !(p = do_set(set_options, "SHELL")))
  623.     p = DEF_SHELL;
  624.     if (!*argv)
  625.     (void) strcpy(buf, p);
  626.     else
  627.     (void) argv_to_string(buf, argv);
  628.     echo_on();
  629.     (void) system(buf);
  630.     echo_off();
  631.     return 0;
  632. }
  633.  
  634. static
  635. sorter(cmd1, cmd2)
  636. register struct cmd *cmd1, *cmd2;
  637. {
  638.     return strcmp(cmd1->command, cmd2->command);
  639. }
  640.  
  641. question_mark(x, argv)
  642. char **argv;
  643. {
  644.     int n = 0;
  645.     char *Cmds[50], *p, *malloc(), buf[30];
  646.  
  647.     qsort((char *)cmds, sizeof(cmds)/sizeof(struct cmd)-1,
  648.             sizeof(struct cmd), sorter);
  649.  
  650.     if (!*++argv) {
  651.     for (x = 0; cmds[x].command; x++) {
  652.         if (!(x % 5))
  653.         if (!(p = Cmds[n++] = malloc(80))) {
  654.             error("malloc in question_mark()");
  655.             free_vec(Cmds);
  656.             return -1;
  657.         }
  658.         p += strlen(sprintf(p, "%-11.11s  ", cmds[x].command));
  659.     }
  660.     Cmds[n++] = savestr("Type: `command -?' for help with most commands.");
  661.     Cmds[n] = NULL;
  662.     (void) help(0, Cmds, NULL);
  663.     free_vec(Cmds);
  664.     } else {
  665.     for (x = 0; cmds[x].command; x++)
  666.         if (!strcmp(*argv, cmds[x].command))
  667.         return cmd_line(sprintf(buf, "%s -?", *argv), msg_list);
  668.     print("Unknown command: %s\n", *argv);
  669.     }
  670.     return -1;
  671. }
  672.  
  673. #ifdef SIGSTOP
  674. stop(argc, argv)
  675. char **argv;
  676. {
  677.     if (istool)
  678.     print("Not a tool-based option.");
  679.     if (argc && *++argv && !strcmp(*argv, "-?"))
  680.     return help(0, "stop", cmd_help);
  681.     if (kill(getpid(), SIGTSTP) == -1)
  682.     error("couldn't stop myself");
  683.     return -1;
  684. }
  685. #endif /* SIGSTOP */
  686.  
  687. extern char **environ;
  688. static int spaces = 0;
  689.  
  690. Setenv(i, argv)
  691. char **argv;
  692. {
  693.     char *newstr;
  694.  
  695.     if (i < 2 || i > 3 || !strcmp(argv[1], "-?"))
  696.     return help(0, "setenv", cmd_help);
  697.  
  698.     if (i == 3) {
  699.     newstr = malloc(strlen(argv[1]) + strlen(argv[2]) + 2);
  700.     (void) sprintf(newstr, "%s=%s", argv[1], argv[2]);
  701.     } else {
  702.     newstr = malloc(strlen(argv[1]) + 2);
  703.     (void) sprintf(newstr, "%s=", argv[1]);
  704.     }
  705.  
  706.     (void) Unsetenv(2, argv);
  707.  
  708.     for (i = 0; environ[i]; i++);
  709.     if (!spaces) {
  710.     char **new_environ = (char **)malloc((i+2) * sizeof(char *));
  711.     /* add 1 for the new item, and 1 for null-termination */
  712.     if (!new_environ) {
  713.         free(newstr);
  714.         return -1;
  715.     }
  716.     spaces = 1;
  717.     for (i = 0; new_environ[i] = environ[i]; i++);
  718.     xfree(environ);
  719.     environ = new_environ;
  720.     }
  721.     environ[i] = newstr;
  722.     environ[i+1] = NULL;
  723.     spaces--;
  724.     return -1;
  725. }
  726.  
  727. Unsetenv(n, argv)
  728. char **argv;
  729. {
  730.     char **envp, **last;
  731.  
  732.     if (n != 2 || !strcmp(argv[1], "-?"))
  733.     return help(0, "unsetenv", cmd_help);
  734.  
  735.     n = strlen(argv[1]);
  736.     for (last = environ; *last; last++);
  737.     last--;
  738.  
  739.     for (envp = environ; envp <= last; envp++) {
  740.     if (strncmp(argv[1], *envp, n) == 0 && (*envp)[n] == '=') {
  741.         xfree(*envp);
  742.         *envp = *last;
  743.         *last-- = NULL;
  744.         spaces++;
  745.     }
  746.     }
  747.     return -1;
  748. }
  749.  
  750. Printenv()
  751. {
  752.     char **e = environ;
  753.     while (*e)
  754.     wprint("%s\n", *e++);
  755.     return -1;
  756. }
  757.  
  758. /*
  759.  * internal stty call to allow the user to change his tty character
  760.  * settings.  sorry, no way to change cbreak/echo modes.  Save echo_flg
  761.  * so that execute() won't reset it.
  762.  */
  763. my_stty(un_used, argv)
  764. char **argv;
  765. {
  766.     u_long save_echo = ison(glob_flags, ECHO_FLAG);
  767.  
  768.     turnon(glob_flags, ECHO_FLAG);
  769.     execute(argv);
  770.     if (save_echo)
  771.     turnon(glob_flags, ECHO_FLAG);
  772.     else
  773.     turnoff(glob_flags, ECHO_FLAG);
  774.  
  775.     savetty();
  776. #ifdef TIOCGLTC
  777.     if (ioctl(0, TIOCGLTC, <chars))
  778.     error("TIOCGLTC");
  779. #endif /* TIOCGLTC */
  780.     echo_off();
  781.     return -1;
  782. }
  783.