home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 1 / 1461 < prev    next >
Encoding:
Internet Message Format  |  1990-12-28  |  61.7 KB

  1. From: sob@lib.tmc.edu (Stan Barber)
  2. Newsgroups: alt.sources
  3. Subject: rrn/rn combo kite part 4 of 9
  4. Message-ID: <430@lib.tmc.edu>
  5. Date: 14 Jun 90 03:27:35 GMT
  6.  
  7. #! /bin/sh
  8.  
  9. # Make a new directory for the rn sources, cd to it, and run kits 1 thru 9 
  10. # through sh.  When all 9 kits have been run, read README.
  11.  
  12. echo "This is rn kit 4 (of 9).  If kit 4 is complete, the line"
  13. echo '"'"End of kit 4 (of 9)"'" will echo at the end.'
  14. echo ""
  15. export PATH || (echo "You didn't use sh, you clunch." ; kill $$)
  16. echo Extracting intrp.c
  17. cat >intrp.c <<'!STUFFY!FUNK!'
  18. /* $Header: intrp.c,v 4.3.2.4 90/04/23 00:31:20 sob Exp $
  19.  *
  20.  * $Log:    intrp.c,v $
  21.  * Revision 4.3.2.4  90/04/23  00:31:20  sob
  22.  * Removed unneeded atoi call.
  23.  * 
  24.  * Revision 4.3.2.3  90/03/22  23:04:35  sob
  25.  * Fixes provided by Wayne Davison <drivax!davison>
  26.  * 
  27.  * Revision 4.3.2.2  90/03/17  17:03:12  sob
  28.  * Fixed determination of the news superuser's id. Fix provided by Chip
  29.  * Rosenthal <chip@chinacat.lonestar.org>.
  30.  * 
  31.  * Revision 4.3.2.1  89/12/17  02:54:55  sob
  32.  * Removed redundant include directive.
  33.  * 
  34.  * Revision 4.3.1.5  85/05/23  17:21:24  lwall
  35.  * Now allows 'r' and 'f' on null articles.
  36.  * 
  37.  * Revision 4.3.1.4  85/05/21  13:35:21  lwall
  38.  * Sped up "rn -c" by not doing unnecessary initialization.
  39.  * 
  40.  * Revision 4.3.1.3  85/05/17  10:37:11  lwall
  41.  * Fixed & substitution to capitalize last name too.
  42.  * 
  43.  * Revision 4.3.1.2  85/05/15  14:39:45  lwall
  44.  * Spelled gecos right.
  45.  * 
  46.  * Revision 4.3.1.1  85/05/10  11:33:51  lwall
  47.  * Branch for patches.
  48.  * 
  49.  * Revision 4.3  85/05/01  11:40:54  lwall
  50.  * Baseline for release with 4.3bsd.
  51.  * 
  52.  */
  53.  
  54. #include "EXTERN.h"
  55. #include "common.h"
  56. #include "util.h"
  57. #include "search.h"
  58. #include "head.h"
  59. #include "rn.h"
  60. #include "artsrch.h"
  61. #include "ng.h"
  62. #include "respond.h"
  63. #include "rcstuff.h"
  64. #include "bits.h"
  65. #include "artio.h"
  66. #include "term.h"
  67. #include "final.h"
  68. #include "INTERN.h"
  69. #include "intrp.h"
  70.  
  71. char orgname[] = ORGNAME;
  72.  
  73. /* name of this site */
  74. #ifdef GETHOSTNAME
  75.     char *hostname;
  76. #   undef SITENAME
  77. #   define SITENAME hostname
  78. #else !GETHOSTNAME
  79. #   ifdef DOUNAME
  80. #    include <sys/utsname.h>
  81.     struct utsname uts;
  82. #    undef SITENAME
  83. #    define SITENAME uts.nodename
  84. #   else !DOUNAME
  85. #    ifdef PHOSTNAME
  86.         char *hostname;
  87. #        undef SITENAME
  88. #        define SITENAME hostname
  89. #    else !PHOSTNAME
  90. #        ifdef WHOAMI
  91. #        undef SITENAME
  92. #        define SITENAME sysname
  93. #        endif WHOAMI
  94. #    endif PHOSTNAME
  95. #   endif DOUNAME
  96. #endif GETHOSTNAME
  97.  
  98. #ifdef TILDENAME
  99. static char *tildename = Nullch;
  100. static char *tildedir = Nullch;
  101. #endif
  102.  
  103. char *realname INIT(Nullch);    /* real name of sender from /etc/passwd */
  104.  
  105. char *dointerp();
  106. char *getrealname();
  107. #ifdef CONDSUB
  108. char *skipinterp();
  109. #endif
  110.  
  111. static void abort_interp();
  112.  
  113. void
  114. intrp_init(tcbuf)
  115. char *tcbuf;
  116. {
  117.     char *getlogin();
  118.  
  119.     spool = savestr(filexp(SPOOL));    /* usually /usr/spool/news */
  120.     
  121.     /* get environmental stuff */
  122.  
  123.     /* get home directory */
  124.  
  125.     homedir = getenv("HOME");
  126.     if (homedir == Nullch)
  127.     homedir = getenv("LOGDIR");
  128.  
  129.     dotdir = getval("DOTDIR",homedir);
  130.  
  131.     /* get login name */
  132.  
  133.     logname = getenv("USER");
  134.     if (logname == Nullch)
  135.     logname = getenv("LOGNAME");
  136. #ifdef GETLOGIN
  137.     if (logname == Nullch)
  138.     logname = savestr(getlogin());
  139. #endif
  140.     
  141.     if (checkflag)            /* that getwd below takes ~1/3 sec. */
  142.     return;                /* and we do not need it for -c */
  143.     getwd(tcbuf);            /* find working directory name */
  144.     origdir = savestr(tcbuf);        /* and remember it */
  145.  
  146.     /* get the real name of the person (%N) */
  147.     /* Must be done after logname is read in because BERKNAMES uses that */
  148.  
  149.     strcpy(tcbuf,getrealname(getuid()));
  150.     realname = savestr(tcbuf);
  151.  
  152.     /* name of header file (%h) */
  153.  
  154.     headname = savestr(filexp(HEADNAME));
  155.  
  156.     /* name of this site (%H) */
  157.  
  158. #ifdef GETHOSTNAME
  159.     gethostname(buf,sizeof buf);
  160.     hostname = savestr(buf);
  161. #else
  162. #ifdef DOUNAME
  163.     /* get sysname */
  164.     uname(&uts);
  165. #else
  166. #ifdef PHOSTNAME
  167.     {
  168.     FILE *popen();
  169.     FILE *pipefp = popen(PHOSTNAME,"r");
  170.     
  171.     if (pipefp == Nullfp) {
  172.         printf("Can't find hostname\n");
  173.         sig_catcher(0);
  174.     }
  175.     fgets(buf,sizeof buf,pipefp);
  176.     buf[strlen(buf)-1] = '\0';    /* wipe out newline */
  177.     hostname = savestr(buf);
  178.     pclose(pipefp);
  179.     }
  180. #endif
  181. #endif
  182. #endif
  183.     sitename = savestr(SITENAME);
  184. }
  185.  
  186. /* expand filename via %, ~, and $ interpretation */
  187. /* returns pointer to static area */
  188. /* Note that there is a 1-deep cache of ~name interpretation */
  189.  
  190. char *
  191. filexp(s)
  192. register char *s;
  193. {
  194.     static char filename[CBUFLEN];
  195.     char scrbuf[CBUFLEN];
  196.     register char *d;
  197.  
  198. #ifdef DEBUGGING
  199.     if (debug & DEB_FILEXP)
  200.     printf("< %s\n",s) FLUSH;
  201. #endif
  202.     interp(filename, (sizeof filename), s);            /* interpret any % escapes */
  203. #ifdef DEBUGGING
  204.     if (debug & DEB_FILEXP)
  205.     printf("%% %s\n",filename) FLUSH;
  206. #endif
  207.     s = filename;
  208.     if (*s == '~') {    /* does destination start with ~? */
  209.     if (!*(++s) || *s == '/') {
  210.         sprintf(scrbuf,"%s%s",homedir,s);
  211.                 /* swap $HOME for it */
  212. #ifdef DEBUGGING
  213.     if (debug & DEB_FILEXP)
  214.     printf("~ %s\n",scrbuf) FLUSH;
  215. #endif
  216.         strcpy(filename,scrbuf);
  217.     }
  218.     else {
  219. #ifdef TILDENAME
  220.         for (d=scrbuf; isalnum(*s); s++,d++)
  221.         *d = *s;
  222.         *d = '\0';
  223.         if (tildedir && strEQ(tildename,scrbuf)) {
  224.         strcpy(scrbuf,tildedir);
  225.         strcat(scrbuf, s);
  226.         strcpy(filename, scrbuf);
  227. #ifdef DEBUGGING
  228.         if (debug & DEB_FILEXP)
  229.             printf("r %s %s\n",tildename,tildedir) FLUSH;
  230. #endif
  231.         }
  232.         else {
  233.         if (tildename) {
  234.             free(tildename);
  235.             free(tildedir);
  236.         }
  237.         tildedir = Nullch;
  238.         tildename = savestr(scrbuf);
  239. #ifdef GETPWENT        /* getpwnam() is not the paragon of efficiency */
  240.         {
  241.             struct passwd *getpwnam();
  242.             struct passwd *pwd = getpwnam(tildename);
  243.  
  244.             sprintf(scrbuf,"%s%s",pwd->pw_dir,s);
  245.             tildedir = savestr(pwd->pw_dir);
  246. #ifdef NEWSADMIN
  247.             if ((pwd != NULL) && strEQ(newsadmin,tildename))
  248.             newsuid = pwd->pw_uid;
  249. #endif
  250.             strcpy(filename,scrbuf);
  251. #ifdef GETPWENT
  252.             endpwent();
  253. #endif
  254.         }
  255. #else            /* this will run faster, and is less D space */
  256.         {    /* just be sure LOGDIRFIELD is correct */
  257.             FILE *pfp = fopen("/etc/passwd","r");
  258.             char tmpbuf[512];
  259.             int i;
  260.             
  261.             if (pfp == Nullfp) {
  262.             printf(cantopen,"passwd") FLUSH;
  263.             sig_catcher(0);
  264.             }
  265.             while (fgets(tmpbuf,512,pfp) != Nullch) {
  266.             d = cpytill(scrbuf,tmpbuf,':');
  267. #ifdef DEBUGGING
  268.             if (debug & DEB_FILEXP)
  269.                 printf("p %s\n",tmpbuf) FLUSH;
  270. #endif
  271.             if (strEQ(scrbuf,tildename)) {
  272. #ifdef NEWSADMIN
  273.                 if (strEQ(newsadmin,tildename))
  274.                 newsuid = atoi(index(d+1,':')+1);
  275. #endif
  276.                 for (i=LOGDIRFIELD-2; i; i--) {
  277.                 if (d)
  278.                     d = index(d+1,':');
  279.                 }
  280.                 if (d) {
  281.                 cpytill(scrbuf,d+1,':');
  282.                 tildedir = savestr(scrbuf);
  283.                 strcat(scrbuf,s);
  284.                 strcpy(filename,scrbuf);
  285.                 }
  286.                 break;
  287.             }
  288.             }
  289.             fclose(pfp);
  290.         }
  291. #endif
  292.         }
  293. #else !TILDENAME
  294. #ifdef VERBOSE
  295.         IF(verbose)
  296.         fputs("~loginname not implemented.\n",stdout) FLUSH;
  297.         ELSE
  298. #endif
  299. #ifdef TERSE
  300.         fputs("~login not impl.\n",stdout) FLUSH;
  301. #endif
  302. #endif
  303.     }
  304.     }
  305.     else if (*s == '$') {    /* starts with some env variable? */
  306.     d = scrbuf;
  307.     *d++ = '%';
  308.     if (s[1] == '{')
  309.         strcpy(d,s+2);
  310.     else {
  311.         *d++ = '{';
  312.         for (s++; isalnum(*s); s++) *d++ = *s;
  313.                 /* skip over token */
  314.         *d++ = '}';
  315.         strcpy(d,s);
  316.     }
  317. #ifdef DEBUGGING
  318.     if (debug & DEB_FILEXP)
  319.         printf("$ %s\n",scrbuf) FLUSH;
  320. #endif
  321.     interp(filename, (sizeof filename), scrbuf);
  322.                     /* this might do some extra '%'s but */
  323.                     /* that is how the Mercedes Benz */
  324.     }
  325. #ifdef DEBUGGING
  326.     if (debug & DEB_FILEXP)
  327.     printf("> %s\n",filename) FLUSH;
  328. #endif
  329.     return filename;
  330. }
  331.  
  332. #ifdef CONDSUB
  333. /* skip interpolations */
  334.  
  335. char *
  336. skipinterp(pattern,stoppers)
  337. register char *pattern;
  338. char *stoppers;
  339. {
  340.  
  341.     while (*pattern && (!stoppers || !index(stoppers,*pattern))) {
  342. #ifdef DEBUGGING
  343.     if (debug & 8)
  344.         printf("skipinterp till %s at %s\n",stoppers?stoppers:"",pattern);
  345. #endif
  346.     if (*pattern == '%' && pattern[1]) {
  347.         switch (*++pattern) {
  348.         case '{':
  349.         for (pattern++; *pattern && *pattern != '}'; pattern++)
  350.             if (*pattern == '\\')
  351.             pattern++;
  352.         break;
  353.         case '[':
  354.         for (pattern++; *pattern && *pattern != ']'; pattern++)
  355.             if (*pattern == '\\')
  356.             pattern++;
  357.         break;
  358. #ifdef CONDSUB
  359.         case '(': {
  360.         pattern = skipinterp(pattern+1,"!=");
  361.         if (!*pattern)
  362.             goto getout;
  363.         for (pattern++; *pattern && *pattern != '?'; pattern++)
  364.             if (*pattern == '\\')
  365.             pattern++;
  366.         if (!*pattern)
  367.             goto getout;
  368.         pattern = skipinterp(pattern+1,":)");
  369.         if (*pattern == ':')
  370.             pattern = skipinterp(pattern+1,")");
  371.         break;
  372.         }
  373. #endif
  374. #ifdef BACKTICK
  375.         case '`': {
  376.         pattern = skipinterp(pattern+1,"`");
  377.         break;
  378.         }
  379. #endif
  380. #ifdef PROMPTTTY
  381.         case '"':
  382.         pattern = skipinterp(pattern+1,"\"");
  383.         break;
  384. #endif
  385.         default:
  386.         break;
  387.         }
  388.         pattern++;
  389.     }
  390.     else {
  391.         if (*pattern == '^' && pattern[1])
  392.         pattern += 2;
  393.         else if (*pattern == '\\' && pattern[1])
  394.         pattern += 2;
  395.         else
  396.         pattern++;
  397.     }
  398.     }
  399. getout:
  400.     return pattern;            /* where we left off */
  401. }
  402. #endif
  403.  
  404. /* interpret interpolations */
  405.  
  406. char *
  407. dointerp(dest,destsize,pattern,stoppers)
  408. register char *dest;
  409. register int destsize;
  410. register char *pattern;
  411. char *stoppers;
  412. {
  413.     char *subj_buf = Nullch;
  414.     char *ngs_buf = Nullch;
  415.     char *refs_buf = Nullch;
  416.     char *artid_buf = Nullch;
  417.     char *reply_buf = Nullch;
  418.     char *from_buf = Nullch;
  419.     char *path_buf = Nullch;
  420.     char *follow_buf = Nullch;
  421.     char *dist_buf = Nullch;
  422.     char *line_buf = Nullch;
  423.     register char *s, *h;
  424.     register int i;
  425.     char scrbuf[512];
  426.     bool upper = FALSE;
  427.     bool lastcomp = FALSE;
  428.     int metabit = 0;
  429.  
  430.     while (*pattern && (!stoppers || !index(stoppers,*pattern))) {
  431. #ifdef DEBUGGING
  432.     if (debug & 8)
  433.         printf("dointerp till %s at %s\n",stoppers?stoppers:"",pattern);
  434. #endif
  435.     if (*pattern == '%' && pattern[1]) {
  436.         upper = FALSE;
  437.         lastcomp = FALSE;
  438.         for (s=Nullch; !s; ) {
  439.         switch (*++pattern) {
  440.         case '^':
  441.             upper = TRUE;
  442.             break;
  443.         case '_':
  444.             lastcomp = TRUE;
  445.             break;
  446.         case '/':
  447. #ifdef ARTSRCH
  448.             s = scrbuf;
  449.             if (!index("/?g",pattern[-2]))
  450.             *s++ = '/';
  451.             strcpy(s,lastpat);
  452.             s += strlen(s);
  453.             if (pattern[-2] != 'g') {
  454.             if (index("/?",pattern[-2]))
  455.                 *s++ = pattern[-2];
  456.             else
  457.                 *s++ = '/';
  458.             if (art_howmuch == 1)
  459.                 *s++ = 'h';
  460.             else if (art_howmuch == 2)
  461.                 *s++ = 'a';
  462.             if (art_doread)
  463.                 *s++ = 'r';
  464.             }
  465.             *s = '\0';
  466.             s = scrbuf;
  467. #else
  468.             s = nullstr;
  469. #endif
  470.             break;
  471.         case '{':
  472.             pattern = cpytill(scrbuf,pattern+1,'}');
  473.             if (s = index(scrbuf,'-'))
  474.             *s++ = '\0';
  475.             else
  476.             s = nullstr;
  477.             s = getval(scrbuf,s);
  478.             break;
  479.         case '[':
  480.             pattern = cpytill(scrbuf,pattern+1,']');
  481.             i = set_line_type(scrbuf,scrbuf+strlen(scrbuf));
  482.             if (line_buf)
  483.             free(line_buf);
  484.             s = line_buf = fetchlines(art,i);
  485.             break;
  486. #ifdef CONDSUB
  487.         case '(': {
  488.             COMPEX *oldbra_compex = bra_compex;
  489.             COMPEX cond_compex;
  490.             char rch;
  491.             bool matched;
  492.             
  493.             init_compex(&cond_compex);
  494.             pattern = dointerp(dest,destsize,pattern+1,"!=");
  495.             rch = *pattern;
  496.             if (rch == '!')
  497.             pattern++;
  498.             if (*pattern != '=')
  499.             goto getout;
  500.             pattern = cpytill(scrbuf,pattern+1,'?');
  501.             if (!*pattern)
  502.             goto getout;
  503.             if (s = compile(&cond_compex,scrbuf,TRUE,TRUE)) {
  504.             printf("%s: %s\n",scrbuf,s) FLUSH;
  505.             pattern += strlen(pattern);
  506.             goto getout;
  507.             }
  508.             matched = (execute(&cond_compex,dest) != Nullch);
  509.             if (cond_compex.nbra)    /* were there brackets? */
  510.             bra_compex = &cond_compex;
  511.             if (matched==(rch == '=')) {
  512.             pattern = dointerp(dest,destsize,pattern+1,":)");
  513.             if (*pattern == ':')
  514.                 pattern = skipinterp(pattern+1,")");
  515.             }
  516.             else {
  517.             pattern = skipinterp(pattern+1,":)");
  518.             if (*pattern == ':')
  519.                 pattern++;
  520.             pattern = dointerp(dest,destsize,pattern,")");
  521.             }
  522.             s = dest;
  523.             bra_compex = oldbra_compex;
  524.             free_compex(&cond_compex);
  525.             break;
  526.         }
  527. #endif
  528. #ifdef BACKTICK
  529.         case '`': {
  530.             FILE *pipefp, *popen();
  531.  
  532.             pattern = dointerp(scrbuf,(sizeof scrbuf),pattern+1,"`");
  533.             pipefp = popen(scrbuf,"r");
  534.             if (pipefp != Nullfp) {
  535.             int len;
  536.  
  537.             len = fread(scrbuf,sizeof(char),(sizeof scrbuf)-1,
  538.                 pipefp);
  539.             scrbuf[len] = '\0';
  540.             pclose(pipefp);
  541.             }
  542.             else {
  543.             printf("\nCan't run %s\n",scrbuf);
  544.             *scrbuf = '\0';
  545.             }
  546.             for (s=scrbuf; *s; s++) {
  547.             if (*s == '\n') {
  548.                 if (s[1])
  549.                 *s = ' ';
  550.                 else
  551.                 *s = '\0';
  552.             }
  553.             }
  554.             s = scrbuf;
  555.             break;
  556.         }
  557. #endif
  558. #ifdef PROMPTTTY
  559.         case '"':
  560.             pattern = dointerp(scrbuf,(sizeof scrbuf),pattern+1,"\"");
  561.             fputs(scrbuf,stdout) FLUSH;
  562.             resetty();
  563.             gets(scrbuf);
  564.             noecho();
  565.             crmode();
  566.             s = scrbuf;
  567.             break;
  568. #endif
  569.         case '~':
  570.             s = homedir;
  571.             break;
  572.         case '.':
  573.             s = dotdir;
  574.             break;
  575.         case '$':
  576.             s = scrbuf;
  577.             sprintf(s,"%d",getpid());
  578.             break;
  579.         case '0': case '1': case '2': case '3': case '4':
  580.         case '5': case '6': case '7': case '8': case '9':
  581. #ifdef CONDSUB
  582.             s = getbracket(bra_compex,*pattern - '0');
  583. #else
  584.             s = nullstr;
  585. #endif
  586.             break;
  587.         case 'a':
  588.             s = scrbuf;
  589.             sprintf(s,"%ld",(long)art);
  590.             break;
  591.         case 'A':
  592. #ifdef LINKART
  593.             s = linkartname;    /* so Eunice people get right file */
  594. #else
  595.             s = scrbuf;
  596.             sprintf(s,"%s/%s/%ld",spool,ngdir,(long)art);
  597. #endif
  598.             break;
  599.         case 'b':
  600.             s = savedest;
  601.             break;
  602.         case 'B':
  603.             s = scrbuf;
  604.             sprintf(s,"%ld",(long)savefrom);
  605.             break;
  606.         case 'c':
  607.             s = ngdir;
  608.             break;
  609.         case 'C':
  610.             s = ngname;
  611.             break;
  612.         case 'd':
  613.             s = scrbuf;
  614.             sprintf(s,"%s/%s",spool,ngdir);
  615.             break;
  616.         case 'D':
  617.             s = dist_buf = fetchlines(art,DIST_LINE);
  618.             break;
  619.         case 'f':            /* from line */
  620. #ifdef ASYNC_PARSE
  621.             parse_maybe(art);
  622. #endif
  623.             if (htype[REPLY_LINE].ht_minpos >= 0) {
  624.                         /* was there a reply line? */
  625.             if (!(s=reply_buf))
  626.                 s = reply_buf = fetchlines(art,REPLY_LINE);
  627.             }
  628.             else if (!(s = from_buf))
  629.             s = from_buf = fetchlines(art,FROM_LINE);
  630.             break;
  631.         case 'F':
  632. #ifdef ASYNC_PARSE
  633.             parse_maybe(art);
  634. #endif
  635.             if (htype[FOLLOW_LINE].ht_minpos >= 0)
  636.                     /* is there a Followup-To line? */
  637.             s = follow_buf = fetchlines(art,FOLLOW_LINE);
  638.             else {
  639.             int off;
  640.         
  641.             s = ngs_buf = fetchlines(art,NGS_LINE);
  642.             if (h = instr(s,"net.general")) {
  643.                 off = h-s;
  644.                 strncpy(scrbuf,s,off+4);
  645.                 strcpy(scrbuf+off+4,"followup");
  646.                 safecpy(scrbuf+off+12,h+11,sizeof(scrbuf));
  647.                 s = scrbuf;
  648.             }
  649.             }
  650.             break;
  651.         case 'h':            /* header file name */
  652.             s = headname;
  653.             break;
  654.         case 'H':            /* host name */
  655.             s = sitename;
  656.             break;
  657.         case 'i':
  658.             if (!(s=artid_buf))
  659.             s = artid_buf = fetchlines(art,MESSID_LINE);
  660.             if (*s && *s != '<') {
  661.             sprintf(scrbuf,"<%s>",artid_buf);
  662.             s = scrbuf;
  663.             }
  664.             break;
  665.         case 'I':            /* ref article indicator */
  666.             s = scrbuf;
  667.             sprintf(scrbuf,"'%s'",indstr);
  668.             break;
  669.         case 'l':            /* rn library */
  670. #ifdef NEWSADMIN
  671.             s = newsadmin;
  672. #else
  673.             s = "???";
  674. #endif
  675.             break;
  676.         case 'L':            /* login id */
  677.             s = logname;
  678.             break;
  679.         case 'm':        /* current mode */
  680.             s = scrbuf;
  681.             *s = mode;
  682.             s[1] = '\0';
  683.             break;
  684.         case 'M':
  685. #ifdef DELAYMARK
  686.             sprintf(scrbuf,"%ld",(long)dmcount);
  687.             s = scrbuf;
  688. #else
  689.             s = nullstr;
  690. #endif
  691.             break;
  692.         case 'n':            /* newsgroups */
  693.             s = ngs_buf = fetchlines(art,NGS_LINE);
  694.             break;
  695.         case 'N':            /* full name */
  696.             s = getval("NAME",realname);
  697.             break;
  698.         case 'o':            /* organization */
  699.             s = getval("ORGANIZATION",orgname);
  700. #ifdef ORGFILE
  701.             if (*s == '/') {
  702.             FILE *ofp = fopen(s,"r");
  703.  
  704.             if (ofp) {
  705.                 fgets(scrbuf,sizeof scrbuf,ofp);
  706.                 fclose(ofp);
  707.                 s = scrbuf;
  708.                 s[strlen(s)-1] = '\0';
  709.             }
  710.             }
  711. #endif
  712.             break;
  713.         case 'O':
  714.             s = origdir;
  715.             break;
  716.         case 'p':
  717.             s = cwd;
  718.             break;
  719.         case 'P':
  720.             s = spool;
  721.             break;
  722.         case 'r':
  723. #ifdef ASYNC_PARSE
  724.             parse_maybe(art);
  725. #endif
  726.             if (htype[REFS_LINE].ht_minpos >= 0) {
  727.             refs_buf = fetchlines(art,REFS_LINE);
  728.             refscpy(scrbuf,(sizeof scrbuf),refs_buf);
  729.             }
  730.             else
  731.             *scrbuf = '\0';
  732.             s = rindex(scrbuf,'<');
  733.             break;
  734.         case 'R':
  735. #ifdef ASYNC_PARSE
  736.             parse_maybe(art);
  737. #endif
  738.             if (htype[REFS_LINE].ht_minpos >= 0) {
  739.             refs_buf = fetchlines(art,REFS_LINE);
  740.             refscpy(scrbuf,(sizeof scrbuf),refs_buf);
  741.             /* no more than 3 prior references allowed,
  742.             ** including the one concatenated below */
  743.             if ((s = rindex(scrbuf,'<')) > scrbuf) {
  744.                 *s = '\0';
  745.                 h = rindex(scrbuf,'<');
  746.                 *s = '<';
  747.                 if (h > scrbuf)
  748.                 strcpy(scrbuf,h);
  749.             }
  750.             }
  751.             else
  752.             *scrbuf = '\0';
  753.             if (!artid_buf)
  754.             artid_buf = fetchlines(art,MESSID_LINE);
  755.             if (artid_buf[0] == '<')
  756.             safecat(scrbuf,artid_buf,sizeof(scrbuf));
  757.             else if (artid_buf[0]) {
  758.             char tmpbuf[64];
  759.     
  760.             sprintf(tmpbuf,"<%s>",artid_buf);
  761.             safecat(scrbuf,tmpbuf,sizeof(scrbuf));
  762.             }
  763.             s = scrbuf;
  764.             break;
  765.         case 's':
  766.             if (!(s=subj_buf))
  767.             s = subj_buf = fetchsubj(art,TRUE,TRUE);
  768.                         /* get subject handy */
  769.             while ((*s=='R'||*s=='r')&&(s[1]=='E'||s[1]=='e')&&s[2]==':') {
  770.                         /* skip extra Re: */
  771.             s += 3;
  772.             if (*s == ' ')
  773.                 s++;
  774.             }
  775.             if (h = instr(s,"- (nf"))
  776.             *h = '\0';
  777.             break;
  778.         case 'S':
  779.             if (!(s=subj_buf))
  780.             s = subj_buf = fetchsubj(art,TRUE,TRUE);
  781.                         /* get subject handy */
  782.             if ((*s=='R'||*s=='r')&&(s[1]=='E'||s[1]=='e')&&s[2]==':') {
  783.                         /* skip extra Re: */
  784.             s += 3;
  785.             if (*s == ' ')
  786.                 s++;
  787.             }
  788.             break;
  789.         case 't':
  790.         case 'T':
  791. #ifdef ASYNC_PARSE
  792.             parse_maybe(art);
  793. #endif
  794.             if (htype[REPLY_LINE].ht_minpos >= 0) {
  795.                     /* was there a reply line? */
  796.             if (!(s=reply_buf))
  797.                 s = reply_buf = fetchlines(art,REPLY_LINE);
  798.             }
  799.             else if (!(s = from_buf))
  800.             s = from_buf = fetchlines(art,FROM_LINE);
  801.             if (*pattern == 'T') {
  802.             if (htype[PATH_LINE].ht_minpos >= 0) {
  803.                     /* should we substitute path? */
  804.                 s = path_buf = fetchlines(art,PATH_LINE);
  805.             }
  806.             i = strlen(sitename);
  807.             if (strnEQ(sitename,s,i) && s[i] == '!')
  808.                 s += i + 1;
  809.             }
  810.             if ((h=index(s,'(')) != Nullch)
  811.                         /* strip garbage from end */
  812.             *(h-1) = '\0';
  813.             else if ((h=index(s,'<')) != Nullch) {
  814.                         /* or perhaps from beginning */
  815.             s = h+1;
  816.             if ((h=index(s,'>')) != Nullch)
  817.                 *h = '\0';
  818.             }
  819.             break;
  820.         case 'u':
  821.             sprintf(scrbuf,"%ld",(long)toread[ng]);
  822.             s = scrbuf;
  823.             break;
  824.         case 'U':
  825.             sprintf(scrbuf,"%ld",
  826.             (long)(((ART_NUM)toread[ng]) - 1 + was_read(art)));
  827.             s = scrbuf;
  828.             break;
  829.         case 'x':            /* news library */
  830.             s = lib;
  831.             break;
  832.         case 'X':            /* rn library */
  833.             s = rnlib;
  834.             break;
  835.         case 'z':
  836. #ifdef LINKART
  837.             s = linkartname;    /* so Eunice people get right file */
  838. #else
  839.             s = scrbuf;
  840.             sprintf(s,"%ld",(long)art);
  841. #endif
  842.             if (stat(s,&filestat) < 0)
  843.             filestat.st_size = 0L;
  844.             sprintf(scrbuf,"%5ld",(long)filestat.st_size);
  845.             s = scrbuf;
  846.             break;
  847.         default:
  848.             if (--destsize <= 0)
  849.             abort_interp();
  850.             *dest++ = *pattern | metabit;
  851.             s = nullstr;
  852.             break;
  853.         }
  854.         }
  855.         if (!s)
  856.         s = nullstr;
  857.         pattern++;
  858.         if (upper || lastcomp) {
  859.         char *t;
  860.  
  861.         if (s != scrbuf) {
  862.             safecpy(scrbuf,s,(sizeof scrbuf));
  863.             s = scrbuf;
  864.         }
  865.         if (upper || !(t=rindex(s,'/')))
  866.             t = s;
  867.         while (*t && !isalpha(*t))
  868.             t++;
  869.         if (islower(*t))
  870.             *t = toupper(*t);
  871.         }
  872.         i = metabit;        /* maybe get into register */
  873.         if (s == dest) {
  874.         while (*dest) {
  875.             if (--destsize <= 0)
  876.             abort_interp();
  877.             *dest++ |= i;
  878.         }
  879.         }
  880.         else {
  881.         while (*s) {
  882.             if (--destsize <= 0)
  883.             abort_interp();
  884.             *dest++ = *s++ | i;
  885.         }
  886.         }
  887.     }
  888.     else {
  889.         if (--destsize <= 0)
  890.         abort_interp();
  891.         if (*pattern == '^' && pattern[1]) {
  892.         ++pattern;            /* skip uparrow */
  893.         i = *pattern;        /* get char into a register */
  894.         if (i == '?')
  895.             *dest++ = '\177' | metabit;
  896.         else if (i == '(') {
  897.             metabit = 0200;
  898.             destsize++;
  899.         }
  900.         else if (i == ')') {
  901.             metabit = 0;
  902.             destsize++;
  903.         }
  904.         else
  905.             *dest++ = i & 037 | metabit;
  906.         pattern++;
  907.         }
  908.         else if (*pattern == '\\' && pattern[1]) {
  909.         ++pattern;            /* skip backslash */
  910.         i = *pattern;        /* get char into a register */
  911.     
  912.         /* this used to be a switch but the if may save space */
  913.         
  914.         if (i >= '0' && i <= '7') {
  915.             i = 1;
  916.             while (i < 01000 && *pattern >= '0' && *pattern <= '7') {
  917.             i <<= 3;
  918.             i += *pattern++ - '0';
  919.             }
  920.             *dest++ = i & 0377 | metabit;
  921.             --pattern;
  922.         }
  923.         else if (i == 'b')
  924.             *dest++ = '\b' | metabit;
  925.         else if (i == 'f')
  926.             *dest++ = '\f' | metabit;
  927.         else if (i == 'n')
  928.             *dest++ = '\n' | metabit;
  929.         else if (i == 'r')
  930.             *dest++ = '\r' | metabit;
  931.         else if (i == 't')
  932.             *dest++ = '\t' | metabit;
  933.         else
  934.             *dest++ = i | metabit;
  935.         pattern++;
  936.         }
  937.         else
  938.         *dest++ = *pattern++ | metabit;
  939.     }
  940.     }
  941.     *dest = '\0';
  942. getout:
  943.     if (subj_buf != Nullch)    /* return any checked out storage */
  944.     free(subj_buf);
  945.     if (ngs_buf != Nullch)
  946.     free(ngs_buf);
  947.     if (refs_buf != Nullch)
  948.     free(refs_buf);
  949.     if (artid_buf != Nullch)
  950.     free(artid_buf);
  951.     if (reply_buf != Nullch)
  952.     free(reply_buf);
  953.     if (from_buf != Nullch)
  954.     free(from_buf);
  955.     if (path_buf != Nullch)
  956.     free(path_buf);
  957.     if (follow_buf != Nullch)
  958.     free(follow_buf);
  959.     if (dist_buf != Nullch)
  960.     free(dist_buf);
  961.     if (line_buf != Nullch)
  962.     free(line_buf);
  963.     return pattern;            /* where we left off */
  964. }
  965.  
  966. void
  967. interp(dest,destsize,pattern)
  968. char *dest;
  969. int destsize;
  970. char *pattern;
  971. {
  972.     dointerp(dest,destsize,pattern,Nullch);
  973. #ifdef DEBUGGING
  974.     if (debug & DEB_FILEXP)
  975.     fputs(dest,stdout);
  976. #endif
  977. }
  978.  
  979. /* copy a references line, normalizing as we go */
  980.  
  981. void
  982. refscpy(dest,destsize,src)
  983. register char *dest, *src;
  984. register int destsize;
  985. {
  986.     register char *dot, *at, *beg;
  987.     char tmpbuf[64];
  988.     
  989.     while (*src) {
  990.     if (*src != '<') {
  991.         if (--destsize <= 0)
  992.         break;
  993.         *dest++ = '<';
  994.         at = dot = Nullch;
  995.         beg = src;
  996.         while (*src && *src != ' ' && *src != ',') {
  997.         if (*src == '.')
  998.             dot = src;
  999.         else if (*src == '@')
  1000.             at = src;
  1001.         if (--destsize <= 0)
  1002.             break;
  1003.         *dest++ = *src++;
  1004.         }
  1005.         if (destsize <= 0)
  1006.         break;
  1007.         if (dot && !at) {
  1008.         int len;
  1009.  
  1010.         *dest = *dot++ = '\0';
  1011.         sprintf(tmpbuf,"%s@%s.UUCP",dot,beg);
  1012.         len = strlen(tmpbuf);
  1013.         if (destsize > len) {
  1014.             strcpy(dest,tmpbuf);
  1015.             dest = dest + len;
  1016.             destsize -= len;
  1017.         }
  1018.         }
  1019.         if (--destsize <= 0)
  1020.         break;
  1021.         *dest++ = '>';
  1022.     }
  1023.     else {
  1024.         while (*src && --destsize > 0 && (*dest++ = *src++) != '>') ;
  1025.         if (destsize <= 0)
  1026.         break;
  1027.     }
  1028.     while (*src == ' ' || *src == ',') src++;
  1029.     if (*src && --destsize > 0)
  1030.         *dest++ = ' ';
  1031.     }
  1032.     *dest = '\0';
  1033.  
  1034. /* get the person's real name from /etc/passwd */
  1035. /* (string is overwritten, so it must be copied) */
  1036.  
  1037. char *
  1038. getrealname(uid)
  1039. int uid;
  1040. {
  1041.     char *s, *c;
  1042.  
  1043. #ifdef PASSNAMES
  1044. #ifdef GETPWENT
  1045.     struct passwd *pwd = getpwuid(uid);
  1046.     
  1047.     s = pwd->pw_gecos;
  1048. #else
  1049.     char tmpbuf[512];
  1050.     int i;
  1051.  
  1052.     getpw(uid, tmpbuf);
  1053.     for (s=tmpbuf, i=GCOSFIELD-1; i; i--) {
  1054.     if (s)
  1055.         s = index(s,':')+1;
  1056.     }
  1057.     if (!s)
  1058.     return nullstr;
  1059.     cpytill(tmpbuf,s,':');
  1060.     s = tmpbuf;
  1061. #endif
  1062. #ifdef BERKNAMES
  1063. #ifdef BERKJUNK
  1064.     while (*s && !isalnum(*s) && *s != '&') s++;
  1065. #endif
  1066.     if ((c = index(s, ',')) != Nullch)
  1067.     *c = '\0';
  1068.     if ((c = index(s, ';')) != Nullch)
  1069.     *c = '\0';
  1070.     s = cpytill(buf,s,'&');
  1071.     if (*s == '&') {            /* whoever thought this one up was */
  1072.     c = buf + strlen(buf);        /* in the middle of the night */
  1073.     strcat(c,logname);        /* before the morning after */
  1074.     strcat(c,s+1);
  1075.     if (islower(*c))
  1076.         *c = toupper(*c);        /* gack and double gack */
  1077.     }
  1078. #else
  1079.     if ((c = index(s, '(')) != Nullch)
  1080.     *c = '\0';
  1081.     if ((c = index(s, '-')) != Nullch)
  1082.     s = c;
  1083.     strcpy(buf,tmpbuf);
  1084. #endif
  1085. #ifdef GETPWENT
  1086.     endpwent();
  1087. #endif
  1088.     return buf;                /* return something static */
  1089. #else
  1090.     if ((tmpfp=fopen(filexp(FULLNAMEFILE),"r")) != Nullfp) {
  1091.     fgets(buf,sizeof buf,tmpfp);
  1092.     fclose(tmpfp);
  1093.     buf[strlen(buf)-1] = '\0';
  1094.     return buf;
  1095.     }
  1096.     return "PUT YOUR NAME HERE";
  1097. #endif
  1098. }
  1099.  
  1100. static void
  1101. abort_interp()
  1102. {
  1103.     fputs("\n% interp buffer overflow!\n",stdout) FLUSH;
  1104.     sig_catcher(0);
  1105. }
  1106. !STUFFY!FUNK!
  1107. echo Extracting term.c
  1108. cat >term.c <<'!STUFFY!FUNK!'
  1109. /* $Header: term.c,v 4.3.2.7 90/04/21 16:54:29 sob Exp $
  1110.  *
  1111.  * $Log:    term.c,v $
  1112.  * Revision 4.3.2.7  90/04/21  16:54:29  sob
  1113.  * Installed patches provided by SCO for SCO Xenix
  1114.  * 
  1115.  * Revision 4.3.2.6  90/04/13  23:48:17  sob
  1116.  * Modifications provided by Gene Hackney for 3b2.
  1117.  * 
  1118.  * Revision 4.3.2.5  90/04/06  20:35:08  sob
  1119.  * Added fixes for SCO Xenix sent by ronald@robobar.co.uk.
  1120.  * 
  1121.  * Revision 4.3.2.4  90/03/22  23:05:38  sob
  1122.  * Fixes provided by Wayne Davison <drivax!davison>
  1123.  * 
  1124.  * Revision 4.3.2.3  89/11/28  01:51:58  sob
  1125.  * Now handles SIGWINCH correctly.
  1126.  * 
  1127.  * Revision 4.3.2.2  89/11/27  01:31:34  sob
  1128.  * Altered NNTP code per ideas suggested by Bela Lubkin
  1129.  * <filbo@gorn.santa-cruz.ca.us>
  1130.  * 
  1131.  * Revision 4.3.2.1  89/11/06  01:02:12  sob
  1132.  * Added RRN support from NNTP 1.5
  1133.  * 
  1134.  * Revision 4.3.1.3  85/09/10  11:05:23  lwall
  1135.  * Improved %m in in_char().
  1136.  * 
  1137.  * Revision 4.3.1.2  85/05/16  16:45:35  lwall
  1138.  * Forced \r to \n on input.
  1139.  * Fix for terminfo braindamage regarding bc emulation.
  1140.  * 
  1141.  * Revision 4.3.1.1  85/05/10  11:41:03  lwall
  1142.  * Branch for patches.
  1143.  * 
  1144.  * Revision 4.3  85/05/01  11:51:10  lwall
  1145.  * Baseline for release with 4.3bsd.
  1146.  * 
  1147.  */
  1148.  
  1149. #include "EXTERN.h"
  1150. #include "common.h"
  1151. #include "util.h"
  1152. #include "final.h"
  1153. #include "help.h"
  1154. #include "cheat.h"
  1155. #include "intrp.h"
  1156. #include "INTERN.h"
  1157. #include "term.h"
  1158.  
  1159. char ERASECH;        /* rubout character */
  1160. char KILLCH;        /* line delete character */
  1161. char tcarea[TCSIZE];    /* area for "compiled" termcap strings */
  1162.  
  1163. /* guarantee capability pointer != Nullch */
  1164. /* (I believe terminfo will ignore the &tmpaddr argument.) */
  1165.  
  1166. #define Tgetstr(key) ((tmpstr = tgetstr(key,&tmpaddr)) ? tmpstr : nullstr)
  1167.  
  1168. #ifdef PUSHBACK
  1169. struct keymap {
  1170.     char km_type[128];
  1171.     union km_union {
  1172.     struct keymap *km_km;
  1173.     char *km_str;
  1174.     } km_ptr[128];
  1175. };
  1176.  
  1177. #define KM_NOTHIN 0
  1178. #define KM_STRING 1
  1179. #define KM_KEYMAP 2
  1180. #define KM_BOGUS 3
  1181.  
  1182. #define KM_TMASK 3
  1183. #define KM_GSHIFT 4
  1184. #define KM_GMASK 7
  1185.  
  1186. typedef struct keymap KEYMAP;
  1187.  
  1188. KEYMAP *topmap INIT(Null(KEYMAP*));
  1189.  
  1190. void mac_init();
  1191. KEYMAP *newkeymap();
  1192. void show_keymap();
  1193. void pushstring();
  1194. #endif
  1195.  
  1196. void line_col_calcs();
  1197.  
  1198. /* terminal initialization */
  1199.  
  1200. void
  1201. term_init()
  1202. {
  1203.     savetty();                /* remember current tty state */
  1204.  
  1205. #ifdef TERMIO
  1206.     ospeed = _tty.c_cflag & CBAUD;    /* for tputs() */
  1207.     ERASECH = _tty.c_cc[VERASE];    /* for finish_command() */
  1208.     KILLCH = _tty.c_cc[VKILL];        /* for finish_command() */
  1209. #else
  1210.     ospeed = _tty.sg_ospeed;        /* for tputs() */
  1211.     ERASECH = _tty.sg_erase;        /* for finish_command() */
  1212.     KILLCH = _tty.sg_kill;        /* for finish_command() */
  1213. #endif
  1214.  
  1215.     /* The following could be a table but I can't be sure that there isn't */
  1216.     /* some degree of sparsity out there in the world. */
  1217.  
  1218.     switch (ospeed) {            /* 1 second of padding */
  1219. #ifdef BEXTA
  1220.         case BEXTA:  just_a_sec = 1920; break;
  1221. #else
  1222. #ifdef B19200
  1223.         case B19200: just_a_sec = 1920; break;
  1224. #endif
  1225. #endif
  1226.         case B9600:  just_a_sec =  960; break;
  1227.         case B4800:  just_a_sec =  480; break;
  1228.         case B2400:  just_a_sec =  240; break;
  1229.         case B1800:  just_a_sec =  180; break;
  1230.         case B1200:  just_a_sec =  120; break;
  1231.         case B600:   just_a_sec =   60; break;
  1232.     case B300:   just_a_sec =   30; break;
  1233.     /* do I really have to type the rest of this??? */
  1234.         case B200:   just_a_sec =   20; break;
  1235.         case B150:   just_a_sec =   15; break;
  1236.         case B134:   just_a_sec =   13; break;
  1237.         case B110:   just_a_sec =   11; break;
  1238.         case B75:    just_a_sec =    8; break;
  1239.         case B50:    just_a_sec =    5; break;
  1240.         default:     just_a_sec =  960; break;
  1241.                     /* if we are running detached I */
  1242.     }                    /*  don't want to know about it! */
  1243. }
  1244.  
  1245. /* set terminal characteristics */
  1246.  
  1247. void
  1248. term_set(tcbuf)
  1249. char *tcbuf;        /* temp area for "uncompiled" termcap entry */
  1250. {
  1251.     char *tmpaddr;            /* must not be register */
  1252.     register char *tmpstr;
  1253.     char *tgetstr();
  1254.     char *s;
  1255.     int status;
  1256. #ifdef TIOCGWINSZ
  1257. #ifdef u3b2
  1258. struct winsize {
  1259.     unsigned short ws_row;       /* rows, in characters*/
  1260.     unsigned short ws_col;       /* columns, in character */
  1261.     unsigned short ws_xpixel;    /* horizontal size, pixels */
  1262.     unsigned short ws_ypixel;    /* vertical size, pixels */
  1263. };
  1264. #endif
  1265.     struct winsize winsize;
  1266. #endif
  1267.  
  1268. #ifdef PENDING
  1269. #if ! defined (FIONREAD) && ! defined (RDCHK)
  1270.     /* do no delay reads on something that always gets closed on exit */
  1271.  
  1272.     devtty = open("/dev/tty",0);
  1273.     if (devtty < 0) {
  1274.     printf(cantopen,"/dev/tty") FLUSH;
  1275.     finalize(1);
  1276.     }
  1277.     fcntl(devtty,F_SETFL,O_NDELAY);
  1278. #endif
  1279. #endif
  1280.     
  1281.     /* get all that good termcap stuff */
  1282.  
  1283. #ifdef HAVETERMLIB
  1284.     status = tgetent(tcbuf,getenv("TERM"));    /* get termcap entry */
  1285.     if (status < 1) {
  1286. #ifdef VERBOSE
  1287.     printf("No termcap %s found.\n", status ? "file" : "entry") FLUSH;
  1288. #else
  1289.     fputs("Termcap botch\n",stdout) FLUSH
  1290. #endif
  1291.     finalize(1);
  1292.     }
  1293.     tmpaddr = tcarea;            /* set up strange tgetstr pointer */
  1294.     s = Tgetstr("pc");            /* get pad character */
  1295.     PC = *s;                /* get it where tputs wants it */
  1296.     if (!tgetflag("bs")) {        /* is backspace not used? */
  1297.     BC = Tgetstr("bc");        /* find out what is */
  1298.     if (BC == nullstr)         /* terminfo grok's 'bs' but not 'bc' */
  1299.         BC = Tgetstr("le");
  1300.     } else
  1301.     BC = "\b";            /* make a backspace handy */
  1302.     UP = Tgetstr("up");            /* move up a line */
  1303.     if (!*UP)                /* no UP string? */
  1304.     marking = 0;            /* disable any marking */
  1305.     if (muck_up_clear)            /* this is for weird HPs */
  1306.     CL = "\n\n\n\n";
  1307.     else
  1308.     CL = Tgetstr("cl");        /* get clear string */
  1309.     CE = Tgetstr("ce");            /* clear to end of line string */
  1310. #ifdef CLEAREOL
  1311.     CM = Tgetstr("cm");            /* cursor motion */
  1312.     HO = Tgetstr("ho");            /* home cursor if no CM */
  1313.     CD = Tgetstr("cd");            /* clear to end of display */
  1314.     if (!*CE || !*CD || (!*CM && !*HO))    /* can we CE, CD, and home? */
  1315.     can_home_clear = FALSE;        /*  no, so disable use of clear eol */
  1316. #endif CLEAREOL
  1317.     SO = Tgetstr("so");            /* begin standout */
  1318.     SE = Tgetstr("se");            /* end standout */
  1319.     if ((SG = tgetnum("sg"))<0)
  1320.     SG = 0;                /* blanks left by SG, SE */
  1321.     US = Tgetstr("us");            /* start underline */
  1322.     UE = Tgetstr("ue");            /* end underline */
  1323.     if ((UG = tgetnum("ug"))<0)
  1324.     UG = 0;                /* blanks left by US, UE */
  1325.     if (*US)
  1326.     UC = nullstr;            /* UC must not be NULL */
  1327.     else
  1328.     UC = Tgetstr("uc");        /* underline a character */
  1329.     if (!*US && !*UC) {            /* no underline mode? */
  1330.     US = SO;            /* substitute standout mode */
  1331.     UE = SE;
  1332.     UG = SG;
  1333.     }
  1334.     LINES = tgetnum("li");        /* lines per page */
  1335.     COLS = tgetnum("co");        /* columns on page */
  1336.  
  1337. #ifdef TIOCGWINSZ
  1338.     { struct winsize ws;
  1339.     if (ioctl(0, TIOCGWINSZ, &ws) >= 0 && ws.ws_row > 0 && ws.ws_col > 0) {
  1340.         LINES = ws.ws_row;
  1341.         COLS = ws.ws_col;
  1342.     }
  1343.     }
  1344. #endif
  1345.     
  1346.     AM = tgetflag("am");        /* terminal wraps automatically? */
  1347.     XN = tgetflag("xn");        /* then eats next newline? */
  1348.     VB = Tgetstr("vb");
  1349.     if (!*VB)
  1350.     VB = "\007";
  1351.     CR = Tgetstr("cr");
  1352.     if (!*CR) {
  1353.     if (tgetflag("nc") && *UP) {
  1354.         CR = safemalloc((MEM_SIZE)strlen(UP)+2);
  1355.         sprintf(CR,"%s\r",UP);
  1356.     }
  1357.     else
  1358.         CR = "\r";
  1359.     }
  1360. #ifdef TIOCGWINSZ
  1361.     if (ioctl(1, TIOCGWINSZ, &winsize)>=0) {
  1362.         if (winsize.ws_row>0) LINES=winsize.ws_row;
  1363.         if (winsize.ws_col>0) COLS=winsize.ws_col;
  1364.     }
  1365. #endif
  1366. #else
  1367.     ??????                /* Roll your own... */
  1368. #endif
  1369.     line_col_calcs();
  1370.     noecho();                /* turn off echo */
  1371.     crmode();                /* enter cbreak mode */
  1372.  
  1373. #ifdef PUSHBACK
  1374.     mac_init(tcbuf);
  1375. #endif
  1376. }
  1377.  
  1378. #ifdef PUSHBACK
  1379. void
  1380. mac_init(tcbuf)
  1381. char *tcbuf;
  1382. {
  1383.     char tmpbuf[1024];
  1384.  
  1385.     tmpfp = fopen(filexp(getval("RNMACRO",RNMACRO)),"r");
  1386.     if (tmpfp != Nullfp) {
  1387.     while (fgets(tcbuf,1024,tmpfp) != Nullch) {
  1388.         mac_line(tcbuf,tmpbuf,(sizeof tmpbuf));
  1389.     }
  1390.     fclose(tmpfp);
  1391.     }
  1392. }
  1393.  
  1394. void
  1395. mac_line(line,tmpbuf,tbsize)
  1396. char *line;
  1397. char *tmpbuf;
  1398. int tbsize;
  1399. {
  1400.     register char *s, *m;
  1401.     register KEYMAP *curmap;
  1402.     register int ch;
  1403.     register int garbage = 0;
  1404.     static char override[] = "\nkeymap overrides string\n";
  1405.  
  1406.     if (topmap == Null(KEYMAP*))
  1407.     topmap = newkeymap();
  1408.     if (*line == '#' || *line == '\n')
  1409.     return;
  1410.     if (line[ch = strlen(line)-1] == '\n')
  1411.     line[ch] = '\0';
  1412.     m = dointerp(tmpbuf,tbsize,line," \t");
  1413.     if (!*m)
  1414.     return;
  1415.     while (*m == ' ' || *m == '\t') m++;
  1416.     for (s=tmpbuf,curmap=topmap; *s; s++) {
  1417.     ch = *s & 0177;
  1418.     if (s[1] == '+' && isdigit(s[2])) {
  1419.         s += 2;
  1420.         garbage = (*s & KM_GMASK) << KM_GSHIFT;
  1421.     }
  1422.     else
  1423.         garbage = 0;
  1424.     if (s[1]) {
  1425.         if ((curmap->km_type[ch] & KM_TMASK) == KM_STRING) {
  1426.         fputs(override,stdout) FLUSH;
  1427.         free(curmap->km_ptr[ch].km_str);
  1428.         curmap->km_ptr[ch].km_str = Nullch;
  1429.         }
  1430.         curmap->km_type[ch] = KM_KEYMAP + garbage;
  1431.         if (curmap->km_ptr[ch].km_km == Null(KEYMAP*))
  1432.         curmap->km_ptr[ch].km_km = newkeymap();
  1433.         curmap = curmap->km_ptr[ch].km_km;
  1434.     }
  1435.     else {
  1436.         if ((curmap->km_type[ch] & KM_TMASK) == KM_KEYMAP)
  1437.         fputs(override,stdout) FLUSH;
  1438.         else {
  1439.         curmap->km_type[ch] = KM_STRING + garbage;
  1440.         curmap->km_ptr[ch].km_str = savestr(m);
  1441.         }
  1442.     }
  1443.     }
  1444. }
  1445.  
  1446. KEYMAP*
  1447. newkeymap()
  1448. {
  1449.     register int i;
  1450.     register KEYMAP *map;
  1451.  
  1452. #ifndef lint
  1453.     map = (KEYMAP*)safemalloc(sizeof(KEYMAP));
  1454. #else
  1455.     map = Null(KEYMAP*);
  1456. #endif lint
  1457.     for (i=127; i>=0; --i) {
  1458.     map->km_ptr[i].km_km = Null(KEYMAP*);
  1459.     map->km_type[i] = KM_NOTHIN;
  1460.     }
  1461.     return map;
  1462. }
  1463.  
  1464. void
  1465. show_macros()
  1466. {
  1467.     char prebuf[64];
  1468.  
  1469.     if (topmap != Null(KEYMAP*)) {
  1470.     print_lines("Macros:\n",STANDOUT);
  1471.     *prebuf = '\0';
  1472.     show_keymap(topmap,prebuf);
  1473.     }
  1474. }
  1475.  
  1476. void
  1477. show_keymap(curmap,prefix)
  1478. register KEYMAP *curmap;
  1479. char *prefix;
  1480. {
  1481.     register int i;
  1482.     register char *next = prefix + strlen(prefix);
  1483.     register int kt;
  1484.  
  1485.     for (i=0; i<128; i++) {
  1486.     if (kt = curmap->km_type[i]) {
  1487.         if (i < ' ')
  1488.         sprintf(next,"^%c",i+64);
  1489.         else if (i == ' ')
  1490.         strcpy(next,"\\040");
  1491.         else if (i == 127)
  1492.         strcpy(next,"^?");
  1493.         else
  1494.         sprintf(next,"%c",i);
  1495.         if ((kt >> KM_GSHIFT) & KM_GMASK) {
  1496.         sprintf(cmd_buf,"+%d", (kt >> KM_GSHIFT) & KM_GMASK);
  1497.         strcat(next,cmd_buf);
  1498.         }
  1499.         switch (kt & KM_TMASK) {
  1500.         case KM_NOTHIN:
  1501.         sprintf(cmd_buf,"%s    %c\n",prefix,i);
  1502.         print_lines(cmd_buf,NOMARKING);
  1503.         break;
  1504.         case KM_KEYMAP:
  1505.         show_keymap(curmap->km_ptr[(char)i].km_km, prefix);
  1506.         break;
  1507.         case KM_STRING:
  1508.         sprintf(cmd_buf,"%s    %s\n",prefix,curmap->km_ptr[i].km_str);
  1509.         print_lines(cmd_buf,NOMARKING);
  1510.         break;
  1511.         case KM_BOGUS:
  1512.         sprintf(cmd_buf,"%s    BOGUS\n",prefix);
  1513.         print_lines(cmd_buf,STANDOUT);
  1514.         break;
  1515.         }
  1516.     }
  1517.     }
  1518. }
  1519.  
  1520. #endif
  1521.  
  1522. /* routine to pass to tputs */
  1523.  
  1524. char
  1525. putchr(ch)
  1526. register char ch;
  1527. {
  1528.     putchar(ch);
  1529. #ifdef lint
  1530.     ch = Null(char);
  1531.     ch = ch;
  1532. #endif
  1533.     return((char) 0);
  1534. }
  1535.  
  1536. /* input the 2nd and succeeding characters of a multi-character command */
  1537. /* returns TRUE if command finished, FALSE if they rubbed out first character */
  1538.  
  1539. bool
  1540. finish_command(donewline)
  1541. int donewline;
  1542. {
  1543.     register char *s;
  1544.     register bool quoteone = FALSE;
  1545.  
  1546.     s = buf;
  1547.     if (s[1] != FINISHCMD)        /* someone faking up a command? */
  1548.     return TRUE;
  1549.     do {
  1550.       top:
  1551.     if (*s < ' ') {
  1552.         putchar('^');
  1553.         putchar(*s | 64);
  1554.     }
  1555.     else if (*s == '\177') {
  1556.         putchar('^');
  1557.         putchar('?');
  1558.     }
  1559.     else
  1560.         putchar(*s);        /* echo previous character */
  1561.     s++;
  1562. re_read:
  1563.     fflush(stdout);
  1564.     getcmd(s);
  1565.     if (quoteone) {
  1566.         quoteone = FALSE;
  1567.         continue;
  1568.     }
  1569.     if (errno || *s == Ctl('l')) {
  1570.         *s = Ctl('r');        /* force rewrite on CONT */
  1571.     }
  1572.     if (*s == '\033') {        /* substitution desired? */
  1573. #ifdef ESCSUBS
  1574.         char tmpbuf[4], *cpybuf;
  1575.  
  1576.         tmpbuf[0] = '%';
  1577.         read_tty(&tmpbuf[1],1);
  1578. #ifdef RAWONLY
  1579.         tmpbuf[1] &= 0177;
  1580. #endif
  1581.         tmpbuf[2] = '\0';
  1582.         if (tmpbuf[1] == 'h') {
  1583.         (void) help_subs();
  1584.         *s = '\0';
  1585.         reprint();
  1586.         goto re_read;
  1587.         }
  1588.         else if (tmpbuf[1] == '\033') {
  1589.         *s = '\0';
  1590.         cpybuf = savestr(buf);
  1591.         interp(buf, (sizeof buf), cpybuf);
  1592.         free(cpybuf);
  1593.         s = buf + strlen(buf);
  1594.         reprint();
  1595.         goto re_read;
  1596.         }
  1597.         else {
  1598.         interp(s,(sizeof buf) - (s-buf),tmpbuf);
  1599.         fputs(s,stdout);
  1600.         s += strlen(s);
  1601.         }
  1602.         goto re_read;
  1603. #else
  1604.         notincl("^[");
  1605.         *s = '\0';
  1606.         reprint();
  1607.         goto re_read;
  1608. #endif
  1609.     }
  1610.     else if (*s == ERASECH) {    /* they want to rubout a char? */
  1611.         rubout();
  1612.         s--;            /* discount the char rubbed out */
  1613.         if (*s < ' ' || *s == '\177')
  1614.         rubout();
  1615.         if (s == buf) {        /* entire string gone? */
  1616.         fflush(stdout);        /* return to single char command mode */
  1617.         return FALSE;
  1618.         }
  1619.         else
  1620.         goto re_read;
  1621.     }
  1622.     else if (*s == KILLCH) {    /* wipe out the whole line? */
  1623.         while (s-- != buf) {    /* emulate that many ERASEs */
  1624.         rubout();
  1625.         if (*s < ' ' || *s == '\177')
  1626.             rubout();
  1627.         }
  1628.         fflush(stdout);
  1629.         return FALSE;        /* return to single char mode */
  1630.     }
  1631. #ifdef WORDERASE
  1632.     else if (*s == Ctl('w')) {    /* wipe out one word? */
  1633.         *s-- = ' ';
  1634.         while (!isspace(*s) || isspace(s[1])) {
  1635.         rubout();
  1636.         if (s-- == buf) {
  1637.             fflush(stdout);
  1638.             return FALSE;    /* return to single char mode */
  1639.         }
  1640.         if (*s < ' ' || *s == '\177')
  1641.             rubout();
  1642.         }
  1643.         s++;
  1644.         goto re_read;
  1645.     }
  1646. #endif
  1647.     else if (*s == Ctl('r')) {
  1648.         *s = '\0';
  1649.         reprint();
  1650.         goto re_read;
  1651.     }
  1652.     else if (*s == Ctl('v')) {
  1653.         putchar('^');
  1654.         backspace();
  1655.         fflush(stdout);
  1656.         getcmd(s);
  1657.         goto top;
  1658.     }
  1659.     else if (*s == '\\') {
  1660.         quoteone = TRUE;
  1661.     }
  1662.     } while (*s != '\n');        /* till a newline (not echoed) */
  1663.     *s = '\0';                /* terminate the string nicely */
  1664.     if (donewline)
  1665.     putchar('\n') FLUSH;
  1666.     return TRUE;            /* say we succeeded */
  1667. }
  1668.  
  1669. /* discard any characters typed ahead */
  1670.  
  1671. void
  1672. eat_typeahead()
  1673. {
  1674. #ifdef PUSHBACK
  1675.     if (!typeahead && nextin==nextout)    /* cancel only keyboard stuff */
  1676. #else
  1677.     if (!typeahead)
  1678. #endif
  1679.     {
  1680. #ifdef PENDING
  1681.     while (input_pending())
  1682.         read_tty(buf,sizeof(buf));
  1683. #else /* this is probably v7 */
  1684.     ioctl(_tty_ch,TIOCSETP,&_tty);
  1685. #endif
  1686.     }
  1687. }
  1688.  
  1689. void
  1690. settle_down()
  1691. {
  1692.     dingaling();
  1693.     fflush(stdout);
  1694.     sleep(1);
  1695. #ifdef PUSHBACK
  1696.     nextout = nextin;            /* empty circlebuf */
  1697. #endif
  1698.     eat_typeahead();
  1699. }
  1700.  
  1701. #ifdef PUSHBACK
  1702. /* read a character from the terminal, with multi-character pushback */
  1703.  
  1704. int
  1705. read_tty(addr,size)
  1706. char *addr;
  1707. int size;
  1708. {
  1709.     if (nextout != nextin) {
  1710.     *addr = circlebuf[nextout++];
  1711.     nextout %= PUSHSIZE;
  1712.     return 1;
  1713.     }
  1714.     else {
  1715.     size = read(0,addr,size);
  1716. #ifdef RAWONLY
  1717.     *addr &= 0177;
  1718. #endif
  1719.     return size;
  1720.     }
  1721. }
  1722.  
  1723. #ifdef PENDING
  1724. #if ! defined (FIONREAD) && ! defined (RDCHK)
  1725. int
  1726. circfill()
  1727. {
  1728.     register int Howmany = read(devtty,circlebuf+nextin,1);
  1729.  
  1730.     if (Howmany) {
  1731.     nextin += Howmany;
  1732.     nextin %= PUSHSIZE;
  1733.     }
  1734.     return Howmany;
  1735. }
  1736. #endif PENDING
  1737. #endif FIONREAD
  1738.  
  1739. void
  1740. pushchar(c)
  1741. char c;
  1742. {
  1743.     nextout--;
  1744.     if (nextout < 0)
  1745.     nextout = PUSHSIZE - 1;
  1746.     if (nextout == nextin) {
  1747.     fputs("\npushback buffer overflow\n",stdout) FLUSH;
  1748.     sig_catcher(0);
  1749.     }
  1750.     circlebuf[nextout] = c;
  1751. }
  1752.  
  1753. #else PUSHBACK
  1754. #ifndef read_tty
  1755. /* read a character from the terminal, with hacks for O_NDELAY reads */
  1756.  
  1757. int
  1758. read_tty(addr,size)
  1759. char *addr;
  1760. int size;
  1761. {
  1762.     if (is_input) {
  1763.     *addr = pending_ch;
  1764.     is_input = FALSE;
  1765.     return 1;
  1766.     }
  1767.     else {
  1768.     size = read(0,addr,size);
  1769. #ifdef RAWONLY
  1770.     *addr &= 0177;
  1771. #endif
  1772.     return size;
  1773.     }
  1774. }
  1775. #endif read_tty
  1776. #endif PUSHBACK
  1777.  
  1778. /* print an underlined string, one way or another */
  1779.  
  1780. void
  1781. underprint(s)
  1782. register char *s;
  1783. {
  1784.     assert(UC);
  1785.     if (*UC) {        /* char by char underline? */
  1786.     while (*s) {
  1787.         if (*s < ' ') {
  1788.         putchar('^');
  1789.         backspace();/* back up over it */
  1790.         underchar();/* and do the underline */
  1791.         putchar(*s+64);
  1792.         backspace();/* back up over it */
  1793.         underchar();/* and do the underline */
  1794.         }
  1795.         else {
  1796.         putchar(*s);
  1797.         backspace();/* back up over it */
  1798.         underchar();/* and do the underline */
  1799.         }
  1800.         s++;
  1801.     }
  1802.     }
  1803.     else {        /* start and stop underline */
  1804.     underline();    /* start underlining */
  1805.     while (*s) {
  1806.         if (*s < ' ') {
  1807.         putchar('^');
  1808.         putchar(*s+64);
  1809.         }
  1810.         else
  1811.         putchar(*s);
  1812.         s++;
  1813.     }
  1814.     un_underline();    /* stop underlining */
  1815.     }
  1816. }
  1817.  
  1818. /* keep screen from flashing strangely on magic cookie terminals */
  1819.  
  1820. #ifdef NOFIREWORKS
  1821. void
  1822. no_sofire()
  1823. {
  1824.     if (*UP && *SE) {        /* should we disable fireworks? */
  1825.     putchar('\n');
  1826.     un_standout();
  1827.     up_line();
  1828.     carriage_return();
  1829.     }
  1830. }
  1831.  
  1832. void
  1833. no_ulfire()
  1834. {
  1835.     if (*UP && *US) {        /* should we disable fireworks? */
  1836.     putchar('\n');
  1837.     un_underline();
  1838.     up_line();
  1839.     carriage_return();
  1840.     }
  1841. }
  1842. #endif
  1843.  
  1844. /* get a character into a buffer */
  1845.  
  1846. void
  1847. getcmd(whatbuf)
  1848. register char *whatbuf;
  1849. {
  1850. #ifdef PUSHBACK
  1851.     register KEYMAP *curmap;
  1852.     register int i;
  1853.     bool no_macros; 
  1854.     int times = 0;            /* loop detector */
  1855.     char scrchar;
  1856.  
  1857. tryagain:
  1858.     curmap = topmap;
  1859.     no_macros = (whatbuf != buf && nextin == nextout); 
  1860. #endif
  1861.     for (;;) {
  1862.     int_count = 0;
  1863.     errno = 0;
  1864.     if (read_tty(whatbuf,1) < 0)
  1865.         if (!errno)
  1866.             errno = EINTR;
  1867.         else {
  1868.         perror(readerr);
  1869.         sig_catcher(0);
  1870.     }
  1871. #ifdef PUSHBACK
  1872.     if (*whatbuf & 0200 || no_macros) {
  1873.         *whatbuf &= 0177;
  1874.         goto got_canonical;
  1875.     }
  1876.     if (curmap == Null(KEYMAP*))
  1877.         goto got_canonical;
  1878.     for (i = (curmap->km_type[*whatbuf] >> KM_GSHIFT) & KM_GMASK; i; --i){
  1879.         read_tty(&scrchar,1);
  1880.     }
  1881.     switch (curmap->km_type[*whatbuf] & KM_TMASK) {
  1882.     case KM_NOTHIN:            /* no entry? */
  1883.         if (curmap == topmap)    /* unmapped canonical */
  1884.         goto got_canonical;
  1885.         settle_down();
  1886.         goto tryagain;
  1887.     case KM_KEYMAP:            /* another keymap? */
  1888.         curmap = curmap->km_ptr[*whatbuf].km_km;
  1889.         assert(curmap != Null(KEYMAP*));
  1890.         break;
  1891.     case KM_STRING:            /* a string? */
  1892.         pushstring(curmap->km_ptr[*whatbuf].km_str);
  1893.         if (++times > 20) {        /* loop? */
  1894.         fputs("\nmacro loop?\n",stdout);
  1895.         settle_down();
  1896.         }
  1897.         no_macros = FALSE;
  1898.         goto tryagain;
  1899.     }
  1900. #else
  1901. #ifdef RAWONLY
  1902.     *whatbuf &= 0177;
  1903. #endif
  1904.     break;
  1905. #endif
  1906.     }
  1907.  
  1908. got_canonical:
  1909. #ifndef TERMIO
  1910.     if (*whatbuf == '\r')
  1911.     *whatbuf = '\n';
  1912. #endif
  1913.     if (whatbuf == buf)
  1914.     whatbuf[1] = FINISHCMD;        /* tell finish_command to work */
  1915. }
  1916.  
  1917. #ifdef PUSHBACK
  1918. void
  1919. pushstring(str)
  1920. char *str;
  1921. {
  1922.     register int i;
  1923.     char tmpbuf[PUSHSIZE];
  1924.     register char *s = tmpbuf;
  1925.  
  1926.     assert(str != Nullch);
  1927.     interp(s,PUSHSIZE,str);
  1928.     for (i = strlen(s)-1; i >= 0; --i) {
  1929.     s[i] ^= 0200; 
  1930.     pushchar(s[i]);
  1931.     }
  1932. }
  1933. #endif
  1934.  
  1935. int
  1936. get_anything()
  1937. {
  1938.     char tmpbuf[2];
  1939.  
  1940. reask_anything:
  1941.     unflush_output();            /* disable any ^O in effect */
  1942.     standout();
  1943. #ifdef VERBOSE
  1944.     IF(verbose)
  1945.     fputs("[Type space to continue] ",stdout);
  1946.     ELSE
  1947. #endif
  1948. #ifdef TERSE
  1949.     fputs("[MORE] ",stdout);
  1950. #endif
  1951.     un_standout();
  1952.     fflush(stdout);
  1953.     eat_typeahead();
  1954.     if (int_count) {
  1955.     return -1;
  1956.     }
  1957.     collect_subjects();            /* loads subject cache until */
  1958.                     /* input is pending */
  1959.     getcmd(tmpbuf);
  1960.     if (errno || *tmpbuf == '\f') {
  1961.     putchar('\n') FLUSH;        /* if return from stop signal */
  1962.     goto reask_anything;        /* give them a prompt again */
  1963.     }
  1964.     if (*tmpbuf == 'h') {
  1965. #ifdef VERBOSE
  1966.     IF(verbose)
  1967.         fputs("\nType q to quit or space to continue.\n",stdout) FLUSH;
  1968.     ELSE
  1969. #endif
  1970. #ifdef TERSE
  1971.         fputs("\nq to quit, space to continue.\n",stdout) FLUSH;
  1972. #endif
  1973.     goto reask_anything;
  1974.     }
  1975.     else if (*tmpbuf != ' ' && *tmpbuf != '\n') {
  1976.     carriage_return();
  1977.     erase_eol();    /* erase the prompt */
  1978.     carriage_return();
  1979.     return *tmpbuf == 'q' ? -1 : *tmpbuf;
  1980.     }
  1981.     if (*tmpbuf == '\n') {
  1982.     page_line = LINES - 1;
  1983.     carriage_return();
  1984.     erase_eol();
  1985.     carriage_return();
  1986.     }
  1987.     else {
  1988.     page_line = 1;
  1989.     if (erase_screen)        /* -e? */
  1990.         clear();            /* clear screen */
  1991.     else {
  1992.         carriage_return();
  1993.         erase_eol();        /* erase the prompt */
  1994.         carriage_return();
  1995.     }
  1996.     }
  1997.     return 0;
  1998. }
  1999.  
  2000. void
  2001. in_char(prompt, newmode)
  2002. char *prompt;
  2003. char newmode;
  2004. {
  2005.     char oldmode = mode;
  2006.  
  2007. reask_in_char:
  2008.     unflush_output();            /* disable any ^O in effect */
  2009.     fputs(prompt,stdout);
  2010.     fflush(stdout);
  2011.     eat_typeahead();
  2012.     mode = newmode;
  2013.     getcmd(buf);
  2014.     if (errno || *buf == '\f') {
  2015.     putchar('\n') FLUSH;        /* if return from stop signal */
  2016.     goto reask_in_char;        /* give them a prompt again */
  2017.     }
  2018.     mode = oldmode;
  2019. }
  2020.  
  2021. int
  2022. print_lines(what_to_print,hilite)
  2023. char *what_to_print;
  2024. int hilite;
  2025. {
  2026.     register char *s;
  2027.     register int i;
  2028.  
  2029.     if (page_line < 0)            /* they do not want to see this? */
  2030.     return -1;
  2031.     for (s=what_to_print; *s; ) {
  2032.     if (page_line >= LINES || int_count) {
  2033.         if (i = -1, int_count || (i = get_anything())) {
  2034.         page_line = -1;        /* disable further print_lines */
  2035.         return i;
  2036.         }
  2037.     }
  2038.     page_line++;
  2039.     if (hilite == STANDOUT) {
  2040. #ifdef NOFIREWORKS
  2041.         if (erase_screen)
  2042.         no_sofire();
  2043. #endif
  2044.         standout();
  2045.     }
  2046.     else if (hilite == UNDERLINE) {
  2047. #ifdef NOFIREWORKS
  2048.         if (erase_screen)
  2049.         no_ulfire();
  2050. #endif
  2051.         underline();
  2052.     }
  2053.     for (i=0; i<COLS; i++) {
  2054.         if (!*s)
  2055.         break;
  2056.         if (*s >= ' ')
  2057.         putchar(*s);
  2058.         else if (*s == '\t') {
  2059.         putchar(*s);
  2060.         i = ((i+8) & ~7) - 1; 
  2061.         }
  2062.         else if (*s == '\n') {
  2063.         i = 32000;
  2064.         }
  2065.         else {
  2066.         i++;
  2067.         putchar('^');
  2068.         putchar(*s + 64);
  2069.         }
  2070.         s++;
  2071.     }
  2072.     if (i) {
  2073.         if (hilite == STANDOUT)
  2074.         un_standout();
  2075.         else if (hilite == UNDERLINE)
  2076.         un_underline();
  2077.         if (AM && i == COLS)
  2078.         fflush(stdout);
  2079.         else
  2080.         putchar('\n') FLUSH;
  2081.     }
  2082.     }
  2083.     return 0;
  2084. }
  2085.  
  2086. void
  2087. page_init()
  2088. {
  2089.     page_line = 1;
  2090.     if (erase_screen)
  2091.     clear();
  2092.     else
  2093.     putchar('\n') FLUSH;
  2094. }
  2095.  
  2096. void
  2097. pad(num)
  2098. int num;
  2099. {
  2100.     register int i;
  2101.  
  2102.     for (i = num; i; --i)
  2103.     putchar(PC);
  2104.     fflush(stdout);
  2105. }
  2106.  
  2107. /* echo the command just typed */
  2108.  
  2109. #ifdef VERIFY
  2110. void
  2111. printcmd()
  2112. {
  2113.     if (verify && buf[1] == FINISHCMD) {
  2114.     if (*buf < ' ') {
  2115.         putchar('^');
  2116.         putchar(*buf | 64);
  2117.         backspace();
  2118.         backspace();
  2119.     }
  2120.     else {
  2121.         putchar(*buf);
  2122.         backspace();
  2123.     }
  2124.     fflush(stdout);
  2125.     }
  2126. }
  2127. #endif
  2128.  
  2129. void
  2130. rubout()
  2131. {
  2132.     backspace();            /* do the old backspace, */
  2133.     putchar(' ');            /*   space, */
  2134.     backspace();            /*     backspace trick */
  2135. }
  2136.  
  2137. void
  2138. reprint()
  2139. {
  2140.     register char *s;
  2141.  
  2142.     fputs("^R\n",stdout) FLUSH;
  2143.     for (s = buf; *s; s++) {
  2144.     if (*s < ' ') {
  2145.         putchar('^');
  2146.         putchar(*s | 64);
  2147.     }
  2148.     else
  2149.         putchar(*s);
  2150.     }
  2151. }
  2152.  
  2153. #ifdef CLEAREOL
  2154. void
  2155. home_cursor()
  2156. {
  2157.     char *tgoto();
  2158.  
  2159.     if (!*HO) {            /* no home sequence? */
  2160.     if (!*CM) {        /* no cursor motion either? */
  2161.         fputs ("\n\n\n", stdout);
  2162.         return;        /* forget it. */
  2163.     }
  2164.     tputs (tgoto (CM, 0, 0), 1, putchr);    /* go to home via CM */
  2165.     return;
  2166.     }
  2167.     else {            /* we have home sequence */
  2168.     tputs (HO, 1, putchr);    /* home via HO */
  2169.     }
  2170. }
  2171. #endif CLEAREOL
  2172.  
  2173.  
  2174. void
  2175. line_col_calcs()
  2176. {
  2177.      if (LINES > 0) {            /* is this a crt? */
  2178.       if ((!initlines) || (!initlines_specified))
  2179.            /* no -i or unreasonable value for initlines */
  2180.            if (ospeed >= B9600)     /* whole page at >= 9600 baud */
  2181.             initlines = LINES;
  2182.            else if (ospeed >= B4800)/* 16 lines at 4800 */
  2183.             initlines = 16;
  2184.            else            /* otherwise just header */
  2185.             initlines = 8;
  2186.      }
  2187.      else {                /* not a crt */
  2188.       LINES = 30000;        /* so don't page */
  2189.       CL = "\n\n";            /* put a couple of lines between */
  2190.       if ((!initlines) || (!initlines_specified))
  2191.            /* make initlines reasonable */
  2192.            initlines = 8;
  2193.      }
  2194.      if (COLS <= 0)
  2195.       COLS = 80;
  2196. }
  2197.  
  2198.  
  2199. #ifdef SIGWINCH
  2200. int
  2201. winch_catcher()
  2202. {
  2203.      /* Come here if window size change signal received */
  2204. #ifdef TIOCGWINSZ
  2205.      struct winsize ws;
  2206.  
  2207.      if (ioctl(0, TIOCGWINSZ, &ws) >= 0 && ws.ws_row > 0 && ws.ws_col > 0) {
  2208.           LINES = ws.ws_row;
  2209.           COLS = ws.ws_col;
  2210.           line_col_calcs();
  2211.      }
  2212. #else
  2213.      ???????
  2214.      /* Well, if SIGWINCH is defined, but TIOCGWINSZ isn't, there's    */
  2215.      /* almost certainly something wrong.  Figure it out for yourself, */
  2216.      /* because I don't know now to deal :-)                           */
  2217. #endif
  2218. }
  2219. #endif
  2220. !STUFFY!FUNK!
  2221. echo Extracting search.c
  2222. cat >search.c <<'!STUFFY!FUNK!'
  2223. /* $Header: search.c,v 4.3.2.2 90/03/22 23:05:31 sob Exp $
  2224.  *
  2225.  * $Log:    search.c,v $
  2226.  * Revision 4.3.2.2  90/03/22  23:05:31  sob
  2227.  * Fixes provided by Wayne Davison <drivax!davison>
  2228.  * 
  2229.  * Revision 4.3.2.1  90/03/17  17:46:29  sob
  2230.  * Added changes to insure that null search strings won't result in core dumps
  2231.  * on non-VAX computers.
  2232.  * 
  2233.  * Revision 4.3  85/05/01  11:50:16  lwall
  2234.  * Baseline for release with 4.3bsd.
  2235.  * 
  2236.  */
  2237.  
  2238. /* string search routines */
  2239.  
  2240. /*        Copyright (c) 1981,1980 James Gosling        */
  2241.  
  2242. /* Modified Aug. 12, 1981 by Tom London to include regular expressions
  2243.    as in ed.  RE stuff hacked over by jag to correct a few major problems,
  2244.    mainly dealing with searching within the buffer rather than copying
  2245.    each line to a separate array.  Newlines can now appear in RE's */
  2246.  
  2247. /* Ripped to shreds and glued back together to make a search package,
  2248.  * July 6, 1984, by Larry Wall. (If it doesn't work, it's probably my fault.)
  2249.  * Changes include:
  2250.  *    Buffer, window, and mlisp stuff gone.
  2251.  *    Translation tables reduced to 1 table.
  2252.  *    Expression buffer is now dynamically allocated.
  2253.  *    Character classes now implemented with a bitmap.
  2254.  */
  2255.  
  2256. #include "EXTERN.h"
  2257. #include "common.h"
  2258. #include "util.h"
  2259. #include "INTERN.h"
  2260. #include "search.h"
  2261.  
  2262. #ifndef BITSPERBYTE
  2263. #define BITSPERBYTE 8
  2264. #endif
  2265.  
  2266. #define BMAPSIZ (127 / BITSPERBYTE + 1)
  2267.  
  2268. /* meta characters in the "compiled" form of a regular expression */
  2269. #define    CBRA    2        /* \( -- begin bracket */
  2270. #define    CCHR    4        /* a vanilla character */
  2271. #define    CDOT    6        /* . -- match anything except a newline */
  2272. #define    CCL    8        /* [...] -- character class */
  2273. #define    NCCL    10        /* [^...] -- negated character class */
  2274. #define    CDOL    12        /* $ -- matches the end of a line */
  2275. #define    CEND    14        /* The end of the pattern */
  2276. #define    CKET    16        /* \) -- close bracket */
  2277. #define    CBACK    18        /* \N -- backreference to the Nth bracketed
  2278.                    string */
  2279. #define CIRC    20        /* ^ matches the beginning of a line */
  2280.  
  2281. #define WORD    32        /* matches word character \w */
  2282. #define NWORD    34        /* matches non-word characer \W */
  2283. #define WBOUND    36        /* matches word boundary \b */
  2284. #define NWBOUND    38        /* matches non-(word boundary) \B */
  2285.  
  2286. #define    STAR    01        /* * -- Kleene star, repeats the previous
  2287.                    REas many times as possible; the value
  2288.                    ORs with the other operator types */
  2289.  
  2290. #define ASCSIZ 0200
  2291. typedef char    TRANSTABLE[ASCSIZ];
  2292.  
  2293. static    TRANSTABLE trans = {
  2294. 0000,0001,0002,0003,0004,0005,0006,0007,
  2295. 0010,0011,0012,0013,0014,0015,0016,0017,
  2296. 0020,0021,0022,0023,0024,0025,0026,0027,
  2297. 0030,0031,0032,0033,0034,0035,0036,0037,
  2298. 0040,0041,0042,0043,0044,0045,0046,0047,
  2299. 0050,0051,0052,0053,0054,0055,0056,0057,
  2300. 0060,0061,0062,0063,0064,0065,0066,0067,
  2301. 0070,0071,0072,0073,0074,0075,0076,0077,
  2302. 0100,0101,0102,0103,0104,0105,0106,0107,
  2303. 0110,0111,0112,0113,0114,0115,0116,0117,
  2304. 0120,0121,0122,0123,0124,0125,0126,0127,
  2305. 0130,0131,0132,0133,0134,0135,0136,0137,
  2306. 0140,0141,0142,0143,0144,0145,0146,0147,
  2307. 0150,0151,0152,0153,0154,0155,0156,0157,
  2308. 0160,0161,0162,0163,0164,0165,0166,0167,
  2309. 0170,0171,0172,0173,0174,0175,0176,0177,
  2310. };
  2311. static bool folding = FALSE;
  2312.  
  2313. static int err;
  2314. static char *FirstCharacter;
  2315.  
  2316. void
  2317. search_init()
  2318. {
  2319. #ifdef UNDEF
  2320.     register int    i;
  2321.     
  2322.     for (i = 0; i < ASCSIZ; i++)
  2323.     trans[i] = i;
  2324. #else
  2325.     ;
  2326. #endif
  2327. }
  2328.  
  2329. void
  2330. init_compex(compex)
  2331. register COMPEX *compex;
  2332. {
  2333.     /* the following must start off zeroed */
  2334.  
  2335.     compex->eblen = 0;
  2336.     compex->brastr = Nullch;
  2337. }
  2338.  
  2339. void
  2340. free_compex(compex)
  2341. register COMPEX *compex;
  2342. {
  2343.     if (compex->eblen) {
  2344.     free(compex->expbuf);
  2345.     compex->eblen = 0;
  2346.     }
  2347.     if (compex->brastr) {
  2348.     free(compex->brastr);
  2349.     compex->brastr = Nullch;
  2350.     }
  2351. }
  2352.  
  2353. static char *gbr_str = Nullch;
  2354. static int gbr_siz = 0;
  2355.  
  2356. char *
  2357. getbracket(compex,n)
  2358. register COMPEX *compex;
  2359. int n;
  2360. {
  2361.     int length = compex->braelist[n] - compex->braslist[n];
  2362.  
  2363.     if (!compex->nbra || n > compex->nbra || !compex->braelist[n] || length<0)
  2364.     return nullstr;
  2365.     growstr(&gbr_str, &gbr_siz, length+1);
  2366.     safecpy(gbr_str, compex->braslist[n], length+1);
  2367.     return gbr_str;
  2368. }
  2369.  
  2370. void
  2371. case_fold(which)
  2372. int which;
  2373. {
  2374.     register int i;
  2375.  
  2376.     if (which != folding) {
  2377.     if (which) {
  2378.         for (i = 'A'; i <= 'Z'; i++)
  2379.         trans[i] = tolower(i);
  2380.     }
  2381.     else {
  2382.         for (i = 'A'; i <= 'Z'; i++)
  2383.         trans[i] = i;
  2384.     }
  2385.     folding = which;
  2386.     }
  2387. }
  2388.  
  2389. /* Compile the given regular expression into a [secret] internal format */
  2390.  
  2391. char *
  2392. compile (compex, strp, RE, fold)
  2393. register COMPEX *compex;
  2394. register char   *strp;
  2395. int RE;
  2396. int fold;
  2397. {
  2398.     register int c;
  2399.     register char  *ep;
  2400.     char   *lastep;
  2401.     char    bracket[NBRA],
  2402.        *bracketp;
  2403.     char **alt = compex->alternatives;
  2404.     char *retmes = "Badly formed search string";
  2405.  
  2406.     case_fold(compex->do_folding = fold);
  2407.     if (!compex->eblen) {
  2408.     compex->expbuf = safemalloc(84);
  2409.     compex->eblen = 80;
  2410.     }
  2411.     ep = compex->expbuf;        /* point at expression buffer */
  2412.     *alt++ = ep;            /* first alternative starts here */
  2413.     bracketp = bracket;            /* first bracket goes here */
  2414.     if (*strp == 0) {            /* nothing to compile? */
  2415.     if (*ep == 0)            /* nothing there yet? */
  2416.         return "Null search string";
  2417.     return Nullch;            /* just keep old expression */
  2418.     }
  2419.     compex->nbra = 0;            /* no brackets yet */
  2420.     lastep = 0;
  2421.     for (;;) {
  2422.     if (ep - compex->expbuf >= compex->eblen)
  2423.         grow_eb(compex);
  2424.     c = *strp++;            /* fetch next char of pattern */
  2425.     if (c == 0) {            /* end of pattern? */
  2426.         if (bracketp != bracket) {    /* balanced brackets? */
  2427. #ifdef VERBOSE
  2428.         retmes = "Unbalanced parens";
  2429. #endif
  2430.         goto cerror;
  2431.         }
  2432.         *ep++ = CEND;        /* terminate expression */
  2433.         *alt++ = 0;            /* terminal alternative list */
  2434.         /*
  2435.         compex->eblen = ep - compex->expbuf + 1;
  2436.         compex->expbuf = saferealloc(compex->expbuf,compex->eblen+4); */
  2437.         return Nullch;        /* return success */
  2438.     }
  2439.     if (c != '*')
  2440.         lastep = ep;
  2441.     if (!RE) {            /* just a normal search string? */
  2442.         *ep++ = CCHR;        /* everything is a normal char */
  2443.         *ep++ = c;
  2444.     }
  2445.     else                /* it is a regular expression */
  2446.         switch (c) {
  2447.  
  2448.         case '\\':        /* meta something */
  2449.             switch (c = *strp++) {
  2450.             case '(':
  2451.             if (compex->nbra >= NBRA) {
  2452. #ifdef VERBOSE
  2453.                 retmes = "Too many parens";
  2454. #endif
  2455.                 goto cerror;
  2456.             }
  2457.             *bracketp++ = ++compex->nbra;
  2458.             *ep++ = CBRA;
  2459.             *ep++ = compex->nbra;
  2460.             break;
  2461.             case '|':
  2462.             if (bracketp>bracket) {
  2463. #ifdef VERBOSE
  2464.                 retmes = "No \\| in parens";    /* Alas! */
  2465. #endif
  2466.                 goto cerror;
  2467.             }
  2468.             *ep++ = CEND;
  2469.             *alt++ = ep;
  2470.             break;
  2471.             case ')':
  2472.             if (bracketp <= bracket) {
  2473. #ifdef VERBOSE
  2474.                 retmes = "Unmatched right paren";
  2475. #endif
  2476.                 goto cerror;
  2477.             }
  2478.             *ep++ = CKET;
  2479.             *ep++ = *--bracketp;
  2480.             break;
  2481.             case 'w':
  2482.             *ep++ = WORD;
  2483.             break;
  2484.             case 'W':
  2485.             *ep++ = NWORD;
  2486.             break;
  2487.             case 'b':
  2488.             *ep++ = WBOUND;
  2489.             break;
  2490.             case 'B':
  2491.             *ep++ = NWBOUND;
  2492.             break;
  2493.             case '0': case '1': case '2': case '3': case '4':
  2494.             case '5': case '6': case '7': case '8': case '9':
  2495.             *ep++ = CBACK;
  2496.             *ep++ = c - '0';
  2497.             break;
  2498.             default:
  2499.             *ep++ = CCHR;
  2500.             if (c == '\0')
  2501.                 goto cerror;
  2502.             *ep++ = c;
  2503.             break;
  2504.             }
  2505.             break;
  2506.         case '.':
  2507.             *ep++ = CDOT;
  2508.             continue;
  2509.  
  2510.         case '*':
  2511.             if (lastep == 0 || *lastep == CBRA || *lastep == CKET
  2512.             || *lastep == CIRC
  2513.             || (*lastep&STAR)|| *lastep>NWORD)
  2514.             goto defchar;
  2515.             *lastep |= STAR;
  2516.             continue;
  2517.  
  2518.         case '^':
  2519.             if (ep != compex->expbuf && ep[-1] != CEND)
  2520.             goto defchar;
  2521.             *ep++ = CIRC;
  2522.             continue;
  2523.  
  2524.         case '$':
  2525.             if (*strp != 0 && (*strp != '\\' || strp[1] != '|'))
  2526.             goto defchar;
  2527.             *ep++ = CDOL;
  2528.             continue;
  2529.  
  2530.         case '[': {        /* character class */
  2531.             register int i;
  2532.             
  2533.             if (ep - compex->expbuf >= compex->eblen - BMAPSIZ)
  2534.             grow_eb(compex);    /* reserve bitmap */
  2535.             for (i = BMAPSIZ; i; --i)
  2536.             ep[i] = 0;
  2537.             
  2538.             if ((c = *strp++) == '^') {
  2539.             c = *strp++;
  2540.             *ep++ = NCCL;    /* negated */
  2541.             }
  2542.             else
  2543.             *ep++ = CCL;    /* normal */
  2544.             
  2545.             i = 0;        /* remember oldchar */
  2546.             do {
  2547.             if (c == '\0') {
  2548. #ifdef VERBOSE
  2549.                 retmes = "Missing ]";
  2550. #endif
  2551.                 goto cerror;
  2552.             }
  2553.             if (*strp == '-' && *(++strp))
  2554.                 i = *strp++;
  2555.             else
  2556.                 i = c;
  2557.             while (c <= i) {
  2558.                 ep[c / BITSPERBYTE] |= 1 << (c % BITSPERBYTE);
  2559.                 if (fold && isalpha(c))
  2560.                 ep[(c ^ 32) / BITSPERBYTE] |=
  2561.                     1 << ((c ^ 32) % BITSPERBYTE);
  2562.                     /* set the other bit too */
  2563.                 c++;
  2564.             }
  2565.             } while ((c = *strp++) != ']');
  2566.             ep += BMAPSIZ;
  2567.             continue;
  2568.         }
  2569.  
  2570.         defchar:
  2571.         default:
  2572.             *ep++ = CCHR;
  2573.             *ep++ = c;
  2574.         }
  2575.     }
  2576. cerror:
  2577.     compex->expbuf[0] = 0;
  2578.     compex->nbra = 0;
  2579.     return retmes;
  2580. }
  2581.  
  2582. void
  2583. grow_eb(compex)
  2584. register COMPEX *compex;
  2585. {
  2586.     compex->eblen += 80;
  2587.     compex->expbuf = saferealloc(compex->expbuf, (MEM_SIZE)compex->eblen + 4);
  2588. }
  2589.  
  2590. char *
  2591. execute (compex, addr)
  2592. register COMPEX *compex;
  2593. char *addr;
  2594. {
  2595.     register char *p1 = addr;
  2596.     register char *trt = trans;
  2597.     register int c;
  2598.  
  2599.     if (addr == Nullch || compex->expbuf == Nullch)
  2600.     return Nullch;
  2601.     if (compex->nbra) {            /* any brackets? */
  2602.     for (c = 0; c <= compex->nbra; c++)
  2603.         compex->braslist[c] = compex->braelist[c] = Nullch;
  2604.     if (compex->brastr)
  2605.         free(compex->brastr);
  2606.     compex->brastr = savestr(p1);    /* in case p1 is not static */
  2607.     p1 = compex->brastr;        /* ! */
  2608.     }
  2609.     case_fold(compex->do_folding);    /* make sure table is correct */
  2610.     FirstCharacter = p1;        /* for ^ tests */
  2611.     if (compex->expbuf[0] == CCHR && !compex->alternatives[1]) {
  2612.     c = trt[compex->expbuf[1]];    /* fast check for first character */
  2613.     do {
  2614.         if (trt[*p1] == c && advance (compex, p1, compex->expbuf))
  2615.         return p1;
  2616.         p1++;
  2617.     } while (*p1 && !err);
  2618.     return Nullch;
  2619.     }
  2620.     else {            /* regular algorithm */
  2621.     do {
  2622.         register char **alt = compex->alternatives;
  2623.         while (*alt) {
  2624.         if (advance (compex, p1, *alt++))
  2625.             return p1;
  2626.         }
  2627.         p1++;
  2628.     } while (*p1 && !err);
  2629.     return Nullch;
  2630.     }
  2631. }
  2632.  
  2633. /* advance the match of the regular expression starting at ep along the
  2634.    string lp, simulates an NDFSA */
  2635. bool
  2636. advance (compex, lp, ep)
  2637. register COMPEX *compex;
  2638. register char *ep;
  2639. register char *lp;
  2640. {
  2641.     register char *curlp;
  2642.     register char *trt = trans;
  2643.     register int i;
  2644.  
  2645.     while ((*ep & STAR) || *lp || *ep == CIRC || *ep == CKET)
  2646.     switch (*ep++) {
  2647.  
  2648.         case CCHR:
  2649.         if (trt[*ep++] != trt[*lp]) return FALSE;
  2650.         lp++;
  2651.         continue;
  2652.  
  2653.         case CDOT:
  2654.         if (*lp == '\n') return FALSE;
  2655.         lp++;
  2656.         continue;
  2657.  
  2658.         case CDOL:
  2659.         if (!*lp || *lp == '\n')
  2660.             continue;
  2661.         return FALSE;
  2662.  
  2663.         case CIRC:
  2664.         if (lp == FirstCharacter || lp[-1]=='\n')
  2665.             continue;
  2666.         return FALSE;
  2667.  
  2668.         case WORD:
  2669.         if (isalnum(*lp)) {
  2670.             lp++;
  2671.             continue;
  2672.         }
  2673.         return FALSE;
  2674.  
  2675.         case NWORD:
  2676.         if (!isalnum(*lp)) {
  2677.             lp++;
  2678.             continue;
  2679.         }
  2680.         return FALSE;
  2681.  
  2682.         case WBOUND:
  2683.         if ((lp == FirstCharacter || !isalnum(lp[-1])) !=
  2684.             (!*lp || !isalnum(*lp)) )
  2685.             continue;
  2686.         return FALSE;
  2687.  
  2688.         case NWBOUND:
  2689.         if ((lp == FirstCharacter || !isalnum(lp[-1])) ==
  2690.             (!*lp || !isalnum(*lp)))
  2691.             continue;
  2692.         return FALSE;
  2693.  
  2694.         case CEND:
  2695.         return TRUE;
  2696.  
  2697.         case CCL:
  2698.         if (cclass (ep, *lp, 1)) {
  2699.             ep += BMAPSIZ;
  2700.             lp++;
  2701.             continue;
  2702.         }
  2703.         return FALSE;
  2704.  
  2705.         case NCCL:
  2706.         if (cclass (ep, *lp, 0)) {
  2707.             ep += BMAPSIZ;
  2708.             lp++;
  2709.             continue;
  2710.         }
  2711.         return FALSE;
  2712.  
  2713.         case CBRA:
  2714.         compex->braslist[*ep++] = lp;
  2715.         continue;
  2716.  
  2717.         case CKET:
  2718.         i = *ep++;
  2719.         compex->braelist[i] = lp;
  2720.         compex->braelist[0] = lp;
  2721.         compex->braslist[0] = compex->braslist[i];
  2722.         continue;
  2723.  
  2724.         case CBACK:
  2725.         if (compex->braelist[i = *ep++] == 0) {
  2726.             fputs("bad braces\n",stdout) FLUSH;
  2727.             err = TRUE;
  2728.             return FALSE;
  2729.         }
  2730.         if (backref (compex, i, lp)) {
  2731.             lp += compex->braelist[i] - compex->braslist[i];
  2732.             continue;
  2733.         }
  2734.         return FALSE;
  2735.  
  2736.         case CBACK | STAR:
  2737.         if (compex->braelist[i = *ep++] == 0) {
  2738.             fputs("bad braces\n",stdout) FLUSH;
  2739.             err = TRUE;
  2740.             return FALSE;
  2741.         }
  2742.         curlp = lp;
  2743.         while (backref (compex, i, lp)) {
  2744.             lp += compex->braelist[i] - compex->braslist[i];
  2745.         }
  2746.         while (lp >= curlp) {
  2747.             if (advance (compex, lp, ep))
  2748.             return TRUE;
  2749.             lp -= compex->braelist[i] - compex->braslist[i];
  2750.         }
  2751.         continue;
  2752.  
  2753.         case CDOT | STAR:
  2754.         curlp = lp;
  2755.         while (*lp++ && lp[-1] != '\n');
  2756.         goto star;
  2757.  
  2758.         case WORD | STAR:
  2759.         curlp = lp;
  2760.         while (*lp++ && isalnum(lp[-1]));
  2761.         goto star;
  2762.  
  2763.         case NWORD | STAR:
  2764.         curlp = lp;
  2765.         while (*lp++ && !isalnum(lp[-1]));
  2766.         goto star;
  2767.  
  2768.         case CCHR | STAR:
  2769.         curlp = lp;
  2770.         while (*lp++ && trt[lp[-1]] == trt[*ep]);
  2771.         ep++;
  2772.         goto star;
  2773.  
  2774.         case CCL | STAR:
  2775.         case NCCL | STAR:
  2776.         curlp = lp;
  2777.         while (*lp++ && cclass (ep, lp[-1], ep[-1] == (CCL | STAR)));
  2778.         ep += BMAPSIZ;
  2779.         goto star;
  2780.  
  2781.     star:
  2782.         do {
  2783.             lp--;
  2784.             if (advance (compex, lp, ep))
  2785.             return TRUE;
  2786.         } while (lp > curlp);
  2787.         return FALSE;
  2788.  
  2789.         default:
  2790.         fputs("Badly compiled pattern\n",stdout) FLUSH;
  2791.         err = TRUE;
  2792.         return -1;
  2793.     }
  2794.     if (*ep == CEND || *ep == CDOL) {
  2795.         return TRUE;
  2796.     }
  2797.     return FALSE;
  2798. }
  2799.  
  2800. bool
  2801. backref (compex, i, lp)
  2802. register COMPEX *compex;
  2803. register int i;
  2804. register char *lp;
  2805. {
  2806.     register char *bp;
  2807.  
  2808.     bp = compex->braslist[i];
  2809.     while (*lp && *bp == *lp) {
  2810.     bp++;
  2811.     lp++;
  2812.     if (bp >= compex->braelist[i])
  2813.         return TRUE;
  2814.     }
  2815.     return FALSE;
  2816. }
  2817.  
  2818. bool
  2819. cclass (set, c, af)
  2820. register char  *set;
  2821. register int c;
  2822. {
  2823.     c &= 0177;
  2824. #if BITSPERBYTE == 8
  2825.     if (set[c >> 3] & 1 << (c & 7))
  2826. #else
  2827.     if (set[c / BITSPERBYTE] & 1 << (c % BITSPERBYTE))
  2828. #endif
  2829.     return af;
  2830.     return !af;
  2831. }
  2832. !STUFFY!FUNK!
  2833. echo Extracting artsrch.h
  2834. cat >artsrch.h <<'!STUFFY!FUNK!'
  2835. /* $Header: artsrch.h,v 4.3 85/05/01 11:35:55 lwall Exp $
  2836.  *
  2837.  * $Log:    artsrch.h,v $
  2838.  * Revision 4.3  85/05/01  11:35:55  lwall
  2839.  * Baseline for release with 4.3bsd.
  2840.  * 
  2841.  */
  2842.  
  2843. #ifndef NBRA
  2844. #include "search.h"
  2845. #endif
  2846.  
  2847. #ifdef ARTSEARCH
  2848.  
  2849. #define SRCH_ABORT 0
  2850. #define SRCH_INTR 1
  2851. #define SRCH_FOUND 2
  2852. #define SRCH_NOTFOUND 3
  2853. #define SRCH_DONE 4
  2854. #define SRCH_SUBJDONE 5
  2855. #define SRCH_ERROR 6
  2856. #endif
  2857.  
  2858. EXT char *lastpat INIT(nullstr);    /* last search pattern */
  2859. #ifdef ARTSEARCH
  2860.     EXT COMPEX sub_compex;        /* last compiled subject search */
  2861.     EXT COMPEX art_compex;        /* last compiled normal search */
  2862. #   ifdef CONDSUB
  2863.     EXT COMPEX *bra_compex INIT(&art_compex);
  2864.                     /* current compex with brackets */
  2865. #   endif
  2866.     EXT char art_howmuch;        /* search just the subjects */
  2867.     EXT bool art_doread;        /* search read articles? */
  2868. #endif
  2869.  
  2870. void    artsrch_init();
  2871. #ifdef ARTSEARCH
  2872.     int        art_search();
  2873.     bool    wanted();    /* return TRUE if current article matches pattern */
  2874. #endif
  2875. !STUFFY!FUNK!
  2876. echo ""
  2877. echo "End of kit 4 (of 9)"
  2878. cat /dev/null >kit4isdone
  2879. config=true
  2880. for iskit in 1 2 3 4 5 6 7 8 9 ; do
  2881.     if test -f kit${iskit}isdone; then
  2882.     echo "You have run kit ${iskit}."
  2883.     else
  2884.     echo "You still need to run kit ${iskit}."
  2885.     config=false
  2886.     fi
  2887. done
  2888. case $config in
  2889.     true)
  2890.     echo "You have run all your kits.  Please read README and then type Configure."
  2891.     chmod 755 Configure
  2892.     ;;
  2893. esac
  2894. : I do not append .signature, but someone might mail this.
  2895. exit
  2896.