[comp.sources.unix] v18i027: Mail user's shell version 6.4, Part05/19

rsalz@bbn.com (Rich Salz) (03/16/89)

Submitted-by: Dan Heller <island!argv@sun.com>
Posting-number: Volume 18, Issue 27
Archive-name: mush6.4/part05



#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 5 (of 19)."
# Contents:  doproc.c file.c signals.c strings.c
# Wrapped by rsalz@papaya.bbn.com on Mon Mar 13 19:25:11 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'doproc.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'doproc.c'\"
else
echo shar: Extracting \"'doproc.c'\" \(12131 characters\)
sed "s/^X//" >'doproc.c' <<'END_OF_FILE'
X/* @(#)doproc.c		(c) copyright	10/18/86 (Dan Heller) */
X
X/* do main panel item procedures */
X#include "mush.h"
X
Xrespond_mail(item, value, event)
XPanel_item item;
Xint value;
Xstruct inputevent *event;
X{
X    char buf[80];
X
X    if (value == 4)
X	return help(panel_sw->ts_windowfd, "respond", tool_help);
X    if (ison(glob_flags, IS_GETTING)) {
X	print("Finish editing current message first");
X	return;
X    }
X    if (!msg_cnt) {
X	print("No messages to respond to.\n");
X	return;
X    }
X    print("Responding to message %d", current_msg+1);
X    if (event && event->ie_code == MS_LEFT)
X	value = 0;
X    (void) sprintf(buf, "%s %s %d",
X	(value == 2 || value == 3)? "replyall" : "replysender",
X	(value == 1 || value == 3)? "-i": NO_STRING, current_msg+1);
X    (void) cmd_line(buf, msg_list);
X}
X
X/* following macro is for the next two procedures */
X#define hdr_item (item == sub_hdr_item[0] || item == sub_hdr_item[1] || \
X                  item == sub_hdr_item[2] || item == sub_hdr_item[3] || \
X                  item == sub_hdr_item[4] || item == sub_hdr_item[5])
X
Xdelete_mail(item, value, event)
Xregister Panel_item item;
Xint value;
Xregister struct inputevent *event;
X{
X    int val = value; /* save cuz we reset value immediately */
X    u_long bang = ison(glob_flags, IGN_BANG);
X    char buf[128];
X
X    panel_set(item, PANEL_VALUE, 0, 0);
X    if (hdr_item && event->ie_code != MS_LEFT || val == 2)
X	return help(panel_sw->ts_windowfd, "delete", tool_help);
X    /* delete current message */
X    print(sprintf(buf, "%sdelete %s",
X	((event->ie_code == MS_LEFT || val == 0)? "" : "un"),
X	panel_get_value(msg_num_item)));
X    turnon(glob_flags, IGN_BANG);
X    (void) cmd_line(buf, msg_list);
X    if (!bang)
X	turnoff(glob_flags, IGN_BANG);
X}
X
Xread_mail(item, value, event)
Xregister Panel_item item;
Xregister int value;
Xregister struct inputevent *event;
X{
X    register int this_msg = current_msg;
X
X    /* check "event" in case we were called from select.c
X     * in which case event would be NULL
X     */
X    if (event && event->ie_code == MS_RIGHT &&
X        item && (item == read_item && value ||
X	(item == sub_hdr_item[0] || item == sub_hdr_item[1])))
X	return help(panel_sw->ts_windowfd, "next", tool_help);
X    if (item && (item == sub_hdr_item[4] || item == sub_hdr_item[5]))
X	return help(panel_sw->ts_windowfd, "msg_menu", tool_help);
X    if (!msg_cnt) {
X	print ("No Mail.");
X	return -1;
X    }
X    if (item && item == read_item || ison(msg[current_msg].m_flags, DELETE))
X	(void) next_msg();
X    if (this_msg != current_msg || ison(msg[current_msg].m_flags, UNREAD) ||
X	    (current_msg < n_array[0] || current_msg > n_array[screen])) {
X	set_isread(current_msg);
X	(void) do_hdrs(0, DUBL_NULL, NULL);
X    }
X    if (isoff(msg[current_msg].m_flags, DELETE))
X	display_msg(current_msg, (long)0);
X    return -1;
X}
X
X/* the panel button that says "filename" and "directory", etc... text item */
Xfile_dir(item, event)
XPanel_item item;
Xstruct inputevent *event;
X{
X    register char *p;
X    u_long bang = ison(glob_flags, IGN_BANG);
X    char buf[128], *which = panel_get(item, PANEL_LABEL_STRING);
X
X    if (!strcmp(which, "folder:"))
X	if (event->ie_code == '\n' || event->ie_code == '\r')
X	    (void) sprintf(buf, "folder %s", panel_get_value(item));
X	else
X	    (void) sprintf(buf, "folder ! %s", panel_get_value(item));
X
X    else if (!strcmp(which, "directory:"))
X	(void) sprintf(buf, "cd %s", panel_get_value(item));
X
X    else if (!msg_cnt)
X	print("No messages to save");
X
X    else if (!strcmp(which, "filename:")) {
X	int x = 1;
X	register char *b = buf;
X	if (event->ie_code == '\n' || event->ie_code == '\r')
X	    b += Strcpy(buf, "save  ");
X	else
X	    b += Strcpy(buf, "write ");
X	if ((p = panel_get_value(msg_num_item)) && *p)
X	    b += Strcpy(b, p);
X	else
X	    b += strlen(sprintf(b, "%d", current_msg+1));
X	*b++ = ' ', *b = 0;
X	if (!(p = panel_get_value(item)) || !*p &&
X	    (!(p = do_set(set_options, "mbox")) || !*p))
X		p = DEF_MBOX;
X	print(buf), print_more("in %s?", p); /* prompt before adding to cmd */
X	(void) strcpy(b, p); /* now add to command */
X	if ((x = confirm(print_sw->ts_windowfd)) != 'y' && x != MS_LEFT) {
X	    print("Message not saved");
X	    return;
X	}
X    }
X    turnon(glob_flags, IGN_BANG);
X    (void) cmd_line(buf, msg_list);
X    if (!bang)
X	turnoff(glob_flags, IGN_BANG);
X}
X
Xdo_file_dir(item, value, event)
XPanel_item item;
Xint value;
Xstruct inputevent *event;
X{
X    char buf[92];
X    u_long bang = ison(glob_flags, IGN_BANG);
X    int x; /* used for confirmation */
X
X    if (item == folder_item) {
X	(void) strcpy(buf, "folder ");
X	if (event->ie_code == MS_LEFT) {
X	    print("Current folder is: \"%s\"", mailfile);
X	    panel_set(file_item, PANEL_LABEL_STRING, "folder:", 0);
X	    panel_set(file_item, PANEL_MENU_CHOICE_STRINGS,
X			    "Change without updating current folder", 0, 0);
X	} else {
X	    if (!value)
X		(void) strcat(buf, "%");
X	    else if (value == 1)
X		(void) strcat(buf, "&");
X	    else if (value == 2)
X		(void) strcat(buf, "#");
X	    else {
X		(void) sprintf(buf, "folder %s",
X			      panel_get(item, PANEL_CHOICE_STRING, value));
X		if (!strcmp(buf+7, "Help"))
X		    return help(panel_sw->ts_windowfd, "folder", tool_help);
X	    }
X	}
X    } else if (item == cd_item) {
X	(void) strcpy(buf, "cd ");
X	if (event->ie_code == MS_LEFT || !value) {
X	    panel_set(file_item, PANEL_LABEL_STRING, "directory:", 0);
X	    panel_set(file_item, PANEL_MENU_CHOICE_STRINGS,
X				"Change to specified directory", 0, 0);
X	} else if (value == 1)
X	    (void) strcat(buf, "~");
X	else if (value == 2)
X	    (void) strcat(buf, "+");
X	else
X	    return help(panel_sw->ts_windowfd, "chdir", tool_help);
X    } else if (item == save_item) {
X	(void) strcpy(buf, "save ");
X	if (event->ie_code == MS_LEFT)
X	    if (!strcmp("filename:", panel_get(file_item,PANEL_LABEL_STRING))) {
X		event->ie_code = '\n';  /* let file_dir think it got a \n */
X		return file_dir(file_item, event);
X	    } else {
X		panel_set(file_item, PANEL_LABEL_STRING, "filename:", 0);
X		panel_set(file_item, PANEL_MENU_CHOICE_STRINGS,
X			"Save message WITHOUT headers", 0,0);
X		print("Type in Main Panel Window a filename to save message");
X		return;
X	    }
X	else if (value == 0) {
X	    register char *p = panel_get_value(file_item);
X	    register char *p2 = panel_get_value(msg_num_item);
X	    if ((!p || !*p) && (!(p = do_set(set_options, "mbox")) || !*p))
X		p = DEF_MBOX;
X	    print("Save in %s? ", p);
X	    if ((x = confirm(panel_sw->ts_windowfd)) != 'y' && x != MS_LEFT) {
X		print("Message not saved");
X		return;
X	    }
X	    if (p2 && *p2) {
X		(void) strcat(buf, p2);
X		panel_set(msg_num_item, PANEL_VALUE, NO_STRING, 0);
X		(void) strcat(buf, " ");
X	    }
X	    (void) strcat(buf, p);
X	} else {
X	    (void) sprintf(buf, "save %s",
X		panel_get(item, PANEL_CHOICE_STRING, value));
X	    if (!strcmp(buf+5, "Help"))
X		return help(panel_sw->ts_windowfd, "save", tool_help);
X	}
X    }
X    turnon(glob_flags, IGN_BANG);
X    (void) cmd_line(buf, msg_list);
X    if (!bang)
X	turnoff(glob_flags, IGN_BANG);
X    panel_set(item, PANEL_VALUE, NO_STRING, 0); /* remove last value */
X}
X
Xtext_done(item, event)
XPanel_item item;
Xstruct inputevent *event;
X{
X    char opt[30], buf[82], cmd[82];
X    register char *p;
X    u_long bang = ison(glob_flags, IGN_BANG);
X    Panel_item which = NO_ITEM;
X    int set_it;
X
X    if ((event->ie_code == '\n' || event->ie_code == '\r') && 
X				 *strcpy(buf, panel_get_value(item))) {
X	(void) strcpy(opt, panel_get(item, PANEL_LABEL_STRING));
X	set_it = (*opt == 'S');
X	if (!(p = index(opt, ' '))) {
X	    print("Hmmm... there seems to be a problem here.");
X	    return;
X	}
X	++p;
X	switch(lower(*p)) {
X	    case 'o':
X		(void) sprintf(cmd, "%set %s", (set_it)? "s": "uns", buf);
X		which = option_item;
X	    when 'i':
X		(void) sprintf(cmd, "%sgnore %s", (set_it)? "i": "uni", buf);
X		which = ignore_item;
X	    when 'a':
X		(void) sprintf(cmd, "%slias %s", (set_it)? "a": "una", buf);
X		which = alias_item;
X	    otherwise: print("HUH!? (%c)", *p); return;
X	}
X	turnon(glob_flags, IGN_BANG);
X	(void) cmd_line(cmd, msg_list);
X	if (!bang)
X	    turnoff(glob_flags, IGN_BANG);
X    }
X    panel_set(input_item, PANEL_VALUE, NO_STRING, 0); /* remove last value */
X    panel_set(item, PANEL_SHOW_ITEM, FALSE, 0);
X}
X
Xdo_help(item, value, event)
XPanel_item item;
Xregister int value;
Xstruct inputevent *event;
X{
X    register char *p, *helpfile = tool_help;
X    switch(value) {
X	case 1: p = "help";
X	when 2: p = "mouse";
X	when 3: p = "windows";
X	when 4: p = "function keys";
X	when 5: p = "hdr_format", helpfile = cmd_help;
X	when 6: p = "msg_list", helpfile = cmd_help;
X	otherwise: p = "general";
X    }
X    (void) help(panel_sw->ts_windowfd, p, helpfile);
X}
X
Xtoolquit(item, value, event)
XPanel_item item;
Xint value;
Xstruct inputevent *event;
X{
X    register int which;
X
X    if (!value || event->ie_code == MS_LEFT) {
X	if (ison(glob_flags, DO_UPDATE)) {
X	    do_update(NO_ITEM, 0, NO_EVENT);
X	    turnoff(glob_flags, NEW_MAIL);
X	    mail_status(0); /* lower flag (if up) print current num of msgs */
X	}
X	wmgr_changestate (tool->tl_windowfd, rootfd, TRUE);
X	wmgr_changelevel (tool->tl_windowfd, parentfd, TRUE);
X	return;
X    } else if (value == 2) {
X	(void) help(panel_sw->ts_windowfd, "quit", tool_help);
X	return;
X    }
X    print("Left updates changes. Middle does not. Right aborts quit.");
X    if ((which = confirm(panel_sw->ts_windowfd)) == MS_RIGHT) {
X	print("Quit aborted.");
X	return;
X    }
X    abort_mail(NO_ITEM, 0);
X    if (which == MS_LEFT)
X	lock_cursors(), copyback();
X    else
X	print("Bye bye");
X    cleanup(0);
X}
X
Xdo_lpr(item, value, event)
XPanel_item item;
Xint value;
Xstruct inputevent *event;
X{
X    char buf[128];
X
X    if (event && (event->ie_code == MS_LEFT || value == 1)) {
X	print("Sending message %d to printer...", current_msg+1);
X	(void) strcpy(buf, "lpr ");
X	if (value)
X	    (void) sprintf(buf, "lpr \"%s\"", panel_get_value(msg_num_item));
X	lock_cursors();
X	(void) cmd_line(buf, msg_list);
X	unlock_cursors();
X    } else
X	(void) help(panel_sw->ts_windowfd, "printer", tool_help);
X}
X
Xdo_clear()
X{
X    /* actions that clears window indicates user wants to quit getting opts */
X    if (msg_pix)
X	pr_destroy(msg_pix), msg_pix = (struct pixrect *)NULL;
X    if (getting_opts)
X	getting_opts = 0, unlock_cursors();
X    pw_writebackground(msg_win, 0,0, msg_rect.r_width,msg_rect.r_height,
X		       PIX_CLR);
X    txt.x = 5, txt.y = l_height(curfont) - 1;
X}
X
Xdo_update(item, value, event)
XPanel_item item;
Xregister int value;
Xstruct inputevent *event;
X{
X    char *argv[2];
X    if (event && event->ie_code != MS_LEFT)
X	return help(panel_sw->ts_windowfd, "update", tool_help);
X    argv[0] = "update";
X    argv[1] = NULL;
X    (void) folder(0, argv, NULL);
X}
X
X/* panel selction button to send a letter.
X * add a CR if necessary, and finish up letter
X */
Xdo_send(item, value, event)
XPanel_item item;
Xregister int value;
Xregister struct inputevent *event;
X{
X    if (event->ie_code != MS_LEFT)
X	return help(panel_sw->ts_windowfd, "send", tool_help);
X    if (txt.x > 5) {
X	type_cursor(PIX_CLR);
X	add_to_letter(rite('\n')); /* if line isn't complete, flush it */
X    }
X    finish_up_letter();
X}
X
Xdo_edit(item, value, event)
XPanel_item item;
Xregister int value;
Xregister struct inputevent *event;
X{
X    char buf[4];
X    if (event->ie_code != MS_LEFT)
X	return help(panel_sw->ts_windowfd, "edit", tool_help);
X    if (txt.x > 5)
X	add_to_letter(rite('\n')); /* flush line for him */
X    add_to_letter(sprintf(buf, "%cv", *escape));
X}
X
Xdo_compose(item, value, event)
XPanel_item item;
Xregister int value;
Xstruct inputevent *event;
X{
X    if (event && event->ie_code != MS_LEFT)
X	return help(panel_sw->ts_windowfd, "compose", tool_help);
X    print("Composing letter.");
X    win_setcursor(msg_sw->ts_windowfd, &write_cursor);
X    clear_msg_list(msg_list);
X    do_mail(0, DUBL_NULL, msg_list);
X}
X
Xchange_font(item, value, event)
XPanel_item item;
Xregister int value;
Xstruct inputevent event;
X{
X    if (ison(glob_flags, IS_GETTING))
X	type_cursor(PIX_XOR);
X    curfont = value % total_fonts;
X    print("New font: %s\n",
X	    (!curfont)? "Normal": (curfont == 1)? "Small": "Large");
X    if (ison(glob_flags, IS_GETTING))
X	type_cursor(PIX_XOR);
X    crt = msg_rect.r_height / l_height(curfont);
X}
END_OF_FILE
if test 12131 -ne `wc -c <'doproc.c'`; then
    echo shar: \"'doproc.c'\" unpacked with wrong size!
fi
# end of 'doproc.c'
fi
if test -f 'file.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'file.c'\"
else
echo shar: Extracting \"'file.c'\" \(9633 characters\)
sed "s/^X//" >'file.c' <<'END_OF_FILE'
X/* file.c -- Copyright (1988) Dan Heller */
X
X#include "mush.h"
X#include <pwd.h>
X
X/* takes string 'p' and address of int (isdir).  If p uses the ~ to reference
X * a home directory of some sort, then expand it.  find out what sort of
X * file final path is. set isdir to 1 if a directory, 0 if not, -1 on error
X * return final path. If an error occurs, return string indicating error.
X * if isdir has a value of 1 when passed, it ignores "No such file or directory"
X */
Xchar *
Xgetpath(p, isdir)
Xregister char *p;
Xint *isdir;
X{
X    static char buf[BUFSIZ];
X    struct stat stat_buf;
X
X    if (!p || !*p || !strcmp(p, "~")) {
X	char *home = do_set(set_options, "home");
X	if (!home || !*home)
X	    home = ALTERNATE_HOME;
X	(void) strcpy(buf, home);  /* no arg means home */
X    } else if (*p == '~') {
X	if (p[1] != '/') {
X	    /* not our home, but someone else's
X	     * look for ~user or ~user/subpath
X	     * if '/' exists, separate into tmp="user" p="subpath"
X	     */
X	    struct passwd *ent, *getpwnam();
X	    char *p2 = p+1;
X	    if (p = index(p2, '/'))
X		*p++ = 0;
X	    if (!(ent = getpwnam(p2))) {
X		*isdir = -1;
X		return sprintf(buf, "no such user: %s", p2);
X	    }
X	    /* append subpath to pathname */
X	    if (p && *p)
X		(void) sprintf(buf, "%s/%s", ent->pw_dir, p);
X	    /* if *p == NULL, pathname is done (buf), set isdir = 1 */
X	    else {
X		*isdir = 1;
X		return strcpy(buf, ent->pw_dir);
X	    }
X	} else {
X	    char *home = do_set(set_options, "home");
X	    if (!home || !*home)
X		home = ALTERNATE_HOME;
X	    (void) sprintf(buf, "%s/%s", home, p+2);
X	}
X    } else if (*p == '%') {
X	/* if %user, append user name... else, it's just us */
X	if (!*++p || *p == ' ' || *p == '\t')
X	    (void) strcpy(buf, spoolfile);
X	else
X#ifndef HOMEMAIL
X	    (void) sprintf(buf, "%s/%s", MAILDIR, p);
X#else /* HOMEMAIL */
X	{
X	    char *p2 = do_set(set_options, "home");
X	    (void) sprintf(buf, "%s/%s", p2 ? p2 : ALTERNATE_HOME, MAILFILE);
X	} else {
X	    int t_isdir = *isdir;
X	    char *t, tmp[256];
X	    (void) sprintf(tmp, "~%s/%s", p, MAILFILE);
X	    t = getpath(tmp, &t_isdir);
X	    if (t_isdir == -1) {
X		*isdir = -1;
X		return t;
X	    }
X	    /* strcpy(buf, t); --buf already has info because it's static */
X	}
X#endif /* HOMEMAIL */
X    } else if (*p == '+') {
X	register char *p2 = do_set(set_options, "folder");
X	if (!p2 || !*p2)
X	    p2 = DEF_FOLDER;
X	(void) sprintf(buf, "%s/%s", p2, ++p);
X	if (*buf != '/') {
X	    int t_isdir = *isdir;
X	    char *t, tmp[256];
X	    if (*buf != '~')
X		(void) sprintf(tmp, "~/%s", buf);
X	    else
X		(void) strcpy(tmp, buf);
X	    t = getpath(tmp, &t_isdir);
X	    if (t_isdir == -1) {
X		*isdir = -1;
X		return t;
X	    }
X	    /* strcpy(buf, t); --buf already has info because it's static */
X	}
X    } else {  /* allow \ to escape the special chars, +, %, ~ */
X	if (*p == '\\')
X	    p++;
X	(void) strcpy(buf, p);
X    }
X    if (stat(buf, &stat_buf)) {
X	(void) access(buf, F_OK); /* set errno to the "real" reason */
X	if (errno == ENOENT && *isdir == 1) {
X	    *isdir = 0; /* say it's a regular file even tho it doesn't exist */
X	    return buf; /* it may be wanted for creating */
X	}
X	*isdir = -1;
X	return sys_errlist[errno];
X    }
X    *isdir = ((stat_buf.st_mode & S_IFDIR) != 0);
X    return buf;
X}
X
X/*
X * Given a filename[pointer] (p), a file pointer, and a mode, file_to_fp
X * opens the file with the mode.
X * If the mode is "r" then we read the file into the file pointer at the
X * end (fseek(fp, 2, 0)).  If the file is opened for writing, then read
X * from the beginning of fp and write it into the file.
X * This is usually called to read .signatures into messages (thus,
X * opening .signature with "r" and writing to the end of fp which is probably
X * the sendmail process or the message file pointer) or to write fortunes into
X * the message buffer: reading fp (the popened fortune) and writing into file.
X */
Xvoid
Xfile_to_fp(p, fp, mode)
Xregister char *p;
Xregister FILE *fp;
Xchar *mode;
X{
X    int 	x = 1;
X    char 	*file, buf[BUFSIZ];
X    FILE 	*tmp_fp;
X
X    if (!p || !*p) {
X	print("specify filename");
X	return;
X    }
X    file = getpath(p, &x);
X    if (x == -1) { /* on error, file contains error message */
X	wprint(file);
X	return;
X    }
X    wprint("%s: ", file);
X    if (x)   /* if x == 1, then path is a directory */
X	wprint("directory.\n");
X    else if (!(tmp_fp = fopen(file, mode))) {
X	wprint("%s\n", sys_errlist[errno]);
X	return;
X    } else if (*mode != 'r') {
X	rewind(fp);
X	for(x = 0; fgets(buf, BUFSIZ, fp); x++)
X	    fputs(buf, tmp_fp);
X    } else
X	for(x = 0; fgets(buf, BUFSIZ, tmp_fp); x++)
X	    fputs(buf, fp);
X    wprint("%s%d line%s\n", (*mode == 'a')? "added ": "",
X				  x, (x == 1)? "": "s");
X    fflush(fp);
X    fclose(tmp_fp);
X}
X
X/* clear all contents of the file.  Careful that the file is opened for
X * _writing_ --tempfile is opened for reading, so don't try to empty it
X * if you're using ftruncate.   Return -1 on error, 0 on success.
X */
Xemptyfile(fp, fname)
Xregister FILE **fp;
Xregister char *fname;
X{
X    Debug("Emptying \"%s\"\n", fname);
X#ifndef SYSV
X    return ftruncate(fileno(*fp), 0L);
X#else
X    {
X	int omask = umask(077), ret;
X	fclose(*fp);
X	if (!(*fp = fopen(fname, "w")))
X	    ret = -1;
X	ret = 0;
X	(void) umask(omask);
X	return ret;
X    }
X#endif /* SYSV */
X}
X
X/*
X * Finds out how many file descriptors are opened.  Useful for making sure
X * no files got opened in subprocedures which were not subsequently closed.
X */
Xnopenfiles(argc)
X{
X    register int nfiles = 0;
X#ifdef MAXFILES
X    register int size = MAXFILES;
X#else
X    register int size = getdtablesize();
X#endif /* MAXFILES */
X
X    if (argc < 2)
X	print("open file descriptors:");
X    while (--size >= 0)
X        if (fcntl(size, F_GETFL, 0) != -1) {
X	    if (argc < 2)
X		print_more(" %d", size);
X            ++nfiles;
X        }
X    if (argc < 2)
X	print("\n");
X    return nfiles;
X}
X
X/*
X * Close all "extraneous" file descriptors; return the number closed
X */
Xclosefileds (n)
X{
X    register int nfiles = 0;
X#ifdef MAXFILES
X    register int size = MAXFILES;
X#else
X    register int size = getdtablesize();
X#endif /* MAXFILES */
X
X    while (--size >= n)
X        if (fcntl(size, F_GETFL, 0) != -1) {
X	    (void) close(size);
X            ++nfiles;
X        }
X    return nfiles;
X}
X
X/*
X * Open a path for writing or appending -- return a FILE pointer.
X * If program is TRUE, then use popen, not fopen and don't check 
X * to see if the file is writable.
X */
XFILE *
Xopen_file(p, program)
Xregister char *p;
X{
X    register FILE *newfile = NULL_FILE;
X    register char *tmp;
X    int x = 1;
X
X    if (program || *p == '/')
X	tmp = p, x = 0;
X    else
X	tmp = getpath(p, &x);
X    if (x == 1)
X	print("%s is a directory.\n", tmp);
X    else if (x == -1)
X	print("%s: %s\n", p, tmp);
X    else {
X	register char *mode = NULL;
X	/* if it doesn't exist open for "w" */
X	if (program || Access(tmp, F_OK))
X	    mode = "w";
X	/* if we can't write to it, forget it */
X	else if (Access(tmp, W_OK))
X	    error(tmp);
X	else
X	    mode = "a";
X	if (mode)
X	    if (program) {
X		if (!(newfile = popen(tmp, mode))) {
X		    error("Can't execute %s\n", tmp);
X		    return newfile;
X		}
X	    } else
X		if (!(newfile = mask_fopen(tmp, mode)))
X		    error("Can't write to %s", tmp);
X	    else
X		Debug("Successfully opened %s\n", tmp);
X    }
X    return newfile;
X}
X
X/*
X * find_files gets a set of addresses and an array of
X * file pointers and the maximum size that array can be.
X * The object is to find the files or programs listed in "s", attempt
X * to fopen/popen them and save their file pointers in the array. If the
X * size is 0, then just extract the file names and give error messages
X * for each one since they will not be opened. Return the number of
X * files opened and delete all files (opened or not) from the list in
X * "s".  Tokens beginning with a "/, ~, or + are files; tokens beginning
X * with a | are programs.
X * The string "s" is modified to be a list of address -- all names AND
X * files are stripped out of the list.
X */
Xfind_files(s, files, size)
Xregister char *s;
XFILE *files[];
X{
X    register int     total = 0, prog;
X    char 	     file[MAXPATHLEN], buf[HDRSIZ], *start = s, c;
X    register char    *p, *b = buf;
X
X    do  {
X	if (!(p = get_name_n_addr(s, NULL, file)))
X	    break;
X	c = *p, *p = 0;
X	/* It's a file -- try to open it.  This doesn't get written back
X	 * onto "buf" since it is supposed to be extracted anyway.
X	 */
X	if (*file == '+' || *file == '~' || *file == '|' || *file == '/') {
X	    prog = (*file == '|');
X	    if (size && total < size) {
X		/* either open "file" or &file[1] */
X		if (files[total] = open_file(&file[prog], prog))
X		    total++;
X	    } else
X		print("No open space for %s\n", file);
X	} else {
X	    b += Strcpy(b, s);
X	    *b++ = ',', *b++ = ' ';
X	}
X	for (*p = c, s = p; *s == ',' || isspace(*s); s++)
X	    ;
X    } while (*s);
X    for (*b-- = 0; b > buf && (*b == ',' || isspace(*b)); b--)
X	*b = 0;
X    (void) strcpy(start, buf);
X    return total;
X}
X
X/*
X * access(2) has an undocumented feature which ignores suid.  If you are
X * su'ed and try to read your mail, you will be unable to because access()
X * will give the illusion that you cannot read/write to your mbox.  Solve
X * the problem by using stat() instead.
X */
XAccess(file, mode)
Xregister char *file;
X{
X    struct stat buf;
X
X    if (stat(file, &buf) == -1)
X	return -1;
X    if (mode == R_OK)
X	return (buf.st_mode & 0400)? 0 : -1;
X    if (mode == W_OK)
X	return (buf.st_mode & 0200)? 0 : -1;
X    return 0;
X}
X
X/*
X * Open a file for read/write/whatever but make sure umask is rw by user only.
X */
XFILE *
Xmask_fopen(file, mode)
Xchar *file, *mode;
X{
X    int omask = umask(077);
X    FILE *fp = fopen(file, mode);
X    (void) umask(omask);
X    return fp;
X}
END_OF_FILE
if test 9633 -ne `wc -c <'file.c'`; then
    echo shar: \"'file.c'\" unpacked with wrong size!
fi
# end of 'file.c'
fi
if test -f 'signals.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'signals.c'\"
else
echo shar: Extracting \"'signals.c'\" \(10419 characters\)
sed "s/^X//" >'signals.c' <<'END_OF_FILE'
X/* @(#)signals.c	(c) copyright 10/18/86 (Dan Heller) */
X
X#include "mush.h"
X
X#ifndef SYSV
Xextern char *sys_siglist[];
X#else
X/* sys-v doesn't have normal sys_siglist */
Xstatic char	*sys_siglist[] = {
X/* no error */  "no error",
X/* SIGHUP */	"hangup",
X/* SIGINT */	"interrupt (rubout)",
X/* SIGQUIT */	"quit (ASCII FS)",
X/* SIGILL */	"illegal instruction (not reset when caught)",
X/* SIGTRAP */	"trace trap (not reset when caught)",
X/* SIGIOT */	"IOT instruction",
X/* SIGEMT */	"EMT instruction",
X/* SIGFPE */	"floating point exception",
X/* SIGKILL */	"kill (cannot be caught or ignored)",
X/* SIGBUS */	"bus error",
X/* SIGSEGV */	"segmentation violation",
X/* SIGSYS */	"bad argument to system call",
X/* SIGPIPE */	"write on a pipe with no one to read it",
X/* SIGALRM */	"alarm clock",
X/* SIGTERM */	"software termination signal from kill",
X/* SIGUSR1 */	"user defined signal 1",
X/* SIGUSR2 */	"user defined signal 2",
X/* SIGCLD */	"death of a child",
X/* SIGPWR */	"power-fail restart"
X};
X#endif /* SYSV */
X
X#ifdef SUNTOOL
Xmsgwin_handlesigwinch()
X{
X    register struct rect rect;
X    if (exec_pid)
X	return;
X    rect = msg_rect;
X    pw_damaged(msg_win);
X    /* this prevents old screen from being lost when editor finishes */
X    if (isoff(glob_flags, IS_GETTING))
X	gfxsw_interpretesigwinch(msg_sw->ts_data);
X    gfxsw_handlesigwinch(msg_sw->ts_data);
X    pw_repairretained(msg_win);
X    pw_donedamaged(msg_win);
X    win_getrect(msg_sw->ts_windowfd, &msg_rect);
X    crt = msg_rect.r_height / l_height(curfont);
X    if (rect.r_height != msg_rect.r_height || rect.r_width != rect.r_width)
X	if (getting_opts == 1)
X	    display_opts(0);
X	else if (getting_opts == 2)
X	    set_fkeys();
X	else if (msg_pix)
X	    scroll_win(0);
X}
X
Xhdrwin_handlesigwinch()
X{
X    register struct rect rect;
X    rect = hdr_rect;
X    pw_damaged(hdr_win);
X    gfxsw_interpretesigwinch(hdr_sw->ts_data);
X    gfxsw_handlesigwinch(hdr_sw->ts_data);
X    pw_repairretained(hdr_win);
X    pw_donedamaged(hdr_win);
X    win_getrect(hdr_sw->ts_windowfd, &hdr_rect);
X    if (rect.r_width != hdr_rect.r_width || rect.r_height != hdr_rect.r_height){
X	pw_writebackground(hdr_win, 0,0,
X			   hdr_rect.r_width, hdr_rect.r_height, PIX_CLR);
X	screen = hdr_rect.r_height/l_height(DEFAULT);
X	(void) do_hdrs(0, DUBL_NULL, NULL);
X    }
X}
X
Xprint_sigwinch()
X{
X    pw_damaged(print_win);
X    gfxsw_handlesigwinch(print_sw->ts_data);
X    pw_writebackground(print_win, 0,0,
X        win_getwidth(print_sw->ts_windowfd),
X	win_getheight(print_sw->ts_windowfd), PIX_CLR);
X    pw_donedamaged(print_win);
X    print(NULL);  /* reprint whatever was there before damage */
X}
X
XSIGRET
Xsigwinchcatcher()
X{
X    tool_sigwinch(tool);
X}
X#endif /* SUNTOOL */
X
XSIGRET
Xintrpt(sig)
X{
X    Debug("interrupt() caught: %d\n", sig);
X    mac_flush();
X    turnon(glob_flags, WAS_INTR);
X}
X
X/*
X * catch signals to reset state of the machine.  Always print signal caught.
X * If signals are ignored, return.  If we're running the shell, longjmp back.
X */
X/*ARGSUSED*/
XSIGRET
Xcatch(sig)
X{
X    Debug("Caught signal: %d\n", sig);
X    (void) signal(sig, catch);
X    if (ison(glob_flags, IGN_SIGS) && sig != SIGTERM && sig != SIGHUP)
X	return;
X    mac_flush();
X    print("%s: %s\n", prog_name, sys_siglist[sig]);
X    turnoff(glob_flags, IS_PIPE);
X    if (istool || sig == SIGTERM || sig == SIGHUP) {
X	if (istool) /* istool is 2 if tool is complete */
X	    istool = 1;
X	(void) setjmp(jmpbuf);
X	if (ison(glob_flags, IS_GETTING))
X	    rm_edfile(-1);
X	cleanup(sig);
X    }
X    if (ison(glob_flags, DO_SHELL)) {
X	/* wrapcolumn may have been trashed -- restore it */
X	if (ison(glob_flags, IS_GETTING)) {
X	    char *fix = do_set(set_options, "wrapcolumn");
X	    if (fix && *fix)
X		wrapcolumn = atoi(fix);
X	}
X	turnoff(glob_flags, IS_GETTING);
X	longjmp(jmpbuf, 1);
X    } else
X	puts("exiting"), cleanup(sig);
X}
X
X#ifdef SIGCONT
XSIGRET
Xstop_start(sig)
X{
X    extern FILE *ed_fp;
X
X    Debug("Caught signal: %d", sig);
X    if (sig == SIGCONT) {
X	(void) signal(SIGTSTP, stop_start);
X	(void) signal(SIGCONT, stop_start);
X	echo_off();
X	if (istool || ison(glob_flags, IGN_SIGS) && !iscurses)
X	    return;
X	/* we're not in an editor but we're editing a letter */
X	if (ison(glob_flags, IS_GETTING)) {
X	    if (ed_fp)
X		print("(Continue editing letter)\n");
X	}
X#ifdef CURSES
X	else if (iscurses)
X	    if (ison(glob_flags, IGN_SIGS)) {
X		clr_bot_line();
X		if (msg_list)
X		    puts(compose_hdr(current_msg));
X		mail_status(1), addstr("...continue... ");
X		refresh();
X	    } else {
X		int curlin = max(1, current_msg - n_array[0] + 1);
X		redraw();
X		print("Continue");
X		move(curlin, 0);
X		refresh();
X		/* make sure we lose reverse video on continuation */
X		if (ison(glob_flags, REV_VIDEO) && msg_cnt) {
X		    char buf[256];
X		    (void) strncpy(buf, compose_hdr(current_msg), COLS-1);
X		    buf[COLS-1] = 0; /* strncpy does not null terminate */
X		    mvaddstr(curlin, 0, buf);
X		}
X	    }
X#endif /* CURSES */
X  	else
X	    mail_status(1), fflush(stdout);
X    } else {
X#ifdef CURSES
X	if (iscurses) {
X	    /* when user stops mush, the current header is not in reverse
X	     * video -- note that a refresh() has not been called in curses.c!
X	     * so, make sure that when a continue is called, the reverse video
X	     * for the current message returns.
X	     */
X	    turnon(glob_flags, WAS_INTR);
X	    if (isoff(glob_flags, IGN_SIGS) && ison(glob_flags, REV_VIDEO) &&
X		    msg_cnt) {
X		int curlin = max(1, current_msg - n_array[0] + 1);
X		char buf[256];
X		scrn_line(curlin, buf);
X		STANDOUT(curlin, 0, buf);
X	    }
X	    print("Stopping...");
X	}
X#endif /* CURSES */
X	echo_on();
X	(void) signal(SIGTSTP, SIG_DFL);
X	(void) signal(SIGCONT, stop_start);
X	(void) kill(getpid(), sig);
X    }
X}
X#endif /* SIGCONT */
X
X/*ARGSUSED*/
Xvoid
Xcleanup(sig)
X{
X    char buf[128], c;
X    if (sig != SIGTERM && sig != SIGHUP && ison(glob_flags, IGN_SIGS))
X	c = 'n';
X    else
X	c = 'y';
X
X#ifdef CURSES
X    if (iscurses)
X	iscurses = FALSE, endwin();
X#endif /* CURSES */
X
X    echo_on();
X
X    if (ison(glob_flags, IS_GETTING))
X	turnoff(glob_flags, IS_GETTING), dead_letter();
X    if ((sig == SIGSEGV || sig == SIGBUS) && isoff(glob_flags, IGN_SIGS)
X	&& *tempfile) {
X	fprintf(stderr, "remove %s [y]? ", tempfile), fflush(stderr);
X	if (fgets(buf, sizeof(buf), stdin))
X	    c = lower(*buf);
X    }
X    if (c != 'n' && *tempfile && unlink(tempfile) && !sig && errno != ENOENT)
X	error(tempfile);
X    if (sig == SIGSEGV || sig == SIGBUS) {
X	if (isoff(glob_flags, IGN_SIGS)) {
X	    fprintf(stderr, "coredump [n]? "), fflush(stderr);
X	    if (fgets(buf, sizeof(buf), stdin))
X		c = lower(*buf);
X	}
X	if (c == 'y')
X	    puts("dumping core for debugging"), abort();
X    }
X    exit(sig);
X}
X
Xlong    last_spool_size = -1;	/* declared here cuz it's initialized here */
X
X/*
X * if new mail comes in, print who it's from.  sprintf it all into one
X * buffer and print that instead of separate print statements to allow
X * the tool mode to make one print statement. The reason for this is that
X * when the tool is refreshed (caused by a resize, reopen, move, top, etc)
X * the last thing printed is displayed -- display the entire line.
X * return 0 if no new mail, 1 if new mail and -1 if new mail is in system
X * folder, but current mbox is not system mbox.
X */
Xcheck_new_mail()
X{
X    int 	   ret_value;
X    char 	   buf[BUFSIZ];
X    register char  *p = buf;
X
X#ifdef SUNTOOL
X    static int is_iconic, was_iconic;
X
X    if (istool) {
X	timerclear(&(mail_timer.it_interval));
X	timerclear(&(mail_timer.it_value));
X	mail_timer.it_value.tv_sec = time_out;
X	setitimer(ITIMER_REAL, &mail_timer, NULL);
X    }
X#endif /* SUNTOOL */
X    /* if fullscreen access in progress (help), don't do anything */
X    if (ret_value = mail_size()) {
X#ifdef CURSES
X	int new_hdrs = last_msg_cnt;
X#endif /* CURSES */
X#ifdef SUNTOOL
X	/* if our status has changed from icon to toolform, then
X	 * there will already be a message stating number of new
X	 * messages.  reset `n' to msg_cnt so we don't restate
X	 * the same # of new messages upon receipt of yet another new message.
X	 */
X	if (istool && !(is_iconic = (tool->tl_flags&TOOL_ICONIC)) && was_iconic)
X	    last_msg_cnt = msg_cnt;
X#endif /* SUNTOOL */
X	if (last_spool_size > spool_size) {
X	    wprint("Someone changed \"%s\"! Reinitializing...\n", mailfile);
X	    if (isoff(glob_flags, READ_ONLY))
X		(void) emptyfile(&tmpf, tempfile);
X	    msg_cnt = 0;
X	}
X	(void) load_folder(mailfile, 1, NULL);
X	if (msg_cnt < last_msg_cnt)
X	    turnoff(glob_flags, NEW_MAIL);
X	else
X	    turnon(glob_flags, NEW_MAIL);
X	if (istool) {
X	    mail_status(0);
X	    (void) do_hdrs(0, DUBL_NULL, NULL);
X	    bell();
X	}
X	if (msg_cnt < last_msg_cnt) {
X	    last_msg_cnt = msg_cnt;
X	    last_spool_size = spool_size;
X	    if (!istool)
X		mail_status(0);
X	    return 0;
X	}
X	p += Strcpy(p, "New mail ");
X	if (msg_cnt - last_msg_cnt <= 1)
X	    p += strlen(sprintf(p, "(#%d) ", msg_cnt));
X	else
X	    p += strlen(sprintf(p, "(#%d thru #%d)\n", last_msg_cnt+1,msg_cnt));
X#ifdef SUNTOOL
X	/*
X	 * If mush is in tool mode and in icon form, don't update
X	 * last_msg_cnt so that when the tool is opened, print() will
X	 * print the correct number of "new" messages.
X	 */
X	if (!istool || !(was_iconic = tool->tl_flags & TOOL_ICONIC))
X#endif /* SUNTOOL */
X	    if (iscurses && isoff(glob_flags, CNTD_CMD))
X		last_msg_cnt = msg_cnt;
X	    else while (last_msg_cnt < msg_cnt) {
X		char *p2 = compose_hdr(last_msg_cnt++) + 9;
X		if (strlen(p2) + (p - buf) >= BUFSIZ-5) {
X		    (void) strcat(p, "...\n");
X		    /* force a break by setting last_msg_cnt correctly */
X		    last_msg_cnt = msg_cnt;
X		} else
X		    p += strlen(sprintf(p, " %s\n", p2));
X	    }
X#ifdef CURSES
X	if (iscurses && isoff(glob_flags, CNTD_CMD)) {
X	    if (new_hdrs - n_array[screen-1] < screen)
X		(void) do_hdrs(0, DUBL_NULL, NULL);
X	    print("%s ...", buf);
X	} else
X#endif /* CURSES */
X	    print("%s", buf); /* buf might have %'s in them!!! */
X    } else
X#ifdef SUNTOOL
X	if (!istool || !is_iconic)
X#endif /* SUNTOOL */
X	    turnoff(glob_flags, NEW_MAIL);
X    if (last_spool_size > -1 && /* handle first case */
X	    strcmp(mailfile, spoolfile) && last_spool_size < spool_size)
X	print("You have new mail in your system mailbox.\n"), ret_value = -1;
X    last_spool_size = spool_size;
X    return ret_value;
X}
X
X/*ARGSUSED*/   /* we ignore the sigstack, cpu-usage, etc... */
XSIGRET
Xbus_n_seg(sig)
X{
X    (void) signal(sig, SIG_DFL);
X    fprintf(stderr, "%s: %s\n", prog_name,
X	(sig == SIGSEGV)? "Segmentation violation": "Bus error");
X    cleanup(sig);
X}
END_OF_FILE
if test 10419 -ne `wc -c <'signals.c'`; then
    echo shar: \"'signals.c'\" unpacked with wrong size!
fi
# end of 'signals.c'
fi
if test -f 'strings.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'strings.c'\"
else
echo shar: Extracting \"'strings.c'\" \(9787 characters\)
sed "s/^X//" >'strings.c' <<'END_OF_FILE'
X/* strings.c Copyright(1988) Dan Heller */
X
X#include "mush.h"
X
X/*
X * reverse a string.  Useful for uucp-style address comparisons.
X */
Xchar *
Xreverse(s)
Xchar s[];
X{
X    int n = strlen(s), m;
X    char c;
X
X    if (n < 1)
X	return;
X    if (n & 1)
X	n = n/2 + 1, m = n - 2;
X    else
X	n /= 2, m = n - 1;
X    for ( ; m >= 0; m--, n++)
X	c = s[n], s[n] = s[m], s[m] = c;
X    return s;
X}
X
X/*
X * lose the newline character, trailing whitespace, and return the end of p
X * test for '\n' separately since some _ctype_[] arrays may not have the
X * _S bit set for the newline character.  see <ctype.h> for more info.
X */
Xchar *
Xno_newln(p)
Xregister char *p;
X{
X    register char *p2 = p + strlen(p);	/* point it to the null terminator */
X
X    while (p2 > p && *--p2 == '\n' || isspace(*p2))
X	*p2 = 0;  /* get rid of newline and trailing spaces */
X    return p2;
X}
X
X/* find any character in s1 that's in s2; return pointer to char in s1. */
Xchar *
Xany(s1, s2)
Xregister char *s1, *s2;
X{
X    register char *p;
X    if (!s1 || !*s1 || !s2 || !*s2)
X	return NULL;
X    for( ; *s1; s1++) {
X	for(p = s2; *p; p++)
X	    if (*p == *s1)
X		return s1;
X    }
X    return NULL;
X}
X
X/* check two lists of strings each of which contain substrings.
X * Each substring is delimited by any char in "delimiters"
X * return true if any elements in list1 are on list2.
X * thus:
X * string1 = "foo, bar, baz"
X * string2 = "foobar, baz, etc"
X * delimiters = ", \t"
X * example returns 1 because "baz" exists in both lists
X * NOTE: case is ignored.
X */
Xchk_two_lists(list1, list2, delimiters)
Xregister char *list1, *list2, *delimiters;
X{
X    register char *p, c;
X    register int found = 0;
X
X    if (p = any(list1, delimiters)) {
X	for (p++; *p && index(delimiters, *p); p++)
X	    ;
X	if (chk_two_lists(p, list2, delimiters))
X	    return 1;
X    }
X    if (p = any(list2, delimiters)) {
X	for (p++; *p && index(delimiters, *p); p++)
X	    ;
X	if (chk_two_lists(list1, p, delimiters))
X	    return 1;
X    }
X    if (p) {
X	while (index(delimiters, *(p-1)))
X	    --p;
X	c = *p, *p = 0;
X    }
X    found = !lcase_strncmp(list1, list2, -1);
X    if (p)
X	*p = c;
X    return found;
X}
X
Xbzero(addr, size)
Xregister char *addr;
Xregister int size;
X{
X    while (size-- > 0)
X	addr[size] = 0;
X}
X
X/* do an atoi() on the string passed and return in "val" the decimal value.
X * the function returns a pointer to the location in the string that is not
X * a digit.
X */
Xchar *
Xmy_atoi(p, val)
Xregister char *p;
Xregister int *val;
X{
X    int positive = 1;
X
X    if (!p)
X	return NULL;
X    *val = 0;
X    if (*p == '-')
X	positive = -1, p++;
X    while (isdigit(*p))
X	*val = (*val) * 10 + *p++ - '0';
X    *val *= positive;
X    return p;
X}
X
X/* strcmp ignoring case */
Xlcase_strncmp(str1, str2, n)
Xregister char *str1, *str2;
X{
X    while (*str1 && *str2 && --n != 0)
X	if (lower(*str1) != lower(*str2))
X	    break;
X	else
X	    str1++, str2++;
X    return lower(*str1) - lower(*str2);
X}
X
X/* strcpy converting everything to lower case (arbitrary) to ignore cases */
Xchar *
Xlcase_strcpy(dst, src)
Xregister char *dst, *src;
X{
X    register char *s = dst;
X
X    /* "lower" is a macro, don't increment its argument! */
X    while (*dst++ = lower(*src))
X	src++;
X    return s;
X}
X
X/* this strcpy returns number of bytes copied */
XStrcpy(dst, src)
Xregister char *dst, *src;
X{
X    register int n = 0;
X    if (!dst || !src)
X	return 0;
X    while (*dst++ = *src++)
X	n++;
X    return n;
X}
X
Xvoid
Xxfree(cp)
Xchar *cp;
X{
X    extern char end[];
X
X    if (cp >= end && cp < (char *) &cp && debug < 5)
X	free(cp);
X}
X
Xchar *
Xsavestr(s)
Xregister char *s;
X{
X    register char *p;
X    char *malloc();
X    if (!s)
X	s = "";
X    if (!(p = malloc((unsigned) (strlen(s) + 1)))) {
X	error("out of memory saving %s", s);
X	return NULL;
X    }
X    return strcpy(p, s);
X}
X
Xvoid
Xfree_vec(argv)
Xchar **argv;
X{
X    register int n;
X    if (!argv)
X	return;
X    for (n = 0; argv[n]; n++)
X	xfree(argv[n]);
X    xfree((char *)argv);
X}
X
X/* copy a vector of strings into one string -- return the end of the string */
Xchar *
Xargv_to_string(p, argv)
Xregister char *p, **argv;
X{
X    register int i;
X    register char *ptr = p;
X
X    *p = 0;
X    if (!argv[0])
X	return "";
X    for (i = 0; argv[i]; i++)
X	ptr += strlen(sprintf(ptr, "%s ", argv[i]));
X    *--ptr = 0;   /* get rid of the last space */
X    return ptr;
X}
X
Xchar *
Xitoa(n)
X{
X    static char buf[10];
X    return sprintf(buf, "%d", n);
X}
X
X/*
X * There are two different kinds of sprintf() --those that return char * and
X * those that return int.  System-V returns int (the length of the resulting
X * string).  BSD has historically returned a pointer to the resulting string
X * instead. Mush was originally written under BSD, so the usage has always
X * been to assume the char * method.  Because the system-v method is far more
X * useful, mush should some day change to use that method, but until then,
X * this routine was written to allow all the unix'es to appear the same to
X * the programmer regardless of which sprintf is actually used.  The "latest"
X * version of 4.3BSD (as of Fall 1988) has changed its format to go from the
X * historical BSD method to the sys-v method.  It is no longer possible to
X * simply #ifdef this routine for sys-v --it is now required to use this
X * routine regardless of which sprintf is notice to your machine.  However,
X * if you know your system's sprintf returns a char *, you can remove the
X * define in strings.h
X */
X#include <varargs.h>
X/*VARARGS*/
X/*ARGSUSED*/
Xchar *
XSprintf(va_alist)
Xva_dcl
X{
X    char *buf, *fmt;
X    va_list ap;
X
X    va_start(ap);
X    buf = va_arg(ap, char *);
X    fmt = va_arg(ap, char *);
X#ifdef VPRINTF
X    (void) vsprintf(buf, fmt, ap);
X#else
X    {
X	FILE foo;
X	foo._cnt = BUFSIZ;
X	foo._base = foo._ptr = buf; /* may have to be cast (unsigned char *) */
X	foo._flag = _IOWRT+_IOSTRG;
X	(void) _doprnt(fmt, ap, &foo);
X	*foo._ptr = '\0'; /* plant terminating null character */
X    }
X#endif /* VPRINTF */
X    va_end(ap);
X    return buf;
X}
X
Xvoid
Xprint_argv(argv)
Xchar **argv;
X{
X    while (*argv)
X	if (debug)
X	    printf("(%s) ", *argv++);
X	else
X	    wprint("%s ", *argv++);
X    if (debug) {
X	putchar('\n');
X	fflush(stdout);
X    } else
X	wprint("\n");
X}
X
X/*
X * putstring -- put a string into a file.  Expand \t's into tabs and \n's
X * into newlines.  Append a \n and fflush(fp);
X */
Xvoid
Xputstring(p, fp)
Xregister char *p;
Xregister FILE *fp;
X{
X    for ( ; *p; ++p)
X	if (*p != '\\')
X	    fputc(*p, fp);
X	else
X	    switch(*++p) {
X		case 'n': fputc('\n', fp);
X		when 't': fputc('\t', fp);
X		otherwise: fputc(*p, fp);
X	    }
X    fputc('\n', fp);
X    fflush(fp);
X}
X
X#define chtoi(c)	((int)(c) - (int)'0')
X
X/* m_xlate(str) converts strings of chars which contain ascii representations
X *  of control characters appearing in str into the literal characters they
X *  represent.  The usual curses-mode character expansions (\Cx -> control-x)
X *  are honored, as are most C escapes.  Unrecognized portions are unchanged.
X */
Xchar *
Xm_xlate (str)
Xregister char *str;
X{
X    register char *r, *s, *t;
X    int dv, nd;
X
X    /*
X     * r will receive the new string, s will track the old one,
X     *  and t will step through escape sequences
X     * This allows the translation to be done in place
X     */
X    r = s = str;
X    while (s && *s) {
X	if (*s == '\\') {
X	    t = s + 1;
X	    /*
X	     * After each case below, t should point to the character
X	     *  following the escape sequence
X	     */
X	    switch(*t) {
X		case '\0' :
X		    /*
X		     * Hmmm ... a backslash followed by the string
X		     *  terminator.  Copy the backslash ONLY.
X		     */
X		    *r++ = *s++;
X		    break;
X		case '0' :
X		case '1' :
X		case '2' :
X		case '3' :
X		case '4' :
X		case '5' :
X		case '6' :
X		case '7' :
X		    /*
X		     * Convert up to 3 octal digits to their ascii value
X		     */
X		    dv = chtoi(*t++);
X		    for (nd = 0; (isdigit(*t) && (nd < 2)); nd++)
X			if (chtoi(*t) < 8)
X			    dv = (8 * dv) + chtoi(*t++);
X			else
X			    break;
X		    if (dv < 256 && dv > 0)
X			/* Valid octal number escaped */
X			*r++ = (char)dv;
X		    else
X			/* Invalid octal number, so copy unchanged */
X			while (s < t)
X			    *r++ = *s++;
X		    break;
X		case 'b' :
X		    *r++ = '\b';
X		    t++;
X		    break;
X		case 'C' :
X		    t++;
X		    if (*t == '?')
X			*r++ = '\177';
X		    else if (*t == '~')
X			*r++ = '\036';
X		    else if (*t == '/')
X			*r++ = '\037';
X		    else if (isalpha(*t) || *t > '\132' && *t < '\140')
X			*r++ = *t & 037;
X		    else
X			while (s <= t) *r++ = *s++;
X		    t++;
X		    break;
X		case 'E' :
X		    *r++ = '\033';
X		    t++;
X		    break;
X		case 'f' :
X		    *r++ = '\f';
X		    t++;
X		    break;
X		case 'n' :
X		    *r++ = '\n';
X		    t++;
X		    break;
X		case 'r' :
X		    *r++ = '\r';
X		    t++;
X		    break;
X		case 't' :
X		    *r++ = '\t';
X		    t++;
X		    break;
X		case '\\' :
X		    *r++ = *t++;
X		    break;
X		default :
X		    /*
X		     * Not recognized, so copy both characters
X		     */
X		    *r++ = *s++;
X		    *r++ = *s++;
X		    break;
X	    }
X	    /*
X	     * Now make sure s also points to the character after the
X	     *  escape sequence, by comparing to t
X	     */
X	    if (t > s)
X		s = t;
X	} else
X	    *r++ = *s++;
X    }
X    *r = '\0';
X    return str;
X}
X
X/*
X * Convert control characters to ascii format (reverse effect of m_xlate()).
X */
Xchar *
Xctrl_strcpy(s_out, s_in, bind_format)
Xregister char *s_out, *s_in;
X{
X    extern char *_unctrl[];
X    char *start = s_out;
X
X    for (; *s_in; s_in++)
X	if (*s_in == '\n')
X	    *s_out++ = '\\', *s_out++ = 'n';
X	else if (*s_in == '\r')
X	    *s_out++ = '\\', *s_out++ = 'r';
X	else if (*s_in == '\t')
X	    *s_out++ = '\\', *s_out++ = 't';
X	else if (*s_in == ESC)
X	    *s_out++ = '\\', *s_out++ = 'E';
X	else if (iscntrl(*s_in)) {
X	    if (bind_format)
X		*s_out++ = '\\', *s_out++ = 'C';
X	    else
X		*s_out++ = '^';
X	    *s_out++ = _unctrl[*s_in][1];
X	} else
X	    *s_out++ = *s_in;
X    *s_out = 0;
X    return start;
X}
END_OF_FILE
if test 9787 -ne `wc -c <'strings.c'`; then
    echo shar: \"'strings.c'\" unpacked with wrong size!
fi
# end of 'strings.c'
fi
echo shar: End of archive 5 \(of 19\).
cp /dev/null ark5isdone
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
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.