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.