v18i027: Mail user's shell version 6.4, Part05/19
Rich Salz
rsalz at bbn.com
Thu Mar 16 06:27:05 AEST 1989
Submitted-by: Dan Heller <island!argv at 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 at 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 at uunet.uu.net.
More information about the Comp.sources.unix
mailing list