source: git/doc/doc2tex.pl @ 354f3b

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