home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume12
/
mush
/
part18
< prev
next >
Wrap
Text File
|
1990-05-05
|
57KB
|
2,057 lines
Newsgroups: comp.sources.misc
subject: v12i046: Mail User's Shell, Part18/19
from: argv@Eng.Sun.COM (Dan Heller)
Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
Posting-number: Volume 12, Issue 46
Submitted-by: argv@Eng.Sun.COM (Dan Heller)
Archive-name: mush/part18
#! /bin/sh
# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix@uunet.uu.net if you want that tool.
# If this archive is complete, you will see the following message at the end:
# "End of archive 18 (of 19)."
# Contents: mush/Mushrc mush/expr.c mush/macros.c mush/main.c
# mush/options.c mush/print.c mush/sort.c
# Wrapped by argv@turnpike on Wed May 2 13:59:53 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'mush/Mushrc' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'mush/Mushrc'\"
else
echo shar: Extracting \"'mush/Mushrc'\" \(5551 characters\)
sed "s/^X//" >'mush/Mushrc' <<'END_OF_FILE'
X# Mushrc -- suggested /usr/lib/Mushrc init file for Mush
X# Copyright (c) 1989 by Bart Schaefer and Dan Heller
X#
X# Set these variables as they are set in config.h
X# (assumes that this file is DEFAULT_RC from config.h)
Xset \
X MAILRC = ".mushrc" \
X ALTERNATE_RC = ".mailrc" \
X ALT_DEF_RC = "/usr/lib/Mail.rc"
X
X# Set up the display early to allow quick exit in headers-only mode.
X# The hdrs_only flag is true if the command line was: "mush -H".
X# The variable hdr_format is set to change the format of the header
X# summaries that are displayed.
Xif hdrs_only
X set hdr_format='%22a %M %-2N %5T %.33s'
X exit # Quits reading this file
Xelse
X set hdr_format='%22a %M %-2N %5T (%3.5l li) %.25s'
Xendif
X
X# Set the prompt to show current time, name of the current folder,
X# current message number, and count of total messages.
Xset prompt="(%T) %f: #%m of %t> "
X
X# Hitting <CR> should do nothing (helps make mush more shell-like). If
X# newline is not set, hitting <CR> prints the next message (like Mail).
X# This variable could be set to any mush command.
Xset newline
X
X# When reading messages, don't bother looking at lengthy, boring headers.
Xignore message-id received via status
X
X# Since mush has csh-like history, you might find it annoying to type
X# things like "mail host\!host1\!host2\!user" from within the mush shell.
X# Setting nonobang will prevent the "unknown event" and allow the !'s to
X# be typed without having to be preceded by backslashes.
Xset nonobang
X
X# By default, mush's history is set to the last command only. Set it to
X# remember the last 100 commands.
Xset history = 100
X
X# If the variable "unix" is set, then any command that isn't a mush command
X# will execute the command as if you typed it from the shell. Note, such
X# commands will not go through another shell -- this is it. This may be
X# considered confusing for new users, so it is commented out by default.
X# set unix
X
X# When you use the -i option to reply, or use the ~i tilde escape in a letter
X# when in compose mode, the current message will be included in your text.
X# Put a nice wrapper around those included messages. Here, show the author's
X# name and the subject of his letter, label the end, and add a trailing blank
X# to separate each inclusion and make finding the end easier.
Xset pre_indent_str='On %M %N, %T, %.50n wrote:\n} Subject: %.65s'
Xset indent_str='} ' # actual message text is preceded by a "}"
Xset post_indent_str='}-- End of excerpt from %.50n\n'
X
X# Label replies with a header showing the who, what, and when of the
X# message being replied-to.
Xset in_reply_to='%f\n\t"%s" (%d)'
X
X# Mail routing and address-fixing conveniences. If auto_route is set, then
X# replies to messages take a closer look at the addresses of the recipients.
X# If any redundant paths are present, they are pruned. Also, the path that
X# precedes any hosts listed in the "known_hosts" list is truncated. This is
X# useful for uucp sites only, and is therefore commented out by default.
X# set auto_route known_hosts="sun ucbcad well unicom"
X
X# The curses mode allows the screen to be set up like a full screen editor.
X# There are basic "curses commands" which are bound to keyboard key-sequences
X# (usually one character). The user can rebind these keys to suit his tastes.
X# Note that the binding for R below removes the binding of reply-all.
X#
Xset curses_help # Unset this to remove help message in curses.
Xbind \n display # Hit return to display the next message.
Xbind e macro "[line-mode]edit\n" # Quick edit from curses.
Xbind P macro "[line-mode]Print\n" # Show me all the headers.
X
X# "cmd" is used to set command line aliases similar to the way "csh"
X# does it. The only difference is that "alias" is a reserved word in
X# Mush and Mail, so cmd is used.
X#
Xcmd dq 'd \!*; q' # Delete a message list, then quit.
Xcmd unread 'flags \!* U O' # Mark messages unread.
Xcmd : curses # Colon now "toggles" curses mode.
X
X# Read the alternate system init file in addition to this file
Xsource $ALT_DEF_RC
Xunset ALT_DEF_RC
X
X# Mush tries to read ~/.mushrc first, then it tries ~/.mailrc. If .mushrc
X# is found, .mailrc is normally not read. Source the contents of .mailrc
X# as well in case there are Mail aliases that are set there.
Xif -e $HOME/$MAILRC
X if -e $HOME/$ALTERNATE_RC
X source $HOME/$ALTERNATE_RC
X endif
Xendif
Xunset ALTERNATE_RC
X
X# The rest of this file demonstrates how sysadmins with novice users
X# might want to set things up.
X
Xif -e $HOME/.mushexpert
X set quiet
X exit
Xendif
Xif ! -e $HOME/.mushuser
X echo "I see you've never used the Mush program before."
X echo "I'll set some special flags to help you out."
X echo "After you've used Mush a few times, you can type the command:"
X echo ""
X echo " expert"
X echo ""
X echo "and the flags will no longer be set unless you put them"
X echo "in your $HOME/$MAILRC file."
X echo ""
X sh touch $HOME/.mushuser # Use sh in case $unix is not set.
X if $?quiet
X unset quiet # Show the help message on startup.
X endif
Xendif
X# At this point some helpful variables should be set. See the list above,
X# marked as "helpful for new users", for suggestions.
X#
X# Create the "expert" command mentioned in the message above.
Xcmd expert 'sh touch $HOME/.mushexpert'
X
X# These variables are helpful for new users:
X# ask -- always prompt for Subject: of mail
X# ignoreeof -- ignore end-of-file from keyboard
X# verify -- query that all is well before sending mail
X# warning -- report miscellaneous possible problems
Xset ask verify warning
Xset ignoreeof="echo 'Use "'"'quit'"'" to quit.'"
END_OF_FILE
if test 5551 -ne `wc -c <'mush/Mushrc'`; then
echo shar: \"'mush/Mushrc'\" unpacked with wrong size!
fi
# end of 'mush/Mushrc'
fi
if test -f 'mush/expr.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'mush/expr.c'\"
else
echo shar: Extracting \"'mush/expr.c'\" \(4685 characters\)
sed "s/^X//" >'mush/expr.c' <<'END_OF_FILE'
X/* @(#)expr.c 2.3 (c) copyright 10/15/86 (Dan Heller) */
X
X#include "mush.h"
X
Xchar *eval_expr();
X
X/* Parse a string (p) to interpret numbers and ranges of numbers (n-m)
X * delimited by whitespace or comma's. Set msg_list bitfields using
X * macros in mush.h.
X * Return the address of the end of whatever we parsed (in case there's
X * more that the calling routine cares to deal with).
X * Finally, remember that user specifies one more than actual message number
X */
Xchar *
Xdo_range(p, list1)
Xregister char *p, *list1;
X{
X register int num1 = -1, num2 = -1, except = 0;
X register char *p2;
X char list2[MAXMSGS_BITS];
X
X if (!p)
X return "";
X while (*p) {
X if (isdigit(*p) || *p == '$' || *p == '.' || *p == '^') {
X if (isdigit(*p)) {
X char c;
X p2 = p;
X skipdigits(0); /* find the end of the digits */
X c = *p, *p = 0; /* temporarily plug a null */
X if (!(num2 = chk_msg(p2))) {
X clear_msg_list(list1);
X return NULL;
X }
X *p = c;
X } else if (*p == '$')
X p++, num2 = msg_cnt;
X else if (*p == '.')
X p++, num2 = current_msg+1;
X else if (*p == '^')
X p++, num2 = 1;
X if (except)
X unset_msg_bit(list1, num2-1);
X else
X set_msg_bit(list1, num2-1);
X if (num1 >= 0) {
X if (num1 > num2) {
X print("syntax error: range sequence order reversed.\n");
X clear_msg_list(list1);
X return NULL;
X }
X while (++num1 < num2)
X if (except)
X unset_msg_bit(list1, num1-1);
X else
X set_msg_bit(list1, num1-1);
X num1 = num2 = -1;
X }
X }
X /* expressions to evaluate start with a `
X * p2 points to first char passed the last char parsed.
X */
X if (*p == '`') {
X clear_msg_list(list2);
X if (!(p = eval_expr(p, list2))) {
X clear_msg_list(list1);
X return NULL;
X } else {
X if (except)
X bitput(list2, list1, msg_cnt, &=~); /* MACRO */
X else
X bitput(list2, list1, msg_cnt, |=); /* MACRO */
X }
X }
X /* NOT operator: `* {5}' (everything except for 5)
X * `4-16 {8-10}' (4 thru 16 except for 8,9,10)
X */
X if (*p == '{' || *p == '}') {
X if (*p == '{' && (except || num1 >= 0))
X break;
X if (*p == '}' && !except) {
X print("syntax error: missing {\n"); /* } */
X break;
X }
X except = !except;
X } else if (*p == '-')
X if (num1 >= 0 || num2 < 0
X || !index(" \t{},.*`$", *(p+1)) && !isdigit(*(p+1)))
X break;
X else
X num1 = num2;
X else if (*p == ',' || *p == '*') {
X if (num1 >= 0)
X break;
X else if (*p == '*') {
X if (except)
X clear_msg_list(list1);
X else
X for (num1 = 0; num1 < msg_cnt; num1++)
X set_msg_bit(list1, num1);
X num1 = -1;
X }
X } else if (!index(" \t`", *p))
X break;
X if (*p)
X skipspaces(1); /* don't make user type stuff squished together */
X }
X if (num1 >= 0 || except) {
X if (except)
X /* { */ print("syntax error: unmatched }\n");
X else
X print("syntax error: unfinished range\n");
X clear_msg_list(list1);
X return NULL;
X }
X return p;
X}
X
X/*
X * convert a message list to an ascii string.
X */
Xvoid
Xlist_to_str(list, str)
Xchar list[], *str;
X{
X int n, m = -1;
X
X for (n = 0; n < msg_cnt; n++) {
X if (msg_bit(list, n)) {
X if (m == -1)
X str += strlen(sprintf(str, "%d", (m = n) + 1 ));
X continue;
X }
X if (m == -1)
X continue;
X if (n - m > 2)
X str += strlen(sprintf(str, "-%d", n));
X else if (n - m == 2)
X str += strlen(sprintf(str, " %d", n));
X *str++ = ' ';
X m = -1;
X }
X if (m > -1 && m != n - 1) {
X if (n - m > 2)
X *str++ = '-';
X else
X *str++ = ' ';
X str += Strcpy(str, itoa(msg_cnt));
X }
X *str = 0;
X}
X
X/* evaluate expressions:
X * mail> delete `pick -f root` deletes all messages from root.
X * mail> save * {`pick -s "Re:"`} save all message that don't have "Re:"
X * in the subject header.
X * mail> save `pick -x -s "Re:"` same
X * args as follows:
X * p should point to the first ` -- check for it.
X * on tells whether to turn bits on or off if messages match.
X */
Xchar *
Xeval_expr(p, new_list)
Xregister char *p, new_list[];
X{
X register char *p2, **argv;
X int argc;
X u_long save_flags = glob_flags;
X
X if (!(p2 = index(++p, '`'))) {
X print("unmatched backquote (`)\n");
X return NULL;
X }
X *p2 = 0;
X
X skipspaces(0);
X if (!*p) {
X print("Invalid null command\n");
X return NULL;
X }
X turnon(glob_flags, DO_PIPE);
X /* ignore sigs only because if user interrupts the do_command,
X * the longjmp will corrupt the stack and the program is hosed.
X * fix is to have layers of jmp_bufs to return to different levels.
X */
X turnon(glob_flags, IGN_SIGS);
X if (*p && (argv = make_command(p, TRPL_NULL, &argc)))
X (void) do_command(argc, argv, new_list);
X glob_flags = save_flags;
X *p2 = '`';
X return p2+1;
X}
END_OF_FILE
if test 4685 -ne `wc -c <'mush/expr.c'`; then
echo shar: \"'mush/expr.c'\" unpacked with wrong size!
fi
# end of 'mush/expr.c'
fi
if test -f 'mush/macros.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'mush/macros.c'\"
else
echo shar: Extracting \"'mush/macros.c'\" \(9279 characters\)
sed "s/^X//" >'mush/macros.c' <<'END_OF_FILE'
X/* (@)# macros.c (c) copyright 9/19/88 (Bart Schaefer, Dan Heller) */
X
X#include "bindings.h"
X#include "mush.h"
X
Xextern struct cmd_map map_func_names[];
X
Xstruct cmd_map *mac_stack, *mac_hide;
X
X/*
X * print current binding to macro mappings if "str" is NULL.
X * else return the string "x_str" which the str is bound to.
X */
Xchar *
Xc_macro(name, str, opts)
Xchar *name;
Xregister char *str;
Xregister struct cmd_map *opts;
X{
X register int incurses = iscurses;
X char buf[MAX_MACRO_LEN], buf2[sizeof buf * 3];
X
X if (!str) {
X for (; opts; opts = opts->m_next)
X if (opts->m_cmd == C_MACRO)
X break;
X if (!opts) {
X print("No %s settings.\n", name);
X return (char *)(-1);
X }
X if (incurses)
X clr_bot_line(), iscurses = FALSE;
X (void) do_pager(NULL, TRUE);
X (void) do_pager(sprintf(buf, "\nCurrent %s settings:\n\n",name), FALSE);
X }
X
X if (!opts)
X return NULL;
X
X for (; opts; opts = opts->m_next) {
X if (opts->m_cmd != C_MACRO)
X continue;
X if (!str) {
X (void) do_pager(sprintf(buf, "%-20.20s ",
X ctrl_strcpy(buf2, opts->m_str, FALSE)), FALSE);
X if (do_pager(sprintf(buf, "%s\n",
X ctrl_strcpy(buf2, opts->x_str, TRUE)), FALSE) == EOF)
X break;
X } else {
X if (strcmp(str, opts->m_str))
X continue;
X else
X return opts->x_str;
X }
X }
X iscurses = incurses;
X if (str)
X (void) do_pager(NULL, FALSE);
X return NULL;
X}
X
Xmac_push(str)
Xregister char *str;
X{
X register struct cmd_map *tmp;
X
X /* now make a new macro struct and set fields */
X if (!(tmp = (struct cmd_map *)calloc((unsigned)1,sizeof(struct cmd_map)))) {
X error("calloc");
X return -1;
X }
X tmp->m_next = mac_stack;
X mac_stack = tmp;
X tmp->x_str = savestr(str); /* x_str is the text of the expansion */
X tmp->m_str = tmp->x_str; /* m_str is the current read position */
X
X /*
X * Save the current state of the glob_flags so
X * mac_push() can also serve as unget of stdin
X */
X tmp->m_cmd = glob_flags;
X return 0;
X}
X
Xmac_queue(str)
Xregister char *str;
X{
X register struct cmd_map **tmp; /* NOTE pointer to pointer! */
X
X /* Find the bottom of the macro stack */
X for (tmp = &mac_stack; *tmp; tmp = &((*tmp)->m_next))
X ;
X /* now make a new macro struct and set fields */
X if (!(*tmp =
X (struct cmd_map *)calloc((unsigned)1,sizeof(struct cmd_map)))) {
X error("calloc");
X return -1;
X }
X (*tmp)->m_next = (struct cmd_map *)0; /* calloc should do this .... */
X (*tmp)->x_str = savestr(str); /* x_str is the text of the expansion */
X (*tmp)->m_str = (*tmp)->x_str; /* m_str is the current read position */
X
X /*
X * Save the current state of the glob_flags
X */
X (*tmp)->m_cmd = glob_flags;
X return 0;
X}
X
Xvoid
Xmac_pop()
X{
X register struct cmd_map *tmp;
X
X if (mac_stack) {
X tmp = mac_stack;
X mac_stack = tmp->m_next;
X xfree(tmp->x_str);
X xfree((char *) tmp);
X }
X /*
X * Restore saved MACRO glob_flags only (see mac_push())
X */
X if (mac_stack) {
X if (ison(mac_stack->m_cmd, IN_MACRO))
X turnon(glob_flags, IN_MACRO);
X else
X turnoff(glob_flags, IN_MACRO);
X if (ison(mac_stack->m_cmd, LINE_MACRO))
X turnon(glob_flags, LINE_MACRO);
X else
X turnoff(glob_flags, LINE_MACRO);
X if (ison(mac_stack->m_cmd, QUOTE_MACRO))
X turnon(glob_flags, QUOTE_MACRO);
X else
X turnoff(glob_flags, QUOTE_MACRO);
X }
X}
X
X/* Abandon macro processing */
Xvoid
Xmac_flush()
X{
X while (mac_stack)
X mac_pop();
X if (mac_hide) {
X mac_stack = mac_hide;
X mac_hide = NULL_MAP;
X while (mac_stack)
X mac_pop();
X }
X turnoff(glob_flags, IN_MACRO);
X turnoff(glob_flags, LINE_MACRO);
X turnoff(glob_flags, QUOTE_MACRO);
X}
X
X/* Check for pending input from a macro. */
Xmac_pending()
X{
X register struct cmd_map *msp;
X
X for (msp = mac_stack; msp && !*(msp->m_str); msp = msp->m_next)
X ;
X
X return !!msp;
X}
X
X/* Get input and treat it as a macro. */
Xget_mac_input(newline)
Xint newline; /* 1 if newline to be appended, 0 otherwise */
X{
X register int len;
X char buf[MAX_MACRO_LEN];
X
X /* This call cannot be nested */
X if (mac_hide)
X return -1;
X
X /* Hide the mac_stack so input comes from stdin */
X mac_hide = mac_stack; mac_stack = NULL_MAP;
X
X if ((len = Getstr(buf, MAX_MACRO_LEN - 1, 0)) < 0)
X return len;
X if (newline) {
X buf[len++] = '\n';
X buf[len] = 0;
X }
X
X /* Restore the mac_stack */
X if (mac_stack) {
X /*
X * Somehow, a push happened even though mac_hide was
X * nonzero -- maybe by line wrap? Fix it as best we can.
X */
X struct cmd_map *msp;
X for (msp = mac_stack; msp->m_next; msp = msp->m_next)
X ;
X msp->m_next = mac_hide;
X } else
X mac_stack = mac_hide;
X mac_hide = NULL_MAP;
X
X /* Restore saved flags */
X if (mac_stack) {
X if (ison(mac_stack->m_cmd, IN_MACRO))
X turnon(glob_flags, IN_MACRO);
X else
X turnoff(glob_flags, IN_MACRO);
X if (ison(mac_stack->m_cmd, LINE_MACRO))
X turnon(glob_flags, LINE_MACRO);
X else
X turnoff(glob_flags, LINE_MACRO);
X }
X if (len > 0)
X Ungetstr(buf);
X
X return 1;
X}
X
X/* getchar() substitute -- reads from the current macro if one is active,
X * otherwise does a getchar().
X *
X * NOTE: In the mac_stack, x_str is the saved text of the current macro,
X * and m_str is the current read position within the macro.
X */
Xm_getchar()
X{
X int c;
X
X while (mac_stack && (! *(mac_stack->m_str)))
X mac_pop();
X if (mac_stack) {
X c = *((mac_stack->m_str)++);
X return c;
X } else {
X turnoff(glob_flags, IN_MACRO);
X turnoff(glob_flags, LINE_MACRO);
X turnoff(glob_flags, QUOTE_MACRO);
X while ((c = getchar()) == 0) /* Ignore NUL chars from stdin */
X ; /* until better solution found */
X return c;
X }
X}
X
Xm_ungetc(c)
Xchar c;
X{
X if (mac_stack && (mac_stack->m_str > mac_stack->x_str))
X *(--(mac_stack->m_str)) = c;
X else
X (void) ungetc(c, stdin);
X}
X
X/*
X * Try to read a long command; assumes MAC_LONG_CMD already seen.
X * On immediate failure, return 0.
X * On failure after reading some input, return less than zero.
X * On success, return greater than 0.
X * The absolute value of the return is the number of chars placed in buf.
X */
Xread_long_cmd (buf)
Xchar *buf;
X{
X register char c, *p = buf;
X register int count = 0;
X
X /*
X * Test in_macro() in this loop because the _entire_
X * long command _must_ be in the macro -- if we run
X * out of macro in mid-long-command, it is an error.
X */
X while (in_macro() && (count < MAX_LONG_CMD - 1)
X && ((c = m_getchar()) != MAC_LONG_END)) {
X *p++ = c; ++count;
X }
X *p = '\0';
X if (c != MAC_LONG_END)
X return (-count);
X return count;
X}
X
X/*
X * Identify and possibly execute a reserved long macro command
X * Executes if do_exec is true. Otherwise, just parse.
X */
Xreserved_cmd (buf, do_exec)
Xchar *buf;
X{
X int ret = 1;
X
X if (!strcmp(buf, MAC_GET_STR)) {
X if (do_exec)
X ret = get_mac_input(0);
X } else if (!strcmp(buf, MAC_GET_LINE)) {
X if (do_exec)
X ret = get_mac_input(1);
X } else
X ret = 0;
X return ret;
X}
X
X#ifdef CURSES
X
X/*
X * Identify (and possibly execute, if reserved) curses mode commands
X * that appear in macro strings enclosed by MAC_LONG_CMD and
X * MAC_LONG_END. Return the binding of the command.
X */
Xlong_mac_cmd (c, do_exec)
Xint c;
X{
X char buf[MAX_LONG_CMD];
X register int count, binding;
X int y, x;
X
X if (c != MAC_LONG_CMD)
X return C_ERROR;
X
X if ((count = read_long_cmd(buf)) <= 0) {
X print("Invalid long macro command");
X if (ison(glob_flags, CNTD_CMD))
X putchar('\n');
X if (do_exec)
X mac_flush();
X return C_ERROR;
X }
X
X if (do_exec) {
X if (ison(glob_flags, CNTD_CMD))
X clr_bot_line();
X getyx(stdscr, y, x);
X move(LINES - 1, 0);
X }
X if (reserved_cmd(buf, do_exec)) {
X if (do_exec) {
X if (isoff(glob_flags, CNTD_CMD))
X move(y, x);
X return getcmd();
X } else
X return C_NULL;
X } else if (do_exec)
X move(y, x);
X
X /* Can start at C_NULL because of "no-op" command */
X for (count = 0; count <= C_HELP; count++) {
X if (!strcmp(buf, map_func_names[count].m_str)) {
X binding = (int)map_func_names[count].m_cmd;
X break;
X }
X }
X /* Don't allow C_MACRO to be called directly */
X if (count > C_HELP || binding == C_MACRO) {
X print("Invalid long macro command");
X if (ison(glob_flags, CNTD_CMD))
X putchar('\n');
X return C_ERROR;
X } else
X return binding;
X}
X
X#endif /* CURSES */
X
X/*
X * Check the validity of a macro binding as far as possible
X */
Xcheck_mac_bindings(buf)
Xchar *buf;
X{
X int ok = TRUE;
X
X while (ok && buf && *buf) {
X if (*buf == MAC_LONG_CMD) {
X char *i;
X#ifdef CURSES
X int count;
X#endif /* CURSES */
X
X if (ok)
X ok = ((i = index(++buf, MAC_LONG_END)) != NULL);
X if (i)
X *i = '\0'; /* Don't worry, we'll fix it */
X else
X return ok;
X#ifdef CURSES
X /* OK to start at C_NULL because of "no-op" command */
X for (count = 0; count <= C_HELP; count++)
X if (! strcmp(buf, map_func_names[count].m_str))
X break;
X /* Don't allow C_MACRO to be called directly */
X if (count == C_MACRO)
X ok = FALSE;
X else if (count > C_HELP)
X#endif /* CURSES */
X if (ok && !(ok = reserved_cmd(buf, FALSE)))
X wprint("Warning: unrecognized curses command: \"%s\"\n", buf);
X buf = i;
X *buf++ = MAC_LONG_END;
X } else if (*buf++ == '\\' && *buf)
X ++buf;
X }
X return ok;
X}
END_OF_FILE
if test 9279 -ne `wc -c <'mush/macros.c'`; then
echo shar: \"'mush/macros.c'\" unpacked with wrong size!
fi
# end of 'mush/macros.c'
fi
if test -f 'mush/main.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'mush/main.c'\"
else
echo shar: Extracting \"'mush/main.c'\" \(8938 characters\)
sed "s/^X//" >'mush/main.c' <<'END_OF_FILE'
X/* @(#)main.c (c) copyright 10/18/86 (Dan Heller) */
X
X#include "mush.h"
X#include "options.h"
X
X#if defined(sun) && defined(M_DEBUG)
Xcpu()
X{
X print("CPU time limit exceeded!\n");
X}
X#endif /* sun && DEBUG */
X
X#ifdef LCKDFLDIR
Xextern char *lckdfldir;
X#endif /* LCKDFLDIR */
X
X#ifdef DOT_LOCK
Xint sgid;
X#ifdef BSD
Xint rgid;
X#endif /* BSD */
X#endif /* DOT_LOCK */
X
X/*ARGSUSED*/ /* we ignore envp */
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X int n;
X char buf[MAXPATHLEN];
X register char *p;
X struct mush_flags Flags;
X
X#ifndef INTERNAL_MALLOC
X extern char *stackbottom; /* used by xfree() */
X
X stackbottom = (char *) &argc;
X#endif /* INTERNAL_MALLOC */
X
X#ifdef LCKDFLDIR
X lckdfldir = LCKDFLDIR;
X#endif /* LCKDFLDIR */
X if (prog_name = rindex(*argv, '/'))
X prog_name++;
X else
X prog_name = *argv;
X
X (void) signal(SIGBUS, bus_n_seg);
X (void) signal(SIGSEGV, bus_n_seg);
X (void) signal(SIGPIPE, SIG_IGN); /* if pager is terminated before end */
X
X#if defined(sun) && defined(M_DEBUG)
X (void) signal(SIGXCPU, cpu);
X
X if (p = getenv("MALLOC_DEBUG"))
X malloc_debug(atoi(p));
X else
X malloc_debug(0);
X#endif /* sun && debug */
X
X if (!isatty(0))
X turnon(glob_flags, REDIRECT);
X else
X (void) setbuf(stdin, NULL);
X
X (void) cmd_line(strcpy(buf, "set cmd_help"), NULL);
X
X init(); /* must be done before checking mail since "login" is set here */
X mailfile = "";
X#ifdef HOMEMAIL
X {
X char *home = do_set(set_options, "home");
X if (!home)
X home = ALTERNATE_HOME;
X strdup(spoolfile, sprintf(buf, "%s/%s", home, MAILFILE));
X }
X#else /* HOMEMAIL */
X strdup(spoolfile, sprintf(buf, "%s/%s", MAILDIR, login));
X#endif /* HOMEMAIL */
X
X n = preparse_opts(&argc,argv);
X
X /* check for any mail at all and exit if we're not continuing */
X if (!n) {
X struct stat statb;
X if (stat(spoolfile, &statb) || statb.st_size == 0) {
X (void) printf("No mail for %s.\n", login);
X exit(0);
X }
X }
X
X#ifdef DOT_LOCK
X sgid = getegid();
X#ifdef BSD
X rgid = getgid();
X setregid(sgid, rgid);
X#else
X setgid(getgid());
X#endif /* BSD */
X#endif /* DOT_LOCK */
X
X parse_options(&argv, &Flags);
X
X set_cwd();
X
X if (Flags.init_file)
X (void) cmd_line(sprintf(buf, "source %s", Flags.init_file), msg_list);
X if (Flags.source_rc > 0) {
X /* use cmd_line() in case DEFAULT_RC has expandable chars */
X (void) cmd_line(sprintf(buf, "source %s", DEFAULT_RC), msg_list);
X }
X if (Flags.source_rc > -1)
X (void) source(0, DUBL_NULL);
X mailfile = Flags.folder;
X
X if (*spoolfile != '/') {
X n = 1;
X p = getpath(spoolfile, &n);
X if (n == -1)
X (void) fputs(p, stderr), exit(1);
X else if (n)
X (void) fprintf(stderr, "\"%s\" is a directory.\n", p), exit(1);
X else if (*p != '/') {
X /* if it still isn't a full path, make it one */
X char *wd = do_set(set_options, "cwd");
X if (*wd) {
X (void) sprintf(buf, "%s/%s", wd, p);
X strdup(spoolfile, buf);
X } else
X strdup(spoolfile, p);
X } else
X strdup(spoolfile, p);
X }
X
X#ifdef SUNTOOL
X if (istool) {
X make_tool();
X turnon(glob_flags, DO_SHELL);
X turnoff(glob_flags, REDIRECT); /* -- SunOS-4.0 has a problem here */
X }
X#endif /* SUNTOOL */
X
X /* now we're ready for I/O */
X if (isoff(glob_flags, REDIRECT)) {
X /* make sure we can always recover from no echo mode */
X (void) signal(SIGINT, catch);
X (void) signal(SIGQUIT, catch);
X (void) signal(SIGHUP, catch);
X if (istool)
X turnon(glob_flags, ECHO_FLAG);
X tty_settings();
X#ifdef SIGCONT
X (void) signal(SIGTSTP, stop_start); /* this will take care of SIGCONT */
X#endif /* SIGCONT */
X /* echo_off() checks to see if echo_flg is set, so don't worry */
X echo_off();
X }
X
X if (!istool && ison(glob_flags, IS_SENDING)) {
X char recipients[BUFSIZ], *mailv[16];
X (void) argv_to_string(recipients, argv);
X fix_up_addr(recipients);
X mailv[0] = "mail";
X n = 1;
X if (ison(Flags.flg, VERBOSE))
X mailv[n++] = "-v";
X if (Flags.Subj && *(Flags.Subj)) {
X mailv[n++] = "-s";
X mailv[n++] = Flags.Subj;
X }
X if (Flags.Cc && *(Flags.Cc)) {
X fix_up_addr(Flags.Cc);
X mailv[n++] = "-c";
X mailv[n++] = Flags.Cc;
X }
X if (Flags.Bcc && *(Flags.Bcc)) {
X fix_up_addr(Flags.Bcc);
X mailv[n++] = "-b";
X mailv[n++] = Flags.Bcc;
X }
X if (ison(Flags.flg, NO_SIGN))
X mailv[n++] = "-u";
X if (ison(Flags.flg, SEND_NOW))
X mailv[n++] = "-U";
X if (Flags.draft) {
X if (isoff(Flags.flg, SEND_NOW))
X mailv[n++] = "-E";
X mailv[n++] = "-h";
X mailv[n++] = Flags.draft;
X }
X mailv[n++] = recipients;
X mailv[n] = NULL;
X /* set now in case user is not running shell, but is running debug */
X#ifndef SUNTOOL
X (void) signal(SIGCHLD, sigchldcatcher);
X#endif /* SUNTOOL */
X if (!setjmp(jmpbuf))
X (void) do_mail(n, mailv, msg_list);
X /* do shell set from above: "mush -S user" perhaps */
X if (isoff(glob_flags, DO_SHELL) && !*mailfile) {
X if (isoff(glob_flags, REDIRECT))
X echo_on();
X exit(0);
X }
X }
X turnoff(glob_flags, IS_SENDING); /* no longer sending mail; running shell */
X
X if (ison(glob_flags, REDIRECT)
X && (!Flags.src_file || !Flags.src_n_exit)) {
X puts("You can't redirect input unless you're sending mail.");
X puts("If you want to run a shell with redirection, use \"-i\"");
X cleanup(0);
X }
X if (!*mailfile) {
X strdup(mailfile, spoolfile);
X if (!mail_size() && isoff(glob_flags, DO_SHELL)) {
X /* we know it's not the spool file here */
X (void) printf("No mail in %s.\n", mailfile);
X echo_on(), exit(0);
X }
X }
X
X if (!hdrs_only) {
X /* catch will test DO_SHELL and try to longjmp if set. this is a
X * transition state from no-shell to do-shell to ignore sigs to
X * avoid a longjmp botch. Note setjmp isn't called until do_loop().
X */
X turnon(glob_flags, IGN_SIGS);
X#ifdef CURSES
X if (ison(glob_flags, PRE_CURSES))
X (void) curses_init(0, DUBL_NULL);
X turnoff(glob_flags, PRE_CURSES);
X#endif /* CURSES */
X }
X
X /* find a free tmpfile */
X if (!(p = getdir(do_set(set_options, "tmpdir"))))
Xalted:
X p = ALTERNATE_HOME;
X {
X int pid = getpid();
X while (!Access(sprintf(tempfile, "%s/.%s%d", p, prog_name, pid++), F_OK))
X ;
X }
X /* just create the file, make sure it's empty. It'll close later and
X * be reopened for reading only.
X */
X if (!(tmpf = mask_fopen(tempfile, "w"))) {
X if (strcmp(p, ALTERNATE_HOME))
X goto alted;
X error("Can't create tempfile %s", tempfile);
X cleanup(0);
X }
X
X /* do pseudo-intelligent stuff with certain signals */
X (void) signal(SIGINT, catch);
X (void) signal(SIGQUIT, catch);
X (void) signal(SIGHUP, catch);
X
X if (!hdrs_only && !istool && (!Flags.src_file || !Flags.src_n_exit) &&
X !glob(do_set(set_options, "quiet"), "{,{,*[ \\,]}startup{,[ \\,]*}}"))
X (void) printf("%s: Type '?' for help.\n", check_internal("version"));
X
X (void) sprintf(buf, "folder %s %s", Flags.f_flags, mailfile);
X if ((argv = mk_argv(buf, &argc, TRUE)) && argc > 0) {
X if (folder(argc, argv, NULL) == -1 && isoff(glob_flags, DO_SHELL)) {
X if (iscurses)
X putchar('\n');
X turnoff(glob_flags, IGN_SIGS), cleanup(0);
X }
X#ifdef CURSES
X if (iscurses)
X (void) curses_help_msg(TRUE);
X#endif /* CURSES */
X free_vec(argv);
X }
X
X if (hdrs_only) {
X (void) sprintf(buf, "headers %s", hdrs_only);
X if (argv = make_command(buf, TRPL_NULL, &argc))
X (void) do_hdrs(argc, argv, NULL);
X cleanup(0);
X }
X
X turnon(glob_flags, DO_SHELL);
X if (istool && msg_cnt)
X set_isread(current_msg);
X
X /* finally, if the user wanted to source a file to execute, do it now */
X if (Flags.src_file) {
X char *s_argv[2];
X s_argv[1] = Flags.src_file;
X (void) source(2, s_argv);
X if (!istool && Flags.src_n_exit)
X cleanup(0);
X }
X
X#ifdef SUNTOOL
X if (istool) {
X char buf[16];
X n = 0;
X (void) cmd_line(strcpy(buf, "set tool_help"), NULL);
X if (time_out < 30)
X time_out = 30;
X turnoff(glob_flags, IGN_SIGS);
X (void) do_hdrs(0, DUBL_NULL, NULL);
X timerclear(&(mail_timer.it_interval));
X timerclear(&(mail_timer.it_value));
X
X /* Reload time with value of timeout upon timer expiration. */
X mail_timer.it_interval.tv_sec = time_out;
X
X mail_timer.it_value.tv_sec = time_out;
X (void) notify_set_itimer_func(tool, do_check,
X ITIMER_REAL, &mail_timer, (struct itimerval *) 0);
X timeout_cursors(FALSE);
X turnoff(glob_flags, DO_UPDATE);
X window_main_loop(tool);
X cleanup(0);
X }
X#endif /* SUNTOOL */
X do_loop();
X}
X
Xdo_version()
X{
X print("%s\n", check_internal("version"));
X return -1;
X}
X
X/* set the current working directory */
Xset_cwd()
X{
X char cwd[MAXPATHLEN];
X#ifndef SYSV
X extern char *getwd();
X#else /* SYSV */
X extern char *getcwd();
X#endif /* SYSV */
X
X#ifndef SYSV
X if (getwd(cwd) == NULL)
X#else
X if (getcwd(cwd, MAXPATHLEN) == NULL)
X#endif /* SYSV */
X {
X error("set_cwd: %s", cwd);
X (void) un_set(&set_options, "cwd");
X } else {
X char *argv[4];
X argv[0] = "cwd";
X argv[1] = "=";
X argv[2] = cwd;
X argv[3] = NULL;
X (void) add_option(&set_options, argv);
X }
X}
END_OF_FILE
if test 8938 -ne `wc -c <'mush/main.c'`; then
echo shar: \"'mush/main.c'\" unpacked with wrong size!
fi
# end of 'mush/main.c'
fi
if test -f 'mush/options.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'mush/options.c'\"
else
echo shar: Extracting \"'mush/options.c'\" \(8816 characters\)
sed "s/^X//" >'mush/options.c' <<'END_OF_FILE'
X/* @(#)options.c (c) copyright 10/10/88 (Dan Heller, Bart Schaefer) */
X
X#include "mush.h"
X#include "options.h"
X
X/*
X * NOTE: Any word flag which is a prefix of another word flag must be
X * listed AFTER the flag it prefixes in the list below
X */
X
Xchar *word_flags[][2] = {
X { "-bcc", "-b" },
X { "-blindcarbon", "-b" },
X { "-blind", "-b" },
X { "-carbon", "-c" },
X { "-cc", "-c" },
X { "-copy", "-c" },
X { "-curses", "-C" },
X { "-debug", "-d" },
X { "-draft", "-h" },
X { "-echo", "-e" },
X { "-folder", "-f" }, /* Maybe -file should become -f too? */
X { "-file", "-F" }, /* Don't really like -file for -F */
X { "-headerfile", "-h" },
X { "-headers", "-H" },
X { "-initialize", "-I" },
X { "-init", "-I" },
X { "-interactive", "-i" },
X { "-interact", "-i" },
X { "-mailbox", "-m" },
X { "-message", "-h" },
X { "-noheaders", "-N" },
X { "-noinit", "-n" },
X { "-readonly", "-r" },
X { "-send", "-U" },
X { "-shell", "-S" },
X { "-source", "-F" }, /* This is better for -F */
X { "-subject", "-s" },
X { "-timeout", "-T" },
X { "-toolhelp", "-2" },
X { "-tool", "-t" },
X { "-user", "-u" },
X { "-verbose", "-v" },
X { "-visual", "-C" },
X { NULL, NULL } /* This must be the last entry */
X};
X
Xfix_word_flag(argp)
Xregister char **argp;
X{
X int i;
X
X Debug("%s --> ", *argp);
X for (i = 0; word_flags[i][0]; i++) {
X int len = strlen(word_flags[i][0]);
X if (! strncmp(*argp, word_flags[i][0], len)) {
X char buf[BUFSIZ], *p = buf;
X p += Strcpy(buf, word_flags[i][1]);
X (void) strcpy(p, *argp + len);
X (void) strcpy(*argp, buf);
X }
X }
X Debug("%s\n", *argp);
X}
X
X/*
X * preparse the command line to determine whether or not we're going
X * to bail out after checking that the user has no mail. Also, check
X * to see if we're going to run a tool because it must be built first.
X */
Xpreparse_opts(argcp, argv)
Xregister int *argcp; /* Pointer to argument count */
Xregister char **argv; /* Argument vector */
X{
X int n = FALSE;
X char **args;
X
X#ifdef SUNTOOL
X /* Note: we are assigning a boolean result to n and istool here */
X if (n = istool = (strlen(prog_name) > 3 &&
X (!strcmp(prog_name+strlen(prog_name)-4, "tool") ||
X !strcmp(prog_name+strlen(prog_name)-4, "view")))) {
X turnon(glob_flags, DO_SHELL);
X parse_tool_opts(argcp, argv);
X }
X#endif /* SUNTOOL */
X
X if (!istool && *argcp > 1) {
X for (args = argv+1; *args && args[0][0] == '-'; args++) {
X int next = 1;
X fix_word_flag(&args[0]);
XDoNext:
X switch (args[0][next]) {
X#ifdef SUNTOOL
X case 'T' :
X if (args[1])
X args++;
X case 't' :
X /* Note: we won't ever get here if started as
X * "mushtool" or "mushview" because istool is true.
X */
X istool = 1;
X parse_tool_opts(argcp, argv);
X turnon(glob_flags, DO_SHELL);
X return TRUE;
X /* break; */
X#endif /* SUNTOOL */
X case 'S' :
X turnon(glob_flags, DO_SHELL);
X n = TRUE;
X break;
X case 'f' :
X case 'F' :
X case 'h' :
X case 'm' :
X case 'u' :
X n = TRUE;
X case 'b' :
X case 'c' :
X case 'I' :
X case 's' :
X if (args[1]) {
X args++;
X next = 0;
X }
X break;
X case 'H' :
X if (args[0][next+1] == ':')
X next = 0;
X break;
X case '\0':
X next = 0;
X default : ;
X }
X if (next) {
X ++next;
X goto DoNext;
X }
X }
X if (*args) { /* unused args indicates sending mail to someone */
X n = TRUE;
X if (!istool)
X turnon(glob_flags, IS_SENDING);
X }
X }
X
X return n;
X}
X
Xstatic char *usage_str =
X#ifdef SUNTOOL
X "usage: %s [-t] [-C] [-i] [-f [folder] ] [-v] [-S] [-s subject] [users]\n";
X#else
X#ifdef CURSES
X "usage: %s [-C] [-i] [-f [folder] ] [-v] [-S] [-s subject] [user list]\n";
X#else
X "usage: %s [-i] [-f [folder] ] [-v] [-S] [-s subject] [user list]\n";
X#endif /* CURSES */
X#endif /* SUNTOOL */
X
Xparse_options(argvp, flags)
Xregister char ***argvp;
Xstruct mush_flags *flags;
X{
X char buf[256];
X
X bzero((char *) flags, sizeof (struct mush_flags));
X flags->source_rc = TRUE;
X flags->folder = "";
X
X for (++(*argvp); **argvp && ***argvp == '-'; (*argvp)++) {
X int look_again;
XDoLookAgain:
X look_again = TRUE;
X switch ((*argvp)[0][1]) {
X case 'e':
X /*
X * don't set tty modes -- e.g. echo and cbreak modes aren't
X * changed.
X */
X turnon(glob_flags, ECHO_FLAG);
X#ifdef CURSES
X when 'C':
X /* don't init curses -- don't even set iscurses. */
X if (istool) {
X puts("-C: You are already running in tool mode");
X turnoff(glob_flags, PRE_CURSES);
X } else if (hdrs_only)
X puts("headers only: ignoring -C flag");
X else
X turnon(glob_flags, PRE_CURSES);
X#endif /* CURSES */
X when 'F':
X flags->src_n_exit = ((*argvp)[0][2] == '!');
X if (!(flags->src_file = *++(*argvp)))
X puts("specify filename to source"), exit(1);
X look_again = FALSE;
X /* fall thru! */
X case 'N':
X (void) strcat(flags->f_flags, "-N ");
X when 'r':
X (void) strcat(flags->f_flags, "-r "); /* folder() argument */
X when 'H':
X if (istool) {
X puts("running in tool-mode; -H option ignored.");
X break;
X }
X turnoff(glob_flags, PRE_CURSES);
X if (*(hdrs_only = (*(*argvp))+2) != ':')
X hdrs_only = ":a";
X else
X look_again = FALSE;
X /* read only cuz no updates */
X (void) strcat(flags->f_flags, "-N -r ");
X when 'i':
X /* force interactive even if !isatty(0) */
X turnoff(glob_flags, REDIRECT);
X when 'u': /* specify a user's mailbox */
X if (*(flags->folder))
X puts("You can't specify more than one mailbox"), exit(1);
X#ifdef HOMEMAIL
X {
X char *p;
X int isdir = 1;
X (void) sprintf(buf, "%%%s",
X (*argvp)[1] ? (*argvp)[1] : "root");
X if ((p = getpath(buf, &isdir)) && !isdir)
X strdup(flags->folder, p);
X else if (isdir < 0)
X puts(p), exit(1);
X else if (isdir)
X (void) printf("\"%s\" is a directory\n", p), exit(1);
X }
X#else /* HOMEMAIL */
X strdup(flags->folder, sprintf(buf, "%s/%s",
X MAILDIR, ((*argvp)[1])? (*argvp)[1] : "root"));
X#endif /* HOMEMAIL */
X if ((*argvp)[1])
X ++(*argvp);
X look_again = FALSE;
X when 'h':
X if (istool)
X puts("bad option when run as a tool"), exit(1);
X if ((*argvp)[1])
X flags->draft = *++(*argvp);
X else
X (void) printf("-h: missing file name.\n"), exit(1);
X look_again = FALSE;
X turnon(glob_flags, IS_SENDING);
X when 'U':
X if (istool)
X puts("bad option when run as a tool"), exit(1);
X turnon(flags->flg, SEND_NOW);
X if ((*argvp)[0][2] == '!') {
X turnon(flags->flg, NO_SIGN);
X ++(**argvp);
X }
X when 'm':
X if ((*argvp)[1])
X strdup(spoolfile, *++(*argvp));
X else
X (void) printf("-m: missing mailbox name.\n"), exit(1);
X look_again = FALSE;
X when 'f':
X if (*(flags->folder))
X puts("You can't specify more than one mailbox"), exit(1);
X if ((*argvp)[1]) {
X strdup(flags->folder, *++(*argvp));
X look_again = FALSE;
X } else
X strdup(flags->folder, "&");
X when 's':
X if (istool)
X puts("bad option when run as a tool"), exit(1);
X else if ((*argvp)[1])
X flags->Subj = *++(*argvp);
X else
X puts("-s \"subject\""), exit(1);
X look_again = FALSE;
X when 'b':
X if (istool)
X puts("-b: bad option when run as a tool"), exit(1);
X else if ((*argvp)[1])
X flags->Bcc = *++(*argvp);
X else
X puts("-b \"bcc list\""), exit(1);
X look_again = FALSE;
X when 'c':
X if (istool)
X puts("-c: bad option when run as a tool"), exit(1);
X else if ((*argvp)[1])
X flags->Cc = *++(*argvp);
X else
X puts("-c \"cc list\""), exit(1);
X look_again = FALSE;
X break;
X#ifdef VERBOSE_ARG
X case 'v':
X if (istool)
X puts("bad option when run as a tool"), exit(1);
X turnon(flags->flg, VERBOSE);
X break;
X#endif /* VERBOSE_ARG */
X#ifdef SUNTOOL
X case 'T':
X if ((time_out = atoi(*(*argvp))) <= 29)
X time_out = 30;
X look_again = FALSE;
X /* -T implies -t */
X case 't': istool = 1;
X#endif /* SUNTOOL */
X case 'S': turnon(glob_flags, DO_SHELL);
X when 'n':
X if ((*argvp)[0][2] == '!') {
X ++(**argvp);
X flags->source_rc = -1; /* No init files sourced */
X } else
X flags->source_rc = 0; /* Only ~/.mushrc sourced */
X when 'I':
X if ((*argvp)[0][2] == '!' && flags->source_rc > 0)
X flags->source_rc = 0; /* Only ~/.mushrc sourced */
X if (!(flags->init_file = *++(*argvp)))
X puts("specify filename for init"), exit(1);
X look_again = FALSE;
X when 'd': debug = 1;
X when '\0' : look_again = FALSE;
X otherwise:
X print("%s: unknown option: `%c'\n", prog_name,
X (*argvp)[0][1]? (*argvp)[0][1] : '-');
X print(usage_str, prog_name);
X }
X if (look_again && ++(**argvp) != '\0')
X goto DoLookAgain;
X }
X
X if (ison(flags->flg, SEND_NOW) && !flags->draft) {
X print("You must specify a draft file to autosend\n");
X exit(1);
X }
X}
END_OF_FILE
if test 8816 -ne `wc -c <'mush/options.c'`; then
echo shar: \"'mush/options.c'\" unpacked with wrong size!
fi
# end of 'mush/options.c'
fi
if test -f 'mush/print.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'mush/print.c'\"
else
echo shar: Extracting \"'mush/print.c'\" \(5410 characters\)
sed "s/^X//" >'mush/print.c' <<'END_OF_FILE'
X/* @(#)print.c 2.4 (c) copyright 10/15/86 (Dan Heller) */
X
X#include "mush.h"
X#include <varargs.h>
X
X/*ARGSUSED*/
X/*VARARGS1*/
Xvoid
Xerror(fmt, arg1, arg2, arg3, arg4)
Xregister char *fmt;
Xchar *arg1, *arg2, *arg3, *arg4;
X{
X char buf[BUFSIZ];
X
X (void) sprintf(buf, fmt, arg1, arg2, arg3, arg4);
X sprintf(buf+strlen(buf), ": %s\n", sys_errlist[errno]);
X#ifdef SUNTOOL
X if (istool > 1)
X ok_box(buf);
X else
X#endif /* SUNTOOL */
X print(buf);
X}
X
X#if defined(SUNTOOL) || defined(CURSES)
X/*
X * print just like printf -- to a window, to curses, or to stdout. Use vprintf
X * if available. msgbuf is the buffer used to print into if necessary.
X * If you're running SUN3.2 or higher, the typecast (unsigned char *)msgbuf
X * (where indicated) otherwise, msgbuf is not typecast at all.
X */
X/*VARARGS*/
Xvoid
Xprint(va_alist)
Xva_dcl
X{
X static char msgbuf[BUFSIZ];
X char *fmt;
X va_list args;
X#ifndef VPRINTF
X FILE foo;
X#endif /* VPRINTF */
X static int x; /* position on line saved for continued prints */
X char *p; /* same type as struct file _ptr,_buf in stdio.h */
X
X#ifdef CURSES
X if (iscurses) {
X if (isoff(glob_flags, CONT_PRNT))
X move(LINES-1, x = 0), refresh();
X } else
X#endif /* CURSES */
X if (istool < 2) {
X va_start(args);
X fmt = va_arg(args, char *);
X#ifdef VPRINTF
X (void) vprintf(fmt, args);
X#else /* VPRINTF */
X _doprnt(fmt, args, stdout);
X#endif /* VPRINTF */
X va_end(args);
X (void) fflush(stdout);
X return;
X }
X va_start(args);
X fmt = va_arg(args, char *);
X if (fmt) {
X#ifdef VPRINTF
X (void) vsprintf(msgbuf, fmt, args); /* NULL in fmt reprints last msg */
X#else /* VPRINTF */
X foo._cnt = BUFSIZ;
X foo._base = foo._ptr = msgbuf; /* may have to cast(unsigned char *) */
X foo._flag = _IOWRT+_IOSTRG;
X (void) _doprnt(fmt, args, &foo);
X *foo._ptr = '\0'; /* plant terminating null character */
X#endif /* VPRINTF */
X }
X va_end(args);
X if (istool) {
X wprint("%s", msgbuf);
X return;
X }
X p = msgbuf;
X if (iscurses)
X while (p = index(p, '\n'))
X *p = ' ';
X#ifdef CURSES
X if (iscurses) {
X p = msgbuf;
X for (;;) {
X int len = COLS-1-x; /* space remaining at till the eol */
X /* don't wrap the line! Just print it and refresh() */
X printw("%-.*s", len, p), clrtoeol(), refresh();
X /* if length(p) (remainder of msgbuf) doesn't wrap, break loop */
X if ((x += strlen(p)) < COLS-1)
X break;
X /* the next print will overwrite bottom line, so \n first */
X putchar('\n'), move(LINES-1, x = 0); /* reset x */
X /* move p forward the number of chars we were able to display */
X p += len;
X turnon(glob_flags, CNTD_CMD); /* display ...continue... prompt */
X }
X turnoff(glob_flags, CONT_PRNT);
X (void) fflush(stdout); /* some sys-v's aren't fflushing \n's */
X return;
X }
X#endif /* CURSES */
X}
X
X#endif /* SUNTOOL || CURSES */
X
X/* for curses mode */
Xclr_bot_line()
X{
X print("");
X}
X
X#ifdef SUNTOOL
X
X/*
X * wprint prints stuff to a scrollable textsw. This is intended for
X * print statements that need to be recalled since print() overwrites
X * its last message. Messages are printed to whatever wprint_sw
X * currently points to. If you set it to null, nothing prints.
X * For non-suntool mode, wprint() is just like printf(). For curses mode,
X * wprint() does -not- act like print() -- lines length is not counted
X * and newlines are not stripped.
X */
X/*VARARGS*/
Xvoid
Xwprint(va_alist)
Xva_dcl
X{
X#ifndef VPRINTF
X FILE foo;
X#endif /* VPRINTF */
X char msgbuf[BUFSIZ]; /* we're not getting huge strings */
X char *fmt;
X va_list args;
X
X if (istool < 2) {
X va_start(args);
X fmt = va_arg(args, char *);
X#ifdef VPRINTF
X (void) vprintf(fmt, args);
X#else /* VPRINTF */
X _doprnt(fmt, args, stdout);
X#endif /* VPRINTF */
X va_end(args);
X (void) fflush(stdout);
X return;
X }
X if (!compose_frame || !window_get(compose_frame, WIN_SHOW) || !cprint_sw)
X wprint_sw = mfprint_sw;
X else
X wprint_sw = cprint_sw;
X
X if (!wprint_sw)
X return;
X va_start(args);
X fmt = va_arg(args, char *);
X if (fmt) {
X#ifdef VPRINTF
X (void) vsprintf(msgbuf, fmt, args); /* NULL in fmt reprints last msg */
X#else /* VPRINTF */
X foo._cnt = BUFSIZ;
X foo._base = foo._ptr = msgbuf; /* may have to cast (unsigned char *) */
X foo._flag = _IOWRT+_IOSTRG;
X _doprnt(fmt, args, &foo); /* format like printf into msgbuf via foo */
X *foo._ptr = '\0'; /* plant terminating null character */
X#endif /* VPRINTF */
X textsw_insert(wprint_sw, msgbuf, strlen(msgbuf));
X }
X va_end(args);
X}
X
X#include <sundev/kbio.h>
X#include <sundev/kbd.h>
X
Xbell()
X{
X#ifdef KIOCCMD
X if (istool) {
X int kbd = open("/dev/kbd", O_WRONLY, 0);
X struct timeval timer;
X timer.tv_sec = 0;
X timer.tv_usec = 100000;
X if (kbd != -1) {
X int cmd = KBD_CMD_BELL;
X (void) ioctl(kbd, KIOCCMD, &cmd);
X (void) select(32, (fd_set *) 0,(fd_set *) 0,(fd_set *) 0, &timer);
X cmd = KBD_CMD_NOBELL;
X (void) ioctl(kbd, KIOCCMD, &cmd);
X (void) close(kbd);
X }
X } else
X#endif /* KIOCCMD */
X (void) fputc('\007', stderr), (void) fflush(stderr);
X return 0;
X}
X
X#endif /* SUNTOOL */
X
X#ifdef BSD
X#undef fputs
X
X/*
X * The standard 4.x BSD fputs() does not return any useful value.
X * For compatibility with Sun and SysV fputs(), we use this wrapper.
X */
X
XFputs(line, fp)
Xchar *line;
XFILE *fp;
X{
X clearerr(fp);
X (void) fputs(line, fp);
X if (ferror(fp))
X return EOF;
X return 0;
X}
X
X#endif /* BSD */
END_OF_FILE
if test 5410 -ne `wc -c <'mush/print.c'`; then
echo shar: \"'mush/print.c'\" unpacked with wrong size!
fi
# end of 'mush/print.c'
fi
if test -f 'mush/sort.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'mush/sort.c'\"
else
echo shar: Extracting \"'mush/sort.c'\" \(8063 characters\)
sed "s/^X//" >'mush/sort.c' <<'END_OF_FILE'
X/* sort.c 3.0 (c) copyright 1986,1990 (Dan Heller) */
X
X#include "mush.h"
X/* #define MYQSORT */
X
X/* The size of this array should really be bounded by
X * 2 spaces for each possible different sort criteria
X * (one space for each key letter and one per for 'r'),
X * but 16 leaves room to add to the current list.
X */
Xstatic char subsort[16];
X
Xstatic int depth, order, ignore_case;
Xstatic jmp_buf sortbuf;
X
Xsort(argc, argv, list)
Xregister int argc;
Xregister char *argv[], list[];
X{
X int msg_cmp();
X SIGRET (*oldint)(), (*oldquit)();
X int n, offset = -1, range = 0;
X long curr_msg_off = msg[current_msg].m_offset;
X
X depth = 0, order = 1, ignore_case = FALSE;
X
X while (argc && *++argv) {
X n = (argv[0][0] == '-' && argv[0][1] != 0);
X while (argv[0][n]) {
X if (depth > sizeof subsort - 2)
X break;
X switch(argv[0][n]) {
X case '-': /* reverse order of next criteria (obsolete) */
X argv[0][n] = 'r'; /* fix it and fall through */
X case 'r': /* reverse order of next criteria */
X case 'd': /* sort by date */
X case 'a': /* sort by author (address) */
X case 's': /* sort by subject (ignore Re:) */
X case 'R': /* sort by subject including Re: */
X case 'l': /* sort by length in bytes */
X case 'S': /* sort by message status */
X /* skip consecutive repeats of the same flag */
X if (subsort[depth-1] != argv[0][n])
X subsort[depth++] = argv[0][n];
X when 'i': ignore_case = TRUE;
X otherwise: return help(0, "sort", cmd_help);
X }
X n++;
X }
X }
X if (depth == 0 || subsort[depth-1] == 'r')
X subsort[depth++] = 'S'; /* status sort is the default */
X subsort[depth] = 0;
X depth = 0; /* start at the beginning */
X if (msg_cnt <= 1) {
X print("Not enough messages to sort.\n");
X return -1;
X }
X turnon(glob_flags, IGN_SIGS);
X on_intr();
X
X if (list && ison(glob_flags, IS_PIPE)) {
X for (n = 0; n < msg_cnt; n++)
X if (msg_bit(list, n)) {
X if (offset < 0)
X offset = n;
X range++;
X } else if (offset >= 0)
X break;
X } else
X offset = 0, range = msg_cnt;
X
X if (range < 2)
X print("Range not broad enough to sort anything\n");
X else {
X Debug("Sorting %d messages starting at message %d\n", range, offset+1);
X
X if (setjmp(sortbuf) == 0)
X qsort((char *)&msg[offset], range, sizeof (struct msg), msg_cmp);
X else
X print("WARNING: Sorting interrupted: unpredictable order.\n");
X turnon(glob_flags, DO_UPDATE);
X }
X for (n = 0; n < msg_cnt; n++)
X if (msg[n].m_offset == curr_msg_off)
X break;
X current_msg = n;
X turnoff(glob_flags, IGN_SIGS);
X off_intr();
X /* Break pipes because message lists are invalid */
X return 0 - in_pipe();
X}
X
X#ifdef MYQSORT
Xqsort(base, len, siz, compar)
Xregister struct msg *base;
Xint (*compar)();
X{
X register int i, swapping;
X struct msg temp;
X
X do {
X swapping = 0;
X for (i = 0; i < len-1; ++i) {
X if (compar(base+i, base+i+1) > 0) {
X temp = base[i];
X base[i] = base[i+1];
X base[i+1] = temp;
X swapping = 1;
X }
X }
X } while (swapping);
X}
X#endif /* MYSORT */
X
Xstatus_cmp(msg1, msg2)
Xregister struct msg *msg1, *msg2;
X{
X if (msg1->m_flags == msg2->m_flags)
X return msg_cmp(msg1, msg2);
X if (ison(msg1->m_flags, DELETE) && isoff(msg2->m_flags, DELETE))
X return order;
X if (isoff(msg1->m_flags, DELETE) && ison(msg2->m_flags, DELETE))
X return -order;
X if (isoff(msg1->m_flags, OLD) && ison(msg2->m_flags, OLD))
X return -order;
X if (ison(msg1->m_flags, OLD) && isoff(msg2->m_flags, OLD))
X return order;
X if (ison(msg1->m_flags, UNREAD) && isoff(msg2->m_flags, UNREAD))
X return -order;
X if (isoff(msg1->m_flags, UNREAD) && ison(msg2->m_flags, UNREAD))
X return order;
X if (ison(msg1->m_flags,PRESERVE) && isoff(msg2->m_flags,PRESERVE))
X return -order;
X if (isoff(msg1->m_flags,PRESERVE) && ison(msg2->m_flags,PRESERVE))
X return order;
X if (ison(msg1->m_flags,REPLIED) && isoff(msg2->m_flags,REPLIED))
X return -order;
X if (isoff(msg1->m_flags,REPLIED) && ison(msg2->m_flags,REPLIED))
X return order;
X if (ison(msg1->m_flags,SAVED) && isoff(msg2->m_flags,SAVED))
X return -order;
X if (isoff(msg1->m_flags,SAVED) && ison(msg2->m_flags,SAVED))
X return order;
X if (ison(msg1->m_flags,PRINTED) && isoff(msg2->m_flags,PRINTED))
X return -order;
X if (isoff(msg1->m_flags,PRINTED) && ison(msg2->m_flags,PRINTED))
X return order;
X if (ison(msg1->m_flags,FORWARD) && isoff(msg2->m_flags,FORWARD))
X return -order;
X if (isoff(msg1->m_flags,FORWARD) && ison(msg2->m_flags,FORWARD))
X return order;
X
X return order;
X}
X
Xauthor_cmp(msg1, msg2)
Xregister struct msg *msg1, *msg2;
X{
X char buf1[HDRSIZ], buf2[HDRSIZ];
X int retval;
X
X (void) reply_to(msg1 - msg, 0, buf1); /* "0" for "author only" */
X (void) reply_to(msg2 - msg, 0, buf2);
X Debug("author: msg %d: %s, msg %d: %s\n", msg1-msg, buf1, msg2-msg, buf2);
X if (ignore_case)
X retval = lcase_strncmp(buf1, buf2, -1) * order;
X else
X retval = strcmp(buf1, buf2) * order;
X return retval ? retval : msg_cmp(msg1, msg2);
X}
X
X/* compare messages according to size (length) */
Xsize_cmp(msg1, msg2)
Xregister struct msg *msg1, *msg2;
X{
X int retval;
X
X Debug("sizes: (%d): %d, (%d): %d\"\n",
X msg1-msg, msg1->m_size, msg2-msg, msg2->m_size);
X if (retval = (msg1->m_size - msg2->m_size) * order) /* assign and test */
X return retval;
X return msg_cmp(msg1, msg2);
X}
X
X/*
X * Subject comparison ignoring Re: subject_to() appends an Re: if there is
X * any subject whatsoever.
X */
Xsubject_cmp(msg1, msg2)
Xregister struct msg *msg1, *msg2;
X{
X char buf1[HDRSIZ], buf2[HDRSIZ];
X register char *p1, *p2;
X int retval;
X
X p1 = subject_to(msg1 - msg, buf1);
X p2 = subject_to(msg2 - msg, buf2);
X if (p1) {
X p1 += 4;
X while (isspace(*p1))
X p1++;
X } else
X p1 = buf1; /* subject_to() makes it an empty string */
X if (p2) {
X p2 += 4;
X while (isspace(*p2))
X p2++;
X } else
X p2 = buf2; /* subject_to() makes it an empty string */
X Debug("subjects: (%d): \"%s\" (%d): \"%s\"\n", msg1-msg, p1, msg2-msg, p2);
X if (ignore_case)
X retval = lcase_strncmp(p1, p2, -1) * order;
X else
X retval = strcmp(p1, p2) * order;
X return retval ? retval : msg_cmp(msg1, msg2);
X}
X
X/*
X * compare subject strings from two messages.
X * If Re is appended, so be it -- if user wants to ignore Re: use 'R' flag.
X */
Xsubj_with_re(msg1, msg2)
Xregister struct msg *msg1, *msg2;
X{
X char buf1[HDRSIZ], buf2[HDRSIZ], *p;
X int retval;
X
X if (!(p = header_field(msg1 - msg, "subject")))
X p = "";
X (void) strcpy(buf1, p);
X if (!(p = header_field(msg2 - msg, "subject")))
X p = "";
X (void) strcpy(buf2, p);
X Debug("subjects: (%d): \"%s\" (%d): \"%s\"\n",
X msg1-msg, buf1, msg2-msg, buf2);
X if (ignore_case)
X retval = lcase_strncmp(buf1, buf2, -1) * order;
X else
X retval = strcmp(buf1, buf2) * order;
X return retval ? retval : msg_cmp(msg1, msg2);
X}
X
Xdate_cmp(msg1, msg2)
Xregister struct msg *msg1, *msg2;
X{
X int retval;
X long tm1, tm2;
X
X if (ison(glob_flags, DATE_RECV)) {
X (void) sscanf(msg1->m_date_recv, "%ld", &tm1);
X (void) sscanf(msg2->m_date_recv, "%ld", &tm2);
X } else {
X (void) sscanf(msg1->m_date_sent, "%ld", &tm1);
X (void) sscanf(msg2->m_date_sent, "%ld", &tm2);
X }
X return tm1 < tm2 ? -order : (tm1 > tm2) ? order : msg_cmp(msg1, msg2);
X}
X
Xstatic
Xmsg_cmp(msg1, msg2)
Xregister struct msg *msg1, *msg2;
X{
X int sv_order = order, sv_depth = depth, retval = 0;
X
X if (ison(glob_flags, WAS_INTR))
X longjmp(sortbuf, 1);
X if (msg1 < msg || msg2 < msg) {
X wprint("sort botch trying to sort %d and %d using %s\n",
X msg1-msg, msg2-msg, subsort);
X return 0;
X }
X
X if (subsort[depth] == 'r') {
X order = -1;
X depth++;
X } else
X order = 1;
X switch(subsort[depth++]) {
X case '\0': retval = 0;
X when 'd': retval = date_cmp(msg1, msg2);
X when 'a': retval = author_cmp(msg1, msg2);
X when 's': retval = subject_cmp(msg1, msg2);
X when 'R': retval = subj_with_re(msg1, msg2);
X when 'l': retval = size_cmp(msg1, msg2); /* length compare */
X otherwise: retval = status_cmp(msg1, msg2);
X }
X depth = sv_depth;
X order = sv_order;
X return retval;
X}
END_OF_FILE
if test 8063 -ne `wc -c <'mush/sort.c'`; then
echo shar: \"'mush/sort.c'\" unpacked with wrong size!
fi
# end of 'mush/sort.c'
fi
echo shar: End of archive 18 \(of 19\).
cp /dev/null ark18isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 19 archives.
rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0