source: git/doc/doc2tex.pl @ 65a2bd

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