source: git/doc/doc2tex.pl @ a70441f

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