source: git/doc/doc2tex.pl @ cb12e46

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