rsalz@bbn.com (Rich Salz) (01/04/91)
Submitted-by: Wayne Davison <0004475895@mcimail.com> Posting-number: Volume 23, Issue 66 Archive-name: trn/part07 #! /bin/sh # This is a shell archive. Remove anything before this line, then feed it # into a shell via "sh file" or similar. To overwrite existing files, # type "sh file -c". # The tool that generated this appeared in the comp.sources.unix newsgroup; # send mail to comp-sources-unix@uunet.uu.net if you want that tool. # Contents: art.c init.c term.c # Wrapped by rsalz@litchi.bbn.com on Thu Dec 27 11:34:06 1990 PATH=/bin:/usr/bin:/usr/ucb ; export PATH echo If this archive is complete, you will see the following message: echo ' "shar: End of archive 7 (of 14)."' if test -f 'art.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'art.c'\" else echo shar: Extracting \"'art.c'\" \(25145 characters\) sed "s/^X//" >'art.c' <<'END_OF_FILE' X/* $Header: art.c,v 4.3.3.2 90/08/20 16:05:33 davison Trn $ X * X * $Log: art.c,v $ X * Revision 4.3.3.2 90/08/20 16:05:33 davison X * Fixed bug in backpage code. X * X * Revision 4.3.3.1 90/06/20 22:35:51 davison X * Initial Trn Release X * X * Revision 4.3.2.3 90/04/21 14:43:27 sob X * Revised previous patch insure that it does not decrement below zero. X * X * Revision 4.3.2.2 90/03/22 23:03:25 sob X * Fixes provided by Wayne Davison <drivax!davison> X * X * Revision 4.3.2.1 89/11/07 23:20:57 sob X * Bug fixes for NNTP X * X * Revision 4.3.1.5 85/09/10 11:07:18 lwall X * %m not restored on some returns. X * X * Revision 4.3.1.4 85/05/23 12:13:31 lwall X * shouldn't display article that's really a subdirectory. X * X * Revision 4.3.1.3 85/05/13 09:29:55 lwall X * Added CUSTOMLINES option. X * X * Revision 4.3.1.2 85/05/10 13:46:07 lwall X * Fixed header reparse bug on backpage. X * X * Revision 4.3.1.1 85/05/10 11:30:56 lwall X * Branch for patches. X * X * Revision 4.3 85/05/01 11:34:51 lwall X * Baseline for release with 4.3bsd. X * X */ X X#include "EXTERN.h" X#include "common.h" X#include "rn.h" X#include "ngstuff.h" X#include "ngdata.h" X#include "head.h" X#include "cheat.h" X#include "help.h" X#include "search.h" X#include "artio.h" X#include "ng.h" X#include "bits.h" X#include "final.h" X#include "artstate.h" X#include "rcstuff.h" X#include "term.h" X#include "sw.h" X#include "util.h" X#include "backpage.h" X#include "intrp.h" X#ifdef USETHREADS X#include "rthreads.h" X#endif X#include "INTERN.h" X#include "art.h" X X/* page_switch() return values */ X X#define PS_NORM 0 X#define PS_ASK 1 X#define PS_RAISE 2 X#define PS_TOEND 3 X Xbool special = FALSE; /* is next page special length? */ Xint slines = 0; /* how long to make page when special */ XART_LINE highlight = -1; /* next line to be highlighted */ Xchar *restart = Nullch; /* if nonzero, the place where last */ X /* line left off on line split */ Xchar *blinebeg; /* where in buffer current line began */ XART_POS alinebeg; /* where in file current line began */ X X#ifdef INNERSEARCH XART_POS innersearch = 0; /* artpos of end of line we found */ X /* for 'g' command */ XART_LINE isrchline = 0; /* last line to display */ Xbool hide_everything = FALSE; X /* if set, do not write page now, */ X /* but refresh when done with page */ XCOMPEX gcompex; /* in article search pattern */ X#endif X Xbool firstpage; /* is this the 1st page of article? */ X Xchar art_buf[LBUFLEN]; /* place for article lines */ X Xvoid Xart_init() X{ X ; X} X Xint Xdo_article() X{ X register char *s; X ART_POS artsize; /* size in bytes of article */ X bool hide_this_line = FALSE; /* hidden header line? */ X ART_LINE linenum; /* line # on page, 1 origin */ X#ifdef ULSMARTS X bool under_lining = FALSE; X /* are we underlining a word? */ X#endif X register char *bufptr = art_buf; X /* pointer to input buffer */ X register int outpos; /* column position of output */ X static char prompt_buf[64]; /* place to hold prompt */ X bool notesfiles = FALSE; /* might there be notesfiles junk? */ X char oldmode = mode; X X#ifdef INNERSEARCH X register int outputok; X#endif X X if (fstat(artfp->_file,&filestat)) X /* get article file stats */ X return DA_CLEAN; X if ((filestat.st_mode & S_IFMT) != S_IFREG) X return DA_NORM; X artsize = filestat.st_size; X /* from that get article size */ X sprintf(prompt_buf, X "%%sEnd of article %ld (of %ld)--what next? [%%s]", X (long)art,(long)lastart); /* format prompt string */ X prompt = prompt_buf; X int_count = 0; /* interrupt count is 0 */ X firstpage = (topline < 0); X for (;;) { /* for each page */ X#ifdef USETHREADS X if (max_tree_lines) X init_tree(); /* init tree display */ X#endif X assert(art == openart); X if (do_fseek) { X#ifdef ASYNC_PARSE X parse_maybe(art); /* make sure header is ours */ X#endif X artpos = vrdary(artline); X if (artpos < 0) X artpos = -artpos; /* labs(), anyone? */ X if (firstpage) X artpos = (ART_POS)0; X fseek(artfp,artpos,0); X if (artpos < htype[PAST_HEADER].ht_minpos) X in_header = SOME_LINE; X do_fseek = FALSE; X restart = Nullch; X } X linenum = 1; X if (firstpage) { X if (firstline) { X interp(art_buf, (sizeof art_buf), firstline); X#ifdef USETHREADS X linenum += tree_puts(art_buf,linenum+topline,0); X#else X#ifdef CLEAREOL X maybe_eol(); X#endif /* CLEAREOL */ X fputs(art_buf,stdout) FLUSH; X linenum++; X#endif X artopen(art); /* rewind article in case interp */ X /* forced a header parse */ X } X else { X ART_NUM i; X X#ifdef USETHREADS X if (ThreadedGroup) { X int sel, unseen; X X sel = curr_p_art && (selected_roots[curr_p_art->root] & 1); X unseen = !was_read(art); X sprintf(art_buf,"%s%s #%ld",ngname,moderated,(long)art); X if (selected_root_cnt) { X i = selected_count - (unseen && sel); X sprintf(art_buf+strlen(art_buf)," (%ld + %ld more)", X (long)i,(long)toread[ng] - selected_count X - unthreaded - (!sel && unseen)); X } X else if ((i = (ART_NUM)(toread[ng]-unthreaded-unseen)) != 0) X sprintf(art_buf+strlen(art_buf)," (%ld more)",(long)i); X linenum += tree_puts(art_buf,linenum+topline,0); X } X else X#endif X { X#ifdef CLEAREOL X maybe_eol(); X#endif /* CLEAREOL */ X printf("Article %ld",(long)art); X i = (ART_NUM)(toread[ng] - 1 + was_read(art)); X#ifdef DELAYMARK X if (i || dmcount) { X printf(" (%ld more",(long)i); X if (dmcount) X printf(" + %ld Marked to return)",(long)dmcount); X putchar(')'); X } X#else X if (i) X printf(" (%ld more)",(long)i); X#endif X if (htype[NGS_LINE].ht_flags & HT_HIDE) X printf(" in %s", ngname); X fputs(moderated,stdout); X fputs(":\n",stdout) FLUSH; X linenum++; X } X } X start_header(art); X forcelast = FALSE; /* we will have our day in court */ X restart = Nullch; X artline = 0; /* start counting lines */ X artpos = 0; X vwtary(artline,artpos); /* remember pos in file */ X } X for (; /* linenum already set */ X in_header || ( X#ifdef INNERSEARCH X innersearch ? innermore() : X#endif X linenum<(firstpage?initlines:(special?slines:LINES)) ); X linenum++) { /* for each line on page */ X if (int_count) { /* exit via interrupt? */ X putchar('\n') FLUSH; /* get to left margin */ X int_count = 0; /* reset interrupt count */ X mode = oldmode; X special = FALSE; X return DA_NORM; /* skip out of loops */ X } X if (restart) { /* did not finish last line? */ X bufptr = restart; /* then start again here */ X restart = Nullch; /* and reset the flag */ X } X else { /* not a restart */ X if (fgets(art_buf,LBUFLEN,artfp)==Nullch) { X /* if all done */ X mode = oldmode; X special = FALSE; X return DA_NORM; /* skip out of loops */ X } X bufptr = art_buf; /* so start at beginning */ X art_buf[LBUFLEN-1] = '\0'; X /* make sure string ends */ X } X blinebeg = bufptr; /* remember where we began */ X alinebeg = artpos; /* both in buffer and file */ X if (in_header && bufptr == art_buf) { X hide_this_line = X parseline(art_buf,do_hiding,hide_this_line); X#ifdef USETHREADS X if (!in_header) { X linenum += finish_tree(linenum+topline); X } X#endif X } else if (notesfiles && do_hiding && X bufptr == art_buf && *art_buf == '#' && X isupper(art_buf[1]) && art_buf[2] == ':' ) { X fgets(art_buf,sizeof(art_buf),artfp); X if (index(art_buf,'!') != Nullch) X fgets(art_buf,sizeof(art_buf),artfp); X htype[PAST_HEADER].ht_minpos = ftell(artfp); X /* exclude notesfiles droppings */ X hide_this_line = TRUE; /* and do not print either */ X notesfiles = FALSE; X } X#ifdef CUSTOMLINES X if (hideline && bufptr == art_buf && X execute(&hide_compex,art_buf) ) X hide_this_line = TRUE; X#endif X if (in_header && htype[in_header].ht_flags & HT_MAGIC) { X if (in_header == NGS_LINE) { X hide_this_line = (index(art_buf,',') == Nullch); X } X else if (in_header == EXPIR_LINE) { X if (!(htype[EXPIR_LINE].ht_flags & HT_HIDE)) X hide_this_line = (strlen(art_buf) < 10); X } X else if (in_header == FROM_LINE) { X if (do_hiding && (s = index(art_buf+6,'(')) != Nullch) { X strcpy(art_buf+6,s+1); X if((s = rindex(art_buf+6,')')) != Nullch) X *s = '\0'; X } X } X#ifdef USETHREADS X else if (in_header == DATE_LINE && curr_p_art && do_hiding) { X strcpy(art_buf+6,ctime(&curr_p_art->date)); X } X#endif X } X if (in_header == SUBJ_LINE && X htype[SUBJ_LINE].ht_flags & HT_MAGIC) { X /* is this the subject? */ X int length; X X length = strlen(art_buf)-1; X artline++; X art_buf[length] = '\0'; /* wipe out newline */ X#ifdef NOFIREWORKS X no_ulfire(); X#endif X notesfiles = X (instr(&art_buf[length-10]," - (nf") != Nullch); X#ifdef USETHREADS X /* tree_puts(, ,1) underlines subject */ X linenum += tree_puts(art_buf,linenum+topline,1)-1; X#else X if (oldsubject) { X length += 7; X fputs("(SAME) ",stdout); X oldsubject = FALSE; X } X if (length+UG > COLS) { /* rarely true */ X linenum++; X vwtary(artline,vrdary(artline-1)+COLS); X artline++; X } X s = art_buf + 8; X *s++ = '\0'; /* make into 2 strings */ X#ifdef CLEAREOL X maybe_eol(); X#endif /* CLEAREOL */ X fputs(art_buf,stdout) FLUSH; X /* print up through : */ X if (!UG) X putchar(' '); X underprint(s); /* print subject underlined */ X putchar('\n') FLUSH; /* and finish the line */ X#endif X } X else if (hide_this_line && do_hiding) { X /* do not print line? */ X linenum--; /* compensate for linenum++ */ X if (!in_header) X hide_this_line = FALSE; X } X#ifdef USETHREADS X else if (in_header) { X artline++; X linenum += tree_puts(art_buf,linenum+topline,0)-1; X } X#endif X else { /* just a normal line */ X if (highlight==artline) { /* this line to be highlit? */ X if (marking == STANDOUT) { X#ifdef NOFIREWORKS X if (erase_screen) X no_sofire(); X#endif X standout(); X } X else { X#ifdef NOFIREWORKS X if (erase_screen) X no_ulfire(); X#endif X underline(); X } X if (*bufptr == '\n') X putchar(' '); X } X#ifdef INNERSEARCH X outputok = !hide_everything; X /* get it into register, hopefully */ X#endif X#ifdef CLEAREOL X#ifdef INNERSEARCH X if (outputok) X#endif X maybe_eol(); X#endif /* CLEAREOL */ X#ifdef CUSTOMLINES X if (pagestop && bufptr == art_buf && X execute(&page_compex,art_buf) ) X linenum = 32700; X#endif X for (outpos = 0; outpos < COLS; ) { X /* while line has room */ X if (*bufptr >= ' ') { /* normal char? */ X#ifdef ULSMARTS X if (*bufptr == '_') { X if (bufptr[1] == '\b') { X if (!under_lining && highlight!=artline X#ifdef INNERSEARCH X && outputok X#endif X ) { X under_lining++; X if (UG) { X if (bufptr != buf && X bufptr[-1] == ' ') { X outpos--; X backspace(); X } X } X underline(); X } X bufptr += 2; X } X } X else { X if (under_lining) { X under_lining = 0; X un_underline(); X if (UG) { X if (*bufptr == ' ') X goto skip_put; X outpos++; X } X } X } X#endif X#ifdef INNERSEARCH X if (outputok) X#endif X { X#ifdef ROTATION X if (rotate && !in_header X && isalpha(*bufptr)) { X if ((*bufptr & 31) <= 13) X putchar(*bufptr+13); X else X putchar(*bufptr-13); X } X else X#endif X putchar(*bufptr); X } X if (*UC && ((highlight==artline && marking == 1) X#ifdef ULSMARTS X || under_lining X#endif X )) { X backspace(); X underchar(); X } X skip_put: X bufptr++; X outpos++; X } X else if (*bufptr == '\n' || !*bufptr) { X /* newline? */ X#ifdef ULSMARTS X if (under_lining) { X under_lining = 0; X un_underline(); X } X#endif X#ifdef DEBUGGING X if (debug & DEB_INNERSRCH && outpos < COLS - 6) { X standout(); X printf("%4d",artline); X un_standout(); X } X#endif X#ifdef INNERSEARCH X if (outputok) X#endif X putchar('\n') FLUSH; X restart = 0; X outpos = 1000; /* signal normal \n */ X } X else if (*bufptr == '\t') { /* tab? */ X#ifdef INNERSEARCH X if (outputok) X#endif X putchar(*bufptr); X bufptr++; X outpos += 8 - outpos % 8; X } X else if (*bufptr == '\f') { /* form feed? */ X#ifdef INNERSEARCH X if (outputok) X#endif X fputs("^L",stdout); X if (bufptr == blinebeg && highlight != artline) X linenum = 32700; X /* how is that for a magic number? */ X bufptr++; X outpos += 2; X } X else { /* other control char */ X#ifdef INNERSEARCH X if (outputok) X#endif X { X putchar('^'); X if (highlight == artline && *UC && marking == 1) { X backspace(); X underchar(); X putchar(*bufptr+64); X backspace(); X underchar(); X } X else X putchar(*bufptr+64); X } X bufptr++; X outpos += 2; X } X X } /* end of column loop */ X X if (outpos < 1000) {/* did line overflow? */ X restart = bufptr; X /* restart here next time */ X if (AM) { /* automatic margins on tty? */ X if (!XN && *bufptr == '\n') X /* need we simulate XN? */ X restart = 0; X /* skip the newline */ X } X else { /* cursor just hangs there */ X#ifdef INNERSEARCH X if (outputok) X#endif X putchar('\n') FLUSH; X /* so move it down ourselves */ X if (*bufptr == '\n') X restart = 0; X /* simulate XN if need be */ X } X#ifdef CLEAREOL X/* #ifdef INNERSEARCH X if (outputok) X#endif X maybe_eol(); */ /* comment this out for now X until I am sure it is X needed*/ X X#endif /* CLEAREOL */ X } X X /* handle normal end of output line formalities */ X X if (highlight == artline) { X /* were we highlighting line? */ X if (marking == STANDOUT) X un_standout(); X else X un_underline(); X highlight = -1; /* no more we are */ X } X artline++; /* count the line just printed */ X if (artline - LINES + 1 > topline) X /* did we just scroll top line off? */ X topline = artline - LINES + 1; X /* then recompute top line # */ X } X X /* determine actual position in file */ X X if (restart) /* stranded somewhere in the buffer? */ X artpos += restart - blinebeg; X /* just calculate position */ X else /* no, ftell will do */ X artpos = ftell(artfp); X /* so do ftell */ X vwtary(artline,artpos); /* remember pos in file */ X } /* end of line loop */ X X#ifdef INNERSEARCH X innersearch = 0; X if (hide_everything) { X hide_everything = FALSE; X *buf = Ctl('l'); X goto fake_command; X } X#endif X if (linenum >= 32700)/* did last line have formfeed? */ X vwtary(artline-1,-vrdary(artline-1)); X /* remember by negating pos in file */ X X special = FALSE; /* end of page, so reset page length */ X firstpage = FALSE; /* and say it is not 1st time thru */ X X /* extra loop bombout */ X X if (artpos == artsize) {/* did we just now reach EOF? */ X mode = oldmode; X return DA_NORM; /* avoid --MORE--(100%) */ X } X X/* not done with this article, so pretend we are a pager */ X Xreask_pager: X unflush_output(); /* disable any ^O in effect */ X standout(); /* enter standout mode */ X printf("--MORE--(%ld%%)",(long)(artpos*100/artsize)); X un_standout(); /* leave standout mode */ X fflush(stdout); X/* reinp_pager: /* unused, commented for lint */ X eat_typeahead(); X#ifdef DEBUGGING X if (debug & DEB_CHECKPOINTING) { X printf("(%d %d %d)",checkcount,linenum,artline); X fflush(stdout); X } X#endif X if (checkcount >= docheckwhen && X linenum == LINES && X (artline > 40 || checkcount >= docheckwhen+10) ) { X /* while he is reading a whole page */ X /* in an article he is interested in */ X checkcount = 0; X checkpoint_rc(); /* update .newsrc */ X } X collect_subjects(); /* loads subject cache until */ X /* input is pending */ X mode = 'p'; X getcmd(buf); X if (errno) { X if (LINES < 100 && !int_count) X *buf = '\f';/* on CONT fake up refresh */ X else { X *buf = 'q'; /* on INTR or paper just quit */ X } X } X carriage_return(); X#ifndef CLEAREOL X erase_eol(); /* and erase the prompt */ X#else X if (erase_screen && can_home_clear) X clear_rest(); X else X erase_eol(); /* and erase the prompt */ X#endif /* CLEAREOL */ X carriage_return(); /* Resets kernel's tab column counter to 0 */ X fflush(stdout); X X fake_command: /* used by innersearch */ X X /* parse and process pager command */ X X switch (page_switch()) { X case PS_ASK: /* reprompt "--MORE--..." */ X goto reask_pager; X case PS_RAISE: /* reparse on article level */ X mode = oldmode; X return DA_RAISE; X case PS_TOEND: /* fast pager loop exit */ X mode = oldmode; X return DA_TOEND; X case PS_NORM: /* display more article */ X break; X } X } /* end of page loop */ X} X X/* process pager commands */ X Xint Xpage_switch() X{ X register char *s; X X switch (*buf) { X case 'd': X case Ctl('d'): /* half page */ X special = TRUE; X slines = LINES / 2 + 1; X if (marking && *blinebeg != '\f' X#ifdef CUSTOMLINES X && (!pagestop || blinebeg != art_buf || X !execute(&page_compex,blinebeg)) X#endif X ) { X up_line(); X highlight = --artline; X restart = blinebeg; X artpos = alinebeg; X } X return PS_NORM; X case '!': /* shell escape */ X escapade(); X return PS_ASK; X#ifdef INNERSEARCH X case Ctl('i'): X gline = 3; X sprintf(cmd_buf,"^[^%c]",*blinebeg); X compile(&gcompex,cmd_buf,TRUE,TRUE); X goto caseG; X case Ctl('g'): X gline = 3; X compile(&gcompex,"^Subject:",TRUE,TRUE); X goto caseG; X case 'g': /* in-article search */ X if (!finish_command(FALSE))/* get rest of command */ X return PS_ASK; X s = buf+1; X if (isspace(*s)) X s++; X if ((s = compile(&gcompex,s,TRUE,TRUE)) != Nullch) { X /* compile regular expression */ X printf("\n%s\n",s) FLUSH; X return PS_ASK; X } X carriage_return(); X erase_eol(); /* erase the prompt */ X carriage_return(); /* Resets kernel's tab column counter to 0 */ X /* FALL THROUGH */ X caseG: X case 'G': { X /* ART_LINE lines_to_skip = 0; */ X ART_POS start_where; X X if (gline < 0 || gline > LINES-2) X gline = LINES-2; X#ifdef DEBUGGING X if (debug & DEB_INNERSRCH) X printf("Start here? %d >=? %d\n",topline + gline + 1,artline) X FLUSH; X#endif X if (*buf == Ctl('i') || topline+gline+1 >= artline) X start_where = artpos; X /* in case we had a line wrap */ X else { X start_where = vrdary(topline+gline+1); X if (start_where < 0) X start_where = -start_where; X } X if (start_where < htype[PAST_HEADER].ht_minpos) X start_where = htype[PAST_HEADER].ht_minpos; X fseek(artfp,(long)start_where,0); X innersearch = 0; /* assume not found */ X while (fgets(buf, sizeof buf, artfp) != Nullch) { X /* lines_to_skip++; NOT USED NOW */ X#ifdef DEBUGGING X if (debug & DEB_INNERSRCH) X printf("Test %s",buf) FLUSH; X#endif X if (execute(&gcompex,buf) != Nullch) { X innersearch = ftell(artfp); X break; X } X } X if (!innersearch) { X fseek(artfp,artpos,0); X fputs("(Not found)",stdout) FLUSH; X return PS_ASK; X } X#ifdef DEBUGGING X if (debug & DEB_INNERSRCH) X printf("On page? %ld <=? %ld\n",(long)innersearch,(long)artpos) X FLUSH; X#endif X if (innersearch <= artpos) { /* already on page? */ X if (innersearch < artpos) { X artline = topline+1; X while (vrdary(artline) < innersearch) X artline++; X } X highlight = artline - 1; X#ifdef DEBUGGING X if (debug & DEB_INNERSRCH) X printf("@ %d\n",highlight) FLUSH; X#endif X topline = highlight - gline; X if (topline < -1) X topline = -1; X *buf = '\f'; /* fake up a refresh */ X innersearch = 0; X return page_switch(); X } X else { /* who knows how many lines it is? */ X do_fseek = TRUE; X hide_everything = TRUE; X } X return PS_NORM; X } X#else X case 'g': case 'G': case Ctl('g'): X notincl("g"); X return PS_ASK; X#endif X case '\n': /* one line */ X special = TRUE; X slines = 2; X return PS_NORM; X#ifdef ROTATION X case 'X': X rotate = !rotate; X /* FALL THROUGH */ X#endif X case 'l': X case '\f': /* refresh screen */ X#ifdef DEBUGGING X if (debug & DEB_INNERSRCH) { X printf("Topline = %d",topline) FLUSH; X gets(buf); X } X#endif X clear(); X carriage_return(); /* Resets kernel's tab column counter to 0 */ X do_fseek = TRUE; X artline = topline; X if (artline < 0) X artline = 0; X firstpage = (topline < 0); X return PS_NORM; X case 'b': X case '\b': X case Ctl('b'): { /* back up a page */ X ART_LINE target; X X#ifndef CLEAREOL X clear(); X#else X if (can_home_clear) /* if we can home do it */ X home_cursor(); X else X clear(); X X#endif /* CLEAREOL */ X carriage_return(); /* Resets kernel's tab column counter to 0 */ X do_fseek = TRUE; /* reposition article file */ X target = topline - (LINES - 2); X artline = topline; X if (artline >= 0) do { X artline--; X } while(artline >= 0 && artline > target && vrdary(artline-1) >= 0); X topline = artline; X /* remember top line of screen */ X /* (line # within article file) */ X if (artline < 0) X artline = 0; X firstpage = (topline < 0); X return PS_NORM; X } X case 'h': { /* help */ X int cmd; X X if ((cmd = help_page()) > 0) X pushchar(cmd); X return PS_ASK; X } X#ifdef USETHREADS X case 't': /* output thread data */ X page_line = 1; X p_art = curr_p_art; X entire_tree(); X return PS_ASK; X#endif X case '\177': X case '\0': /* treat del,break as 'n' */ X *buf = 'n'; X /* FALL THROUGH */ X case 'k': case 'K': X#ifdef USETHREADS X case 'T': case 'J': X#endif X case 'n': case 'N': case Ctl('n'): X case 's': case 'S': X case 'e': X case 'u': X case 'w': case 'W': X case '|': X mark_as_read(); /* mark article as read */ X /* FALL THROUGH */ X#ifdef USETHREADS X case 'U': case ',': X case '<': case '>': X case '[': case ']': X case '{': case '}': X case '+': case ':': X#endif X case '#': X case '$': X case '&': X case '-': X case '.': X case '/': X case '1': case '2': case '3': case '4': case '5': X case '6': case '7': case '8': case '9': X case '=': X case '?': X case 'c': case 'C': X#ifdef DEBUGGING X case 'D': X#endif X case 'E': X case 'f': case 'F': X case 'j': X case Ctl('k'): X case 'm': case 'M': X case 'p': case 'P': case Ctl('p'): X case 'Q': X case 'r': case 'R': case Ctl('r'): X case 'v': X case 'Y': X#ifndef ROTATION X case 'x': case 'X': X#endif X case Ctl('x'): X case '^': X X#ifdef ROTATION X rotate = FALSE; X#endif X reread = FALSE; X do_hiding = TRUE; X if (index("nNpP",*buf) == Nullch && X index("wWsSe:!&|/?123456789.",*buf) != Nullch) { X setdfltcmd(); X standout(); /* enter standout mode */ X printf(prompt,mailcall,dfltcmd); X /* print prompt, whatever it is */ X un_standout(); /* leave standout mode */ X putchar(' '); X fflush(stdout); X } X return PS_RAISE; /* and pretend we were at end */ X#ifdef ROTATION X case 'x': X rotate = TRUE; X /* FALL THROUGH */ X#endif X case 'y': X case Ctl('v'): X /* Leaving it undocumented in case */ X /* I want to steal the key--LAW */ X case ' ': /* continue current article */ X if (erase_screen) { /* -e? */ X#ifndef CLEAREOL X clear(); /* clear screen */ X#else X if (can_home_clear) /* if we can home do it */ X home_cursor(); X else X clear(); /* else clear screen */ X X#endif /* CLEAREOL */ X if (*blinebeg != '\f' X#ifdef CUSTOMLINES X && (!pagestop || blinebeg != art_buf || X !execute(&page_compex,blinebeg)) X#endif X ) { X restart = blinebeg; X artline--; /* restart this line */ X artpos = alinebeg; X if (marking) /* and mark repeated line */ X highlight = artline; X } X topline = artline; X /* and remember top line of screen */ X /* (line # within article file) */ X } X else if (marking && *blinebeg != '\f' X#ifdef CUSTOMLINES X && (!pagestop || blinebeg != art_buf || X !execute(&page_compex,blinebeg)) X#endif X ) { X /* are we marking repeats? */ X up_line(); /* go up one line */ X highlight = --artline;/* and get ready to highlight */ X restart = blinebeg; /* the old line */ X artpos = alinebeg; X } X return PS_NORM; X case 'q': /* quit this article? */ X do_hiding = TRUE; X return PS_TOEND; X default: X fputs(hforhelp,stdout) FLUSH; X settle_down(); X return PS_ASK; X } X} X X#ifdef INNERSEARCH Xbool Xinnermore() X{ X if (artpos < innersearch) { /* not even on page yet? */ X#ifdef DEBUGGING X if (debug & DEB_INNERSRCH) X printf("Not on page %ld < %ld\n",(long)artpos,(long)innersearch) X FLUSH; X#endif X return TRUE; X } X if (artpos == innersearch) { /* just got onto page? */ X isrchline = artline; /* remember first line after */ X highlight = artline - 1; X#ifdef DEBUGGING X if (debug & DEB_INNERSRCH) X printf("There it is %ld = %ld, %d @ %d\n",(long)artpos, X (long)innersearch,hide_everything,highlight) FLUSH; X#endif X if (hide_everything) { /* forced refresh? */ X topline = highlight - gline; X if (topline < -1) X topline = -1; X return FALSE; /* let refresh do it all */ X } X } X#ifdef DEBUGGING X if (debug & DEB_INNERSRCH) X printf("Not far enough? %d <? %d + %d\n",artline,isrchline,gline) X FLUSH; X#endif X if (artline < isrchline + gline) { X return TRUE; X } X return FALSE; X} X#endif END_OF_FILE if test 25145 -ne `wc -c <'art.c'`; then echo shar: \"'art.c'\" unpacked with wrong size! fi # end of 'art.c' fi if test -f 'init.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'init.c'\" else echo shar: Extracting \"'init.c'\" \(8405 characters\) sed "s/^X//" >'init.c' <<'END_OF_FILE' X/* $Header: init.c,v 4.3.3.1 90/06/20 22:37:39 davison Trn $ X * X * $Log: init.c,v $ X * Revision 4.3.3.1 90/06/20 22:37:39 davison X * Initial Trn Release X * X * Revision 4.3.2.6 90/05/08 22:05:55 sob X * Added quick startup (-q) flag. X * X * Revision 4.3.2.5 90/05/04 23:10:01 sob X * Fix for exiting "second" rn such that tty will be left in correct state. X * Provided by glenn@mathcs.emory.edu X * X * Revision 4.3.2.4 90/03/22 23:04:32 sob X * Fixes provided by Wayne Davison <drivax!davison> X * X * Revision 4.3.2.3 90/03/17 21:34:04 sob X * Cleaned up a bit. X * X * Revision 4.3.2.2 89/11/08 01:17:48 sob X * Added changes to insure that this will compile for RN or RRN with no X * changes to the source code. X * X * Revision 4.3.2.1 89/11/06 00:39:14 sob X * Added RRN support from NNTP 1.5 X * X * Revision 4.3.1.4 86/09/05 14:24:02 lwall X * Removed net.announce dependency. X * X * Revision 4.3.1.3 85/07/23 18:08:36 lwall X * Fixed up NOLINEBUF option to work. X * X * Revision 4.3.1.2 85/05/21 14:22:46 lwall X * Sped up "rn -c" by avoiding unnecessary initialization. X * X * Revision 4.3.1.1 85/05/10 11:33:39 lwall X * Branch for patches. X * X * Revision 4.3 85/05/01 16:16:13 lwall X * Baseline for release with 4.3bsd. X * X */ X X#include "EXTERN.h" X#include "common.h" X#include "util.h" X#include "final.h" X#include "term.h" X#include "last.h" X#include "rn.h" X#include "rcstuff.h" X#include "ngdata.h" X#include "only.h" X#include "intrp.h" X#include "addng.h" X#include "sw.h" X#include "art.h" X#include "artsrch.h" X#include "artio.h" X#include "backpage.h" X#include "bits.h" X#include "cheat.h" X#include "head.h" X#include "help.h" X#include "kfile.h" X#include "ngsrch.h" X#include "ngstuff.h" X#include "rcln.h" X#include "respond.h" X#ifdef SERVER X#include "server.h" X#endif X#ifdef USETHREADS X#include "rthreads.h" X#endif X#include "ng.h" X#include "INTERN.h" X#include "init.h" X Xbool Xinitialize(argc,argv) Xint argc; Xchar *argv[]; X{ X char *tcbuf; X register bool foundany = FALSE; X long time(); X#ifdef SERVER X char *server; X int response; X#endif X#ifdef NOLINEBUF X static char std_out_buf[BUFSIZ]; /* must be static or malloced */ X X setbuf(stdout, std_out_buf); X#endif X X tcbuf = safemalloc(1024); /* make temp buffer for termcap and */ X /* other initialization stuff */ X X /* init terminal */ X X term_init(); /* must precede sw_init() so that */ X /* ospeed is set for baud-rate */ X /* switches. Actually terminal */ X /* mode setting is in term_set() */ X X /* we have to know rnlib to look up global switches in %X/INIT */ X X lib = savestr(filexp(LIB)); X rnlib = savestr(filexp(RNLIB)); X X /* decode switches */ X X sw_init(argc,argv,&tcbuf); /* must not do % interps! */ X /* (but may mung environment) */ X X /* init signals, status flags */ X X final_init(); X X /* start up file expansion and the % interpreter */ X X intrp_init(tcbuf); X X /* now make sure we have a current working directory */ X X if (!checkflag) X cwd_check(); X X /* now that we know where to save things, cd to news directory */ X X if (chdir(spool)) { X printf(nocd,spool) FLUSH; X finalize(1); X } X X /* if we aren't just checking, turn off echo */ X X if (!checkflag) X term_set(tcbuf); X X /* get info on last rn run, if any */ X X if (!checkflag) X last_init(tcbuf); X X free(tcbuf); /* recover 1024 bytes */ X X /* make sure we are the sole possessors of .newsrc */ X X if (!checkflag) X lock_check(); X X /* check for news news */ X X if (!checkflag) X newsnews_check(); X X#ifdef SERVER X X /* open connection to server if appropriate */ X X server = getserverbyfile(SERVER_FILE); X if (server == NULL) { X fprintf(stderr, "Can't get the name of the news server from %s\n", X SERVER_FILE); X fprintf(stderr, X "Either fix this file, or put NNTPSERVER in your environment.\n"); X finalize(1); X } X X response = server_init(server); X if (response < 0) { X fprintf(stderr, X "Couldn't connect to %s news server, try again later.\n", X server); X finalize(1); X } X X if (handle_server_response(response, server) < 0) X finalize(1); X X#endif X X /* open active file, etc. */ X X ngdata_init(); X X /* now read in the .newsrc file */ X X foundany = rcstuff_init(); X X /* it looks like we will actually read something, so init everything */ X X addng_init(); X art_init(); X artio_init(); X artsrch_init(); X backpage_init(); X bits_init(); X cheat_init(); X head_init(); X help_init(); X kfile_init(); X ng_init(); X ngsrch_init(); X ngstuff_init(); X only_init(); X rcln_init(); X respond_init(); X rn_init(); X search_init(); X#ifdef USETHREADS X thread_init(); X#endif X util_init(); X X#ifdef FINDNEWNG X fstat(actfp->_file,&filestat); /* did active file grow? */ X /* X * Skip this check if the -q flag was given. X */ X X if (!quickstart && filestat.st_size != lastactsiz) { X long actsiz = filestat.st_size; /* remember new size */ X NG_NUM oldnext = nextrcline; /* remember # lines in newsrc */ X#ifdef FASTNEW X bool munged = writesoft || !lastactsiz; X /* bad soft ptrs -> edited active */ X#else X bool munged = TRUE; /* just assume .newsrc munged */ X#endif X X#ifdef VERBOSE X IF(verbose) X fputs("\nChecking active list for new newsgroups...\n",stdout) X FLUSH; X ELSE X#endif X#ifdef TERSE X fputs("\nNew newsgroups:\n",stdout) FLUSH; X#endif X#ifdef FASTNEW X if (!munged) { /* maybe just do tail of file? */ X fseek(actfp,lastactsiz-1,0); X fgets(buf,LBUFLEN,actfp); X munged = (*buf != '\n'); X if (!munged) X munged = newlist(munged,FALSE); X } X#endif X if (munged) { /* must we scan entire file? */ X fseek(actfp,0L,0); /* rewind active file */ X newlist(munged,FALSE); /* sure hope they use hashing... */ X } X lastactsiz = actsiz; /* remember for .rnlast */ X if (nextrcline != oldnext) { /* did we add any new groups? */ X foundany = TRUE; /* let main() know */ X starthere = 0; /* and start ng scan from the top */ X } X } X#endif X time(&lasttime); /* remember when we inited-- */ X /* ends up back in .rnlast */ X writelast(); /* in fact, put it there now */ X X#ifdef FINDNEWNG X# ifdef ONLY X if (maxngtodo) /* patterns on command line? */ X foundany |= scanactive(); X# endif X#endif X X return foundany; X} X X/* make sure there is no rn out there already */ X Xvoid Xlock_check() X{ X lockname = savestr(filexp(LOCKNAME)); X if (!checkflag) { X tmpfp = fopen(lockname,"r"); X if (tmpfp != Nullfp) { X int processnum; X X fgets(buf,LBUFLEN,tmpfp); X fclose(tmpfp); X processnum = atoi(buf); X#ifdef VERBOSE X IF(verbose) X printf("You seem to have left an rn running, process %d.\n", X processnum) FLUSH; X ELSE X#endif X#ifdef TERSE X printf("Rn left running, #%d.\n", processnum) FLUSH; X#endif X if (kill(processnum, SIGEMT)) { X /* does process not exist? */ X /* (rn ignores SIGEMT) */ X sleep(2); X#ifdef VERBOSE X IF(verbose) X fputs("\n\ XThat process does not seem to exist anymore. The count of read articles\n\ Xmay be incorrect in the last newsgroup accessed by that other (defunct)\n\ Xprocess.\n\n",stdout) FLUSH; X ELSE X#endif X#ifdef TERSE X fputs("\nProcess crashed.\n",stdout) FLUSH; X#endif X if (*lastngname) { X#ifdef VERBOSE X IF(verbose) X printf("(The last newsgroup accessed was %s.)\n\n", X lastngname) FLUSH; X ELSE X#endif X#ifdef TERSE X printf("(In %s.)\n\n",lastngname) FLUSH; X#endif X } X get_anything(); X putchar('\n') FLUSH; X } X else { X#ifdef VERBOSE X IF(verbose) X fputs("\n\ XYou may not have two copies of rn running simultaneously. Goodbye.\n\ X",stdout) FLUSH; X ELSE X#endif X#ifdef TERSE X fputs("\nCan't start another.\n",stdout) FLUSH; X#endif X if (bizarre) X resetty(); X exit(0); X } X } X tmpfp = fopen(lockname,"w"); X if (tmpfp == Nullfp) { X printf(cantcreate,lockname) FLUSH; X sig_catcher(0); X } X fprintf(tmpfp,"%d\n",getpid()); X fclose(tmpfp); X } X} X Xvoid Xnewsnews_check() X{ X char *newsnewsname = filexp(NEWSNEWSNAME); X X if ((tmpfp = fopen(newsnewsname,"r")) != Nullfp) { X fstat(tmpfp->_file,&filestat); X if (filestat.st_mtime > lasttime) { X while (fgets(buf,sizeof(buf),tmpfp) != Nullch) X fputs(buf,stdout) FLUSH; X get_anything(); X putchar('\n') FLUSH; X } X fclose(tmpfp); X } X} END_OF_FILE if test 8405 -ne `wc -c <'init.c'`; then echo shar: \"'init.c'\" unpacked with wrong size! fi # end of 'init.c' fi if test -f 'term.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'term.c'\" else echo shar: Extracting \"'term.c'\" \(25423 characters\) sed "s/^X//" >'term.c' <<'END_OF_FILE' X/* $Header: term.c,v 4.3.3.1 90/07/28 18:09:09 davison Trn $ X * X * $Log: term.c,v $ X * Revision 4.3.3.1 90/07/28 18:09:09 davison X * Initial Trn Release X * X * Revision 4.3.2.7 90/04/21 16:54:29 sob X * Installed patches provided by SCO for SCO Xenix X * X * Revision 4.3.2.6 90/04/13 23:48:17 sob X * Modifications provided by Gene Hackney for 3b2. X * X * Revision 4.3.2.5 90/04/06 20:35:08 sob X * Added fixes for SCO Xenix sent by ronald@robobar.co.uk. X * X * Revision 4.3.2.4 90/03/22 23:05:38 sob X * Fixes provided by Wayne Davison <drivax!davison> X * X * Revision 4.3.2.3 89/11/28 01:51:58 sob X * Now handles SIGWINCH correctly. X * X * Revision 4.3.2.2 89/11/27 01:31:34 sob X * Altered NNTP code per ideas suggested by Bela Lubkin X * <filbo@gorn.santa-cruz.ca.us> X * X * Revision 4.3.2.1 89/11/06 01:02:12 sob X * Added RRN support from NNTP 1.5 X * X * Revision 4.3.1.3 85/09/10 11:05:23 lwall X * Improved %m in in_char(). X * X * Revision 4.3.1.2 85/05/16 16:45:35 lwall X * Forced \r to \n on input. X * Fix for terminfo braindamage regarding bc emulation. X * X * Revision 4.3.1.1 85/05/10 11:41:03 lwall X * Branch for patches. X * X * Revision 4.3 85/05/01 11:51:10 lwall X * Baseline for release with 4.3bsd. X * X */ X X#include "EXTERN.h" X#include "common.h" X#include "util.h" X#include "final.h" X#include "help.h" X#include "cheat.h" X#include "intrp.h" X#include "INTERN.h" X#include "term.h" X X#ifdef SYS_PTEM X#include <sys/stream.h> X#include <sys/ptem.h> X#endif X Xchar ERASECH; /* rubout character */ Xchar KILLCH; /* line delete character */ Xchar tcarea[TCSIZE]; /* area for "compiled" termcap strings */ X X#ifdef USETHREADS Xint upcost; X#endif X X/* guarantee capability pointer != Nullch */ X/* (I believe terminfo will ignore the &tmpaddr argument.) */ X X#define Tgetstr(key) ((tmpstr = tgetstr(key,&tmpaddr)) ? tmpstr : nullstr) X X#ifdef PUSHBACK Xstruct keymap { X char km_type[128]; X union km_union { X struct keymap *km_km; X char *km_str; X } km_ptr[128]; X}; X X#define KM_NOTHIN 0 X#define KM_STRING 1 X#define KM_KEYMAP 2 X#define KM_BOGUS 3 X X#define KM_TMASK 3 X#define KM_GSHIFT 4 X#define KM_GMASK 7 X Xtypedef struct keymap KEYMAP; X XKEYMAP *topmap INIT(Null(KEYMAP*)); X Xvoid mac_init(); XKEYMAP *newkeymap(); Xvoid show_keymap(); Xvoid pushstring(); X#endif X Xvoid line_col_calcs(); X X/* terminal initialization */ X Xvoid Xterm_init() X{ X savetty(); /* remember current tty state */ X X#ifdef TERMIO X ospeed = _tty.c_cflag & CBAUD; /* for tputs() */ X ERASECH = _tty.c_cc[VERASE]; /* for finish_command() */ X KILLCH = _tty.c_cc[VKILL]; /* for finish_command() */ X#else X ospeed = _tty.sg_ospeed; /* for tputs() */ X ERASECH = _tty.sg_erase; /* for finish_command() */ X KILLCH = _tty.sg_kill; /* for finish_command() */ X#endif X X /* The following could be a table but I can't be sure that there isn't */ X /* some degree of sparsity out there in the world. */ X X switch (ospeed) { /* 1 second of padding */ X#ifdef BEXTA X case BEXTA: just_a_sec = 1920; break; X#else X#ifdef B19200 X case B19200: just_a_sec = 1920; break; X#endif X#endif X case B9600: just_a_sec = 960; break; X case B4800: just_a_sec = 480; break; X case B2400: just_a_sec = 240; break; X case B1800: just_a_sec = 180; break; X case B1200: just_a_sec = 120; break; X case B600: just_a_sec = 60; break; X case B300: just_a_sec = 30; break; X /* do I really have to type the rest of this??? */ X case B200: just_a_sec = 20; break; X case B150: just_a_sec = 15; break; X case B134: just_a_sec = 13; break; X case B110: just_a_sec = 11; break; X case B75: just_a_sec = 8; break; X case B50: just_a_sec = 5; break; X default: just_a_sec = 960; break; X /* if we are running detached I */ X } /* don't want to know about it! */ X} X X/* set terminal characteristics */ X Xvoid Xterm_set(tcbuf) Xchar *tcbuf; /* temp area for "uncompiled" termcap entry */ X{ X char *tmpaddr; /* must not be register */ X register char *tmpstr; X char *tgetstr(); X char *s; X int status; X#ifdef TIOCGWINSZ X#ifdef u3b2 Xstruct winsize { X unsigned short ws_row; /* rows, in characters*/ X unsigned short ws_col; /* columns, in character */ X unsigned short ws_xpixel; /* horizontal size, pixels */ X unsigned short ws_ypixel; /* vertical size, pixels */ X}; X#endif X struct winsize winsize; X#endif X X#ifdef PENDING X#if ! defined (FIONREAD) && ! defined (RDCHK) X /* do no delay reads on something that always gets closed on exit */ X X devtty = open("/dev/tty",0); X if (devtty < 0) { X printf(cantopen,"/dev/tty") FLUSH; X finalize(1); X } X fcntl(devtty,F_SETFL,O_NDELAY); X#endif X#endif X X /* get all that good termcap stuff */ X X#ifdef HAVETERMLIB X status = tgetent(tcbuf,getenv("TERM")); /* get termcap entry */ X if (status < 1) { X#ifdef VERBOSE X printf("No termcap %s found.\n", status ? "file" : "entry") FLUSH; X#else X fputs("Termcap botch\n",stdout) FLUSH; X#endif X finalize(1); X } X tmpaddr = tcarea; /* set up strange tgetstr pointer */ X s = Tgetstr("pc"); /* get pad character */ X PC = *s; /* get it where tputs wants it */ X if (!tgetflag("bs")) { /* is backspace not used? */ X BC = Tgetstr("bc"); /* find out what is */ X if (BC == nullstr) /* terminfo grok's 'bs' but not 'bc' */ X BC = Tgetstr("le"); X } else X BC = "\b"; /* make a backspace handy */ X UP = Tgetstr("up"); /* move up a line */ X if (!*UP) /* no UP string? */ X marking = 0; /* disable any marking */ X if (muck_up_clear) /* this is for weird HPs */ X CL = "\n\n\n\n"; X else X CL = Tgetstr("cl"); /* get clear string */ X CE = Tgetstr("ce"); /* clear to end of line string */ X#if defined(CLEAREOL) || defined(USETHREADS) X HO = Tgetstr("ho"); /* home cursor if no CM */ X CM = Tgetstr("cm"); /* cursor motion */ X if (*CM || *HO) X can_home = TRUE; X#endif X#ifdef CLEAREOL X CD = Tgetstr("cd"); /* clear to end of display */ X if (!*CE || !*CD || !can_home) /* can we CE, CD, and home? */ X can_home_clear = FALSE; /* no, so disable use of clear eol */ X#endif /* CLEAREOL */ X#ifdef USETHREADS X upcost = strlen(UP); X#endif X SO = Tgetstr("so"); /* begin standout */ X SE = Tgetstr("se"); /* end standout */ X if ((SG = tgetnum("sg"))<0) X SG = 0; /* blanks left by SG, SE */ X US = Tgetstr("us"); /* start underline */ X UE = Tgetstr("ue"); /* end underline */ X if ((UG = tgetnum("ug"))<0) X UG = 0; /* blanks left by US, UE */ X if (*US) X UC = nullstr; /* UC must not be NULL */ X else X UC = Tgetstr("uc"); /* underline a character */ X if (!*US && !*UC) { /* no underline mode? */ X US = SO; /* substitute standout mode */ X UE = SE; X UG = SG; X } X LINES = tgetnum("li"); /* lines per page */ X COLS = tgetnum("co"); /* columns on page */ X X#ifdef TIOCGWINSZ X { struct winsize ws; X if (ioctl(0, TIOCGWINSZ, &ws) >= 0 && ws.ws_row > 0 && ws.ws_col > 0) { X LINES = ws.ws_row; X COLS = ws.ws_col; X } X } X#endif X X AM = tgetflag("am"); /* terminal wraps automatically? */ X XN = tgetflag("xn"); /* then eats next newline? */ X VB = Tgetstr("vb"); X if (!*VB) X VB = "\007"; X CR = Tgetstr("cr"); X if (!*CR) { X if (tgetflag("nc") && *UP) { X CR = safemalloc((MEM_SIZE)strlen(UP)+2); X sprintf(CR,"%s\r",UP); X } X else X CR = "\r"; X } X#ifdef TIOCGWINSZ X if (ioctl(1, TIOCGWINSZ, &winsize)>=0) { X if (winsize.ws_row>0) LINES=winsize.ws_row; X if (winsize.ws_col>0) COLS=winsize.ws_col; X } X#endif X#else X ?????? /* Roll your own... */ X#endif X line_col_calcs(); X noecho(); /* turn off echo */ X crmode(); /* enter cbreak mode */ X X#ifdef PUSHBACK X mac_init(tcbuf); X#endif X} X X#ifdef PUSHBACK Xvoid Xmac_init(tcbuf) Xchar *tcbuf; X{ X char tmpbuf[1024]; X X tmpfp = fopen(filexp(getval("RNMACRO",RNMACRO)),"r"); X if (tmpfp != Nullfp) { X while (fgets(tcbuf,1024,tmpfp) != Nullch) { X mac_line(tcbuf,tmpbuf,(sizeof tmpbuf)); X } X fclose(tmpfp); X } X} X Xvoid Xmac_line(line,tmpbuf,tbsize) Xchar *line; Xchar *tmpbuf; Xint tbsize; X{ X register char *s, *m; X register KEYMAP *curmap; X register int ch; X register int garbage = 0; X static char override[] = "\nkeymap overrides string\n"; X X if (topmap == Null(KEYMAP*)) X topmap = newkeymap(); X if (*line == '#' || *line == '\n') X return; X if (line[ch = strlen(line)-1] == '\n') X line[ch] = '\0'; X m = dointerp(tmpbuf,tbsize,line," \t"); X if (!*m) X return; X while (*m == ' ' || *m == '\t') m++; X for (s=tmpbuf,curmap=topmap; *s; s++) { X ch = *s & 0177; X if (s[1] == '+' && isdigit(s[2])) { X s += 2; X garbage = (*s & KM_GMASK) << KM_GSHIFT; X } X else X garbage = 0; X if (s[1]) { X if ((curmap->km_type[ch] & KM_TMASK) == KM_STRING) { X fputs(override,stdout) FLUSH; X free(curmap->km_ptr[ch].km_str); X curmap->km_ptr[ch].km_str = Nullch; X } X curmap->km_type[ch] = KM_KEYMAP + garbage; X if (curmap->km_ptr[ch].km_km == Null(KEYMAP*)) X curmap->km_ptr[ch].km_km = newkeymap(); X curmap = curmap->km_ptr[ch].km_km; X } X else { X if ((curmap->km_type[ch] & KM_TMASK) == KM_KEYMAP) X fputs(override,stdout) FLUSH; X else { X curmap->km_type[ch] = KM_STRING + garbage; X curmap->km_ptr[ch].km_str = savestr(m); X } X } X } X} X XKEYMAP* Xnewkeymap() X{ X register int i; X register KEYMAP *map; X X#ifndef lint X map = (KEYMAP*)safemalloc(sizeof(KEYMAP)); X#else X map = Null(KEYMAP*); X#endif /* lint */ X for (i=127; i>=0; --i) { X map->km_ptr[i].km_km = Null(KEYMAP*); X map->km_type[i] = KM_NOTHIN; X } X return map; X} X Xvoid Xshow_macros() X{ X char prebuf[64]; X X if (topmap != Null(KEYMAP*)) { X print_lines("Macros:\n",STANDOUT); X *prebuf = '\0'; X show_keymap(topmap,prebuf); X } X else { X print_lines("No macros defined.\n", NOMARKING); X } X} X Xvoid Xshow_keymap(curmap,prefix) Xregister KEYMAP *curmap; Xchar *prefix; X{ X register int i; X register char *next = prefix + strlen(prefix); X register int kt; X X for (i=0; i<128; i++) { X if (kt = curmap->km_type[i]) { X if (i < ' ') X sprintf(next,"^%c",i+64); X else if (i == ' ') X strcpy(next,"\\040"); X else if (i == 127) X strcpy(next,"^?"); X else X sprintf(next,"%c",i); X if ((kt >> KM_GSHIFT) & KM_GMASK) { X sprintf(cmd_buf,"+%d", (kt >> KM_GSHIFT) & KM_GMASK); X strcat(next,cmd_buf); X } X switch (kt & KM_TMASK) { X case KM_NOTHIN: X sprintf(cmd_buf,"%s %c\n",prefix,i); X print_lines(cmd_buf,NOMARKING); X break; X case KM_KEYMAP: X show_keymap(curmap->km_ptr[(char)i].km_km, prefix); X break; X case KM_STRING: X sprintf(cmd_buf,"%s %s\n",prefix,curmap->km_ptr[i].km_str); X print_lines(cmd_buf,NOMARKING); X break; X case KM_BOGUS: X sprintf(cmd_buf,"%s BOGUS\n",prefix); X print_lines(cmd_buf,STANDOUT); X break; X } X } X } X} X X#endif X X/* routine to pass to tputs */ X Xchar Xputchr(ch) Xregister char ch; X{ X putchar(ch); X#ifdef lint X ch = Null(char); X ch = ch; X#endif X return((char) 0); X} X X/* input the 2nd and succeeding characters of a multi-character command */ X/* returns TRUE if command finished, FALSE if they rubbed out first character */ X Xbool Xfinish_command(donewline) Xint donewline; X{ X register char *s; X register bool quoteone = FALSE; X X s = buf; X if (s[1] != FINISHCMD) /* someone faking up a command? */ X return TRUE; X do { X top: X if ((unsigned char)*s < ' ') { X putchar('^'); X putchar(*s | 64); X } X else if (*s == '\177') { X putchar('^'); X putchar('?'); X } X else X putchar(*s); /* echo previous character */ X s++; Xre_read: X fflush(stdout); X getcmd(s); X if (quoteone) { X quoteone = FALSE; X continue; X } X if (errno || *s == Ctl('l')) { X *s = Ctl('r'); /* force rewrite on CONT */ X } X if (*s == '\033') { /* substitution desired? */ X#ifdef ESCSUBS X char tmpbuf[4], *cpybuf; X X tmpbuf[0] = '%'; X read_tty(&tmpbuf[1],1); X#ifdef RAWONLY X tmpbuf[1] &= 0177; X#endif X tmpbuf[2] = '\0'; X if (tmpbuf[1] == 'h') { X (void) help_subs(); X *s = '\0'; X reprint(); X goto re_read; X } X else if (tmpbuf[1] == '\033') { X *s = '\0'; X cpybuf = savestr(buf); X interp(buf, (sizeof buf), cpybuf); X free(cpybuf); X s = buf + strlen(buf); X reprint(); X goto re_read; X } X else { X interp(s,(sizeof buf) - (s-buf),tmpbuf); X fputs(s,stdout); X s += strlen(s); X } X goto re_read; X#else X notincl("^["); X *s = '\0'; X reprint(); X goto re_read; X#endif X } X else if (*s == ERASECH) { /* they want to rubout a char? */ X rubout(); X s--; /* discount the char rubbed out */ X if ((unsigned char)*s < ' ' || *s == '\177') X rubout(); X if (s == buf) { /* entire string gone? */ X fflush(stdout); /* return to single char command mode */ X return FALSE; X } X else X goto re_read; X } X else if (*s == KILLCH) { /* wipe out the whole line? */ X while (s-- != buf) { /* emulate that many ERASEs */ X rubout(); X if ((unsigned char)*s < ' ' || *s == '\177') X rubout(); X } X fflush(stdout); X return FALSE; /* return to single char mode */ X } X#ifdef WORDERASE X else if (*s == Ctl('w')) { /* wipe out one word? */ X *s-- = ' '; X while (!isspace(*s) || isspace(s[1])) { X rubout(); X if (s-- == buf) { X fflush(stdout); X return FALSE; /* return to single char mode */ X } X if ((unsigned char)*s < ' ' || *s == '\177') X rubout(); X } X s++; X goto re_read; X } X#endif X else if (*s == Ctl('r')) { X *s = '\0'; X reprint(); X goto re_read; X } X else if (*s == Ctl('v')) { X putchar('^'); X backspace(); X fflush(stdout); X getcmd(s); X goto top; X } X else if (*s == '\\') { X quoteone = TRUE; X } X } while (*s != '\n'); /* till a newline (not echoed) */ X *s = '\0'; /* terminate the string nicely */ X if (donewline) X putchar('\n') FLUSH; X return TRUE; /* say we succeeded */ X} X X/* discard any characters typed ahead */ X Xvoid Xeat_typeahead() X{ X#ifdef PUSHBACK X if (!typeahead && nextin==nextout) /* cancel only keyboard stuff */ X#else X if (!typeahead) X#endif X { X#ifdef PENDING X while (input_pending()) X read_tty(buf,sizeof(buf)); X#else /* this is probably v7 */ X ioctl(_tty_ch,TIOCSETP,&_tty); X#endif X } X} X Xvoid Xsettle_down() X{ X dingaling(); X fflush(stdout); X sleep(1); X#ifdef PUSHBACK X nextout = nextin; /* empty circlebuf */ X#endif X eat_typeahead(); X} X X#ifdef PUSHBACK X/* read a character from the terminal, with multi-character pushback */ X Xint Xread_tty(addr,size) Xchar *addr; Xint size; X{ X if (nextout != nextin) { X *addr = circlebuf[nextout++]; X nextout %= PUSHSIZE; X return 1; X } X else { X size = read(0,addr,size); X#ifdef RAWONLY X *addr &= 0177; X#endif X return size; X } X} X X#ifdef PENDING X#if ! defined (FIONREAD) && ! defined (RDCHK) Xint Xcircfill() X{ X register int Howmany = read(devtty,circlebuf+nextin,1); X X if (Howmany) { X nextin += Howmany; X nextin %= PUSHSIZE; X } X return Howmany; X} X#endif /* PENDING */ X#endif /* FIONREAD */ X Xvoid Xpushchar(c) Xchar c; X{ X nextout--; X if (nextout < 0) X nextout = PUSHSIZE - 1; X if (nextout == nextin) { X fputs("\npushback buffer overflow\n",stdout) FLUSH; X sig_catcher(0); X } X circlebuf[nextout] = c; X} X X#else /* PUSHBACK */ X#ifndef read_tty X/* read a character from the terminal, with hacks for O_NDELAY reads */ X Xint Xread_tty(addr,size) Xchar *addr; Xint size; X{ X if (is_input) { X *addr = pending_ch; X is_input = FALSE; X return 1; X } X else { X size = read(0,addr,size); X#ifdef RAWONLY X *addr &= 0177; X#endif X return size; X } X} X#endif /* read_tty */ X#endif /* PUSHBACK */ X X/* print an underlined string, one way or another */ X Xvoid Xunderprint(s) Xregister char *s; X{ X assert(UC); X if (*UC) { /* char by char underline? */ X while (*s) { X if ((unsigned char)*s < ' ') { X putchar('^'); X backspace();/* back up over it */ X underchar();/* and do the underline */ X putchar(*s+64); X backspace();/* back up over it */ X underchar();/* and do the underline */ X } X else { X putchar(*s); X backspace();/* back up over it */ X underchar();/* and do the underline */ X } X s++; X } X } X else { /* start and stop underline */ X underline(); /* start underlining */ X while (*s) { X if ((unsigned char)*s < ' ') { X putchar('^'); X putchar(*s+64); X } X else X putchar(*s); X s++; X } X un_underline(); /* stop underlining */ X } X} X X/* keep screen from flashing strangely on magic cookie terminals */ X X#ifdef NOFIREWORKS Xvoid Xno_sofire() X{ X if (*UP && *SE) { /* should we disable fireworks? */ X putchar('\n'); X un_standout(); X up_line(); X carriage_return(); X } X} X Xvoid Xno_ulfire() X{ X if (*UP && *US) { /* should we disable fireworks? */ X putchar('\n'); X un_underline(); X up_line(); X carriage_return(); X } X} X#endif X X/* get a character into a buffer */ X Xvoid Xgetcmd(whatbuf) Xregister char *whatbuf; X{ X#ifdef PUSHBACK X register KEYMAP *curmap; X register int i; X bool no_macros; X int times = 0; /* loop detector */ X char scrchar; X Xtryagain: X curmap = topmap; X no_macros = (whatbuf != buf && nextin == nextout); X#endif X for (;;) { X int_count = 0; X errno = 0; X if (read_tty(whatbuf,1) < 0) X if (!errno) X errno = EINTR; X else { X perror(readerr); X sig_catcher(0); X } X#ifdef PUSHBACK X if (*whatbuf & 0200 || no_macros) { X *whatbuf &= 0177; X goto got_canonical; X } X if (curmap == Null(KEYMAP*)) X goto got_canonical; X for (i = (curmap->km_type[*whatbuf] >> KM_GSHIFT) & KM_GMASK; i; --i){ X read_tty(&scrchar,1); X } X switch (curmap->km_type[*whatbuf] & KM_TMASK) { X case KM_NOTHIN: /* no entry? */ X if (curmap == topmap) /* unmapped canonical */ X goto got_canonical; X settle_down(); X goto tryagain; X case KM_KEYMAP: /* another keymap? */ X curmap = curmap->km_ptr[*whatbuf].km_km; X assert(curmap != Null(KEYMAP*)); X break; X case KM_STRING: /* a string? */ X pushstring(curmap->km_ptr[*whatbuf].km_str); X if (++times > 20) { /* loop? */ X fputs("\nmacro loop?\n",stdout); X settle_down(); X } X no_macros = FALSE; X goto tryagain; X } X#else X#ifdef RAWONLY X *whatbuf &= 0177; X#endif X break; X#endif X } X Xgot_canonical: X#ifndef TERMIO X if (*whatbuf == '\r') X *whatbuf = '\n'; X#endif X if (whatbuf == buf) X whatbuf[1] = FINISHCMD; /* tell finish_command to work */ X} X X#ifdef PUSHBACK Xvoid Xpushstring(str) Xchar *str; X{ X register int i; X char tmpbuf[PUSHSIZE]; X register char *s = tmpbuf; X X assert(str != Nullch); X interp(s,PUSHSIZE,str); X for (i = strlen(s)-1; i >= 0; --i) { X s[i] ^= 0200; X pushchar(s[i]); X } X} X#endif X Xint Xget_anything() X{ X char tmpbuf[2]; X Xreask_anything: X unflush_output(); /* disable any ^O in effect */ X standout(); X#ifdef VERBOSE X IF(verbose) X fputs("[Type space to continue] ",stdout); X ELSE X#endif X#ifdef TERSE X fputs("[MORE] ",stdout); X#endif X un_standout(); X fflush(stdout); X eat_typeahead(); X if (int_count) { X return -1; X } X collect_subjects(); /* loads subject cache until */ X /* input is pending */ X getcmd(tmpbuf); X if (errno || *tmpbuf == '\f') { X putchar('\n') FLUSH; /* if return from stop signal */ X goto reask_anything; /* give them a prompt again */ X } X if (*tmpbuf == 'h') { X#ifdef VERBOSE X IF(verbose) X fputs("\nType q to quit or space to continue.\n",stdout) FLUSH; X ELSE X#endif X#ifdef TERSE X fputs("\nq to quit, space to continue.\n",stdout) FLUSH; X#endif X goto reask_anything; X } X else if (*tmpbuf != ' ' && *tmpbuf != '\n') { X carriage_return(); X erase_eol(); /* erase the prompt */ X carriage_return(); X return *tmpbuf == 'q' ? -1 : *tmpbuf; X } X if (*tmpbuf == '\n') { X page_line = LINES - 1; X carriage_return(); X erase_eol(); X carriage_return(); X } X else { X page_line = 1; X if (erase_screen) /* -e? */ X clear(); /* clear screen */ X else { X carriage_return(); X erase_eol(); /* erase the prompt */ X carriage_return(); X } X } X return 0; X} X X#ifdef USETHREADS Xint Xpause_getcmd() X{ X unflush_output(); /* disable any ^O in effect */ X standout(); X#ifdef VERBOSE X IF(verbose) X fputs("[Type space or a command] ",stdout); X ELSE X#endif X#ifdef TERSE X fputs("[CMD] ",stdout); X#endif X un_standout(); X fflush(stdout); X eat_typeahead(); X if (int_count) { X return -1; X } X getcmd(buf); X if (errno || *buf == '\f') { X return 0; /* if return from stop signal */ X } X else if (*buf != ' ') { X carriage_return(); X erase_eol(); /* erase the prompt */ X carriage_return(); X return *buf; X } X return 0; X} X#endif X Xvoid Xin_char(prompt, newmode) Xchar *prompt; Xchar newmode; X{ X char oldmode = mode; X Xreask_in_char: X unflush_output(); /* disable any ^O in effect */ X fputs(prompt,stdout); X fflush(stdout); X eat_typeahead(); X mode = newmode; X getcmd(buf); X if (errno || *buf == '\f') { X putchar('\n') FLUSH; /* if return from stop signal */ X goto reask_in_char; /* give them a prompt again */ X } X mode = oldmode; X} X Xint Xprint_lines(what_to_print,hilite) Xchar *what_to_print; Xint hilite; X{ X register char *s; X register int i; X X if (page_line < 0) /* they do not want to see this? */ X return -1; X for (s=what_to_print; *s; ) { X if (page_line >= LINES || int_count) { X if (i = -1, int_count || (i = get_anything())) { X page_line = -1; /* disable further print_lines */ X return i; X } X } X page_line++; X if (hilite == STANDOUT) { X#ifdef NOFIREWORKS X if (erase_screen) X no_sofire(); X#endif X standout(); X } X else if (hilite == UNDERLINE) { X#ifdef NOFIREWORKS X if (erase_screen) X no_ulfire(); X#endif X underline(); X } X for (i=0; i<COLS; i++) { X if (!*s) X break; X if ((unsigned char)*s >= ' ') X putchar(*s); X else if (*s == '\t') { X putchar(*s); X i = ((i+8) & ~7) - 1; X } X else if (*s == '\n') { X i = 32000; X } X else { X i++; X putchar('^'); X putchar(*s + 64); X } X s++; X } X if (i) { X if (hilite == STANDOUT) X un_standout(); X else if (hilite == UNDERLINE) X un_underline(); X if (AM && i == COLS) X fflush(stdout); X else X putchar('\n') FLUSH; X } X } X return 0; X} X Xvoid Xpage_init() X{ X page_line = 1; X if (erase_screen) X clear(); X else X putchar('\n') FLUSH; X} X Xvoid Xpad(num) Xint num; X{ X register int i; X X for (i = num; i; --i) X putchar(PC); X fflush(stdout); X} X X/* echo the command just typed */ X X#ifdef VERIFY Xvoid Xprintcmd() X{ X if (verify && buf[1] == FINISHCMD) { X if ((unsigned char)*buf < ' ') { X putchar('^'); X putchar(*buf | 64); X backspace(); X backspace(); X } X else { X putchar(*buf); X backspace(); X } X fflush(stdout); X } X} X#endif X Xvoid Xrubout() X{ X backspace(); /* do the old backspace, */ X putchar(' '); /* space, */ X backspace(); /* backspace trick */ X} X Xvoid Xreprint() X{ X register char *s; X X fputs("^R\n",stdout) FLUSH; X for (s = buf; *s; s++) { X if ((unsigned char)*s < ' ') { X putchar('^'); X putchar(*s | 64); X } X else X putchar(*s); X } X} X X#if defined(CLEAREOL) || defined(USETHREADS) Xvoid Xhome_cursor() X{ X char *tgoto(); X X if (!*HO) { /* no home sequence? */ X if (!*CM) { /* no cursor motion either? */ X fputs ("\n\n\n", stdout); X return; /* forget it. */ X } X tputs (tgoto (CM, 0, 0), 1, putchr); /* go to home via CM */ X return; X } X else { /* we have home sequence */ X tputs (HO, 1, putchr); /* home via HO */ X } X} X#endif X X#ifdef USETHREADS Xvoid Xgoto_line(from,to) /* assumes caller is already at beginning of line */ Xint from,to; X{ X char *tgoto(), *str; X int cmcost; X X if (from == to) { X return; X } X if (*CM) { X cmcost = strlen(str = tgoto(CM,0,to)); X } else { X cmcost = 9999; X } X if (to > from) { X go_down: X if (to - from <= cmcost) { X while(from++ < to) { X putchar('\n'); X } X return; X } X } else if(*UP) { X if ((from - to) * upcost <= cmcost) { X while(from-- > to) { X tputs(UP,1,putchr); X } X return; X } X } else if (cmcost == 9999) { X home_cursor(); X from = 0; X goto go_down; X } X tputs(str,1,putchr); X} X#endif X X Xvoid Xline_col_calcs() X{ X if (LINES > 0) { /* is this a crt? */ X if ((!initlines) || (!initlines_specified)) X /* no -i or unreasonable value for initlines */ X if (ospeed >= B9600) /* whole page at >= 9600 baud */ X initlines = LINES; X else if (ospeed >= B4800)/* 16 lines at 4800 */ X initlines = 16; X else /* otherwise just header */ X initlines = 8; X } X else { /* not a crt */ X LINES = 30000; /* so don't page */ X CL = "\n\n"; /* put a couple of lines between */ X if ((!initlines) || (!initlines_specified)) X /* make initlines reasonable */ X initlines = 8; X } X if (COLS <= 0) X COLS = 80; X} X X X#ifdef SIGWINCH Xint Xwinch_catcher() X{ X /* Come here if window size change signal received */ X#ifdef TIOCGWINSZ X struct winsize ws; X X if (ioctl(0, TIOCGWINSZ, &ws) >= 0 && ws.ws_row > 0 && ws.ws_col > 0) { X LINES = ws.ws_row; X COLS = ws.ws_col; X line_col_calcs(); X } X#else X ??????? X /* Well, if SIGWINCH is defined, but TIOCGWINSZ isn't, there's */ X /* almost certainly something wrong. Figure it out for yourself, */ X /* because I don't know now to deal :-) */ X#endif X} X#endif END_OF_FILE if test 25423 -ne `wc -c <'term.c'`; then echo shar: \"'term.c'\" unpacked with wrong size! fi # end of 'term.c' fi echo shar: End of archive 7 \(of 14\). cp /dev/null ark7isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 14 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still must unpack the following archives: echo " " ${MISSING} fi exit 0 exit 0 # Just in case... -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net. Use a domain-based address or give alternate paths, or you may lose out.