home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 31 / CDASC_31_1996_juillet_aout.iso / internet / rnr214.zip / RNRART.PAS < prev    next >
Pascal/Delphi Source File  |  1996-01-30  |  20KB  |  788 lines

  1. unit rnrart;
  2.  
  3. {
  4.  
  5. rnrart.pas - rnr article-reading code
  6.  
  7. }
  8.  
  9. {$I rnr-def.pas}
  10.  
  11. interface
  12.  
  13. {
  14. uses dos,crt,rnrglob,genericf,rnrfunc,rnrio,rnrproc,rnrkill,
  15.   rnrmous,rnrfile,rnrcrea
  16. }
  17.  
  18. uses rnrglob,rnrconf,genericf,rnrfunc,rnrio,rnrproc
  19.  
  20. {$ifdef charset}
  21. ,rnrchar
  22. {$endif};
  23.  
  24. const
  25.   yestoscreen=true;
  26.   notoscreen=false;
  27.  
  28.   yesfullheaders=true;
  29.   nofullheaders=false;
  30.  
  31. var
  32.   artfn: string;
  33.   artf: text;
  34.   arteof: boolean;
  35.   startofline: boolean;
  36.   firstemptyline: integer;
  37.   showallheaders: boolean;
  38.   donebrowse: boolean;
  39.   rot13ing: boolean;
  40.   compactspaces: boolean;
  41.   highlightsearchhits: boolean;
  42.   usingalternatecolor: boolean;
  43.   shouldswitchcolor: boolean;
  44.  
  45. procedure getartl(var oneline: string; maxlen: integer; toscreen: boolean);
  46. procedure artreset;
  47. procedure artclose;
  48.  
  49. function isheaderline: boolean;  {valid only once getartl has returned it}
  50.  
  51. procedure showartl(s: string);
  52.  
  53. procedure saveart;
  54. procedure writeart;
  55.  
  56. function bestquotechar: char;
  57.  
  58. implementation
  59.  
  60. var
  61.   artlinebuf: string;
  62.   artcharbuf: char;
  63.   artcharbufused: boolean;
  64.   artwaslongline: boolean;
  65.   artlineno: integer;
  66.   artuheader: string;
  67.   artlinefirstchar: char;
  68.   artopen: boolean;
  69.  
  70. procedure getartl;
  71.  
  72. var
  73.   gotaline: boolean;
  74.   lenused: integer;
  75.   spaceat: integer;
  76.   lenread: integer;
  77.   donereading: boolean;
  78.  
  79.   c: char;
  80.  
  81. begin
  82.   inc(artlineno);
  83.   startofline := false;
  84.  
  85. { first, check if there was something left over from last getartl() call}
  86.  
  87.   if artlinebuf<>'' then
  88.     begin
  89.       oneline := artlinebuf;
  90.  
  91.       lenused := length(oneline);
  92.  
  93. { look for line-feed }
  94.  
  95.       if (pos(lf,oneline)<lenused) and (pos(lf,oneline)<>0) then
  96.         begin
  97.           lenused := pos(lf,oneline);
  98.         end;
  99.  
  100. { try to break at a word boundary }
  101.  
  102.       if artlineno>=firstemptyline then
  103.         if lenused>maxlen then
  104.           begin
  105.             spaceat := maxlen;
  106.             while spaceat>0 do
  107.               begin
  108.                 if oneline[spaceat]=' ' then
  109.                   begin
  110.                     lenused := spaceat;  {keep space on this line}
  111.                     spaceat := 0;  {end the loop}
  112.                   end;
  113.                 dec(spaceat);
  114.               end;
  115.           end;
  116.  
  117.       if lenused>maxlen then
  118.         lenused := maxlen;
  119.  
  120.       oneline := copy(artlinebuf,1,lenused);
  121.  
  122.       if maxlen=255 then
  123.         artlinebuf := ''
  124.       else
  125.         artlinebuf := copy(artlinebuf,length(oneline)+1,255);
  126.  
  127. { looks redundant with case below just like this, but isn't.  really.}
  128.  
  129.       if artlinebuf='' then
  130.         arteof := eof(artf);
  131.  
  132.     end
  133.   else if eof(artf) then
  134.     begin
  135.       arteof := true;
  136.       oneline := '(internal error)'
  137.     end
  138.   else
  139.  
  140. {nothing left over, so try reading}
  141.  
  142.     begin
  143.       gotaline := false;
  144.       while not gotaline and not arteof do
  145.         begin
  146.  
  147.           startofline := not artwaslongline;
  148.           artwaslongline := false;
  149.  
  150.           if crlf then
  151.             begin
  152.               read(artf,oneline);
  153.  
  154.               if eoln(artf) then
  155.                 readln(artf)  {discard end of line}
  156.               else
  157.                 artwaslongline := true;
  158.             end
  159.           else
  160.             begin
  161.               lenread := 0;
  162.               artwaslongline := true;
  163.  
  164.               if artcharbufused then
  165.                 oneline := artcharbuf
  166.               else
  167.                 oneline := '';
  168.  
  169.               artcharbufused := false;
  170.  
  171.               donereading := false;
  172.               while not donereading do
  173.                 begin
  174.                   if eof(artf) then
  175.                     donereading := true
  176.                   else
  177.                     begin
  178.                       read(artf,artcharbuf);
  179.                       if artcharbuf=lf then
  180.                         begin
  181.                           donereading := true;
  182.                           artwaslongline := false;
  183.                         end
  184.                       else if artcharbuf<>cr then
  185.                         begin
  186.                           inc(lenread);
  187.  
  188. { if we can fit it onto the string, just do it }
  189.                           if ((lenread<maxlen) and (lenread<255)) then
  190.                             oneline := oneline+artcharbuf
  191.  
  192. { if it won't fit at all, just stop }
  193.                           else if lenread>=255 then
  194.                             begin
  195.                               donereading := true;
  196.                               artcharbufused := true;
  197.                             end
  198.  
  199. {
  200. it's longer than desired, so add it,
  201. but stop if it was a good word break place 
  202. }
  203.                           else
  204.                             begin
  205.                               oneline := oneline+artcharbuf;
  206.                               if (artcharbuf=' ') or (artcharbuf=tab) then
  207.                                 donereading := true;
  208.                             end;
  209.                         end;
  210.                     end;
  211.                 end;
  212.             end;
  213.  
  214.           if oneline='' then
  215.             if firstemptyline>artlineno then
  216.               firstemptyline := artlineno;
  217.  
  218.           gotaline := true;
  219.  
  220. {$ifdef problemswithlf}
  221. {}{}{}{}{} writeln('gotaline=true, oneline=',copy(oneline,1,10),
  222. {}{}{}{}{}   '..., len=',length(oneline));
  223. {$endif}
  224.  
  225. { don't use isheaderline here.  if last header is hidden, first pass }
  226. { will set firstemptyline to a small number, which will then cause }
  227. { artlineno=firstemptyline before the first empty line is actually seen }
  228.  
  229. {$ifdef problemswithlf}
  230. {}{}{}{}{} if artlineno>firstemptyline then writeln('uhoh lineno');
  231. {}{}{}{}{} if not startofline then writeln('uhoh startofline');
  232. {}{}{}{}{} if oneline='' then writeln('uhoh empty');
  233. {}{}{}{}{} if oneline<>'' then if (oneline[1]=' ') or (oneline[1]=tab) then
  234. {}{}{}{}{}   writeln('uhoh ws');
  235.  
  236. { it's `startofline' not being set -- weirdness.  gotta move to a buffer }
  237.  
  238. {$endif}
  239.  
  240.           if (artlineno<=firstemptyline) then
  241.             if startofline then
  242.               if (oneline<>'') then
  243.                 if (oneline[1]<>' ') and (oneline[1]<>tab) then
  244.                   artuheader := upper(getfirstw(oneline));
  245.  
  246. {$ifdef problemswithlf}
  247. {}{}{}{}{} writeln('artuheader=>',artuheader,'<');
  248. {$endif}
  249.  
  250.           if (artlineno<=firstemptyline) and not showallheaders and
  251.            toscreen and (oneline<>'') then
  252.             if hideheaders<>'' then
  253.               begin
  254.                 if isheaderinlist(artuheader,hideheaders) then
  255.                   gotaline := false;
  256.               end
  257.             else if showheaders<>'' then
  258.               if pos(':'+artuheader,showheaders)=0 then
  259.                 gotaline := false;
  260.  
  261. {$ifdef problemswithlf}
  262. {}{}{}{}{} if not gotaline then
  263. {}{}{}{}{} begin
  264. {}{}{}{}{} writeln('now gotaline=false!');
  265. {}{}{}{}{} if hideheaders<>'' then if isheaderinlist(artuheader,hideheaders)
  266. {}{}{}{}{} then writeln('because of hideheaders');
  267. {}{}{}{}{} if showheaders<>'' then if pos(':'+artuheader,showheaders)=0
  268. {}{}{}{}{} then writeln('because of showheaders');
  269. {}{}{}{}{} end;
  270. {$endif}
  271.  
  272. {will trim() break _anything_?  like, while reading in headers?  mail? etc.}
  273.  
  274. {using trim() is _not_ evil on headers - is it ever a problem?  what about}
  275. {expanding tabs?  except for Makefiles and map entries...}
  276.  
  277. {trim() messes up signatures, which are added after getartl is used}
  278.  
  279. {trim() messes up old-style uuencoded postings!  taken out!}
  280.  
  281. {taken out trim() and expand() when not showing on screen (ie saving to disk) }
  282.  
  283. {}{}{} {unfortunately, this doesn't work when replying to long lines that}
  284. {}{}{} {begin with a tab - the line overflows in the editor.  needs work}
  285.  
  286.           if gotaline then
  287.             begin
  288.               if toscreen then
  289.                 oneline := trim(expand(oneline));
  290.  
  291. { start by using all of it }
  292.                 lenused := length(oneline);
  293.  
  294. { look for linefeeds }
  295.                 if (pos(lf,oneline)<lenused) and (pos(lf,oneline)<>0) then
  296.                   begin
  297.                     lenused := pos(lf,oneline);
  298.                   end;
  299.  
  300. { try to break at a word boundary }
  301.  
  302.                 if artlineno>=firstemptyline then
  303.                   if lenused>maxlen then
  304.                     begin
  305.                       spaceat := maxlen;
  306.                       while spaceat>0 do
  307.                         begin
  308.                           if oneline[spaceat]=' ' then
  309.                             begin
  310.                               lenused := spaceat;  {keep space on this line}
  311.                               spaceat := 0;  {end the loop}
  312.                             end;
  313.                           dec(spaceat);
  314.                         end;
  315.                     end;
  316.  
  317.                 if lenused>maxlen then
  318.                   lenused := maxlen;
  319.  
  320. {time-saver, probably, to skip over the copy/copy when possible}
  321.               if length(oneline)>lenused then
  322.                 begin
  323.                   artlinebuf := copy(oneline,lenused+1,255);
  324.                   oneline := copy(oneline,1,lenused);
  325.                 end;
  326.             end;
  327.  
  328. { in case of malformed articles - prevent infinite loop }
  329.  
  330.           if artlinebuf='' then
  331.             arteof := eof(artf);
  332.  
  333.         end;
  334.  
  335.       if not gotaline then
  336.         oneline := '(malformed article)';
  337.  
  338.       if oneline='' then
  339.         artlinefirstchar := chr(0)
  340.       else
  341.         artlinefirstchar := oneline[1];
  342.  
  343.     end;
  344.  
  345.   if toscreen then
  346.     oneline := nonastychar(oneline);
  347.  
  348.   if oneline<>'' then
  349.     if oneline[length(oneline)]=lf then
  350.       oneline[length(oneline)] := ' ';
  351. end;
  352.  
  353. procedure artresetattempt;
  354.  
  355. { don't bother with filemode here - tpascal doesn't use it on text files }
  356.  
  357. var
  358.   savedioresult: word;
  359.  
  360. begin
  361.  
  362. {
  363. sometimes reset() takes a _long_ time, e.g., over a LAN with 4000 files
  364. in one directory
  365. }
  366.  
  367.   if dotsonreset then
  368.     begin
  369.       xgotoxy(1,1);
  370.       xwrites('...');
  371.     end;
  372.  
  373. {
  374. could use safereset here, but don't, since we don't want to do a
  375. new assign each time
  376. }
  377.  
  378. {$I-}
  379.   reset(artf);
  380. {$I+}
  381.  
  382. {the write() in the dotsonreset stuff can change ioresult}
  383.   savedioresult := ioresult;
  384.  
  385.   if dotsonreset then
  386.     begin
  387.       xgotoxy(1,1);
  388.       xwrites('   ');
  389.       xgotoxy(1,1);
  390.     end;
  391.  
  392.   if savedioresult=0 then
  393.     begin
  394.       arteof := eof(artf);
  395.       artlinebuf := '';
  396.       artcharbufused := false;
  397.       artwaslongline := false;
  398.       artlineno := 0;
  399.       artuheader := '';
  400.       artopen := true;
  401.       artlinefirstchar := ' ';
  402.     end;
  403. end;
  404.  
  405. procedure artreset;
  406.  
  407. var
  408.   givenup: boolean;
  409.   yn: char;
  410.  
  411. begin
  412.   givenup := false;
  413.   artopen := false;
  414.  
  415.   while not artopen and not givenup do
  416.     begin
  417.       artresetattempt;
  418.       if not artopen then
  419.         begin
  420.           yn := onekeydef('unable to open '+right(artfn,40)+
  421.            ' -- try again?  {y}/{n}','yn','y');
  422.           if yn='n' then
  423.             givenup := true;
  424.         end;
  425.     end;
  426.  
  427.   if not artopen then
  428.     begin
  429.       donebrowse := true;
  430.       arteof := true;
  431.     end;
  432. end;
  433.  
  434. procedure artclose;
  435.  
  436. begin
  437.   if artopen then
  438.     close(artf);
  439.   artopen := false;
  440. end;
  441.  
  442. function isheaderline;  {valid only once getartl has returned it}
  443.  
  444. begin
  445.   isheaderline := artlineno<firstemptyline;
  446. end;
  447.  
  448. procedure showartl;
  449.  
  450. var
  451.   changeds: string;
  452.   i: integer;
  453.   thisisfindhit: boolean;
  454.   thisisquoted: boolean;
  455.   thisisbreakline: boolean;
  456.  
  457. begin
  458.   if hideformfeeds then
  459.     changeds := crepl(s,^L,' ')
  460.   else
  461.     changeds := s;
  462.  
  463.   if isheaderline then
  464.     begin
  465.       usingalternatecolor := true;  {it gets toggled on empty line following}
  466.       if isheaderinlist(artuheader,highlightheaders) then
  467.         begin
  468.  
  469. {write first part and chop it so it isn't shown again}
  470.           if startofline then
  471.             xwritess(chopfirstw(changeds),' ');
  472.  
  473.           xhighvideo;
  474.           xwritelns(screenline(changeds));
  475.           xlowvideo;
  476.         end
  477.       else
  478.         xwritelns(screenline(changeds));
  479.     end
  480.   else
  481.     begin
  482.       if compactspaces then
  483.         changeds := sreplmulti(changeds,'  ',' ');
  484.  
  485.       if rot13ing then
  486.         changeds := rot13(changeds);
  487.  
  488. {$ifdef charset}
  489.       if uselocalcharset then
  490.         linetolocal(changeds);
  491. {$endif}
  492.  
  493.       thisisfindhit := false;
  494.       if highlightsearchhits then
  495.         if textintext(browseuppersearchstring,upper(changeds)) then
  496.           thisisfindhit := true;
  497.  
  498. {quotecolor is just a time-waster if we're not on the console}
  499.       thisisquoted := (artlinefirstchar=quotechar) and console;
  500.  
  501.       changeds := screenline(changeds);
  502.  
  503.       if thisisfindhit then
  504. {}{} {highlight just the word?}
  505.         begin
  506.           xhighvideo;
  507.           xwritelns(changeds);
  508.           xlowvideo;
  509.         end
  510.       else if thisisquoted then
  511.         begin
  512.           xsetcolor(quotecolor);
  513.           xwritelns(changeds);
  514.           xlowvideo;
  515.         end
  516.       else
  517.         begin
  518.           if not console then
  519.             xwritelns(changeds)
  520.           else
  521.             begin
  522.               thisisbreakline := false;
  523.  
  524. {only go through this effort if it will be visible!}
  525.               if alternatecolor<>lowcolor then
  526.                 if isabreakline(changeds) then
  527.                   thisisbreakline := true;
  528.  
  529. {don't switch colors twice on two empty lines in a row}
  530.               if shouldswitchcolor and not thisisbreakline then
  531.                 begin
  532.                   usingalternatecolor := not usingalternatecolor;
  533.                   shouldswitchcolor := false;
  534.                 end;
  535.  
  536.               if usingalternatecolor then
  537.                 xsetcolor(alternatecolor)
  538.               else
  539.                 xlowvideo;
  540.  
  541.               xwritelns(changeds);
  542.  
  543.               if usingalternatecolor then
  544.                 xlowvideo;
  545.  
  546.               if thisisbreakline then
  547.                 shouldswitchcolor := true;  {duplicating true is ok}
  548.             end;
  549.         end;
  550.     end;
  551. end;
  552.  
  553. procedure savewriteart(fullheaders: boolean);
  554.  
  555. var
  556.   outfilen: string;
  557.   outfile: text;
  558.   outfileisopen: boolean;
  559.   illegal: boolean;
  560.   doit: boolean;
  561.   appending: boolean;
  562.   oneline: string;
  563.   appendoverwriteforgetit: char;
  564.  
  565. {$ifdef charset}
  566.   yn: char;
  567.   foundemptyline: boolean;
  568.   saveusinglocal: boolean;
  569. {$endif}
  570.  
  571. {for non-trusted users, make sure no : or \ in unslash(filename)}
  572. {and try to make sure it's not a device driver (con, aux, lpt1, etc.)}
  573. {then force it in the user's home directory}
  574.  
  575. begin
  576.   getfilename(outfilen,'file name (blank to abort):',lastfilen);
  577.  
  578.   outfilen := ltrim(trim(outfilen));
  579.  
  580.   if outfilen<>'' then
  581.     lastfilen := outfilen;
  582.  
  583.   if tildehome then
  584.     if copy(outfilen,1,2)='~/' then
  585.       outfilen := home+copy(outfilen,2,255);
  586.  
  587.   outfilen := unslash(outfilen);
  588.  
  589.   doit := (outfilen<>'');
  590.   illegal := illegalfn(outfilen);
  591.  
  592.   if doit and not trusted then
  593.     begin
  594.       illegal := illegal or suspiciousfn(outfilen);
  595.     end;
  596.  
  597.   if doit and illegal then
  598.     begin
  599.       warn('unable to use that filename');
  600.     end;
  601.  
  602.   if doit and not illegal then
  603.     begin
  604.       if not trusted then
  605.         outfilen := withbackslash(home)+outfilen;
  606.  
  607.       appendoverwriteforgetit := 'o';
  608.  
  609.       if fexists(outfilen) then
  610.         begin
  611.           xclreolxy(1,lpp);
  612.           appendoverwriteforgetit :=
  613.            onekeydef('{O}verwrite {a}ppend {f}orget it','Oaf','f');
  614.         end;
  615.  
  616.       if appendoverwriteforgetit<>'f' then
  617.         begin
  618.  
  619. {$ifdef charset}
  620.           saveusinglocal := false;
  621.           if uselocalcharset then
  622.             begin
  623.               yn := onekeydef('Change to local charset?  {y}/{n}','yn','y');
  624.               saveusinglocal := (yn = 'y');
  625.             end;
  626. {$endif}
  627.  
  628.           xclreolxy(1,lpp);
  629.  
  630.           appending := (appendoverwriteforgetit='a');
  631.  
  632.           if appending then
  633.             xwritesss('appending to ',outfilen,' ...')
  634.           else
  635.             xwritesss('writing to ',outfilen,' ...');
  636.  
  637.           assign(outfile,outfilen);
  638.  
  639.           outfileisopen := false;
  640.  
  641.           if appending then
  642.             begin
  643. {$I-}
  644.               append(outfile);
  645. {$I+}
  646.               if ioresult<>0 then
  647.                 begin
  648.                   warn('could not append to '+outfilen);
  649.                 end
  650.               else
  651.                 begin
  652.                   outfileisopen := true;
  653.                   writeln(outfile);
  654.                   writeln(outfile,outputseparator);
  655.                   writeln(outfile);
  656.                 end;
  657.             end
  658.           else
  659.             begin
  660. {$I-}
  661.               rewrite(outfile);
  662. {$I+}
  663.               if ioresult<>0 then
  664.                 begin
  665.                   warn('could not write to '+outfilen);
  666.                 end
  667.               else
  668.                 begin
  669.                   outfileisopen := true;
  670.                 end;
  671.             end;
  672.  
  673.     {need to check fullheaders here!}
  674.  
  675.           artreset;
  676.  
  677. {$ifdef charset}
  678.           foundemptyline:= false;
  679. {$endif}
  680.  
  681.           if outfileisopen then
  682.             begin
  683.               while not arteof do
  684.                 begin
  685.                   getartl(oneline,255,false);
  686. {$ifdef charset}
  687.                   if foundemptyline and saveusinglocal then
  688.                     linetolocal(oneline)
  689.                   else
  690.                     if oneline='' then
  691.                       foundemptyline := true;
  692. {$endif}
  693.                   writeln(outfile,oneline);
  694.                 end;
  695.               close(outfile);
  696.             end;
  697.  
  698.           xclreolxy(1,lpp);
  699.           xwrites('done.');
  700.         end;
  701.     end;
  702. end;
  703.  
  704. procedure writeart;
  705.  
  706. begin
  707.   savewriteart(nofullheaders);
  708. end;
  709.  
  710. procedure saveart;
  711.  
  712. begin
  713.   savewriteart(yesfullheaders);
  714. end;
  715.  
  716. function bestquotechar;
  717.  
  718. var
  719.   result: char;
  720.   foundemptyline: boolean;
  721.   done: boolean;
  722.   prevchar: char;
  723.   wastes: string;
  724.   linesread: integer;
  725.  
  726. begin
  727.   result := '>';
  728.  
  729.   artreset;
  730.  
  731.   if artopen then
  732.     begin
  733.       foundemptyline := false;
  734.       while not foundemptyline and not arteof do
  735.         begin
  736.           getartl(wastes,255,notoscreen);
  737.           if not isheaderline then
  738.             foundemptyline := true;
  739.         end;
  740.  
  741.       prevchar := #0;  {unlikely to appear}
  742.  
  743.       linesread := 0;
  744.       done := false;
  745.       while not done and (linesread<20) and not arteof do
  746.         begin
  747.           inc(linesread);
  748.           getartl(wastes,255,notoscreen);
  749.  
  750. {hit a signature -- give up}
  751. {sigh -- @trn.com is right -- the dash-dash-space is often broken}
  752.  
  753.           if (wastes='-- ') or (wastes='--') then
  754.             begin
  755.               done := true;
  756.               wastes := '';
  757.             end;
  758.  
  759.           if wastes<>'' then
  760.             begin
  761.               if (wastes[1]=' ')
  762.                or (wastes[1]=tab)
  763.                or isalpha(wastes[1])
  764.                or isdigit(wastes[1]) then
  765.                 prevchar := #0
  766.               else
  767.                 begin
  768.                   if wastes[1]=prevchar then
  769.                     begin
  770.                       result := prevchar;
  771.                       done := true;
  772.                     end;
  773.                   prevchar := wastes[1];
  774.                   if (prevchar=':') or (prevchar='>') or (prevchar='|') then
  775.                     begin
  776.                       result := prevchar;
  777.                       done := true;
  778.                     end;
  779.                 end;
  780.             end;
  781.         end;
  782.     end;
  783.  
  784.   bestquotechar := result;
  785. end;
  786.  
  787. end.
  788.