source: git/doc/doc2tex.pl @ 4b72f6

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