home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume1 / rn / part05 < prev    next >
Encoding:
Internet Message Format  |  1986-11-30  |  61.7 KB

  1. Date: Tue, 7 May 85 13:53:58 pdt
  2. From: allegra!sdcrdcf!RDCF.SDC.UUCP!lwall (Larry Wall)
  3. Newsgroups: mod.sources
  4. Subject: rn version 4.3 (kit 5 of 9)
  5. Reply-To: lwall@sdcrdcf.UUCP
  6. Organization: System Development Corporation R&D, Santa Monica
  7.  
  8. #! /bin/sh
  9.  
  10. # Make a new directory for the rn sources, cd to it, and run kits 1 thru 9 
  11. # through sh.  When all 9 kits have been run, read README.
  12.  
  13. echo "This is rn kit 5 (of 9).  If kit 5 is complete, the line"
  14. echo '"'"End of kit 5 (of 9)"'" will echo at the end.'
  15. echo ""
  16. export PATH || (echo "You didn't use sh, you clunch." ; kill $$)
  17. echo Extracting term.c
  18. cat >term.c <<'!STUFFY!FUNK!'
  19. /* $Header: term.c,v 4.3 85/05/01 11:51:10 lwall Exp $
  20.  *
  21.  * $Log:    term.c,v $
  22.  * Revision 4.3  85/05/01  11:51:10  lwall
  23.  * Baseline for release with 4.3bsd.
  24.  * 
  25.  */
  26.  
  27. #include "EXTERN.h"
  28. #include "common.h"
  29. #include "util.h"
  30. #include "final.h"
  31. #include "help.h"
  32. #include "cheat.h"
  33. #include "intrp.h"
  34. #include "INTERN.h"
  35. #include "term.h"
  36.  
  37. char ERASECH;        /* rubout character */
  38. char KILLCH;        /* line delete character */
  39. char tcarea[TCSIZE];    /* area for "compiled" termcap strings */
  40.  
  41. /* guarantee capability pointer != Nullch */
  42. /* (I believe terminfo will ignore the &tmpaddr argument.) */
  43.  
  44. #define Tgetstr(key) ((tmpstr = tgetstr(key,&tmpaddr)) ? tmpstr : nullstr)
  45.  
  46. #ifdef PUSHBACK
  47. struct keymap {
  48.     char km_type[128];
  49.     union km_union {
  50.     struct keymap *km_km;
  51.     char *km_str;
  52.     } km_ptr[128];
  53. };
  54.  
  55. #define KM_NOTHIN 0
  56. #define KM_STRING 1
  57. #define KM_KEYMAP 2
  58. #define KM_BOGUS 3
  59.  
  60. #define KM_TMASK 3
  61. #define KM_GSHIFT 4
  62. #define KM_GMASK 7
  63.  
  64. typedef struct keymap KEYMAP;
  65.  
  66. KEYMAP *topmap INIT(Null(KEYMAP*));
  67.  
  68. void mac_init();
  69. KEYMAP *newkeymap();
  70. void show_keymap();
  71. void pushstring();
  72. #endif
  73.  
  74. /* terminal initialization */
  75.  
  76. void
  77. term_init()
  78. {
  79.     savetty();                /* remember current tty state */
  80.  
  81. #ifdef TERMIO
  82.     ospeed = _tty.c_cflag & CBAUD;    /* for tputs() */
  83.     ERASECH = _tty.c_cc[VERASE];    /* for finish_command() */
  84.     KILLCH = _tty.c_cc[VKILL];        /* for finish_command() */
  85. #else
  86.     ospeed = _tty.sg_ospeed;        /* for tputs() */
  87.     ERASECH = _tty.sg_erase;        /* for finish_command() */
  88.     KILLCH = _tty.sg_kill;        /* for finish_command() */
  89. #endif
  90.  
  91.     /* The following could be a table but I can't be sure that there isn't */
  92.     /* some degree of sparsity out there in the world. */
  93.  
  94.     switch (ospeed) {            /* 1 second of padding */
  95. #ifdef BEXTA
  96.         case BEXTA:  just_a_sec = 1920; break;
  97. #else
  98. #ifdef B19200
  99.         case B19200: just_a_sec = 1920; break;
  100. #endif
  101. #endif
  102.         case B9600:  just_a_sec =  960; break;
  103.         case B4800:  just_a_sec =  480; break;
  104.         case B2400:  just_a_sec =  240; break;
  105.         case B1800:  just_a_sec =  180; break;
  106.         case B1200:  just_a_sec =  120; break;
  107.         case B600:   just_a_sec =   60; break;
  108.     case B300:   just_a_sec =   30; break;
  109.     /* do I really have to type the rest of this??? */
  110.         case B200:   just_a_sec =   20; break;
  111.         case B150:   just_a_sec =   15; break;
  112.         case B134:   just_a_sec =   13; break;
  113.         case B110:   just_a_sec =   11; break;
  114.         case B75:    just_a_sec =    8; break;
  115.         case B50:    just_a_sec =    5; break;
  116.         default:     just_a_sec =  960; break;
  117.                     /* if we are running detached I */
  118.     }                    /*  don't want to know about it! */
  119. }
  120.  
  121. /* set terminal characteristics */
  122.  
  123. void
  124. term_set(tcbuf)
  125. char *tcbuf;        /* temp area for "uncompiled" termcap entry */
  126. {
  127.     char *tmpaddr;            /* must not be register */
  128.     register char *tmpstr;
  129.     char *tgetstr();
  130.     char *s;
  131.     int status;
  132.  
  133. #ifdef PENDING
  134. #ifndef FIONREAD
  135.     /* do no delay reads on something that always gets closed on exit */
  136.  
  137.     devtty = open("/dev/tty",0);
  138.     if (devtty < 0) {
  139.     printf(cantopen,"/dev/tty") FLUSH;
  140.     finalize(1);
  141.     }
  142.     fcntl(devtty,F_SETFL,O_NDELAY);
  143. #endif
  144. #endif
  145.     
  146.     /* get all that good termcap stuff */
  147.  
  148. #ifdef HAVETERMLIB
  149.     status = tgetent(tcbuf,getenv("TERM"));    /* get termcap entry */
  150.     if (status < 1) {
  151. #ifdef VERBOSE
  152.     printf("No termcap %s found.\n", status ? "file" : "entry") FLUSH;
  153. #else
  154.     fputs("Termcap botch\n",stdout) FLUSH
  155. #endif
  156.     finalize(1);
  157.     }
  158.     tmpaddr = tcarea;            /* set up strange tgetstr pointer */
  159.     s = Tgetstr("pc");            /* get pad character */
  160.     PC = *s;                /* get it where tputs wants it */
  161.     if (!tgetflag("bs"))        /* is backspace not used? */
  162.     BC = Tgetstr("bc");        /* find out what is */
  163.     else
  164.     BC = "\b";            /* make a backspace handy */
  165.     UP = Tgetstr("up");            /* move up a line */
  166.     if (!*UP)                /* no UP string? */
  167.     marking = 0;            /* disable any marking */
  168.     if (muck_up_clear)            /* this is for weird HPs */
  169.     CL = "\n\n\n\n";
  170.     else
  171.     CL = Tgetstr("cl");        /* get clear string */
  172.     CE = Tgetstr("ce");            /* clear to end of line string */
  173. #ifdef CLEAREOL
  174.     CM = Tgetstr("cm");            /* cursor motion - PWP */
  175.     HO = Tgetstr("ho");            /* home cursor if no CM - PWP */
  176.     CD = Tgetstr("cd");            /* clear to end of display - PWP */
  177.     if (!*CE || !*CD || (!*CM && !*HO))    /* can we CE, CD, and home? */
  178.     can_home_clear = FALSE;        /*  no, so disable use of clear eol */
  179. #endif CLEAREOL
  180.     SO = Tgetstr("so");            /* begin standout */
  181.     SE = Tgetstr("se");            /* end standout */
  182.     if ((SG = tgetnum("sg"))<0)
  183.     SG = 0;                /* blanks left by SG, SE */
  184.     US = Tgetstr("us");            /* start underline */
  185.     UE = Tgetstr("ue");            /* end underline */
  186.     if ((UG = tgetnum("ug"))<0)
  187.     UG = 0;                /* blanks left by US, UE */
  188.     if (*US)
  189.     UC = nullstr;            /* UC must not be NULL */
  190.     else
  191.     UC = Tgetstr("uc");        /* underline a character */
  192.     if (!*US && !*UC) {            /* no underline mode? */
  193.     US = SO;            /* substitute standout mode */
  194.     UE = SE;
  195.     UG = SG;
  196.     }
  197.     LINES = tgetnum("li");        /* lines per page */
  198.     COLS = tgetnum("co");        /* columns on page */
  199.     AM = tgetflag("am");        /* terminal wraps automatically? */
  200.     XN = tgetflag("xn");        /* then eats next newline? */
  201.     VB = Tgetstr("vb");
  202.     if (!*VB)
  203.     VB = "\007";
  204.     CR = Tgetstr("cr");
  205.     if (!*CR) {
  206.     if (tgetflag("nc") && *UP) {
  207.         CR = safemalloc((MEM_SIZE)strlen(UP)+2);
  208.         sprintf(CR,"%s\r",UP);
  209.     }
  210.     else
  211.         CR = "\r";
  212.     }
  213. #else
  214.     ??????                /* Roll your own... */
  215. #endif
  216.     if (LINES > 0) {            /* is this a crt? */
  217.     if (!initlines)            /* no -i? */
  218.         if (ospeed >= B9600)    /* whole page at >= 9600 baud */
  219.         initlines = LINES;
  220.         else if (ospeed >= B4800)    /* 16 lines at 4800 */
  221.         initlines = 16;
  222.         else            /* otherwise just header */
  223.         initlines = 8;
  224.     }
  225.     else {                /* not a crt */
  226.     LINES = 30000;            /* so don't page */
  227.     CL = "\n\n";            /* put a couple of lines between */
  228.     if (!initlines)            /* make initlines reasonable */
  229.         initlines = 8;
  230.     }
  231.     if (COLS <= 0)
  232.     COLS = 80;
  233.     noecho();                /* turn off echo */
  234.     crmode();                /* enter cbreak mode */
  235.  
  236. #ifdef PUSHBACK
  237.     mac_init(tcbuf);
  238. #endif
  239. }
  240.  
  241. #ifdef PUSHBACK
  242. void
  243. mac_init(tcbuf)
  244. char *tcbuf;
  245. {
  246.     char tmpbuf[1024];
  247.  
  248.     tmpfp = fopen(filexp(getval("RNMACRO",RNMACRO)),"r");
  249.     if (tmpfp != Nullfp) {
  250.     while (fgets(tcbuf,1024,tmpfp) != Nullch) {
  251.         mac_line(tcbuf,tmpbuf,(sizeof tmpbuf));
  252.     }
  253.     fclose(tmpfp);
  254.     }
  255. }
  256.  
  257. void
  258. mac_line(line,tmpbuf,tbsize)
  259. char *line;
  260. char *tmpbuf;
  261. int tbsize;
  262. {
  263.     register char *s, *m;
  264.     register KEYMAP *curmap;
  265.     register int ch;
  266.     register int garbage = 0;
  267.     static char override[] = "\nkeymap overrides string\n";
  268.  
  269.     if (topmap == Null(KEYMAP*))
  270.     topmap = newkeymap();
  271.     if (*line == '#' || *line == '\n')
  272.     return;
  273.     if (line[ch = strlen(line)-1] == '\n')
  274.     line[ch] = '\0';
  275.     m = dointerp(tmpbuf,tbsize,line," \t");
  276.     if (!*m)
  277.     return;
  278.     while (*m == ' ' || *m == '\t') m++;
  279.     for (s=tmpbuf,curmap=topmap; *s; s++) {
  280.     ch = *s & 0177;
  281.     if (s[1] == '+' && isdigit(s[2])) {
  282.         s += 2;
  283.         garbage = (*s & KM_GMASK) << KM_GSHIFT;
  284.     }
  285.     else
  286.         garbage = 0;
  287.     if (s[1]) {
  288.         if ((curmap->km_type[ch] & KM_TMASK) == KM_STRING) {
  289.         puts(override,stdout) FLUSH;
  290.         free(curmap->km_ptr[ch].km_str);
  291.         curmap->km_ptr[ch].km_str = Nullch;
  292.         }
  293.         curmap->km_type[ch] = KM_KEYMAP + garbage;
  294.         if (curmap->km_ptr[ch].km_km == Null(KEYMAP*))
  295.         curmap->km_ptr[ch].km_km = newkeymap();
  296.         curmap = curmap->km_ptr[ch].km_km;
  297.     }
  298.     else {
  299.         if ((curmap->km_type[ch] & KM_TMASK) == KM_KEYMAP)
  300.         puts(override,stdout) FLUSH;
  301.         else {
  302.         curmap->km_type[ch] = KM_STRING + garbage;
  303.         curmap->km_ptr[ch].km_str = savestr(m);
  304.         }
  305.     }
  306.     }
  307. }
  308.  
  309. KEYMAP*
  310. newkeymap()
  311. {
  312.     register int i;
  313.     register KEYMAP *map;
  314.  
  315. #ifndef lint
  316.     map = (KEYMAP*)safemalloc(sizeof(KEYMAP));
  317. #else
  318.     map = Null(KEYMAP*);
  319. #endif lint
  320.     for (i=127; i>=0; --i) {
  321.     map->km_ptr[i].km_km = Null(KEYMAP*);
  322.     map->km_type[i] = KM_NOTHIN;
  323.     }
  324.     return map;
  325. }
  326.  
  327. void
  328. show_macros()
  329. {
  330.     char prebuf[64];
  331.  
  332.     if (topmap != Null(KEYMAP*)) {
  333.     print_lines("Macros:\n",STANDOUT);
  334.     *prebuf = '\0';
  335.     show_keymap(topmap,prebuf);
  336.     }
  337. }
  338.  
  339. void
  340. show_keymap(curmap,prefix)
  341. register KEYMAP *curmap;
  342. char *prefix;
  343. {
  344.     register int i;
  345.     register char *next = prefix + strlen(prefix);
  346.     register int kt;
  347.  
  348.     for (i=0; i<128; i++) {
  349.     if (kt = curmap->km_type[i]) {
  350.         if (i < ' ')
  351.         sprintf(next,"^%c",i+64);
  352.         else if (i == ' ')
  353.         strcpy(next,"\\040");
  354.         else if (i == 127)
  355.         strcpy(next,"^?");
  356.         else
  357.         sprintf(next,"%c",i);
  358.         if ((kt >> KM_GSHIFT) & KM_GMASK) {
  359.         sprintf(cmd_buf,"+%d", (kt >> KM_GSHIFT) & KM_GMASK);
  360.         strcat(next,cmd_buf);
  361.         }
  362.         switch (kt & KM_TMASK) {
  363.         case KM_NOTHIN:
  364.         sprintf(cmd_buf,"%s    %c\n",prefix,i);
  365.         print_lines(cmd_buf,NOMARKING);
  366.         break;
  367.         case KM_KEYMAP:
  368.         show_keymap(curmap->km_ptr[(char)i].km_km, prefix);
  369.         break;
  370.         case KM_STRING:
  371.         sprintf(cmd_buf,"%s    %s\n",prefix,curmap->km_ptr[i].km_str);
  372.         print_lines(cmd_buf,NOMARKING);
  373.         break;
  374.         case KM_BOGUS:
  375.         sprintf(cmd_buf,"%s    BOGUS\n",prefix);
  376.         print_lines(cmd_buf,STANDOUT);
  377.         break;
  378.         }
  379.     }
  380.     }
  381. }
  382.  
  383. #endif
  384.  
  385. /* routine to pass to tputs */
  386.  
  387. char
  388. putchr(ch)
  389. register char ch;
  390. {
  391.     putchar(ch);
  392. #ifdef lint
  393.     ch = Null(char);
  394.     ch = ch;
  395. #endif
  396. }
  397.  
  398. /* input the 2nd and succeeding characters of a multi-character command */
  399. /* returns TRUE if command finished, FALSE if they rubbed out first character */
  400.  
  401. bool
  402. finish_command(donewline)
  403. int donewline;
  404. {
  405.     register char *s;
  406.     register bool quoteone = FALSE;
  407.  
  408.     s = buf;
  409.     if (s[1] != FINISHCMD)        /* someone faking up a command? */
  410.     return TRUE;
  411.     do {
  412.       top:
  413.     if (*s < ' ') {
  414.         putchar('^');
  415.         putchar(*s | 64);
  416.     }
  417.     else if (*s == '\177') {
  418.         putchar('^');
  419.         putchar('?');
  420.     }
  421.     else
  422.         putchar(*s);        /* echo previous character */
  423.     s++;
  424. re_read:
  425.     fflush(stdout);
  426.     getcmd(s);
  427.     if (quoteone) {
  428.         quoteone = FALSE;
  429.         continue;
  430.     }
  431.     if (errno || *s == Ctl('l')) {
  432.         *s = Ctl('r');        /* force rewrite on CONT */
  433.     }
  434.     if (*s == '\033') {        /* substitution desired? */
  435. #ifdef ESCSUBS
  436.         char tmpbuf[4], *cpybuf;
  437.  
  438.         tmpbuf[0] = '%';
  439.         read_tty(&tmpbuf[1],1);
  440. #ifdef RAWONLY
  441.         tmpbuf[1] &= 0177;
  442. #endif
  443.         tmpbuf[2] = '\0';
  444.         if (tmpbuf[1] == 'h') {
  445.         (void) help_subs();
  446.         *s = '\0';
  447.         reprint();
  448.         goto re_read;
  449.         }
  450.         else if (tmpbuf[1] == '\033') {
  451.         *s = '\0';
  452.         cpybuf = savestr(buf);
  453.         interp(buf, (sizeof buf), cpybuf);
  454.         free(cpybuf);
  455.         s = buf + strlen(buf);
  456.         reprint();
  457.         goto re_read;
  458.         }
  459.         else {
  460.         interp(s,(sizeof buf) - (s-buf),tmpbuf);
  461.         fputs(s,stdout);
  462.         s += strlen(s);
  463.         }
  464.         goto re_read;
  465. #else
  466.         notincl("^[");
  467.         *s = '\0';
  468.         reprint();
  469.         goto re_read;
  470. #endif
  471.     }
  472.     else if (*s == ERASECH) {    /* they want to rubout a char? */
  473.         rubout();
  474.         s--;            /* discount the char rubbed out */
  475.         if (*s < ' ' || *s == '\177')
  476.         rubout();
  477.         if (s == buf) {        /* entire string gone? */
  478.         fflush(stdout);        /* return to single char command mode */
  479.         return FALSE;
  480.         }
  481.         else
  482.         goto re_read;
  483.     }
  484.     else if (*s == KILLCH) {    /* wipe out the whole line? */
  485.         while (s-- != buf) {    /* emulate that many ERASEs */
  486.         rubout();
  487.         if (*s < ' ' || *s == '\177')
  488.             rubout();
  489.         }
  490.         fflush(stdout);
  491.         return FALSE;        /* return to single char mode */
  492.     }
  493. #ifdef WORDERASE
  494.     else if (*s == Ctl('w')) {    /* wipe out one word? */
  495.         *s-- = ' ';
  496.         while (!isspace(*s) || isspace(s[1])) {
  497.         rubout();
  498.         if (s-- == buf) {
  499.             fflush(stdout);
  500.             return FALSE;    /* return to single char mode */
  501.         }
  502.         if (*s < ' ' || *s == '\177')
  503.             rubout();
  504.         }
  505.         s++;
  506.         goto re_read;
  507.     }
  508. #endif
  509.     else if (*s == Ctl('r')) {
  510.         *s = '\0';
  511.         reprint();
  512.         goto re_read;
  513.     }
  514.     else if (*s == Ctl('v')) {
  515.         putchar('^');
  516.         backspace();
  517.         fflush(stdout);
  518.         getcmd(s);
  519.         goto top;
  520.     }
  521.     else if (*s == '\\') {
  522.         quoteone = TRUE;
  523.     }
  524.     } while (*s != '\n');        /* till a newline (not echoed) */
  525.     *s = '\0';                /* terminate the string nicely */
  526.     if (donewline)
  527.     putchar('\n') FLUSH;
  528.     return TRUE;            /* say we succeeded */
  529. }
  530.  
  531. /* discard any characters typed ahead */
  532.  
  533. void
  534. eat_typeahead()
  535. {
  536. #ifdef PUSHBACK
  537.     if (!typeahead && nextin==nextout)    /* cancel only keyboard stuff */
  538. #else
  539.     if (!typeahead)
  540. #endif
  541.     {
  542. #ifdef PENDING
  543.     while (input_pending())
  544.         read_tty(buf,sizeof(buf));
  545. #else /* this is probably v7 */
  546.     ioctl(_tty_ch,TIOCSETP,&_tty);
  547. #endif
  548.     }
  549. }
  550.  
  551. void
  552. settle_down()
  553. {
  554.     dingaling();
  555.     fflush(stdout);
  556.     sleep(1);
  557. #ifdef PUSHBACK
  558.     nextout = nextin;            /* empty circlebuf */
  559. #endif
  560.     eat_typeahead();
  561. }
  562.  
  563. #ifdef PUSHBACK
  564. /* read a character from the terminal, with multi-character pushback */
  565.  
  566. int
  567. read_tty(addr,size)
  568. char *addr;
  569. int size;
  570. {
  571.     if (nextout != nextin) {
  572.     *addr = circlebuf[nextout++];
  573.     nextout %= PUSHSIZE;
  574.     return 1;
  575.     }
  576.     else {
  577.     size = read(0,addr,size);
  578. #ifdef RAWONLY
  579.     *addr &= 0177;
  580. #endif
  581.     return size;
  582.     }
  583. }
  584.  
  585. #ifdef PENDING
  586. #ifndef FIONREAD
  587. int
  588. circfill()
  589. {
  590.     register int howmany = read(devtty,circlebuf+nextin,1);
  591.  
  592.     if (howmany) {
  593.     nextin += howmany;
  594.     nextin %= PUSHSIZE;
  595.     }
  596.     return howmany;
  597. }
  598. #endif PENDING
  599. #endif FIONREAD
  600.  
  601. void
  602. pushchar(c)
  603. char c;
  604. {
  605.     nextout--;
  606.     if (nextout < 0)
  607.     nextout = PUSHSIZE - 1;
  608.     if (nextout == nextin) {
  609.     fputs("\npushback buffer overflow\n",stdout) FLUSH;
  610.     sig_catcher(0);
  611.     }
  612.     circlebuf[nextout] = c;
  613. }
  614.  
  615. #else PUSHBACK
  616. #ifndef read_tty
  617. /* read a character from the terminal, with hacks for O_NDELAY reads */
  618.  
  619. int
  620. read_tty(addr,size)
  621. char *addr;
  622. int size;
  623. {
  624.     if (is_input) {
  625.     *addr = pending_ch;
  626.     is_input = FALSE;
  627.     return 1;
  628.     }
  629.     else {
  630.     size = read(0,addr,size)
  631. #ifdef RAWONLY
  632.     *addr &= 0177;
  633. #endif
  634.     return size;
  635.     }
  636. }
  637. #endif read_tty
  638. #endif PUSHBACK
  639.  
  640. /* print an underlined string, one way or another */
  641.  
  642. void
  643. underprint(s)
  644. register char *s;
  645. {
  646.     assert(UC);
  647.     if (*UC) {        /* char by char underline? */
  648.     while (*s) {
  649.         if (*s < ' ') {
  650.         putchar('^');
  651.         backspace();/* back up over it */
  652.         underchar();/* and do the underline */
  653.         putchar(*s+64);
  654.         backspace();/* back up over it */
  655.         underchar();/* and do the underline */
  656.         }
  657.         else {
  658.         putchar(*s);
  659.         backspace();/* back up over it */
  660.         underchar();/* and do the underline */
  661.         }
  662.         s++;
  663.     }
  664.     }
  665.     else {        /* start and stop underline */
  666.     underline();    /* start underlining */
  667.     while (*s) {
  668.         if (*s < ' ') {
  669.         putchar('^');
  670.         putchar(*s+64);
  671.         }
  672.         else
  673.         putchar(*s);
  674.         s++;
  675.     }
  676.     un_underline();    /* stop underlining */
  677.     }
  678. }
  679.  
  680. /* keep screen from flashing strangely on magic cookie terminals */
  681.  
  682. #ifdef NOFIREWORKS
  683. void
  684. no_sofire()
  685. {
  686.     if (*UP && *SE) {        /* should we disable fireworks? */
  687.     putchar('\n');
  688.     un_standout();
  689.     up_line();
  690.     carriage_return();
  691.     }
  692. }
  693.  
  694. void
  695. no_ulfire()
  696. {
  697.     if (*UP && *US) {        /* should we disable fireworks? */
  698.     putchar('\n');
  699.     un_underline();
  700.     up_line();
  701.     carriage_return();
  702.     }
  703. }
  704. #endif
  705.  
  706. /* get a character into a buffer */
  707.  
  708. void
  709. getcmd(whatbuf)
  710. register char *whatbuf;
  711. {
  712. #ifdef PUSHBACK
  713.     register KEYMAP *curmap;
  714.     register int i;
  715.     bool no_macros; 
  716.     int times = 0;            /* loop detector */
  717.     char scrchar;
  718.  
  719. tryagain:
  720.     curmap = topmap;
  721.     no_macros = (whatbuf != buf && nextin == nextout); 
  722. #endif
  723.     for (;;) {
  724.     int_count = 0;
  725.     errno = 0;
  726.     if (read_tty(whatbuf,1) < 0 && !errno)
  727.         errno = EINTR;
  728.     if (errno && errno != EINTR) {
  729.         perror(readerr);
  730.         sig_catcher(0);
  731.     }
  732. #ifdef PUSHBACK
  733.     if (*whatbuf & 0200 || no_macros) {
  734.         *whatbuf &= 0177;
  735.         goto got_canonical;
  736.     }
  737.     if (curmap == Null(KEYMAP*))
  738.         goto got_canonical;
  739.     for (i = (curmap->km_type[*whatbuf] >> KM_GSHIFT) & KM_GMASK; i; --i){
  740.         read_tty(&scrchar,1);
  741.     }
  742.     switch (curmap->km_type[*whatbuf] & KM_TMASK) {
  743.     case KM_NOTHIN:            /* no entry? */
  744.         if (curmap == topmap)    /* unmapped canonical */
  745.         goto got_canonical;
  746.         settle_down();
  747.         goto tryagain;
  748.     case KM_KEYMAP:            /* another keymap? */
  749.         curmap = curmap->km_ptr[*whatbuf].km_km;
  750.         assert(curmap != Null(KEYMAP*));
  751.         break;
  752.     case KM_STRING:            /* a string? */
  753.         pushstring(curmap->km_ptr[*whatbuf].km_str);
  754.         if (++times > 20) {        /* loop? */
  755.         fputs("\nmacro loop?\n",stdout);
  756.         settle_down();
  757.         }
  758.         no_macros = FALSE;
  759.         goto tryagain;
  760.     }
  761. #else
  762. #ifdef RAWONLY
  763.     *whatbuf &= 0177;
  764. #endif
  765.     break;
  766. #endif
  767.     }
  768.  
  769. got_canonical:
  770.     if (whatbuf == buf)
  771.     whatbuf[1] = FINISHCMD;        /* tell finish_command to work */
  772. }
  773.  
  774. #ifdef PUSHBACK
  775. void
  776. pushstring(str)
  777. char *str;
  778. {
  779.     register int i;
  780.     char tmpbuf[PUSHSIZE];
  781.     register char *s = tmpbuf;
  782.  
  783.     assert(str != Nullch);
  784.     interp(s,PUSHSIZE,str);
  785.     for (i = strlen(s)-1; i >= 0; --i) {
  786.     s[i] ^= 0200; 
  787.     pushchar(s[i]);
  788.     }
  789. }
  790. #endif
  791.  
  792. int
  793. get_anything()
  794. {
  795.     char tmpbuf[2];
  796.  
  797. reask_anything:
  798.     unflush_output();            /* disable any ^O in effect */
  799.     standout();
  800. #ifdef VERBOSE
  801.     IF(verbose)
  802.     fputs("[Type space to continue] ",stdout);
  803.     ELSE
  804. #endif
  805. #ifdef TERSE
  806.     fputs("[MORE] ",stdout);
  807. #endif
  808.     un_standout();
  809.     fflush(stdout);
  810.     eat_typeahead();
  811.     if (int_count) {
  812.     return -1;
  813.     }
  814.     collect_subjects();            /* loads subject cache until */
  815.                     /* input is pending */
  816.     getcmd(tmpbuf);
  817.     if (errno || *tmpbuf == '\f') {
  818.     putchar('\n') FLUSH;        /* if return from stop signal */
  819.     goto reask_anything;        /* give them a prompt again */
  820.     }
  821.     if (*tmpbuf == 'h') {
  822. #ifdef VERBOSE
  823.     IF(verbose)
  824.         fputs("\nType q to quit or space to continue.\n",stdout) FLUSH;
  825.     ELSE
  826. #endif
  827. #ifdef TERSE
  828.         fputs("\nq to quit, space to continue.\n",stdout) FLUSH;
  829. #endif
  830.     goto reask_anything;
  831.     }
  832.     else if (*tmpbuf != ' ' && *tmpbuf != '\n') {
  833.     carriage_return();
  834.     erase_eol();    /* erase the prompt */
  835.     return *tmpbuf == 'q' ? -1 : *tmpbuf;
  836.     }
  837.     if (*tmpbuf == '\n') {
  838.     page_line = LINES - 1;
  839.     carriage_return();
  840.     erase_eol();
  841.     }
  842.     else {
  843.     page_line = 1;
  844.     if (erase_screen)        /* -e? */
  845.         clear();            /* clear screen */
  846.     else {
  847.         carriage_return();
  848.         erase_eol();        /* erase the prompt */
  849.     }
  850.     }
  851.     return 0;
  852. }
  853.  
  854. void
  855. in_char(prompt)
  856. char *prompt;
  857. {
  858.     char oldmode = mode;
  859.  
  860. reask_in_char:
  861.     unflush_output();            /* disable any ^O in effect */
  862.     fputs(prompt,stdout);
  863.     fflush(stdout);
  864.     eat_typeahead();
  865.     mode = 'm';
  866.     getcmd(buf);
  867.     if (errno || *buf == '\f') {
  868.     putchar('\n') FLUSH;        /* if return from stop signal */
  869.     goto reask_in_char;        /* give them a prompt again */
  870.     }
  871.     mode = oldmode;
  872. }
  873.  
  874. int
  875. print_lines(what_to_print,hilite)
  876. char *what_to_print;
  877. int hilite;
  878. {
  879.     register char *s;
  880.     register int i;
  881.  
  882.     if (page_line < 0)            /* they do not want to see this? */
  883.     return -1;
  884.     for (s=what_to_print; *s; ) {
  885.     if (page_line >= LINES || int_count) {
  886.         if (i = -1, int_count || (i = get_anything())) {
  887.         page_line = -1;        /* disable further print_lines */
  888.         return i;
  889.         }
  890.     }
  891.     page_line++;
  892.     if (hilite == STANDOUT) {
  893. #ifdef NOFIREWORKS
  894.         if (erase_screen)
  895.         no_sofire();
  896. #endif
  897.         standout();
  898.     }
  899.     else if (hilite == UNDERLINE) {
  900. #ifdef NOFIREWORKS
  901.         if (erase_screen)
  902.         no_ulfire();
  903. #endif
  904.         underline();
  905.     }
  906.     for (i=0; i<COLS; i++) {
  907.         if (!*s)
  908.         break;
  909.         if (*s >= ' ')
  910.         putchar(*s);
  911.         else if (*s == '\t') {
  912.         putchar(*s);
  913.         i = ((i+8) & ~7) - 1; 
  914.         }
  915.         else if (*s == '\n') {
  916.         i = 32000;
  917.         }
  918.         else {
  919.         i++;
  920.         putchar('^');
  921.         putchar(*s + 64);
  922.         }
  923.         s++;
  924.     }
  925.     if (i) {
  926.         if (hilite == STANDOUT)
  927.         un_standout();
  928.         else if (hilite == UNDERLINE)
  929.         un_underline();
  930.         if (AM && i == COLS)
  931.         fflush(stdout);
  932.         else
  933.         putchar('\n') FLUSH;
  934.     }
  935.     }
  936.     return 0;
  937. }
  938.  
  939. void
  940. page_init()
  941. {
  942.     page_line = 1;
  943.     if (erase_screen)
  944.     clear();
  945.     else
  946.     putchar('\n') FLUSH;
  947. }
  948.  
  949. void
  950. pad(num)
  951. int num;
  952. {
  953.     register int i;
  954.  
  955.     for (i = num; i; --i)
  956.     putchar(PC);
  957.     fflush(stdout);
  958. }
  959.  
  960. /* echo the command just typed */
  961.  
  962. #ifdef VERIFY
  963. void
  964. printcmd()
  965. {
  966.     if (verify && buf[1] == FINISHCMD) {
  967.     if (*buf < ' ') {
  968.         putchar('^');
  969.         putchar(*buf | 64);
  970.         backspace();
  971.         backspace();
  972.     }
  973.     else {
  974.         putchar(*buf);
  975.         backspace();
  976.     }
  977.     fflush(stdout);
  978.     }
  979. }
  980. #endif
  981.  
  982. void
  983. rubout()
  984. {
  985.     backspace();            /* do the old backspace, */
  986.     putchar(' ');            /*   space, */
  987.     backspace();            /*     backspace trick */
  988. }
  989.  
  990. void
  991. reprint()
  992. {
  993.     register char *s;
  994.  
  995.     fputs("^R\n",stdout) FLUSH;
  996.     for (s = buf; *s; s++) {
  997.     if (*s < ' ') {
  998.         putchar('^');
  999.         putchar(*s | 64);
  1000.     }
  1001.     else
  1002.         putchar(*s);
  1003.     }
  1004. }
  1005.  
  1006. #ifdef CLEAREOL
  1007. /* start of additions by Paul Placeway (PWP) */
  1008.  
  1009. void
  1010. home_cursor()
  1011. {
  1012.     char *tgoto();
  1013.  
  1014.     if (!*HO) {            /* no home sequence? */
  1015.     if (!*CM) {        /* no cursor motion either? */
  1016.         fputs ("\n\n\n", stdout);
  1017.         return;        /* forget it. */
  1018.     }
  1019.     tputs (tgoto (CM, 0, 0), 1, putchr);    /* go to home via CM */
  1020.     return;
  1021.     }
  1022.     else {            /* we have home sequence */
  1023.     tputs (HO, 1, putchr);    /* home via HO */
  1024.     }
  1025. }
  1026. #endif CLEAREOL
  1027. !STUFFY!FUNK!
  1028. echo Extracting Pnews.SH
  1029. cat >Pnews.SH <<'!STUFFY!FUNK!'
  1030. case $CONFIG in
  1031.     '') . config.sh ;;
  1032. esac
  1033. echo "Extracting Pnews (with variable substitutions)"
  1034. $spitshell >Pnews <<!GROK!THIS!
  1035. $startsh
  1036. # $Header: Pnews.SH,v 4.3 85/05/01 12:20:33 lwall Exp $
  1037. #
  1038. # $Log:    Pnews.SH,v $
  1039. # Revision 4.3  85/05/01  12:20:33  lwall
  1040. # Baseline for release with 4.3bsd.
  1041. #
  1042. # syntax: Pnews -h headerfile            or
  1043. #      Pnews -h headerfile oldarticle    or
  1044. #         Pnews newsgroup title            or just
  1045. #         Pnews
  1046.  
  1047. export PATH || (echo "OOPS, this isn't sh.  Desperation time.  I will feed myself to sh."; sh \$0; kill \$\$)
  1048.  
  1049. # System dependencies
  1050.  
  1051. mailer="${mailer-/bin/mail}"
  1052. # if you change this to something that does signatures, take out signature code
  1053.  
  1054. case $portable in
  1055. define)
  1056. # your site name
  1057. sitename=\`$hostcmd\`
  1058. # where recordings, distributions and moderators are kept
  1059. lib=\`$filexp $lib\`
  1060. # where important rn things are kept
  1061. rnlib=\`$filexp $rnlib\`
  1062. ;;
  1063. undef)
  1064. # your site name
  1065. sitename="$sitename"
  1066. # where recordings, distributions and moderators are kept
  1067. lib="$lib"
  1068. # where important rn things are kept
  1069. rnlib="$rnlib"
  1070. ;;
  1071. esac
  1072.  
  1073. # your organization name
  1074. orgname="$orgname"
  1075. # what pager you use--if you have kernal paging use cat
  1076. pager="\${PAGER-$pager}"
  1077. # how you derive full names, bsd, usg, or other
  1078. nametype="$nametype"
  1079. # default editor
  1080. defeditor="$defeditor"
  1081. # how not to echo with newline
  1082. n="$n"
  1083. c="$c"
  1084.  
  1085. # You should also look at the distribution warnings below marked !DIST!
  1086. # to make sure any distribution regions you are a member of are included.
  1087. # The following are some prototypical distribution groups.  If you do not
  1088. # use them all set the unused ones to a non-null string such as 'none'.
  1089. loc="$locpref"
  1090. org="$orgpref"
  1091. city="$citypref"
  1092. state="$statepref"
  1093. cntry="$cntrypref"
  1094. cont="$contpref"
  1095.  
  1096. test=${test-test}
  1097. sed=${sed-sed}
  1098. echo=${echo-echo}
  1099. cat=${cat-cat}
  1100. egrep=${egrep-egrep}
  1101. grep=${grep-grep}
  1102. rm=${rm-rm}
  1103. tr=${tr-tr}
  1104. inews=${inews-inews}
  1105.  
  1106. !GROK!THIS!
  1107. $spitshell >>Pnews <<'!NO!SUBS!'
  1108. if $test -f ${DOTDIR-${HOME-$LOGDIR}}/.pnewsexpert; then
  1109.     expertise=expert
  1110. else
  1111.     $cat <<'EOM'
  1112. I see you've never used this version of Pnews before.  I will give you extra
  1113. help this first time through, but then you must remember what you learned.
  1114. If you don't understand any question, type h and a CR (carriage return) for
  1115. help.
  1116.  
  1117. If you've never posted an article to the net before, it is HIGHLY recommended
  1118. that you read the netiquette document found in net.announce.newusers so
  1119. that you'll know to avoid the commonest blunders.  To do that, interrupt
  1120. Pnews, and get to the top-level prompt of rn.  Say "g net.announce.newusers"
  1121. and you are on your way.
  1122.  
  1123. EOM
  1124.     expertise=beginner
  1125. fi
  1126.  
  1127. case $cntry in
  1128.   can) stpr=Province ;;
  1129.   *)   stpr=State ;;
  1130. esac
  1131.  
  1132. tmpart=/tmp/article$$
  1133.  
  1134. headerfile=""
  1135. case $# in
  1136. 0) ;;
  1137. *)  case $1 in
  1138.     -h)
  1139.     headerfile="$2"
  1140.     shift
  1141.     shift
  1142.     case $# in
  1143.     0)
  1144.         oldart=""
  1145.         ;;
  1146.     *)
  1147.         oldart="$1"
  1148.         shift
  1149.         ;;
  1150.     esac
  1151.     ;;
  1152.     esac
  1153.     ;;
  1154. esac
  1155.  
  1156. case $headerfile in
  1157. '')
  1158.     . $rnlib/Pnews.header
  1159.     ;;
  1160. *)
  1161.     $cat < $headerfile  > $tmpart
  1162.     ;;
  1163. esac
  1164.     rescue="sleep 1; $cat $tmpart >>${HOME-$LOGDIR}/dead.article ; $echo saved in ${HOME-$LOGDIR}/dead.article ; $rm -f $tmpart; exit"
  1165.     trap "$rescue" 1
  1166.     trap "$rescue" 2
  1167.  
  1168. $echo ""
  1169. set X `$sed < $tmpart -n -e '/^Distribution: /{' -e p -e q -e '}' -e '/^$/q'`
  1170. shift
  1171. case $# in
  1172. 0|1)
  1173.     set X `$sed < $tmpart -n -e '/^Newsgroups: /{' -e p -e q -e '}'`
  1174.     shift
  1175.     case $# in
  1176.     0|1)
  1177.     set "x net.whatever"
  1178.     ;;
  1179.     esac
  1180.     ;;
  1181. *)
  1182.     set $1 $2.whatever
  1183.     ;;
  1184. esac
  1185. shift
  1186.  
  1187. #: play recorded message
  1188. #if $test -s ${lib}/recording ; then
  1189. #     ng=`$echo $1 | $sed "s/,.*//"`
  1190. #    _rec1=${lib}/`$sed -n "/^$ng/s/^.*    //p" ${lib}/recording`
  1191. #    _tmp=`$echo $ng |$sed "s/\..*//"`
  1192. #    _rec2=${lib}/`$cat -s ${lib}/recording|$grep ${_tmp}.all|$sed "s/^.*    //"`
  1193. #    if $test -f ${_rec1} ; then
  1194. #    $cat -s ${_rec1}
  1195. #    fi
  1196. #    if $test -f ${_rec2} ; then
  1197. #    $cat -s ${_rec2}
  1198. #    fi
  1199. #fi
  1200.  
  1201. # tell them what we think they are doing... !DIST!
  1202. case $1 in
  1203. net.*)
  1204.     $echo 'This program posts news to many hundreds of machines throughout the world.'
  1205.     ;;
  1206. $cont.*)
  1207.     $echo 'This program posts news to many machines throughout the continent.'
  1208.     ;;
  1209. $cntry.*)
  1210.     $echo 'This program posts news to many machines throughout the country.'
  1211.     ;;
  1212. $state.*)
  1213.     $echo 'This program posts news to many machines throughout the state.'
  1214.     ;;
  1215. $city.*)
  1216.     $echo 'This program posts news to many machines throughout the city.'
  1217.     ;;
  1218. $org.*)
  1219.     $echo 'This program posts news to machines throughout the organization.'
  1220.     ;;
  1221. $loc.*)
  1222.     $echo 'This program posts news to machines throughout the local organization.'
  1223.     ;;
  1224. *.*)
  1225.     $echo 'This program may post news to many machines.'
  1226.     ;;
  1227. *)
  1228.     $echo 'This program posts news to everyone on the machine.'
  1229.     ;;
  1230. esac
  1231. ans=""
  1232. while $test "$ans" = "" ; do
  1233.     $echo $n "Are you absolutely sure that you want to do this? [ny] $c"
  1234.     read ans
  1235.     case $ans in
  1236.     y*) ;;
  1237.     f*) suppressmess=y ;;
  1238.     h*) $cat <<'EOH'
  1239.  
  1240. Type n or CR to exit, y to post.
  1241.  
  1242. EOH
  1243.     ans="" ;;
  1244.     *) exit ;;
  1245.     esac
  1246. done
  1247.  
  1248. file=h
  1249. while $test "$file" = h ; do
  1250.     $echo ""
  1251.     $echo $n "Prepared file to include [none]: $c"
  1252.     read file
  1253.     case $file in
  1254.     h)
  1255.     $cat <<'EOH'
  1256.  
  1257. If you have already produced the body of your article, type the filename
  1258. for it here.  If you just want to proceed directly to the editor, type a
  1259. RETURN.  In any event, you will be allowed to edit as many times as you
  1260. want before you send off the article.
  1261. EOH
  1262.     ;;
  1263.     '')
  1264.     $echo "" >> $tmpart
  1265.     state=edit
  1266.     ;;
  1267.     *)
  1268.     $cat $file >>$tmpart
  1269.     state=ask
  1270.     ;;
  1271.     esac
  1272. done
  1273.  
  1274. $echo ""
  1275.  
  1276. while true ; do
  1277.     case $state in
  1278.     edit)
  1279.     case $expertise in
  1280.     beginner)
  1281.         $cat </dev/null >${DOTDIR-${HOME-$LOGDIR}}/.pnewsexpert
  1282.         $cat <<'EOMessage'
  1283. A temporary file has been created for you to edit.  Be sure to leave at
  1284. least one blank line between the header and the body of your message.
  1285. (And until a certain bug is fixed all over the net, don't start the body of
  1286. your message with any indentation, or it may get eaten.)
  1287.  
  1288. Within the header may be fields that you don't understand.  If you don't
  1289. understand a field (or even if you do), you can simply leave it blank, and
  1290. it will go away when the article is posted.
  1291.  
  1292. Type return to get the default editor, or type the name of your favorite
  1293. editor.
  1294.  
  1295. EOMessage
  1296.         ;;
  1297.     esac
  1298.     case "${VISUAL-${EDITOR-}}" in
  1299.     '')
  1300.         tmp=h
  1301.         ;;
  1302.     *)
  1303.         tmp=''
  1304.         ;;
  1305.     esac
  1306.     while $test "$tmp" = h ; do
  1307.         $echo $n "Editor [${VISUAL-${EDITOR-$defeditor}}]: $c"
  1308.         read tmp
  1309.         case $tmp in
  1310.         h)
  1311.         $cat <<'EOH'
  1312.  
  1313. Type a return to get the default editor, or type the name of the editor you
  1314. prefer.  The default editor depends on the VISUAL and EDITOR environment
  1315. variables.
  1316.  
  1317. EOH
  1318.         ;;
  1319.         '')
  1320.         ;;
  1321.         *)
  1322.         VISUAL=$tmp
  1323.         export VISUAL
  1324.         ;;
  1325.         esac
  1326.     done
  1327.     trap : 2
  1328.     ${VISUAL-${EDITOR-$defeditor}} $tmpart $oldart
  1329.     trap "$rescue" 2
  1330.     state=ask
  1331.     ;;
  1332.     
  1333.     ask)
  1334.     $echo ""
  1335.     $echo $n "Send, abort, edit, or list? $c"
  1336.     read ans
  1337.     
  1338.     case $ans in
  1339.     a*)
  1340.         state=rescue
  1341.         ;;
  1342.     e*)
  1343.         state=edit
  1344.         ;;
  1345.     l*)
  1346.         $pager $tmpart
  1347.         state=ask
  1348.         ;;
  1349.     s*)
  1350.         state=send
  1351.         ;;
  1352.     h*)
  1353.         $cat <<'EOH'
  1354.  
  1355. Type s to send the article, a to abort and append the article to dead.article,
  1356. e to edit the article again, or l to list the article.
  1357. EOH
  1358.     esac
  1359.     ;;
  1360.     
  1361.     send)
  1362.     set X `$sed < $tmpart -n -e '/^Newsgroups: /{' -e p -e q -e '}'`
  1363.     shift
  1364.     case $# in
  1365.     2)
  1366.         state=cleanup
  1367.         if $test -f $lib/moderators; then
  1368.         tryinews=no
  1369.         shift
  1370.         case "$1" in
  1371.         *,*) set `$echo $1 | tr ',' ' '`;;
  1372.         esac
  1373.         for newsgroup in $*; do
  1374. # the following screwy sed should prevent Eunice from hanging on no match
  1375.             moderator=`$sed <$lib/moderators \\
  1376.             -e "/^$newsgroup[     ]/!s/.*//" \\
  1377.             -e "s/^$newsgroup[     ]//"`
  1378.             case ${moderator}X in
  1379.             X)  tryinews=yes
  1380.             ;;
  1381.             *)
  1382.             $echo Mailing to moderator $moderator
  1383.             case "$mailer" in
  1384.             *recmail)
  1385.                 $echo To: $moderator | $cat - $tmpart | $mailer
  1386.                 ;;
  1387.             *)
  1388.                 $mailer $moderator < $tmpart
  1389.                 ;;
  1390.             esac
  1391.             case $? in
  1392.             0) ;;
  1393.             *)
  1394.                 $echo Unable to mail to moderator $moderator
  1395.                 state=rescue
  1396.                 ;;
  1397.             esac
  1398.             ;;
  1399.             esac
  1400.         done
  1401.         else
  1402.         tryinews=yes
  1403.         fi
  1404.         case "$tryinews" in
  1405.         yes)
  1406.         if $inews -h < $tmpart ; then
  1407.             : null
  1408.         else
  1409.             state=rescue
  1410.         fi
  1411.         ;;
  1412.         esac
  1413.         ;;
  1414.     *)
  1415.         $echo ""
  1416.         $echo "Malformed Newsgroups line."
  1417.         $echo ""
  1418.         sleep 1
  1419.         state=edit
  1420.         ;;
  1421.     esac
  1422.     ;;
  1423.     rescue)
  1424.     $cat $tmpart >> ${HOME-$LOGDIR}/dead.article
  1425.     $echo "Article saved to ${HOME-$LOGDIR}/dead.article"
  1426.     state=cleanup
  1427.     ;;
  1428.     cleanup)
  1429.     $rm -f $tmpart
  1430.     exit
  1431.     ;;
  1432.     esac
  1433. done
  1434. !NO!SUBS!
  1435. $eunicefix Pnews
  1436. chmod 755 Pnews
  1437. $spitshell >Pnews.header <<'!NO!SUBS!'
  1438. case $# in
  1439. 0)
  1440.     ng=h
  1441.     while $test "$ng" = h ; do
  1442.     $echo ""
  1443.     $echo $n "Newsgroup(s): $c"
  1444.     read ng
  1445.     case $ng in
  1446.     h)
  1447.         $cat <<'EOH'
  1448.  
  1449. Type the name of one or more newsgroups to which you wish to post an article.
  1450. If you want to post to multiple newsgroups, it is better to do them all at
  1451. once than to post to each newsgroup individually, which defeats the news
  1452. reading programs' strategies of eliminating duplicates.
  1453.  
  1454. Separate multiple newsgroup names with commas.
  1455. EOH
  1456.         ;;
  1457.     esac
  1458.     done
  1459.     ;;
  1460. *)
  1461.     ng=$1
  1462.     shift
  1463.     ;;
  1464. esac
  1465. case $ng in
  1466. *\ *)
  1467.     ng=`$echo "$ng" | $sed 's/[, ] */,/g'`
  1468.     ;;
  1469. esac
  1470. case $ng in
  1471. net.*|fa.*|mod.*)
  1472.     defdist=net
  1473.     dist=h
  1474.     ;;
  1475. *.*)
  1476.     defdist=`expr "X$ng" : 'X\([a-z0-9]*\)'`
  1477.     dist=h
  1478.     ;;
  1479. *)
  1480.     defdist=''
  1481.     dist=''
  1482.     ;;
  1483. esac
  1484.  
  1485. while $test "$dist" = h ; do
  1486.     if $test -f $lib/distributions; then
  1487.     $echo " "
  1488.     $echo "Your local distribution prefixes are:"
  1489.     $cat $lib/distributions
  1490.     else
  1491.     $egrep -v '[     ]none$' <<EOM
  1492.  
  1493. Your local distribution prefixes are:
  1494.     Local organization:    $loc
  1495.     Organization:        $org
  1496.     City:            $city
  1497.     $stpr:          $state
  1498.     Country:        $cntry
  1499.     Continent:        $cont
  1500.     Everywhere:        net,mod,fa
  1501.  
  1502. EOM
  1503.     fi
  1504.     $echo $n "Distribution ($defdist): $c"
  1505.     read dist
  1506.     case $dist in
  1507.     '') dist=$defdist ;;
  1508.     esac
  1509.     case $dist in
  1510.     h)
  1511.     $cat <<'EOH'
  1512.  
  1513. The Distribution line may be used to limit the distribution of an article
  1514. to some subset of the systems that would receive the article based only on
  1515. the Newsgroups line.  For example, if you want to sell your car in net.auto,
  1516. and you live in New Jersey, you might want to put "nj" on the Distribution
  1517. line to avoid advertising in California, which has enough problems of its own.
  1518. The actual area designators to use depend on where you are, of course.
  1519. EOH
  1520.     ;;
  1521.     ''|$loc*|$org*|$city*|$state*|$cntry*|$cont*|fa*|mod*)
  1522.     ;;
  1523.     net*|world*)
  1524.     dist=''
  1525.     ;;
  1526.     *)  
  1527.     if $test -f $lib/distributions && \
  1528.       $egrep "^$dist[     ]" $lib/distributions >$tmpart && \
  1529.       $test -s $tmpart; then
  1530.         : null
  1531.     else
  1532.         $echo "Unrecognized distribution prefix--type h for help."
  1533.         dist=h
  1534.     fi
  1535.     ;;
  1536.     esac
  1537. done
  1538.  
  1539. case $ng in
  1540. *net.general*)
  1541.     follow=`echo "$ng" | sed 's/net\.general/net.followup/g'`
  1542.     ;;
  1543. *)
  1544.     follow=""
  1545.     ;;
  1546. esac
  1547.  
  1548. case $# in
  1549. 0)
  1550.     title=h
  1551.     while $test "$title" = h ; do
  1552.     $echo ""
  1553.     $echo $n "Title/Subject: $c"
  1554.     read title
  1555.     case $title in
  1556.     h)
  1557.         $cat <<'EOH'
  1558.  
  1559. Type the title for your article.  Please make it as informative as possible
  1560. (within reason) so that people who aren't interested won't have to read the
  1561. article to find out they aren't interested.  This includes marking movie
  1562. spoilers as (spoiler), and rotated jokes as (rot 13).
  1563. EOH
  1564.     ;;
  1565.     esac
  1566.     done
  1567.     ;;
  1568. *)
  1569.     title="$*"
  1570.     ;;
  1571. esac
  1572.  
  1573. # now build a file with a header for them to edit
  1574.  
  1575. set X ${USER-${LOGNAME-`who am i`}}
  1576. shift
  1577. logname=$1
  1578. case $logname in
  1579. *!*) logname=`expr "$logname" : '!\(.*\)$'` ;;
  1580. esac
  1581. case ${NAME-$nametype} in
  1582. bsd)
  1583.     fullname=`$sed </etc/passwd -e "/^$logname:/{s/^[^:]*:[^:]*:[^:]*:[^:]*:\([^,:;]*\).*"'$'"/\1/" -e "q" -e "}" -e "d"`
  1584.     case $fullname in
  1585.     *'&'*) : GACK
  1586.     lname=`$echo $logname | $tr 'a-z' 'A-Z'`
  1587.     lname=`$echo $lname $logname | $sed 's/^\(.\)[^ ]* ./\1/'`
  1588.     fullname=`$echo "$fullname" | $sed "s/&/${lname}/"`
  1589.     ;;
  1590.     esac
  1591.     ;;
  1592. usg)
  1593.     fullname=`$sed </etc/passwd -e "/^$logname:/{s/^[^:]*:[^:]*:[^:]*:[^:]*:\([^(:]*\).*"'$'"/\1/" -e "s/^.*-//" -e "q" -e "}" -e "d"`
  1594.     ;;
  1595. *)
  1596.     fullname=${NAME-`$cat ${HOME-$LOGDIR}/.fullname`}
  1597.     ;;
  1598. esac
  1599.  
  1600. orgname=${ORGANIZATION-$orgname}
  1601. case $orgname in
  1602. /*) orgname=`$cat $orgname` ;;
  1603. esac
  1604.  
  1605. $cat > $tmpart <<EOHeader
  1606. Newsgroups: $ng
  1607. Subject: $title
  1608. Expires: 
  1609. References: 
  1610. Sender: 
  1611. Reply-To: $logname@$sitename.UUCP ($fullname)
  1612. Followup-To: $follow
  1613. Distribution: $dist
  1614. Organization: $orgname
  1615. Keywords: 
  1616.  
  1617. EOHeader
  1618.  
  1619. !NO!SUBS!
  1620. $eunicefix Pnews.header
  1621. !STUFFY!FUNK!
  1622. echo Extracting rn.c
  1623. cat >rn.c <<'!STUFFY!FUNK!'
  1624. /*  rn -- new readnews program
  1625.  *
  1626.  *  From: lwall@sdcrdcf.UUCP (Larry Wall)
  1627.  *  Organization: System Development Corporation, Santa Monica
  1628.  *
  1629.  *  begun:   01/14/83
  1630.  *    1.0: 04/08/83
  1631.  *      2.0: 09/01/83
  1632.  */
  1633.  
  1634. static char rnid[] = "@(#)$Header: rn.c,v 4.3 85/05/01 11:47:56 lwall Exp $";
  1635.  
  1636. /* $Log:    rn.c,v $
  1637.  * Revision 4.3  85/05/01  11:47:56  lwall
  1638.  * Baseline for release with 4.3bsd.
  1639.  * 
  1640.  */
  1641.  
  1642. #include "INTERN.h"
  1643. #include "common.h"
  1644. #include "rn.h"
  1645. #include "EXTERN.h"
  1646. #include "rcstuff.h"
  1647. #include "term.h"
  1648. #include "final.h"
  1649. #include "ngdata.h"
  1650. #include "util.h"
  1651. #include "only.h"
  1652. #include "ngsrch.h"
  1653. #include "help.h"
  1654. #include "last.h"
  1655. #include "init.h"
  1656. #include "intrp.h"
  1657. #include "rcln.h"
  1658. #include "sw.h"
  1659. #include "addng.h"
  1660. #include "ng.h"
  1661. #include "INTERN.h"
  1662.  
  1663. void
  1664. rn_init()
  1665. {
  1666.     ;
  1667. }
  1668.  
  1669. void
  1670. main(argc,argv)
  1671. int argc;
  1672. char *argv[];
  1673. {
  1674.     bool foundany = initialize(argc,argv);
  1675.     register char *s;
  1676.     bool oh_for_the_good_old_days = FALSE;
  1677.     
  1678.     if (maxngtodo)
  1679.     starthere = 0;
  1680.     else if (!foundany) {        /* nothing to do? */
  1681. #ifdef VERBOSE
  1682.     if (verbose)
  1683.         fputs("\
  1684. No unread news in subscribed-to newsgroups.  To subscribe to a new\n\
  1685. newsgroup use the g<newsgroup> command.\n\
  1686. ",stdout) FLUSH;
  1687. #endif
  1688.     starthere = nextrcline;
  1689.     }
  1690.  
  1691.     /* loop through all unread news */
  1692.  
  1693.     {
  1694.     char promptbuf[80];
  1695.     bool special = FALSE;        /* temporarily allow newsgroup */
  1696.                     /*   with no unread news? */
  1697.     bool retry;            /* cycle back to top of list? */
  1698.     NG_NUM recent_ng = 0;
  1699.     
  1700.     current_ng = 0;
  1701.     do {
  1702.         retry = FALSE;
  1703.         if (findlast) {
  1704.         findlast = FALSE;
  1705.         starthere = 0;
  1706.         if (*lastngname) {
  1707.             if ((ng = find_ng(lastngname)) == nextrcline)
  1708.             ng = 0;
  1709.             else {
  1710.             set_ngname(lastngname);
  1711.                 set_toread(ng);
  1712.             if (toread[ng] <= TR_NONE)
  1713.                 ng = 0;
  1714.             }
  1715.         }
  1716.         }
  1717.         else {
  1718.         ng = starthere;
  1719.         starthere = 0;
  1720.         }
  1721.         while (ng <= nextrcline) {    /* for each newsgroup */
  1722.         mode = 'n';
  1723.         if (ng >= nextrcline) {    /* after the last newsgroup? */
  1724.             ng = nextrcline;    /* force it to 1 after */
  1725. #ifdef ONLY
  1726.             if (maxngtodo) {
  1727.             if (retry)
  1728. #ifdef VERBOSE
  1729.                 IF(verbose)
  1730.                 printf("\nRestriction %s%s still in effect.\n",
  1731.                     ngtodo[0],
  1732.                     maxngtodo > 1 ? ", etc." : nullstr) FLUSH;
  1733.                 ELSE
  1734. #endif
  1735. #ifdef TERSE
  1736.                 fputs("\n(\"Only\" mode.)\n",stdout) FLUSH;
  1737. #endif
  1738.             else {
  1739. #ifdef VERBOSE
  1740.                 IF(verbose)
  1741.                 fputs("\nNo articles under restriction.",
  1742.                   stdout) FLUSH;
  1743.                 ELSE
  1744. #endif
  1745. #ifdef TERSE
  1746.                 fputs("\nNo \"only\" articles.",stdout) FLUSH;
  1747. #endif
  1748.                 end_only();    /* release the restriction */
  1749.                 retry = TRUE;
  1750.             }
  1751.             }
  1752. #endif
  1753.             dfltcmd = (retry ? "npq" : "qnp");
  1754. #ifdef VERBOSE
  1755.             IF(verbose)
  1756.             sprintf(promptbuf,
  1757.                 "\n******** End of newsgroups--what next? [%s] ",
  1758.                 dfltcmd);
  1759.             ELSE
  1760. #endif
  1761. #ifdef TERSE
  1762.             sprintf(promptbuf,
  1763.                 "\n**** End--next? [%s] ", dfltcmd);
  1764. #endif
  1765.         }
  1766.         else {
  1767.             bool shoe_fits;    /* newsgroup matches restriction? */
  1768.  
  1769.             if (toread[ng] >= TR_NONE) {    /* recalc toread? */
  1770.             set_ngname(rcline[ng]);
  1771.             if (shoe_fits = (special || inlist(ngname)))
  1772.                 set_toread(ng);
  1773.             if (paranoid) {
  1774.                 recent_ng = current_ng;
  1775.                 current_ng = ng;
  1776.                 cleanup_rc();
  1777.                     /* this may move newsgroups around */
  1778.                 ng = current_ng;
  1779.                 set_ngname(rcline[ng]);
  1780.             }
  1781.             }
  1782.             if (toread[ng] < (maxngtodo||special ? TR_NONE : TR_ONE) || !shoe_fits) {
  1783.                     /* unwanted newsgroup? */
  1784.             ng++;        /* then skip it */
  1785.             continue;
  1786.             }
  1787.             dfltcmd = "ynq";
  1788. #ifdef VERBOSE
  1789.             IF(verbose)
  1790.             sprintf(promptbuf,
  1791.                 "\n******** %3ld unread article%c in %s--read now? [%s] ",
  1792.                 (long)toread[ng], (toread[ng]==TR_ONE ? ' ' : 's'),
  1793.                 ngname, dfltcmd);    /* format prompt string */
  1794.             ELSE
  1795. #endif
  1796. #ifdef TERSE
  1797.             sprintf(promptbuf,
  1798.                 "\n**** %3ld in %s--read? [%s] ",
  1799.                 (long)toread[ng],
  1800.                 ngname,dfltcmd);    /* format prompt string */
  1801. #endif
  1802.         }
  1803.         special = FALSE;    /* go back to normal mode */
  1804.         if (ng != current_ng) {
  1805.             recent_ng = current_ng;
  1806.                     /* remember previous newsgroup */
  1807.             current_ng = ng;    /* remember current newsgroup */
  1808.         }
  1809.     reask_newsgroup:
  1810.         unflush_output();    /* disable any ^O in effect */
  1811.         fputs(promptbuf,stdout) FLUSH;/* print prompt */
  1812.         fflush(stdout);
  1813.     reinp_newsgroup:
  1814.         eat_typeahead();
  1815.         getcmd(buf);
  1816.         if (errno || *buf == '\f') {
  1817.             putchar('\n') FLUSH; /* if return from stop signal */
  1818.             goto reask_newsgroup;    /* give them a prompt again */
  1819.         }
  1820.         setdef(buf,dfltcmd);
  1821. #ifdef VERIFY
  1822.         printcmd();
  1823. #endif
  1824.         switch (*buf) {
  1825.         case 'p':        /* find previous unread newsgroup */
  1826.             do {
  1827.             if (ng <= 0)
  1828.                 break;
  1829.             ng--;
  1830.             if (toread[ng] == TR_NONE)
  1831.                 set_toread(ng);
  1832.             } while (toread[ng] <= TR_NONE);
  1833.             break;
  1834.         case 'P':        /* goto previous newsgroup */
  1835.             do {
  1836.             if (ng <= 0)
  1837.                 break;
  1838.             ng--;
  1839.             } while (toread[ng] < TR_NONE);
  1840.             special = TRUE;    /* don't skip it if toread==0 */
  1841.             break;
  1842.         case '-':
  1843.             ng = recent_ng;    /* recall previous newsgroup */
  1844.             special = TRUE;    /* don't skip it if toread==0 */
  1845.             break;
  1846.         case 'q': case 'Q': case 'x':    /* quit? */
  1847.             oh_for_the_good_old_days = (*buf == 'x');
  1848.             putchar('\n') FLUSH;
  1849.             ng = nextrcline+1;    /* satisfy */
  1850.             retry = FALSE;    /*   loop conditions */
  1851.             break;
  1852.         case '^':
  1853.             putchar('\n') FLUSH;
  1854.             ng = 0;
  1855.             break;
  1856.         case 'n': case '+':    /* find next unread newsgroup */
  1857.             if (ng == nextrcline) {
  1858.             putchar('\n') FLUSH;
  1859.             retry = TRUE;
  1860.             }
  1861.             else if (toread[ng] > TR_NONE)
  1862.             retry = TRUE;
  1863.             ng++;
  1864.             break;
  1865.         case 'N':        /* goto next newsgroup */
  1866.             ng++;
  1867.             special = TRUE;    /* and don't skip it if toread==0 */
  1868.             break;
  1869.         case '1':        /* goto 1st newsgroup */
  1870.             ng = 0;
  1871.             special = TRUE;    /* and don't skip it if toread==0 */
  1872.             break;
  1873.         case '$':
  1874.             ng = nextrcline;    /* goto last newsgroup */
  1875.             retry = TRUE;
  1876.             break;
  1877.         case 'L':
  1878.             list_newsgroups();
  1879.             goto reask_newsgroup;
  1880.         case '/': case '?':    /* scan for newsgroup pattern */
  1881. #ifdef NGSEARCH
  1882.             switch (ng_search(buf,TRUE)) {
  1883.             case NGS_ABORT:
  1884.             goto reinp_newsgroup;
  1885.             case NGS_INTR:
  1886. #ifdef VERBOSE
  1887.             IF(verbose)
  1888.                 fputs("\n(Interrupted)\n",stdout) FLUSH;
  1889.             ELSE
  1890. #endif
  1891. #ifdef TERSE
  1892.                 fputs("\n(Intr)\n",stdout) FLUSH;
  1893. #endif
  1894.             ng = current_ng;
  1895.             goto reask_newsgroup;
  1896.             case NGS_FOUND:
  1897.             special = TRUE;    /* don't skip it if toread==0 */
  1898.             break;
  1899.             case NGS_NOTFOUND:
  1900. #ifdef VERBOSE
  1901.             IF(verbose)
  1902.                 fputs("\n\nNot found--use g to add newsgroups\n",
  1903.                 stdout) FLUSH;
  1904.             ELSE
  1905. #endif
  1906. #ifdef TERSE
  1907.                 fputs("\n\nNot found\n",stdout) FLUSH;
  1908. #endif
  1909.             goto reask_newsgroup;
  1910.             }
  1911. #else
  1912.             notincl("/");
  1913. #endif
  1914.             break;
  1915.         case 'm':
  1916. #ifndef RELOCATE
  1917.             notincl("m");
  1918.             break;
  1919. #endif            
  1920.         case 'g':    /* goto named newsgroup */
  1921.             if (!finish_command(FALSE))
  1922.                     /* if they didn't finish command */
  1923.             goto reinp_newsgroup;    /* go try something else */
  1924.             for (s = buf+1; *s == ' '; s++);
  1925.                     /* skip leading spaces */
  1926.             if (!*s)
  1927.             strcpy(s,ngname);
  1928. #ifdef RELOCATE
  1929.             if (!get_ng(s,*buf=='m'))    /* try to find newsgroup */
  1930. #else
  1931.             if (!get_ng(s,FALSE))    /* try to find newsgroup */
  1932. #endif
  1933.             ng = current_ng;/* if not found, go nowhere */
  1934.             special = TRUE;    /* don't skip it if toread==0 */
  1935.             break;
  1936. #ifdef DEBUGGING
  1937.         case 'D':
  1938.             printf("\nTries: %d Hits: %d\n",
  1939.             softtries,softtries-softmisses) FLUSH;
  1940.             goto reask_newsgroup;
  1941. #endif
  1942.         case '!':        /* shell escape */
  1943.             if (escapade())     /* do command */
  1944.             goto reinp_newsgroup;
  1945.                     /* if rubbed out, re input */
  1946.             goto reask_newsgroup;
  1947.         case Ctl('k'):        /* edit global KILL file */
  1948.             edit_kfile();
  1949.             goto reask_newsgroup;
  1950.         case 'c':        /* catch up */
  1951. #ifdef CATCHUP
  1952. reask_catchup:
  1953. #ifdef VERBOSE
  1954.             in_char("\nDo you really want to mark everything as read? [yn] ");
  1955. #else
  1956.             in_char("\nReally? [ynh] ");
  1957. #endif
  1958.             putchar('\n') FLUSH;
  1959.             setdef(buf,"y");
  1960.             if (*buf == 'h') {
  1961. #ifdef VERBOSE
  1962.             printf("Type y or SP to mark all articles as read.\n");
  1963.             printf("Type n to leave articles marked as they are.\n");
  1964. #else
  1965.             printf("y or SP to mark all read.\n");
  1966.             printf("n to forget it.\n");
  1967. #endif
  1968.             goto reask_catchup;
  1969.             }
  1970.             else if (*buf!=' ' && *buf!='y' && *buf!='n' && *buf!='q') {
  1971.             printf(hforhelp);
  1972.             settle_down();
  1973.             goto reask_catchup;
  1974.             } else if ( (*buf == ' ' || *buf == 'y') && ng<nextrcline )
  1975.             catch_up(ng);
  1976.             else
  1977.             retry = TRUE;
  1978.             ng++;
  1979. #else
  1980.             notincl("c");
  1981. #endif
  1982.             break;
  1983.         case 'u':        /* unsubscribe */
  1984.             if (ng < nextrcline && toread[ng] >= TR_NONE) {
  1985.                     /* unsubscribable? */
  1986.             printf(unsubto,rcline[ng]) FLUSH;
  1987.             rcchar[ng] = NEGCHAR;
  1988.                     /* unsubscribe to (from?) it */
  1989.             toread[ng] = TR_UNSUB;
  1990.                     /* and make line invisible */
  1991.             ng++;        /* do an automatic 'n' */
  1992.             }
  1993.             break;
  1994.         case 'h': {        /* help */
  1995.             int cmd;
  1996.  
  1997.             if ((cmd = help_ng()) > 0)
  1998.             pushchar(cmd);
  1999.             goto reask_newsgroup;
  2000.         }
  2001.         case 'a':
  2002. #ifndef FINDNEWNG
  2003.             notincl("a");
  2004.             goto reask_newsgroup;
  2005. #else
  2006.             /* FALL THROUGH */
  2007. #endif
  2008.         case 'o':
  2009. #ifdef ONLY
  2010.         {
  2011. #ifdef FINDNEWNG
  2012.             bool doscan = (*buf == 'a');
  2013. #endif
  2014.  
  2015.             if (!finish_command(TRUE)) /* get rest of command */
  2016.             goto reinp_newsgroup;    /* if rubbed out, try something else */
  2017.             end_only();
  2018.             if (buf[1]) {
  2019.             bool minusd = instr(buf+1,"-d") != Nullch;
  2020.  
  2021.             sw_list(buf+1);
  2022.             if (minusd)
  2023.                 cwd_check();
  2024.             putchar('\n') FLUSH;
  2025. #ifdef FINDNEWNG
  2026.             if (doscan && maxngtodo)
  2027.                 scanactive();
  2028. #endif
  2029.             }
  2030.             ng = 0;        /* simulate ^ */
  2031.             retry = FALSE;
  2032.             break;
  2033.         }
  2034. #else
  2035.             notincl("o");
  2036.             goto reask_newsgroup;
  2037. #endif
  2038.         case '&':
  2039.             if (switcheroo()) /* get rest of command */
  2040.             goto reinp_newsgroup;    /* if rubbed out, try something else */
  2041.             goto reask_newsgroup;
  2042.         case 'l': {        /* list other newsgroups */
  2043.             if (!finish_command(TRUE)) /* get rest of command */
  2044.             goto reinp_newsgroup;    /* if rubbed out, try something else */
  2045.             for (s = buf+1; *s == ' '; s++);
  2046.                         /* skip leading spaces */
  2047.             sprintf(cmd_buf,"%s '%s'",filexp(NEWSGROUPS),s);
  2048.             resetty();
  2049.             if (doshell(sh,cmd_buf))
  2050. #ifdef VERBOSE
  2051.             IF(verbose)
  2052.                 fputs("    (Error from newsgroups program)\n",
  2053.                 stdout) FLUSH;
  2054.             ELSE
  2055. #endif
  2056. #ifdef TERSE
  2057.                 fputs("(Error)\n",stdout) FLUSH;
  2058. #endif
  2059.             noecho();
  2060.             crmode();
  2061.             goto reask_newsgroup;
  2062.         }
  2063.         case '.': case '=':
  2064.         case 'y': case 'Y': /* do normal thing */
  2065.             if (ng >= nextrcline) {
  2066.             fputs("\nNot on a newsgroup.",stdout) FLUSH;
  2067.             goto reask_newsgroup;
  2068.             }
  2069.             if (*buf == '=')
  2070.             s = savestr("=");
  2071.             else if (*buf == '.') {    /* start command? */
  2072.             if (!finish_command(FALSE)) /* get rest of command */
  2073.                 goto reinp_newsgroup;
  2074.             s = savestr(buf+1);
  2075.                     /* do_newsgroup will free it */
  2076.             }
  2077.             else
  2078.             s = Nullch;
  2079.             if (toread[ng])
  2080.             retry = TRUE;
  2081.             switch (do_newsgroup(s)) {
  2082.             case NG_ERROR:
  2083.             case NG_NORM:
  2084.             ng++;
  2085.             break;
  2086.             case NG_ASK:
  2087.             goto reask_newsgroup;
  2088.             case NG_MINUS:
  2089.             ng = recent_ng;    /* recall previous newsgroup */
  2090.             special = TRUE;    /* don't skip it if toread==0 */
  2091.             break;
  2092.             }
  2093.             break;
  2094. #ifdef STRICTCR
  2095.         case '\n':
  2096.             fputs(badcr,stdout) FLUSH;
  2097.             goto reask_newsgroup;
  2098. #endif
  2099.         case 'v':
  2100.             printf("\n%s\n",rnid) FLUSH;
  2101.             goto reask_newsgroup;
  2102.         default:
  2103.             printf("\n%s",hforhelp) FLUSH;
  2104.             settle_down();
  2105.             goto reask_newsgroup;
  2106.         }
  2107.         }
  2108.     } while (retry);
  2109.     }
  2110.  
  2111.     /* now write .newsrc back out */
  2112.  
  2113.     write_rc();
  2114.  
  2115.     if (oh_for_the_good_old_days)
  2116.     get_old_rc();
  2117.  
  2118.     finalize(0);            /* and exit */
  2119. }
  2120.  
  2121. /* set current newsgroup */
  2122.  
  2123. void
  2124. set_ngname(what)
  2125. char *what;
  2126. {
  2127.     int len = strlen(what)+1;
  2128.  
  2129.     growstr(&ngname,&ngnlen,len);
  2130.     strcpy(ngname,what);
  2131.     growstr(&ngdir,&ngdlen,len);
  2132.     strcpy(ngdir,getngdir(ngname));
  2133. }
  2134.  
  2135. static char *myngdir;
  2136. static int ngdirlen = 0;
  2137.  
  2138. char *
  2139. getngdir(ngnam)
  2140. char *ngnam;
  2141. {
  2142.     register char *s;
  2143.  
  2144.     growstr(&myngdir,&ngdirlen,strlen(ngnam)+1);
  2145.     strcpy(myngdir,ngnam);
  2146.     for (s = myngdir; *s; s++)
  2147.     if (*s == '.')
  2148.         *s = '/';
  2149.     return myngdir;
  2150. }
  2151.  
  2152. !STUFFY!FUNK!
  2153. echo Extracting rcln.c
  2154. cat >rcln.c <<'!STUFFY!FUNK!'
  2155. /* $Header: rcln.c,v 4.3 85/05/01 11:45:36 lwall Exp $
  2156.  *
  2157.  * $Log:    rcln.c,v $
  2158.  * Revision 4.3  85/05/01  11:45:36  lwall
  2159.  * Baseline for release with 4.3bsd.
  2160.  * 
  2161.  */
  2162.  
  2163. #include "EXTERN.h"
  2164. #include "common.h"
  2165. #include "util.h"
  2166. #include "rcstuff.h"
  2167. #include "ngdata.h"
  2168. #include "INTERN.h"
  2169. #include "rcln.h"
  2170.  
  2171. void
  2172. rcln_init()
  2173. {
  2174.     ;
  2175. }
  2176.  
  2177. #ifdef CATCHUP
  2178. void
  2179. catch_up(ngx)
  2180. NG_NUM ngx;
  2181. {
  2182.     char tmpbuf[128];
  2183.     
  2184. #ifdef VERBOSE
  2185.     IF(verbose)
  2186.     printf("\nMarking %s as all read.\n",rcline[ngx]) FLUSH;
  2187.     ELSE
  2188. #endif
  2189. #ifdef TERSE
  2190.     fputs("\nMarked read\n",stdout) FLUSH;
  2191. #endif
  2192.     sprintf(tmpbuf,"%s: 1-%ld", rcline[ngx],(long)getngsize(ngx));
  2193.     free(rcline[ngx]);
  2194.     rcline[ngx] = savestr(tmpbuf);
  2195.     *(rcline[ngx] + rcnums[ngx] - 1) = '\0';
  2196.     write_rc();
  2197. }
  2198. #endif
  2199.  
  2200. /* add an article number to a newsgroup, if it isn't already read */
  2201.  
  2202. int
  2203. addartnum(artnum,ngnam)
  2204. ART_NUM artnum;
  2205. char *ngnam;
  2206. {
  2207.     register NG_NUM ngnum = find_ng(ngnam);
  2208.     register char *s, *t, *maxt = Nullch;
  2209.     ART_NUM min = 0, max = -1, lastnum = 0;
  2210.     char *mbuf;
  2211.     bool morenum;
  2212.  
  2213.     if (!artnum)
  2214.     return 0;
  2215.     if (ngnum == nextrcline || !rcnums[ngnum])
  2216.                     /* not found in newsrc? */
  2217.     return 0;
  2218. #ifdef CACHEFIRST
  2219.     if (!abs1st[ngnum])
  2220. #else
  2221.     if (!toread[ngnum])
  2222. #endif
  2223.                     /* now is a good time to trim down */
  2224.     set_toread(ngnum);        /* the list due to expires if we */
  2225.                     /* have not yet. */
  2226. #ifdef DEBUGGING
  2227.     if (artnum > ngmax[ngnum] + 10    /* allow for incoming articles */
  2228.        ) {
  2229.     printf("\nCorrupt Xref line!!!  %ld --> %s(1..%ld)\n",
  2230.         artnum,ngnam,
  2231.         ngmax[ngnum]) FLUSH;
  2232.     paranoid = TRUE;        /* paranoia reigns supreme */
  2233.     return -1;            /* hope this was the first newsgroup */
  2234.     }
  2235. #endif
  2236.  
  2237.     if (toread[ngnum] == TR_BOGUS)
  2238.     return 0;
  2239. #ifdef DEBUGGING
  2240.     if (debug & DEB_XREF_MARKER) {
  2241.     printf("%ld->\n%s%c%s\n",(long)artnum,rcline[ngnum],rcchar[ngnum],
  2242.       rcline[ngnum] + rcnums[ngnum]) FLUSH;
  2243.     }
  2244. #endif
  2245.     s = rcline[ngnum] + rcnums[ngnum];
  2246.     while (*s == ' ') s++;        /* skip spaces */
  2247.     t = s;
  2248.     while (isdigit(*s) && artnum >= (min = atol(s))) {
  2249.                     /* while it might have been read */
  2250.     for (t = s; isdigit(*t); t++) ;    /* skip number */
  2251.     if (*t == '-') {        /* is it a range? */
  2252.         t++;            /* skip to next number */
  2253.         if (artnum <= (max = atol(t)))
  2254.         return 0;        /* it is in range => already read */
  2255.         lastnum = max;        /* remember it */
  2256.         maxt = t;            /* remember position in case we */
  2257.                     /* want to overwrite the max */
  2258.         while (isdigit(*t)) t++;    /* skip second number */
  2259.     }
  2260.     else {
  2261.         if (artnum == min)        /* explicitly a read article? */
  2262.         return 0;
  2263.         lastnum = min;        /* remember what the number was */
  2264.         maxt = Nullch;        /* last one was not a range */
  2265.     }
  2266.     while (*t && !isdigit(*t)) t++;    /* skip comma and any spaces */
  2267.     s = t;
  2268.     }
  2269.     
  2270.     /* we have not read it, so insert the article number before s */
  2271.     
  2272.     morenum = isdigit(*s);        /* will it need a comma after? */
  2273.     *(rcline[ngnum] + rcnums[ngnum] - 1) = rcchar[ngnum];
  2274.     mbuf = safemalloc((MEM_SIZE)(strlen(s) + (s-rcline[ngnum]) + 8));
  2275.     strcpy(mbuf,rcline[ngnum]);        /* make new rc line */
  2276.     if (maxt && lastnum && artnum == lastnum+1)
  2277.                         /* can we just extend last range? */
  2278.     t = mbuf + (maxt-rcline[ngnum]);/* then overwrite previous max */
  2279.     else {
  2280.     t = mbuf + (t-rcline[ngnum]);    /* point t into new line instead */
  2281.     if (lastnum) {            /* have we parsed any line? */
  2282.         if (!morenum)        /* are we adding to the tail? */
  2283.         *t++ = ',';        /* supply comma before */
  2284.         if (!maxt && artnum == lastnum+1 && *(t-1) == ',')
  2285.                     /* adjacent singletons? */
  2286.         *(t-1) = '-';        /* turn them into a range */
  2287.     }
  2288.     }
  2289.     if (morenum) {            /* is there more to life? */
  2290.     if (min == artnum+1) {        /* can we consolidate further? */
  2291.         bool range_before = (*(t-1) == '-');
  2292.         bool range_after;
  2293.         char *nextmax;
  2294.  
  2295.         for (nextmax = s; isdigit(*nextmax); nextmax++) ;
  2296.         range_after = *nextmax++ == '-';
  2297.         
  2298.         if (range_before)
  2299.         *t = '\0';        /* artnum is redundant */
  2300.         else
  2301.         sprintf(t,"%ld-",(long)artnum);/* artnum will be new min */
  2302.         
  2303.         if (range_after)
  2304.         s = nextmax;        /* *s is redundant */
  2305.     /*  else
  2306.         s = s */        /* *s is new max */
  2307.     }
  2308.     else
  2309.         sprintf(t,"%ld,",(long)artnum);    /* put the number and comma */
  2310.     }
  2311.     else
  2312.     sprintf(t,"%ld",(long)artnum);    /* put the number there (wherever) */
  2313.     strcat(t,s);            /* copy remainder of line */
  2314. #ifdef DEBUGGING
  2315.     if (debug & DEB_XREF_MARKER) {
  2316.     printf("%s\n",mbuf) FLUSH;
  2317.     }
  2318. #endif
  2319.     free(rcline[ngnum]);
  2320.     rcline[ngnum] = mbuf;        /* pull the switcheroo */
  2321.     *(rcline[ngnum] + rcnums[ngnum] - 1) = '\0';
  2322.                     /* wipe out : or ! */
  2323.     if (toread[ngnum] > TR_NONE)    /* lest we turn unsub into bogus */
  2324.     --toread[ngnum];
  2325.     return 0;
  2326. }
  2327.  
  2328. #ifdef MCHASE
  2329. /* delete an article number from a newsgroup, if it is there */
  2330.  
  2331. void
  2332. subartnum(artnum,ngnam)
  2333. register ART_NUM artnum;
  2334. char *ngnam;
  2335. {
  2336.     register NG_NUM ngnum = find_ng(ngnam);
  2337.     register char *s, *t;
  2338.     register ART_NUM min, max;
  2339.     char *mbuf;
  2340.     int curlen;
  2341.  
  2342.     if (!artnum)
  2343.     return;
  2344.     if (ngnum == nextrcline || !rcnums[ngnum])
  2345.     return;                /* not found in newsrc? */
  2346. #ifdef DEBUGGING
  2347.     if (debug & DEB_XREF_MARKER) {
  2348.     printf("%ld<-\n%s%c%s\n",(long)artnum,rcline[ngnum],rcchar[ngnum],
  2349.       rcline[ngnum] + rcnums[ngnum]) FLUSH;
  2350.     }
  2351. #endif
  2352.     s = rcline[ngnum] + rcnums[ngnum];
  2353.     while (*s == ' ') s++;        /* skip spaces */
  2354.     
  2355.     /* a little optimization, since it is almost always the last number */
  2356.     
  2357.     for (t=s; *t; t++) ;        /* find end of string */
  2358.     curlen = t-rcline[ngnum];
  2359.     for (t--; isdigit(*t); t--) ;    /* find previous delim */
  2360.     if (*t == ',' && atol(t+1) == artnum) {
  2361.     *t = '\0';
  2362.     if (toread[ngnum] >= TR_NONE)
  2363.         ++toread[ngnum];
  2364. #ifdef DEBUGGING
  2365.     if (debug & DEB_XREF_MARKER)
  2366.         printf("%s%c %s\n",rcline[ngnum],rcchar[ngnum],s) FLUSH;
  2367. #endif
  2368.     return;
  2369.     }
  2370.  
  2371.     /* not the last number, oh well, we may need the length anyway */
  2372.  
  2373.     while (isdigit(*s) && artnum >= (min = atol(s))) {
  2374.                     /* while it might have been read */
  2375.     for (t = s; isdigit(*t); t++) ;    /* skip number */
  2376.     if (*t == '-') {        /* is it a range? */
  2377.         t++;            /* skip to next number */
  2378.         max = atol(t);
  2379.         while (isdigit(*t)) t++;    /* skip second number */
  2380.         if (artnum <= max) {
  2381.                     /* it is in range => already read */
  2382.         if (artnum == min) {
  2383.             min++;
  2384.             artnum = 0;
  2385.         }
  2386.         else if (artnum == max) {
  2387.             max--;
  2388.             artnum = 0;
  2389.         }
  2390.         *(rcline[ngnum] + rcnums[ngnum] - 1) = rcchar[ngnum];
  2391.         mbuf = safemalloc((MEM_SIZE)(curlen + (artnum?15:2)));
  2392.         *s = '\0';
  2393.         strcpy(mbuf,rcline[ngnum]);    /* make new rc line */
  2394.         s = mbuf + (s-rcline[ngnum]);
  2395.                     /* point s into mbuf now */
  2396.         if (artnum) {        /* split into two ranges? */
  2397.             prange(s,min,artnum-1);
  2398.             s += strlen(s);
  2399.             *s++ = ',';
  2400.             prange(s,artnum+1,max);
  2401.         }
  2402.         else            /* only one range */
  2403.             prange(s,min,max);
  2404.         s += strlen(s);
  2405.         strcpy(s,t);        /* copy remainder over */
  2406. #ifdef DEBUGGING
  2407.         if (debug & DEB_XREF_MARKER) {
  2408.             printf("%s\n",mbuf) FLUSH;
  2409.         }
  2410. #endif
  2411.         free(rcline[ngnum]);
  2412.         rcline[ngnum] = mbuf;    /* pull the switcheroo */
  2413.         *(rcline[ngnum] + rcnums[ngnum] - 1) = '\0';
  2414.                     /* wipe out : or ! */
  2415.         if (toread[ngnum] >= TR_NONE)
  2416.             ++toread[ngnum];
  2417.         return;
  2418.         }
  2419.     }
  2420.     else {
  2421.         if (artnum == min) {    /* explicitly a read article? */
  2422.         if (*t == ',')        /* pick a comma, any comma */
  2423.             t++;
  2424.         else if (s[-1] == ',')
  2425.             s--;
  2426.         else if (s[-2] == ',')    /* (in case of space) */
  2427.             s -= 2;
  2428.         strcpy(s,t);        /* no need to realloc */
  2429.         if (toread[ngnum] >= TR_NONE)
  2430.             ++toread[ngnum];
  2431. #ifdef DEBUGGING
  2432.         if (debug & DEB_XREF_MARKER) {
  2433.             printf("%s%c%s\n",rcline[ngnum],rcchar[ngnum],
  2434.               rcline[ngnum] + rcnums[ngnum]) FLUSH;
  2435.         }
  2436. #endif
  2437.         return;
  2438.         }
  2439.     }
  2440.     while (*t && !isdigit(*t)) t++;    /* skip comma and any spaces */
  2441.     s = t;
  2442.     }
  2443. }
  2444.  
  2445. void
  2446. prange(where,min,max)
  2447. char *where;
  2448. ART_NUM min,max;
  2449. {
  2450.     if (min == max)
  2451.     sprintf(where,"%ld",(long)min);
  2452.     else
  2453.     sprintf(where,"%ld-%ld",(long)min,(long)max);
  2454. }
  2455. #endif
  2456.  
  2457. /* calculate the number of unread articles for a newsgroup */
  2458.  
  2459. void
  2460. set_toread(ngnum)
  2461. register NG_NUM ngnum;
  2462. {
  2463.     register char *s, *c, *h;
  2464.     char tmpbuf[64], *mybuf = tmpbuf;
  2465.     char *nums;
  2466.     int length;
  2467. #ifdef CACHEFIRST
  2468.     bool virgin_ng = (!abs1st[ngnum]);
  2469. #endif
  2470.     ART_NUM ngsize = getngsize(ngnum);
  2471.     ART_NUM unread = ngsize;
  2472.     ART_NUM newmax;
  2473.  
  2474. #ifdef DEBUGGING
  2475.     ngmax[ngnum] = ngsize;        /* for checking out-of-range Xrefs */
  2476. #endif
  2477.     if (ngsize == TR_BOGUS) {
  2478.     printf("Warning!  Bogus newsgroup: %s\n",rcline[ngnum]) FLUSH;
  2479.     paranoid = TRUE;
  2480.     toread[ngnum] = TR_BOGUS;
  2481.     return;
  2482.     }
  2483. #ifdef CACHEFIRST
  2484.     if (virgin_ng)
  2485. #else
  2486.     if (!toread[ngnum])
  2487. #endif
  2488.     {
  2489.     sprintf(tmpbuf," 1-%ld",(long)ngsize);
  2490.     if (strNE(tmpbuf,rcline[ngnum]+rcnums[ngnum]))
  2491.         checkexpired(ngnum,ngsize);    /* this might realloc rcline */
  2492.     }
  2493.     nums = rcline[ngnum]+rcnums[ngnum];
  2494.     length = strlen(nums);
  2495.     if (length >= 60)
  2496.     mybuf = safemalloc((MEM_SIZE)(length+5));
  2497.     strcpy(mybuf,nums);
  2498.     mybuf[length++] = ',';
  2499.     mybuf[length] = '\0';
  2500.     for (s = mybuf; isspace(*s); s++)
  2501.         ;
  2502.     for ( ; (c = index(s,',')) != Nullch ; s = ++c) {
  2503.                     /* for each range */
  2504.     *c = '\0';            /* keep index from running off */
  2505.     if ((h = index(s,'-')) != Nullch)    /* find - in range, if any */
  2506.         unread -= (newmax = atol(h+1)) - atol(s) + 1;
  2507.     else if (newmax = atol(s))
  2508.         unread--;        /* recalculate length */
  2509.     if (newmax > ngsize) {    /* paranoia check */
  2510.         unread = -1;
  2511.         break;
  2512.     }
  2513.     }
  2514.     if (unread >= 0)        /* reasonable number? */
  2515.     toread[ngnum] = (ART_UNREAD)unread;
  2516.                     /* remember how many are left */
  2517.     else {                /* SOMEONE RESET THE NEWSGROUP!!! */
  2518.     toread[ngnum] = (ART_UNREAD)ngsize;
  2519.                     /* assume nothing carried over */
  2520.     printf("Warning!  Somebody reset %s--assuming nothing read.\n",
  2521.         rcline[ngnum]) FLUSH;
  2522.     *(rcline[ngnum] + rcnums[ngnum]) = '\0';
  2523.     paranoid = TRUE;        /* enough to make a guy paranoid */
  2524.     }
  2525.     if (mybuf != tmpbuf)
  2526.     free(mybuf);
  2527.     if (rcchar[ngnum] == NEGCHAR)
  2528.     toread[ngnum] = TR_UNSUB;
  2529. }
  2530.  
  2531. /* make sure expired articles are marked as read */
  2532.  
  2533. void
  2534. checkexpired(ngnum,ngsize)
  2535. register NG_NUM ngnum;
  2536. ART_NUM ngsize;
  2537. {
  2538.     register ART_NUM a1st = getabsfirst(ngnum,ngsize);
  2539.     register char *s, *t;
  2540.     register ART_NUM num, lastnum = 0;
  2541.     char *mbuf, *newnum;
  2542.  
  2543.     if (a1st<=1)
  2544.     return;
  2545. #ifdef DEBUGGING
  2546.     if (debug & DEB_XREF_MARKER) {
  2547.     printf("1-%ld->\n%s%c%s\n",(long)(a1st-1),rcline[ngnum],rcchar[ngnum],
  2548.       rcline[ngnum] + rcnums[ngnum]) FLUSH;
  2549.     }
  2550. #endif
  2551.     for (s = rcline[ngnum] + rcnums[ngnum]; isspace(*s); s++);
  2552.     while (*s && (num = atol(s)) <= a1st) {
  2553.     while (isdigit(*s)) s++;
  2554.     while (*s && !isdigit(*s)) s++;
  2555.     lastnum = num;
  2556.     }
  2557.     if (*s) {
  2558.     if (s[-1] == '-') {            /* landed in a range? */
  2559.         if (lastnum != 1)
  2560.         sprintf(rcline[ngnum]+rcnums[ngnum]," 1-%s",s);
  2561.         goto ret;
  2562.     }
  2563.     }
  2564.     /* s now points to what should follow first range */
  2565.     if (s - rcline[ngnum] > rcnums[ngnum] + 10) 
  2566.     mbuf = rcline[ngnum];
  2567.     else {
  2568.     mbuf = safemalloc((MEM_SIZE)(rcnums[ngnum] + strlen(s) + 10));
  2569.     strcpy(mbuf,rcline[ngnum]);
  2570.     }
  2571.     newnum = t = mbuf+rcnums[ngnum];
  2572.     sprintf(t," 1-%ld",(long)(a1st - (lastnum != a1st)));
  2573.     if (*s) {
  2574.     t += strlen(t);
  2575.     *t++ = ',';
  2576.     strcpy(t,s);
  2577.     }
  2578.     if (mbuf == rcline[ngnum]) {
  2579.     rcline[ngnum] = saferealloc(rcline[ngnum],
  2580.         (MEM_SIZE)(rcnums[ngnum] + strlen(newnum) + 1));
  2581.     }
  2582.     else {
  2583.     free(rcline[ngnum]);
  2584.     rcline[ngnum] = mbuf;
  2585.     }
  2586.  
  2587. ret:;        /* semicolon in case DEBUGGING undefined */
  2588. #ifdef DEBUGGING
  2589.     if (debug & DEB_XREF_MARKER) {
  2590.     printf("%s%c%s\n",rcline[ngnum],rcchar[ngnum],
  2591.       rcline[ngnum] + rcnums[ngnum]) FLUSH;
  2592.     }
  2593. #endif
  2594. }
  2595.  
  2596. !STUFFY!FUNK!
  2597. echo Extracting HACKERSGUIDE
  2598. cat >HACKERSGUIDE <<'!STUFFY!FUNK!'
  2599. Hacking Notes
  2600.  
  2601. If you aren't interested in mucking with the innards of rn, don't read this.
  2602.  
  2603. In the interests of both space and time optimization, things are done inside
  2604. rn that don't always conform to the highest ideals of programming.  To the
  2605. extent I felt it was practical, I've tried to conform to good programming
  2606. practice, but you must realize that my goal was to make a better mousetrap,
  2607. so certain conscious tradeoffs were made in the design of rn right from the
  2608. start.  In particular, if you want to hack on rn (and I wouldn't blame you,
  2609. it's fun), beware of the following:
  2610.   
  2611.   * buf and cmd_buf are reused all over the place.  11-squishing is a good
  2612.     term for it.  No, I'm on a Vax now, but I've been there.
  2613.  
  2614.   * The article header is parsed on the fly, while it is being displayed.
  2615.     In fact, practically everything is done on the fly within the article
  2616.     display loop, and there are plenty of state variables.  The header
  2617.     is never explicitly stored in memory; rather, pointers are kept into
  2618.     the file.  The information required to backup pages is not stored in
  2619.     memory, except for 1 buffer's worth.  The information required to do
  2620.     the delayed mark as unread (M) is not stored in memory either.
  2621.  
  2622.   * Lots of contortions are gone through to avoid using static memory, or
  2623.     allocating unnecessary memory, or losing track of allocated memory,
  2624.     while at the same time allowing .newsrc lines and header lines to be
  2625.     ANY length up to the amount of memory you have.  Rn spends a great deal
  2626.     of effort being lazy.  Do not use a static buffer when you can use
  2627.     growstr().
  2628.  
  2629.   * Lots of contortions are gone through to try to do things when people
  2630.     aren't waiting, or have only been waiting a very short time.  Guessing
  2631.     the next article to be opened and opening it, searching ahead for the
  2632.     next article with the same subject, delaying the look up of the number
  2633.     of articles in a newsgroup, writing the rest of the page while the
  2634.     reader is examining the header, cacheing up subjects while the user
  2635.     is reading, checkpointing the .newsrc only while the reader is in the
  2636.     middle of an interesting article, are some of the strategies employed.
  2637.   
  2638.   * There are plenty of goto's.  Most of them involve going back to reprompt,
  2639.     to reask for input, or to just plain do the unstructured things people
  2640.     want to do when they are glaring at a terminal.  If they bother you
  2641.     too much, just think of rn as a big state machine.  If they don't bother
  2642.     you at all, I don't want you hacking on rn.
  2643.  
  2644.   * Put all includes at the front of the file, before the first function,
  2645.     or makedepend will not work right.  I could relax this, but makedepend
  2646.     would take about 5 times longer to run.
  2647.  
  2648. In general then, feel free to hack on rn.  Just don't broadcast untested
  2649. patches to the net.  Remember that there are people with limited address
  2650. spaces and limited cpu cycles.  If you add a wonderful new feature and
  2651. want to publish a patch, put #ifdef's around it so that people who don't
  2652. want it or can't afford it can work around it.  THIS MEANS YOU.  We don't
  2653. need 57 varieties of mutually incompatible and incomprehensible rn floating
  2654. about the net.  Consider telling me about your patch so that I can consider
  2655. including it in the standard version.  A COMPLETE PATCH TAKES INTO ACCOUNT
  2656. SYSTEM DEPENDENCIES AS DETERMINED BY THE CONFIGURE SCRIPT.
  2657.  
  2658. * Don't use ints where rn uses typedefs, in particular, for article numbers.
  2659. * Don't use %d anywhere that someone might need a %ld.  (Just because YOU
  2660.     typedefed it as an int doesn't mean someone else won't need a long.)
  2661. * Don't use %D, that's archaic.
  2662. * Put FLUSHes after printf()s, fputs()es and putchar('\n')s for our poor
  2663.     brethern and sistern without line buffering.
  2664. * Declare the type of every function.  Use void, even if your C compiler
  2665.     doesn't.
  2666. * Follow the style that rn already uses!  This is my pet peeve.  Well, one of
  2667.     them, anyway.  I follow other people's strange styles when modifying
  2668.     their programs, so I'd be much obliged if you did likewise.
  2669. * Use lint.
  2670. * Use RCS.  Start a new branch, like 4.3.[2-9].  (I will use 4.3.1 myself.)
  2671. * Be structured wherever it doesn't interfere with practicality.
  2672. * Long live paranoid programming.  The rest of the program is out to get you.
  2673.     The world is out to destroy the program, not to mention the .newsrc.
  2674.     And then there's always bitrot...
  2675. * Stop reading this lugubrious trash and start thinking for yourself.
  2676. * Thank you and good night.
  2677. !STUFFY!FUNK!
  2678. echo ""
  2679. echo "End of kit 5 (of 9)"
  2680. cat /dev/null >kit5isdone
  2681. config=true
  2682. for iskit in 1 2 3 4 5 6 7 8 9; do
  2683.     if test -f kit${iskit}isdone; then
  2684.     echo "You have run kit ${iskit}."
  2685.     else
  2686.     echo "You still need to run kit ${iskit}."
  2687.     config=false
  2688.     fi
  2689. done
  2690. case $config in
  2691.     true)
  2692.     echo "You have run all your kits.  Please read README and then type Configure."
  2693.     chmod 755 Configure
  2694.     ;;
  2695. esac
  2696. : I do not append .signature, but someone might mail this.
  2697. exit
  2698.  
  2699.