home *** CD-ROM | disk | FTP | other *** search
/ CD Actual Thematic 7: Programming / CDAT7.iso / Share / Editores / Perl5 / perl / lib / site / Tk / Parse.pm < prev    next >
Encoding:
Perl POD Document  |  1997-08-10  |  22.8 KB  |  876 lines

  1. #!/usr/bin/perl
  2.  
  3. package Tk::Parse;
  4.  
  5. require Exporter;
  6.  
  7.  
  8. @ISA=qw(Exporter);
  9. @EXPORT=qw(Parse Simplify hide start_hide unhide Normalize Normalize2 Escapes
  10.     $VERBATIM $HEADING $ITEM $INDEX $TEXT $PRAGMA $INDENT );
  11.     
  12. # Different types of text:
  13.  
  14. # 0. Name of file
  15. # 1. Verbatim paragraphs
  16. # 2. Headings
  17. # 3. Items
  18. # 4. Index mark
  19. # 5. Comment block
  20. # 6. Formatted paragraphs
  21. # 7. Pragmas
  22. # 8. Indented sections (which can contain 1-9)
  23. # 9. Cut (conveys no information, but may be useful in interparagraph spacing)
  24.  
  25. # 0 = [0,0,0,0,"filename"]
  26. # 1 = [1,line,pos,0,"verbatim paragraph"]
  27. # 2 = [2,line,pos,level,"heading"]
  28. # 3 = [3,line,pos,0,item]
  29. # 4 = [4,line,pos,0,"indexing"]
  30. # #5 = [5,line,pos,0,"comment"]
  31. # 6 = [6,line,pos,0,"paragraph"]
  32. # 7 = [7,line,pos,0,"pragma"]
  33. # 8 = [8,line,pos,indentation,type...] #type 1 = "*", type 2 = "1.,2." 3=else
  34. # 9 = [9,line,pos,0,"cut"]
  35.  
  36. =head1 NAME
  37.  
  38. Pod::Parse - Parse perl's pod files.
  39.  
  40. =head1 SYNOPSIS
  41.  
  42. B<THIS TK SNAPSHOT SHOULD BE REPLACED BY A CPAN MODULE>
  43.  
  44. =head1 DESCRIPTION
  45.  
  46. A module designed to simplify the job of parsing and formatting ``pods'', the
  47. documentation format used by perl5. This consists of several different
  48. functions to present and modify predigested pod files.
  49.  
  50. =head1 GUESSES
  51.  
  52. This is a work in progress, so I may have some stuff wrong, perhaps badly.
  53. Some of my more reaching guesses:
  54.  
  55. =over 4
  56.  
  57. =item *
  58.  
  59. An =index paragraph should be split into lines, and each line placed inside
  60. an `X' formatting command which is then preprended to the next paragraph,
  61. like this:
  62.  
  63.   =index foo
  64.   foo2
  65.   foo3
  66.   foo2!subfoo
  67.   
  68.   Foo!
  69.  
  70. Will become:
  71.  
  72.   X<foo>X<foo2>X<foo3>X<foo2!subfoo>Foo!
  73.  
  74. =item *
  75.  
  76. A related change: that an `X' command is to be used for indexing data. This
  77. implies that all formatters need to at least ignore the `X' command.
  78.  
  79. =item *
  80.  
  81. Inside an =command, no special significance is to be placed on the first line
  82. of the argument. Thus the following two lines should be parsed identically:
  83.  
  84.  =item 1. ABC
  85.  
  86.  =item 1.
  87.  ABC
  88.  
  89. Note that neither of these are identical to this:
  90.  
  91.  =item 1.
  92.  
  93.  ABC
  94.  
  95. which puts the "ABC" in a separate paragraph.
  96.  
  97. =item *
  98.  
  99. I actually violate this rule twice: in parsing =index commands, and in
  100. passing through the =pragma commands. I hope this make sense.
  101.  
  102. =item *
  103.  
  104. I added the =comment command, which simply ignores the next paragraph
  105.  
  106. =item *
  107.  
  108. I also added =pragma, which also ignores the next paragraph, but this time
  109. it gives the formatter a chance at doing something sinister with it.
  110.  
  111. =back
  112.  
  113. =head1 POD CONVENTIONS
  114.  
  115. This module has two goals: first, to simplify the usage of the pod format,
  116. and secondly the codification of the pod format. While perlpod contains some
  117. information, it hardly gives the entire story. Here I present "the rules",
  118. or at least the rules as far as I've managed to work them out.
  119.  
  120. =over 4
  121.  
  122. =item Paragraphs: The basic element
  123.  
  124. The fundamental "atom" of a pod file is the paragraph, where a paragraph is
  125. defined as the text up to the next completely blank line ("\n\n"). Any pod
  126. parser will read in paragraphs sequentially, deciding what do to with each
  127. based solely on the current state and on the text at the _beginning_ of the
  128. paragraph.
  129.  
  130. =item Commands: The method of communication
  131.  
  132. A paragraph that starts with the `=' symbol is assumed to be a special command.
  133. All of the alphanumeric characters directly after the `=' are assumed to be
  134. part of the name of the command, up to the first whitespace. Anything past that
  135. whitespace is considered "the arugment", and the argument continues up till
  136. the end of the paragraph, regardless of newlines or other whitespace.
  137.  
  138. =item Text: Commands that aren't Commands
  139.  
  140. A paragraph that doesn't start with `=' is treated as either of two types of
  141. text. If it starts with a space or tab, it is considered a B<verbatim>
  142. paragraph, which will be printed out... verbatim. No formatting changes
  143. whatsover may be done. (Actually, this isn't quite true, but I'll get back to
  144. that at a later date.)
  145.  
  146. A paragraph that doesn't start with whitespace or `=' is assumed to consist of
  147. formmated text that can be molded as the formatter sees fit. Reformatting to
  148. fit margins, whatever, it's fair game. These paragraphs also can contain a
  149. number of different formatting codes, which verbatim paragraphs can't. These
  150. formatting codes are covered later.
  151.  
  152. =item =cut: The uncommand
  153.  
  154. There is one command that needs special mention: =cut. Anything after a
  155. paragraph starting with =cut is simply ignored by the formatter. In
  156. addition, any text B<before> a valid command is equally ignored. Any valid
  157. `=' command will reenable formating. This fact is used to great benefit by
  158. Perl, which is glad to ignore anything between an `=' command and `=cut', so
  159. you can embed a pod document right inside a perl program, and neither will
  160. bother the other.
  161.  
  162. =item Reference to paragraph commands
  163.  
  164. =over 4
  165.  
  166. =item =cut
  167.  
  168. Ignore anything till the next paragraph starting with `='.
  169.  
  170. =item =head1
  171.  
  172. A top-level heading. Anything after the command (either on the same line or 
  173. on further lines) is included in the heading, up until the end of the paragraph.
  174.  
  175. =item =head2
  176.  
  177. Secondary heading. Same as =head1, but different. No, there isn't a head3,
  178. head4, etc.
  179.  
  180. =item =over [N]
  181.  
  182. Start a list. The C<N> is the number of characters to indent by. Not all
  183. formatters will listen to this, though. A good number to use is 4.
  184.  
  185. While =over sounds like it should just be indentation, it's more complex then
  186. that. It actually starts a nested environment, specifically for the use of
  187. =item's. As this command recurses properly, you can use more then one, you
  188. just have to make sure they are closed off properly by =back commands.
  189.  
  190. =item =back
  191.  
  192. Ends the last =over block. Resets the indentation to whatever it was
  193. previously. Closes off the list of =item's.
  194.  
  195. =item =item
  196.  
  197. The point behind =over and =back. This command should only be used between
  198. them. The argument supplied should be consistent (within a list) to one of 
  199. three types: enumeration, itemization, or description. To exemplify:
  200.  
  201.  
  202. An itemized list
  203.  
  204.   =over 4
  205.   
  206.   =item *
  207.   
  208.   A bulleted item
  209.   
  210.   =item *
  211.   
  212.   Another bulleted item
  213.  
  214.   =back
  215.   
  216. An enumerated list
  217.  
  218.   =over 4
  219.   
  220.   =item 1.
  221.   
  222.   First item.
  223.   
  224.   =item 2.
  225.   
  226.   Second item.
  227.   
  228.   =back
  229.   
  230. A described list
  231.  
  232.   =over 4
  233.   
  234.   =item Item #1
  235.   
  236.   First item
  237.   
  238.   =item Item #2 (which isn't really like #1, but is the second).
  239.   
  240.   Second item
  241.   
  242.   =back  
  243.   
  244.   
  245. If you aren't consistent about the arguments to =item, Pod::Parse will
  246. complain.
  247.  
  248. =item =comment
  249.  
  250. Ignore this paragraph
  251.  
  252. =item =pragma
  253.  
  254. Ignore this paragraph, as well, unless you know what you are doing.
  255.  
  256. =item =index
  257.  
  258. Undecided at this time, but probably magic involving XZ<><>.
  259.  
  260. =back
  261.  
  262. =item Reference to formatting directives
  263.  
  264. =over 4
  265.  
  266. =item BZ<><...>
  267.  
  268. Format text inside the brackets as bold.
  269.  
  270. =item IZ<><...>
  271.  
  272. Format text inside the brackets as italics.
  273.  
  274. =item ZZ<><>
  275.  
  276. Replace with a zero-width character. You'll probably figure out some uses
  277. for this.
  278.  
  279. =item And yet more that I haven't described yet...
  280.  
  281. =back
  282.  
  283. =back
  284.  
  285. =head1 USAGE
  286.  
  287. =head2 Parse
  288.  
  289. This function takes a list of files as an argument. If no argument is given,
  290. it defaults to the contents of @ARGV. Parse then reads through each file and
  291. returns the data as a list. Each element of this list will be a nested list
  292. containing data from a paragraph of the pod file. Elements pertaining to
  293. "=over" paragraphs will themselves contain the nested entries for all of the
  294. paragraphs within that list. Thus, it's easier to parse the output of Parse
  295. using a recursive parses. (Um, did that parse?)
  296.  
  297. It is I<highly> recommended that you use the output of Simplify, not Parse,
  298. as it's simpler.
  299.  
  300. The output will consist of a list, where each element in the list matches
  301. one of these prototypes:
  302.  
  303. =over 4
  304.  
  305. =item [0,0,0,0,$filename]
  306.  
  307. This is produced at the beginning of each file parsed, where $filename is
  308. the name of that file.
  309.  
  310. =item [-1,0,0,0,$filename]
  311.  
  312. End of same.
  313.  
  314. =item [1,$line,$pos,0,$verbatim]
  315.  
  316. This is produced for each paragraph of verbatim text. $verbatim is the text, 
  317. $line is the line offset of the paragraph within the file, and $pos is the
  318. byte offset. (In all of the following elements, $pos and $line have identical
  319. meanings, so I'll skip explaining them each time.)
  320.  
  321. =item [2,$line,$pos,$level,$heading]
  322.  
  323. Producded by a =head1 or =head2 command. $level is either 1 or 2, and $heading
  324. is the argument.
  325.  
  326. =item [3,$line,$pos,0,$item]
  327.  
  328. $item is the argument from an =item paragraph.
  329.  
  330. =item [4,$line,$pos,0,$index]
  331.  
  332. $index is the argument from an =index paragraph.
  333.  
  334. =item [6,$line,$pos,0,$text]
  335.  
  336. Normal formatted text paragraph. $text is the text.
  337.  
  338. =item [7,$line,$pos,0,$pragma]
  339.  
  340. $pragma is the argument from a =pragma paragraph.
  341.  
  342. =item [8,$line,$pos,$indentation,$type,...]
  343.  
  344. This item is produced for each matching =over/=back pair. $indentation is
  345. the argument to =over, $type is 1 if the embedded =item's are bulleted, 2 if
  346. they are enumerated, 3 if they are text, and 0 if there are no items.
  347.  
  348. The "..." indicates an unlimited number of further elements which are
  349. themselves nested arrays in exactly the format being described. In other
  350. words, a list item includes all the paragraphs inside the list inside
  351. itself. (Clear? No? Nevermind.)
  352.  
  353. =item [9,$line,$pos,0,$cut]
  354.  
  355. $cut contains the text from a =cut paragraph. You shouldn't need to use
  356. this, but I _suppose_ it might be necessary to do special breaks on a cut. I
  357. doubt it though. This one is "depreciated", as Larry put it. Or perhaps
  358. disappreciated.
  359.  
  360. =back
  361.  
  362. =head2 Simplify
  363.  
  364. This procedure takes as it's input the convoluted output from Parse(), and
  365. outputs a much simpler array consisting of pairs of commands and arguments,
  366. designed to be easy (easier?) to parse in your pod formatting code.
  367.  
  368. It is used very simply by saying something like:
  369.  
  370.  @Pod = Simplify(Parse());
  371.  
  372.  while($cmd = shift @Pod) { $arg = shift @Pod;
  373.      #...
  374.  }
  375.  
  376. Where #... is the code that responds to any of the commands from the
  377. following list. Note that you are welcome to ignore any of the commands that
  378. you want to. Many contain duplicate information, or at least information
  379. that will go unused. A formatted based on this data can be quite simple
  380. indeed. (See pod2text for entirely too simple an example.)
  381.  
  382. =head2 Reference to Simplify commands
  383.  
  384. =over 4
  385.  
  386. =item "filename"
  387.  
  388. The argument contains the name of the pod file that is being parsed. These
  389. will be present at the start of each file. You should open an output file,
  390. output headers, etc., based on this, and not when you start parsing.
  391.  
  392. =item "endfile"
  393.  
  394. The end of the file. Each file will be ended before the next one begins, and
  395. after all files are done with. You can do end processing here. The argument
  396. is the same name as in "filename".
  397.  
  398. =item "setline"
  399.  
  400. This gives you a chance to record the "current" input line, probably for
  401. debugging purposes. In this case, "current" means that the next command you
  402. see that was derived from an input paragraph will have start at the
  403. arguments line in the file.
  404.  
  405. =item "setloc"
  406.  
  407. Same as setline, but the byte offset in the input, instead of the line offset.
  408.  
  409. =item "pragma"
  410.  
  411. The argument contains the text of a pragma command.
  412.  
  413. =item "text"
  414.  
  415. The argument contains a paragraph of formatted text.
  416.  
  417. =item "verbatim"
  418.  
  419. The argument contains a paragraph of verbatim text.
  420.  
  421. =item "cut"
  422.  
  423. A =cut command was hit. You shouldn't really need to listen for this one.
  424.  
  425. =item "index"
  426.  
  427. The argument contains an =index paragraph. (Note: Current =index commands are
  428. not fed through, but turned into XZ<><> commands.)
  429.  
  430. =item "head1"
  431.  
  432. =item "head2"
  433.  
  434. The argument contains the argument from a header command.
  435.  
  436.  
  437. =item "setindent"
  438.  
  439. If you are tracking indentation, use the argument to set the indentation level.
  440.  
  441. =item "listbegin"
  442.  
  443. Start a list environment. The argument is the type of list (1,2,3 or 0).
  444.  
  445. =item "listend"
  446.  
  447. Ends a list environment. Same argument as listbegin.
  448.  
  449. =item "listtype"
  450.  
  451. The argument is the type of list. You can just record the argument when you
  452. see one of these, instead of paying attention to listbegin & listend.
  453.  
  454. =item "over"
  455.  
  456. The argument is the indentation. It's probably better to listen to the
  457. "list..." commands.
  458.  
  459. =item "back"
  460.  
  461. Ends an "over" list. The argument is the original indentation.
  462.  
  463. =item "item"
  464.  
  465. The argument is the text of the =item command.
  466.  
  467. =back
  468.  
  469. Note that all of these various commands you've seen are syncronized properly
  470. so you don't have to pay attention to all at once, but they are all output
  471. for your benefit. Consider the following example:
  472.  
  473.  listtype 2
  474.  listbegin 2
  475.  setindent 4
  476.  over 4
  477.  item 1.
  478.  text Item #1
  479.  item 2.
  480.  text Item #2
  481.  setindent 0
  482.  listend 2
  483.  back 0
  484.  listtype 0
  485.  
  486. =head2 Normalize
  487.  
  488. This command is normally invoked by Parse, so you shouldn't need to deal
  489. with it. It just cleans up text a little, turning spare '<', '>', and '&'
  490. characters into HTML escapes (E<lt>, etc.) as well as generating warnings for
  491. some pod formatting mistakes.
  492.  
  493. =head2 Normalize2
  494.  
  495. A little more aggresive formating based on heuristics. Not applied by
  496. default, as it might confuse your own heuristics.
  497.  
  498. =head2 %Escapes
  499.  
  500. This hash is exported from Pod::Parse, and contains default ASCII
  501. translations for some common HTML escape sequences. You might like to use this
  502. as a basis for an %HTML_Escapes array in your own formatter.
  503.  
  504. =cut
  505.  
  506. $ENDFILE = -1;
  507. $FILE = 0;
  508. $VERBATIM = 1;
  509. $HEADING = 2;
  510. $ITEM = 3;
  511. $INDEX = 4;
  512. $TEXT = 6;
  513. $PRAGMA = 7;
  514. $INDENT = 8;
  515. $CUT = 9;
  516.  
  517.        
  518.  
  519.  
  520.  
  521. # "hide" suite
  522.  
  523. sub hide {
  524.     local($thing_to_hide) = shift;
  525.     $thing_to_hide =~ tr/\000-\177/\200-\377/;
  526.     return $thing_to_hide;
  527. }
  528.             
  529. sub start_hide {
  530.     if ( /[\200-\377]/ ) {
  531.         warn "hit bit char in input stream";
  532.     }
  533. }
  534.                             
  535. sub unhide {
  536.     local($tmp) = shift;
  537.     $tmp =~ tr/\200-\377/\000-\177/;
  538.     return $tmp;
  539. }
  540.                                         
  541.  
  542. # Turn formatted text into a more normalized version. All '<' and '>' will
  543. # belong to a command, the rest will have turned into E<lt> and E<gt>. '&'
  544. # has been changed into E<amp>. Possibly generate some warnings
  545.  
  546. sub Normalize {
  547.     local($_) = $_[0];
  548.  
  549.     start_hide;
  550.         s/(E<[^<>]*>)/hide($1)/ge;
  551.         s/([A-Z]<[^<>]*>)/hide($1)/ge;
  552.         
  553.         s/</hide("E<lt>")/ge;
  554.         s/>/hide("E<gt>")/ge;
  555.         s/&/hide("E<amp>")/ge;
  556.  
  557.           #if (m{ ([\-\w]+\([^\051]*?[\@\$,][^\051]*?\))
  558.         #    }x && $` !~ /([LCI]<[^<>]*|-)$/ && !/^=\w/)
  559.         #    {
  560.         #    warn "``$1'' should be a [LCI]<$1> ref near line $line of $ARGV\n";
  561.         #}
  562.         
  563.         while (/(-[a-zA-Z])\b/g && $` !~ /[\w\-]$/) {
  564.         warn  "``$1'' should be [CB]<$1> ref near line $line of $ARGV\n";
  565.     }
  566.         
  567.     # put back pod quotes so we get the inside of <> processed;
  568.         $_ = unhide($_);
  569.         
  570. }
  571.  
  572. # Apply heuristics to a formatted string.
  573. sub Normalize2 {
  574.     local($_) = @_;        
  575.         
  576.     # func() is a reference to a perl function
  577.            s{\b([:\w]+\(\))}{I<$1>}g;
  578.            
  579.         # func(n) is a reference to a man page
  580.         s{(\w+)(\([^\s,\051]+\))}{I<$1>$2}g;
  581.         
  582.         # convert simple variable references
  583.         s/(\s+)([\$\@%][\w:]+)/${1}C<$2>/g;
  584.         #       s/([\$\@%][\w:]+)/C<$1>/g;
  585.         #       s/\$[\w:]+\[[0-9]+\]/C<$&>/g;
  586.     $_;
  587. }
  588.  
  589. # Take output from the following Parse routine, and turns it into a much
  590. # more straightforward, non-recursive, data structure. It returns an
  591. # array consisting of pairs of elements, the first of each pair being a 
  592. # command, and the second it's argument. Hopefully this should prove
  593. # simple to parse. Note that it is intended that your formatter only "listens"
  594. # for the commands it is interested in, and simply discards the rest.
  595.  
  596. sub Simplify { &Simplify2(0,0,@_); }
  597.  
  598. sub Simplify2 {
  599.     my($indent,$type,@list) = @_;
  600.     my(@result)=();
  601.     foreach(@list) {
  602.         my($code,$line,$loc,$param,$text) = @{$_};
  603.         push(@result,"setline",$line);
  604.         push(@result,"setloc",$loc);
  605.         if( $code == $INDENT) {
  606.             my($code_dummy,$line,$loc,$i,$t,@more) = @{$_};
  607.             #   ^^^^^^^^^^ This may be bug of perl5.002b2
  608.             push(@result,"listtype",$t);
  609.             push(@result,"listbegin",$t);
  610.             push(@result,"setindent",$i);
  611.             push(@result,"over",$i);
  612.             push(@result,&Simplify2($i,$t,@more));
  613.             push(@result,"setindent",$indent);
  614.             push(@result,"listend",$t);
  615.             push(@result,"back",$indent);
  616.             push(@result,"listtype",$type);
  617.         } elsif( $code == $PRAGMA) {
  618.             push(@result,"pragma",$text);
  619.         } elsif( $code == $ITEM) {
  620.             push(@result,"item",$text);
  621.         } elsif( $code == $INDEX) {
  622.             push(@result,"index",$text);
  623.         } elsif( $code == $TEXT) {
  624.             push(@result,"text",$text);
  625.         } elsif( $code == $VERBATIM) {
  626.             push(@result,"verbatim",$text);
  627.         } elsif( $code == $HEADING) {
  628.             push(@result,"head$param",$text);
  629.         } elsif( $code == $CUT) {
  630.             push(@result,"cut",0);
  631.         } elsif( $code == $FILE) {
  632.             push(@result,"filename",$text);
  633.         } elsif( $code == $ENDFILE) {
  634.             push(@result,"endfile",$text);
  635.         }
  636.     }
  637.     @result;
  638. }
  639.  
  640. # Read input from a pod file, and generate a list describing it. Keeps
  641. # track of the line number and position in the stream. Recursive.
  642.  
  643. sub Parse {
  644.     local(@ARGV)=@ARGV;
  645.     if(@_) { @ARGV = @_ }
  646.     
  647.     local($/);
  648.  
  649.     $type=0;
  650.     $typecount=0;
  651.     $eof=0;
  652.     $bof=1;
  653.     $saveindex="";
  654.  
  655.     $/="";
  656.     
  657.     $cutting=1;
  658.  
  659.     $recurse=0;
  660.  
  661.     $line=0;
  662.  
  663.     $loc=0;
  664.  
  665.     $newloc=0; $newline=0;
  666.     
  667.     $infile = undef;
  668.  
  669.     
  670.     &Parse2();
  671.  
  672. }
  673.  
  674. sub Parse2 {
  675.     my(@result)=();
  676.     while(<>) {
  677.         if($bof) {
  678.             push(@result,[-1,0,0,0,$infile]) if $infile;
  679.             push(@result,[0,0,0,0,$ARGV]);
  680.             $infile = $ARGV;
  681.             $newloc=0;
  682.             $newline=0;
  683.             $bof=0;
  684.         }
  685.         if(eof) {
  686.             $bof=1;
  687.         }
  688.         $loc=$newloc;
  689.         $line=$newline;
  690.         $newloc = $loc + length($_);
  691.         $newline= $line + (tr/\n/\n/);
  692.         
  693.         #Should I?
  694.         #s/[ \t]+$//gm;
  695.         
  696.         #print STDERR "Read $_\n";
  697.         
  698.         if($cutting && !/^=/) {
  699.             next;
  700.         }
  701.         $cutting=0;
  702.         chomp;
  703.         
  704.         if(/^=cut/) {
  705.             $cutting=1;
  706.             push(@result,[9,$line,$loc,0,0]);
  707.             next;
  708.         }
  709.         
  710.         if(/^\s/) {
  711.             push(@result,[1,$line,$loc,0,$_]);
  712.         } elsif( /^=head(\d+)\s*/ ) {
  713.             my($data) = $';
  714.             $data =~ s/\n/ /g;
  715.             push(@result,[2,$line,$loc,$1,Normalize($data)]);
  716.         } elsif( /^=item\s*/ ) {
  717.             my($data) = $';
  718.             $data =~ s/\n/ /g;
  719.             if(!$recurse) {
  720.                 warn "=item outside of an =over block near line $line of $ARGV\n";
  721.             }
  722.             if( $data eq "*" ) {
  723.                 if( $type == 0 || $type == 1) {
  724.                      $type = 1;
  725.                 } else {
  726.                     warn "Inconsistent =item near line $line of $ARGV\n";
  727.                 }
  728.             } elsif( $data =~ /^(\d+)\.$/ ) {
  729.                 if( $type == 0 ) {
  730.                     $type=2;
  731.                     $typecount=0;
  732.                 } elsif( $type != 2 ) {
  733.                     warn "Inconsistent =item near line $line of $ARGV\n";
  734.                 }
  735.                 if( ++$typecount != $1) {
  736.                     warn "Inconsistently numbered =item near line $line of $ARGV\n";
  737.                     $typecount = $1;
  738.                 }
  739.                 
  740.             } else {
  741.                 if( $type == 0 || $type == 3) {
  742.                     $type = 3;
  743.                 } else {
  744.                     warn "Inconsistent =item near line $line of $ARGV\n";
  745.                 }
  746.             }
  747.             push(@result,[3,$line,$loc,0,Normalize($data)]);
  748.             
  749.         } elsif( /^=over(?:\s+(\d+))?/ ) {
  750.             my($indent,$l1,$l2)=($1,$line,$loc);
  751.             $indent ||= 5; # good?
  752.             $recurse++;
  753.             local($type)=0;
  754.             local($typecount)=0;
  755.             my(@newresult) = Parse2();
  756.             #print STDERR "PUSH\n";
  757.             push(@result,[8,$l1,$l2,$indent,$type,@newresult]);
  758.             #print STDERR "POP\n";
  759.             $recurse--;
  760.             last if $eof;
  761.         } elsif( /^=back/ ) {
  762.             if(!$recurse) {
  763.                 die "Unmatched =back near line $line of $ARGV\n";
  764.             } 
  765.             return @result;
  766.         } elsif( /^=pragma\s*/) {
  767.             push(@result,[7,$line,$loc,0,$']);
  768.         } elsif( /^=index\s*/) {
  769.             #push(@result,[4,$line,$loc,0,$']);
  770.             $saveindex=$';
  771.         } elsif( /^=comment/ ) {
  772.             #push(@result,[5,$line,$loc]);
  773.         } elsif( /^=/ ) {
  774.             m/^(=\S+)/;
  775.             warn "Unknown pod command `$1' near line $line of $ARGV\n";
  776.         } else {
  777.             if($saveindex) {
  778.                 $_ = join("",map("X<$_>",grep(!/^\s*$/,split(/\n/,$saveindex))))
  779.                      . $_;
  780.                 $saveindex="";
  781.             }
  782.             push(@result,[6,$line,$loc,0,Normalize($_)]);
  783.         }
  784.         
  785.     }
  786.     $eof=1;
  787.     if($recurse) {
  788.         #die ...
  789.         warn "Unmatched =over near line $line of $ARGV\n";
  790.         #Assume =back
  791.     }
  792.     push(@result,[-1,0,0,0,$infile]) if $infile;
  793.     @result;
  794. }
  795.  
  796. # for testing
  797. #@result=Parse();
  798. #print Dumpstruct::Dumpstruct(\@result);
  799.  
  800.  
  801. # Common escapes with ASCII translations. You should copy this into you're
  802. # own local escapes hash and override the ones you need to change.
  803.  
  804. %Escapes = (
  805.     'amp'    =>    '&',    #   ampersand
  806.     'lt'    =>    '<',    #   left chevron, less-than
  807.     'gt'    =>    '>',    #   right chevron, greater-than
  808.     'quot'    =>    '"',    #   double quote
  809.  
  810.     "Aacute"    =>    "A",    #   capital A, acute accent
  811.     "aacute"    =>    "a",    #   small a, acute accent
  812.     "Acirc"    =>    "A",    #   capital A, circumflex accent
  813.     "acirc"    =>    "a",    #   small a, circumflex accent
  814.     "AElig"    =>    'Ae',        #   capital AE diphthong (ligature)
  815.     "aelig"    =>    'ae',        #   small ae diphthong (ligature)
  816.     "Agrave"    =>    "A",    #   capital A, grave accent
  817.     "agrave"    =>    "a",    #   small a, grave accent
  818.     "Aring"    =>    'A',    #   capital A, ring
  819.     "aring"    =>    'a',    #   small a, ring
  820.     "Atilde"    =>    'A',    #   capital A, tilde
  821.     "atilde"    =>    'a',    #   small a, tilde
  822.     "Auml"    =>    'A',    #   capital A, dieresis or umlaut mark
  823.     "auml"    =>    'a',    #   small a, dieresis or umlaut mark
  824.     "Ccedil"    =>    'C',    #   capital C, cedilla
  825.     "ccedil"    =>    'c',    #   small c, cedilla
  826.     "Eacute"    =>    "E",    #   capital E, acute accent
  827.     "eacute"    =>    "e",    #   small e, acute accent
  828.     "Ecirc"    =>    "E",    #   capital E, circumflex accent
  829.     "ecirc"    =>    "e",    #   small e, circumflex accent
  830.     "Egrave"    =>    "E",    #   capital E, grave accent
  831.     "egrave"    =>    "e",    #   small e, grave accent
  832.     "ETH"    =>    'Oe',        #   capital Eth, Icelandic
  833.     "eth"    =>    'oe',        #   small eth, Icelandic
  834.     "Euml"    =>    'E',    #   capital E, dieresis or umlaut mark
  835.     "euml"    =>    'e',    #   small e, dieresis or umlaut mark
  836.     "Iacute"    =>    "I",    #   capital I, acute accent
  837.     "iacute"    =>    "i",    #   small i, acute accent
  838.     "Icirc"    =>    "I",    #   capital I, circumflex accent
  839.     "icirc"    =>    "i",    #   small i, circumflex accent
  840.     "Igrave"    =>    "I",    #   capital I, grave accent
  841.     "igrave"    =>    "i",    #   small i, grave accent
  842.     "Iuml"    =>    'I',    #   capital I, dieresis or umlaut mark
  843.     "iuml"    =>    'i',    #   small i, dieresis or umlaut mark
  844.     "Ntilde"    =>    'N',    #   capital N, tilde
  845.     "ntilde"    =>    'n',    #   small n, tilde
  846.     "Oacute"    =>    "O",    #   capital O, acute accent
  847.     "oacute"    =>    "o",    #   small o, acute accent
  848.     "Ocirc"    =>    "O",    #   capital O, circumflex accent
  849.     "ocirc"    =>    "o",    #   small o, circumflex accent
  850.     "Ograve"    =>    "O",    #   capital O, grave accent
  851.     "ograve"    =>    "o",    #   small o, grave accent
  852.     "Oslash"    =>    "O",        #   capital O, slash
  853.     "oslash"    =>    "o",        #   small o, slash
  854.     "Otilde"    =>    "O",    #   capital O, tilde
  855.     "otilde"    =>    "o",    #   small o, tilde
  856.     "Ouml"    =>    'O',    #   capital O, dieresis or umlaut mark
  857.     "ouml"    =>    'o',    #   small o, dieresis or umlaut mark
  858.     "szlig"    =>    'ss',        #   small sharp s, German (sz ligature)
  859.     "THORN"    =>    'L',        #   capital THORN, Icelandic
  860.     "thorn"    =>    'l',        #   small thorn, Icelandic
  861.     "Uacute"    =>    "U",    #   capital U, acute accent
  862.     "uacute"    =>    "u",    #   small u, acute accent
  863.     "Ucirc"    =>    "U",    #   capital U, circumflex accent
  864.     "ucirc"    =>    "u",    #   small u, circumflex accent
  865.     "Ugrave"    =>    "U",    #   capital U, grave accent
  866.     "ugrave"    =>    "u",    #   small u, grave accent
  867.     "Uuml"    =>    'U',    #   capital U, dieresis or umlaut mark
  868.     "uuml"    =>    'u',    #   small u, dieresis or umlaut mark
  869.     "Yacute"    =>    "Y",    #   capital Y, acute accent
  870.     "yacute"    =>    "y",    #   small y, acute accent
  871.     "yuml"    =>    'y',    #   small y, dieresis or umlaut mark
  872. );
  873.  
  874.  
  875. 1;
  876.