home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume9
/
elm2
/
part11
< prev
next >
Wrap
Text File
|
1987-03-09
|
49KB
|
1,892 lines
Subject: v09i011: ELM Mail System, Part11/19
Newsgroups: mod.sources
Approved: rs@mirror.TMC.COM
Submitted by: Dave Taylor <hplabs!taylor>
Mod.sources: Volume 9, Issue 11
Archive-name: elm2/Part11
#! /bin/sh
# This is a shell archive. Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
# If this archive is complete, you will see the message:
# "End of archive 11 (of 19)."
# Contents: src/screen.c src/screen3270.q src/showmsg.c src/strings.c
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo shar: Extracting \"src/screen.c\" \(11166 characters\)
if test -f src/screen.c ; then
echo shar: Will not over-write existing file \"src/screen.c\"
else
sed "s/^X//" >src/screen.c <<'END_OF_src/screen.c'
X/** screen.c **/
X
X/** screen display routines for ELM program
X
X (C) Copyright 1985, Dave Taylor
X**/
X
X#include "headers.h"
X
X#define minimum(a,b) ((a) < (b) ? (a) : (b))
X
Xstatic int last_current = -1;
X
Xchar *strcpy(), *strncpy(), *nameof();
X
Xshowscreen()
X{
X char buffer[SLEN];
X
X ClearScreen();
X
X if (selected)
X sprintf(buffer,
X "Mailbox is '%s' with %d shown out of %d [Elm %s]",
X nameof(infile), selected, message_count, VERSION);
X else
X sprintf(buffer, "Mailbox is '%s' with %d message%s [Elm %s]",
X nameof(infile), message_count, plural(message_count), VERSION);
X Centerline(1, buffer);
X
X last_header_page = -1; /* force a redraw regardless */
X show_headers();
X
X if (mini_menu)
X show_menu();
X
X show_last_error();
X
X if (hp_terminal)
X define_softkeys(MAIN);
X}
X
Xupdate_title()
X{
X /** display a new title line, probably due to new mail arriving **/
X
X char buffer[SLEN];
X
X if (selected)
X sprintf(buffer,
X "Mailbox is '%s' with %d shown out of %d [Elm %s]",
X nameof(infile), selected, message_count, VERSION);
X else
X sprintf(buffer, "Mailbox is '%s' with %d message%s [Elm %s]",
X nameof(infile), message_count, plural(message_count), VERSION);
X
X ClearLine(1);
X
X Centerline(1, buffer);
X}
X
Xshow_menu()
X{
X /** write main system menu... **/
X
X if (user_level == 0) { /* a rank beginner. Give less options */
X Centerline(LINES-7,
X "You can use any of the following commands by pressing the first character;");
X Centerline(LINES-6,
X"D)elete mail, M)ail a message, R)eply to mail, U)ndelete, or Q)uit");
X Centerline(LINES-5,
X "To read a message, press <return>. j = move arrow down, k = move arrow up");
X } else {
X Centerline(LINES-7,
X "|=pipe, !=shell, ?=help, <n>=set current to n, /=search pattern");
X Centerline(LINES-6,
X"A)lias, C)hange mailbox, D)elete, E)dit, F)orward, G)roup reply, M)ail,");
X Centerline(LINES-5,
X "N)ext, O)ptions, P)rint, R)eply, S)ave, T)ag, Q)uit, U)ndelete, or eX)it");
X }
X}
X
Xint
Xshow_headers()
X{
X /** Display page of headers (10) if present. First check to
X ensure that header_page is in bounds, fixing silently if not.
X If out of bounds, return zero, else return non-zero
X Modified to only show headers that are "visible" to ze human
X person using ze program, eh?
X **/
X
X register int this_msg = 0, line = 4, last = 0, last_line,
X displayed = 0;
X char newfrom[SLEN], buffer[SLEN];
X
X if (fix_header_page()) {
X dprint0(7, "show_headers returned FALSE 'cause of fix-header-page\n");
X return(FALSE);
X }
X
X if (selected) {
X if ((header_page*headers_per_page) > selected) {
X dprint2(7, "show_headers returned FALSE since selected [%d] < %d\n",
X selected, header_page*headers_per_page);
X return(FALSE); /* too far! too far! */
X }
X
X dprint0(6,"** show_headers AND selected...\n");
X
X if (header_page == 0) {
X this_msg = visible_to_index(1);
X displayed = 0;
X }
X else {
X this_msg = visible_to_index(header_page * headers_per_page + 1);
X displayed = header_page * headers_per_page;
X }
X
X dprint2(7,"this_msg (index) = %d [header_page = %d]\n", this_msg,
X header_page);
X
X dprint1(7,"we've already displayed %d messages\n", displayed);
X
X last = displayed+headers_per_page;
X
X dprint1(7,"and the last msg on this page is %d\n", last);
X }
X else {
X if (header_page == last_header_page) /* nothing to do! */
X return(FALSE);
X
X /** compute last header to display **/
X
X this_msg = header_page * headers_per_page;
X last = this_msg + (headers_per_page - 1);
X }
X
X if (last >= message_count) last = message_count-1;
X
X /** Okay, now let's show the header page! **/
X
X ClearLine(line); /* Clear the top line... */
X
X MoveCursor(line, 0); /* and move back to the top of the page... */
X
X while ((selected && displayed < last) || this_msg <= last) {
X tail_of(header_table[this_msg].from, newfrom, TRUE);
X
X if (selected) {
X if (this_msg == current-1)
X build_header_line(buffer, &header_table[this_msg], ++displayed,
X TRUE, newfrom);
X else
X build_header_line(buffer, &header_table[this_msg],
X ++displayed, FALSE, newfrom);
X }
X else {
X if (this_msg == current-1)
X build_header_line(buffer, &header_table[this_msg], this_msg+1,
X TRUE, newfrom);
X else
X build_header_line(buffer, &header_table[this_msg],
X this_msg+1, FALSE, newfrom);
X }
X
X Write_to_screen("%s\r\n", 1, buffer); /* avoid '%' probs */
X CleartoEOLN();
X line++; /* for clearing up in a sec... */
X
X if (selected) {
X if ((this_msg = next_visible(this_msg+1)-1) < 0)
X break; /* GET OUTTA HERE! */
X
X /* the preceeding looks gross because we're using an INDEX
X variable to pretend to be a "current" counter, and the
X current counter is always 1 greater than the actual
X index. Does that make sense??
X */
X }
X else
X this_msg++; /* even dumber... */
X }
X
X dprint0(1,"** out of redraw loop! **\n");
X
X if (mini_menu)
X last_line = LINES-8;
X else
X last_line = LINES-3;
X
X while (line < last_line) {
X CleartoEOLN();
X Writechar('\r');
X Writechar('\n');
X line++;
X }
X
X display_central_message();
X
X last_current = current;
X last_header_page = header_page;
X
X return(TRUE);
X}
X
Xshow_current()
X{
X /** Show the new header, with all the usual checks **/
X
X register int first = 0, last = 0, last_line, new_line, i=0, j=0;
X char newfrom[SLEN], old_buffer[SLEN], new_buffer[SLEN];
X
X (void) fix_header_page(); /* Who cares what it does? ;-) */
X
X /** compute last header to display **/
X
X first = header_page * headers_per_page;
X last = first + (headers_per_page - 1);
X
X if (last > message_count)
X last = message_count;
X
X /** okay, now let's show the pointers... **/
X
X /** have we changed??? **/
X
X if (current == last_current)
X return;
X
X if (selected) {
X dprint2(2,"\nshow_current\n* last_current = %d, current = %d\n",
X last_current, current);
X last_line = ((i=compute_visible(last_current-1)-1) %
X headers_per_page)+4;
X new_line = ((j=compute_visible(current-1)-1) % headers_per_page)+4;
X dprint1(2,"* compute_visible(last-1)=%d\n",
X compute_visible(last_current-1));
X dprint1(2,"* compute_visible(current-1)=%d\n",
X compute_visible(current-1));
X dprint2(2,"* ending up with last_line = %d and new_line = %d\n",
X last_line, new_line);
X }
X else {
X last_line = ((last_current-1) % headers_per_page)+4;
X new_line = ((current-1) % headers_per_page)+4;
X }
X
X dprint4(7,
X "--> show-current: last_current=%d [%d] and current=%d [%d]\n",
X last_current, i, current, j);
X
X dprint2(7," maps to lines %d and %d\n", last_line, new_line);
X
X if (has_highlighting && ! arrow_cursor) {
X /** build the old and new header lines... **/
X
X tail_of(header_table[current-1].from, newfrom, TRUE);
X build_header_line(new_buffer, &header_table[current-1],
X (selected? compute_visible(current-1) : current),
X TRUE, newfrom);
X
X if (last_current > 0) { /* say we went from no mail to new... */
X tail_of(header_table[last_current-1].from, newfrom, TRUE);
X build_header_line(old_buffer, &header_table[last_current-1],
X (selected? compute_visible(last_current-1) : last_current),
X FALSE, newfrom);
X
X ClearLine(last_line);
X PutLine0(last_line, 0, old_buffer);
X }
X PutLine0(new_line, 0, new_buffer);
X }
X else {
X if (on_page(last_current))
X PutLine0(last_line,0," "); /* remove old pointer... */
X if (on_page(current))
X PutLine0(new_line, 0,"->");
X }
X
X last_current = current;
X}
X
Xbuild_header_line(buffer, entry, message_number, highlight, from)
Xchar *buffer;
Xstruct header_rec *entry;
Xint message_number, highlight;
Xchar *from;
X{
X /** Build in buffer the message header ... entry is the current
X message entry, 'from' is a modified (displayable) from line,
X 'highlight' is either TRUE or FALSE, and 'message_number'
X is the number of the message.
X **/
X
X /** Note: using 'strncpy' allows us to output as much of the
X subject line as possible given the dimensions of the screen.
X The key is that 'strncpy' returns a 'char *' to the string
X that it is handing to the dummy variable! Neat, eh? **/
X
X char subj[LONG_SLEN], /* to output subject */
X buff[NLEN]; /* keep start_highlight value */
X
X if (strcmp(start_highlight,"->") != 0 && arrow_cursor) {
X strcpy(buff, start_highlight);
X strcpy(start_highlight, "->");
X }
X
X strncpy(subj, entry->subject, COLUMNS-45);
X
X subj[COLUMNS-45] = '\0'; /* insurance, eh? */
X
X /* now THIS is a frightening format statement!!! */
X
X sprintf(buffer, "%s%s%c%c%c%-3d %3.3s %-2d %-18.18s (%d) %s%s%s",
X highlight? ((has_highlighting && !arrow_cursor) ?
X start_highlight : "->") : " ",
X (highlight && has_highlighting && !arrow_cursor)? " " : "",
X show_status(entry->status),
X (entry->status & DELETED? 'D' : ' '),
X (entry->status & TAGGED? '+' : ' '),
X message_number,
X entry->month,
X atoi(entry->day),
X from,
X entry->lines,
X (entry->lines / 1000 > 0? "" : /* spacing the */
X entry->lines / 100 > 0? " " : /* same for the */
X entry->lines / 10 > 0? " " : /* lines in () */
X " "), /* [wierd] */
X subj,
X (highlight && has_highlighting && !arrow_cursor) ?
X end_highlight : "");
X
X /** Actually, it's rather an impressive feat that we can
X do so much in essentially one statement! (Of course,
X I'll bet the test suite for the printf routine isn't
X THIS rigorous either!!!) (to be honest, though, just
X looking at this statement makes me chuckle...)
X **/
X
X if (arrow_cursor) /* restore! */
X strcpy(start_highlight, buff);
X
X}
X
Xint
Xfix_header_page()
X{
X /** this routine will check and ensure that the current header
X page being displayed contains messages! It will silently
X fix 'header-page' if wrong. Returns TRUE if changed. **/
X
X int last_page, old_header;
X
X old_header = header_page;
X
X last_page = (int) ((message_count-1) / headers_per_page);
X
X if (header_page > last_page)
X header_page = last_page;
X else if (header_page < 0)
X header_page = 0;
X
X return(old_header != header_page);
X}
X
Xint
Xon_page(message)
Xint message;
X{
X /** Returns true iff the specified message is on the displayed page. **/
X
X dprint1(6,"** on_page(%d) returns...", message);
X
X if (selected) message = compute_visible(message-1);
X
X if (message >= header_page * headers_per_page)
X if (message <= ((header_page+1) * headers_per_page)) {
X dprint0(6,"TRUE\n");
X return(TRUE);
X }
X
X dprint0(6,"FALSE\n");
X return(FALSE);
X}
X
Xshow_status(status)
Xint status;
X{
X /** This routine returns a single character indicative of
X the status of this message. The precedence is;
X
X F = form letter
X E = Expired message
X P = Priority message
X A = Action associated with message
X N = New message
X _ = (space) default
X **/
X
X if (status & FORM_LETTER) return( 'F' );
X else if (status & EXPIRED) return( 'E' );
X else if (status & PRIORITY) return( 'P' );
X else if (status & ACTION) return( 'A' );
X else if (status & NEW) return( 'N' );
X else return( ' ' );
X}
END_OF_src/screen.c
if test 11166 -ne `wc -c <src/screen.c`; then
echo shar: \"src/screen.c\" unpacked with wrong size!?
fi
# end of overwriting check
fi
echo shar: Extracting \"src/screen3270.q\" \(11593 characters\)
if test -f src/screen3270.q ; then
echo shar: Will not over-write existing file \"src/screen3270.q\"
else
sed "s/^X//" >src/screen3270.q <<'END_OF_src/screen3270.q'
XFrom hpccc!mcgregor@hplabs.ARPA Thu Jun 5 11:41:49 1986
XReceived: from hplabs.ARPA by hpldat ; Thu, 5 Jun 86 11:41:32 pdt
XMessage-Id: <8606051841.AA16872@hpldat>
XReceived: by hplabs.ARPA ; Thu, 5 Jun 86 11:38:07 pdt
XTo: hplabs!taylor@hplabs.ARPA
XDate: Thu, 5 Jun 86 11:36:39 PDT
XFrom: hpccc!mcgregor@hplabs.ARPA (Scott McGregor)
XSubject: revised screen3270.q
XTelephone: (415) 857-5875
XPostal-Address: Hewlett-Packard, PO Box 10301, Mail stop 20CH, Palo Alto CA 943X03-0890
XX-Mailer: ELM [version 1.0]
X
X
X/*
X * screen3270.q
X *
X * Created for ELM, 5/86 to work (hopefully) on UTS systems with 3270
X * type terminals, by Scott L. McGregor, HP Corporate Computing Center.
X *
X */
X
X#include "headers.h"
X# include <sys/utsname.h>
X# include <sys/tubio.h>
X
X# include <errno.h>
X
X
X# define TTYIN 0 /* standard input */
X#include <stdio.h>
X#define MAXKEYS 101
X#define OFF 0
X#define UNKNOWN 0
X#define ON 1
X#define FALSE 0
X#define TRUE 1
X
Xchar *error_name();
X
Xextern int _line, _col;
X
X
Xpfinitialize()
X{
X char cp[80];
X
X dprint0(9,"pfinitialize()\n");
X pfinit();
X /*
X * load the system defined pfkeys
X */
X pfload("/usr/local/etc/.elmpfrc");
X /*
X * load the user's keys if any
X */
X strcat(cp,home);
X strcat(cp,"/.elmpfrc");
X pfload(cp);
X pfprint();
X}
X
X/*
X * note, inputs are limited to 80 characters! Any larger amount
X * will be truncated without notice!
X */
X
X
X/*
X * pfinit() initializes _pftable
X */
Xpfinit()
X{
X int i,j;
X
X dprint0(9,"pfinit()\n");
X for (i=0;i<MAXKEYS;i++) {
X for (j=0;j<80;j++) {
X _pftable[i][j]='\0';
X }
X }
X return(0);
X}
X
X
X/*
X * pfset(key) sets _pftable entries.
X */
Xpfset(key,return_string)
Xint key;
Xchar *return_string;
X{
X int i;
X
X dprint2(9,"pfset(%d,%s)\n",key,return_string);
X for (i=0;i<=80;i++) {
X if (i <= strlen(return_string))
X _pftable[key][i] = return_string[i];
X else _pftable[key][i] = '\0';
X }
X dprint2(9,"pfset: %d %s\n",key,_pftable[key]);
X
X return(0);
X}
X
X/*
X * pfload(name) reads file "name" and parses the
X * key definitions in it into a table used by the
X * pfreturn.
X */
Xpfload(name)
Xchar *name;
X{
X FILE *pfdefs;
X int i,j,k;
X int key = 0;
X char defn[80];
X char newdefn[80];
X
X dprint1(9,"pfload(%s)\n",name);
X if ((pfdefs = fopen(name,"r")) == NULL){
X dprint2(2,"%s pfrc open failed, %s \n",name,
X error_name(errno));
X return(0);
X }
X
X /*
X * This program reads .elmpfrc files which it currently
X * expects to be in the form:
X *
X * <pfkeynumber> <whitespace> <pfkeyvalue> [<whitespace> <comment>]
X *
X * Pfkeynumber is an integer 1-24. Whitespace can be one
X * or more blanks or tabs. Pfkeyvalue is any string NOT
X * containing whitespace (however, \b for blank, \t for tab
X * and \n for newline can be used instead to indicate that
X * the indicated whitespace character is part of a command.
X * Note that the EnTER key will NOT be treated as a newline
X * command, so defining a newline key is a good idea!
X * Anything else appearing on the line after the pfkey is ignored
X * and so can be used as a comment.
X *
X * This may not be the best form for a file used by
X * humans to set parms, and if someone comes up with a
X * better one and a parser to read it, then this can be
X * replaced.
X *
X */
X
X dprint1(1,"%s pfrc opened\n",name);
X k = 0;
X while ( fscanf(pfdefs,"%d%s",&key,defn) != EOF ) {
X dprint2(9,"pfkey definition 1: %d %s\n",key,defn);
X if ((key < 0) || (key > MAXKEYS)) {
X dprint2(9,"pfkey defn failed: key=%d MAXKEYS=%d\n",key,MAXKEYS);
X k++;
X } else {
X dprint2(9,"pfkey definition 2: %d %s\n",key,defn);
X for (i=0,j=0;i<strlen(defn);i++) {
X if (defn[i]=='\\') {
X if (defn[i+1]=='n') {
X newdefn[j++]='\n'; i++;
X }
X if (defn[i+1]=='t') {
X newdefn[j++]='\t'; i++;
X }
X if (defn[i+1]=='0') {
X newdefn[j++]='\0'; i++;
X }
X if (defn[i+1]=='1') {
X newdefn[j++]='\001'; i++;
X }
X if (defn[i+1]=='b') {
X newdefn[j++]=' '; i++;
X }
X }
X else {
X newdefn[j++]=defn[i];
X }
X }
X dprint2(9,"pfkey new definition: %d %s\n",key,newdefn);
X pfset(key,newdefn);
X }
X }
X dprint1(9,"pfkey definition table: %s\n",_pftable);
X return(k);
X}
X
X
X/*
X * pfreturn(key) returns the stored string for that pfkey.
X */
Xpfreturn(key,string)
Xint key;
Xchar string[];
X{
X int i;
X
X dprint2(9,"pfreturn(%d,%s)\n",key,string);
X for (i=0;i<80;i++) {
X string[i] = _pftable[key][i];
X }
X dprint1(9,"pfreturn string=%s\n",string);
X return;
X}
X
X
X/*
X * pfprint() prints all pfkey definitions
X */
Xpfprint()
X
X{
X int i;
X char string[80];
X
X for (i=0;i<MAXKEYS;i++) {
X if (strlen(_pftable[i]) != 0)
X dprint2(9,"%d pf table entry=%s\n",i+1,_pftable[i]);
X }
X}
X
X/*
X * rowcol2offset(row,col) takes the row and column numbers and
X * returns the offset into the array.
X * row and column are assumed to vary from 0 to LINES-1, and COLUMNS-1
X * respectively.
X */
Xrowcol2offset(row,col)
Xint row, col;
X{
X dprint2(9,"rowcol2offset(%d,%d)\n",row,col);
X
X if ((row <= LINES) && (row >= 0)) {
X if ((col <= COLUMNS) && (col >=0)) {
X return(row*COLUMNS+col);
X }
X else return(0);
X }
X else return(0);
X}
X
X/*
X * offset2row(offset) takes the offset returnes the row.
X * row is assumed to vary from 0 to LINES-1.
X */
Xoffset2row(offset)
Xint offset;
X{
X int i;
X
X dprint1(9,"offset2row(%d)\n",offset);
X i = (int) (offset / COLUMNS);
X dprint1(9,"offset2row returns= %d)\n",i);
X return(i);
X}
X
X/*
X * offset2col(offset) takes the offset returnes the col.
X * col is assumed to vary from 0 to COLUMNS-1.
X */
Xoffset2col(offset)
Xint offset;
X{
X int i;
X
X dprint1(9,"offset2col(%d)\n",offset);
X i = (int) (offset % COLUMNS);
X dprint1(9,"offset2col returns= %d)\n",i);
X return(i);
X}
X
X/*
X * Row(row) takes the row in 0 <= row < LINES and returns
X * row in 0 < row <= LINES.
X */
XRow(row)
Xint row;
X{
X dprint1(9,"Row(%d)\n",row);
X return(row+1);
X}
X
X/*
X * Col(Col) takes the col in 0 <= col < COLUMNS and returns
X * col in 0 < col <= COLUMNS.
X */
XCol(col)
Xint col;
X{
X dprint1(9,"Col(%d)\n",col);
X return(col+1);
X}
X
X
Xgethostname(hostname,size) /* get name of current host */
Xint size;
Xchar *hostname;
X{
X /** Return the name of the current host machine. UTS only **/
X
X /** This routine compliments of Scott McGregor at the HP
X Corporate Computing Center **/
X
X int uname();
X struct utsname name;
X
X dprint2(9,"gethostname(%s,%d)\n",hostname,size);
X (void) uname(&name);
X (void) strncpy(hostname,name.nodename,size-1);
X if (strlen(name.nodename) > SLEN)
X hostname[size] = '\0';
X}
X
Xint
Xisa3270()
X{
X /** Returns TRUE and sets LINES and COLUMNS to the correct values
X for an Amdahl (IBM) tube screen, or returns FALSE if on a normal
X terminal (of course, next to a 3270, ANYTHING is normal!!) **/
X
X struct tubiocb tubecb;
X
X dprint0(9,"isa3270()\n");
X if (ioctl(TTYIN, TUBGETMOD, &tubecb) == -1){
X return(FALSE); /* not a tube! */
X }
X LINES = tubecb.line_cnt - 2;
X COLUMNS = tubecb.col_cnt;
X if (!check_only && !mail_only) {
X isatube = TRUE;
X return(TRUE);
X }
X else {
X isatube = FALSE;
X return(FALSE);
X }
X}
X
X/*
X * ReadCh3270() reads a character from the 3270.
X */
Xint ReadCh3270()
X{
X /** read a character from the display! **/
X
X register int x;
X char tempstr[80];
X char ch;
X
X dprint0(9,"ReadCh3270()\n");
X if ((_input_buf_ptr > COLUMNS) ||
X (_input_buffer[_input_buf_ptr] == '\0')) {
X WriteScreen3270();
X for (x=0; x < COLUMNS; x++) _input_buffer[x] = '\0';
X panel (noerase, read) {
X #@ LINES+1,1# #INC,_input_buffer,COLUMNS#
X }
X dprint1(9,"ReadCh3270 _input_buffer=%s\n",_input_buffer);
X x=strlen(_input_buffer);
X pfreturn(qskp,tempstr);
X if (!strcmp(tempstr,"\001")) {
X if (strlen(_input_buffer) == 1) {
X tempstr[0]='\0';
X }
X else {
X tempstr[0]='\n';
X tempstr[1]='\0';
X }
X }
X dprint1(9,"ReadCh3270 pfkey=%s\n",tempstr);
X strcat(_input_buffer,tempstr);
X dprint1(9,"ReadCh3270 _input_buffer+pfkey=%s\n",_input_buffer);
X ch = _input_buffer[0];
X dprint1(9,"ReadCh3270 returns(%c)\n",ch);
X _input_buf_ptr = 1;
X return(ch);
X }
X else {
X ch = _input_buffer[_input_buf_ptr];
X dprint1(9,"ReadCh3270 returns(%c)\n",ch);
X _input_buf_ptr = _input_buf_ptr + 1;
X return(ch);
X }
X}
X
X
X/*
X * WriteScreen3270() Loads a screen to the buffer.
X *
X */
XWriteScreen3270()
X{
X register int x;
X int currcol;
X int currrow;
X int i;
X int state = OFF;
X int prevrow = 1;
X int prevcol = 1;
X int prevptr = 0;
X int clear_state = ON;
X char tempstr[80];
X char copy_screen[66*132];
X
X dprint0(9,"WriteScreen3270()\n");
X prevrow = 1;
X prevcol = 1;
X prevptr = 0;
X state = OFF;
X for (x=0; x < LINES*COLUMNS; x++){
X if ((_internal_screen[x] == '\016')
X && (state == OFF)) {
X currrow = (x / COLUMNS ) + 1;
X currcol = (x % COLUMNS ) + 1 ;
X i = x - prevptr - 1;
X strncpy(copy_screen, (char *) (_internal_screen+(prevptr)),i);
X panel(erase=clear_state,write,noread) {
X #@ prevrow, prevcol # #ON,copy_screen,i #
X }
X clear_state = OFF;
X state = ON;
X /* prevrow = currrow; */
X /* prevcol = currcol; */
X prevrow = currrow + 1;
X prevcol = 0;
X prevptr = x+1;
X }
X else if ((_internal_screen[x] == '\017')
X && (state == ON)) {
X currrow = (x / COLUMNS ) + 1;
X currcol = (x % COLUMNS ) + 1;
X i = x - prevptr - 1;
X strncpy(copy_screen, (char *) (_internal_screen+(prevptr)),i);
X panel(erase = clear_state,write,noread) {
X #@ prevrow,prevcol # #OH,copy_screen,i #
X }
X clear_state = OFF;
X state = OFF;
X /* prevrow = currrow; */
X /* prevcol = currcol; */
X prevrow = currrow + 1;
X prevcol = 0;
X }
X else if (_internal_screen[x] < ' ') {
X _internal_screen[x] = ' ';
X prevptr = x + 1;
X }
X }
X /* write remainder of buffer */
X if (state == OFF) {
X currrow = (LINES) + 1 ;
X currcol = (COLUMNS ) + 1;
X i = x - prevptr ;
X strncpy(copy_screen, (char *) (_internal_screen+(prevptr)),i);
X panel(erase=clear_state,write,noread) {
X #@ prevrow,prevcol # #ON,copy_screen,i #
X }
X }
X else {
X currrow = (LINES ) + 1 ;
X currcol = (COLUMNS ) + 1 ;
X i = x - prevptr ;
X strncpy(copy_screen, (char *) (_internal_screen+(prevptr)),i);
X panel(erase=clear_state,write,noread) {
X #@ prevrow,prevcol # #OH,copy_screen,i #
X }
X }
X}
X
X
X/*
X * Clear3270
X */
XClear3270()
X{
X int i,j;
X
X dprint0(9,"Clear3270()\n");
X j = rowcol2offset(LINES,COLUMNS);
X for (i = 0; i < j; i++) {
X _internal_screen[i] = ' ';
X }
X return(0);
X}
X
X/*
X * WriteChar3270(row,col) writes a character at the row and column.
X */
XWriteChar3270(row,col,ch)
Xint row, col;
Xchar ch;
X{
X dprint3(9,"WriteChar3270(%d,%d,%c)\n",row,col,ch);
X _internal_screen[rowcol2offset(row,col)] = ch;
X}
X
X/*
X * WriteLine3270(row,col) writes a line at the row and column.
X */
XWriteLine3270(row,col,line)
Xint row, col;
Xchar *line;
X{
X int i, j, k;
X dprint3(9,"WriteLine3270(%d,%d,%s)\n",row,col,line);
X _line = row;
X _col = col;
X k = strlen(line);
X i=rowcol2offset(row,col);
X for (j=0; j<k; i++, j++) {
X if ((line[j] >= ' ') ||
X (line[j] == '\016') ||
X (line[j] == '\017'))
X _internal_screen[i] = line[j];
X else _internal_screen[i] = ' ';
X }
X /* _line = offset2row(i-1); calling program updates location */
X /* _col = offset2col(i-1); */
X
X}
X
X
X/*
X * ClearEOLN3270() clears the remainder of the current line on a 3270.
X */
XClearEOLN3270()
X{
X int i,j ;
X
X dprint0(9,"ClearEOLN3270()\n");
X j = rowcol2offset(_line,COLUMNS);
X for (i=rowcol2offset(_line,_col); i < j; i++) {
X _internal_screen[i] = ' ';
X }
X}
X
X/*
X * ClearEOS3270() clears the remainder of the current screen on a 3270.
X */
XClearEOS3270()
X{
X int i,j;
X
X dprint0(9,"ClearEOS3270()\n");
X j = rowcol2offset(LINES,COLUMNS);
X for (i = rowcol2offset(_line,_col); i < j; i++) {
X _internal_screen[i] = ' ';
X }
X}
X
END_OF_src/screen3270.q
if test 11593 -ne `wc -c <src/screen3270.q`; then
echo shar: \"src/screen3270.q\" unpacked with wrong size!?
fi
# end of overwriting check
fi
echo shar: Extracting \"src/showmsg.c\" \(10629 characters\)
if test -f src/showmsg.c ; then
echo shar: Will not over-write existing file \"src/showmsg.c\"
else
sed "s/^X//" >src/showmsg.c <<'END_OF_src/showmsg.c'
X/** showmsg.c **/
X
X/** This file contains all the routines needed to display the specified
X message.
X
X These routines (C) Copyright 1986 Dave Taylor
X
X Modified 6/86 to use pager variable!!! Hurrah!!!!
X Modified 7/86 to have secure pipes.. *sigh*
X**/
X
X#include "headers.h"
X#include <ctype.h>
X#include <errno.h>
X#include <signal.h>
X
X#ifdef BSD
X# include <sys/wait.h>
X# undef tolower
X#endif
X
Xextern int errno;
X
Xchar *error_name(), *strcat(), *strcpy();
Xvoid _exit();
X
Xint memory_lock = FALSE; /* is it available?? */
Xint pipe_abort = FALSE; /* did we receive a SIGNAL(SIGPIPE)? */
X
Xint
Xshow_msg(number)
Xint number;
X{
X /*** display number'th message. Get starting and ending lines
X of message from headers data structure, then fly through
X the file, displaying only those lines that are between the
X two!
X Returns non-zero iff screen was changed
X ***/
X
X dprint0(8, "show_msg called\n");
X
X if (number > message_count) {
X error1("Only %d messages!", message_count);
X return(0);
X }
X else if (number < 1) {
X error("you can't read THAT message!");
X return(0);
X }
X
X clearit(header_table[number-1].status, NEW); /* it's been read now! */
X
X memory_lock = FALSE;
X
X /* some explaination for that last one - We COULD use memory locking
X to speed up the paging, but the action of "ClearScreen" on a screen
X with memory lock turned on seems to vary considerably (amazingly so)
X so it's safer to only allow memory lock to be a viable bit of
X trickery when dumping text to the screen in scroll mode.
X Philosophical arguments should be forwarded to Bruce at the
X University of Walamazoo, Australia, via ACSNet *wry chuckle* */
X
X return(show_message(header_table[number-1].lines,
X header_table[number-1].offset,number));
X}
X
Xint
Xshow_message(lines, file_loc, msgnumber)
Xint lines, msgnumber;
Xlong file_loc;
X{
X /*** Show the indicated range of lines from mailfile
X for message 'msgnumber' by using 'display'
X Returns non-zero iff screen was altered.
X ***/
X
X dprint3(9,"show_message(%d,%ld,%d)\n", lines, file_loc, msgnumber);
X
X if (fseek(mailfile, file_loc, 0) != 0) {
X dprint2(1,"Error: seek %d bytes into file, errno %s (show_message)\n",
X file_loc, error_name(errno));
X error2("ELM failed seeking %d bytes into file (%s)",
X file_loc, error_name(errno));
X return(0);
X }
X
X if (feof(mailfile))
X dprint0(1,"\n*** seek put us at END OF FILE!!! ***\n");
X
X /* next read will get 'this' line so must be at end of previous */
X
X Raw(OFF);
X if (strcmp(pager,"builtin") == 0 || strcmp(pager,"internal") == 0)
X display(lines, msgnumber);
X else
X secure_display(lines, msgnumber);
X Raw(ON);
X if (memory_lock) EndMemlock(); /* turn it off!! */
X
X return(1); /* we did it boss! */
X}
X
X
X/** This next one is the 'pipe' file descriptor for writing to the
X pager process... **/
X
XFILE *output_pipe, *popen();
X
Xint
Xdisplay(lines, msgnum)
Xint lines, msgnum;
X{
X /** Display specified number of lines from file mailfile.
X Note: This routine MUST be placed at the first line
X of the input file!
X Returns the same as the routine above (namely zero or one)
X **/
X
X char from_buffer[LONG_STRING], buffer[VERY_LONG_STRING], *full_month();
X
X int lines_displayed = 0;
X int crypted = 0, gotten_key = 0; /* encryption */
X int weed_header, weeding_out = 0; /* weeding */
X int mail_sent, /* misc use */
X form_letter = FALSE, /* Form ltr? */
X form_letter_section = 0, /* section */
X builtin = FALSE; /* our pager? */
X
X dprint3(4,"displaying %d lines from message %d using %s\n",
X lines, msgnum, pager);
X
X ClearScreen();
X
X if (cursor_control) transmit_functions(OFF);
X
X pipe_abort = FALSE;
X
X builtin = (strcmp(pager, "builtin") == 0 ||
X strcmp(pager,"internal") == 0);
X
X if (form_letter = (header_table[msgnum-1].status&FORM_LETTER)) {
X if (filter)
X form_letter_section = 1; /* initialize to section 1 */
X }
X
X if (builtin)
X start_builtin(lines);
X else {
X if ((output_pipe = popen(pager,"w")) == NULL) {
X error2("Can't create pipe to %s [%s]", pager,
X error_name(errno));
X dprint2(1,"\n*** Can't create pipe to %s - error %s ***\n\n",
X pager, error_name(errno));
X return(0);
X }
X dprint1(4,"Opened a write-only pipe to routine %s \n", pager);
X }
X
X if (title_messages) {
X
X mail_sent = (strncmp(header_table[msgnum-1].from, "To:", 3) == 0);
X
X tail_of(header_table[msgnum-1].from, from_buffer, FALSE);
X
X sprintf(buffer, "\r%s #%d %s %s%s\t %s %s %s, %d at %s%s\n\r",
X form_letter? "Form": "Message",
X msgnum, mail_sent? "to" : "from", from_buffer,
X (strlen(from_buffer) > 24? "\n\r":
X (strlen(from_buffer) > 16 ? "" : "\t")),
X "Mailed",
X full_month(header_table[msgnum-1].month),
X header_table[msgnum-1].day,
X atoi(header_table[msgnum-1].year) + 1900,
X header_table[msgnum-1].time,
X filter? "": "\n\r\n\r");
X
X if (builtin)
X display_line(buffer);
X else
X fprintf(output_pipe, "%s", buffer);
X
X if (! mail_sent && matches_weedlist("To:") && filter &&
X strcmp(header_table[current-1].to,username) != 0 &&
X strlen(header_table[current-1].to) > 0) {
X sprintf(buffer, "\n\r(message addressed to %s)\n\r",
X header_table[current-1].to);
X if (builtin)
X display_line(buffer);
X else
X fprintf(output_pipe, "%s", buffer);
X }
X
X /** The test above is: if we didn't originally send the mail
X (e.g. we're not reading "mail.sent") AND the user is currently
X weeding out the "To:" line (otherwise they'll get it twice!)
X AND the user is actually weeding out headers AND the message
X wasn't addressed to the user AND the 'to' address is non-zero
X (consider what happens when the message doesn't HAVE a "To:"
X line...the value is NULL but it doesn't match the username
X either. We don't want to display something ugly like
X "(message addressed to )" which will just clutter up the
X display!).
X
X And you thought programming was EASY!!!!
X **/
X }
X
X weed_header = filter; /* allow us to change it after header */
X
X while (lines > 0 && pipe_abort == FALSE) {
X
X if (fgets(buffer, VERY_LONG_STRING, mailfile) == NULL) {
X if (lines_displayed == 0) {
X
X /* AUGH! Why do we get this occasionally??? */
X
X dprint0(1,
X "\n\n** Out of Sync!! EOF with nothing read (display) **\n");
X dprint0(1,"** closing and reopening mailfile... **\n\n");
X
X if (!builtin) pclose(output_pipe); /* close pipe NOW! */
X
X if (mailfile != NULL)
X fclose(mailfile); /* huh? */
X
X if ((mailfile = fopen(infile, "r")) == NULL) {
X error("Sync error: can't re-open mailbox!!");
X show_mailfile_stats();
X emergency_exit();
X }
X return(show_message(lines,
X header_table[msgnum-1].offset,
X msgnum));
X }
X if (!builtin)
X pclose(output_pipe);
X if (lines == 0 && pipe_abort == FALSE) { /* displayed it all */
X if (!builtin)
X PutLine0(LINES,0,"\rPress <return> to return to Elm: ");
X else
X printf("\n\r\n\rPress <return> to return to Elm: ");
X fflush(stdout);
X Raw(ON);
X (void) ReadCh();
X Raw(OFF);
X }
X return(TRUE);
X }
X
X if (strlen(buffer) > 0)
X no_ret(buffer);
X
X if (strlen(buffer) == 0) {
X weed_header = 0; /* past header! */
X weeding_out = 0;
X }
X
X lines--;
X lines_displayed++;
X
X if (form_letter && weed_header)
X /* skip it. NEVER display random headers in forms! */;
X else if (weed_header && matches_weedlist(buffer))
X weeding_out = 1; /* aha! We don't want to see this! */
X else if (buffer[0] == '[') {
X if (strcmp(buffer, START_ENCODE)==0)
X crypted++;
X else if (strcmp(buffer, END_ENCODE)==0)
X crypted--;
X else if (crypted) {
X encode(buffer);
X show_line(buffer, builtin);
X }
X else
X show_line(buffer, builtin);
X }
X else if (crypted) {
X if (! gotten_key++) getkey(OFF);
X encode(buffer);
X show_line(buffer, builtin);
X }
X else if (weeding_out) {
X weeding_out = (whitespace(buffer[0])); /* 'n' line weed */
X if (! weeding_out) /* just turned on! */
X show_line(buffer, builtin);
X }
X else if (form_letter && first_word(buffer,"***") && filter) {
X strcpy(buffer,
X"\n------------------------------------------------------------------------------\n");
X show_line(buffer, builtin); /* hide '***' */
X form_letter_section++;
X }
X else if (form_letter_section == 1 || form_letter_section == 3)
X /** skip this stuff - we can't deal with it... **/;
X else
X show_line(buffer, builtin);
X }
X
X if (cursor_control) transmit_functions(ON);
X
X if (! builtin) pclose(output_pipe);
X
X if (lines == 0 && pipe_abort == FALSE) { /* displayed it all! */
X if (! builtin)
X PutLine0(LINES,0,"\rPress <return> to return to Elm: ");
X else
X printf("\n\r\n\rPress <return> to return to Elm: ");
X fflush(stdout);
X Raw(ON);
X (void) ReadCh();
X Raw(OFF);
X }
X return(TRUE);
X}
X
Xshow_line(buffer, builtin)
Xchar *buffer;
Xint builtin;
X{
X /** Hands the given line to the output pipe. 'builtin' is true if
X we're using the builtin pager. **/
X
X if (builtin) {
X strcat(buffer, "\n\r");
X pipe_abort = display_line(buffer);
X }
X else {
X errno = 0;
X fprintf(output_pipe, "%s\n", buffer);
X
X if (errno != 0)
X dprint1(1,"\terror %s hit!\n", error_name(errno));
X }
X}
X
Xint
Xsecure_display(lines, msgnumber)
Xint lines, msgnumber;
X{
X /** This is the cheap way to implement secure pipes - spawn a
X child process running under the old userid, then open the
X pager and feed the message to it. When the subprocess ends
X (the routine returns) simply return. Simple and effective.
X (too bad it's this much of a hassle to implement secure
X pipes, though - I can imagine it being a constant problem!)
X **/
X
X int pid, w;
X#ifdef BSD
X union wait status;
X#else
X int status;
X#endif
X register int (*istat)(), (*qstat)();
X
X#ifdef NO_VM /* machine without virtual memory! */
X if ((pid = fork()) == 0) {
X#else
X if ((pid = vfork()) == 0) {
X#endif
X
X setgid(groupid); /* and group id */
X setuid(userid); /* back to the normal user! */
X
X _exit(display(lines, msgnumber));
X }
X
X istat = signal(SIGINT, SIG_IGN);
X qstat = signal(SIGQUIT, SIG_IGN);
X
X while ((w = wait(&status)) != pid && w != -1)
X ;
X
X signal(SIGINT, istat);
X signal(SIGQUIT, qstat);
X
X#ifdef BSD
X return(status.w_retcode);
X#else
X return(status);
X#endif
X}
END_OF_src/showmsg.c
if test 10629 -ne `wc -c <src/showmsg.c`; then
echo shar: \"src/showmsg.c\" unpacked with wrong size!?
fi
# end of overwriting check
fi
echo shar: Extracting \"src/strings.c\" \(11005 characters\)
if test -f src/strings.c ; then
echo shar: Will not over-write existing file \"src/strings.c\"
else
sed "s/^X//" >src/strings.c <<'END_OF_src/strings.c'
X/** strings.c **/
X
X/** This file contains all the string oriented functions for the
X ELM Mailer, and lots of other generally useful string functions!
X
X For BSD systems, this file also includes the function "tolower"
X to translate the given character from upper case to lower case.
X
X (C) Copyright 1985, Dave Taylor
X**/
X
X#include <stdio.h>
X#include "headers.h"
X#include <ctype.h>
X
X#ifdef BSD
X#undef tolower
X#undef toupper
X#endif
X
X/** forward declarations **/
X
Xchar *format_long(), *strip_commas(), *tail_of_string(), *shift_lower(),
X *get_token(), *strip_parens(), *argv_zero(), *strcpy(), *strncpy();
X
X#ifdef BSD
X
Xint
Xtolower(ch)
Xchar ch;
X{
X /** This should be a macro call, but if you use this as a macro
X calls to 'tolower' where the argument is a function call will
X cause the function to be called TWICE which is obviously the
X wrong behaviour. On the other hand, to just blindly translate
X assuming the character is always uppercase can cause BIG
X problems, so...
X **/
X
X return ( isupper(ch) ? ch - 'A' + 'a' : ch );
X}
X
Xint
Xtoupper(ch)
Xchar ch;
X{
X /** see comment for above routine - tolower() **/
X
X return ( islower(ch) ? ch - 'a' + 'A' : ch );
X}
X
X#endif
X
Xint
Xprintable_chars(string)
Xchar *string;
X{
X /** Returns the number of "printable" (ie non-control) characters
X in the given string... Modified 4/86 to know about TAB
X characters being every eight characters... **/
X
X register int count = 0, index;
X
X for (index = 0; index < strlen(string); index++)
X if (string[index] >= ' ')
X if (string[index] == '\t')
X count += (7-(count % 8));
X else
X count++;
X
X return(count);
X}
X
Xtail_of(from, buffer, header_line)
Xchar *from, *buffer;
Xint header_line;
X{
X /** Return last two words of 'from'. This is to allow
X painless display of long return addresses as simply the
X machine!username. Alternatively, if the first three
X characters of the 'from' address are 'To:' and 'header_line'
X is TRUE, then return the buffer value prepended with 'To '.
X
X Mangled to know about the PREFER_UUCP hack. 6/86
X **/
X
X /** Note: '!' delimits Usenet nodes, '@' delimits ARPA nodes,
X ':' delimits CSNet & Bitnet nodes, and '%' delimits
X multiple stage ARPA hops... **/
X
X register int loc, i = 0, cnt = 0;
X char tempbuffer[SLEN];
X
X#ifdef PREFER_UUCP
X
X /** let's see if we have an address appropriate for hacking **/
X
X if (chloc(from,'!') != -1 && in_string(from, BOGUS_INTERNET))
X from[strlen(from)-strlen(BOGUS_INTERNET)] = '\0';
X
X#endif
X
X for (loc = strlen(from)-1; loc >= 0 && cnt < 2; loc--) {
X if (from[loc] == BANG || from[loc] == AT_SIGN ||
X from[loc] == COLON) cnt++;
X if (cnt < 2) buffer[i++] = from[loc];
X }
X
X buffer[i] = '\0';
X
X reverse(buffer);
X
X if ((strncmp(buffer,"To:", 3) == 0) && header_line)
X buffer[2] = ' ';
X else if ((strncmp(from, "To:", 3) == 0) && header_line) {
X sprintf(tempbuffer,"To %s", buffer);
X strcpy(buffer, tempbuffer);
X }
X else if (strncmp(buffer, "To:", 3) == 0) {
X for (i=3; i < strlen(buffer); i++)
X tempbuffer[i-3] = buffer[i];
X tempbuffer[i-3] = '\0';
X strcpy(buffer, tempbuffer);
X }
X}
X
Xchar *format_long(inbuff, init_len)
Xchar *inbuff;
Xint init_len;
X{
X /** Return buffer with \n\t sequences added at each point where it
X would be more than 80 chars long. It only allows the breaks at
X legal points (ie commas followed by white spaces). init-len is
X the characters already on the first line... Changed so that if
X this is called while mailing without the overhead of "elm", it'll
X include "\r\n\t" instead.
X Changed to use ',' as a separator and to REPLACE it after it's
X found in the output stream...
X **/
X
X static char ret_buffer[VERY_LONG_STRING];
X register int index = 0, current_length = 0, depth=15, i;
X char buffer[VERY_LONG_STRING];
X char *word, *bufptr;
X
X strcpy(buffer, inbuff);
X
X bufptr = (char *) buffer;
X
X current_length = init_len + 2; /* for luck */
X
X while ((word = get_token(bufptr,",", depth)) != NULL) {
X
X /* first, decide what sort of separator we need, if any... */
X
X if (strlen(word) + current_length > 80) {
X if (index > 0) {
X ret_buffer[index++] = ','; /* close 'er up, doctor! */
X if (mail_only)
X ret_buffer[index++] = '\r';
X ret_buffer[index++] = '\n';
X ret_buffer[index++] = '\t';
X }
X
X /* now add this pup! */
X
X for (i=(word[0] == ' '? 1:0); i<strlen(word); i++)
X ret_buffer[index++] = word[i];
X current_length = strlen(word) + 8; /* 8 = TAB */
X }
X
X else { /* just add this address to the list.. */
X
X if (index > 0) {
X ret_buffer[index++] = ','; /* comma added! */
X ret_buffer[index++] = ' ';
X current_length += 2;
X }
X for (i=(word[0] == ' '? 1:0); i<strlen(word); i++)
X ret_buffer[index++] = word[i];
X current_length += strlen(word);
X }
X
X bufptr = NULL;
X }
X
X ret_buffer[index] = '\0';
X
X return( (char *) ret_buffer);
X}
X
Xchar *strip_commas(string)
Xchar *string;
X{
X /** return string with all commas changed to spaces. This IS
X destructive and will permanently change the input string.. **/
X
X register int i;
X
X for (i=0; i < strlen(string); i++)
X if (string[i] == COMMA)
X string[i] = SPACE;
X
X return( (char *) string);
X}
X
Xchar *strip_parens(string)
Xchar *string;
X{
X /** Return string with all parenthesized information removed.
X This is a non-destructive algorithm... **/
X
X static char buffer[VERY_LONG_STRING];
X register int i, depth = 0, buffer_index = 0;
X
X for (i=0; i < strlen(string); i++) {
X if (string[i] == '(')
X depth++;
X else if (string[i] == ')')
X depth--;
X else if (depth == 0)
X buffer[buffer_index++] = string[i];
X }
X
X buffer[buffer_index] = '\0';
X
X return( (char *) buffer);
X}
X
Xmove_left(string, chars)
Xchar string[];
Xint chars;
X{
X /** moves string chars characters to the left DESTRUCTIVELY **/
X
X register int i;
X
X chars--; /* index starting at zero! */
X
X for (i=chars; string[i] != '\0' && string[i] != '\n'; i++)
X string[i-chars] = string[i];
X
X string[i-chars] = '\0';
X}
X
Xremove_first_word(string)
Xchar *string;
X{ /** removes first word of string, ie up to first non-white space
X following a white space! **/
X
X register int loc;
X
X for (loc = 0; string[loc] != ' ' && string[loc] != '\0'; loc++)
X ;
X
X while (string[loc] == ' ' || string[loc] == '\t')
X loc++;
X
X move_left(string, ++loc);
X}
X
Xsplit_word(buffer, first, rest)
Xchar *buffer, *first, *rest;
X{
X /** Rip the buffer into first word and rest of word, translating it
X all to lower case as we go along..
X **/
X
X register int i, j = 0;
X
X /** skip leading white space, just in case.. **/
X
X for (i=0; whitespace(buffer[i]); i++) ;
X
X /** now copy into 'first' until we hit white space or EOLN **/
X
X for (j=0; i < strlen(buffer) && ! whitespace(buffer[i]); )
X first[j++] = tolower(buffer[i++]);
X
X first[j] = '\0';
X
X while (whitespace(buffer[i])) i++;
X
X for (j=0; i < strlen(buffer); i++)
X rest[j++] = tolower(buffer[i]);
X
X rest[j] = '\0';
X
X return;
X}
X
Xchar *tail_of_string(string, maxchars)
Xchar *string;
Xint maxchars;
X{
X /** Return a string that is the last 'maxchars' characters of the
X given string. This is only used if the first word of the string
X is longer than maxchars, else it will return what is given to
X it...
X **/
X
X static char buffer[SLEN];
X register int index, i;
X
X for (index=0;! whitespace(string[index]) && index < strlen(string);
X index++)
X ;
X
X if (index < maxchars) {
X strncpy(buffer, string, maxchars-2); /* word too short */
X buffer[maxchars-2] = '.';
X buffer[maxchars-1] = '.';
X buffer[maxchars] = '.';
X buffer[maxchars+1] = '\0';
X }
X else {
X i = maxchars;
X buffer[i--] = '\0';
X while (i > 1)
X buffer[i--] = string[index--];
X buffer[2] = '.';
X buffer[1] = '.';
X buffer[0] = '.';
X }
X
X return( (char *) buffer);
X}
X
Xreverse(string)
Xchar *string;
X{
X /** reverse string... pretty trivial routine, actually! **/
X
X char buffer[SLEN];
X register int i, j = 0;
X
X for (i = strlen(string)-1; i >= 0; i--)
X buffer[j++] = string[i];
X
X buffer[j] = '\0';
X
X strcpy(string, buffer);
X}
X
Xint
Xget_word(buffer, start, word)
Xchar *buffer, *word;
Xint start;
X{
X /** return next word in buffer, starting at 'start'.
X delimiter is space or end-of-line. Returns the
X location of the next word, or -1 if returning
X the last word in the buffer. -2 indicates empty
X buffer! **/
X
X register int loc = 0;
X
X while (buffer[start] == ' ' && buffer[start] != '\0')
X start++;
X
X if (buffer[start] == '\0') return(-2); /* nothing IN buffer! */
X
X while (buffer[start] != ' ' && buffer[start] != '\0')
X word[loc++] = buffer[start++];
X
X word[loc] = '\0';
X return(start);
X}
X
Xchar *shift_lower(string)
Xchar *string;
X{
X /** return 'string' shifted to lower case. Do NOT touch the
X actual string handed to us! **/
X
X static char buffer[LONG_SLEN];
X register int i;
X
X for (i=0; i < strlen(string); i++)
X if (isupper(string[i]))
X buffer[i] = tolower(string[i]);
X else
X buffer[i] = string[i];
X
X buffer[strlen(string)] = 0;
X
X return( (char *) buffer);
X}
X
XCenterline(line, string)
Xint line;
Xchar *string;
X{
X /** Output 'string' on the given line, centered. **/
X
X register int length, col;
X
X length = strlen(string);
X
X if (length > COLUMNS)
X col = 0;
X else
X col = (COLUMNS - length) / 2;
X
X PutLine0(line, col, string);
X}
X
Xchar *argv_zero(string)
Xchar *string;
X{
X /** given a string of the form "/something/name" return a
X string of the form "name"... **/
X
X static char buffer[NLEN];
X register int i, j=0;
X
X for (i=strlen(string)-1; string[i] != '/'; i--)
X buffer[j++] = string[i];
X buffer[j] = '\0';
X
X reverse(buffer);
X
X return( (char *) buffer);
X}
X
X#define MAX_RECURSION 20 /* up to 20 deep recursion */
X
Xchar *get_token(source, keys, depth)
Xchar *source, *keys;
Xint depth;
X{
X /** This function is similar to strtok() (see "opt_utils")
X but allows nesting of calls via pointers...
X **/
X
X register int last_ch;
X static char *buffers[MAX_RECURSION];
X char *return_value, *sourceptr;
X
X if (depth > MAX_RECURSION) {
X error1("get_token calls nested greater than %d deep!",
X MAX_RECURSION);
X emergency_exit();
X }
X
X if (source != NULL)
X buffers[depth] = source;
X
X sourceptr = buffers[depth];
X
X if (*sourceptr == '\0')
X return(NULL); /* we hit end-of-string last time!? */
X
X sourceptr += strspn(sourceptr, keys); /* skip the bad.. */
X
X if (*sourceptr == '\0') {
X buffers[depth] = sourceptr;
X return(NULL); /* we've hit end-of-string */
X }
X
X last_ch = strcspn(sourceptr, keys); /* end of good stuff */
X
X return_value = sourceptr; /* and get the ret */
X
X sourceptr += last_ch; /* ...value */
X
X if (*sourceptr != '\0') /** don't forget if we're at end! **/
X sourceptr++;
X
X return_value[last_ch] = '\0'; /* ..ending right */
X
X buffers[depth] = sourceptr; /* save this, mate! */
X
X return((char *) return_value); /* and we're outta here! */
X}
END_OF_src/strings.c
if test 11005 -ne `wc -c <src/strings.c`; then
echo shar: \"src/strings.c\" unpacked with wrong size!?
fi
# end of overwriting check
fi
echo shar: End of archive 11 \(of 19\).
cp /dev/null ark11isdone
DONE=true
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
echo shar: You still need to run archive ${I}.
DONE=false
fi
done
if test "$DONE" = "true" ; then
echo You have unpacked all 19 archives.
echo "See the Instructions file"
rm -f ark[1-9]isdone ark[1-9][0-9]isdone
fi
## End of shell archive.
exit 0