home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume13 / vn.jan.88 / part05 / reader.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-01-30  |  15.4 KB  |  839 lines

  1. /*
  2. ** vn news reader.
  3. **
  4. ** reader.c - article reading interface - "more" like.
  5. **
  6. ** see copyright disclaimer / history in vn.c source file
  7. */
  8.  
  9. #include <stdio.h>
  10. #include <sys/types.h>
  11. #include "tty.h"
  12. #include "config.h"
  13. #include "tune.h"
  14. #include "head.h"
  15. #include "reader.h"
  16. #include "brk.h"
  17. #include "node.h"
  18. #include "page.h"
  19. #include "vn.h"
  20.  
  21. #define PERTAB 8    /* tab expansion factor */
  22. #define BACKTRACK 24
  23.  
  24. extern char *Printer,*Editor,*Mailer,*Poster,*Orgdir,*Savefile,*Savedir,*Ccfile;
  25. extern int L_allow;
  26. extern int C_allow;
  27. extern int Rot;
  28. extern int Headflag;
  29. extern int Digest;
  30. extern int More;
  31. extern char *No_msg;
  32. extern char *Roton_msg;
  33. extern char *Rotoff_msg;
  34. extern char *Hdon_msg;
  35. extern char *Hdoff_msg;
  36.  
  37. extern PAGE Page;
  38.  
  39. extern int (*Massage)();
  40. extern int (*Postfunc)();
  41. extern int (*Mailfunc)();
  42.  
  43. extern char Cxrtoi[], Cxitor[];
  44.  
  45. static FILE *Fpread;
  46. static char *Fname;
  47. static char *Lookahead;
  48. static int Rlines;
  49. static int Hlines;
  50. static long Rew_pos;
  51.  
  52. /*
  53.     readfile presents article:
  54.         fn = name of article.
  55.         sn - name of next article, NULL if last.
  56.         pages - pages to advance on return, if applicable
  57.     returns 0 for "continue", <0 for "quit"
  58.  
  59.     calls sig_set(BRK_READ / BRK_RFIN) around reading article.
  60. */
  61. readfile (fn,sn,pages)
  62. char *fn;
  63. char *sn;
  64. int *pages;
  65. {
  66.     ARTHEADER hdr;
  67.     FILE *fopen();
  68.     int lines,percent;
  69.     int i;
  70.     int top, bottom;
  71.     int step;
  72.     char c,  buf[RECLEN];
  73.     char lasave[RECLEN];
  74.     char pstr[24], dgname[48];
  75.     char getpgch(), *index(), *digest_extract(), *tgetstr();
  76.     char *any;
  77.     FILE *vns_aopen();
  78.     long ftell();
  79.  
  80.     Fname = fn;
  81.     *pages = 0;
  82.     step = FALSE;    /* Boolean; to indicate user input a <RET> (PG_STEP) */
  83.  
  84.     term_set(ERASE);
  85.     sig_set(BRK_READ,&Fpread);
  86.  
  87.     any = "any key to continue .... ";
  88.  
  89.     if (Digest)
  90.     {
  91.         lines = atoi(Fname);
  92.         if ((Fname = digest_extract(dgname,lines,&hdr,&Rew_pos)) == NULL)
  93.         {
  94.             rerrmsg("couldn't extract article %d from digest",lines);
  95.             printf(any);
  96.             getnoctl();
  97.             sig_set(BRK_RFIN);
  98.             return (0);
  99.         }
  100.         if ((Fpread = fopen(Fname,"r")) == NULL)
  101.         {
  102.             rerrmsg("couldn't open %s",Fname);
  103.             printf(any);
  104.             getnoctl();
  105.             sig_set(BRK_RFIN);
  106.             return (0);
  107.         }
  108.         fseek(Fpread,Rew_pos,0);
  109.     }
  110.     else
  111.     {
  112.         if ((Fpread = vns_aopen(atoi(Fname),&hdr)) == NULL)
  113.         {
  114.             rerrmsg("couldn't open article %s",Fname);
  115.             printf(any);
  116.             getnoctl();
  117.             sig_set(BRK_RFIN);
  118.             return (0);
  119.         }
  120.         Rew_pos = ftell(Fpread);
  121.     }
  122.  
  123.     Hlines = hdr.hlines;
  124.     printf (ANFORM,Fname,Cxrtoi[PG_HELP]);
  125.  
  126.     lines = 0;
  127.  
  128.     if (Headflag)
  129.     {
  130.         rewind(Fpread);
  131.         Rlines = 0;
  132.     }
  133.     else
  134.     {
  135.         /* use do_out to guard against control sequences */
  136.         Rlines = Hlines;
  137.         for (i=0; i < hdr.show_num; ++i)
  138.             lines += do_out((hdr.show)[i],L_allow-lines);
  139.         lines += do_out("",L_allow-lines);
  140.     }
  141.  
  142.     /* will return out of outer while loop */
  143.     Lookahead = NULL;
  144.     while (1)
  145.     {
  146.         /*
  147.         ** lines counts folded lines from do_out.
  148.         ** globals Hlines and Rlines refer to records.
  149.         ** If Lookahead is null after this loop, we've
  150.         ** hit EOF.
  151.         */
  152.         if (Lookahead != NULL && More && !step)
  153.         {
  154.             char *looktmp;
  155.  
  156.             /*
  157.             ** Save Lookahead because `do_out' nukes it.
  158.             ** Perhaps we could just use `printf' here
  159.             ** but for now we'll play it safe. - GKE 12/26/87
  160.             */
  161.             looktmp = Lookahead;
  162.             term_set(ERASE);
  163.             /* 
  164.             ** The following presents the last line of the
  165.             ** previous page in reversed video, as the first line
  166.             ** of the current page, `rn'-stylee.  Since `rn'
  167.             ** uses an option to enable/disable this, remove the
  168.             ** two `term_set's if not to your liking.
  169.             */
  170.             term_set(ONREVERSE);
  171.             do_out(lasave,1);
  172.             term_set(OFFREVERSE);
  173.             Lookahead = looktmp;
  174.         }
  175.         lines += do_out(Lookahead,L_allow-lines);
  176.         while (1)
  177.         {
  178.             if (Lookahead == NULL)
  179.             {
  180.                 if (fgets(buf,RECLEN-1,Fpread) == NULL)
  181.                     break;
  182.                 Lookahead = buf;
  183.                 if (Rot != 0 && Rlines >= Hlines)
  184.                     rot_line(buf);
  185.                 ++Rlines;
  186.             }
  187.             if (lines >= L_allow)
  188.                 break;
  189.             if (More)
  190.                 strcpy(lasave,Lookahead);
  191.             lines += do_out(Lookahead,L_allow-lines);
  192.         }
  193.  
  194.         if (Lookahead != NULL)
  195.         {
  196.             /*
  197.             ** calculation is truncated rather than rounded,
  198.             ** so we shouldn't get "100%".  Subtract 2 for
  199.             ** 1 line lookahead and empty line at beginning
  200.             ** of article.
  201.             */
  202.             if (Headflag)
  203.             {
  204.                 top = (Rlines-2)*100;
  205.                 bottom = hdr.lines + Hlines;
  206.             }
  207.             else
  208.             {
  209.                 top = (Rlines-Hlines-2)*100;
  210.                 bottom = hdr.lines;
  211.             }
  212.             /*
  213.             ** protect against division by zero -
  214.             ** shouldn't actually come up zero at this
  215.             ** point if vns_aopen is sane. 999 will let user
  216.             ** know the percentage is obviously wrong.
  217.             */
  218.             if (bottom != 0)
  219.                 percent = top/bottom;
  220.             else
  221.                 percent = 999;
  222.             sprintf (pstr,PAGE_MID,percent);
  223.         }
  224.         else
  225.         {
  226.             if (sn == NULL)
  227.                 strcpy (pstr,PAGE_END);
  228.             else
  229.             strcpy (pstr,PAGE_NEXT);
  230.         }
  231.         c = getpgch(pstr,&hdr);
  232.  
  233.         /*
  234.             handle user input:
  235.             CAUTION!!  return cases must close Fpread.
  236.         */
  237.         step = FALSE;
  238.         switch (c)
  239.         {
  240.         case PG_NEXT:
  241.             if (Digest)
  242.             {
  243.                 fclose (Fpread);
  244.                 unlink (Fname);
  245.             }
  246.             else
  247.                 vns_aclose (Fpread);
  248.             sig_set(BRK_RFIN);
  249.             return (0);
  250.         case PG_FLIP:
  251.             *pages = 1;    /* fall through */
  252.         case PG_QUIT:
  253.             if (Digest)
  254.             {
  255.                 fclose (Fpread);
  256.                 unlink (Fname);
  257.             }
  258.             else
  259.                 vns_aclose (Fpread);
  260.             sig_set(BRK_RFIN);
  261.             return (-1);
  262.         case PG_REWIND:
  263.             if (Headflag)
  264.             {
  265.                 Rlines = 0;
  266.                 rewind (Fpread);
  267.             }
  268.             else
  269.             {
  270.                 fseek (Fpread,Rew_pos,0);
  271.                 Rlines = Hlines;
  272.             }
  273.             Lookahead = NULL;
  274.             lines = 2 - RECBIAS;
  275.             break;
  276.         case PG_SEARCH:
  277.             searcher(buf);
  278.             lines = 2 - RECBIAS;
  279.             lines += do_out(buf,L_allow-lines);
  280.             break;
  281.         case PG_WIND:
  282.             fseek (Fpread,0L,2);
  283.             lines = 2 - RECBIAS;
  284.             Lookahead = NULL;
  285.             break;
  286.         case PG_STEP:
  287.             if (Lookahead == NULL)
  288.             {
  289.                 if (Digest)
  290.                 {
  291.                     fclose (Fpread);
  292.                     unlink (Fname);
  293.                 }
  294.                 else
  295.                     vns_aclose (Fpread);
  296.                 sig_set(BRK_RFIN);
  297.                 return (0);
  298.             }
  299.             lines = L_allow - 1;
  300.             step = TRUE;    /* Temporarily disable paging */
  301.             break;
  302.         default:
  303.             if (Lookahead == NULL)
  304.             {
  305.                 if (Digest)
  306.                 {
  307.                     fclose (Fpread);
  308.                     unlink (Fname);
  309.                 }
  310.                 else
  311.                     vns_aclose (Fpread);
  312.                 sig_set(BRK_RFIN);
  313.                 return (0);
  314.             }
  315.             lines = 2 - RECBIAS;
  316.             break;
  317.         }
  318.     }
  319. }
  320.  
  321. /*
  322.     getpgch prints prompt and gets command from user
  323.     handles "mail", "save" and "followup" internally
  324.     as well as flag resets.
  325. */
  326. static char
  327. getpgch(prompt,hdr)
  328. char *prompt;
  329. ARTHEADER *hdr;
  330. {
  331.     char c;
  332.     int ic;
  333.     term_set (ONREVERSE);
  334.     printf("%s\015",prompt);
  335.     term_set (OFFREVERSE);
  336.     while ((ic=getnoctl()) != EOF)
  337.     {
  338.         switch (c = Cxitor[ic])
  339.         {
  340.         case SETROT:
  341.             term_set (ZAP,0,PPR_MAX);
  342.             if (Rot == 0)
  343.             {
  344.                 Rot = 13;
  345.                 printf ("%s\n",Roton_msg);
  346.             }
  347.             else
  348.             {
  349.                 Rot = 0;
  350.                 printf ("%s\n",Rotoff_msg);
  351.             }
  352.             if (Lookahead != NULL && Rlines > Hlines)
  353.                 rot_line(Lookahead);
  354.             break;
  355.         case HEADTOG:
  356.             term_set (ZAP,0,PPR_MAX);
  357.             if (Headflag)
  358.             {
  359.                 Headflag = FALSE;
  360.                 printf ("%s\n",Hdoff_msg);
  361.             }
  362.             else
  363.             {
  364.                 Headflag = TRUE;
  365.                 printf ("%s\n",Hdon_msg);
  366.             }
  367.             break;
  368.         case PG_HELP:
  369.             term_set (ZAP,0,PPR_MAX);
  370.             help_rd ();
  371.             break;
  372.         case PG_REPLY:
  373.             mail (hdr);
  374.             break;
  375.         case PG_FOLLOW:
  376.             followup (hdr);
  377.             break;
  378.         case SAVE:
  379.             saver ();
  380.             break;
  381.         case PRINT:
  382.             printr ();
  383.             break;
  384.         default:
  385.             term_set (ZAP,0,PPR_MAX);
  386.             return (c);
  387.         }
  388.  
  389.         term_set (ONREVERSE);
  390.         printf("%s\015",prompt);
  391.         term_set (OFFREVERSE);
  392.     }
  393.     term_set (ZAP,0,PPR_MAX);
  394.     return (c);
  395. }
  396.  
  397. /*
  398.     save article.  Like its "session" counterpart, this loses storage
  399.     if the user specifies a new file, but it should not be significant
  400. */
  401. static
  402. saver ()
  403. {
  404.     char buf[RECLEN],msg[RECLEN],*str_store();
  405.  
  406.     user_str (buf,"save file ? ",0,Savefile);
  407.     if (buf[0] != '\0' && buf[0] != '|')
  408.         Savefile = str_store(buf);
  409.     if (save_art(Fname,buf,msg) != 0)
  410.         rerrmsg(msg);
  411.     else
  412.         printf("%s\n",msg);
  413. }
  414.  
  415. /*
  416.     invoke editor on new temp file, mail using reply line,
  417.     possibly first allowing user to overide the reply (not INLETTER)
  418. */
  419. static
  420. mail (hdr)
  421. ARTHEADER *hdr;
  422. {
  423.     char *new, fn[L_tmpnam], cmd [RECLEN+60], *rprompt ();
  424.     int i;
  425.     FILE *fp, *fopen();
  426.  
  427.     if (Massage != NULL)
  428.         (*Massage)(hdr);
  429.  
  430.     if (hdr->mail_err != NULL)
  431.     {
  432.         rerrmsg(hdr->mail_err);
  433.         return;
  434.     }
  435.  
  436.     tmpnam (fn);
  437.     if ((fp = fopen(fn,"w")) == NULL)
  438.     {
  439.         rerrmsg("can't open temp file, %s",fn);
  440.         return;
  441.     }
  442.  
  443.     for (i = 0; i < hdr->mail_num; ++i)
  444.         fprintf(fp,"%s\n",(hdr->mail)[i]);
  445.     fprintf(fp,"\n");
  446.  
  447.     fprintf(fp,"%s:\n",hdr->from);
  448.     edcopy (fp);
  449.     fclose (fp);
  450.  
  451.     tty_set (SAVEMODE);
  452.  
  453.     sprintf (cmd,"%s %s", Editor, fn);
  454.     chdir (Orgdir);
  455.     system (cmd);
  456.     vns_gset (Page.h.name);
  457.  
  458.     new = rprompt ("still want to mail it ? ",cmd);
  459.     if (new != NULL && (*new == 'y' || *new == 'Y'))
  460.     {
  461.         if (Mailfunc == NULL)
  462.         {
  463.             sprintf (cmd, hdr->mailcmd, fn);
  464.             system (cmd);
  465.             printf ("given to mailer\n");
  466.         }
  467.         else
  468.             (*Mailfunc)(hdr,fn);
  469.     }
  470.     else
  471.         printf ("not mailed\n");
  472.  
  473.     unlink (fn);
  474.  
  475.     tty_set (RESTORE);
  476.     term_set (RESTART);
  477. }
  478.  
  479. /*
  480.     post a followup article, invoking editor for user after creating
  481.     new temp file.  remove after posting.
  482. */
  483. static
  484. followup (hdr)
  485. ARTHEADER *hdr;
  486. {
  487.     char fn[L_tmpnam], *new, cmd [RECLEN], *rprompt();
  488.     int i;
  489.     FILE *f, *fopen();
  490.     char *rindex();
  491.  
  492.     if (hdr->post_err != NULL)
  493.     {
  494.         rerrmsg(hdr->post_err);
  495.         return;
  496.     }
  497.  
  498.     tmpnam (fn);
  499.     if ((f = fopen(fn,"w")) == NULL)
  500.     {
  501.         rerrmsg("can't open temp file, %s",fn);
  502.         return;
  503.     }
  504.  
  505.     for (i=0; i < hdr->post_num; ++i)
  506.         fprintf(f,"%s\n",(hdr->post)[i]);
  507.     fprintf(f,"\n");
  508.  
  509.     fprintf(f,"From article %s, by %s:\n", hdr->artid, hdr->from);
  510.         
  511.     edcopy (f);
  512.     fclose (f);
  513.     tty_set (SAVEMODE);
  514.     sprintf (cmd,"%s %s", Editor, fn);
  515.     chdir (Orgdir);
  516.     system (cmd);
  517.     vns_gset (Page.h.name);
  518.  
  519.     new = rprompt("still want to post it ? ",cmd);
  520.     if (new != NULL && (*new == 'y' || *new == 'Y'))
  521.     {
  522.         if (Postfunc == NULL)
  523.         {
  524.             sprintf (cmd, hdr->postcmd, fn);
  525.             system (cmd);
  526.             printf ("given to posting program\n");
  527.         }
  528.         else
  529.             (*Postfunc)(hdr,fn);
  530.         save_article (fn);
  531.     }
  532.     else
  533.         printf ("not posted\n");
  534.     unlink (fn);
  535.     tty_set (RESTORE);
  536.     term_set (RESTART);
  537. }
  538.  
  539. /*
  540.     get user buffer, return whitespace delimited token
  541.     buffer is allowed to overwrite prompt string.  This routine
  542.     should only be used when the terminal is in cooked mode.
  543.     In raw, use user_str().
  544. */
  545. static char *
  546. rprompt(s,buf)
  547. char *s,*buf;
  548. {
  549.     char *strtok();
  550.  
  551.     printf("%s",s);
  552.     fgets (buf,RECLEN-1,stdin);
  553.     return (strtok(buf," \t\n"));
  554. }
  555.  
  556. /*
  557.     edcopy copies article to file which user is editting for
  558.     a reply or followup, so it may be referenced.  It places
  559.     ED_MARK in the left hand margin.
  560. */
  561. static
  562. edcopy(fp)
  563. FILE *fp;
  564. {
  565.     long current;
  566.     char buf[RECLEN];
  567.  
  568.     /* save position, and seek to top of article */
  569.     current = ftell(Fpread);
  570.     fseek (Fpread,Rew_pos,0);
  571.  
  572.     /* if line already begins with ED_MARK, forget about the space */
  573.     while (fgets(buf,RECLEN-1,Fpread) != NULL)
  574.     {
  575.         if (buf[0] == ED_MARK)
  576.             fprintf(fp,"%c%s",ED_MARK,buf);
  577.         else
  578.             fprintf(fp,"%c %s",ED_MARK,buf);
  579.     }
  580.  
  581.     /* restore position */
  582.     fseek(Fpread,current,0);
  583. }
  584.  
  585. static
  586. rot_line (s)
  587. unsigned char *s;
  588. {
  589.     for ( ; *s != '\0'; ++s)
  590.     {
  591.         if (*s >= 'A' && *s <= 'Z')
  592.         {
  593.             *s += Rot;
  594.             if (*s > 'Z')
  595.                 *s -= 26;
  596.             continue;
  597.         }
  598.         if (*s >= 'a' && *s <= 'z')
  599.         {
  600.             *s += Rot;
  601.             if (*s > 'z')
  602.                 *s -= 26;
  603.         }
  604.     }
  605. }
  606.  
  607. /*
  608. ** output record.  folds record to terminal width on word boundaries,
  609. ** returning number of lines output.  If limit is reached, remainder
  610. ** of buffer waiting to be output is returned.  Processes several
  611. ** special characters:
  612. **    form-feed - return "lim" lines so we stop on that line
  613. **    tabs - counts "expanded" width
  614. **    backspace - assumes they work, -1 width unless in first col.
  615. **    bell - pass through with zero width
  616. **    newline - end of record.
  617. **    del - turns into '_'
  618. **    other control - 'A' - 1 added ('01' = ctl-A).  Makes escape = "[".
  619. **        (prevents "letter bombs" containing inappropriate control
  620. **            sequences for the terminal).
  621. **
  622. ** Sets Lookahead pointer to remainder of line or NULL.
  623. */
  624. static
  625. do_out(s,lim)
  626. char *s;
  627. int lim;
  628. {
  629.     int len,i;
  630.     char cs,*word,*start;
  631.  
  632.     Lookahead = NULL;
  633.     if (s == NULL)
  634.         return(0);
  635.     len = 0;
  636.     start = word = s;
  637.  
  638.     /*
  639.     ** NOTE: "normal" return is buried inside switch, at newline
  640.     ** ending record
  641.     */
  642.     for (i=0; i < lim; ++i)
  643.     {
  644.         for ( ; len < C_allow; ++s)
  645.         {
  646.             switch (*s)
  647.             {
  648.             case '\n':
  649.                 *s = '\0';    /* fall through */
  650.             case '\0':
  651.                 printf("%s\n",start);
  652.                 return(i+1);
  653.             case '\t':
  654.                 len = ((len/PERTAB)+1)*PERTAB;
  655.                 word = s;
  656.                 break;
  657.             case '\b':
  658.                 if (len > 0)
  659.                     --len;
  660.                 break;
  661.             case '\014':
  662.                 *s = ' ';
  663.                 i = lim-1;    /* fall through */
  664.             case ' ':
  665.                 word = s+1;
  666.                 ++len;
  667.                 break;
  668.             case '\177':
  669.                 *s = '_';
  670.                 ++len;
  671.                 break;
  672.             default:
  673.                 if (*s < ' ')
  674.                     *s += 'A' - 1;
  675.                 ++len;        /* fall through */
  676.             case '\07':
  677.                 break;
  678.             }
  679.         }
  680.         cs = *s;
  681.         *s = '\0';
  682.         if ((len = strlen(word)) < BACKTRACK)
  683.         {
  684.             *s = cs;
  685.             s = word;
  686.             cs = *s;
  687.             *s = '\0';
  688.         }
  689.         else
  690.             len = 0;
  691.         printf("%s\n",start);
  692.         start = s;
  693.         *s = cs;
  694.     }
  695.     Lookahead = start;
  696.     return(lim);
  697. }
  698.  
  699. static
  700. save_article(tempfname)
  701. char *tempfname;
  702. {
  703.     FILE *in, *out;
  704.     int c;
  705.     time_t timenow, time();
  706.     char *today, *ctime();
  707.  
  708.     if ((in = fopen(tempfname, "r")) == NULL)
  709.         return;
  710.     if ((out = fopen(Ccfile, "a")) == NULL)
  711.     {
  712.         fclose(in);
  713.         return;
  714.     }
  715.     timenow = time((time_t)0);
  716.     today = ctime(&timenow);
  717.     fprintf(out,"From vn %s",today);
  718.     while ((c=getc(in)) != EOF)
  719.         putc(c, out);
  720.     putc('\n', out);
  721.     fclose(in);
  722.     fclose(out);
  723.     printf ("a copy has been saved in %s\n", Ccfile);
  724. }
  725.  
  726. /*
  727.     send article to printer
  728. */
  729. static
  730. printr ()
  731. {
  732.     char cmd[RECLEN];
  733.     char fn[L_tmpnam];
  734.     long savepos;
  735.     FILE *f;
  736.  
  737.     tmpnam (fn);
  738.     if ((f = fopen(fn,"w")) == NULL)
  739.     {
  740.         rerrmsg("can't open temp file, %s",fn);
  741.         return;
  742.     }
  743.  
  744.     savepos = ftell(Fpread);
  745.     rewind(Fpread);
  746.     while (fgets(cmd,RECLEN-1,Fpread) != NULL)
  747.         fputs(cmd,f);
  748.     fclose(f);
  749.     fseek(Fpread,savepos,0);
  750.  
  751.     tty_set (SAVEMODE);
  752.     printf("Sent to printer\n");
  753.     sprintf (cmd,"%s %s 2>/dev/null",Printer,fn);
  754.     system (cmd);
  755.     tty_set (RESTORE);
  756.     unlink (fn);
  757. }
  758.  
  759. /*
  760.     search article for specified search pattern, returning the line on which
  761.         it is found in buf, a null buffer otherwise. The input file will
  762.         be positioned either after the line on which the pattern is
  763.         found, or unaaltered if match fails.
  764. */
  765. static
  766. searcher (buf)
  767. char    *buf;
  768. {
  769.     static char    searchstr[RECLEN] = "";
  770.     char    lasave[RECLEN];
  771.     char    *reg, *regcmp(), *regex();
  772.     long    current;
  773.     int    orlines;
  774.  
  775.     /* save position, then request search pattern */
  776.     current = ftell(Fpread);
  777.     orlines = Rlines;
  778.  
  779.     sprintf (lasave,SEARCHFORM,searchstr);
  780.     user_str (searchstr,lasave,0,searchstr);
  781.  
  782.     /* Now compile the search string */
  783.     if(( reg = regcmp(searchstr, (char *)0)) == NULL) {
  784.         rerrmsg("Invalid search string \"%s\"", searchstr);
  785.         *buf = '\0';
  786.         return;
  787.     }
  788.  
  789.     /* try lookahead buffer first */
  790.     if (Lookahead != NULL && regex(reg,Lookahead) != NULL)
  791.     {
  792.         strcpy(buf,Lookahead);
  793.         regfree(reg);
  794.         return;
  795.     }
  796.  
  797.     /* Lookahead can point into buf */
  798.     if (Lookahead != NULL)
  799.         strcpy(lasave,Lookahead);
  800.  
  801.     /* now start reading lines, rotating if necessary and do search */
  802.     while (fgets(buf,RECLEN-1,Fpread) != NULL)
  803.     {
  804.         if (Rot != 0 && Rlines >= Hlines)
  805.             rot_line(buf);
  806.         ++Rlines;
  807.         if( regex(reg, buf) != NULL ){    /* Got it */
  808.             rerrmsg("\n\tSkipping ....\n\n");
  809.             regfree(reg);
  810.             return;
  811.         }
  812.     }
  813.  
  814.     /* no dice, so restore position */
  815.     regfree(reg);
  816.     rerrmsg("Cannot find string \"%s\" in remainder of article", searchstr);
  817.     fseek(Fpread,current,0);
  818.     Rlines = orlines;
  819.     if (Lookahead != NULL)
  820.         strcpy(buf,lasave);
  821.     else
  822.         *buf = '\0';
  823. }
  824.  
  825. /*
  826. ** print a reverse video error message while reading an article.
  827. */
  828. static
  829. rerrmsg(s,a,b,c,d,e)
  830. char *s;
  831. long a,b,c,d,e;
  832. {
  833.     term_set (ONREVERSE);
  834.     printf("\n ");
  835.     printf(s,a,b,c,d,e);
  836.     printf(" \07\n");
  837.     term_set (OFFREVERSE);
  838. }
  839.