source: git/doc/doc2tex.pl @ 8a0ba8

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