home *** CD-ROM | disk | FTP | other *** search
- Date: Tue, 7 May 85 13:53:58 pdt
- From: allegra!sdcrdcf!RDCF.SDC.UUCP!lwall (Larry Wall)
- Newsgroups: mod.sources
- Subject: rn version 4.3 (kit 5 of 9)
- Reply-To: lwall@sdcrdcf.UUCP
- Organization: System Development Corporation R&D, Santa Monica
-
- #! /bin/sh
-
- # Make a new directory for the rn sources, cd to it, and run kits 1 thru 9
- # through sh. When all 9 kits have been run, read README.
-
- echo "This is rn kit 5 (of 9). If kit 5 is complete, the line"
- echo '"'"End of kit 5 (of 9)"'" will echo at the end.'
- echo ""
- export PATH || (echo "You didn't use sh, you clunch." ; kill $$)
- echo Extracting term.c
- cat >term.c <<'!STUFFY!FUNK!'
- /* $Header: term.c,v 4.3 85/05/01 11:51:10 lwall Exp $
- *
- * $Log: term.c,v $
- * Revision 4.3 85/05/01 11:51:10 lwall
- * Baseline for release with 4.3bsd.
- *
- */
-
- #include "EXTERN.h"
- #include "common.h"
- #include "util.h"
- #include "final.h"
- #include "help.h"
- #include "cheat.h"
- #include "intrp.h"
- #include "INTERN.h"
- #include "term.h"
-
- char ERASECH; /* rubout character */
- char KILLCH; /* line delete character */
- char tcarea[TCSIZE]; /* area for "compiled" termcap strings */
-
- /* guarantee capability pointer != Nullch */
- /* (I believe terminfo will ignore the &tmpaddr argument.) */
-
- #define Tgetstr(key) ((tmpstr = tgetstr(key,&tmpaddr)) ? tmpstr : nullstr)
-
- #ifdef PUSHBACK
- struct keymap {
- char km_type[128];
- union km_union {
- struct keymap *km_km;
- char *km_str;
- } km_ptr[128];
- };
-
- #define KM_NOTHIN 0
- #define KM_STRING 1
- #define KM_KEYMAP 2
- #define KM_BOGUS 3
-
- #define KM_TMASK 3
- #define KM_GSHIFT 4
- #define KM_GMASK 7
-
- typedef struct keymap KEYMAP;
-
- KEYMAP *topmap INIT(Null(KEYMAP*));
-
- void mac_init();
- KEYMAP *newkeymap();
- void show_keymap();
- void pushstring();
- #endif
-
- /* terminal initialization */
-
- void
- term_init()
- {
- savetty(); /* remember current tty state */
-
- #ifdef TERMIO
- ospeed = _tty.c_cflag & CBAUD; /* for tputs() */
- ERASECH = _tty.c_cc[VERASE]; /* for finish_command() */
- KILLCH = _tty.c_cc[VKILL]; /* for finish_command() */
- #else
- ospeed = _tty.sg_ospeed; /* for tputs() */
- ERASECH = _tty.sg_erase; /* for finish_command() */
- KILLCH = _tty.sg_kill; /* for finish_command() */
- #endif
-
- /* The following could be a table but I can't be sure that there isn't */
- /* some degree of sparsity out there in the world. */
-
- switch (ospeed) { /* 1 second of padding */
- #ifdef BEXTA
- case BEXTA: just_a_sec = 1920; break;
- #else
- #ifdef B19200
- case B19200: just_a_sec = 1920; break;
- #endif
- #endif
- case B9600: just_a_sec = 960; break;
- case B4800: just_a_sec = 480; break;
- case B2400: just_a_sec = 240; break;
- case B1800: just_a_sec = 180; break;
- case B1200: just_a_sec = 120; break;
- case B600: just_a_sec = 60; break;
- case B300: just_a_sec = 30; break;
- /* do I really have to type the rest of this??? */
- case B200: just_a_sec = 20; break;
- case B150: just_a_sec = 15; break;
- case B134: just_a_sec = 13; break;
- case B110: just_a_sec = 11; break;
- case B75: just_a_sec = 8; break;
- case B50: just_a_sec = 5; break;
- default: just_a_sec = 960; break;
- /* if we are running detached I */
- } /* don't want to know about it! */
- }
-
- /* set terminal characteristics */
-
- void
- term_set(tcbuf)
- char *tcbuf; /* temp area for "uncompiled" termcap entry */
- {
- char *tmpaddr; /* must not be register */
- register char *tmpstr;
- char *tgetstr();
- char *s;
- int status;
-
- #ifdef PENDING
- #ifndef FIONREAD
- /* do no delay reads on something that always gets closed on exit */
-
- devtty = open("/dev/tty",0);
- if (devtty < 0) {
- printf(cantopen,"/dev/tty") FLUSH;
- finalize(1);
- }
- fcntl(devtty,F_SETFL,O_NDELAY);
- #endif
- #endif
-
- /* get all that good termcap stuff */
-
- #ifdef HAVETERMLIB
- status = tgetent(tcbuf,getenv("TERM")); /* get termcap entry */
- if (status < 1) {
- #ifdef VERBOSE
- printf("No termcap %s found.\n", status ? "file" : "entry") FLUSH;
- #else
- fputs("Termcap botch\n",stdout) FLUSH
- #endif
- finalize(1);
- }
- tmpaddr = tcarea; /* set up strange tgetstr pointer */
- s = Tgetstr("pc"); /* get pad character */
- PC = *s; /* get it where tputs wants it */
- if (!tgetflag("bs")) /* is backspace not used? */
- BC = Tgetstr("bc"); /* find out what is */
- else
- BC = "\b"; /* make a backspace handy */
- UP = Tgetstr("up"); /* move up a line */
- if (!*UP) /* no UP string? */
- marking = 0; /* disable any marking */
- if (muck_up_clear) /* this is for weird HPs */
- CL = "\n\n\n\n";
- else
- CL = Tgetstr("cl"); /* get clear string */
- CE = Tgetstr("ce"); /* clear to end of line string */
- #ifdef CLEAREOL
- CM = Tgetstr("cm"); /* cursor motion - PWP */
- HO = Tgetstr("ho"); /* home cursor if no CM - PWP */
- CD = Tgetstr("cd"); /* clear to end of display - PWP */
- if (!*CE || !*CD || (!*CM && !*HO)) /* can we CE, CD, and home? */
- can_home_clear = FALSE; /* no, so disable use of clear eol */
- #endif CLEAREOL
- SO = Tgetstr("so"); /* begin standout */
- SE = Tgetstr("se"); /* end standout */
- if ((SG = tgetnum("sg"))<0)
- SG = 0; /* blanks left by SG, SE */
- US = Tgetstr("us"); /* start underline */
- UE = Tgetstr("ue"); /* end underline */
- if ((UG = tgetnum("ug"))<0)
- UG = 0; /* blanks left by US, UE */
- if (*US)
- UC = nullstr; /* UC must not be NULL */
- else
- UC = Tgetstr("uc"); /* underline a character */
- if (!*US && !*UC) { /* no underline mode? */
- US = SO; /* substitute standout mode */
- UE = SE;
- UG = SG;
- }
- LINES = tgetnum("li"); /* lines per page */
- COLS = tgetnum("co"); /* columns on page */
- AM = tgetflag("am"); /* terminal wraps automatically? */
- XN = tgetflag("xn"); /* then eats next newline? */
- VB = Tgetstr("vb");
- if (!*VB)
- VB = "\007";
- CR = Tgetstr("cr");
- if (!*CR) {
- if (tgetflag("nc") && *UP) {
- CR = safemalloc((MEM_SIZE)strlen(UP)+2);
- sprintf(CR,"%s\r",UP);
- }
- else
- CR = "\r";
- }
- #else
- ?????? /* Roll your own... */
- #endif
- if (LINES > 0) { /* is this a crt? */
- if (!initlines) /* no -i? */
- if (ospeed >= B9600) /* whole page at >= 9600 baud */
- initlines = LINES;
- else if (ospeed >= B4800) /* 16 lines at 4800 */
- initlines = 16;
- else /* otherwise just header */
- initlines = 8;
- }
- else { /* not a crt */
- LINES = 30000; /* so don't page */
- CL = "\n\n"; /* put a couple of lines between */
- if (!initlines) /* make initlines reasonable */
- initlines = 8;
- }
- if (COLS <= 0)
- COLS = 80;
- noecho(); /* turn off echo */
- crmode(); /* enter cbreak mode */
-
- #ifdef PUSHBACK
- mac_init(tcbuf);
- #endif
- }
-
- #ifdef PUSHBACK
- void
- mac_init(tcbuf)
- char *tcbuf;
- {
- char tmpbuf[1024];
-
- tmpfp = fopen(filexp(getval("RNMACRO",RNMACRO)),"r");
- if (tmpfp != Nullfp) {
- while (fgets(tcbuf,1024,tmpfp) != Nullch) {
- mac_line(tcbuf,tmpbuf,(sizeof tmpbuf));
- }
- fclose(tmpfp);
- }
- }
-
- void
- mac_line(line,tmpbuf,tbsize)
- char *line;
- char *tmpbuf;
- int tbsize;
- {
- register char *s, *m;
- register KEYMAP *curmap;
- register int ch;
- register int garbage = 0;
- static char override[] = "\nkeymap overrides string\n";
-
- if (topmap == Null(KEYMAP*))
- topmap = newkeymap();
- if (*line == '#' || *line == '\n')
- return;
- if (line[ch = strlen(line)-1] == '\n')
- line[ch] = '\0';
- m = dointerp(tmpbuf,tbsize,line," \t");
- if (!*m)
- return;
- while (*m == ' ' || *m == '\t') m++;
- for (s=tmpbuf,curmap=topmap; *s; s++) {
- ch = *s & 0177;
- if (s[1] == '+' && isdigit(s[2])) {
- s += 2;
- garbage = (*s & KM_GMASK) << KM_GSHIFT;
- }
- else
- garbage = 0;
- if (s[1]) {
- if ((curmap->km_type[ch] & KM_TMASK) == KM_STRING) {
- puts(override,stdout) FLUSH;
- free(curmap->km_ptr[ch].km_str);
- curmap->km_ptr[ch].km_str = Nullch;
- }
- curmap->km_type[ch] = KM_KEYMAP + garbage;
- if (curmap->km_ptr[ch].km_km == Null(KEYMAP*))
- curmap->km_ptr[ch].km_km = newkeymap();
- curmap = curmap->km_ptr[ch].km_km;
- }
- else {
- if ((curmap->km_type[ch] & KM_TMASK) == KM_KEYMAP)
- puts(override,stdout) FLUSH;
- else {
- curmap->km_type[ch] = KM_STRING + garbage;
- curmap->km_ptr[ch].km_str = savestr(m);
- }
- }
- }
- }
-
- KEYMAP*
- newkeymap()
- {
- register int i;
- register KEYMAP *map;
-
- #ifndef lint
- map = (KEYMAP*)safemalloc(sizeof(KEYMAP));
- #else
- map = Null(KEYMAP*);
- #endif lint
- for (i=127; i>=0; --i) {
- map->km_ptr[i].km_km = Null(KEYMAP*);
- map->km_type[i] = KM_NOTHIN;
- }
- return map;
- }
-
- void
- show_macros()
- {
- char prebuf[64];
-
- if (topmap != Null(KEYMAP*)) {
- print_lines("Macros:\n",STANDOUT);
- *prebuf = '\0';
- show_keymap(topmap,prebuf);
- }
- }
-
- void
- show_keymap(curmap,prefix)
- register KEYMAP *curmap;
- char *prefix;
- {
- register int i;
- register char *next = prefix + strlen(prefix);
- register int kt;
-
- for (i=0; i<128; i++) {
- if (kt = curmap->km_type[i]) {
- if (i < ' ')
- sprintf(next,"^%c",i+64);
- else if (i == ' ')
- strcpy(next,"\\040");
- else if (i == 127)
- strcpy(next,"^?");
- else
- sprintf(next,"%c",i);
- if ((kt >> KM_GSHIFT) & KM_GMASK) {
- sprintf(cmd_buf,"+%d", (kt >> KM_GSHIFT) & KM_GMASK);
- strcat(next,cmd_buf);
- }
- switch (kt & KM_TMASK) {
- case KM_NOTHIN:
- sprintf(cmd_buf,"%s %c\n",prefix,i);
- print_lines(cmd_buf,NOMARKING);
- break;
- case KM_KEYMAP:
- show_keymap(curmap->km_ptr[(char)i].km_km, prefix);
- break;
- case KM_STRING:
- sprintf(cmd_buf,"%s %s\n",prefix,curmap->km_ptr[i].km_str);
- print_lines(cmd_buf,NOMARKING);
- break;
- case KM_BOGUS:
- sprintf(cmd_buf,"%s BOGUS\n",prefix);
- print_lines(cmd_buf,STANDOUT);
- break;
- }
- }
- }
- }
-
- #endif
-
- /* routine to pass to tputs */
-
- char
- putchr(ch)
- register char ch;
- {
- putchar(ch);
- #ifdef lint
- ch = Null(char);
- ch = ch;
- #endif
- }
-
- /* input the 2nd and succeeding characters of a multi-character command */
- /* returns TRUE if command finished, FALSE if they rubbed out first character */
-
- bool
- finish_command(donewline)
- int donewline;
- {
- register char *s;
- register bool quoteone = FALSE;
-
- s = buf;
- if (s[1] != FINISHCMD) /* someone faking up a command? */
- return TRUE;
- do {
- top:
- if (*s < ' ') {
- putchar('^');
- putchar(*s | 64);
- }
- else if (*s == '\177') {
- putchar('^');
- putchar('?');
- }
- else
- putchar(*s); /* echo previous character */
- s++;
- re_read:
- fflush(stdout);
- getcmd(s);
- if (quoteone) {
- quoteone = FALSE;
- continue;
- }
- if (errno || *s == Ctl('l')) {
- *s = Ctl('r'); /* force rewrite on CONT */
- }
- if (*s == '\033') { /* substitution desired? */
- #ifdef ESCSUBS
- char tmpbuf[4], *cpybuf;
-
- tmpbuf[0] = '%';
- read_tty(&tmpbuf[1],1);
- #ifdef RAWONLY
- tmpbuf[1] &= 0177;
- #endif
- tmpbuf[2] = '\0';
- if (tmpbuf[1] == 'h') {
- (void) help_subs();
- *s = '\0';
- reprint();
- goto re_read;
- }
- else if (tmpbuf[1] == '\033') {
- *s = '\0';
- cpybuf = savestr(buf);
- interp(buf, (sizeof buf), cpybuf);
- free(cpybuf);
- s = buf + strlen(buf);
- reprint();
- goto re_read;
- }
- else {
- interp(s,(sizeof buf) - (s-buf),tmpbuf);
- fputs(s,stdout);
- s += strlen(s);
- }
- goto re_read;
- #else
- notincl("^[");
- *s = '\0';
- reprint();
- goto re_read;
- #endif
- }
- else if (*s == ERASECH) { /* they want to rubout a char? */
- rubout();
- s--; /* discount the char rubbed out */
- if (*s < ' ' || *s == '\177')
- rubout();
- if (s == buf) { /* entire string gone? */
- fflush(stdout); /* return to single char command mode */
- return FALSE;
- }
- else
- goto re_read;
- }
- else if (*s == KILLCH) { /* wipe out the whole line? */
- while (s-- != buf) { /* emulate that many ERASEs */
- rubout();
- if (*s < ' ' || *s == '\177')
- rubout();
- }
- fflush(stdout);
- return FALSE; /* return to single char mode */
- }
- #ifdef WORDERASE
- else if (*s == Ctl('w')) { /* wipe out one word? */
- *s-- = ' ';
- while (!isspace(*s) || isspace(s[1])) {
- rubout();
- if (s-- == buf) {
- fflush(stdout);
- return FALSE; /* return to single char mode */
- }
- if (*s < ' ' || *s == '\177')
- rubout();
- }
- s++;
- goto re_read;
- }
- #endif
- else if (*s == Ctl('r')) {
- *s = '\0';
- reprint();
- goto re_read;
- }
- else if (*s == Ctl('v')) {
- putchar('^');
- backspace();
- fflush(stdout);
- getcmd(s);
- goto top;
- }
- else if (*s == '\\') {
- quoteone = TRUE;
- }
- } while (*s != '\n'); /* till a newline (not echoed) */
- *s = '\0'; /* terminate the string nicely */
- if (donewline)
- putchar('\n') FLUSH;
- return TRUE; /* say we succeeded */
- }
-
- /* discard any characters typed ahead */
-
- void
- eat_typeahead()
- {
- #ifdef PUSHBACK
- if (!typeahead && nextin==nextout) /* cancel only keyboard stuff */
- #else
- if (!typeahead)
- #endif
- {
- #ifdef PENDING
- while (input_pending())
- read_tty(buf,sizeof(buf));
- #else /* this is probably v7 */
- ioctl(_tty_ch,TIOCSETP,&_tty);
- #endif
- }
- }
-
- void
- settle_down()
- {
- dingaling();
- fflush(stdout);
- sleep(1);
- #ifdef PUSHBACK
- nextout = nextin; /* empty circlebuf */
- #endif
- eat_typeahead();
- }
-
- #ifdef PUSHBACK
- /* read a character from the terminal, with multi-character pushback */
-
- int
- read_tty(addr,size)
- char *addr;
- int size;
- {
- if (nextout != nextin) {
- *addr = circlebuf[nextout++];
- nextout %= PUSHSIZE;
- return 1;
- }
- else {
- size = read(0,addr,size);
- #ifdef RAWONLY
- *addr &= 0177;
- #endif
- return size;
- }
- }
-
- #ifdef PENDING
- #ifndef FIONREAD
- int
- circfill()
- {
- register int howmany = read(devtty,circlebuf+nextin,1);
-
- if (howmany) {
- nextin += howmany;
- nextin %= PUSHSIZE;
- }
- return howmany;
- }
- #endif PENDING
- #endif FIONREAD
-
- void
- pushchar(c)
- char c;
- {
- nextout--;
- if (nextout < 0)
- nextout = PUSHSIZE - 1;
- if (nextout == nextin) {
- fputs("\npushback buffer overflow\n",stdout) FLUSH;
- sig_catcher(0);
- }
- circlebuf[nextout] = c;
- }
-
- #else PUSHBACK
- #ifndef read_tty
- /* read a character from the terminal, with hacks for O_NDELAY reads */
-
- int
- read_tty(addr,size)
- char *addr;
- int size;
- {
- if (is_input) {
- *addr = pending_ch;
- is_input = FALSE;
- return 1;
- }
- else {
- size = read(0,addr,size)
- #ifdef RAWONLY
- *addr &= 0177;
- #endif
- return size;
- }
- }
- #endif read_tty
- #endif PUSHBACK
-
- /* print an underlined string, one way or another */
-
- void
- underprint(s)
- register char *s;
- {
- assert(UC);
- if (*UC) { /* char by char underline? */
- while (*s) {
- if (*s < ' ') {
- putchar('^');
- backspace();/* back up over it */
- underchar();/* and do the underline */
- putchar(*s+64);
- backspace();/* back up over it */
- underchar();/* and do the underline */
- }
- else {
- putchar(*s);
- backspace();/* back up over it */
- underchar();/* and do the underline */
- }
- s++;
- }
- }
- else { /* start and stop underline */
- underline(); /* start underlining */
- while (*s) {
- if (*s < ' ') {
- putchar('^');
- putchar(*s+64);
- }
- else
- putchar(*s);
- s++;
- }
- un_underline(); /* stop underlining */
- }
- }
-
- /* keep screen from flashing strangely on magic cookie terminals */
-
- #ifdef NOFIREWORKS
- void
- no_sofire()
- {
- if (*UP && *SE) { /* should we disable fireworks? */
- putchar('\n');
- un_standout();
- up_line();
- carriage_return();
- }
- }
-
- void
- no_ulfire()
- {
- if (*UP && *US) { /* should we disable fireworks? */
- putchar('\n');
- un_underline();
- up_line();
- carriage_return();
- }
- }
- #endif
-
- /* get a character into a buffer */
-
- void
- getcmd(whatbuf)
- register char *whatbuf;
- {
- #ifdef PUSHBACK
- register KEYMAP *curmap;
- register int i;
- bool no_macros;
- int times = 0; /* loop detector */
- char scrchar;
-
- tryagain:
- curmap = topmap;
- no_macros = (whatbuf != buf && nextin == nextout);
- #endif
- for (;;) {
- int_count = 0;
- errno = 0;
- if (read_tty(whatbuf,1) < 0 && !errno)
- errno = EINTR;
- if (errno && errno != EINTR) {
- perror(readerr);
- sig_catcher(0);
- }
- #ifdef PUSHBACK
- if (*whatbuf & 0200 || no_macros) {
- *whatbuf &= 0177;
- goto got_canonical;
- }
- if (curmap == Null(KEYMAP*))
- goto got_canonical;
- for (i = (curmap->km_type[*whatbuf] >> KM_GSHIFT) & KM_GMASK; i; --i){
- read_tty(&scrchar,1);
- }
- switch (curmap->km_type[*whatbuf] & KM_TMASK) {
- case KM_NOTHIN: /* no entry? */
- if (curmap == topmap) /* unmapped canonical */
- goto got_canonical;
- settle_down();
- goto tryagain;
- case KM_KEYMAP: /* another keymap? */
- curmap = curmap->km_ptr[*whatbuf].km_km;
- assert(curmap != Null(KEYMAP*));
- break;
- case KM_STRING: /* a string? */
- pushstring(curmap->km_ptr[*whatbuf].km_str);
- if (++times > 20) { /* loop? */
- fputs("\nmacro loop?\n",stdout);
- settle_down();
- }
- no_macros = FALSE;
- goto tryagain;
- }
- #else
- #ifdef RAWONLY
- *whatbuf &= 0177;
- #endif
- break;
- #endif
- }
-
- got_canonical:
- if (whatbuf == buf)
- whatbuf[1] = FINISHCMD; /* tell finish_command to work */
- }
-
- #ifdef PUSHBACK
- void
- pushstring(str)
- char *str;
- {
- register int i;
- char tmpbuf[PUSHSIZE];
- register char *s = tmpbuf;
-
- assert(str != Nullch);
- interp(s,PUSHSIZE,str);
- for (i = strlen(s)-1; i >= 0; --i) {
- s[i] ^= 0200;
- pushchar(s[i]);
- }
- }
- #endif
-
- int
- get_anything()
- {
- char tmpbuf[2];
-
- reask_anything:
- unflush_output(); /* disable any ^O in effect */
- standout();
- #ifdef VERBOSE
- IF(verbose)
- fputs("[Type space to continue] ",stdout);
- ELSE
- #endif
- #ifdef TERSE
- fputs("[MORE] ",stdout);
- #endif
- un_standout();
- fflush(stdout);
- eat_typeahead();
- if (int_count) {
- return -1;
- }
- collect_subjects(); /* loads subject cache until */
- /* input is pending */
- getcmd(tmpbuf);
- if (errno || *tmpbuf == '\f') {
- putchar('\n') FLUSH; /* if return from stop signal */
- goto reask_anything; /* give them a prompt again */
- }
- if (*tmpbuf == 'h') {
- #ifdef VERBOSE
- IF(verbose)
- fputs("\nType q to quit or space to continue.\n",stdout) FLUSH;
- ELSE
- #endif
- #ifdef TERSE
- fputs("\nq to quit, space to continue.\n",stdout) FLUSH;
- #endif
- goto reask_anything;
- }
- else if (*tmpbuf != ' ' && *tmpbuf != '\n') {
- carriage_return();
- erase_eol(); /* erase the prompt */
- return *tmpbuf == 'q' ? -1 : *tmpbuf;
- }
- if (*tmpbuf == '\n') {
- page_line = LINES - 1;
- carriage_return();
- erase_eol();
- }
- else {
- page_line = 1;
- if (erase_screen) /* -e? */
- clear(); /* clear screen */
- else {
- carriage_return();
- erase_eol(); /* erase the prompt */
- }
- }
- return 0;
- }
-
- void
- in_char(prompt)
- char *prompt;
- {
- char oldmode = mode;
-
- reask_in_char:
- unflush_output(); /* disable any ^O in effect */
- fputs(prompt,stdout);
- fflush(stdout);
- eat_typeahead();
- mode = 'm';
- getcmd(buf);
- if (errno || *buf == '\f') {
- putchar('\n') FLUSH; /* if return from stop signal */
- goto reask_in_char; /* give them a prompt again */
- }
- mode = oldmode;
- }
-
- int
- print_lines(what_to_print,hilite)
- char *what_to_print;
- int hilite;
- {
- register char *s;
- register int i;
-
- if (page_line < 0) /* they do not want to see this? */
- return -1;
- for (s=what_to_print; *s; ) {
- if (page_line >= LINES || int_count) {
- if (i = -1, int_count || (i = get_anything())) {
- page_line = -1; /* disable further print_lines */
- return i;
- }
- }
- page_line++;
- if (hilite == STANDOUT) {
- #ifdef NOFIREWORKS
- if (erase_screen)
- no_sofire();
- #endif
- standout();
- }
- else if (hilite == UNDERLINE) {
- #ifdef NOFIREWORKS
- if (erase_screen)
- no_ulfire();
- #endif
- underline();
- }
- for (i=0; i<COLS; i++) {
- if (!*s)
- break;
- if (*s >= ' ')
- putchar(*s);
- else if (*s == '\t') {
- putchar(*s);
- i = ((i+8) & ~7) - 1;
- }
- else if (*s == '\n') {
- i = 32000;
- }
- else {
- i++;
- putchar('^');
- putchar(*s + 64);
- }
- s++;
- }
- if (i) {
- if (hilite == STANDOUT)
- un_standout();
- else if (hilite == UNDERLINE)
- un_underline();
- if (AM && i == COLS)
- fflush(stdout);
- else
- putchar('\n') FLUSH;
- }
- }
- return 0;
- }
-
- void
- page_init()
- {
- page_line = 1;
- if (erase_screen)
- clear();
- else
- putchar('\n') FLUSH;
- }
-
- void
- pad(num)
- int num;
- {
- register int i;
-
- for (i = num; i; --i)
- putchar(PC);
- fflush(stdout);
- }
-
- /* echo the command just typed */
-
- #ifdef VERIFY
- void
- printcmd()
- {
- if (verify && buf[1] == FINISHCMD) {
- if (*buf < ' ') {
- putchar('^');
- putchar(*buf | 64);
- backspace();
- backspace();
- }
- else {
- putchar(*buf);
- backspace();
- }
- fflush(stdout);
- }
- }
- #endif
-
- void
- rubout()
- {
- backspace(); /* do the old backspace, */
- putchar(' '); /* space, */
- backspace(); /* backspace trick */
- }
-
- void
- reprint()
- {
- register char *s;
-
- fputs("^R\n",stdout) FLUSH;
- for (s = buf; *s; s++) {
- if (*s < ' ') {
- putchar('^');
- putchar(*s | 64);
- }
- else
- putchar(*s);
- }
- }
-
- #ifdef CLEAREOL
- /* start of additions by Paul Placeway (PWP) */
-
- void
- home_cursor()
- {
- char *tgoto();
-
- if (!*HO) { /* no home sequence? */
- if (!*CM) { /* no cursor motion either? */
- fputs ("\n\n\n", stdout);
- return; /* forget it. */
- }
- tputs (tgoto (CM, 0, 0), 1, putchr); /* go to home via CM */
- return;
- }
- else { /* we have home sequence */
- tputs (HO, 1, putchr); /* home via HO */
- }
- }
- #endif CLEAREOL
- !STUFFY!FUNK!
- echo Extracting Pnews.SH
- cat >Pnews.SH <<'!STUFFY!FUNK!'
- case $CONFIG in
- '') . config.sh ;;
- esac
- echo "Extracting Pnews (with variable substitutions)"
- $spitshell >Pnews <<!GROK!THIS!
- $startsh
- # $Header: Pnews.SH,v 4.3 85/05/01 12:20:33 lwall Exp $
- #
- # $Log: Pnews.SH,v $
- # Revision 4.3 85/05/01 12:20:33 lwall
- # Baseline for release with 4.3bsd.
- #
- #
- # syntax: Pnews -h headerfile or
- # Pnews -h headerfile oldarticle or
- # Pnews newsgroup title or just
- # Pnews
-
- export PATH || (echo "OOPS, this isn't sh. Desperation time. I will feed myself to sh."; sh \$0; kill \$\$)
-
- # System dependencies
-
- mailer="${mailer-/bin/mail}"
- # if you change this to something that does signatures, take out signature code
-
- case $portable in
- define)
- # your site name
- sitename=\`$hostcmd\`
- # where recordings, distributions and moderators are kept
- lib=\`$filexp $lib\`
- # where important rn things are kept
- rnlib=\`$filexp $rnlib\`
- ;;
- undef)
- # your site name
- sitename="$sitename"
- # where recordings, distributions and moderators are kept
- lib="$lib"
- # where important rn things are kept
- rnlib="$rnlib"
- ;;
- esac
-
- # your organization name
- orgname="$orgname"
- # what pager you use--if you have kernal paging use cat
- pager="\${PAGER-$pager}"
- # how you derive full names, bsd, usg, or other
- nametype="$nametype"
- # default editor
- defeditor="$defeditor"
- # how not to echo with newline
- n="$n"
- c="$c"
-
- # You should also look at the distribution warnings below marked !DIST!
- # to make sure any distribution regions you are a member of are included.
- # The following are some prototypical distribution groups. If you do not
- # use them all set the unused ones to a non-null string such as 'none'.
- loc="$locpref"
- org="$orgpref"
- city="$citypref"
- state="$statepref"
- cntry="$cntrypref"
- cont="$contpref"
-
- test=${test-test}
- sed=${sed-sed}
- echo=${echo-echo}
- cat=${cat-cat}
- egrep=${egrep-egrep}
- grep=${grep-grep}
- rm=${rm-rm}
- tr=${tr-tr}
- inews=${inews-inews}
-
- !GROK!THIS!
- $spitshell >>Pnews <<'!NO!SUBS!'
- if $test -f ${DOTDIR-${HOME-$LOGDIR}}/.pnewsexpert; then
- expertise=expert
- else
- $cat <<'EOM'
- I see you've never used this version of Pnews before. I will give you extra
- help this first time through, but then you must remember what you learned.
- If you don't understand any question, type h and a CR (carriage return) for
- help.
-
- If you've never posted an article to the net before, it is HIGHLY recommended
- that you read the netiquette document found in net.announce.newusers so
- that you'll know to avoid the commonest blunders. To do that, interrupt
- Pnews, and get to the top-level prompt of rn. Say "g net.announce.newusers"
- and you are on your way.
-
- EOM
- expertise=beginner
- fi
-
- case $cntry in
- can) stpr=Province ;;
- *) stpr=State ;;
- esac
-
- tmpart=/tmp/article$$
-
- headerfile=""
- case $# in
- 0) ;;
- *) case $1 in
- -h)
- headerfile="$2"
- shift
- shift
- case $# in
- 0)
- oldart=""
- ;;
- *)
- oldart="$1"
- shift
- ;;
- esac
- ;;
- esac
- ;;
- esac
-
- case $headerfile in
- '')
- . $rnlib/Pnews.header
- ;;
- *)
- $cat < $headerfile > $tmpart
- ;;
- esac
- rescue="sleep 1; $cat $tmpart >>${HOME-$LOGDIR}/dead.article ; $echo saved in ${HOME-$LOGDIR}/dead.article ; $rm -f $tmpart; exit"
- trap "$rescue" 1
- trap "$rescue" 2
-
- $echo ""
- set X `$sed < $tmpart -n -e '/^Distribution: /{' -e p -e q -e '}' -e '/^$/q'`
- shift
- case $# in
- 0|1)
- set X `$sed < $tmpart -n -e '/^Newsgroups: /{' -e p -e q -e '}'`
- shift
- case $# in
- 0|1)
- set "x net.whatever"
- ;;
- esac
- ;;
- *)
- set $1 $2.whatever
- ;;
- esac
- shift
-
- #: play recorded message
- #if $test -s ${lib}/recording ; then
- # ng=`$echo $1 | $sed "s/,.*//"`
- # _rec1=${lib}/`$sed -n "/^$ng/s/^.* //p" ${lib}/recording`
- # _tmp=`$echo $ng |$sed "s/\..*//"`
- # _rec2=${lib}/`$cat -s ${lib}/recording|$grep ${_tmp}.all|$sed "s/^.* //"`
- # if $test -f ${_rec1} ; then
- # $cat -s ${_rec1}
- # fi
- # if $test -f ${_rec2} ; then
- # $cat -s ${_rec2}
- # fi
- #fi
-
- # tell them what we think they are doing... !DIST!
- case $1 in
- net.*)
- $echo 'This program posts news to many hundreds of machines throughout the world.'
- ;;
- $cont.*)
- $echo 'This program posts news to many machines throughout the continent.'
- ;;
- $cntry.*)
- $echo 'This program posts news to many machines throughout the country.'
- ;;
- $state.*)
- $echo 'This program posts news to many machines throughout the state.'
- ;;
- $city.*)
- $echo 'This program posts news to many machines throughout the city.'
- ;;
- $org.*)
- $echo 'This program posts news to machines throughout the organization.'
- ;;
- $loc.*)
- $echo 'This program posts news to machines throughout the local organization.'
- ;;
- *.*)
- $echo 'This program may post news to many machines.'
- ;;
- *)
- $echo 'This program posts news to everyone on the machine.'
- ;;
- esac
- ans=""
- while $test "$ans" = "" ; do
- $echo $n "Are you absolutely sure that you want to do this? [ny] $c"
- read ans
- case $ans in
- y*) ;;
- f*) suppressmess=y ;;
- h*) $cat <<'EOH'
-
- Type n or CR to exit, y to post.
-
- EOH
- ans="" ;;
- *) exit ;;
- esac
- done
-
- file=h
- while $test "$file" = h ; do
- $echo ""
- $echo $n "Prepared file to include [none]: $c"
- read file
- case $file in
- h)
- $cat <<'EOH'
-
- If you have already produced the body of your article, type the filename
- for it here. If you just want to proceed directly to the editor, type a
- RETURN. In any event, you will be allowed to edit as many times as you
- want before you send off the article.
- EOH
- ;;
- '')
- $echo "" >> $tmpart
- state=edit
- ;;
- *)
- $cat $file >>$tmpart
- state=ask
- ;;
- esac
- done
-
- $echo ""
-
- while true ; do
- case $state in
- edit)
- case $expertise in
- beginner)
- $cat </dev/null >${DOTDIR-${HOME-$LOGDIR}}/.pnewsexpert
- $cat <<'EOMessage'
- A temporary file has been created for you to edit. Be sure to leave at
- least one blank line between the header and the body of your message.
- (And until a certain bug is fixed all over the net, don't start the body of
- your message with any indentation, or it may get eaten.)
-
- Within the header may be fields that you don't understand. If you don't
- understand a field (or even if you do), you can simply leave it blank, and
- it will go away when the article is posted.
-
- Type return to get the default editor, or type the name of your favorite
- editor.
-
- EOMessage
- ;;
- esac
- case "${VISUAL-${EDITOR-}}" in
- '')
- tmp=h
- ;;
- *)
- tmp=''
- ;;
- esac
- while $test "$tmp" = h ; do
- $echo $n "Editor [${VISUAL-${EDITOR-$defeditor}}]: $c"
- read tmp
- case $tmp in
- h)
- $cat <<'EOH'
-
- Type a return to get the default editor, or type the name of the editor you
- prefer. The default editor depends on the VISUAL and EDITOR environment
- variables.
-
- EOH
- ;;
- '')
- ;;
- *)
- VISUAL=$tmp
- export VISUAL
- ;;
- esac
- done
- trap : 2
- ${VISUAL-${EDITOR-$defeditor}} $tmpart $oldart
- trap "$rescue" 2
- state=ask
- ;;
-
- ask)
- $echo ""
- $echo $n "Send, abort, edit, or list? $c"
- read ans
-
- case $ans in
- a*)
- state=rescue
- ;;
- e*)
- state=edit
- ;;
- l*)
- $pager $tmpart
- state=ask
- ;;
- s*)
- state=send
- ;;
- h*)
- $cat <<'EOH'
-
- Type s to send the article, a to abort and append the article to dead.article,
- e to edit the article again, or l to list the article.
- EOH
- esac
- ;;
-
- send)
- set X `$sed < $tmpart -n -e '/^Newsgroups: /{' -e p -e q -e '}'`
- shift
- case $# in
- 2)
- state=cleanup
- if $test -f $lib/moderators; then
- tryinews=no
- shift
- case "$1" in
- *,*) set `$echo $1 | tr ',' ' '`;;
- esac
- for newsgroup in $*; do
- # the following screwy sed should prevent Eunice from hanging on no match
- moderator=`$sed <$lib/moderators \\
- -e "/^$newsgroup[ ]/!s/.*//" \\
- -e "s/^$newsgroup[ ]//"`
- case ${moderator}X in
- X) tryinews=yes
- ;;
- *)
- $echo Mailing to moderator $moderator
- case "$mailer" in
- *recmail)
- $echo To: $moderator | $cat - $tmpart | $mailer
- ;;
- *)
- $mailer $moderator < $tmpart
- ;;
- esac
- case $? in
- 0) ;;
- *)
- $echo Unable to mail to moderator $moderator
- state=rescue
- ;;
- esac
- ;;
- esac
- done
- else
- tryinews=yes
- fi
- case "$tryinews" in
- yes)
- if $inews -h < $tmpart ; then
- : null
- else
- state=rescue
- fi
- ;;
- esac
- ;;
- *)
- $echo ""
- $echo "Malformed Newsgroups line."
- $echo ""
- sleep 1
- state=edit
- ;;
- esac
- ;;
- rescue)
- $cat $tmpart >> ${HOME-$LOGDIR}/dead.article
- $echo "Article saved to ${HOME-$LOGDIR}/dead.article"
- state=cleanup
- ;;
- cleanup)
- $rm -f $tmpart
- exit
- ;;
- esac
- done
- !NO!SUBS!
- $eunicefix Pnews
- chmod 755 Pnews
- $spitshell >Pnews.header <<'!NO!SUBS!'
- case $# in
- 0)
- ng=h
- while $test "$ng" = h ; do
- $echo ""
- $echo $n "Newsgroup(s): $c"
- read ng
- case $ng in
- h)
- $cat <<'EOH'
-
- Type the name of one or more newsgroups to which you wish to post an article.
- If you want to post to multiple newsgroups, it is better to do them all at
- once than to post to each newsgroup individually, which defeats the news
- reading programs' strategies of eliminating duplicates.
-
- Separate multiple newsgroup names with commas.
- EOH
- ;;
- esac
- done
- ;;
- *)
- ng=$1
- shift
- ;;
- esac
- case $ng in
- *\ *)
- ng=`$echo "$ng" | $sed 's/[, ] */,/g'`
- ;;
- esac
- case $ng in
- net.*|fa.*|mod.*)
- defdist=net
- dist=h
- ;;
- *.*)
- defdist=`expr "X$ng" : 'X\([a-z0-9]*\)'`
- dist=h
- ;;
- *)
- defdist=''
- dist=''
- ;;
- esac
-
- while $test "$dist" = h ; do
- if $test -f $lib/distributions; then
- $echo " "
- $echo "Your local distribution prefixes are:"
- $cat $lib/distributions
- else
- $egrep -v '[ ]none$' <<EOM
-
- Your local distribution prefixes are:
- Local organization: $loc
- Organization: $org
- City: $city
- $stpr: $state
- Country: $cntry
- Continent: $cont
- Everywhere: net,mod,fa
-
- EOM
- fi
- $echo $n "Distribution ($defdist): $c"
- read dist
- case $dist in
- '') dist=$defdist ;;
- esac
- case $dist in
- h)
- $cat <<'EOH'
-
- The Distribution line may be used to limit the distribution of an article
- to some subset of the systems that would receive the article based only on
- the Newsgroups line. For example, if you want to sell your car in net.auto,
- and you live in New Jersey, you might want to put "nj" on the Distribution
- line to avoid advertising in California, which has enough problems of its own.
- The actual area designators to use depend on where you are, of course.
- EOH
- ;;
- ''|$loc*|$org*|$city*|$state*|$cntry*|$cont*|fa*|mod*)
- ;;
- net*|world*)
- dist=''
- ;;
- *)
- if $test -f $lib/distributions && \
- $egrep "^$dist[ ]" $lib/distributions >$tmpart && \
- $test -s $tmpart; then
- : null
- else
- $echo "Unrecognized distribution prefix--type h for help."
- dist=h
- fi
- ;;
- esac
- done
-
- case $ng in
- *net.general*)
- follow=`echo "$ng" | sed 's/net\.general/net.followup/g'`
- ;;
- *)
- follow=""
- ;;
- esac
-
- case $# in
- 0)
- title=h
- while $test "$title" = h ; do
- $echo ""
- $echo $n "Title/Subject: $c"
- read title
- case $title in
- h)
- $cat <<'EOH'
-
- Type the title for your article. Please make it as informative as possible
- (within reason) so that people who aren't interested won't have to read the
- article to find out they aren't interested. This includes marking movie
- spoilers as (spoiler), and rotated jokes as (rot 13).
- EOH
- ;;
- esac
- done
- ;;
- *)
- title="$*"
- ;;
- esac
-
- # now build a file with a header for them to edit
-
- set X ${USER-${LOGNAME-`who am i`}}
- shift
- logname=$1
- case $logname in
- *!*) logname=`expr "$logname" : '!\(.*\)$'` ;;
- esac
- case ${NAME-$nametype} in
- bsd)
- fullname=`$sed </etc/passwd -e "/^$logname:/{s/^[^:]*:[^:]*:[^:]*:[^:]*:\([^,:;]*\).*"'$'"/\1/" -e "q" -e "}" -e "d"`
- case $fullname in
- *'&'*) : GACK
- lname=`$echo $logname | $tr 'a-z' 'A-Z'`
- lname=`$echo $lname $logname | $sed 's/^\(.\)[^ ]* ./\1/'`
- fullname=`$echo "$fullname" | $sed "s/&/${lname}/"`
- ;;
- esac
- ;;
- usg)
- fullname=`$sed </etc/passwd -e "/^$logname:/{s/^[^:]*:[^:]*:[^:]*:[^:]*:\([^(:]*\).*"'$'"/\1/" -e "s/^.*-//" -e "q" -e "}" -e "d"`
- ;;
- *)
- fullname=${NAME-`$cat ${HOME-$LOGDIR}/.fullname`}
- ;;
- esac
-
- orgname=${ORGANIZATION-$orgname}
- case $orgname in
- /*) orgname=`$cat $orgname` ;;
- esac
-
- $cat > $tmpart <<EOHeader
- Newsgroups: $ng
- Subject: $title
- Expires:
- References:
- Sender:
- Reply-To: $logname@$sitename.UUCP ($fullname)
- Followup-To: $follow
- Distribution: $dist
- Organization: $orgname
- Keywords:
-
- EOHeader
-
- !NO!SUBS!
- $eunicefix Pnews.header
- !STUFFY!FUNK!
- echo Extracting rn.c
- cat >rn.c <<'!STUFFY!FUNK!'
- /* rn -- new readnews program
- *
- * From: lwall@sdcrdcf.UUCP (Larry Wall)
- * Organization: System Development Corporation, Santa Monica
- *
- * begun: 01/14/83
- * 1.0: 04/08/83
- * 2.0: 09/01/83
- */
-
- static char rnid[] = "@(#)$Header: rn.c,v 4.3 85/05/01 11:47:56 lwall Exp $";
-
- /* $Log: rn.c,v $
- * Revision 4.3 85/05/01 11:47:56 lwall
- * Baseline for release with 4.3bsd.
- *
- */
-
- #include "INTERN.h"
- #include "common.h"
- #include "rn.h"
- #include "EXTERN.h"
- #include "rcstuff.h"
- #include "term.h"
- #include "final.h"
- #include "ngdata.h"
- #include "util.h"
- #include "only.h"
- #include "ngsrch.h"
- #include "help.h"
- #include "last.h"
- #include "init.h"
- #include "intrp.h"
- #include "rcln.h"
- #include "sw.h"
- #include "addng.h"
- #include "ng.h"
- #include "INTERN.h"
-
- void
- rn_init()
- {
- ;
- }
-
- void
- main(argc,argv)
- int argc;
- char *argv[];
- {
- bool foundany = initialize(argc,argv);
- register char *s;
- bool oh_for_the_good_old_days = FALSE;
-
- if (maxngtodo)
- starthere = 0;
- else if (!foundany) { /* nothing to do? */
- #ifdef VERBOSE
- if (verbose)
- fputs("\
- No unread news in subscribed-to newsgroups. To subscribe to a new\n\
- newsgroup use the g<newsgroup> command.\n\
- ",stdout) FLUSH;
- #endif
- starthere = nextrcline;
- }
-
- /* loop through all unread news */
-
- {
- char promptbuf[80];
- bool special = FALSE; /* temporarily allow newsgroup */
- /* with no unread news? */
- bool retry; /* cycle back to top of list? */
- NG_NUM recent_ng = 0;
-
- current_ng = 0;
- do {
- retry = FALSE;
- if (findlast) {
- findlast = FALSE;
- starthere = 0;
- if (*lastngname) {
- if ((ng = find_ng(lastngname)) == nextrcline)
- ng = 0;
- else {
- set_ngname(lastngname);
- set_toread(ng);
- if (toread[ng] <= TR_NONE)
- ng = 0;
- }
- }
- }
- else {
- ng = starthere;
- starthere = 0;
- }
- while (ng <= nextrcline) { /* for each newsgroup */
- mode = 'n';
- if (ng >= nextrcline) { /* after the last newsgroup? */
- ng = nextrcline; /* force it to 1 after */
- #ifdef ONLY
- if (maxngtodo) {
- if (retry)
- #ifdef VERBOSE
- IF(verbose)
- printf("\nRestriction %s%s still in effect.\n",
- ngtodo[0],
- maxngtodo > 1 ? ", etc." : nullstr) FLUSH;
- ELSE
- #endif
- #ifdef TERSE
- fputs("\n(\"Only\" mode.)\n",stdout) FLUSH;
- #endif
- else {
- #ifdef VERBOSE
- IF(verbose)
- fputs("\nNo articles under restriction.",
- stdout) FLUSH;
- ELSE
- #endif
- #ifdef TERSE
- fputs("\nNo \"only\" articles.",stdout) FLUSH;
- #endif
- end_only(); /* release the restriction */
- retry = TRUE;
- }
- }
- #endif
- dfltcmd = (retry ? "npq" : "qnp");
- #ifdef VERBOSE
- IF(verbose)
- sprintf(promptbuf,
- "\n******** End of newsgroups--what next? [%s] ",
- dfltcmd);
- ELSE
- #endif
- #ifdef TERSE
- sprintf(promptbuf,
- "\n**** End--next? [%s] ", dfltcmd);
- #endif
- }
- else {
- bool shoe_fits; /* newsgroup matches restriction? */
-
- if (toread[ng] >= TR_NONE) { /* recalc toread? */
- set_ngname(rcline[ng]);
- if (shoe_fits = (special || inlist(ngname)))
- set_toread(ng);
- if (paranoid) {
- recent_ng = current_ng;
- current_ng = ng;
- cleanup_rc();
- /* this may move newsgroups around */
- ng = current_ng;
- set_ngname(rcline[ng]);
- }
- }
- if (toread[ng] < (maxngtodo||special ? TR_NONE : TR_ONE) || !shoe_fits) {
- /* unwanted newsgroup? */
- ng++; /* then skip it */
- continue;
- }
- dfltcmd = "ynq";
- #ifdef VERBOSE
- IF(verbose)
- sprintf(promptbuf,
- "\n******** %3ld unread article%c in %s--read now? [%s] ",
- (long)toread[ng], (toread[ng]==TR_ONE ? ' ' : 's'),
- ngname, dfltcmd); /* format prompt string */
- ELSE
- #endif
- #ifdef TERSE
- sprintf(promptbuf,
- "\n**** %3ld in %s--read? [%s] ",
- (long)toread[ng],
- ngname,dfltcmd); /* format prompt string */
- #endif
- }
- special = FALSE; /* go back to normal mode */
- if (ng != current_ng) {
- recent_ng = current_ng;
- /* remember previous newsgroup */
- current_ng = ng; /* remember current newsgroup */
- }
- reask_newsgroup:
- unflush_output(); /* disable any ^O in effect */
- fputs(promptbuf,stdout) FLUSH;/* print prompt */
- fflush(stdout);
- reinp_newsgroup:
- eat_typeahead();
- getcmd(buf);
- if (errno || *buf == '\f') {
- putchar('\n') FLUSH; /* if return from stop signal */
- goto reask_newsgroup; /* give them a prompt again */
- }
- setdef(buf,dfltcmd);
- #ifdef VERIFY
- printcmd();
- #endif
- switch (*buf) {
- case 'p': /* find previous unread newsgroup */
- do {
- if (ng <= 0)
- break;
- ng--;
- if (toread[ng] == TR_NONE)
- set_toread(ng);
- } while (toread[ng] <= TR_NONE);
- break;
- case 'P': /* goto previous newsgroup */
- do {
- if (ng <= 0)
- break;
- ng--;
- } while (toread[ng] < TR_NONE);
- special = TRUE; /* don't skip it if toread==0 */
- break;
- case '-':
- ng = recent_ng; /* recall previous newsgroup */
- special = TRUE; /* don't skip it if toread==0 */
- break;
- case 'q': case 'Q': case 'x': /* quit? */
- oh_for_the_good_old_days = (*buf == 'x');
- putchar('\n') FLUSH;
- ng = nextrcline+1; /* satisfy */
- retry = FALSE; /* loop conditions */
- break;
- case '^':
- putchar('\n') FLUSH;
- ng = 0;
- break;
- case 'n': case '+': /* find next unread newsgroup */
- if (ng == nextrcline) {
- putchar('\n') FLUSH;
- retry = TRUE;
- }
- else if (toread[ng] > TR_NONE)
- retry = TRUE;
- ng++;
- break;
- case 'N': /* goto next newsgroup */
- ng++;
- special = TRUE; /* and don't skip it if toread==0 */
- break;
- case '1': /* goto 1st newsgroup */
- ng = 0;
- special = TRUE; /* and don't skip it if toread==0 */
- break;
- case '$':
- ng = nextrcline; /* goto last newsgroup */
- retry = TRUE;
- break;
- case 'L':
- list_newsgroups();
- goto reask_newsgroup;
- case '/': case '?': /* scan for newsgroup pattern */
- #ifdef NGSEARCH
- switch (ng_search(buf,TRUE)) {
- case NGS_ABORT:
- goto reinp_newsgroup;
- case NGS_INTR:
- #ifdef VERBOSE
- IF(verbose)
- fputs("\n(Interrupted)\n",stdout) FLUSH;
- ELSE
- #endif
- #ifdef TERSE
- fputs("\n(Intr)\n",stdout) FLUSH;
- #endif
- ng = current_ng;
- goto reask_newsgroup;
- case NGS_FOUND:
- special = TRUE; /* don't skip it if toread==0 */
- break;
- case NGS_NOTFOUND:
- #ifdef VERBOSE
- IF(verbose)
- fputs("\n\nNot found--use g to add newsgroups\n",
- stdout) FLUSH;
- ELSE
- #endif
- #ifdef TERSE
- fputs("\n\nNot found\n",stdout) FLUSH;
- #endif
- goto reask_newsgroup;
- }
- #else
- notincl("/");
- #endif
- break;
- case 'm':
- #ifndef RELOCATE
- notincl("m");
- break;
- #endif
- case 'g': /* goto named newsgroup */
- if (!finish_command(FALSE))
- /* if they didn't finish command */
- goto reinp_newsgroup; /* go try something else */
- for (s = buf+1; *s == ' '; s++);
- /* skip leading spaces */
- if (!*s)
- strcpy(s,ngname);
- #ifdef RELOCATE
- if (!get_ng(s,*buf=='m')) /* try to find newsgroup */
- #else
- if (!get_ng(s,FALSE)) /* try to find newsgroup */
- #endif
- ng = current_ng;/* if not found, go nowhere */
- special = TRUE; /* don't skip it if toread==0 */
- break;
- #ifdef DEBUGGING
- case 'D':
- printf("\nTries: %d Hits: %d\n",
- softtries,softtries-softmisses) FLUSH;
- goto reask_newsgroup;
- #endif
- case '!': /* shell escape */
- if (escapade()) /* do command */
- goto reinp_newsgroup;
- /* if rubbed out, re input */
- goto reask_newsgroup;
- case Ctl('k'): /* edit global KILL file */
- edit_kfile();
- goto reask_newsgroup;
- case 'c': /* catch up */
- #ifdef CATCHUP
- reask_catchup:
- #ifdef VERBOSE
- in_char("\nDo you really want to mark everything as read? [yn] ");
- #else
- in_char("\nReally? [ynh] ");
- #endif
- putchar('\n') FLUSH;
- setdef(buf,"y");
- if (*buf == 'h') {
- #ifdef VERBOSE
- printf("Type y or SP to mark all articles as read.\n");
- printf("Type n to leave articles marked as they are.\n");
- #else
- printf("y or SP to mark all read.\n");
- printf("n to forget it.\n");
- #endif
- goto reask_catchup;
- }
- else if (*buf!=' ' && *buf!='y' && *buf!='n' && *buf!='q') {
- printf(hforhelp);
- settle_down();
- goto reask_catchup;
- } else if ( (*buf == ' ' || *buf == 'y') && ng<nextrcline )
- catch_up(ng);
- else
- retry = TRUE;
- ng++;
- #else
- notincl("c");
- #endif
- break;
- case 'u': /* unsubscribe */
- if (ng < nextrcline && toread[ng] >= TR_NONE) {
- /* unsubscribable? */
- printf(unsubto,rcline[ng]) FLUSH;
- rcchar[ng] = NEGCHAR;
- /* unsubscribe to (from?) it */
- toread[ng] = TR_UNSUB;
- /* and make line invisible */
- ng++; /* do an automatic 'n' */
- }
- break;
- case 'h': { /* help */
- int cmd;
-
- if ((cmd = help_ng()) > 0)
- pushchar(cmd);
- goto reask_newsgroup;
- }
- case 'a':
- #ifndef FINDNEWNG
- notincl("a");
- goto reask_newsgroup;
- #else
- /* FALL THROUGH */
- #endif
- case 'o':
- #ifdef ONLY
- {
- #ifdef FINDNEWNG
- bool doscan = (*buf == 'a');
- #endif
-
- if (!finish_command(TRUE)) /* get rest of command */
- goto reinp_newsgroup; /* if rubbed out, try something else */
- end_only();
- if (buf[1]) {
- bool minusd = instr(buf+1,"-d") != Nullch;
-
- sw_list(buf+1);
- if (minusd)
- cwd_check();
- putchar('\n') FLUSH;
- #ifdef FINDNEWNG
- if (doscan && maxngtodo)
- scanactive();
- #endif
- }
- ng = 0; /* simulate ^ */
- retry = FALSE;
- break;
- }
- #else
- notincl("o");
- goto reask_newsgroup;
- #endif
- case '&':
- if (switcheroo()) /* get rest of command */
- goto reinp_newsgroup; /* if rubbed out, try something else */
- goto reask_newsgroup;
- case 'l': { /* list other newsgroups */
- if (!finish_command(TRUE)) /* get rest of command */
- goto reinp_newsgroup; /* if rubbed out, try something else */
- for (s = buf+1; *s == ' '; s++);
- /* skip leading spaces */
- sprintf(cmd_buf,"%s '%s'",filexp(NEWSGROUPS),s);
- resetty();
- if (doshell(sh,cmd_buf))
- #ifdef VERBOSE
- IF(verbose)
- fputs(" (Error from newsgroups program)\n",
- stdout) FLUSH;
- ELSE
- #endif
- #ifdef TERSE
- fputs("(Error)\n",stdout) FLUSH;
- #endif
- noecho();
- crmode();
- goto reask_newsgroup;
- }
- case '.': case '=':
- case 'y': case 'Y': /* do normal thing */
- if (ng >= nextrcline) {
- fputs("\nNot on a newsgroup.",stdout) FLUSH;
- goto reask_newsgroup;
- }
- if (*buf == '=')
- s = savestr("=");
- else if (*buf == '.') { /* start command? */
- if (!finish_command(FALSE)) /* get rest of command */
- goto reinp_newsgroup;
- s = savestr(buf+1);
- /* do_newsgroup will free it */
- }
- else
- s = Nullch;
- if (toread[ng])
- retry = TRUE;
- switch (do_newsgroup(s)) {
- case NG_ERROR:
- case NG_NORM:
- ng++;
- break;
- case NG_ASK:
- goto reask_newsgroup;
- case NG_MINUS:
- ng = recent_ng; /* recall previous newsgroup */
- special = TRUE; /* don't skip it if toread==0 */
- break;
- }
- break;
- #ifdef STRICTCR
- case '\n':
- fputs(badcr,stdout) FLUSH;
- goto reask_newsgroup;
- #endif
- case 'v':
- printf("\n%s\n",rnid) FLUSH;
- goto reask_newsgroup;
- default:
- printf("\n%s",hforhelp) FLUSH;
- settle_down();
- goto reask_newsgroup;
- }
- }
- } while (retry);
- }
-
- /* now write .newsrc back out */
-
- write_rc();
-
- if (oh_for_the_good_old_days)
- get_old_rc();
-
- finalize(0); /* and exit */
- }
-
- /* set current newsgroup */
-
- void
- set_ngname(what)
- char *what;
- {
- int len = strlen(what)+1;
-
- growstr(&ngname,&ngnlen,len);
- strcpy(ngname,what);
- growstr(&ngdir,&ngdlen,len);
- strcpy(ngdir,getngdir(ngname));
- }
-
- static char *myngdir;
- static int ngdirlen = 0;
-
- char *
- getngdir(ngnam)
- char *ngnam;
- {
- register char *s;
-
- growstr(&myngdir,&ngdirlen,strlen(ngnam)+1);
- strcpy(myngdir,ngnam);
- for (s = myngdir; *s; s++)
- if (*s == '.')
- *s = '/';
- return myngdir;
- }
-
- !STUFFY!FUNK!
- echo Extracting rcln.c
- cat >rcln.c <<'!STUFFY!FUNK!'
- /* $Header: rcln.c,v 4.3 85/05/01 11:45:36 lwall Exp $
- *
- * $Log: rcln.c,v $
- * Revision 4.3 85/05/01 11:45:36 lwall
- * Baseline for release with 4.3bsd.
- *
- */
-
- #include "EXTERN.h"
- #include "common.h"
- #include "util.h"
- #include "rcstuff.h"
- #include "ngdata.h"
- #include "INTERN.h"
- #include "rcln.h"
-
- void
- rcln_init()
- {
- ;
- }
-
- #ifdef CATCHUP
- void
- catch_up(ngx)
- NG_NUM ngx;
- {
- char tmpbuf[128];
-
- #ifdef VERBOSE
- IF(verbose)
- printf("\nMarking %s as all read.\n",rcline[ngx]) FLUSH;
- ELSE
- #endif
- #ifdef TERSE
- fputs("\nMarked read\n",stdout) FLUSH;
- #endif
- sprintf(tmpbuf,"%s: 1-%ld", rcline[ngx],(long)getngsize(ngx));
- free(rcline[ngx]);
- rcline[ngx] = savestr(tmpbuf);
- *(rcline[ngx] + rcnums[ngx] - 1) = '\0';
- write_rc();
- }
- #endif
-
- /* add an article number to a newsgroup, if it isn't already read */
-
- int
- addartnum(artnum,ngnam)
- ART_NUM artnum;
- char *ngnam;
- {
- register NG_NUM ngnum = find_ng(ngnam);
- register char *s, *t, *maxt = Nullch;
- ART_NUM min = 0, max = -1, lastnum = 0;
- char *mbuf;
- bool morenum;
-
- if (!artnum)
- return 0;
- if (ngnum == nextrcline || !rcnums[ngnum])
- /* not found in newsrc? */
- return 0;
- #ifdef CACHEFIRST
- if (!abs1st[ngnum])
- #else
- if (!toread[ngnum])
- #endif
- /* now is a good time to trim down */
- set_toread(ngnum); /* the list due to expires if we */
- /* have not yet. */
- #ifdef DEBUGGING
- if (artnum > ngmax[ngnum] + 10 /* allow for incoming articles */
- ) {
- printf("\nCorrupt Xref line!!! %ld --> %s(1..%ld)\n",
- artnum,ngnam,
- ngmax[ngnum]) FLUSH;
- paranoid = TRUE; /* paranoia reigns supreme */
- return -1; /* hope this was the first newsgroup */
- }
- #endif
-
- if (toread[ngnum] == TR_BOGUS)
- return 0;
- #ifdef DEBUGGING
- if (debug & DEB_XREF_MARKER) {
- printf("%ld->\n%s%c%s\n",(long)artnum,rcline[ngnum],rcchar[ngnum],
- rcline[ngnum] + rcnums[ngnum]) FLUSH;
- }
- #endif
- s = rcline[ngnum] + rcnums[ngnum];
- while (*s == ' ') s++; /* skip spaces */
- t = s;
- while (isdigit(*s) && artnum >= (min = atol(s))) {
- /* while it might have been read */
- for (t = s; isdigit(*t); t++) ; /* skip number */
- if (*t == '-') { /* is it a range? */
- t++; /* skip to next number */
- if (artnum <= (max = atol(t)))
- return 0; /* it is in range => already read */
- lastnum = max; /* remember it */
- maxt = t; /* remember position in case we */
- /* want to overwrite the max */
- while (isdigit(*t)) t++; /* skip second number */
- }
- else {
- if (artnum == min) /* explicitly a read article? */
- return 0;
- lastnum = min; /* remember what the number was */
- maxt = Nullch; /* last one was not a range */
- }
- while (*t && !isdigit(*t)) t++; /* skip comma and any spaces */
- s = t;
- }
-
- /* we have not read it, so insert the article number before s */
-
- morenum = isdigit(*s); /* will it need a comma after? */
- *(rcline[ngnum] + rcnums[ngnum] - 1) = rcchar[ngnum];
- mbuf = safemalloc((MEM_SIZE)(strlen(s) + (s-rcline[ngnum]) + 8));
- strcpy(mbuf,rcline[ngnum]); /* make new rc line */
- if (maxt && lastnum && artnum == lastnum+1)
- /* can we just extend last range? */
- t = mbuf + (maxt-rcline[ngnum]);/* then overwrite previous max */
- else {
- t = mbuf + (t-rcline[ngnum]); /* point t into new line instead */
- if (lastnum) { /* have we parsed any line? */
- if (!morenum) /* are we adding to the tail? */
- *t++ = ','; /* supply comma before */
- if (!maxt && artnum == lastnum+1 && *(t-1) == ',')
- /* adjacent singletons? */
- *(t-1) = '-'; /* turn them into a range */
- }
- }
- if (morenum) { /* is there more to life? */
- if (min == artnum+1) { /* can we consolidate further? */
- bool range_before = (*(t-1) == '-');
- bool range_after;
- char *nextmax;
-
- for (nextmax = s; isdigit(*nextmax); nextmax++) ;
- range_after = *nextmax++ == '-';
-
- if (range_before)
- *t = '\0'; /* artnum is redundant */
- else
- sprintf(t,"%ld-",(long)artnum);/* artnum will be new min */
-
- if (range_after)
- s = nextmax; /* *s is redundant */
- /* else
- s = s */ /* *s is new max */
- }
- else
- sprintf(t,"%ld,",(long)artnum); /* put the number and comma */
- }
- else
- sprintf(t,"%ld",(long)artnum); /* put the number there (wherever) */
- strcat(t,s); /* copy remainder of line */
- #ifdef DEBUGGING
- if (debug & DEB_XREF_MARKER) {
- printf("%s\n",mbuf) FLUSH;
- }
- #endif
- free(rcline[ngnum]);
- rcline[ngnum] = mbuf; /* pull the switcheroo */
- *(rcline[ngnum] + rcnums[ngnum] - 1) = '\0';
- /* wipe out : or ! */
- if (toread[ngnum] > TR_NONE) /* lest we turn unsub into bogus */
- --toread[ngnum];
- return 0;
- }
-
- #ifdef MCHASE
- /* delete an article number from a newsgroup, if it is there */
-
- void
- subartnum(artnum,ngnam)
- register ART_NUM artnum;
- char *ngnam;
- {
- register NG_NUM ngnum = find_ng(ngnam);
- register char *s, *t;
- register ART_NUM min, max;
- char *mbuf;
- int curlen;
-
- if (!artnum)
- return;
- if (ngnum == nextrcline || !rcnums[ngnum])
- return; /* not found in newsrc? */
- #ifdef DEBUGGING
- if (debug & DEB_XREF_MARKER) {
- printf("%ld<-\n%s%c%s\n",(long)artnum,rcline[ngnum],rcchar[ngnum],
- rcline[ngnum] + rcnums[ngnum]) FLUSH;
- }
- #endif
- s = rcline[ngnum] + rcnums[ngnum];
- while (*s == ' ') s++; /* skip spaces */
-
- /* a little optimization, since it is almost always the last number */
-
- for (t=s; *t; t++) ; /* find end of string */
- curlen = t-rcline[ngnum];
- for (t--; isdigit(*t); t--) ; /* find previous delim */
- if (*t == ',' && atol(t+1) == artnum) {
- *t = '\0';
- if (toread[ngnum] >= TR_NONE)
- ++toread[ngnum];
- #ifdef DEBUGGING
- if (debug & DEB_XREF_MARKER)
- printf("%s%c %s\n",rcline[ngnum],rcchar[ngnum],s) FLUSH;
- #endif
- return;
- }
-
- /* not the last number, oh well, we may need the length anyway */
-
- while (isdigit(*s) && artnum >= (min = atol(s))) {
- /* while it might have been read */
- for (t = s; isdigit(*t); t++) ; /* skip number */
- if (*t == '-') { /* is it a range? */
- t++; /* skip to next number */
- max = atol(t);
- while (isdigit(*t)) t++; /* skip second number */
- if (artnum <= max) {
- /* it is in range => already read */
- if (artnum == min) {
- min++;
- artnum = 0;
- }
- else if (artnum == max) {
- max--;
- artnum = 0;
- }
- *(rcline[ngnum] + rcnums[ngnum] - 1) = rcchar[ngnum];
- mbuf = safemalloc((MEM_SIZE)(curlen + (artnum?15:2)));
- *s = '\0';
- strcpy(mbuf,rcline[ngnum]); /* make new rc line */
- s = mbuf + (s-rcline[ngnum]);
- /* point s into mbuf now */
- if (artnum) { /* split into two ranges? */
- prange(s,min,artnum-1);
- s += strlen(s);
- *s++ = ',';
- prange(s,artnum+1,max);
- }
- else /* only one range */
- prange(s,min,max);
- s += strlen(s);
- strcpy(s,t); /* copy remainder over */
- #ifdef DEBUGGING
- if (debug & DEB_XREF_MARKER) {
- printf("%s\n",mbuf) FLUSH;
- }
- #endif
- free(rcline[ngnum]);
- rcline[ngnum] = mbuf; /* pull the switcheroo */
- *(rcline[ngnum] + rcnums[ngnum] - 1) = '\0';
- /* wipe out : or ! */
- if (toread[ngnum] >= TR_NONE)
- ++toread[ngnum];
- return;
- }
- }
- else {
- if (artnum == min) { /* explicitly a read article? */
- if (*t == ',') /* pick a comma, any comma */
- t++;
- else if (s[-1] == ',')
- s--;
- else if (s[-2] == ',') /* (in case of space) */
- s -= 2;
- strcpy(s,t); /* no need to realloc */
- if (toread[ngnum] >= TR_NONE)
- ++toread[ngnum];
- #ifdef DEBUGGING
- if (debug & DEB_XREF_MARKER) {
- printf("%s%c%s\n",rcline[ngnum],rcchar[ngnum],
- rcline[ngnum] + rcnums[ngnum]) FLUSH;
- }
- #endif
- return;
- }
- }
- while (*t && !isdigit(*t)) t++; /* skip comma and any spaces */
- s = t;
- }
- }
-
- void
- prange(where,min,max)
- char *where;
- ART_NUM min,max;
- {
- if (min == max)
- sprintf(where,"%ld",(long)min);
- else
- sprintf(where,"%ld-%ld",(long)min,(long)max);
- }
- #endif
-
- /* calculate the number of unread articles for a newsgroup */
-
- void
- set_toread(ngnum)
- register NG_NUM ngnum;
- {
- register char *s, *c, *h;
- char tmpbuf[64], *mybuf = tmpbuf;
- char *nums;
- int length;
- #ifdef CACHEFIRST
- bool virgin_ng = (!abs1st[ngnum]);
- #endif
- ART_NUM ngsize = getngsize(ngnum);
- ART_NUM unread = ngsize;
- ART_NUM newmax;
-
- #ifdef DEBUGGING
- ngmax[ngnum] = ngsize; /* for checking out-of-range Xrefs */
- #endif
- if (ngsize == TR_BOGUS) {
- printf("Warning! Bogus newsgroup: %s\n",rcline[ngnum]) FLUSH;
- paranoid = TRUE;
- toread[ngnum] = TR_BOGUS;
- return;
- }
- #ifdef CACHEFIRST
- if (virgin_ng)
- #else
- if (!toread[ngnum])
- #endif
- {
- sprintf(tmpbuf," 1-%ld",(long)ngsize);
- if (strNE(tmpbuf,rcline[ngnum]+rcnums[ngnum]))
- checkexpired(ngnum,ngsize); /* this might realloc rcline */
- }
- nums = rcline[ngnum]+rcnums[ngnum];
- length = strlen(nums);
- if (length >= 60)
- mybuf = safemalloc((MEM_SIZE)(length+5));
- strcpy(mybuf,nums);
- mybuf[length++] = ',';
- mybuf[length] = '\0';
- for (s = mybuf; isspace(*s); s++)
- ;
- for ( ; (c = index(s,',')) != Nullch ; s = ++c) {
- /* for each range */
- *c = '\0'; /* keep index from running off */
- if ((h = index(s,'-')) != Nullch) /* find - in range, if any */
- unread -= (newmax = atol(h+1)) - atol(s) + 1;
- else if (newmax = atol(s))
- unread--; /* recalculate length */
- if (newmax > ngsize) { /* paranoia check */
- unread = -1;
- break;
- }
- }
- if (unread >= 0) /* reasonable number? */
- toread[ngnum] = (ART_UNREAD)unread;
- /* remember how many are left */
- else { /* SOMEONE RESET THE NEWSGROUP!!! */
- toread[ngnum] = (ART_UNREAD)ngsize;
- /* assume nothing carried over */
- printf("Warning! Somebody reset %s--assuming nothing read.\n",
- rcline[ngnum]) FLUSH;
- *(rcline[ngnum] + rcnums[ngnum]) = '\0';
- paranoid = TRUE; /* enough to make a guy paranoid */
- }
- if (mybuf != tmpbuf)
- free(mybuf);
- if (rcchar[ngnum] == NEGCHAR)
- toread[ngnum] = TR_UNSUB;
- }
-
- /* make sure expired articles are marked as read */
-
- void
- checkexpired(ngnum,ngsize)
- register NG_NUM ngnum;
- ART_NUM ngsize;
- {
- register ART_NUM a1st = getabsfirst(ngnum,ngsize);
- register char *s, *t;
- register ART_NUM num, lastnum = 0;
- char *mbuf, *newnum;
-
- if (a1st<=1)
- return;
- #ifdef DEBUGGING
- if (debug & DEB_XREF_MARKER) {
- printf("1-%ld->\n%s%c%s\n",(long)(a1st-1),rcline[ngnum],rcchar[ngnum],
- rcline[ngnum] + rcnums[ngnum]) FLUSH;
- }
- #endif
- for (s = rcline[ngnum] + rcnums[ngnum]; isspace(*s); s++);
- while (*s && (num = atol(s)) <= a1st) {
- while (isdigit(*s)) s++;
- while (*s && !isdigit(*s)) s++;
- lastnum = num;
- }
- if (*s) {
- if (s[-1] == '-') { /* landed in a range? */
- if (lastnum != 1)
- sprintf(rcline[ngnum]+rcnums[ngnum]," 1-%s",s);
- goto ret;
- }
- }
- /* s now points to what should follow first range */
- if (s - rcline[ngnum] > rcnums[ngnum] + 10)
- mbuf = rcline[ngnum];
- else {
- mbuf = safemalloc((MEM_SIZE)(rcnums[ngnum] + strlen(s) + 10));
- strcpy(mbuf,rcline[ngnum]);
- }
- newnum = t = mbuf+rcnums[ngnum];
- sprintf(t," 1-%ld",(long)(a1st - (lastnum != a1st)));
- if (*s) {
- t += strlen(t);
- *t++ = ',';
- strcpy(t,s);
- }
- if (mbuf == rcline[ngnum]) {
- rcline[ngnum] = saferealloc(rcline[ngnum],
- (MEM_SIZE)(rcnums[ngnum] + strlen(newnum) + 1));
- }
- else {
- free(rcline[ngnum]);
- rcline[ngnum] = mbuf;
- }
-
- ret:; /* semicolon in case DEBUGGING undefined */
- #ifdef DEBUGGING
- if (debug & DEB_XREF_MARKER) {
- printf("%s%c%s\n",rcline[ngnum],rcchar[ngnum],
- rcline[ngnum] + rcnums[ngnum]) FLUSH;
- }
- #endif
- }
-
- !STUFFY!FUNK!
- echo Extracting HACKERSGUIDE
- cat >HACKERSGUIDE <<'!STUFFY!FUNK!'
- Hacking Notes
-
- If you aren't interested in mucking with the innards of rn, don't read this.
-
- In the interests of both space and time optimization, things are done inside
- rn that don't always conform to the highest ideals of programming. To the
- extent I felt it was practical, I've tried to conform to good programming
- practice, but you must realize that my goal was to make a better mousetrap,
- so certain conscious tradeoffs were made in the design of rn right from the
- start. In particular, if you want to hack on rn (and I wouldn't blame you,
- it's fun), beware of the following:
-
- * buf and cmd_buf are reused all over the place. 11-squishing is a good
- term for it. No, I'm on a Vax now, but I've been there.
-
- * The article header is parsed on the fly, while it is being displayed.
- In fact, practically everything is done on the fly within the article
- display loop, and there are plenty of state variables. The header
- is never explicitly stored in memory; rather, pointers are kept into
- the file. The information required to backup pages is not stored in
- memory, except for 1 buffer's worth. The information required to do
- the delayed mark as unread (M) is not stored in memory either.
-
- * Lots of contortions are gone through to avoid using static memory, or
- allocating unnecessary memory, or losing track of allocated memory,
- while at the same time allowing .newsrc lines and header lines to be
- ANY length up to the amount of memory you have. Rn spends a great deal
- of effort being lazy. Do not use a static buffer when you can use
- growstr().
-
- * Lots of contortions are gone through to try to do things when people
- aren't waiting, or have only been waiting a very short time. Guessing
- the next article to be opened and opening it, searching ahead for the
- next article with the same subject, delaying the look up of the number
- of articles in a newsgroup, writing the rest of the page while the
- reader is examining the header, cacheing up subjects while the user
- is reading, checkpointing the .newsrc only while the reader is in the
- middle of an interesting article, are some of the strategies employed.
-
- * There are plenty of goto's. Most of them involve going back to reprompt,
- to reask for input, or to just plain do the unstructured things people
- want to do when they are glaring at a terminal. If they bother you
- too much, just think of rn as a big state machine. If they don't bother
- you at all, I don't want you hacking on rn.
-
- * Put all includes at the front of the file, before the first function,
- or makedepend will not work right. I could relax this, but makedepend
- would take about 5 times longer to run.
-
- In general then, feel free to hack on rn. Just don't broadcast untested
- patches to the net. Remember that there are people with limited address
- spaces and limited cpu cycles. If you add a wonderful new feature and
- want to publish a patch, put #ifdef's around it so that people who don't
- want it or can't afford it can work around it. THIS MEANS YOU. We don't
- need 57 varieties of mutually incompatible and incomprehensible rn floating
- about the net. Consider telling me about your patch so that I can consider
- including it in the standard version. A COMPLETE PATCH TAKES INTO ACCOUNT
- SYSTEM DEPENDENCIES AS DETERMINED BY THE CONFIGURE SCRIPT.
-
- * Don't use ints where rn uses typedefs, in particular, for article numbers.
- * Don't use %d anywhere that someone might need a %ld. (Just because YOU
- typedefed it as an int doesn't mean someone else won't need a long.)
- * Don't use %D, that's archaic.
- * Put FLUSHes after printf()s, fputs()es and putchar('\n')s for our poor
- brethern and sistern without line buffering.
- * Declare the type of every function. Use void, even if your C compiler
- doesn't.
- * Follow the style that rn already uses! This is my pet peeve. Well, one of
- them, anyway. I follow other people's strange styles when modifying
- their programs, so I'd be much obliged if you did likewise.
- * Use lint.
- * Use RCS. Start a new branch, like 4.3.[2-9]. (I will use 4.3.1 myself.)
- * Be structured wherever it doesn't interfere with practicality.
- * Long live paranoid programming. The rest of the program is out to get you.
- The world is out to destroy the program, not to mention the .newsrc.
- And then there's always bitrot...
- * Stop reading this lugubrious trash and start thinking for yourself.
- * Thank you and good night.
- !STUFFY!FUNK!
- echo ""
- echo "End of kit 5 (of 9)"
- cat /dev/null >kit5isdone
- config=true
- for iskit in 1 2 3 4 5 6 7 8 9; do
- if test -f kit${iskit}isdone; then
- echo "You have run kit ${iskit}."
- else
- echo "You still need to run kit ${iskit}."
- config=false
- fi
- done
- case $config in
- true)
- echo "You have run all your kits. Please read README and then type Configure."
- chmod 755 Configure
- ;;
- esac
- : I do not append .signature, but someone might mail this.
- exit
-
-