source: git/doc/doc2tex.pl @ f36635

spielwiese
Last change on this file since f36635 was f36635, checked in by Olaf Bachmann <obachman@…>, 25 years ago
* merged in changes from 1-2-3 git-svn-id: file:///usr/local/Singular/svn/trunk@3207 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100755
File size: 19.0 KB
RevLine 
[f36635]1#!/usr/local/bin/perl
2# $Id: doc2tex.pl,v 1.2 1999-07-01 12:48:00 obachman Exp $
3###################################################################
4#  Computer Algebra System SINGULAR
5#
6#  doc2tex: utility to generate the Singular manual
7#
8####
9# @c example [error]
10#    -> the text till the next @c example is feed into Singular,
11#       the text is then substituted by
12#       @c computed example $example $doc_file:$line
13#       <text from the input>
14#       @expansion{} <corresponding output>
15#       ....
16#       @c end computed example $example $doc_file:$line
17#       reuse computed examples if ($reuse && -r $example.inc)
18#       cut absolute directory names from the loaded messages
19#       substituted @,{ and } by @@, @{ resp. @}
20#       wrap around output lines  longer than $ex_length = 73;
21#       Processing is aborted if error occures in Singular run,
22#       unless 'error' is specified
23#
24####
25# @c include file
26#    -> copy content of file into output file protecting texi special chars
27#
28####
29# @c ref
30# ....
31# @c ref
32#    -> scans intermediate lines for @ref{..} strings
33#    Creates menu of (sorted) refs for ifinfo
34#    Creates comma-separated (sorted) refs for iftex, prepended with
35#    the text before first @ref.
36#
37####
38# @c lib libname.lib [no_ex, lib_fun, lib_ex]
39#   --> includes info of libname.lib in output file
40#   --> includes function names of info into function index
41#   --> if lib_fun is given, includes listing of functions and
42#                      their help into output file
43#   --> if lib_ex is given, includes computed examples of functions, as well
44#
45#   Optional no_ex, lib_fun, lib_ex arguments overwrite respective
46#    command-line arguments
47#
48#
49###################################################################
50
51#
52# default settings of command-line arguments
53#
54$Singular = "../Singular/Singular"; # should be overwritten
55$libparse = "../Singular/libparse"; # change in final version
56$Singular_opts = " -teqr12345678";
57$clean = 0;
58$verbose = 1;
59$reuse = 1;
60$no_ex = 0;
61$lib_fun = 0;
62$lib_ex = 0;
63$doc_subdir = "./d2t_singular";
64@include_dirs = (".", "../Singular/LIB");
65$doc_examples_db = "$doc_subdir/examples";
66
67#
68# misc. defaults
69#
70$ex_length = 73;
71$ERROR = "\n**** Error:";
72$WARNING = "\n** Warning:";
73
74#
75# flush stdout and stderr after every write
76#
77select(STDERR);
78$| = 1;
79select(STDOUT);
80$| = 1;
81
82#
83# get file to convert
84#
85$doc_file = pop(@ARGV);
86if ($doc_file =~  /(.+)\..*$/)
87{
88  die "*** Error: Need .doc file as input\n" . &Usage 
89    unless ($doc_file =~ /(.+)\.doc$/);
90}
91else
92{
93  if ($doc_file =~ /^-h(elp)?$/) { print &Usage; exit;}
94  $doc_file .= ".doc";
95}
96
97#
98# parse command line options
99#
100$args = join(" ", @ARGV);
101while (@ARGV && $ARGV[0] =~ /^-/) 
102{
103  $_ = shift(@ARGV);
104  if (/^-S(ingular)?$/)  { $Singular = shift(@ARGV); next;}
105  if (/^-l(ibparse)?$/)  { $libparse = shift(@ARGV); next;}
106  if (/^-o(output)?$/)   { $tex_file = shift(@ARGV); next;}
107  if (/^-no_r(euse)?$/)  { $reuse = 0; next;}
108  if (/^-c(lean)?$/)     { $clean = 1; next;}
109  if (/^-no_e(x)?$/)     { $no_ex = 1; next;}
110  if (/^-lib_fu(n)?$/)   { $lib_fun = 1;next;}
111  if (/^-lib_e(x)?$/)    { $lib_ex = 1; next;}
112  if (/^-s(ubdir)?$/)    { $doc_subdir = shift(@ARGV); next;}
113  if (/^-I$/)            { unshift(@include_dirs, shift(@ARGV)); next;}
114  if (/^-v(erbose)?$/)   { $verbose = shift(@ARGV); next;}
115  if (/^-h(elp)?$/)      { print &Usage; exit;}
116  die &Usage;
117}
118$verbose = ($verbose < 0 ? 0 : $verbose);
119
120#
121# construct filenames
122#
123($doc_dir = $doc_file) =~ s/(.+)\.doc$/$1/;
124if ($doc_dir =~ /(.*)\//)
125{
126  $doc = $';
127  $doc_dir = $1;
128}
129else
130{
131  $doc = $doc_dir;
132  $doc_dir = ".";
133}
134$tex_file = "$doc_dir/$doc.tex" unless ($tex_file);
135               
136#
137# open files
138#
139open(DOC, "<$doc_file") 
140  || die "$ERROR can't open $doc_file for reading: $!\n" . &Usage;
141open(TEX, ">$tex_file") || die "$ERROR can't open $tex_file for writing: $!\n";
142print "d2t: Generating $tex_file from $doc_file ...\n" if ($verbose > 1);
143print "d2t: $doc_file ==> $tex_file\n" if ($verbose == 1);
144if (-d $doc_subdir)
145{
146  print "d2t: Using $doc_subdir for intermediate files\n" 
147    if ($verbose > 1);
148}
149else
150{
151  mkdir($doc_subdir, oct(755)) 
152    || die "$ERROR can't create directory $doc_subdir: $!\n";
153  print "d2t: Created $doc_subdir for intermediate files\n" 
154    if ($verbose > 1);
155}
156
157dbmopen(%EXAMPLES, $doc_examples_db, oct(755)) || die "$ERROR: can't open examples data base: $!\n";
158
159#######################################################################
160#
161# go !
162#
163while (<DOC>)
164{
165  $line++;
166 
167  if (/^\@c\s*example/)     {&HandleExample; next;}
168  if (/^\@c\s*include\s+/)  {&HandleInclude; next;}
169  if (/^\@c\s*ref\s*$/)     {&HandleRef; next;}
170  if (/^\@c\s*lib\s+/)      {&HandleLib; next;}
171  if (/^\@setfilename/)     {print TEX "\@setfilename $doc.hlp\n"; next;}
172                             
173  print TEX $_;
174
175  if (/^\@bye$/)            {last;}
176}
177
178#
179# wrap up
180#
181close(TEX);
182dbmclose(%EXAMPLES);
183print "\nd2t: Finished generation of $tex_file \n" if ($verbose > 1);
184print "\n" if ($verbose == 1);
185
186
187######################################################################
188# @c example [error]
189#    -> the text till the next @c example is feed into Singular,
190#       the text is then substituted by
191#       @c computed example $example $doc_file:$line
192#       <text from the input>
193#       @expansion{} <corresponding output>
194#       ....
195#       @c end computed example $example $doc_file:$line
196#       reuse computed examples if ($reuse && -r $example.inc)
197#       cut absolute directory names from the loaded messages
198#       substituted @,{ and } by @@, @{ resp. @}
199#       wrap around output lines  longer than $ex_length = 73;
200#       Processing is aborted if error occures in Singular run,
201#       unless 'error' is specified
202sub HandleExample
203{
204  my($lline, $thisexample, $include, $error_ok);
205 
206  $lline = $line;
207  $example++;
208
209  if ($no_ex)
210  {
211    print "{$example}" if ($verbose);
212    print TEX "\@c skipped computation of example $example $doc_file:$lline \n";
213   
214  }
215
216  $thisexample = '';
217  $error_ok = 1 if /error/;
218  # print content in example file till next @c example
219  while (<DOC>)
220  {
221    $line++;
222    last if (/^\@c\s*example\s*$/);
223    s/^\s*//; # remove preceeding white spaces
224    if ($no_ex)
225    {
226      &protect_texi;
227      print TEX $_;
228    }
229    else
230    {
231      $thisexample .= $_ unless (/^\s*$/);
232    }
233  }
234  die "$ERROR no matching '\@c example' found for $doc_file:$lline\n"
235    unless (/^\@c\s*example\s*$/);
236
237  # done, if no examples
238  return if ($no_ex);
239
240  # check whether it can be reused
241  $include = $EXAMPLES{$thisexample};
242  if ($reuse && ($include = $EXAMPLES{$thisexample}))
243  {
244    print "<$example>" if ($verbose);
245    print TEX "\@c reused example $example $doc_file:$lline \n";
246  }
247  else
248  {
249    print "($example" if ($verbose == 1);
250    my ($ex_file, $res_file, $inc_file);
251    $inc_file = "$doc_subdir/$doc"."_$example.inc";
252    $ex_file = "$doc_subdir/$doc"."_$example.tst";
253    $res_file = "$doc_subdir/$doc"."_$example.res";
254
255    print TEX "\@c computed example $example $doc_file:$lline \n";
256
257    # run singular
258    open(EX, ">$ex_file") || die "$ERROR can't open $ex_file for writing: $!\n";
259    print EX "$thisexample\$\n";
260    close(EX);
261
262    &System("$Singular $Singular_opts $ex_file > $res_file");
263    print ")" if ($verbose == 1);
264
265    open(RES, "<$res_file") || die "$ERROR can't open $res_file for reading: $!\n";
266    open(INC, ">$inc_file") || die "$ERROR can't open $inc_file for writing: $!\n";
267
268    $include = '';
269    # get result, manipulate it and put it into inc file
270    while (<RES>)
271    {
272      last if (/^$ex_file\s*([0-9]+)..\$/);
273      # check for error
274      die "$ERROR while running example $example from $doc_file:$lline.\nCall: '$Singular $Singular_opts $ex_file > $res_file'\n"
275        if (/error occurred/ && ! $error_ok);
276      # remove stuff from echo
277      if (/^$ex_file\s*([0-9]+)../)
278      {
279        $_ = $';
280        &protect_texi;
281      }
282      else
283      {
284        local($to_do, $done);
285        # remove absolute path names from laoded messages
286        s/^(\/\/ \*\* loaded )(.*)\/(.+).lib(.*)/$1$3.lib$4/;
287        # shorten error occurred in messages
288        s/\? error occurred in [^ ]* line/\? error occurred in line/;
289        # break after $ex_length characters
290        $to_do = $_;
291        while (length($to_do) > $ex_length)
292        {
293          $done .= substr($to_do, 0, $ex_length)."\\\n   ";
294          $to_do = substr($to_do, $ex_length + 1);
295        }
296        $_ = $done.$to_do if($done);
297        &protect_texi;
298        $_ = "\@expansion{} ".$_;
299      }
300      $include .= $_;
301      print INC $_;
302    }
303    close(RES);
304    close(INC);
305    unlink $ex_file, $res_file, $inc_file if ($clean);
306    $EXAMPLES{$thisexample} = $include;
307  }
308  print TEX $include;
309  print TEX "\@c end example $example $doc_file:$lline\n";
310}
311 
312######################################################################
313# @c include file
314#    -> copy content of file into output file protecting texi special chars
315sub HandleInclude
316{
317  s/^\@c\s*include\s+([^\s]+)\s/$1/;
318  unless (&Open(*INC, "<$_"))
319  {
320    warn "$WARNING HandleInclude: can't open $_ for reading\n";
321    print TEX "\@c include file $_ not found\n";
322    return;
323  }
324  print "<$_>" if ($verbose);
325  print TEX "\@c begin included file $_ from $doc_file:$line\n";
326  while (<INC>)
327  {
328    &protect_texi;
329    print TEX $_;
330  }
331  print TEX "\@c end included file from $doc_file:$line\n";
332  close (INC);
333}
334
335######################################################################
336# @c ref
337# ....
338# @c ref
339#    -> scans intermediate lines for @ref{..} strings
340#    Creates menu of (sorted) refs for ifinfo
341#    Creates comma-separated (sorted) refs for iftex, prepended with
342#    the text before first @ref.
343
344sub HandleRef
345{
346  local(%refs, @refs, $header, $lline, $lref);
347 
348  print TEX "\@c inserted refs from $doc_file:$line\n";
349 
350  # scan lines use %ref to remove duplicates
351  $lline = $line;
352  while (<DOC>)
353  {
354    $line++;
355    last if (/^\@c\s*ref\s*$/);
356   
357    while (/\@ref{([^\s]*)}/)
358    {
359      $refs{$1} = 1;
360      $_ = $';
361      unless ($header)
362      {
363        $header = $`;
364        $header = " " unless ($header);
365      }
366    }
367  }
368  die "$ERRROR no matching \@c ref found for $doc_file:$lline\n" 
369    unless (/^\@c\s*ref\s*$/);
370  # sort refs
371  @refs = sort(keys(%refs));
372  # put them out
373  print TEX "\@ifinfo\n\@menu\n";
374  foreach $ref (@refs) {print TEX "* ".$ref."::\n";}
375  print TEX "\@end menu\n\@end ifinfo\n\@iftex\n";
376
377  if ($header ne " ")
378  {
379    print TEX "$header\n" unless ($header eq " ");
380  }
381  else
382  {
383    print TEX "\@strong{See also:} ";
384  }
385  $lref = pop(@refs);
386  foreach $ref (@refs) {print TEX "\@ref{".$ref."};\n";}
387  print TEX "\@ref{".$lref."}.\n" if ($lref); 
388  print TEX "\@end iftex\n\@c end inserted refs from $doc_file:$lline\n";
389}
390
391###################################################################
392#
393# @c lib libname.lib [no_ex, lib_fun, lib_ex]
394#   --> includes info of libname.lib in output file
395#   --> includes function names of info into function index
396#   --> if lib_fun is given, includes listing of functions and
397#                      their help into output file
398#   --> if lib_ex is given, includes computed examples of functions, as well
399#
400# Optional no_ex, lib_fun, lib_ex arguments overwrite respective
401# command-line arguments
402#
403
404sub HandleLib
405{
406  local($lib, $lib_name, $ltex_file, $l_ex, $l_fun);
407 
408  if (/^\@c\s*lib\s+([^\.]+)\.lib(.*)/)
409  {
410    $lib = $1;
411    $lib_name = $lib.".lib";
412    $_ = $2;
413  }
414  else
415  {
416    warn "$WARNING need .lib file to process '$_'\n";
417    print TEX $_;
418    return;
419  }
420
421  $l_fun = 1 if (($lib_fun || (/lib_fun/)) && !/no_fun/);
422  $l_ex = 1 if (($lib_ex || /lib_ex/) && !/no_ex/ && $l_fun);
423
424  $ltex_file = "$doc_subdir/$lib"."_lib";
425  unless ($l_ex)
426  {
427    if ($l_fun)
428    {
429      $ltex_file .= "_noEx";
430    }
431    else
432    {
433      $ltex_file .= "_noFun";
434    }
435  }
436  $ltex_file .= ".tex";
437 
438  die "$ERROR can't open $lib.lib for reading: $!\n" 
439    unless  ($lib_dir = &Open(*LIB, "<$lib.lib"));
440  close (LIB);
441  if ($reuse && open(LTEX, "<$ltex_file") && 
442      IsNewer($ltex_file, "$lib_dir/$lib.lib"))
443  {
444    print "<lib $lib>" if ($verbose);
445    $reuse_this = 1;
446    print TEX "\@c reused lib docu for $lib_name $doc_file:$line \n";
447  }
448  elsif (&GenerateLibDoc($lib, $ltex_file, $l_fun, $l_ex))
449  {
450    print TEX "\@c generated lib docu for $lib_name $doc_file:$line \n";
451    open(LTEX, "<$ltex_file") 
452      || die "$ERROR can't open $ltex_file for reading: $!\n";
453  }
454  while (<LTEX>) {print TEX $_;}
455  close(LTEX);
456  print TEX "\@c end generated lib docu for $lib_name $doc_file:$line \n";
457  unlink $ltex_file if ($clean);
458}
459 
460sub GenerateLibDoc
461{
462  my($lib, $tex_file, $l_fun, $l_ex) = @_;
463  my($lib_dir, $scall, $pl_file, $doc_file, $i, $example,$largs);
464  # vars from executing the library perl scrip
465  local($info, $libary, $version, @procs, %example, %help);
466 
467  print "(lib $lib: " if ($verbose == 1);
468  # construct doc/tex file name
469  $doc_file = "$doc_subdir/$lib"."_lib";
470  $doc_file .= "_noFun" unless ($l_fun);
471  $doc_file .= ".doc";
472
473  die "$ERROR can't open $lib.lib for reading: $!\n" 
474    unless  ($lib_dir = &Open(*LIB, "<$lib.lib"));
475  close (LIB);
476  if (-r $doc_file && $reuse && IsNewer($doc_file, "$lib_dir/$lib.lib"))
477  {
478    print "<doc>" if ($verbose == 1);
479    print TEX "\@c reused file $doc_file\n";
480  }
481  else
482  {
483    # generate perl file, if necessary
484    $pl_file = "$doc_subdir/$lib"."_lib.pl";
485    if (-r $pl_file && $reuse && IsNewer($pl_file, "$lib_dir/$lib.lib"))
486    {
487      print "<pl>" if ($verbose == 1);
488      print TEX "\@c reused file $pl_file\n";
489    }
490    else
491    {
492      print "(pl" if ($verbose == 1);
493      &System("$libparse -i $lib_dir/$lib.lib > $pl_file");
494      print ")" if ($verbose == 1);
495      print TEX "\@c generated file $pl_file\n";
496    }
497
498    print "(doc" if ($verbose == 1);
499    print TEX "\@c generated file $doc_file\n";
500   
501    do $pl_file;
502    die "$ERROR error while executing $pl_file: $@\n" if ($@);
503    unlink ($pl_file) if ($clean);
504   
505    # generate doc file
506    open(LDOC, ">$doc_file") || die"$ERROR can't open $doc_file for writing: $!\n";
507   
508    # print header
509    $info = &CleanUpHelp($info);
510    print LDOC "\@c library version: $version\n";
511    print LDOC "\@c library file: $library\n";
512    print LDOC "\@strong{Overview:}\n\@example\n";
513    print LDOC $info;
514    print LDOC "\n\@end example\n";
515    # generate findex for every routine mentioned
516    while ($info =~ /^(.*)\n/)
517    {
518      $info = $';
519      if ($1 =~ /^\s*(\w{1}[\w\d]*)\(.*\)/)
520      {
521        print LDOC "\@findex $1\n";
522        print LDOC "\@cindex $1\n" if ($lib eq "standard");
523      }
524    }
525   
526    # print menu of available functions
527    if ($l_fun)
528    {
529      @procs = sort(@procs);
530      print LDOC "\@menu\n";
531      foreach $proc (@procs) {print LDOC "* $proc"."::\n";}
532      print LDOC "\@end menu\n";
533     
534      # print help and example of each function
535      for ($i = 0; $i <= $#procs; $i++)
536      {
537        # print node and section heading
538        print LDOC "\n\@c ------------------- " . $procs[$i]." -------------\n";
539        print LDOC "\@node " . $procs[$i].",";
540        print LDOC " ".$procs[$i+1] if ($i < $#procs);
541        print LDOC ",";
542        print LDOC " ".$procs[$i-1] if ($i > 0);
543        print LDOC ", " . $lib ."_lib\n";
544        print LDOC "\@subsection " . $procs[$i] . "\n";
545        print LDOC "\@findex ". $procs[$i] . "\n";
546        print LDOC "\@cindex ". $procs[$i] . "\n" if ($lib eq "standard");
547       
548        # print help section
549        print LDOC "\@strong{Info:}\n";
550        print LDOC "\@example\n";
551        print LDOC &CleanUpHelp($help{$procs[$i]});
552        print LDOC "\n\@end example\n";
553       
554        # print example section
555        next unless ($example = &CleanUpExample($lib, $example{$procs[$i]}));
556        print LDOC "\@strong{Example:}\n";
557        print LDOC "\@example\n\@c example\n";
558        print LDOC $example;
559        print LDOC "\n\@c example\n\@end example\n";
560      }
561    }
562    close(LDOC);
563    print ")" if ($verbose == 1);
564  }
565
566  $largs = "-no_ex" unless ($l_ex);
567  # call doc2tex on generated doc file
568  print "\n" if ($verbose == 1);
569  dbmclose(%EXAMPLES);
570  &System("$0 $args $largs -o $tex_file $doc_file");
571  dbmopen(%EXAMPLES, $doc_examples_db, oct(755)) 
572    || die "$ERROR: can't open examples data base: $!\n";
573 
574  unlink($doc_file) if ($clean);
575  return 1;
576}
577
578###################################################################
579#
580# Auxiallary functions
581#
582sub CleanUpHelp
583{
584  local($_) = @_;
585 
586  # remove spaces quotations, etc from beginning and end
587  s/^[^\w]*//;
588  s/[\s\n"]*$//; #"
589  # replace
590  s/\\\\/\\/g;
591  s/\\"/"/g;
592  # remove line beginning with example
593  s/\nEXAMPLE.*//;
594  &protect_texi;
595  return ($_);
596}
597 
598sub CleanUpExample
599{
600  local($lib, $example) = @_;
601 
602  # find portion in {}
603  $example =~ s/^[^{]*{(.*)}[^}]*$/$1/s;
604
605  if ($example =~ /EXAMPLE: \(not executed\)/)
606  {
607    # erase first three lines
608    $example =~ s/^.*\n.*\n.*\n/\n/;
609    # erase enclosing " " in every line
610    $example =~ s/\n\s*"/\n/g;
611    $example =~  s/";\n/\n/g;
612  }
613  # erase EXAMPLE, echo and pause statements
614  $example =~ s/"EXAMPLE.*"[^;]*;//g;
615  $example =~ s/echo[^;]*;//g;
616  $example =~ s/pause[^;]*;//g;
617 
618  # prepend LIB command
619  $example = "LIB \"$lib.lib\";\n".$example 
620    if ($example && $lib ne "standard");
621  # erase empty lines
622  $example =~ s/^\s*\n//g;
623  # erase spaces from beginning of lines
624  $example =~ s/\n\s*/\n/g;
625  return $example;
626}
627
628sub IsNewer
629{
630  my $f1 = shift;
631  my $f2 = shift;
632  my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime)
633    = stat($f1);
634  my $m1 = $mtime;
635  ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime) = stat($f2);
636
637  return ($m1 > $mtime);
638}
639
640####################################################################
641# Auxillary routines
642#
643
644# protect texi special characters
645sub protect_texi
646{
647  s/\@/\@\@/g;
648  s/{/\@{/g;
649  s/}/\@}/g;
650}       
651
652# open w.r.t. include_dirs
653sub Open
654{
655  local(*FH, $file) = @_;
656  local($mode);
657  $file =~ s/^(.{1})(.*)/$2/;
658  $mode = $1;
659
660  foreach $dir (@include_dirs)
661  {
662    return $dir if(open(FH, $mode.$dir."/".$file));
663  }
664}
665   
666# system call with echo on verbose > 1 and die on fail
667sub System
668{
669  local($call) = @_;
670  print "d2t system: $call\n" if ($verbose > 1);
671  die "$ERROR non-zero exit status of system call: '$call': $!\n"
672    if (system($call));
673}
674
675   
676#
677# leave this here --otherwise fontification in my emacs gets screwd up
678#
679sub Usage
680{
681  return <<EOT;
682This is doc2tex: a utility to generate Singular texinfo from doc file
683To convert a doc file to texinfo: $0 [options] input_file.doc
684where options can be (abbreviated to shortest possible prefix):
685  -Singular prog: use 'prog' as Singular program to generate ex output
686                          (default: '../Singular/Singular')
687  -libparse prog: use 'prog' as libparse program to generate lib docu
688                          (default: '../Singular/libparse')
689  -output file  : use 'file' as output file
690                          (default: input_file.tex)
691  -clean        : delete intermediate files
692  -no_reuse     : don't reuse intermediate files
693  -no_ex        : skip computation of examples
694  -lib_fun      : include help for library functions
695  -lib_ex       : include example for library functions
696  -subdir  dir  : put intermediate files into 'dir'
697                          (default: './d2t_singular')
698  -I dir        : look also into 'dir' for include  and lib files
699                          (default: ".", "../Singular/LIB")
700  -verbose  val : Set verbosity to 'val' (0=quiet, 1=prot, >1=all)
701  -help         : print help and exit
702EOT
703}
704
Note: See TracBrowser for help on using the repository browser.