source: git/doc/doc2tex.pl @ e61231

spielwiese
Last change on this file since e61231 was c04b94, checked in by Olaf Bachmann <obachman@…>, 24 years ago
* example on kernel commands implemented git-svn-id: file:///usr/local/Singular/svn/trunk@3959 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100755
File size: 16.4 KB
Line 
1#!/usr/local/bin/perl
2# $Id: doc2tex.pl,v 1.22 1999-12-06 16:06:54 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        {
354          $done .= substr($to_do, 0, $ex_length)."\\\n   ";
355          $to_do = substr($to_do, $ex_length + 1);
356        }
357        $_ = $done.$to_do if($done);
358        &protect_texi;
359        $_ = "\@expansion{} ".$_;
360      }
361      print INC $_;
362      print TEX $_;
363    }
364    close(RES);
365    close(INC);
366    unlink $ex_file, $res_file, $inc_file if ($clean);
367  }
368  print TEX "\@c end example $ex_prefix $doc_file:$lline\n";
369}
370 
371######################################################################
372# @c include file
373#    -> copy content of file into output file protecting texi special chars
374sub HandleInclude
375{
376  s/^\@c\s*include\s+([^\s]+)\s/$1/;
377  s/\s*$//;
378  unless (&Open(*INC, "<$_"))
379  {
380    warn "$WARNING HandleInclude: can't open $_ for reading\n";
381    print TEX "\@c include file $_ not found\n";
382    return;
383  }
384  print "<$_>" if ($verbose);
385  print TEX "\@c begin included file $_ from $doc_file:$line\n";
386  while (<INC>)
387  {
388    &protect_texi;
389    print TEX $_;
390  }
391  print TEX "\@c end included file from $doc_file:$line\n";
392  close (INC);
393}
394
395######################################################################
396# @c ref
397# ....
398# @c ref
399#    -> scans intermediate lines for @ref{..} strings
400#    Creates menu of (sorted) refs for ifinfo
401#    Creates comma-separated (sorted) refs for iftex, prepended with
402#    the text before first @ref.
403
404sub HandleRef
405{
406  local(%refs, @refs, $header, $lline, $lref);
407 
408  print TEX "\@c inserted refs from $doc_file:$line\n";
409 
410  # scan lines use %ref to remove duplicates
411  $lline = $line;
412  while (<DOC>)
413  {
414    $line++;
415    last if (/^\@c\s*ref\s*$/);
416   
417    while (/\@ref{(.*?)}/)
418    {
419      $refs{$1} = 1;
420      $_ = $';
421      unless ($header)
422      {
423        $header = $`;
424        $header = " " unless ($header);
425      }
426    }
427    $header = $_ unless ($header)
428  }
429  chomp $header;
430  die "$ERRROR no matching \@c ref found for $doc_file:$lline\n" 
431    unless (/^\@c\s*ref\s*$/);
432  # sort refs
433  @refs = sort(keys(%refs));
434  # put them out
435  print TEX "\@ifinfo\n";
436  print TEX "\@menu\n";
437  if ($header && $header ne " ")
438  {
439    print TEX "$header\n";
440  }
441  else
442  {
443    print TEX "See also:\n";
444  }
445  foreach $ref (@refs) {print TEX "* ".$ref."::\n";}
446  print TEX "\@end menu\n\@end ifinfo\n\@iftex\n";
447
448  if ($header ne " ")
449  {
450    print TEX "$header\n" unless ($header eq " ");
451  }
452  else
453  {
454    print TEX "\@strong{See also:}\n";
455  }
456  $lref = pop(@refs);
457  foreach $ref (@refs) {print TEX "\@ref{".$ref."};\n";}
458  print TEX "\@ref{".$lref."}.\n" if ($lref); 
459  print TEX "\@end iftex\n\@c end inserted refs from $doc_file:$lline\n";
460}
461
462###################################################################
463#
464# @c lib libname.lib[:proc] [no_ex, no_fun, (\w*)section]
465#   --> replaced by @include $texfile where
466#        $texfile = $subdir/libname_lib[_noFun,_noEx].tex
467#   --> if $make, calls "make $texfile"
468#   --> Error, if $tex_file does not exist
469#   --> if [:proc] is given, then includes only of respective
470#       proc body
471#   --> if (\w*)section is given, replaces @subsubsection by @$1section
472#       and pastes in content of tex file directly
473
474sub HandleLib
475{
476  my($lib, $proc, $n_fun, $n_ex, $section, $tex_file);
477
478  if (/^\@c\s*lib\s+([^\.]+)\.lib(.*)/)
479  {
480    $lib = $1;
481    $_ = $2;
482  }
483  else
484  {
485    warn "$WARNING need .lib file to process '$_'\n";
486    print TEX $_;
487    return;
488  }
489
490  $proc = $1 if (/^:(.*?) /);
491  $n_fun = 1 if ($no_fun || /no_fun/);
492  $n_ex = 1 if ($no_ex || /no_ex/);
493  $section = $1 if /(\w*)section/;
494 
495  # contruct tex file name
496  $tex_file = "$doc_subdir/$lib"."_lib";
497  if ($n_fun)
498  {
499    $tex_file .= "_noFun";
500  }
501  elsif ($n_ex)
502  {
503    $tex_file .= "_noEx";
504  }
505  $tex_file .= ".tex";
506
507  if ($make)
508  {
509    print "<lib $lib " if ($verbose);
510    System("make $make_opts VERBOSE=$verbose $tex_file"); 
511  }
512 
513  # make sure file exists
514  if (-r $tex_file)
515  {
516    if ($verbose)
517    {
518      print "<lib $lib " unless $make;
519      print "$proc>";
520    }
521  }
522  else
523  {
524    Error("Can't read $tex_file\n") unless -r $tex_file;
525  }
526
527  # see whether we have to paste something in
528  if ($proc || $section)
529  {
530    open(LTEX, "<$tex_file") 
531      || Error("Can't open $tex_file for reading: $!\n");
532
533    print TEX "\@c start include of docu for $lib.lib:$proc\n";
534    print TEX "\@c replaced \@subsubsection by \@$section\n" if ($section);
535    if ($proc)
536    {
537      my $found = 0;
538      while (<LTEX>)
539      {
540        $found = 1 if /c ---content $proc---/;
541        if ($found)
542        {
543          s/subsubsection/${section}section/ if $section;
544          print TEX $_; 
545        }
546        last if $found && /c ---end content $proc---/;
547      }
548      if ($found)
549      {
550        Error("no end content found for lib proc docu for $lib.lib:$proc $doc_file:$line \n")
551          unless (/c ---end content $proc---/);
552        print TEX "\@c generated lib proc docu for $lib.lib:$proc $doc_file:$line \n";
553      }
554      else
555      {
556        Error("did not find lib proc docu for $lib.lib:$proc $doc_file:$line \n");
557      }
558    }
559    else
560    {
561      while (<LTEX>)
562      {
563        s/subsubsection/${section}section/;
564        print TEX $_;
565      }
566    }
567    print TEX "\@c end include of docu for $lib.lib:$proc\n";
568    close(LTEX);
569  }
570  else
571  {
572    print TEX "\@c include of docu for $lib.lib\n";
573    print TEX "\@include $tex_file\n";
574  }
575}
576
577####################################################################
578# Auxillary routines
579#
580
581# protect texi special characters
582sub protect_texi
583{
584  s/\@/\@\@/g;
585  s/{/\@{/g;
586  s/}/\@}/g;
587}       
588
589# open w.r.t. include_dirs
590sub Open
591{
592  local(*FH, $file) = @_;
593  local($mode);
594  $file =~ s/^(.{1})(.*)/$2/;
595  $mode = $1;
596
597  foreach $dir (@include_dirs)
598  {
599    return $dir if(open(FH, $mode.$dir."/".$file));
600  }
601}
602   
603# system call with echo on verbose > 1 and die on fail
604sub System
605{
606  local($call) = @_;
607  print " d2t system:\n$call\n" if ($verbose > 1);
608  Error("non-zero exit status of system call: '$call': $!\n")
609    if (system($call));
610}
611
612sub Error
613{
614  print "$ERROR $_[0]";
615  close(TEX);
616  unlink $tex_file if $tex_file && -e $tex_file;
617  exit(1);
618}
619
620sub Warn
621{
622  print "$WARNING $_[0]\n";
623}
624#
625# leave this here --otherwise fontification in my emacs gets screwd up
626#
627sub Usage
628{
629  return <<EOT;
630This is doc2tex: a utility to generate Singular texinfo from doc file
631To convert a doc file to texinfo: $0 [options] input_file.doc
632where options can be (abbreviated to shortest possible prefix):
633  -Singular prog: use 'prog' as Singular program to generate ex output
634                          (default: '../Singular/Singular')
635  -output file  : use 'file' as output file
636                          (default: input_file.tex)
637  -clean        : delete intermediate files
638  -make  cmd    : use cmd as make command to generate tex files for libraries
639  -no_reuse     : don't reuse intermediate files
640  -no_ex        : skip computation of examples
641  -no_fun       : don't include help for library functions
642  -docdir  dir  : put intermediate doc/tex files into 'dir'
643                          (default: './d2t_singular')
644  -exdir   dir  : put example files into 'dir'
645                          (default: './examples')
646  -I dir        : look also into 'dir' for include  and lib files
647                          (default: ".", "../Singular/LIB")
648  -verbose  val : Set verbosity to 'val' (0=quiet, 1=prot, >1=all)
649  -help         : print help and exit
650EOT
651}
652
Note: See TracBrowser for help on using the repository browser.