source: git/doc/doc2tex.pl @ 84dee1

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