source: git/doc/doc2tex.pl @ 1173547

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