1 | extproc perl -wS
|
---|
2 | #!perl -w
|
---|
3 | use strict qw(refs subs);
|
---|
4 | use File::Find;
|
---|
5 | use File::Copy 'copy';
|
---|
6 | use Cwd;
|
---|
7 | use Config '%Config';
|
---|
8 | use Getopt::Long 'GetOptions';
|
---|
9 | use vars qw{%do_file_hash %do_dirs_hash %bin_hash %faqs_hash %pragmas_hash
|
---|
10 | %mods_hash %pod_hash %add_mods_hash @add_dir @add_files %tree_hash
|
---|
11 | $skip_embedded_links};
|
---|
12 | # use Fatal qw(open close); # would not work: interprets filehandles as barewords.
|
---|
13 | sub intern_modnamehash;
|
---|
14 | sub do_libdir;
|
---|
15 | sub output_file;
|
---|
16 | sub hash_diff;
|
---|
17 | sub auto_beautify;
|
---|
18 | sub create_tree;
|
---|
19 | sub format_args;
|
---|
20 | sub output_index;
|
---|
21 | sub count_index;
|
---|
22 | sub untabify;
|
---|
23 | sub untabify_after;
|
---|
24 | sub strip;
|
---|
25 | sub find_parent;
|
---|
26 | sub insert_back;
|
---|
27 |
|
---|
28 | require 5.004; # Otherwise pos() in recursive sub cores.
|
---|
29 |
|
---|
30 | #require 'dumpvar.pl';
|
---|
31 |
|
---|
32 | # $rcs = ' $Id: pod2ipf.cmd,v 1.37 2010/07/27 01:40:05 vera Exp $ ' ;
|
---|
33 | ($VERSION) = (' $Revision: 1.37 $ ' =~ /(\d+(\.\d+)*)/);
|
---|
34 |
|
---|
35 | # by Marko.Macek@snet.fri.uni-lj.si, mark@hermes.si
|
---|
36 | # and Ilya Zakharevich ilya@math.ohio-state.edu
|
---|
37 | #
|
---|
38 | # TODO:
|
---|
39 | # eliminate blank panes that link to next pane when =item XX\n\n=itemYY used
|
---|
40 | # rewrite ?<> parsing
|
---|
41 | # better index (mostly done)
|
---|
42 | # cleaner xref heuristics (mostly done)
|
---|
43 | # process embeded pods (done)
|
---|
44 | # IPFC doesn't seem to handle tabs - are
|
---|
45 | # handle perl/SYNOPSIS properly (tabs, indented lines) -- or is it a bug in doc
|
---|
46 | # probably should process as pre but with markup -- done below (ok?)
|
---|
47 | # remove =head1 NAME and use it as toplevel heading (done)
|
---|
48 | # (also collapse DESCRIPTION if the only section).
|
---|
49 | # pod2ipf needs to be split into index generator and translator
|
---|
50 | # this should enable separate translation of each .pod
|
---|
51 | # and use of .INF concatenation to view the full docs together
|
---|
52 | # (with linking if index was used).
|
---|
53 | # IPF requires numerical references when concatenation is used, not symbolic :-(
|
---|
54 | # improved handling of windows (started to be done)
|
---|
55 | # ...
|
---|
56 | #
|
---|
57 | # Changes:
|
---|
58 | #
|
---|
59 | # 10.2: parml used instead of ul if needed.
|
---|
60 | # Readability of .ipf improved.
|
---|
61 | # BI partially supported, F<> and C<> are distinct.
|
---|
62 | # Some options supported.
|
---|
63 | #
|
---|
64 | # 10.3: C<> works again.
|
---|
65 | # --head_off works (0 and 1).
|
---|
66 | #
|
---|
67 | # 10.4: Auto-beautifies some words, vars and functions, finds links
|
---|
68 | # --head_off works (0 and 1 and 2).
|
---|
69 | #
|
---|
70 | # 10.5: --section-name works
|
---|
71 | # Bugs with modules in subdirectories corrected.
|
---|
72 | # --about works.
|
---|
73 | # Better auto-crosslinking.
|
---|
74 | #
|
---|
75 | # 2-level indices. (Since we do not know until the second pass
|
---|
76 | # whether we put something into an index, there are some false
|
---|
77 | # positives.)
|
---|
78 | # Handles tabs (checked with Tk).
|
---|
79 | # Secondary names used for crosslinking.
|
---|
80 | # 11: Additional logic for links like C<-M>.
|
---|
81 | # Will process ../INSTALL and ../Porting/pumpkin.pod as well.
|
---|
82 | # Additional argument --bin-dir.
|
---|
83 | # Support for WWW links via lynx.
|
---|
84 | #
|
---|
85 | # Use of uninit value comes from findrefid for pod2ipf it it is not present.
|
---|
86 | # 1.5: Add back perltoc - have refs to it.
|
---|
87 | # :i[12] tags are shortened to avoid segfaults.
|
---|
88 | # 1.6: `pod2ipf myfile.pod' works again;
|
---|
89 | # --www added.
|
---|
90 | # <-processing could use substr with negative length for C<<=>.
|
---|
91 | # Index entries X<> handled (invisible).
|
---|
92 | # Will not produce links to "contents" pages from higher level
|
---|
93 | # contents pages (YES!).
|
---|
94 | # 1.7: Add implicit links for targets defined by C<>.
|
---|
95 | # Uplinks added.
|
---|
96 | # 1.8: Will not reference -8.
|
---|
97 | # out[12] removed, substituted by 'require 5.004'.
|
---|
98 |
|
---|
99 | # 1.9: Better handling of 'Go up' (last item was going to the following
|
---|
100 | # section).
|
---|
101 |
|
---|
102 | # 1.10: Misprint...
|
---|
103 | # Supports L<foo|bar>
|
---|
104 | # Do not index/create refs for perltoc.
|
---|
105 | # Numeration of panes fixed to be not off-by-one. (Minor bugs may be created for writing TOC sections and "Go up" links.)
|
---|
106 |
|
---|
107 | # 1.11: Remove (last piece?) of voodoo - in contents() - it did not work anyway
|
---|
108 | # Allow links to text containing L<> inside.
|
---|
109 |
|
---|
110 | # 1.12: Allow for --section-name with --file too;
|
---|
111 | # Wrap arguments in "About";
|
---|
112 | # --believe-pod-name implemented.
|
---|
113 | # --alias implemented.
|
---|
114 |
|
---|
115 | # 1.13: One more piece of voodoo for backrefs removed.
|
---|
116 |
|
---|
117 | # 1.14: @add_dir was misspelled
|
---|
118 |
|
---|
119 | # 1.15: Looking for leading whitespace was done with \s instead of [ \t].
|
---|
120 | # Does not help with "By Fermat's little theorem" in PARI tutorial.
|
---|
121 |
|
---|
122 | # 1.16: Add some more E<name> escapes
|
---|
123 |
|
---|
124 | # $rcs = ' $Revision: 1.37 $ ' ;
|
---|
125 |
|
---|
126 | # $Log: pod2ipf.cmd,v $
|
---|
127 | # Revision 1.37 2010/07/27 01:40:05 vera
|
---|
128 | # No warnings (Perl or IPFC) when processing perl5.8.8 + OS2::default bundle.
|
---|
129 | # Allow for :h6.
|
---|
130 | # More debugging and error-logging, more consistent and more visible.
|
---|
131 | # Allow for head3 after head1 without intervening head2.
|
---|
132 | # Allow for blank heading titles.
|
---|
133 | # Remove $' and friends.
|
---|
134 | # Slightly smarter cutting off long headers (take into account expansion of : ).
|
---|
135 | # Breaking long line could create lines starting with . .
|
---|
136 | # Allow for duplicate section names (including path).
|
---|
137 | # Now, when X<> contain non-alphanum stuff, more careful with autoexpansion
|
---|
138 | # in SEE ALSO.
|
---|
139 | # Allow for non-terminated [CB...]< .
|
---|
140 | # When cutting-off long expanded lines, remove parts of &colon. left by the cut.
|
---|
141 | # Allow cut of for very long lines without whitespace.
|
---|
142 | #
|
---|
143 | # Revision 1.36 2006/12/25 21:35:11 vera
|
---|
144 | # Take into account trailing X<> when truncating name of the section.
|
---|
145 | # Do not double-interpret escapes in X<>: X<< IZ<><> >> lead to an empty
|
---|
146 | # index entry.
|
---|
147 | # Do not use panel numbers about 64000.
|
---|
148 | #
|
---|
149 | # Revision 1.35 2006/06/01 06:08:43 vera
|
---|
150 | # Minor cosmetic changes.
|
---|
151 | # Recognize as links things like C<function(foo)> if "function" is
|
---|
152 | # marked as X<>-reference.
|
---|
153 | #
|
---|
154 | # Revision 1.34 2003/12/17 06:31:14 vera
|
---|
155 | # Last uninitialized value warning removed.
|
---|
156 | # Include os2/Changes.
|
---|
157 | # Update perlos2.pod if needed.
|
---|
158 | # Work better with layout of "inherited" directories.
|
---|
159 | #
|
---|
160 | # Revision 1.33 2003/05/25 08:34:59 vera
|
---|
161 | # Tries harder to make links for function calls as Func();
|
---|
162 | # works at least if X<Func> is defined somewhere.
|
---|
163 | #
|
---|
164 | # Revision 1.32 2001/05/26 08:06:31 vera
|
---|
165 | # $Revision was mispelled, so not updated. [wrong case]
|
---|
166 | #
|
---|
167 | # Revision 1.31 2001/05/22 19:11:59 vera
|
---|
168 | # Omited entries in perlfunc, perlvar restored; brush up the docs.
|
---|
169 | #
|
---|
170 | # Revision 1.30 2001/05/22 10:33:27 vera
|
---|
171 | # Warnings 306 gone, but the content of perlfunc became much shorter.
|
---|
172 | #
|
---|
173 | # Revision 1.29 2001/05/22 10:06:42 vera
|
---|
174 | # Add a pod2ipf ref from About; no need to add xsubpp; most "Strip conversion
|
---|
175 | # warnings" are correct now.
|
---|
176 | #
|
---|
177 | # Revision 1.28 2001/05/22 08:57:19 vera
|
---|
178 | # Find pod2ipf too; Avoid double "Go Up"; allow .pl, .plx
|
---|
179 | # and no extension at all; do not leave NAME due only to
|
---|
180 | # long description.
|
---|
181 | #
|
---|
182 | # Revision 1.27 2001/05/16 10:04:04 vera
|
---|
183 | # Remove the undefined reference in $index_seen{$heading}; remove too
|
---|
184 | # agressive case conversion in auto-linking foo(2), better report of
|
---|
185 | # auto-linking Carp to carp.
|
---|
186 | #
|
---|
187 | # Revision 1.26 2001/05/16 09:15:24 vera
|
---|
188 | # More aggressive recognition of longjmp(3) as of a crosslink; more
|
---|
189 | # permissive recognition of links with different whitespacing, case
|
---|
190 | # conversion, and tags.
|
---|
191 | #
|
---|
192 | # Revision 1.25 2001/05/15 21:37:12 vera
|
---|
193 | # toc=12345 instead of 5; split long lines (Warning 206); debugging
|
---|
194 | # output to catch undefined $index_seen{$heading}; link inside a link
|
---|
195 | # was possible (warning 208); leading period was not completely removed
|
---|
196 | # (warning 208).
|
---|
197 | #
|
---|
198 | # Warnings remaining: Warning 306: Missing panel text in head level tag
|
---|
199 | # Warning 117: Duplicate text in tag
|
---|
200 | # Warning 121: Invalid head level [h4] (?!)
|
---|
201 | # Warning 110: No ID for this reference [4387]
|
---|
202 | #
|
---|
203 | # Revision 1.24 2001/05/15 07:30:53 vera
|
---|
204 | # Better output of About section; auto-increment $VERSION; would output ::link.
|
---|
205 | #
|
---|
206 | # Revision 1.23 2001/05/15 07:12:43 vera
|
---|
207 | # Instead of treating files with only the NAME section differently,
|
---|
208 | # added processing of the empty last POD section in the file.
|
---|
209 | #
|
---|
210 | # Revision 1.22 2001/05/15 06:23:28 vera
|
---|
211 | # xsubpp was added too aggressively; Better prefix for last resort
|
---|
212 | # description; avoid an uninit warning; the URL was removed in
|
---|
213 | # out($txt,1); no not skip NAME if nothing else is present;
|
---|
214 | #
|
---|
215 | # Revision 1.21 2001/05/15 04:25:42 vera
|
---|
216 | # Add a flexible multi-browser support.
|
---|
217 | #
|
---|
218 | # Revision 1.20 2001/05/15 01:27:37 vera
|
---|
219 | # Revision log added.
|
---|
220 | #
|
---|
221 |
|
---|
222 | #revision 1.19 locked by: vera;
|
---|
223 | #date: 2001/05/13 10:51:13; author: vera; state: Exp; lines: +3 -2
|
---|
224 | #Remove duplicate Pumpkin entry.
|
---|
225 | #----------------------------
|
---|
226 | #revision 1.18
|
---|
227 | #date: 2001/05/13 06:01:58; author: vera; state: Exp; lines: +3 -3
|
---|
228 | #Better support for =begin/=end.
|
---|
229 | #----------------------------
|
---|
230 | #revision 1.17
|
---|
231 | #date: 2001/05/13 05:59:09; author: vera; state: Exp; lines: +17 -10
|
---|
232 | #Added support for =begin, =end, =for (with no tags supported).
|
---|
233 | #----------------------------
|
---|
234 | #revision 1.16
|
---|
235 | #date: 2001/05/13 05:30:21; author: vera; state: Exp; lines: +69 -59
|
---|
236 | #Works. Courier size made tolerable on both 72 and 96 dpi.
|
---|
237 | #Unresolved link C<< (?>pattern) >>...
|
---|
238 |
|
---|
239 | $font = ''; #':font facename=Helv size=16x8.';
|
---|
240 |
|
---|
241 | $debug = 0;
|
---|
242 | $debug_xref = 0;
|
---|
243 | $dump_xref = 0;
|
---|
244 | $dump_contents = 0;
|
---|
245 | $dump_manpages = 1;
|
---|
246 | $maxtoc = '123456';
|
---|
247 | $dots = 0;
|
---|
248 | $multi_win = 1; # 1 = use alternate window for toc
|
---|
249 | @do_dirs = ();
|
---|
250 | @do_file = ();
|
---|
251 | @bin_dirs = ();
|
---|
252 | $do_burst = 1;
|
---|
253 | $do_about = 1;
|
---|
254 | $do_bin = 1;
|
---|
255 | $do_mods = 1;
|
---|
256 | $do_std = 1;
|
---|
257 | $head_off = 2;
|
---|
258 | $do_tree = 1;
|
---|
259 | $do_faqs = 1;
|
---|
260 | $by_files = $by_dirs = 0;
|
---|
261 | #$sort_files = 1;
|
---|
262 | @add_dir = ();
|
---|
263 | @add_files = ();
|
---|
264 | my @args = @ARGV;
|
---|
265 | my $foundrefs = 0;
|
---|
266 | my %i1ids;
|
---|
267 | my %index_seen;
|
---|
268 | my %index_output;
|
---|
269 | my $www = '%IPFWWW%||lynx||netscape';
|
---|
270 | #my $to_C = ':font facename=Courier size=18x10.';
|
---|
271 | #my $to_C = ':font facename=Courier size=14x8.';
|
---|
272 | my $to_C = ':font facename=Courier size=11x6.'; # Tolerable on 72/96dpi.
|
---|
273 | my $from_C = ':font facename=default size=0x0.'; # Documented: default size
|
---|
274 | @make_bold = qw(EMX RSX WPS Object-REXX HPFS HTML WWW GNU Perl C
|
---|
275 | XFree86 OS/2 CRT PM DOS VIO CPAN IBM URL);
|
---|
276 | @make_code = qw(VCPI DPMI groff awk gawk STDIN STDOUT STDERR Emacs EPM
|
---|
277 | CMD 4os2 sh pdksh zip unzip pkunzip man gcc link386 tr
|
---|
278 | PATH LIBPATH);
|
---|
279 | my %in_INC;
|
---|
280 | @in_INC{@INC} = @INC;
|
---|
281 |
|
---|
282 | sub by_dirs { by_files(); $by_files = 0; $by_dirs = 1; }
|
---|
283 | sub by_files {
|
---|
284 | $dump_manpages = 0;
|
---|
285 | $do_burst = 0;
|
---|
286 | $do_bin = 0;
|
---|
287 | $do_mods = 0;
|
---|
288 | $do_std = 0;
|
---|
289 | # $head_off = 0;
|
---|
290 | $do_tree = 0;
|
---|
291 | $do_faqs = 0;
|
---|
292 | $by_files = 1;
|
---|
293 | $by_dirs = 0;
|
---|
294 | }
|
---|
295 |
|
---|
296 | %cat_descr = (
|
---|
297 | pod => 'Perl documentation',
|
---|
298 | faqs => 'Frequently asked questions',
|
---|
299 | bin => 'Perl utilities (with POD documentation)',
|
---|
300 | mods => 'Standard Perl modules',
|
---|
301 | add_mods => 'Additional Perl modules',
|
---|
302 | do_file => 'Additional modules',
|
---|
303 | do_dirs => 'Additional directories',
|
---|
304 | tree => 'Hierarchy of documented perl modules',
|
---|
305 | pragmas => 'Pragmata: change Perl\'s behaviour',
|
---|
306 | );
|
---|
307 |
|
---|
308 | sub add_dir { # If without args, just finish processing
|
---|
309 | my $name = $_[1];
|
---|
310 | print STDERR "Starting section `$name'.\n" if @_ and $debug;
|
---|
311 | if (@do_dirs) {
|
---|
312 | @add_dir = ($cat_descr{do_dirs},[],[]) unless @add_dir;
|
---|
313 | push @{$add_dir[-2]}, @do_dirs;
|
---|
314 | @do_dirs = ();
|
---|
315 | }
|
---|
316 | if (@do_file) {
|
---|
317 | @add_dir = ($cat_descr{do_file},[],[]) unless @add_dir;
|
---|
318 | push @{$add_dir[-1]}, @do_file;
|
---|
319 | @do_file = ();
|
---|
320 | }
|
---|
321 | push @add_dir, $name, [], [] if @_;
|
---|
322 | push @add_files, $name, [], [] if @_;
|
---|
323 | }
|
---|
324 |
|
---|
325 | sub do_alias {
|
---|
326 | my $alias = $_[1];
|
---|
327 | warn("Ignoring alias $alias: no file name found"), return unless @do_file;
|
---|
328 | $alias{$do_file[-1]} = $alias;
|
---|
329 | }
|
---|
330 |
|
---|
331 | if (@ARGV >= 1 and $ARGV[0] !~ /^-/) {
|
---|
332 | unshift @ARGV, '--by-files';
|
---|
333 | unshift @ARGV, '--head-off=0' if @ARGV == 2;
|
---|
334 | }
|
---|
335 |
|
---|
336 | GetOptions(
|
---|
337 | "debug!" => \$debug,
|
---|
338 | "burst!" => \$do_burst, # Print Logo page
|
---|
339 | "about!" => \$do_about, # Print About page
|
---|
340 | "mods!" => \$do_mods, # Scan through @INC
|
---|
341 | "std!" => \$do_std, # Scan through standard Perl PODs in ./
|
---|
342 | "bin!" => \$do_bin, # Scan through $Config{bin}
|
---|
343 | "tree!" => \$do_tree, # Output tree
|
---|
344 | "faqs!" => \$do_faqs, # Output faqs
|
---|
345 | "file=s@" => \@do_file, # If present, do these files too
|
---|
346 | "dir=s@" => \@do_dirs, # Which addnl directories to scan
|
---|
347 | "dump_xref!" => \$dump_xref, # Dump them to STDERR
|
---|
348 | "dump-contents!" => \$dump_contents, # Dump it to STDERR
|
---|
349 | "dump-manpages!" => \$dump_manpages, # Dump unknown to STDERR
|
---|
350 | "title=s" => \$DocTitle,
|
---|
351 | "head-off=i" => \$head_off,
|
---|
352 | "to-bold=s@" => \@make_bold,
|
---|
353 | "to-code=s@" => \@make_code,
|
---|
354 | "by-files" => \&by_files,
|
---|
355 | "by-dirs" => \&by_dirs,
|
---|
356 | "www" => \$www, # Browser
|
---|
357 | "to-C" => \$to_C, # How to switch to CODE sections
|
---|
358 | "section-name=s" => \&add_dir,
|
---|
359 | "alias=s" => \&do_alias,
|
---|
360 | "bin-dir=s@" => \@bin_dirs, # If present, search for bins here too
|
---|
361 | "believe-pod-name!" => \$believe_pod_name, # Believe NAME section
|
---|
362 | #"sort-files!" => \$sort_files,
|
---|
363 | );
|
---|
364 | if ($by_dirs) {
|
---|
365 | push @do_dirs, @ARGV;
|
---|
366 | } elsif ($by_files) {
|
---|
367 | push @do_file, @ARGV;
|
---|
368 | } else {
|
---|
369 | warn "Ignoring \@ARGV: `@ARGV'.\n" if @ARGV;
|
---|
370 | }
|
---|
371 |
|
---|
372 | $DocTitle = "Perl $Config{version} Manual"
|
---|
373 | unless defined $DocTitle or @do_dirs or @do_file;
|
---|
374 | my $unknownPod_prefix = $do_std ? undef : "File ";
|
---|
375 |
|
---|
376 | sub unknownPod {
|
---|
377 | my $ftitle = shift;
|
---|
378 | my $fname = $modnamehash{$ftitle};
|
---|
379 | my $pref = $unknownPod_prefix;
|
---|
380 | unless (defined $pref) {
|
---|
381 | $pref = "Perl module" if $fname =~ /\.pm$/;
|
---|
382 | $pref = "Perl script" if $fname =~ /\.(plx?|bat|cmd)$/;
|
---|
383 | $pref = "Perl script" if $fname =~ m,[\\/][^\\/.]*$,;
|
---|
384 | $pref = "Perl documentation file" if $fname =~ /\.pod$/;
|
---|
385 | $pref = "Perl component" unless defined $pref;
|
---|
386 | }
|
---|
387 | "$pref $ftitle";
|
---|
388 | }
|
---|
389 |
|
---|
390 | my @www;
|
---|
391 |
|
---|
392 | $www =~ s/^\s+//;
|
---|
393 | $www =~ s/\s+$//;
|
---|
394 | if ($www =~ /\|\||\s|\@\@\@/) {
|
---|
395 | @www = map { /\@\@\@/ ? $_ : $_ . ' "@@@"' } split /\s*\|\|\s*/, $www;
|
---|
396 | } elsif (! $www =~ /\./) {
|
---|
397 | $www .= '.exe'
|
---|
398 | }
|
---|
399 |
|
---|
400 | add_dir();
|
---|
401 | $do_about = 1 if $do_burst;
|
---|
402 |
|
---|
403 | $make_bold = join '|', @make_bold;
|
---|
404 | $make_code = join '|', @make_code;
|
---|
405 |
|
---|
406 | $print_index = 1; # Do not output index for tables of contents
|
---|
407 |
|
---|
408 | debug("Module pod/pm discovery");
|
---|
409 |
|
---|
410 | $curdir = cwd;
|
---|
411 | my $site_perl_prefix;
|
---|
412 | my $libdir;
|
---|
413 |
|
---|
414 | if ((substr $Config{sitelib}, 0, length $Config{privlib})
|
---|
415 | eq $Config{privlib}) {
|
---|
416 | $site_perl_prefix = substr $Config{sitelib}, (length $Config{privlib}) + 1;
|
---|
417 | $site_perl_prefix =~ s!\\!/!g ;
|
---|
418 | }
|
---|
419 |
|
---|
420 | if (@do_file) {
|
---|
421 | foreach $file (@do_file) {
|
---|
422 | do_onefile($file);
|
---|
423 | # Fake File::Find
|
---|
424 | # $File::Find::name = $_ = $file;
|
---|
425 | # $libdir = ".";
|
---|
426 | # intern_modnamehash();
|
---|
427 | }
|
---|
428 | }
|
---|
429 | %do_file_hash = %modnamehash;
|
---|
430 | %old_hash = %modnamehash;
|
---|
431 |
|
---|
432 | sub do_onefile {
|
---|
433 | # Fake File::Find
|
---|
434 | local $_ = shift;
|
---|
435 | $libdir = shift;
|
---|
436 | my $odir;
|
---|
437 | if (defined $libdir) {
|
---|
438 | $File::Find::name = "./$_";
|
---|
439 | $odir = cwd();
|
---|
440 | chdir $libdir or warn "!!! Failed chdir($libdir): $!";
|
---|
441 | } else {
|
---|
442 | $File::Find::name = $_;
|
---|
443 | $libdir = '.';
|
---|
444 | }
|
---|
445 | intern_modnamehash();
|
---|
446 | chdir $odir if defined $odir;
|
---|
447 | }
|
---|
448 |
|
---|
449 | {
|
---|
450 | no strict 'refs';
|
---|
451 | foreach (1 .. @add_dir/3) {
|
---|
452 | foreach $libdir (@{$add_dir[3*$_-2]}) {
|
---|
453 | do_libdir $libdir;
|
---|
454 | }
|
---|
455 | foreach $file (@{$add_dir[3*$_-1]}) {
|
---|
456 | do_onefile($file);
|
---|
457 | }
|
---|
458 | print STDERR "Doing section `$_' named `$add_dir[3*$_-3]': dirs `@{$add_dir[3*$_-2]}', files `@{$add_dir[3*$_-1]}'.\n" if $debug;
|
---|
459 | %{"do_dirs$_\_hash"} = hash_diff(\%old_hash, \%modnamehash);
|
---|
460 | $cat_descr{"do_dirs$_"} = $add_dir[3*$_-3];
|
---|
461 | %old_hash = %modnamehash;
|
---|
462 | }
|
---|
463 | }
|
---|
464 |
|
---|
465 | if ($do_mods or $do_faqs) {
|
---|
466 | foreach $libdir ( @INC ) {
|
---|
467 | do_libdir $libdir;
|
---|
468 | }
|
---|
469 | %mods_hash = hash_diff(\%old_hash, \%modnamehash);
|
---|
470 | %old_hash = %modnamehash;
|
---|
471 |
|
---|
472 | my $regex = quotemeta $Config{sitelib};
|
---|
473 | foreach $key (keys %mods_hash) {
|
---|
474 | next unless $modnamehash{$key} =~ /^$regex/o;
|
---|
475 | $add_mods_hash{$key} = delete $mods_hash{$key};
|
---|
476 | }
|
---|
477 | }
|
---|
478 |
|
---|
479 | foreach $libdir ( $do_bin ? ($Config{bin}, @bin_dirs) : () ) {
|
---|
480 | do_libdir $libdir;
|
---|
481 | }
|
---|
482 | unless (@args) {
|
---|
483 | # my @xsubpp = grep -f "$_/xsubpp", map "$_/ExtUtils", @INC;
|
---|
484 | # do_onefile('xsubpp', $xsubpp[0]) if @xsubpp;
|
---|
485 | my ($dir,$file) = ($0 =~ m,^(.*)[\\/](.*),);
|
---|
486 | do_onefile($file, $dir);
|
---|
487 | }
|
---|
488 |
|
---|
489 | %bin_hash = hash_diff(\%old_hash, \%modnamehash);
|
---|
490 |
|
---|
491 | @modnames = sort keys %modnamehash;
|
---|
492 |
|
---|
493 | print STDERR "\nFound `@modnames'.\n";
|
---|
494 |
|
---|
495 | # %modnamehash now maps module name -> file name.
|
---|
496 | # %moddesc now maps module name -> description.
|
---|
497 |
|
---|
498 | @files = ();
|
---|
499 |
|
---|
500 | if ($do_std and -f 'perl.pod') {
|
---|
501 | open MPOD, 'perl.pod';
|
---|
502 | @files = ();
|
---|
503 | while (<MPOD>) {
|
---|
504 | last if /sections/;
|
---|
505 | }
|
---|
506 | while (<MPOD>) {
|
---|
507 | last if /^[^\s=]/;
|
---|
508 | push @files, [$1, $2]
|
---|
509 | if /^\s+(\S*)\s+(.*)/ and $1 ne 'perltoc' and $1 !~ /^perlfaq/;
|
---|
510 | }
|
---|
511 | close MPOD;
|
---|
512 | open MPOD, 'perltoc.pod';
|
---|
513 | while (<MPOD>) {
|
---|
514 | last if /^=head1\s+pragma/i;
|
---|
515 | }
|
---|
516 | while (<MPOD>) {
|
---|
517 | last if /^=head1/;
|
---|
518 | push @pragmas, $1 if /^=head2\s+(?:L<)?(\S*?)>?\s+-\s/;
|
---|
519 | }
|
---|
520 | close MPOD;
|
---|
521 | foreach $key (@pragmas) {
|
---|
522 | $pragmas_hash{$key} = delete $mods_hash{$key};
|
---|
523 | }
|
---|
524 | @files = grep $_->[0] ne 'perlos2', @files;
|
---|
525 | splice @files, 1, 0,
|
---|
526 | [ 'perlos2', 'Perl under OS/2' ],
|
---|
527 | [ 'perlos2delta', 'Log of changes to OS/2 port of Perl' ],
|
---|
528 | [ 'perltoc', 'Internal table of contents for Perl' ];
|
---|
529 | push @files, [ 'perlinstall', 'Installation/compilation of Perl'];
|
---|
530 | push @files, ['Pumpkin', 'Notes on handling the Perl Patch Pumpkin']
|
---|
531 | unless $] >= 5.006; # Included between modules
|
---|
532 | if (-f '../INSTALL' and not -f 'perlinstall.pod') {
|
---|
533 | copy '../INSTALL', 'perlinstall.pod';
|
---|
534 | }
|
---|
535 | if (-f '../Porting/pumpkin.pod' and not -f 'Pumpkin.pod') {
|
---|
536 | copy '../Porting/pumpkin.pod', 'Pumpkin.pod';
|
---|
537 | }
|
---|
538 | if (-f '../README.os2'
|
---|
539 | and ( not -f 'perlos2.pod' or (-M '../README.os2') < -M 'perlos2.pod' )) {
|
---|
540 | chmod 0666, 'perlos2.pod';
|
---|
541 | unlink 'perlos2.pod';
|
---|
542 | copy '../README.os2', 'perlos2.pod';
|
---|
543 | chmod 0444, 'perlos2.pod';
|
---|
544 | }
|
---|
545 | if (-f '../os2/Changes' and
|
---|
546 | (not -f 'perlos2delta.pod' or (-M '../os2/Changes') < -M 'perlos2delta.pod')) {
|
---|
547 | open my $in, '<', '../os2/Changes' or die;
|
---|
548 | chmod 0666, 'perlos2delta.pod';
|
---|
549 | open my $out, '>', 'perlos2delta.pod' or die;
|
---|
550 | print $out <<EOP;
|
---|
551 | \=head1 NAME
|
---|
552 |
|
---|
553 | perlos2delta - a POD copy of \$builddir/os2/Changes.
|
---|
554 |
|
---|
555 | \=head1 DESCRIPTION
|
---|
556 |
|
---|
557 | EOP
|
---|
558 | local $_;
|
---|
559 | while (<$in>) {
|
---|
560 | s/^(?=\S)/ /;
|
---|
561 | print $out $_;
|
---|
562 | }
|
---|
563 | chmod 0444, 'perlos2delta.pod';
|
---|
564 | }
|
---|
565 | for $file (@files) {
|
---|
566 | push @pods, $file->[0];
|
---|
567 | $pod_hash{$file->[0]}++;
|
---|
568 | $moddesc{$file->[0]} = $file->[1];
|
---|
569 | }
|
---|
570 | }
|
---|
571 |
|
---|
572 | if ($do_faqs and -f 'perlfaq.pod') {
|
---|
573 | opendir DOT, '.';
|
---|
574 | while (defined($file = readdir DOT)) {
|
---|
575 | next unless $file =~ /(perlfaq.*)[.]pod/i;
|
---|
576 | push @faqsfiles, $1;
|
---|
577 | }
|
---|
578 | closedir DOT;
|
---|
579 | # push @faqsfiles, [$1, $2] if /^\s+(\S*)\s+(.*)/ and $1 =~ /^perlfaq/;
|
---|
580 |
|
---|
581 | for $file (@faqsfiles) {
|
---|
582 | #$faqs_hash{$file}++;
|
---|
583 | print STDERR "Doing faq `$file'\n";
|
---|
584 |
|
---|
585 | $faqs_hash{$file} = delete $mods_hash{"Pod::$file"} ||
|
---|
586 | delete $mods_hash{"pod::$file"} || delete $mods_hash{$file};
|
---|
587 | delete $mods_hash{"pod::$file"};
|
---|
588 | delete $mods_hash{"$file"};
|
---|
589 | delete $mods_hash{"Pod::$file"};
|
---|
590 | delete $modnamehash{"pod::$file"};
|
---|
591 | delete $modnamehash{"$file"};
|
---|
592 | delete $modnamehash{"Pod::$file"};
|
---|
593 | # $moddesc{$file->[0]} = $file->[1];
|
---|
594 | $add_info{$file} = $1 if $moddesc{$file} =~ s/(\(\$.*\$\))//; # RCS
|
---|
595 | }
|
---|
596 | unless ($do_mods) {
|
---|
597 | %mods_hash = %add_mods_hash = ();
|
---|
598 | }
|
---|
599 | }
|
---|
600 |
|
---|
601 | #if ($do_tree) {
|
---|
602 | # create_tree([keys %modnamehash]);
|
---|
603 | #}
|
---|
604 |
|
---|
605 | my @std_categories = (qw(pod pragmas mods add_mods bin faqs do_dirs),
|
---|
606 | (map "do_dirs$_", 1 .. @add_dir/3),
|
---|
607 | qw(do_file tree));
|
---|
608 | print STDERR "Categories: `@std_categories'.\n" if $debug;
|
---|
609 |
|
---|
610 | $tree_hash{'::emit_tree'}++ if $do_tree;
|
---|
611 |
|
---|
612 | {
|
---|
613 | no strict 'refs';
|
---|
614 | for $cat (@std_categories) {
|
---|
615 | $categories{$cat} = \%{$cat . "_hash"} if %{$cat . "_hash"};
|
---|
616 | }
|
---|
617 | }
|
---|
618 |
|
---|
619 | for $pod (@files) {
|
---|
620 | $doing_pod{$pod->[0] . ".pod"}++;
|
---|
621 | }
|
---|
622 |
|
---|
623 | for $pod (qw(perlovl.pod)) {
|
---|
624 | $obsolete{$pod}++;
|
---|
625 | }
|
---|
626 |
|
---|
627 | for $pod (<*.pod>) {
|
---|
628 | $not_doing_pod{$pod}++
|
---|
629 | unless $doing_pod{$pod} or $obsolete{$pod} or $pod =~ /perlfaq/;
|
---|
630 | }
|
---|
631 |
|
---|
632 | for $pod (keys %not_doing_pod) {
|
---|
633 | print STDERR "\n!!! Unknown POD: `$pod'\n" if $do_std;
|
---|
634 | }
|
---|
635 |
|
---|
636 | for $name (sort {lc $a cmp lc $b or $a cmp $b} keys %modnamehash) {
|
---|
637 | push @files, [$name, ($moddesc{$name} || unknownPod $name)]
|
---|
638 | }
|
---|
639 |
|
---|
640 |
|
---|
641 | # in these sections an =item will be treated as an =head[n]
|
---|
642 | # this is necessary because .IPF/.INF format/compiler have
|
---|
643 | # some limitations for pane size and linking. :-(
|
---|
644 |
|
---|
645 | @split_sections =
|
---|
646 | (
|
---|
647 | 'perlfunc/DESCRIPTION/Alphabetical Listing of Perl Functions',
|
---|
648 | 'perldiag/DESCRIPTION',
|
---|
649 | 'perlvar/DESCRIPTION/Predefined Names',
|
---|
650 | );
|
---|
651 |
|
---|
652 | @index_sections = # Put first words in =item into index there
|
---|
653 | (
|
---|
654 | 'perlfunc/DESCRIPTION/Alphabetical Listing of Perl Functions',
|
---|
655 | 'perlvar/DESCRIPTION/Predefined Names',
|
---|
656 | );
|
---|
657 |
|
---|
658 | $section_head[0] = ''; # To simplify warnings
|
---|
659 | $section_head[1] = ''; # To simplify warnings
|
---|
660 |
|
---|
661 | %groups = (
|
---|
662 | links => 1,
|
---|
663 | text => 2,
|
---|
664 | logo => 3,
|
---|
665 | camel => 4,
|
---|
666 | l_camel => 5,
|
---|
667 | r_camel => 6,
|
---|
668 | sublinks => 7,
|
---|
669 | about => 8,
|
---|
670 | tree_nodes => 9,
|
---|
671 | );
|
---|
672 |
|
---|
673 | %panelwidths = ( # Make a gap.
|
---|
674 | links => '29%',
|
---|
675 | text => '69%',
|
---|
676 | sublinks => '28%',
|
---|
677 | );
|
---|
678 |
|
---|
679 | # Pickup modules which are not plain words, so it is safer to
|
---|
680 | # auto-crosslink them (with :: or _, or with mixed capitalization, or
|
---|
681 | # without vowels with at least 3 letters - avoid B and Tk):
|
---|
682 | @auto_link = grep /::|_|[a-z][A-Z]|^[^aAeEoOyYiIuU]{3,}$/, keys %alternative_name;
|
---|
683 | @auto_link{@auto_link} = (1) x @auto_link;
|
---|
684 |
|
---|
685 |
|
---|
686 | # This is the rest without vowels, will be highlighted only in obvious places:
|
---|
687 | @auto_link_hard = grep !/::|_|[a-z][A-Z]|^[^aAeEoOyYiIuU]+$/, keys %alternative_name;
|
---|
688 | @auto_link_hard{@auto_link_hard} = (1) x @auto_link_hard;
|
---|
689 |
|
---|
690 | $debug and print STDERR "\n=== Alternative names:\n";
|
---|
691 | $debug and print STDERR " ``$_''\n" for sort keys %alternative_name;
|
---|
692 |
|
---|
693 | sub out;
|
---|
694 | sub contents;
|
---|
695 | sub escape;
|
---|
696 | sub add_ref;
|
---|
697 | sub findref;
|
---|
698 | sub winhead;
|
---|
699 | sub winlink;
|
---|
700 | sub no_markup_len;
|
---|
701 | sub insert_nl;
|
---|
702 |
|
---|
703 | $/ = "";
|
---|
704 |
|
---|
705 | foreach $sc (@split_sections) { $as_head{$sc} = 1; }
|
---|
706 |
|
---|
707 | foreach $sc (@index_sections) { $fine_index{$sc} = 1; }
|
---|
708 |
|
---|
709 | if (not defined $DocTitle) {
|
---|
710 | $DocTitle = @files >= 2 ? "Manual" : $files[0][0];
|
---|
711 | $DocTitle = escape($DocTitle);
|
---|
712 | }
|
---|
713 |
|
---|
714 | $in_item_header = 0;
|
---|
715 |
|
---|
716 | # Smaller values used for some absolute ids in inline IPF
|
---|
717 | my $first_node = 30;
|
---|
718 |
|
---|
719 | for ($pass = 1; $pass <= 2; $pass++) {
|
---|
720 | if ($pass == 2) {
|
---|
721 | $auto_link_hard = join '|', map quotemeta, keys %auto_link_hard;
|
---|
722 | $auto_link = join '|', map quotemeta, keys %auto_link;
|
---|
723 | $auto_link_both = join '|', map quotemeta, keys %auto_link, keys %auto_link_hard;
|
---|
724 | print STDERR "\nautolink: $auto_link\nautolink_hard: $auto_link_hard\n"
|
---|
725 | if $debug;
|
---|
726 | }
|
---|
727 | $headno_2nd = $headno; # Used for out-of-order stuff
|
---|
728 | $headno = $first_node; # make refs hash for this on first pass
|
---|
729 |
|
---|
730 | print STDERR "pass: $pass\n";
|
---|
731 | print <<EOI if $pass == 2;
|
---|
732 | :userdoc.
|
---|
733 | :title.$DocTitle
|
---|
734 | EOI
|
---|
735 |
|
---|
736 | # Insert the Logo page.
|
---|
737 |
|
---|
738 | if ($pass == 2 and $do_burst) {
|
---|
739 | # We position burst window low, so it does not obsure Contents and/or
|
---|
740 | # titles of information windows, and Contents does not obsure us
|
---|
741 | # (completely).
|
---|
742 | print <<EOI;
|
---|
743 | :h1 group=$groups{logo} x=7% width=87% y=1% height=90% id=11 scroll=none.Logo
|
---|
744 | :i1.Logo
|
---|
745 | :link reftype=hd refid=12 auto split group=$groups{l_camel}
|
---|
746 | vpx=left vpy=center vpcx=25c vpcy=12c
|
---|
747 | scroll=none titlebar=none rules=none.
|
---|
748 | :link reftype=hd refid=13 auto split group=$groups{r_camel}
|
---|
749 | vpx=right vpy=center vpcx=25c vpcy=12c
|
---|
750 | scroll=none titlebar=none rules=none.
|
---|
751 | :link reftype=hd refid=14 auto split group=$groups{camel}
|
---|
752 | vpx=center vpy=center vpcx=312x vpcy=390p
|
---|
753 | scroll=none titlebar=none rules=none.
|
---|
754 | :h2 hide noprint nosearch id=12.Dummy
|
---|
755 | :lines.
|
---|
756 | :link reftype=hd group=$groups{links} dependent vpx=left vpcx=$panelwidths{links} refid=@{[findrefid('perl')]}.Enter here!:elink.
|
---|
757 |
|
---|
758 | :link reftype=hd group=$groups{links} dependent vpx=left vpcx=$panelwidths{links} refid=@{[findrefid('perlos2')]}.Perl and OS/2:elink.
|
---|
759 |
|
---|
760 | :link reftype=hd group=$groups{text} dependent vpx=right vpcx=$panelwidths{text} refid=@{[findrefid('CPAN')]}.Where to get ...:elink.
|
---|
761 |
|
---|
762 | :link reftype=hd group=$groups{text} dependent vpx=right vpcx=$panelwidths{text} refid=@{[findrefid('ExtUtils::MakeMaker/Default Makefile Behaviour')]}.After you got it:elink.
|
---|
763 |
|
---|
764 | :link reftype=hd group=$groups{links} dependent vpx=left vpcx=$panelwidths{links} refid=@{[findrefid('perltrap')]}.This should work!:elink.
|
---|
765 |
|
---|
766 | :link reftype=hd group=$groups{links} dependent vpx=left vpcx=$panelwidths{links} refid=@{[findrefid('perldebug')]}.But it does not!:elink.
|
---|
767 | :elines.
|
---|
768 | :h2 hide noprint nosearch id=13.Dummy
|
---|
769 | :lines align=right.
|
---|
770 | :link reftype=hd group=$groups{links} dependent vpx=left vpcx=$panelwidths{links} refid=@{[findrefid('perlbook')]}.The fine book:elink.
|
---|
771 |
|
---|
772 | :link reftype=hd group=$groups{links} dependent vpx=left vpcx=$panelwidths{links} refid=@{[findrefid('perlmod')]}.Perl extensions:elink.
|
---|
773 |
|
---|
774 | :link reftype=hd group=$groups{links} dependent vpx=left vpcx=$panelwidths{links} refid=@{[findrefid('perlxs')]}.C extensions:elink.
|
---|
775 |
|
---|
776 | :link reftype=hd group=$groups{links} dependent vpx=left vpcx=$panelwidths{links} refid=@{[findrefid('perlguts')]}.Inside Camel:elink.
|
---|
777 |
|
---|
778 | :link reftype=hd group=$groups{links} dependent vpx=left vpcx=$panelwidths{links} refid=@{[findrefid('perlstyle')]}.Ugly code:elink.
|
---|
779 |
|
---|
780 | :link reftype=hd group=$groups{about} dependent refid=29.About:elink.
|
---|
781 | :elines.
|
---|
782 | :h2 hide noprint nosearch id=14.Dummy
|
---|
783 | :artwork align=center name='CamelGrayBig.BMP'.
|
---|
784 | Do not forget that you can alway click on :hp9.Contents:ehp9., :hp9.Search:ehp9., and :hp9.Index:ehp9. buttons (or use :hp8.Alt-t:ehp8., :hp8.Alt-s:ehp8., :hp8.Alt-i:ehp8. correspondingly).
|
---|
785 | :font facename=Courier size=7x5. The use of a camel image in conjunction with Perl is a trademark of
|
---|
786 | O'Reilly &. Associates, Inc.:font facename=default size=0x0.
|
---|
787 |
|
---|
788 | EOI
|
---|
789 | }
|
---|
790 | if ($pass == 2 and $do_about) {
|
---|
791 | print <<EOI;
|
---|
792 | :h1 toc=1 group=$groups{about} x=center width=100% y=center height=20% id=29.About
|
---|
793 | EOI
|
---|
794 | print out(<<EOI, 1);
|
---|
795 | Generated on @{[scalar localtime]}, by L<perl> version $],
|
---|
796 | L<pod2ipf> version $VERSION @{[format_args]} in directory F<@{[cwd]}>.
|
---|
797 | EOI
|
---|
798 | }
|
---|
799 | if ($head_off <= 1 or (keys %categories) <= 1) {
|
---|
800 | if ($head_off > 1) {
|
---|
801 | $headno_2nd++;
|
---|
802 | print <<EOP if $pass == 2;
|
---|
803 | :h1 toc=$maxtoc group=$groups{links} x=left width=$panelwidths{links} id=$headno_2nd.$DocTitle
|
---|
804 | $DocTitle.
|
---|
805 |
|
---|
806 | EOP
|
---|
807 | }
|
---|
808 | for ($fn = 0; $fn <= $#files; $fn++) {
|
---|
809 | output_file($files[$fn][0]);
|
---|
810 | }
|
---|
811 | } else {
|
---|
812 | # Separate into categories:
|
---|
813 | my @titles;
|
---|
814 | for $cat (@std_categories) {
|
---|
815 | next unless $categories{$cat};
|
---|
816 | insert_back($headno) if $pass == 2;;
|
---|
817 | category_emit($cat) if $pass == 2;
|
---|
818 | @titles = sort {lc $a cmp lc $b or $a cmp $b}
|
---|
819 | keys %{$categories{$cat}};
|
---|
820 | @titles = @pods if $cat eq 'pod'; # Preserve the sorting order
|
---|
821 | for $title (@titles) {
|
---|
822 | if ($title eq '::emit_tree') {
|
---|
823 | output_tree(create_tree([keys %modnamehash]), '', 2) if $pass == 2;
|
---|
824 | } else {
|
---|
825 | output_file($title);
|
---|
826 | }
|
---|
827 | }
|
---|
828 | }
|
---|
829 | }
|
---|
830 | }
|
---|
831 |
|
---|
832 | print "\n:euserdoc.\n";
|
---|
833 |
|
---|
834 | if ($dump_xref) {
|
---|
835 | foreach (keys %links) {
|
---|
836 | print STDERR $_ . "->" . $links{$_} . "\n";
|
---|
837 | }
|
---|
838 | }
|
---|
839 | if ($dump_contents) {
|
---|
840 | for($i = 0; $i <= $#head; $i++) {
|
---|
841 | print STDERR " " x $headlevel[$i], $head[$i], "\n";
|
---|
842 | }
|
---|
843 | }
|
---|
844 | if ($dump_manpages) {
|
---|
845 | my @arr = sort keys %unknown_manpages;
|
---|
846 | print STDERR "Unknown manpages: @arr.\n";
|
---|
847 | }
|
---|
848 | print STDERR "Found $foundrefs crosslinks.\n";
|
---|
849 |
|
---|
850 | sub category_emit {
|
---|
851 | my $cat = shift;
|
---|
852 | $headno_2nd++;
|
---|
853 | print <<EOP;
|
---|
854 | :h1 toc=$maxtoc group=$groups{links} x=left width=$panelwidths{links} id=$headno_2nd.$cat_descr{$cat}
|
---|
855 | $cat_descr{$cat}.
|
---|
856 |
|
---|
857 | EOP
|
---|
858 | }
|
---|
859 |
|
---|
860 | sub process_index {
|
---|
861 | unless ($print_index) {
|
---|
862 | @index = ();
|
---|
863 | return;
|
---|
864 | }
|
---|
865 | my %seen;
|
---|
866 | for (@index) {
|
---|
867 | $seen{$_}++;
|
---|
868 | }
|
---|
869 | print "\n" if @index;
|
---|
870 | for (keys %seen) {
|
---|
871 | print ":i1." . out($_, 0) . "\n";
|
---|
872 | }
|
---|
873 | @index = ();
|
---|
874 | }
|
---|
875 |
|
---|
876 | my $last_hl = 123; # Very big
|
---|
877 | sub output_preheader ($) { # Fix head3 coming after head2; wrong for IPF
|
---|
878 | my $level = shift; # Warning 121 ==> Warning 110
|
---|
879 | print STDERR " Jump in level: was $last_hl, now $level.\n"
|
---|
880 | if $level > $last_hl + 1;
|
---|
881 | while ($level > $last_hl + 1) {
|
---|
882 | $last_hl++; # Same as tree nodes:
|
---|
883 | print ":h$last_hl group=$groups{tree_nodes} x=left width=10% y=top height=10%.---fake-fix-level-node---\n:p.\n------------ Intentionally blank (missing level in the source POD) -----------\n"
|
---|
884 | }
|
---|
885 | $last_hl = $level;
|
---|
886 | }
|
---|
887 |
|
---|
888 | sub non_empty ($) {
|
---|
889 | my $p = shift;
|
---|
890 | (length $p) ? $p : '=' x 40;
|
---|
891 | }
|
---|
892 |
|
---|
893 | sub output_file {
|
---|
894 | my $ftitle = shift;
|
---|
895 | #warn "<<<doing file for `$ftitle'\n";
|
---|
896 | my $fcomment = $moddesc{$ftitle} || unknownPod $ftitle;
|
---|
897 | my $begin_depth = 0;
|
---|
898 |
|
---|
899 | $fname = $ftitle . '.pod';
|
---|
900 | if (not -f "./$fname") { # Protect 'B::C.pod' from accessing B drive
|
---|
901 | $fname = $modnamehash{$ftitle};
|
---|
902 | }
|
---|
903 | $page = $ftitle;
|
---|
904 | $toc = substr $maxtoc, -1, 1;
|
---|
905 | @index = ();
|
---|
906 |
|
---|
907 | open(IN, $fname) || die "$ftitle: open `$fname': $!";
|
---|
908 | print STDERR $fname . ": ";
|
---|
909 | print STDERR "\n" if !$dots;
|
---|
910 |
|
---|
911 | $section = $ftitle . ' - ' . $fcomment;
|
---|
912 | $section_head[1] = $page;
|
---|
913 | $path = $section_head[1];
|
---|
914 | $headno++;
|
---|
915 | #warn "<<<incremented headno to $headno, page='$page', washead='$heading' out='$section'\n";
|
---|
916 | if ($pass == 1) {
|
---|
917 | addsection($section, $headno, 1);
|
---|
918 | add_ref($page, $headno);
|
---|
919 | $is_head{$ftitle}++;
|
---|
920 | }
|
---|
921 | if ($pass == 2) {
|
---|
922 | insert_nl;
|
---|
923 | my $hlevel = $head_off >= 1 ? $head_off : 1;
|
---|
924 | # Done with $processing_endfile now:
|
---|
925 | output_preheader($hlevel);
|
---|
926 | print ":h$hlevel toc=$maxtoc " . winhead($headno)
|
---|
927 | . " id=$headno."
|
---|
928 | # See DBD::CVS: empty =head; Warning 113: No text found in tag [h3]
|
---|
929 | . non_empty(out($section, 0))
|
---|
930 | . "\n" . $font; # Headers take no fonts.
|
---|
931 | output_index($section, $ftitle);
|
---|
932 | output_index($ftitle, $ftitle);
|
---|
933 | if (exists $add_info{$ftitle}) {
|
---|
934 | print out($add_info{$ftitle}, 0), ":p.\n"
|
---|
935 | }
|
---|
936 | $was_nl = 1;
|
---|
937 | } else {
|
---|
938 | count_index($section);
|
---|
939 | count_index($ftitle);
|
---|
940 | }
|
---|
941 |
|
---|
942 | @lstack = ();
|
---|
943 | # These variables are different when =item is treated as =head
|
---|
944 | $emptypane = $emptysection = 1; # Always: TOC for the file
|
---|
945 | $inpod = 0;
|
---|
946 | my $processing_endfile;
|
---|
947 |
|
---|
948 | PARA: while (defined ($line = <IN>) or ++$processing_endfile) {
|
---|
949 | chomp $line unless $processing_endfile;
|
---|
950 | if ($processing_endfile or $line =~ /^=\w+((?s:.*))/) {
|
---|
951 | if ($processing_endfile or $line =~ /^=head(\d+)\b\s*((?s:.*))/) {
|
---|
952 | $inpod = 1;
|
---|
953 | $nopara = 0;
|
---|
954 | $heading = $+;
|
---|
955 | unless ($processing_endfile) {
|
---|
956 | $heading =~ s/\s*$//; # localize $1
|
---|
957 | $heading = untabify $heading;
|
---|
958 | }
|
---|
959 |
|
---|
960 | if (@lstack) {
|
---|
961 | print STDERR " List not finished (@lstack) in (@section_head[1..$hl]).\n"
|
---|
962 | if $pass == 1;
|
---|
963 | while ($#lstack >= 0) {
|
---|
964 | $t = pop(@lstack);
|
---|
965 | if ($t eq 'ul') {
|
---|
966 | print ":eul.\n" if $pass == 2;
|
---|
967 | $was_nl = 1;
|
---|
968 | } elsif ($t eq 'ol') {
|
---|
969 | print ":eol.\n" if $pass == 2;
|
---|
970 | $was_nl = 1;
|
---|
971 | } elsif ($t eq 'parml') {
|
---|
972 | print ":eparml.\n" if $pass == 2;
|
---|
973 | $was_nl = 1;
|
---|
974 | } elsif ($t eq 'head' or $t eq 'finehead') {
|
---|
975 | $hl--;
|
---|
976 | $path = join('/', @section_head[1..$hl]);
|
---|
977 | }
|
---|
978 | }
|
---|
979 | }
|
---|
980 |
|
---|
981 | unless ($processing_endfile) {
|
---|
982 | $hl = $1 + 1;
|
---|
983 | $section_head[$hl] = $heading;
|
---|
984 | $path = join('/', @section_head[1..$hl]);
|
---|
985 | $sh_path = join('/', @section_head[1..$hl-1]);
|
---|
986 | if ($skip_sections{$path}) {
|
---|
987 | $inpod = 0;
|
---|
988 | next PARA;
|
---|
989 | }
|
---|
990 | }
|
---|
991 | # Finish the previous sections:
|
---|
992 | contents($headno) if $emptypane;
|
---|
993 | insert_back($headno); # Previous header
|
---|
994 | last PARA if $processing_endfile;
|
---|
995 |
|
---|
996 | $headno++;
|
---|
997 | if ($pass == 1) {
|
---|
998 | addsection($heading, $headno, $hl);
|
---|
999 | # XXXX Is wrong with some escapes:
|
---|
1000 | #1 while $heading =~ s/[A-Z]<.*?>/$1/g;
|
---|
1001 | add_ref(qq|$page/"$heading"|, $headno);
|
---|
1002 | $is_head{$heading}++;
|
---|
1003 | }
|
---|
1004 | if ($pass == 2) {
|
---|
1005 | insert_nl;
|
---|
1006 | output_preheader($hl + $head_off - 1);
|
---|
1007 | print ":h$last_hl " . winhead($headno)
|
---|
1008 | . " id=$headno."
|
---|
1009 | # See DBD::CVS: empty =head; Warning 113: No text found in tag [h3]
|
---|
1010 | . non_empty(out($heading, 0)) . "\n" . $font; # Headers take no fonts
|
---|
1011 | output_index($heading, $path);
|
---|
1012 | } else {
|
---|
1013 | count_index($heading);
|
---|
1014 | }
|
---|
1015 | print STDERR "." if $dots;
|
---|
1016 | $emptypane = $emptysection = 1;
|
---|
1017 | } elsif ($line =~ /^=over\b\s*((?s:.*))/) {
|
---|
1018 | $inpod = 1;
|
---|
1019 | $step = 5; # Default
|
---|
1020 | $step = $1 if $1 =~ /(\d+)/;
|
---|
1021 | $step = int($step * 4/3 + 0.5); # Take into account proportional font
|
---|
1022 | # look ahead, to see how the list should look like
|
---|
1023 | if ($pass == 1 and $inpod and $begin_depth == 0) {
|
---|
1024 | $auto_link_hard{$1}++,
|
---|
1025 | $x_index{$1} = $headno
|
---|
1026 | while $line =~ /X<([^<>]+)>/g;
|
---|
1027 | }
|
---|
1028 | chomp($line = <IN>);
|
---|
1029 | if ($pass == 1) {
|
---|
1030 | $auto_link_hard{$1}++ while $line =~ /X<([^<>]+)+>/g;
|
---|
1031 | }
|
---|
1032 | if ($line =~ /^\=item(\s*$|\s+\*)/) { # item * (or empty)
|
---|
1033 | push(@lstack, "ul");
|
---|
1034 | insert_nl if $pass == 2;
|
---|
1035 | print ":ul.\n" if $pass == 2;
|
---|
1036 | $was_nl = 1;
|
---|
1037 | } elsif ($line =~ /^\=item\s+1\.?/) { # item 1.
|
---|
1038 | push(@lstack, "ol");
|
---|
1039 | insert_nl if $pass == 2;
|
---|
1040 | print ":ol.\n" if $pass == 2;
|
---|
1041 | $was_nl = 1;
|
---|
1042 | } elsif (defined($as_head{$path})) {
|
---|
1043 | # in some cases we use headings instead of lists
|
---|
1044 | warn "toc for $page, id=$headno too low" if ! $toc >= $hl + 1;
|
---|
1045 | push(@lstack, $fine_index{$path} ? "finehead" : "head");
|
---|
1046 | $hl++;
|
---|
1047 | $section_head[$hl] = 'list_start';
|
---|
1048 | @eitems = ();
|
---|
1049 | } else {
|
---|
1050 | push(@lstack, "parml");
|
---|
1051 | insert_nl if $pass == 2;
|
---|
1052 | print ":parml break=fit tsize=$step.\n" if $pass == 2;
|
---|
1053 | $was_nl = 1;
|
---|
1054 | }
|
---|
1055 | $nopara = 0;
|
---|
1056 | redo PARA;
|
---|
1057 | } elsif ($line =~ /^=back\b/) {
|
---|
1058 | $inpod = 1;
|
---|
1059 | if ($#lstack >= 0) {
|
---|
1060 | $t = pop(@lstack);
|
---|
1061 | if ($t eq 'ul') {
|
---|
1062 | insert_nl if $pass == 2;
|
---|
1063 | print ":eul.\n" if $pass == 2;
|
---|
1064 | $was_nl = 1;
|
---|
1065 | } elsif ($t eq 'ol') {
|
---|
1066 | insert_nl if $pass == 2;
|
---|
1067 | print ":eol.\n" if $pass == 2;
|
---|
1068 | $was_nl = 1;
|
---|
1069 | } elsif ($t eq 'parml') {
|
---|
1070 | insert_nl if $pass == 2;
|
---|
1071 | print ":eparml.\n" if $pass == 2;
|
---|
1072 | $was_nl = 1;
|
---|
1073 | } elsif ($t eq 'head' or $t eq 'finehead') {
|
---|
1074 | $hl--;
|
---|
1075 | $path = join('/', @section_head[1..$hl]);
|
---|
1076 | }
|
---|
1077 | } else {
|
---|
1078 | print STDERR " stack empty on page=$page, id=$headno";
|
---|
1079 | $hl--;
|
---|
1080 | }
|
---|
1081 | $nopara = 0;
|
---|
1082 | } elsif ($line =~ /^=item\b\s*((?s:.*))/) {
|
---|
1083 | $inpod = 1;
|
---|
1084 | $nopara = 0;
|
---|
1085 | $heading = $1;
|
---|
1086 | $heading =~ s/\s+$//;
|
---|
1087 | $heading = untabify($heading);
|
---|
1088 | $heading =~ s/^\*\s*//; # Too late to process \* anyway
|
---|
1089 | #warn "<<<set head='$heading'\n";
|
---|
1090 | $headx = $heading;
|
---|
1091 | # Unescape
|
---|
1092 | $headx =~ s/E<(.*?)>/$HTML_Escapes{$1} or "E<$1>"/ge;
|
---|
1093 | 1 while $headx =~ s/[A-Z]<(.*?)>/$1/g;
|
---|
1094 | print STDERR "." if $dots;
|
---|
1095 | if ($#lstack == -1) {
|
---|
1096 | push(@lstack, "parml");
|
---|
1097 | insert_nl if $pass == 2;
|
---|
1098 | print ":parml break=fit tsize=7.\n" if $pass == 2;
|
---|
1099 | $was_nl = 1;
|
---|
1100 | print STDERR " An =item without =over in (@section_head[1..$hl])\n"
|
---|
1101 | }
|
---|
1102 | if ($lstack[$#lstack] eq 'head'
|
---|
1103 | or $lstack[$#lstack] eq 'finehead') {
|
---|
1104 | contents($headno - 1) if $emptypane and not @eitems;
|
---|
1105 | insert_back($headno - 1)
|
---|
1106 | unless $emptysection or @eitems; # Previous uplink
|
---|
1107 |
|
---|
1108 | # lowest level never empty, IPFC uses next page
|
---|
1109 | # by default (but Back button doesn't work :-()
|
---|
1110 | #
|
---|
1111 | # However, we treat it specially anyway
|
---|
1112 | $emptypane = 0;
|
---|
1113 | $emptysection = 1;
|
---|
1114 |
|
---|
1115 | my ($word1, $word2);
|
---|
1116 | $headx =~ /(\^?\w+)/; # $^A
|
---|
1117 | $word1 = $1;
|
---|
1118 | $headx =~ /(\S+)/;
|
---|
1119 | $word2 = $1;
|
---|
1120 | $section_head[$hl] = $heading;
|
---|
1121 | $path = join('/', @section_head[1..$hl]);
|
---|
1122 | $sh_path = join('/', @section_head[1..$hl-1]);
|
---|
1123 | insert_nl if $pass == 2;
|
---|
1124 | $headno++;
|
---|
1125 | #warn "<<<incremented headno to $headno, page='$page', head='$heading'\n";
|
---|
1126 | if ($pass == 1) {
|
---|
1127 | addsection($heading, $headno, $hl);
|
---|
1128 | add_ref(qq|$page/"$headx"|, $headno);
|
---|
1129 | add_ref(qq|$page/"$word1"|, $headno) if defined $word1;
|
---|
1130 | add_ref(qq|$page/"$word2"|, $headno) if defined $word2;
|
---|
1131 | }
|
---|
1132 | if ($pass == 2 and not @eitems) {
|
---|
1133 | output_preheader($hl + $head_off - 1);
|
---|
1134 | # See DBD::CVS: empty =head; Warning 113: No text found in tag [h3]
|
---|
1135 | print ":h$last_hl " . winhead($headno) . " id=$headno."
|
---|
1136 | . non_empty(out($heading, 0)) . "\n" . $font;
|
---|
1137 | } # Headers take no fonts
|
---|
1138 | output_index($heading, $path);
|
---|
1139 | $was_nl = 1;
|
---|
1140 | if ($#lstack >= 0
|
---|
1141 | and $lstack[$#lstack] eq 'finehead') {
|
---|
1142 | output_index($word1, $path)
|
---|
1143 | if defined $word1 and $word1 ne $heading;
|
---|
1144 | output_index($word2, $path)
|
---|
1145 | if defined $word2 and $word2 ne $heading
|
---|
1146 | and $word2 ne $word1;
|
---|
1147 | }
|
---|
1148 | $is_head{$heading}++ if $pass == 1; # XXXX Need to strip?
|
---|
1149 |
|
---|
1150 | if ($pass == 1 and $inpod and $begin_depth == 0) {
|
---|
1151 | $auto_link_hard{$1}++,
|
---|
1152 | $x_index{$1} = $headno
|
---|
1153 | while $line =~ /X<([^<>]+)>/g;
|
---|
1154 | }
|
---|
1155 |
|
---|
1156 | # look ahead to see if this =item is empty.
|
---|
1157 | # if it is, create a list of the items
|
---|
1158 | # on first non-empty pane.
|
---|
1159 | chomp($line = <IN>);
|
---|
1160 | if ($line =~ /^=item\b/) {
|
---|
1161 | push @eitems, $heading;
|
---|
1162 | $headno--;
|
---|
1163 | } elsif (@eitems) {
|
---|
1164 | push @eitems, $heading;
|
---|
1165 | if ($pass == 1) {
|
---|
1166 | $hl_eitems{$headno} = [@eitems];
|
---|
1167 | } else {
|
---|
1168 | foreach $l (@eitems) {
|
---|
1169 | print ":p.:hp2." . out($l, 1) . ":ehp2.";
|
---|
1170 | }
|
---|
1171 | }
|
---|
1172 | @eitems = ();
|
---|
1173 | }
|
---|
1174 | if ($pass == 1) {
|
---|
1175 | $auto_link_hard{$1}++ while /X<([^<>]+)+>/g;
|
---|
1176 | }
|
---|
1177 | redo PARA;
|
---|
1178 | } else { # Different list's items
|
---|
1179 | local $in_item_header = 1;
|
---|
1180 | $emptypane = $emptysection = 0;
|
---|
1181 | add_ref(qq|$page/"$headx"|, $headno, 1);
|
---|
1182 | if ($lstack[$#lstack] eq 'ul' && $heading =~ /^\s*\*\s*(.*)$/ or
|
---|
1183 | $lstack[$#lstack] eq 'ol' && $heading =~ /^\s*\d+\.?\s*(.*)$/) { # Bulleted or numbered item matching list type.
|
---|
1184 | print ":li." if $pass == 2;
|
---|
1185 | $heading = $1;
|
---|
1186 | #warn "<<<set head='$heading'\n";
|
---|
1187 | if ($1 ne "") {
|
---|
1188 | print out($heading, 1) . "\n" if $pass == 2;
|
---|
1189 | output_index($heading, $path)
|
---|
1190 | unless $is_head{$heading};
|
---|
1191 | $was_nl = 1;
|
---|
1192 | } else {
|
---|
1193 | $nopara = 1;
|
---|
1194 | $was_nl = 0;
|
---|
1195 | }
|
---|
1196 | } elsif ($lstack[$#lstack] eq 'parml') {
|
---|
1197 | print ":pt." if $pass == 2;
|
---|
1198 | $heading =~ s/^\s*\*?\s+//;
|
---|
1199 | $heading =~ s/\s+$//;
|
---|
1200 | $heading = '*' if $heading eq '';
|
---|
1201 | #warn "<<<set head='$heading'\n";
|
---|
1202 | print out($heading, 1) . "\n" if $pass == 2;
|
---|
1203 | output_index($heading, $path)
|
---|
1204 | unless $is_head{$heading} or $heading eq '*' or $heading eq '';
|
---|
1205 | print ":pd." if $pass == 2;
|
---|
1206 | $nopara = 1;
|
---|
1207 | $was_nl = 0;
|
---|
1208 | } else {
|
---|
1209 | print ":li." . out($heading, 1) . "\n" if $pass == 2;
|
---|
1210 | output_index($heading, $path)
|
---|
1211 | unless $heading eq '' or $heading eq '*' or $is_head{$heading};
|
---|
1212 | $was_nl = 1;
|
---|
1213 | $nopara = 1;
|
---|
1214 | }
|
---|
1215 | }
|
---|
1216 | } elsif ($line =~ /^=cut/) {
|
---|
1217 | $inpod = 0;
|
---|
1218 | } elsif ($line =~ /^=pod/) {
|
---|
1219 | $inpod = 1;
|
---|
1220 | } elsif ($line =~ /^=for\b/) { # Ignore
|
---|
1221 | } elsif ($line =~ /^=begin\b/) {
|
---|
1222 | $begin_depth++;
|
---|
1223 | } elsif ($line =~ /^=end\b/) {
|
---|
1224 | $begin_depth--;
|
---|
1225 | } else {
|
---|
1226 | warn "what to do with '$line'?\n";
|
---|
1227 | }
|
---|
1228 | } elsif ($inpod == 0 or $begin_depth) {
|
---|
1229 | # Just ignore this chunk
|
---|
1230 | } elsif ($line =~ /^[ \t]+\S/) {
|
---|
1231 | if ($pass == 2) {
|
---|
1232 | $pre = untabify($line);
|
---|
1233 | insert_nl;
|
---|
1234 | # A long code line with : expanded to &colon.
|
---|
1235 | 1 while $pre =~ s/^((?:\:|(?>[^\n:]{1,7})){33})(?=[^\n])/$1\n/gm; # Warning 206
|
---|
1236 | $pre =~ s/^\./&per./mg; # period. Warning 204
|
---|
1237 | print ":xmp.$to_C\n" . escape_with_url($pre)
|
---|
1238 | . "\n:exmp.$from_C\n";
|
---|
1239 | $was_nl = 1;
|
---|
1240 | }
|
---|
1241 | $nopara = 0;
|
---|
1242 | $emptypane = $emptysection = 0;
|
---|
1243 | } elsif ($line =~ /^[ \t]+\S/m) { # see perl(run)?/SYNOPSIS for this
|
---|
1244 | if ($pass == 2) {
|
---|
1245 | $mark = out($line, 1);
|
---|
1246 |
|
---|
1247 | # hack hack ;-)
|
---|
1248 | # IPFC doesn't handle tabs
|
---|
1249 | # no_markup_len tries to guess the # of ' ' to next tab,
|
---|
1250 | # but even when the guess is correct, things don't seem
|
---|
1251 | # to align when bold,.. is used :-(
|
---|
1252 | $pre = untabify_after($mark);
|
---|
1253 |
|
---|
1254 | insert_nl;
|
---|
1255 | # Do not split inside &something.
|
---|
1256 | 1 while $pre =~ s/^(.{240}(?=.{13}))[^\n&]{0,12}(?=[^\n])/$1\n/gm; # Warning 206
|
---|
1257 | $pre =~ s/^\./&per./mg; # period. Warning 204
|
---|
1258 | print ":xmp.$to_C\n" . $pre . "\n:exmp.$from_C\n";
|
---|
1259 | $was_nl = 1;
|
---|
1260 | }
|
---|
1261 | $nopara = 0;
|
---|
1262 | $emptypane = $emptysection = 0;
|
---|
1263 | } else {
|
---|
1264 | if ($pass == 2) {
|
---|
1265 | print ":p.\n" unless $nopara;
|
---|
1266 | print out(untabify($line), 1);
|
---|
1267 | process_index();
|
---|
1268 | $was_nl = 0;
|
---|
1269 | } else {
|
---|
1270 | if ($line =~ /^\s+$/) {
|
---|
1271 | warn "line with blanks in $page, id=$headno\n";
|
---|
1272 | }
|
---|
1273 | }
|
---|
1274 | $nopara = 0;
|
---|
1275 | $emptypane = $emptysection = 0;
|
---|
1276 | }
|
---|
1277 | if ($pass == 1 and $inpod and $begin_depth == 0) {
|
---|
1278 | $auto_link_hard{$1}++,
|
---|
1279 | $x_index{$1} = $headno
|
---|
1280 | while $line =~ /X<([^<>]+)>/g;
|
---|
1281 | }
|
---|
1282 | }
|
---|
1283 | close(IN);
|
---|
1284 | print STDERR "\n" if $dots;
|
---|
1285 | }
|
---|
1286 |
|
---|
1287 | sub output_tree {
|
---|
1288 | my ($tree, $prefix, $level) = @_;
|
---|
1289 | my ($node, $mod);
|
---|
1290 | foreach $node (sort keys %$tree) {
|
---|
1291 | $headno_2nd++;
|
---|
1292 | if ($prefix eq '') {
|
---|
1293 | $mod = substr $node, 2;
|
---|
1294 | } else {
|
---|
1295 | $mod = "$prefix$node";
|
---|
1296 | }
|
---|
1297 | if (ref $tree->{$node}) { # Subtree
|
---|
1298 | print <<EOP;
|
---|
1299 | :h$level group=$groups{tree_nodes} x=left width=10% y=top height=10% id=$headno_2nd.@{[escape $mod]}...
|
---|
1300 |
|
---|
1301 | EOP
|
---|
1302 | output_tree($tree->{$node}, $mod, $level + 1);
|
---|
1303 | } else {
|
---|
1304 | print <<EOP;
|
---|
1305 | :h$level group=$groups{tree_nodes} x=left width=10% y=top height=10% id=$headno_2nd.@{[escape $mod]}
|
---|
1306 | :link reftype=hd group=$groups{links} auto vpx=left vpcx=$panelwidths{links} refid=@{[findrefid($mod)]}.
|
---|
1307 | @{[escape $mod]}
|
---|
1308 |
|
---|
1309 | EOP
|
---|
1310 | }
|
---|
1311 | }
|
---|
1312 | }
|
---|
1313 |
|
---|
1314 | sub untabify {
|
---|
1315 | my @tlines = split(/\n/, shift);
|
---|
1316 | my $tline;
|
---|
1317 | foreach $tline (@tlines) {
|
---|
1318 | 1 while $tline =~ s/^(.*?)(\t+)/$1.(' 'x (length($2) * 8 - length($1) % 8))/e;
|
---|
1319 | }
|
---|
1320 | join("\n", @tlines);
|
---|
1321 | }
|
---|
1322 |
|
---|
1323 | sub untabify_after { # Some markup is already there.
|
---|
1324 | my @tlines = split(/\n/, shift);
|
---|
1325 | my $tline;
|
---|
1326 | foreach $tline (@tlines) {
|
---|
1327 | 1 while $tline =~ s/^(.*?)(\t+)/$1.(' 'x (length($2) * 8 - &no_markup_len($1) % 8))/e;
|
---|
1328 | }
|
---|
1329 | join("\n", @tlines);
|
---|
1330 | }
|
---|
1331 |
|
---|
1332 | {
|
---|
1333 | my ($id_c, %path_c) = (0);
|
---|
1334 | sub i1id {
|
---|
1335 | return $i1ids{$_[0]} if exists $i1ids{$_[0]};
|
---|
1336 | $i1ids{$_[0]} = "id_" . ++$id_c;
|
---|
1337 | }
|
---|
1338 | sub path_c ($) {
|
---|
1339 | my $p = shift;
|
---|
1340 | $p = s/^((:|[^:]{7}){17})(?=...)/$1.../; # Warning 205: Text too long in tag [i2]
|
---|
1341 | return $p unless $path_c{$p}++;
|
---|
1342 | return "$p\[$path_c{$p}]"; # Warning 117: duplicate text in tag
|
---|
1343 | }
|
---|
1344 | }
|
---|
1345 |
|
---|
1346 | sub trunc_heading {
|
---|
1347 | my ($h, $with_ind) = (shift, shift);
|
---|
1348 | # Some indexes are merged into headings; do a naive search
|
---|
1349 | $h =~ s/\b((X(<[^<>]+>|<< (?>.*? >>)|<<< (?>.*? >>>))\s*)+)//;
|
---|
1350 | my $x = $1;
|
---|
1351 | $h =~ s/\s+/ /g;
|
---|
1352 | $h =~ s/\s$//;
|
---|
1353 | $h = substr($h, 0, 110) . "..." if length $h > 124;
|
---|
1354 | return $h unless $with_ind;
|
---|
1355 | ($h, $x)
|
---|
1356 | }
|
---|
1357 |
|
---|
1358 | sub output_index {
|
---|
1359 | return &count_index if $pass == 1;
|
---|
1360 | my ($heading, $path) = (shift, shift);
|
---|
1361 | return if $path =~ m,^perltoc/,;
|
---|
1362 | ($heading) = trunc_heading($heading);
|
---|
1363 | $path = trunc_heading($path);
|
---|
1364 | warn "Undefined \$index_seen{\$heading}, \$heading='$heading'.\n"
|
---|
1365 | unless defined $index_seen{$heading};
|
---|
1366 | if (length $heading == 0) { # Do nothing for =item *
|
---|
1367 | } elsif ($index_seen{$heading} > 1) { # Multiply occurning header name
|
---|
1368 | my $id = $i1ids{$heading};
|
---|
1369 | unless ($id) { # First occurence of the header name
|
---|
1370 | $id = i1id($heading);
|
---|
1371 | print ":i1 id=$id." . out($heading, 0) . "\n";
|
---|
1372 | }
|
---|
1373 | my $uniq;
|
---|
1374 | $uniq = path_c($path), print ":i2 refid=$id." . out("[$uniq]", 0) . "\n"
|
---|
1375 | unless $index_output{$id}{$headno}++;
|
---|
1376 | } else {
|
---|
1377 | print ":i1." . out($heading, 0) . "\n";
|
---|
1378 | }
|
---|
1379 | }
|
---|
1380 |
|
---|
1381 | sub count_index { $index_seen{trunc_heading shift}++ }
|
---|
1382 |
|
---|
1383 | sub maybe_link {
|
---|
1384 | my $txt = shift;
|
---|
1385 | return "L<$txt>" if
|
---|
1386 | exists $links{findref($txt,1)} or $txt =~ m,^((\w+)\([23]\)|POSIX\s*\(3\)/(\w+)|(emx\w+))$,i;
|
---|
1387 |
|
---|
1388 | return $txt;
|
---|
1389 | }
|
---|
1390 |
|
---|
1391 | sub strip {
|
---|
1392 | my $in = shift;
|
---|
1393 |
|
---|
1394 | 1 while $in =~ s/X<([^<>]*)>//;
|
---|
1395 | 1 while $in =~ s/[A-Z]<([^<>]*)>/$1/;
|
---|
1396 |
|
---|
1397 | return $in;
|
---|
1398 | }
|
---|
1399 |
|
---|
1400 | sub link_url {
|
---|
1401 | my $url = shift;
|
---|
1402 | if (@www) {
|
---|
1403 | my $cmd = join ' || ', map { s/\@\@\@/$url/; $_ } @www;
|
---|
1404 | ":link reftype=launch object='cmd.exe' data='/c $cmd'."
|
---|
1405 | } else {
|
---|
1406 | ":link reftype=launch object='$www' data='$url'."
|
---|
1407 | }
|
---|
1408 | }
|
---|
1409 |
|
---|
1410 | sub try_external_link {
|
---|
1411 | my ($txt, $outtxt) = shift;
|
---|
1412 | $outtxt = $txt unless defined $outtxt;
|
---|
1413 | my $link;
|
---|
1414 |
|
---|
1415 | $foundrefs++, return ":link reftype=hd refid=$x_index{$txt}."
|
---|
1416 | . out($outtxt) . ":elink."
|
---|
1417 | if exists $x_index{$txt};
|
---|
1418 |
|
---|
1419 | $txt = $1 if $txt =~ m!^[BCI]<{2,}\s+(.*?)\s+>{2,}$!s;
|
---|
1420 | $txt = $1 if $txt =~ m!^[BCI]<(.*?)>$!s;
|
---|
1421 | if ($txt =~ m,^(http|file|ftp|mailto|news|newsrc|gopher)://,) {
|
---|
1422 | $link = strip($txt);
|
---|
1423 | } elsif ($txt =~ m,^\"(http|file|ftp|mailto|news|newsrc|gopher)://,
|
---|
1424 | and $txt =~ /\"$/) {
|
---|
1425 | $link = strip(substr $txt, 1, length($txt) - 2);
|
---|
1426 | } elsif ($txt =~ m,^((\w+)\([23]\)|POSIX\s*\(3\)/(\w+)|(emx\w+))$,i) {
|
---|
1427 | return ":link reftype=launch object='view.exe' data='emxbook $+'."
|
---|
1428 | . out($outtxt) . ":elink.";
|
---|
1429 | }
|
---|
1430 | return link_url($link) . out($outtxt) . ":elink." if $link;
|
---|
1431 | return undef;
|
---|
1432 | }
|
---|
1433 |
|
---|
1434 | sub format_funcall {
|
---|
1435 | my ($pre, $call, $func) = (@_);
|
---|
1436 | ( $func =~ /^($auto_link_both)$/o )
|
---|
1437 | ? "${pre}C<L<$func>()>"
|
---|
1438 | : "${pre}C<$call>"
|
---|
1439 | }
|
---|
1440 |
|
---|
1441 | sub auto_beautify {
|
---|
1442 | my $para = $_[0];
|
---|
1443 | # We start with links to make as many of them as we can:
|
---|
1444 | $para =~ s/(^|[^<:\$@%])\b($auto_link)\b(?=$|[^>:]|:[^:])/$1L<$2>/go
|
---|
1445 | if $auto_link;
|
---|
1446 | # perl(1) Tix(n)
|
---|
1447 | $para =~
|
---|
1448 | s/ (^|[^<]) \b ( [\w:]+ \b \([\dn]\) ) (?=$|[^>]) /$1 . maybe_link($2)/gxe;
|
---|
1449 | # words in "SEE ALSO"
|
---|
1450 | # In fact, now there are many non-words in X<FOO>; so take only those which start and end with \w
|
---|
1451 | $para =~ s/ (^|[^<:|>()\w]) \b (?=\w) ( $auto_link_hard ) \b (?=$|[^\w|>:<)]) /$1L<$2>/gox
|
---|
1452 | if $hl and $section_head[$hl] eq "SEE ALSO" and $auto_link_hard;
|
---|
1453 | # Link highlighted "maybe-references"
|
---|
1454 | $para =~ s/([CBI])<($auto_link_both)>/$1<L<$2>>/go if $auto_link_both;
|
---|
1455 | # Link highlighted "pseudo-references" to function names
|
---|
1456 | $para =~ s/([CBI])<($auto_link_hard)(?=\()/$1<L<$2>/go if $auto_link_hard;
|
---|
1457 | $para =~ s/C<-([^\W\d])>/C<L<-$1>>/g;
|
---|
1458 | $para =~ s/ ^ ( $auto_link_hard ) $ /L<$1>/ox
|
---|
1459 | if $in_item_header and $auto_link_hard;
|
---|
1460 | # URLs inside F<>
|
---|
1461 | $para =~ s, F< ((http|file|ftp|mailto|news|newsrc|gopher):// [^\s<>]* ) >
|
---|
1462 | ,L<$1>,xg ;
|
---|
1463 | # free-standing URLs.
|
---|
1464 | $para =~ s% ( \s | ^ )
|
---|
1465 | ( (?:http|file|ftp|mailto|news|newsrc|gopher)
|
---|
1466 | ://
|
---|
1467 | [^\s<>]*
|
---|
1468 | [^\s.,:;!?\"\'\)] # Strip trailing punctuation.
|
---|
1469 | )
|
---|
1470 | ( [.,:;!?\"\'\)]* ( \s | $ ) | $ )
|
---|
1471 | %$1L<$2>$3%xg ;
|
---|
1472 | # <> below is to avoid BOLDing of C in C<>
|
---|
1473 | $para =~ s/(^|[^<:\$@%])\b($make_bold)\b(?=$|[^<>:]|:[^:])/$1B<$2>/go
|
---|
1474 | if $make_bold;
|
---|
1475 | $para =~ s/(^|[^<:\$@%])\b($make_code)\b(?=$|[^>:]|:[^:])/$1C<$2>/go
|
---|
1476 | if $make_code;
|
---|
1477 | $para =~ s/ (\s+ | ^) ( [\$%\@] [\w:]+ \b) (?=$|[^>]) /$1C<$2>/gx; # $var
|
---|
1478 | # $para =~ s/([CBI])<($auto_link_both)>/$1<L<$2>>/go if $auto_link_both;
|
---|
1479 | $para =~ s{ (^|[^<]) \b ( ([\w:]+) \b \(\) ) (?=$|[^>]) }
|
---|
1480 | { format_funcall($1, $2, $3) }gex; # func()
|
---|
1481 | # if ($para =~ /\bL<(::|\W)>/) {
|
---|
1482 | # print STDERR "auto-b: ``$para''\n";
|
---|
1483 | # }
|
---|
1484 | $para;
|
---|
1485 | }
|
---|
1486 |
|
---|
1487 | my @tag_array;
|
---|
1488 | BEGIN { @tag_array = qr{([<>]|(?!\n)$)} } # ;-) ;-)
|
---|
1489 |
|
---|
1490 | sub fill_tag_array { # Handle L<<<< >>>>
|
---|
1491 | my $upto = shift; # no. of > plus 1
|
---|
1492 | while (@tag_array <= $upto) {
|
---|
1493 | my $repeat = @tag_array + 1;
|
---|
1494 | push @tag_array, qr{(<|\s+>{$repeat}|(?!\n)$)};
|
---|
1495 | }
|
---|
1496 | }
|
---|
1497 |
|
---|
1498 | sub find_matching {
|
---|
1499 | my $kets = 1 + pop;
|
---|
1500 | my $off = pop;
|
---|
1501 | $_[0] = $off
|
---|
1502 | }
|
---|
1503 |
|
---|
1504 | sub out {
|
---|
1505 | return if ($pass == 1);
|
---|
1506 |
|
---|
1507 | my $para = shift;
|
---|
1508 | my $markup = shift;
|
---|
1509 | my $beautify = $markup && ! shift;
|
---|
1510 | my $stop_at_ket = shift; # Not finished: @stack? arg=3 or 4
|
---|
1511 | my $cpos = shift || 0; # scanned up to
|
---|
1512 | my @stack = ();
|
---|
1513 | my @lenstack = $stop_at_ket || 0;
|
---|
1514 | my $output = "";
|
---|
1515 | my ($c, $opos); # opos: output done up to
|
---|
1516 | my $c_deep = 0;
|
---|
1517 | my @pos_stack;
|
---|
1518 |
|
---|
1519 | $para = auto_beautify($para) if $beautify;
|
---|
1520 |
|
---|
1521 | pos $para = $opos = $cpos;
|
---|
1522 | TAG: while ( $para =~ m{$tag_array[$lenstack[-1]]}g ) {
|
---|
1523 | $cpos = pos $para;
|
---|
1524 | $c = $1 || ''; # May hit the end of string
|
---|
1525 |
|
---|
1526 | if ($c eq '<' && $cpos < 2) {
|
---|
1527 | $output .= escape(substr($para, $opos, $cpos - $opos));
|
---|
1528 | } elsif ($c eq '<') {
|
---|
1529 | $output .= escape(substr($para, $opos, $cpos - $opos - 2))
|
---|
1530 | if $cpos - $opos > 2;
|
---|
1531 |
|
---|
1532 | $c = substr($para, $cpos - 2, 1);
|
---|
1533 | if ($c !~ /[A-Z]/) {
|
---|
1534 | $output .= escape(($cpos - $opos > 1 ? $c : '') . '<');
|
---|
1535 | pos($para) = $opos = $cpos;
|
---|
1536 | next TAG;
|
---|
1537 | }
|
---|
1538 |
|
---|
1539 | # Look for L<<< X >>>
|
---|
1540 | my $extra = 0;
|
---|
1541 | pos $para = $cpos;
|
---|
1542 | $cpos = pos $para, $extra = length $1 if $para =~ /\G(<+)\s+/g;
|
---|
1543 | push @lenstack, $extra;
|
---|
1544 | fill_tag_array($extra);
|
---|
1545 |
|
---|
1546 | if ($c eq 'B') {
|
---|
1547 | if (grep {$_ eq 'I'} @stack) {
|
---|
1548 | $output .= ':hp3.' if $markup;
|
---|
1549 | push (@stack, 'BI');
|
---|
1550 | } else {
|
---|
1551 | $output .= ':hp2.' if $markup;
|
---|
1552 | push (@stack, $c);
|
---|
1553 | }
|
---|
1554 | } elsif ($c eq 'F') {
|
---|
1555 | $output .= ':hp6.' if $markup;
|
---|
1556 | push (@stack, $c);
|
---|
1557 | } elsif ($c eq 'S') {
|
---|
1558 | # $output .= ':hp2.' if $markup; # XXXX Should not!
|
---|
1559 | push (@stack, $c);
|
---|
1560 | } elsif ($c eq 'I') {
|
---|
1561 | if (grep {$_ eq 'B'} @stack) {
|
---|
1562 | $output .= ':hp3.' if $markup;
|
---|
1563 | push (@stack, 'BI');
|
---|
1564 | } else {
|
---|
1565 | $output .= ':hp1.' if $markup;
|
---|
1566 | push (@stack, $c);
|
---|
1567 | }
|
---|
1568 | } elsif ($c eq 'C') {
|
---|
1569 | $output .= $to_C if $c_deep++ == 0 and $markup;
|
---|
1570 | push (@stack, $c);
|
---|
1571 | } elsif ($c eq 'L') {
|
---|
1572 | # Allow one level of included modifiers:
|
---|
1573 | push (@stack, $skip_embedded_links ? 'L' : 'LL'); # Treat as ordinary text
|
---|
1574 | pos($para) = $opos = $cpos;
|
---|
1575 | unless ($skip_embedded_links) {
|
---|
1576 | push @pos_stack, $cpos;
|
---|
1577 | push @out_stack, length $output;
|
---|
1578 | }
|
---|
1579 | next TAG;
|
---|
1580 | } elsif ($c eq 'E') {
|
---|
1581 | pos ($para) = $cpos;
|
---|
1582 | if ($para =~ m{$tag_array[$lenstack[-1]]}g) {
|
---|
1583 | my $esc;
|
---|
1584 | my $ocpos = $cpos;
|
---|
1585 | $cpos = pos $para;
|
---|
1586 | my $tag = substr $para, $ocpos, $cpos - $ocpos - length $1;
|
---|
1587 |
|
---|
1588 | if ($tag =~ m/^(([A-Za-z]+)|\d+)$/) {
|
---|
1589 | if (defined $2) {
|
---|
1590 | if (exists $HTML_Escapes{$1}) {
|
---|
1591 | $escaped = 0;
|
---|
1592 | $esc = $HTML_Escapes{$1};
|
---|
1593 | } else {
|
---|
1594 | $esc = exists $HTML_EscapesLit{$1}
|
---|
1595 | ? "&$HTML_EscapesLit{$1}." : "E<$1>";
|
---|
1596 | $escaped = 1;
|
---|
1597 | }
|
---|
1598 | } else {
|
---|
1599 | $esc = chr $1;
|
---|
1600 | $escaped = 1;
|
---|
1601 | }
|
---|
1602 | $output .= ($escaped ? $esc : escape($esc));
|
---|
1603 | } else {
|
---|
1604 | warn "$fname: unknown E<> in `" . (substr $para, $cpos-2, 10) . "'???\n";
|
---|
1605 | }
|
---|
1606 | } else {
|
---|
1607 | warn "$fname: unknown E<> in `" . (substr $para, $cpos-2, 10) . "'???\n";
|
---|
1608 | }
|
---|
1609 | } elsif ($c eq 'X') {
|
---|
1610 | pos ($para) = $cpos;
|
---|
1611 | # Here we match only '>'s, not '<'s
|
---|
1612 | if ($para =~ m{(?!<)$tag_array[$lenstack[-1]]}g) {
|
---|
1613 | my $esc;
|
---|
1614 | my $ocpos = $cpos;
|
---|
1615 | $cpos = pos $para;
|
---|
1616 | my $tag = substr $para, $ocpos, $cpos - $ocpos - length $1;
|
---|
1617 | #$output .= escape($1);
|
---|
1618 | push @index, $tag if $print_index;
|
---|
1619 | } else {
|
---|
1620 | warn "$fname: error parsing X<...> ??? `" . (substr $para, $cpos-2, 160) . "', lenstack=`@lenstack', tag_array=`@tag_array'\n";
|
---|
1621 | }
|
---|
1622 | } elsif ($c eq 'Z') {
|
---|
1623 | pos ($para) = $cpos;
|
---|
1624 | if ($para =~ m/\G>/g) {
|
---|
1625 | $cpos = pos $para;
|
---|
1626 | } else {
|
---|
1627 | warn "funny: Z<...> ???\n";
|
---|
1628 | }
|
---|
1629 | } else {
|
---|
1630 | warn "$fname: what to do with $c<> ?\n";
|
---|
1631 | }
|
---|
1632 | } elsif ($#stack >= 0) {
|
---|
1633 | my ($l, $e) = length $c;
|
---|
1634 |
|
---|
1635 | $output .= escape($e = substr($para, $opos, $cpos - $opos - $l));
|
---|
1636 | $c = pop(@stack);
|
---|
1637 | # XXXX This warning should better be skipped if we process truncated long headings...
|
---|
1638 | printf STDERR " Unfinished tag: %s< Remains: %s\n", $c, $e
|
---|
1639 | unless $l;
|
---|
1640 | if ($c eq 'B') {
|
---|
1641 | $output .= ':ehp2.' if $markup;
|
---|
1642 | } elsif ($c eq 'F') {
|
---|
1643 | $output .= ':ehp6.' if $markup;
|
---|
1644 | } elsif ($c eq 'S') {
|
---|
1645 | # $output .= ':ehp2.' if $markup;
|
---|
1646 | } elsif ($c eq 'I') {
|
---|
1647 | $output .= ':ehp1.' if $markup;
|
---|
1648 | } elsif ($c eq 'BI') {
|
---|
1649 | $output .= ':ehp3.' if $markup;
|
---|
1650 | } elsif ($c eq 'C') {
|
---|
1651 | $output .= $from_C if --$c_deep == 0 and $markup;
|
---|
1652 | } elsif ($c eq 'L') {
|
---|
1653 | # end "unprocessed" link
|
---|
1654 | } elsif ($c eq 'LL') {
|
---|
1655 | # finish processing of the link
|
---|
1656 |
|
---|
1657 | # First, ignore what was added
|
---|
1658 | substr($output, pop @out_stack) = '';
|
---|
1659 | # Avoid warning 208: a link inside a link could be
|
---|
1660 | # created during auto_beautify() above.
|
---|
1661 | local $skip_embedded_links = 1;
|
---|
1662 |
|
---|
1663 | # Get the string inside L<< >>
|
---|
1664 | my $b = pop @pos_stack;
|
---|
1665 | my $link = substr $para, $b, $cpos - $l - $b;
|
---|
1666 | my $linktxt = $link;
|
---|
1667 |
|
---|
1668 | # XXX Use heuristics to find | and /:
|
---|
1669 | my $haveliteral = 0;
|
---|
1670 | $haveliteral = 1, $linktxt = $1
|
---|
1671 | if $link =~ s!^(([A-Z]<[^<>]*>|(?>[^>|/]+))+)\|!!;
|
---|
1672 | $foundlink = findref($link);
|
---|
1673 | if (defined $links{$foundlink}) {
|
---|
1674 | my $blink = $linktxt;
|
---|
1675 | unless ($haveliteral) {
|
---|
1676 | $blink =~ s|^"(.+)"$|$1|sm or
|
---|
1677 | $blink =~ s|^([-\w:]+)/"(.+)"$|$1: $2|sm;
|
---|
1678 | }
|
---|
1679 | $output .= ":link reftype=hd refid=$links{$foundlink}."
|
---|
1680 | if $markup;
|
---|
1681 | $output .= out($blink, 1, 1);
|
---|
1682 | $output .= ":elink." if $markup;
|
---|
1683 | } elsif ($foundlink = try_external_link($link,$linktxt)) {
|
---|
1684 | $output .= $markup ? $foundlink : out($linktxt) ;
|
---|
1685 | } else {
|
---|
1686 | warn " unresolved link: $link\n";
|
---|
1687 | $output .= out($linktxt, 1, 1);
|
---|
1688 | }
|
---|
1689 | pos $para = $opos = $cpos;
|
---|
1690 | } else {
|
---|
1691 | $output .= escape('>'); # XXX Why?
|
---|
1692 | }
|
---|
1693 | pop @lenstack;
|
---|
1694 | } elsif (!length $c) { # Hit the end, and stack is empty
|
---|
1695 | last TAG; # Hitting the end fixes some of Warning 208
|
---|
1696 | } elsif (defined $stop_at_ket) {
|
---|
1697 | $output .= escape(substr($para, $opos, $cpos - $opos - length $c));
|
---|
1698 | $opos = $cpos;
|
---|
1699 | last TAG;
|
---|
1700 | } else {
|
---|
1701 | $output .= escape(substr($para, $opos, $cpos - $opos));
|
---|
1702 | }
|
---|
1703 | pos($para) = $opos = $cpos;
|
---|
1704 | }
|
---|
1705 | $output .= escape(substr($para, $opos, length($para) - $opos));
|
---|
1706 | if (!$markup) { # for toc/index/...
|
---|
1707 | $output =~ s/\n\s*/ /g;
|
---|
1708 | if (length $output > 140) {
|
---|
1709 | $output = substr($output, 0, 140); # strip too long stuff
|
---|
1710 | $output =~ s/&\w*$//; # remove uncomplete escapes: Warning 203
|
---|
1711 | }
|
---|
1712 | }
|
---|
1713 | # Do not split inside "something" unless absolutely necessary
|
---|
1714 | # Try harder: e.g. perljp contains massive unbreakable stuff:
|
---|
1715 | 1 while $output =~
|
---|
1716 | s/^(?=.{250})(.{80}([^\n \t]{0,169}(?=[ \t])|[^\n \t]{160}))[ \t]*/$1\n/gm; # Warning 206
|
---|
1717 | $output =~ s/^\./&per./mg; # period. Warning 204
|
---|
1718 | return $output;
|
---|
1719 | }
|
---|
1720 |
|
---|
1721 | sub insert_back { # Args: head_level and num of finished section,
|
---|
1722 | return unless $pass == 2;
|
---|
1723 | my $parent = find_parent($_[0]);
|
---|
1724 | return if $parent == $_[0];
|
---|
1725 | return if $parent <= $first_node;
|
---|
1726 | insert_nl;
|
---|
1727 | print " :link reftype=hd refid=$parent.:font facename=Courier size=8x6.Go Up:font facename=default size=0x0.:elink.\n";
|
---|
1728 | $was_nl = 1;
|
---|
1729 | }
|
---|
1730 |
|
---|
1731 | # Find the latest node before $i at level < $level
|
---|
1732 | sub find_parent {
|
---|
1733 | my $level = $headlevel[$_[0]];
|
---|
1734 | my $i = $_[0] - 1;
|
---|
1735 |
|
---|
1736 | while ($i > $first_node && $headlevel[$i] >= $level) { $i--; }
|
---|
1737 |
|
---|
1738 | return $i;
|
---|
1739 | }
|
---|
1740 |
|
---|
1741 | sub contents {
|
---|
1742 | my $no = $_[0];
|
---|
1743 | my ($i, $cl, $toplevel);
|
---|
1744 | local $print_index = 0;
|
---|
1745 |
|
---|
1746 | $isempty{$no}++;
|
---|
1747 | if ($pass == 1) {
|
---|
1748 | $wingroup[$no] = $groups{links};
|
---|
1749 | return ;
|
---|
1750 | }
|
---|
1751 |
|
---|
1752 | #$i = find_parent($level,$no);
|
---|
1753 | $i = $no;
|
---|
1754 |
|
---|
1755 | $toplevel = $headlevel[$i];
|
---|
1756 | return if $toplevel <= 0;
|
---|
1757 |
|
---|
1758 | print ":p." . out($head[$i], 1) . "\n";
|
---|
1759 | $was_nl = 1;
|
---|
1760 | $i++;
|
---|
1761 | $cl = $toplevel;
|
---|
1762 | local $skip_embedded_links = 1;
|
---|
1763 | for (; $i <= $#head && $headlevel[$i] > $toplevel; $i++) {
|
---|
1764 | if ($headlevel[$i] > $cl) {
|
---|
1765 | print STDERR " bad nesting: $toplevel, $headlevel[$i], $cl, $i, `$head[$i]`\n" if $headlevel[$i] != $cl + 1;
|
---|
1766 | print ":ul compact.\n";
|
---|
1767 | $was_nl = 1;
|
---|
1768 | $cl++;
|
---|
1769 | } elsif ($cl > $headlevel[$i]) {
|
---|
1770 | while ($cl > $headlevel[$i]) {
|
---|
1771 | print ":eul.\n";
|
---|
1772 | $was_nl = 1;
|
---|
1773 | $cl--;
|
---|
1774 | }
|
---|
1775 | }
|
---|
1776 | if (exists $isempty{$i}) {
|
---|
1777 | print ":li.", out($head[$i], 1, 1), "\n";
|
---|
1778 | } elsif (exists $hl_eitems{$i}) {
|
---|
1779 | print ":li.:link reftype=hd " . winlink($i)
|
---|
1780 | . " refid=$i."
|
---|
1781 | . out($_, 1, 1) . ":elink.\n" for @{$hl_eitems{$i}};
|
---|
1782 | } else {
|
---|
1783 | print ":li.:link reftype=hd " . winlink($i)
|
---|
1784 | . " refid=$i."
|
---|
1785 | . out($head[$i], 1, 1) . ":elink.\n";
|
---|
1786 | }
|
---|
1787 | $was_nl = 1;
|
---|
1788 | }
|
---|
1789 |
|
---|
1790 | while ($cl > $toplevel) {
|
---|
1791 | print ":eul.\n";
|
---|
1792 | $cl--;
|
---|
1793 | $was_nl = 1;
|
---|
1794 | }
|
---|
1795 | }
|
---|
1796 |
|
---|
1797 | sub findrefid {
|
---|
1798 | my $in = shift;
|
---|
1799 | my $out = $links{findref($in)} || $x_index{$in};
|
---|
1800 | warn "No refid for `$in'\n" if $debug and not defined $out;
|
---|
1801 | ($out || 0); # XXXX misplaced link - special panel?
|
---|
1802 | }
|
---|
1803 |
|
---|
1804 | sub findref_with_pages { # various heuristics to get a valid prefix for a link
|
---|
1805 | my $link = shift;
|
---|
1806 | my $links = shift;
|
---|
1807 |
|
---|
1808 | if (!defined $links->{$link}) {
|
---|
1809 | if ($link =~ m|(.*?)\.pod/(.*)|s) {
|
---|
1810 | $link = "$1/$2"; # Remove .pod from page name
|
---|
1811 | } elsif ($link =~ m|(.*?)\.pod$| and defined $links->{$1}) {
|
---|
1812 | $link = $1;
|
---|
1813 | }
|
---|
1814 | }
|
---|
1815 | if (!defined $links->{$link}) { # try harder
|
---|
1816 | if (defined $links->{qq|$page/"$link"|}) {
|
---|
1817 | $link = qq|$page/"$link"|;
|
---|
1818 | } elsif ($link =~ /^\"/) {
|
---|
1819 | $link = "$page/$link";
|
---|
1820 | } elsif ($link =~ m|^/\"|) {
|
---|
1821 | $link = "$page$link";
|
---|
1822 | } elsif ($link =~ m|^/(.*)|s) {
|
---|
1823 | $link = qq|$page/"$1"|;
|
---|
1824 | } elsif ($link =~ m|^([^/ ]+)/([^\"]+)$|) { # A/B to A/"B"
|
---|
1825 | $link = qq|$1/"$2"|;
|
---|
1826 | } elsif (exists $alternative_name{$link}
|
---|
1827 | and exists $links->{$alternative_name{$link}}) {
|
---|
1828 | $link = $alternative_name{$link};
|
---|
1829 | }
|
---|
1830 | # print STDERR "trans: $link\n" if $debug_xref;
|
---|
1831 | }
|
---|
1832 | return $link;
|
---|
1833 | }
|
---|
1834 |
|
---|
1835 | sub warn_strip {
|
---|
1836 | my ($link,$works,$flink) = @_;
|
---|
1837 | my $b = auto_beautify($flink);
|
---|
1838 | return if -1 < index $b, $link; # May be missing perlpod/ or ""
|
---|
1839 | print STDERR " Strip conversion in link: `$link' vs `$flink'.\n";
|
---|
1840 | }
|
---|
1841 |
|
---|
1842 | sub findref_with_variations { # various heuristics to get a valid link
|
---|
1843 | my $link = shift;
|
---|
1844 | my $flink = findref_with_pages($link, \%links);
|
---|
1845 | my $tlink = $link;
|
---|
1846 | my $t;
|
---|
1847 |
|
---|
1848 | if (!defined $links{$flink}) { # try harder
|
---|
1849 | ($tlink = $link) =~ s/\s+/ /g;
|
---|
1850 | $t = findref_with_pages($tlink, \%links_nws);
|
---|
1851 | $flink = $links_nws{$t} if exists $links_nws{$t};
|
---|
1852 | }
|
---|
1853 | if (!defined $links{$flink}) { # try file operators
|
---|
1854 | if ($link =~ /^-[^\W\d]$/) {
|
---|
1855 | $tlink = qq|perlfunc/"-X"|;
|
---|
1856 | $t = findref_with_pages($tlink, \%links_nws);
|
---|
1857 | $flink = $t if exists $links{$t};
|
---|
1858 | }
|
---|
1859 | }
|
---|
1860 | return $flink if $_[0];
|
---|
1861 | if (!defined $links{$flink}) { # try harder
|
---|
1862 | $tlink = lc $tlink;
|
---|
1863 | $t = findref_with_pages($tlink, \%links_lc);
|
---|
1864 | if (exists $links_lc{$t}) {
|
---|
1865 | $flink = $links_lc{$t};
|
---|
1866 | print STDERR " Case conversion in link: `$link' vs `$flink'.\n";
|
---|
1867 | }
|
---|
1868 | }
|
---|
1869 | if (!defined $links{$flink}) { # try another way
|
---|
1870 | $tlink = strip $link;
|
---|
1871 | $t = findref_with_pages($tlink, \%links_strip);
|
---|
1872 | $flink = $links_strip{$t} if exists $links_strip{$t};
|
---|
1873 | if (!defined $links{$flink}) { # try harder
|
---|
1874 | my $b = auto_beautify($tlink);
|
---|
1875 | $t = findref_with_pages($b, \%links_b);
|
---|
1876 | if (exists $links_b{$t}) {
|
---|
1877 | $flink = $links_b{$t};
|
---|
1878 | warn_strip($link,$t,$flink);
|
---|
1879 | }
|
---|
1880 | } else {
|
---|
1881 | warn_strip($link,$t,$flink);
|
---|
1882 | }
|
---|
1883 | }
|
---|
1884 | if (!defined $links{$flink}) { # try another way
|
---|
1885 | my $b = auto_beautify($link);
|
---|
1886 | $t = findref_with_pages($b, \%links_b);
|
---|
1887 | if (exists $links_b{$t}) {
|
---|
1888 | $flink = $links_b{$t} if exists $links_b{$t};
|
---|
1889 | warn "Strip conversion in link: `$link' vs `$flink'.\n";
|
---|
1890 | }
|
---|
1891 | }
|
---|
1892 | return $flink;
|
---|
1893 | }
|
---|
1894 |
|
---|
1895 | sub findref { # various heuristics to get a valid link
|
---|
1896 | my $link = shift;
|
---|
1897 | my $flink = findref_with_variations($link, @_);
|
---|
1898 |
|
---|
1899 | print STDERR "link: $link\n" if $debug_xref;
|
---|
1900 |
|
---|
1901 | if (!defined $links{$flink}) { # try harder
|
---|
1902 | if ($link =~ m|\(\)>?$|) {
|
---|
1903 | my $t = $link;
|
---|
1904 | $t =~ s/\(\)(>?)$/$1/; # open() -> open, C<open()> => C<open>
|
---|
1905 | $t = findref_with_variations $t, @_;
|
---|
1906 | $flink = $t if defined $links{$t};
|
---|
1907 | } elsif ($link =~ /\([\dn]\)>?$/) { # perl(1)
|
---|
1908 | my $t = $link;
|
---|
1909 | $t =~ s/\([\dn]\)(>?)$/$1/; # f(2) -> f, C<f(2)> => C<f>
|
---|
1910 | $t = findref_with_variations $t, @_;
|
---|
1911 | if (defined $links{$t}) {
|
---|
1912 | $flink = $t;
|
---|
1913 | } else {
|
---|
1914 | $unknown_manpages{$link}++; # May be converted to view.exe later
|
---|
1915 | }
|
---|
1916 | }
|
---|
1917 | }
|
---|
1918 | print STDERR "trans: $link => $flink\n" if $debug_xref;
|
---|
1919 | $foundrefs++ if defined $links{$flink};
|
---|
1920 | return $flink;
|
---|
1921 | }
|
---|
1922 |
|
---|
1923 | sub add_ref {
|
---|
1924 | my $page = $_[0];
|
---|
1925 | my $num = $_[1];
|
---|
1926 | my $check = $_[2];
|
---|
1927 |
|
---|
1928 | return if $page =~ m,^perltoc/,;
|
---|
1929 | $page =~ s/\s*$//;
|
---|
1930 | #warn "<<<adding ref $num to \"$page\"\n";
|
---|
1931 |
|
---|
1932 | $links{$page} = $num unless $check and exists $links{$page};
|
---|
1933 | (my $p = $page) =~ s/\s+/ /g;
|
---|
1934 | $links_nws{$p} = $page unless $check and exists $links_nws{$p};
|
---|
1935 | my $lc = lc $p;
|
---|
1936 | $links_lc{$lc} = $page unless $check and exists $links_lc{$lc};
|
---|
1937 | my $s = strip $page;
|
---|
1938 | $links_strip{$s} = $page unless $check and exists $links_strip{$s};
|
---|
1939 | my $b = auto_beautify($s);
|
---|
1940 | $links_b{$b} = $page unless $b eq $page or exists $links_b{$b};
|
---|
1941 | my $bb = auto_beautify($page);
|
---|
1942 | $links_b{$bb} = $page unless $bb eq $page or $bb eq $b;
|
---|
1943 | }
|
---|
1944 |
|
---|
1945 | sub addsection {
|
---|
1946 | my $section = $_[0];
|
---|
1947 | my $num = $_[1];
|
---|
1948 | my $level = $_[2];
|
---|
1949 |
|
---|
1950 | $head[$num] = $section;
|
---|
1951 | $headlevel[$num] = $level;
|
---|
1952 | }
|
---|
1953 |
|
---|
1954 | sub escape {
|
---|
1955 | my $l = $_[0];
|
---|
1956 |
|
---|
1957 | $l =~ s/\&/\&./g;
|
---|
1958 | $l =~ s/\:/\&colon./g;
|
---|
1959 | return $l;
|
---|
1960 | }
|
---|
1961 |
|
---|
1962 | sub remove_colon {
|
---|
1963 | my $in = shift;
|
---|
1964 | $in =~ s/\&colon\./:/g;
|
---|
1965 | $in;
|
---|
1966 | }
|
---|
1967 |
|
---|
1968 | sub escape_with_url {
|
---|
1969 | my $l = escape(shift);
|
---|
1970 |
|
---|
1971 | $l =~ s% ( \s | ^ )
|
---|
1972 | (
|
---|
1973 | (?:http|file|ftp|mailto|news|newsrc|gopher)
|
---|
1974 | \&colon\.//
|
---|
1975 | [^\s<>]*
|
---|
1976 | [^\s.,:;!?\"\'\)] # Strip trailing punctuation.
|
---|
1977 | )
|
---|
1978 | ( [.,:;!?\"\'\)]* ( \s | $ ) | $ )
|
---|
1979 | % "$1" . link_url(remove_colon($2)) . "$2:elink.$3"
|
---|
1980 | %xeg ;
|
---|
1981 |
|
---|
1982 | return $l;
|
---|
1983 | }
|
---|
1984 |
|
---|
1985 | BEGIN {
|
---|
1986 | %HTML_Escapes = # We provide a _practical_ list.
|
---|
1987 | (
|
---|
1988 | 'amp' => '&', # ampersand
|
---|
1989 | 'lt' => '<', # left chevron, less-than
|
---|
1990 | 'gt' => '>', # right chevron, greater-than
|
---|
1991 | 'quot' => '"', # double quote
|
---|
1992 | 'sol' => '/', # slash=solidus
|
---|
1993 | 'verbar' => '|', # vertical bar
|
---|
1994 | 39 => "'", # single quote
|
---|
1995 | );
|
---|
1996 | %HTML_EscapesLit = # We provide a _practical_ list.
|
---|
1997 | (
|
---|
1998 | # Stolen from pod2latex
|
---|
1999 | "Aacute" => "aa", # capital A, acute accent
|
---|
2000 | "aacute" => "aa", # small a, acute accent
|
---|
2001 | "Acirc" => "ac", # capital A, circumflex accent
|
---|
2002 | "acirc" => "ac", # small a, circumflex accent
|
---|
2003 | "AElig" => 'Aelig', # capital AE diphthong (ligature)
|
---|
2004 | "aelig" => 'aelig', # small ae diphthong (ligature)
|
---|
2005 | "Agrave" => "ag", # capital A, grave accent
|
---|
2006 | "agrave" => "ag", # small a, grave accent
|
---|
2007 | "Aring" => 'Ao', # capital A, ring
|
---|
2008 | "aring" => 'ao', # small a, ring
|
---|
2009 | # "Atilde" => '\\~{A}', # capital A, tilde
|
---|
2010 | # "atilde" => '\\~{a}', # small a, tilde
|
---|
2011 | "Auml" => 'Ae', # capital A, dieresis or umlaut mark
|
---|
2012 | "auml" => 'ae', # small a, dieresis or umlaut mark
|
---|
2013 | # "Ccedil" => '\\c{C}', # capital C, cedilla
|
---|
2014 | # "ccedil" => '\\c{c}', # small c, cedilla
|
---|
2015 | "Eacute" => "Ea", # capital E, acute accent
|
---|
2016 | "eacute" => "ea", # small e, acute accent
|
---|
2017 | "Ecirc" => "ec", # capital E, circumflex accent
|
---|
2018 | "ecirc" => "ec", # small e, circumflex accent
|
---|
2019 | "Egrave" => "eg", # capital E, grave accent
|
---|
2020 | "egrave" => "eg", # small e, grave accent
|
---|
2021 | # "ETH" => '\\OE', # capital Eth, Icelandic
|
---|
2022 | # "eth" => '\\oe', # small eth, Icelandic
|
---|
2023 | # "Euml" => '\\"{E}', # capital E, dieresis or umlaut mark
|
---|
2024 | # "euml" => '\\"{e}', # small e, dieresis or umlaut mark
|
---|
2025 | "Iacute" => "ia", # capital I, acute accent
|
---|
2026 | "iacute" => "ia", # small i, acute accent
|
---|
2027 | "Icirc" => "ic", # capital I, circumflex accent
|
---|
2028 | "icirc" => "ic", # small i, circumflex accent
|
---|
2029 | "Igrave" => "ig", # capital I, grave accent
|
---|
2030 | "igrave" => "ig", # small i, grave accent
|
---|
2031 | "Iuml" => 'Ie', # capital I, dieresis or umlaut mark
|
---|
2032 | "iuml" => 'ie', # small i, dieresis or umlaut mark
|
---|
2033 | "Ntilde" => 'Nt', # capital N, tilde
|
---|
2034 | "ntilde" => 'nt', # small n, tilde
|
---|
2035 | "Oacute" => "oa", # capital O, acute accent
|
---|
2036 | "oacute" => "oa", # small o, acute accent
|
---|
2037 | "Ocirc" => "oc", # capital O, circumflex accent
|
---|
2038 | "ocirc" => "oc", # small o, circumflex accent
|
---|
2039 | "Ograve" => "og", # capital O, grave accent
|
---|
2040 | "ograve" => "og", # small o, grave accent
|
---|
2041 | # "Oslash" => "\\O", # capital O, slash
|
---|
2042 | # "oslash" => "\\o", # small o, slash
|
---|
2043 | # "Otilde" => "\\~{O}", # capital O, tilde
|
---|
2044 | # "otilde" => "\\~{o}", # small o, tilde
|
---|
2045 | "Ouml" => 'Oe', # capital O, dieresis or umlaut mark
|
---|
2046 | "ouml" => 'oe', # small o, dieresis or umlaut mark
|
---|
2047 | # "szlig" => '\\ss{}', # small sharp s, German (sz ligature)
|
---|
2048 | # "THORN" => '\\L', # capital THORN, Icelandic
|
---|
2049 | # "thorn" => '\\l',, # small thorn, Icelandic
|
---|
2050 | "Uacute" => "Ua", # capital U, acute accent
|
---|
2051 | "uacute" => "ua", # small u, acute accent
|
---|
2052 | "Ucirc" => "uc", # capital U, circumflex accent
|
---|
2053 | "ucirc" => "uc", # small u, circumflex accent
|
---|
2054 | "Ugrave" => "ug", # capital U, grave accent
|
---|
2055 | "ugrave" => "ug", # small u, grave accent
|
---|
2056 | "Uuml" => 'Ue', # capital U, dieresis or umlaut mark
|
---|
2057 | "uuml" => 'ue', # small u, dieresis or umlaut mark
|
---|
2058 | # "Yacute" => "\\'{Y}", # capital Y, acute accent
|
---|
2059 | # "yacute" => "\\'{y}", # small y, acute accent
|
---|
2060 | "yuml" => 'ye', # small y, dieresis or umlaut mark
|
---|
2061 | );
|
---|
2062 | }
|
---|
2063 |
|
---|
2064 | sub winhead {
|
---|
2065 | my $no = $_[0];
|
---|
2066 |
|
---|
2067 | if ($multi_win) {
|
---|
2068 | if (defined $wingroup[$no]) {
|
---|
2069 | return "group=$groups{links} x=left width=$panelwidths{links}";
|
---|
2070 | }
|
---|
2071 | }
|
---|
2072 | return "";
|
---|
2073 | }
|
---|
2074 |
|
---|
2075 | sub winlink {
|
---|
2076 | my $no = $_[0];
|
---|
2077 |
|
---|
2078 | if ($multi_win) {
|
---|
2079 | if (defined $wingroup[$no]) {
|
---|
2080 | return "group=$groups{sublinks} vpx=2% vpcx=$panelwidths{sublinks}";
|
---|
2081 | } else {
|
---|
2082 | return "group=$groups{text} dependent vpx=right vpcx=$panelwidths{text}"
|
---|
2083 | }
|
---|
2084 | }
|
---|
2085 | return "";
|
---|
2086 | }
|
---|
2087 |
|
---|
2088 | sub no_markup_len { # quick hack
|
---|
2089 | my $l = $_[0];
|
---|
2090 |
|
---|
2091 | $l =~ s/\:.*?\.//g;
|
---|
2092 | $l =~ s/\&.*?\./x/g;
|
---|
2093 | return length $l;
|
---|
2094 | }
|
---|
2095 |
|
---|
2096 | sub insert_nl {
|
---|
2097 | print "\n" if not $was_nl or shift;
|
---|
2098 | $was_nl = 1;
|
---|
2099 | }
|
---|
2100 |
|
---|
2101 | sub do_libdir {
|
---|
2102 | local $_;
|
---|
2103 | $libdir = shift;
|
---|
2104 | chdir $libdir;
|
---|
2105 | debug("Looking in $libdir:");
|
---|
2106 | find (\&intern_modnamehash , '.');
|
---|
2107 | chdir $curdir;
|
---|
2108 | }
|
---|
2109 |
|
---|
2110 | sub intern_modnamehash {
|
---|
2111 | # File::Find is pretty screwy.
|
---|
2112 | # I think we can't modify $_ or File::Find can screw up
|
---|
2113 |
|
---|
2114 | my $shortpath;
|
---|
2115 |
|
---|
2116 | # this could be a problem - if we search $sitelibdir,
|
---|
2117 | # its usually a subdir of $libdir, in which case we don't want it
|
---|
2118 | # to think 'site_perl' is a class name.
|
---|
2119 |
|
---|
2120 | # site_perl and 5.00309 may be seen earlier than needed due to (unconvenient
|
---|
2121 | # for reverse search) ordering of @INC.
|
---|
2122 | if ( defined $site_perl_prefix and
|
---|
2123 | $File::Find::name =~ m!/($site_perl_prefix|5\.(\d{3,5}|\d{1,2}\.\d{1,2}))/!o
|
---|
2124 | and $libdir !~ m!/($site_perl_prefix|5\.(\d{3,5}|\d{1,2}\.\d{1,2}))($|/)!o ) {
|
---|
2125 | return;
|
---|
2126 | }
|
---|
2127 |
|
---|
2128 | # site_perl/5.9.1 and siteperl may be both in @INC.
|
---|
2129 | # One could also make site_perl/5.9.1-hide to avoid @INC
|
---|
2130 | if ( !defined $site_perl_prefix and
|
---|
2131 | $File::Find::name =~ m!/5\.(\d{3,5}|\d{1,2}\.\d{1,2})(-[-\w.]+)?/!
|
---|
2132 | and $libdir !~ m!/5\.(\d{3,5}|\d{1,2}\.\d{1,2})($|/)! ) {
|
---|
2133 | return;
|
---|
2134 | }
|
---|
2135 |
|
---|
2136 | # XXX - may be doing toplevel modules incorrectly in the above case
|
---|
2137 | # is 'name' just the filename? thats not good ....
|
---|
2138 | $shortpath = $_;
|
---|
2139 | local $_ = $File::Find::name;
|
---|
2140 |
|
---|
2141 | # kill leading './'
|
---|
2142 |
|
---|
2143 | s{^[.]/}{};
|
---|
2144 | my $longname = "$libdir/$_";
|
---|
2145 | $longname =~ s{^[.]/}{};
|
---|
2146 |
|
---|
2147 | # XXX - take the current $libdir (/foo/bar)
|
---|
2148 | # and see if the file were testing (/foo/bar/site_perl/Plugh/Blah.pm) is
|
---|
2149 | # in any *other*, deeper subdir in @INC
|
---|
2150 | # (/foo/bar/site_perl) - if so, skip this entry, cuz the deeper
|
---|
2151 | # subdir will catch it properly (Plugh::Blah)
|
---|
2152 |
|
---|
2153 | # for other libraries that are proper subdirs of the current libdir
|
---|
2154 | foreach $otherlibrary (grep /^\Q$libdir\E.+/, @INC) {
|
---|
2155 |
|
---|
2156 | # if the other library is part of the current files path, skip it
|
---|
2157 | # because it will be caught when the other library is used
|
---|
2158 |
|
---|
2159 | if ($longname =~ /^\Q$otherlibrary\//) {
|
---|
2160 | print STDERR ".";
|
---|
2161 | # print "Skipping $_\n";
|
---|
2162 | # print "cuz $otherlibrary caught/will catch it\n";
|
---|
2163 | return;
|
---|
2164 | }
|
---|
2165 | }
|
---|
2166 |
|
---|
2167 | # exclude base pods - perlfoo.pod, but not perlfaqs
|
---|
2168 | /perl(?!faq).*[.]pod/ && $do_std && return;
|
---|
2169 |
|
---|
2170 | # for each file entry, kill trailing '.(pod|pm|cmd)'. Skip other extentions
|
---|
2171 | (-f $shortpath) and
|
---|
2172 | s{^(.*)[.](pod|pm|plx?|cmd|bat)$ }{$1}xi
|
---|
2173 | or $shortpath !~ /[.]/ or return;
|
---|
2174 |
|
---|
2175 | # '.pod' files nonhierarchical - keep only last component as module name.
|
---|
2176 | # well, hierarchical in Tk ... keep it hierarchical for now
|
---|
2177 |
|
---|
2178 | # if ($2 eq 'pod') {$_ =~ s{.*/([^/]+)}{$1}; }
|
---|
2179 |
|
---|
2180 | # translate to module syntax
|
---|
2181 |
|
---|
2182 | s{/}{::}g;
|
---|
2183 |
|
---|
2184 | # if its already in the hash, skip it. We're following @INC order,
|
---|
2185 | # which means if its found in a earlier @INC directory, it will
|
---|
2186 | # be the one thats `use'd. So rather than overwriting an earlier
|
---|
2187 | # @INC entry with a newer one, we skip the newer one if the earlier
|
---|
2188 | # one exists (or, we could do the foreach on (reverse @INC) instead
|
---|
2189 | # of (@INC)).
|
---|
2190 |
|
---|
2191 |
|
---|
2192 | if (defined $seen{lc $_}) {
|
---|
2193 | # print "already found $_\n";
|
---|
2194 | # print "in $modnamehash{$_}\n";
|
---|
2195 | return
|
---|
2196 | };
|
---|
2197 |
|
---|
2198 | # If this is a .pm file, is there actually any documentation in it?
|
---|
2199 |
|
---|
2200 | # Under OS/2 perl utilites can have extension .cmd. To be safe, allow
|
---|
2201 | # .bat as well. Since we look into $Config{bin}, we may allow files
|
---|
2202 | # without extension as well, if they are text files.
|
---|
2203 |
|
---|
2204 | if (($longname =~ /[.](pm|plx?|cmd|bat|pod)$/i
|
---|
2205 | or $shortpath !~ /[.]/) and -T $longname) {
|
---|
2206 | $good = 0;
|
---|
2207 | open(MODULE, $shortpath) or die "Cannot open `$shortpath': $!";
|
---|
2208 | line: while (defined ($theline = <MODULE>)) {
|
---|
2209 | $good = 1, last line if $theline =~ /^=head\d/;
|
---|
2210 | }
|
---|
2211 | $used_name = $_;
|
---|
2212 | if ($good and $theline =~ /^=head\d\s+NAME\b/ ) {
|
---|
2213 | my @alternative_names;
|
---|
2214 |
|
---|
2215 | # Skip whitespace:
|
---|
2216 | $theline = "";
|
---|
2217 | $theline = <MODULE>
|
---|
2218 | while defined $theline and ($theline !~ /\S/ or $theline =~ /^X</);
|
---|
2219 | # Now have the name, find the description:
|
---|
2220 | if ($theline =~ /^((\S+)(,\s+\S+)*)\s*-\s*(.*)/ ) {
|
---|
2221 | my $desc = $4;
|
---|
2222 | my $podname = $1;
|
---|
2223 | my $have_more = length($2) != length($1);
|
---|
2224 |
|
---|
2225 | if (exists $alias{$shortpath}) {
|
---|
2226 | $used_name = $alias{$shortpath};
|
---|
2227 | } elsif ($believe_pod_name) {
|
---|
2228 | $used_name = $podname;
|
---|
2229 | }
|
---|
2230 | my $skipNAME; # safe to skip NAME section
|
---|
2231 | $name_from_pod = $2;
|
---|
2232 | { $name_from_pod =~ s/\.pm$//; }
|
---|
2233 | $name_from_pod = strip($name_from_pod);
|
---|
2234 | # if ( $name_from_pod =~ /^os2::/i
|
---|
2235 | # and $libdir =~ m!/os2/?$! ) {
|
---|
2236 | # (my $l = $libdir) =~ s,/os2/?$,,;
|
---|
2237 | # return if $in_INC{$l}; # Will find it later...
|
---|
2238 | # }
|
---|
2239 | if ( $used_name =~ /^os2::/i and $libdir !~ m!/os2/?$! ) {
|
---|
2240 | if ($seen_from_pod{$name_from_pod}) {
|
---|
2241 | if ($in_INC{"$libdir/os2"}) { # Already processed...
|
---|
2242 | print STDERR "\n... $_: seen already: `$name_from_pod'\n";
|
---|
2243 | return;
|
---|
2244 | }
|
---|
2245 | print STDERR "\n!!! $_: seen but $libdir/os2 not in \@INC: `$name_from_pod'???\n";
|
---|
2246 | } else {
|
---|
2247 | print STDERR "\n!!! $_: bad match for unseen module: `$name_from_pod'\n";
|
---|
2248 | }
|
---|
2249 | # may have backward-compatibility portable library in @INC,
|
---|
2250 | # but not the (assumingly) version specific .../os2
|
---|
2251 | my $rest = ($used_name =~ /^os2::(.*)/i);
|
---|
2252 | return if lc $rest eq lc $name_from_pod
|
---|
2253 | and $seen_from_pod{$name_from_pod};
|
---|
2254 | }
|
---|
2255 | if (lc($used_name) eq lc($name_from_pod)) {
|
---|
2256 | # There is no sense to keep the NAME section due
|
---|
2257 | # only to the long description, since the
|
---|
2258 | # description is put *both* in the title of contents
|
---|
2259 | # window, and at the top of contents window
|
---|
2260 | $skipNAME = !$have_more; # && length(strip $theline) < 60;
|
---|
2261 | # Prefer the name on the line over the file name:
|
---|
2262 | $used_name = $name_from_pod;
|
---|
2263 | # dumpValue(\%alternative_name);
|
---|
2264 | } elsif ($name_from_pod =~ /^OS2::(.*)/ and lc($used_name) eq lc($1)
|
---|
2265 | and $libdir =~ m![\\/]os2([/\\])?$!) {
|
---|
2266 | # Is not this obsolete?
|
---|
2267 | $skipNAME = !$have_more && length(strip $theline) < 60;
|
---|
2268 | $used_name = $name_from_pod;
|
---|
2269 | # dumpValue(\%alternative_name);
|
---|
2270 | } else {
|
---|
2271 | print STDERR "\n!!! Not matching: `$_' vs. `$name_from_pod'\n"
|
---|
2272 | unless /perlfaq/;
|
---|
2273 | }
|
---|
2274 | $seen_from_pod{$name_from_pod}++;
|
---|
2275 | # Now process additional names this manpage may
|
---|
2276 | # appear under (first from the first line only):
|
---|
2277 | @alternative_names = ($podname =~ /([\w:.]*[\w:])/g);
|
---|
2278 | # Second from additional lines
|
---|
2279 | while (defined ($theline = <MODULE>)
|
---|
2280 | and not $theline =~ /^=/) {
|
---|
2281 | if ($theline =~ /^((\S+)(,\s+\S+)*)\s*-\s*(.*)/) {
|
---|
2282 | push @alternative_names, ($1 =~ /([\w:.]*[\w:])/g);
|
---|
2283 | $skipNAME = 0;
|
---|
2284 | } elsif ($theline =~ /\S/) {
|
---|
2285 | $skipNAME = 0;
|
---|
2286 | }
|
---|
2287 | }
|
---|
2288 | my $f = $_;
|
---|
2289 | unshift @alternative_names, $f
|
---|
2290 | unless $f eq $used_name or grep $_ eq $f, @alternative_names;
|
---|
2291 | @alternative_name{@alternative_names} = ($used_name) x @alternative_names;
|
---|
2292 | print STDERR "Auto-aliases `@alternative_names' for `$used_name'.\n"
|
---|
2293 | if $debug or @alternative_names > 1;
|
---|
2294 | $moddesc{$used_name} = $desc;
|
---|
2295 | if ($skipNAME and 0) { # Do not skip if NAME is the only section
|
---|
2296 | $theline = <MODULE>
|
---|
2297 | while defined ($theline) and not $theline =~ /^=(?!cut)/;
|
---|
2298 | $skipNAME = 0 unless defined $theline;
|
---|
2299 | }
|
---|
2300 | $skip_sections{"$used_name/NAME"}++ if $skipNAME;
|
---|
2301 | } else {
|
---|
2302 | print STDERR "\n!!! $_: bad NAME: `$theline'\n";
|
---|
2303 | }
|
---|
2304 | } elsif ($good) {
|
---|
2305 | print STDERR "\n!!! $_: no NAME\n";
|
---|
2306 | }
|
---|
2307 | add_file($used_name, $longname) if $good;
|
---|
2308 | }
|
---|
2309 |
|
---|
2310 | echopod($_) if $modnamehash{$_};
|
---|
2311 | }
|
---|
2312 |
|
---|
2313 | sub add_file {
|
---|
2314 | my ($used_name, $longname) = @_;
|
---|
2315 | $seen{lc $used_name}++;
|
---|
2316 | $modnamehash{$used_name} = $longname;
|
---|
2317 | $alternative_name{$used_name} = $used_name;
|
---|
2318 | }
|
---|
2319 |
|
---|
2320 | sub debug {
|
---|
2321 | print STDERR "\n", '=' x 79, "\n$_[0]\n", '=' x 79 , "\n";
|
---|
2322 | }
|
---|
2323 |
|
---|
2324 | sub echopod {
|
---|
2325 |
|
---|
2326 | $savenew = $_[0];
|
---|
2327 | $oldpod ||= "";
|
---|
2328 |
|
---|
2329 | # if neither has a ::, same line
|
---|
2330 |
|
---|
2331 | if ($oldpod !~ /::/ && $_[0] !~ /::/) {
|
---|
2332 |
|
---|
2333 | # if old one has a ::, different lines
|
---|
2334 |
|
---|
2335 | } elsif ($oldpod =~ /::/ && $_[0] !~ /::/) {
|
---|
2336 |
|
---|
2337 | print STDERR "\n";
|
---|
2338 |
|
---|
2339 | } elsif ($oldpod !~ /::/ && $_[0] =~ /::/) {
|
---|
2340 |
|
---|
2341 | # if its the new one that has ::, start a header line
|
---|
2342 |
|
---|
2343 | ($new) = ($_[0] =~ /^(.+?)::((?s:.*))/);
|
---|
2344 | print STDERR "\n${new} modules: ";
|
---|
2345 | $_[0] = $2;
|
---|
2346 |
|
---|
2347 | } else {
|
---|
2348 |
|
---|
2349 | # if both have ::, if stuff before first :: is different, newline
|
---|
2350 | # if stuff before is the same, trim it before printing (same line)
|
---|
2351 |
|
---|
2352 | ($old) = ($oldpod =~ /^([^:]+)::/);
|
---|
2353 | ($new) = ($_[0] =~ /^([^:]+)::((?s:.*))/);
|
---|
2354 | if ($old eq $new) {
|
---|
2355 | # kill leading stuff
|
---|
2356 | $_[0] = $2;
|
---|
2357 | } else {
|
---|
2358 | print STDERR "\n${new} modules: ";
|
---|
2359 | $_[0] = $2;
|
---|
2360 | }
|
---|
2361 | }
|
---|
2362 |
|
---|
2363 | $oldpod = $savenew;
|
---|
2364 |
|
---|
2365 | print STDERR $_[0], " ";
|
---|
2366 |
|
---|
2367 | }
|
---|
2368 |
|
---|
2369 | sub hash_diff {
|
---|
2370 | my ($old, $new) = @_;
|
---|
2371 | my @keys = grep {not exists $old->{$_}} keys %$new;
|
---|
2372 | my %diff;
|
---|
2373 | @diff{@keys} = $new->{@keys};
|
---|
2374 | %diff;
|
---|
2375 | }
|
---|
2376 |
|
---|
2377 | # Retval: hash: keys: toplevel nodes, values: '' or refs to lower-level-hashes.
|
---|
2378 | # Keys have :: prepended.
|
---|
2379 | sub create_tree {
|
---|
2380 | my $in = shift;
|
---|
2381 | my %branch;
|
---|
2382 | my (%ret, $leaf, $branch, $subbranch);
|
---|
2383 |
|
---|
2384 | # If $leaf is undef, it means ''. The rest has implicit :: prepended.
|
---|
2385 | foreach $leaf (@$in) {
|
---|
2386 | $ret{''} = '', next unless defined $leaf;
|
---|
2387 | if ($leaf =~ /^((?s:.*?))::((?s:.*))/) {
|
---|
2388 | push @{$branch{$1}}, $2;
|
---|
2389 | } else {
|
---|
2390 | push @{$branch{$leaf}}, undef; # Cooky to denote a leaf
|
---|
2391 | }
|
---|
2392 | }
|
---|
2393 | if (exists $ret{''} or keys %branch > 1) { # Need this level!
|
---|
2394 | foreach $branch (keys %branch) {
|
---|
2395 | $subbranch = create_tree($branch{$branch});
|
---|
2396 | if (keys %$subbranch > 1) {
|
---|
2397 | $ret{"::$branch"} = $subbranch;
|
---|
2398 | } else {
|
---|
2399 | $ret{"::$branch" . (keys %$subbranch)[0]} = '';
|
---|
2400 | }
|
---|
2401 | }
|
---|
2402 | } elsif (%branch) { # This level is not needed, just copy sublevel.
|
---|
2403 | my $key = (keys %branch)[0];
|
---|
2404 | $subbranch = create_tree($branch{(keys %branch)[0]});
|
---|
2405 | foreach $leaf (keys %$subbranch) {
|
---|
2406 | $ret{"::$key$leaf"} = $subbranch->{$leaf};
|
---|
2407 | }
|
---|
2408 | }
|
---|
2409 | \%ret;
|
---|
2410 | }
|
---|
2411 |
|
---|
2412 | sub format_args {
|
---|
2413 | return "with no command-line arguments" unless @args;
|
---|
2414 | 'with arguments C<"' . (join qq(">\nC<"), @args) . '">'
|
---|
2415 | }
|
---|
2416 |
|
---|
2417 | __END__
|
---|
2418 |
|
---|
2419 | =head1 NAME
|
---|
2420 |
|
---|
2421 | pod2ipf - translator from POD format to IBM's F<.INF> format.
|
---|
2422 |
|
---|
2423 | =head1 SYNOPSYS
|
---|
2424 |
|
---|
2425 | cd \perllib\lib\pod
|
---|
2426 | pod2ipf > perl.ipf
|
---|
2427 | ipfc /inf perl.ipf
|
---|
2428 |
|
---|
2429 | pod2ipf my.pod > my.ipf
|
---|
2430 |
|
---|
2431 | pod2ipf my1.pod my2.pod > my.ipf
|
---|
2432 |
|
---|
2433 | pod2ipf --by-files "--title=My first book" \
|
---|
2434 | chapter1.pod chapter2.pod > mybook.ipf
|
---|
2435 |
|
---|
2436 | pod2ipf --by-dirs "--title=Book for /this/dir" /this/dir > book.ipf
|
---|
2437 |
|
---|
2438 | pod2ipf --by-dirs "--title=Book with chapters" \
|
---|
2439 | "--section-name=General topics" --dir=gen1 --dir=gen2 \
|
---|
2440 | "--section-name=Specific topics" --dir=spe1
|
---|
2441 | --dir=spe2 --dir spe3 > longbook.ipf
|
---|
2442 |
|
---|
2443 | =head1 DESCRIPTION
|
---|
2444 |
|
---|
2445 | By default, if no command-line options: processes all the
|
---|
2446 | standard Perl pods in the current directory, as well as all the Perl
|
---|
2447 | libraries and all the Perl utilities it can find using F<Config.pm>,
|
---|
2448 |
|
---|
2449 | The result should be converted to .INF via F<ipfc.exe>, with C</inf> switch.
|
---|
2450 |
|
---|
2451 | Both steps may produce warnings, mostly because of malformed
|
---|
2452 | C<POD>s. [Currently, the only false warnings are some of C<Strip conversion>
|
---|
2453 | warnings.]
|
---|
2454 |
|
---|
2455 | Recognized command-line switches (with defaults);
|
---|
2456 |
|
---|
2457 | --title Title of the INF file
|
---|
2458 | --(no)burst Print Logo and About pages (y)
|
---|
2459 | --(no)about Print About page (y)
|
---|
2460 | --(no)mods Scan through @INC (y)
|
---|
2461 | --(no)std Scan ./ for standard Perl PODs (y)
|
---|
2462 | --(no)bin Scan through $Config{bin} (y)
|
---|
2463 | --(no)tree Output modules tree (y)
|
---|
2464 | --(no)faqs Output faqs (y)
|
---|
2465 | --file If present, do these files too (multiple OK)
|
---|
2466 | --dir Which addnl directories to scan (multiple OK)
|
---|
2467 | --(no)dump-xref Dump them to STDERR (n)
|
---|
2468 | --(no)dump-contents Dump it to STDERR (n)
|
---|
2469 | --(no)dump-manpages Dump unknown manpages to STDERR (y)
|
---|
2470 | --(no)debug Print an additional debug info (n)
|
---|
2471 | --head-off Offset of .IPF headings wrt POD (2|0)
|
---|
2472 | --to-bold If present, words to auto-make bold (multiple OK)
|
---|
2473 | (EMX RSX WPS Object-REXX HPFS HTML WWW GNU Perl C
|
---|
2474 | XFree86 OS/2 CRT PM DOS VIO CPAN IBM URL);
|
---|
2475 | --to-code If present, words to auto-make code-like (multiple OK)
|
---|
2476 | (VCPI DPMI groff awk gawk STDIN STDOUT STDERR Emacs
|
---|
2477 | EPM CMD 4os2 sh pdksh zip unzip pkunzip man gcc
|
---|
2478 | link386 tr PATH LIBPATH)
|
---|
2479 | --section-name Groups next --dir/--file's into a section (multiple OK)
|
---|
2480 | --bin-dir If present, search for binaries here too (multiple OK)
|
---|
2481 | --by-files Interpret extra args as file names (n if options seen)
|
---|
2482 | --by-dirs Interpret extra args as dir names (n)
|
---|
2483 | --www Which browser to use. (%IPFWWW%||lynx||netscape)
|
---|
2484 | --(no)believe-pod-name Take names from NAME sections (n)
|
---|
2485 | --alias Assign name to the preceding file (multiple OK)
|
---|
2486 |
|
---|
2487 | Depending on the value of C<head_off>, the toplevel sections of the generated
|
---|
2488 | book are formed basing on:
|
---|
2489 |
|
---|
2490 | =over 4
|
---|
2491 |
|
---|
2492 | =item 0
|
---|
2493 |
|
---|
2494 | C<=head1>-entries of the POD document(s);
|
---|
2495 |
|
---|
2496 | =item 1
|
---|
2497 |
|
---|
2498 | processed POD documents;
|
---|
2499 |
|
---|
2500 | =item 2
|
---|
2501 |
|
---|
2502 | processed groups of POD documents (sections).
|
---|
2503 |
|
---|
2504 | =back
|
---|
2505 |
|
---|
2506 | Options C<--by-files> and C<--by-dirs> reset the values to
|
---|
2507 |
|
---|
2508 | --nodump-manpages --noburst --nobin --nomods --nostd --notree --nofaqs
|
---|
2509 |
|
---|
2510 | and interpret the unprocessed command-line parameters as names of
|
---|
2511 | files or directories to process.
|
---|
2512 |
|
---|
2513 | If the first argument is not an option, an implicit C<--by-files> is
|
---|
2514 | assumed. If the only argument is not an option, an implicit
|
---|
2515 | C<--head-off=0> is assumed.
|
---|
2516 |
|
---|
2517 | =head2 URL
|
---|
2518 |
|
---|
2519 | Found URLs are made into links. Each link starts a browser; the browser
|
---|
2520 | to start is configured at conversion time by the C<--www> option. Multiple
|
---|
2521 | browsers may be specified, then they are started one-by-one until one of
|
---|
2522 | them succeeds. Use C<||> to separate browsers. The first C<@@@> in
|
---|
2523 | the browser command is replaced by the URL. If no C<@@@> is present,
|
---|
2524 | C<@@@> is assumed at the end.
|
---|
2525 |
|
---|
2526 | Since the default uses C<%IPFWWW%> as the first of the browsers, the user of
|
---|
2527 | the generated files may specify his own browser by setting the
|
---|
2528 | environment variable C<IPFWWW>.
|
---|
2529 |
|
---|
2530 | =head1 PREREQUISITES
|
---|
2531 |
|
---|
2532 | Developer toolkit for OS/2 is required (for C<ifpc>). It is reported that C<ipfc> is also on DDK which is freely available from IBM site.
|
---|
2533 |
|
---|
2534 | =head1 AUTHOR
|
---|
2535 |
|
---|
2536 | C<Marko.Macek@snet.fri.uni-lj.si>, C<mark@hermes.si>,
|
---|
2537 | Ilya Zakharevich C<ilya@math.ohio-state.edu>.
|
---|
2538 |
|
---|
2539 | =head1 SEE ALSO
|
---|
2540 |
|
---|
2541 | L<perlpod>, L<perl>, L<pod2man>, L<perldoc>, L<pod2html>, L<pod2latex>, L<pod2texi>, L<pod2text>.
|
---|
2542 |
|
---|
2543 | =cut
|
---|
2544 |
|
---|
2545 | No docs: L<pod2html>, L<pod2latex>, L<pod2texi>, L<pod2text>,
|
---|