1#!/usr/local/bin/perl
2
3# This script is taken from GAP's etc/ directory. Since xgap is the only
4# GAP package left using it, we make our own copy of it.
5
6@msfiles = ();
7@gdfiles = ();
8$DIR = ".";
9$LIB=".";
10$check=0;
11
12if ( @ARGV && $ARGV[0] =~ /-f/  ) {
13    open( COF, "$ARGV[1]" );
14    while ( $line = <COF> ) {
15        chomp $line;
16        if ( $line =~ /DIR/ ) {
17            @words = split /=/, $line;
18            $DIR = $words[1];
19            $DIR =~ s/[; "]//g;
20            print "DIR set to $DIR\n";
21        } elsif ( $line =~ /LIB/ ) {
22            @words = split /=/, $line;
23            $LIB = $words[1];
24            $LIB =~ s/[; "]//g;
25            print "LIB set to $LIB\n";
26        } elsif ( $line =~ /msfiles/ ) {
27            @words = split /=/, $line;
28            $files = $words[1];
29            while ( !( $line =~ /;/ ) ) { $line = <COF>; $files .= $line; }
30            $files =~ s/[\(\);\n" ]//g;
31            @msfiles = split /,/, $files;
32        } elsif ( $line =~ /gdfiles/ ) {
33            @words = split /=/, $line;
34            $files = $words[1];
35            while ( !( $line =~ /;/ ) ) { $line = <COF>; $files .= $line; }
36            $files =~ s/[\(\);\n" ]//g;
37            @gdfiles = split /,/, $files;
38        } elsif ( $line =~ /check/ ) {
39            # the manual builder should produce a file `notfound'.
40            $check = 1;
41        } elsif ( $line =~ /=/ ) {
42            # assignment of {{variable}} replacements
43            @varass = split /=/, $line;
44            $defaults{$varass[0]} = $varass[1];
45        }
46    }
47}
48
49
50sub coll_and_fam {
51# cope with `DeclareCategoryFamily' and `DeclareCategoryCollection'
52
53    if ($line =~ "DeclareCategoryFamily") {
54        @lipa = split /\"/, $line;
55        $line = $lipa[1].":= NewCategory(\"".$lipa[1]."Family\");";
56    }
57
58    if ($line =~ "DeclareCategoryCollection") {
59        @lipa = split /\"/, $line;
60        if ($lipa[1] =~ "Collection") {
61            $lipa[1] =~ s/Collection//g;
62            $line = $lipa[1] . "CollColl := NewCategory(\"" .
63                    $lipa[1] . "CollColl\",IsObject);";
64        } else {
65            $line = $lipa[1] . "Collection := NewCategory(\"" .
66                    $lipa[1] . "Collection\",IsObject);";
67        }
68    }
69}
70
71
72sub read_table {
73    foreach $file ( @gdfiles ) {
74        $currread = ($file =~ /\.(g|tbd|tmd)/ ) ? $file : "$file.gd";
75        open( GDF, "$LIB/$currread") ? do {print "reading $LIB/$currread\n";
76                                           $readon=1;}
77                                     : do {print "$LIB/$currread not found.\n";
78                                           $readon=0;};
79
80        while ( ($readon) && ($line = <GDF>) ) {
81            if ( $line =~ /^#[CAPOFVR]/ ) {
82                # We look for lines of form:
83                # #<code>  <func-name>( <args> ) . . <description>
84                # #<code>  <var-name>  . . . . . . . <description>
85                # where <code> is a letter in "CAPOFVR".
86                $nfun = 0;       #no. of functions in the block
87                @code = ();      #CAPOFVR codes of the functions
88                @fdec = ();      #things of form: <func-name>( <args> )
89                                 #or:             <var-name>
90                @ldes = ();      #things of form: <description>
91                                 #with dots and superfluous spaces stripped out
92                                 #... which we don't currently use.
93                while ( $line =~ /^#([CAPOFVR])/ ) {
94                    $code[++$nfun] = $1;
95
96# The following piece of code is for long declarations that use several lines.
97# It is assumed that such a long declaration contains "(" on the first line
98# and ")" on some line below.
99
100                    $des = $line;
101                    if ( $line =~ /\(/ ) {
102                        while ( !( $line =~ /\)/ ) ) {
103                            ($line = <GDF>) =~ s/^#[CAPOFVR]\s*/ /;
104                            if ($line =~ /^##\s*$/) {
105                                $des =~ m/^#([A-Z])\s*([^\(]*)/;
106                                #Is it better to die or print an error message?
107                                #... I opted for print error message + try to
108                                #recover, because people don't read error
109                                #messages ... right or wrong? - GG
110                                #die "Closing bracket missing for ".
111                                #    "$1 definition of $2\n".
112                                #    "near line $. of $LIB/$currread\n";
113                                print STDERR "Closing bracket missing for ",
114                                             "$1 definition of $2\n",
115                                             "near line $. of $LIB/$currread\n",
116                                             "... attempting to recover by ",
117                                             "inserting needed closing ",
118                                             "bracket.\n";
119                                $line .= ") ";
120                            }
121                            $des =~ s/[%]*$/%/;
122                            $des .= $line;
123                        }
124                    }
125
126                    ( $des =~ /#[A-Z]\s*(\w+(\s*\([^\)]*\))?)(.*)/ )
127                        || die "syntax error near line $. of $LIB/$currread\n";
128                    ($fdec[$nfun] = $1) =~ s/\s*\(/\(/;
129                    ($ldes[$nfun] = $3) =~ s/[.]//g;
130                    $ldes[$nfun] =~ s/^\s+//;
131                    $ldes[$nfun] =~ s/\s+/ /g;
132                    #print STDERR "fdec: $fdec[$nfun], ldes: $ldes[$nfun]\n";
133
134                    $line = <GDF>;
135                }
136
137                $code[0] = $nfun;
138                $fdec[0] = $nfun;
139                $ldes[0] = $nfun;
140
141                @words = split /\(/, $fdec[1];
142                $key = $words[0];
143                $key .= "@"; $key .= $file;
144
145                if ( ( %{ $tab{$key} } ) ) {
146                    print "DUPLICATE DEFINITION OF $key\n";
147                }
148
149                @args = ();
150                $args[0] = $nfun;
151
152                for ($k=1; $k <= $nfun; ++$k ) {
153                    @argsk = ();
154                    $argsk[0] = 0;
155                    if ( $fdec[$k] =~ /\(/ ) {
156                        @aa = split /\(/, $fdec[$k];
157                        $w = $aa[1];
158                        @aa = split /\)/, $w;
159                        $w = $aa[0];
160                        if (!$w) { $w= " ";}
161                        @aa = split /,/, $w;
162                        $noa = 0;
163
164                        foreach $a ( @aa ) {
165                            ++$noa;
166                            $argsk[$noa] = $a;
167                        }
168                    }
169
170                    $argsk[0] = $noa;
171                    $args[$k] = [ @argsk ];
172                }
173
174                $expl = "";
175                while ( ($line = <GDF>) =~ /^#/  ) {
176                    if ( !( $line =~ /^#T/ ) ) {
177                        $line =~ s/^[#]*//g;
178                        # remove two leading spaces
179                        # Hmmm! ... This doesn't require any spaces!!
180                        $line =~ s/^ //;
181                        $line =~ s/^ //;
182                        $expl .= $line;
183                    }
184                }
185
186                @impl = ();
187                $impl[0] = $nfun;
188                @ipmt = ();
189                $ipmt[0] = $nfun;
190                $ww0 = "";
191                for ($k=1; $k <= $nfun; ++$k) {
192                    $ww1 = $ww0;
193                    if ( $fdec[$k] =~ /\(/ ) {
194                        @ww = split /\(/, $fdec[$k];
195                        $ww0 = $ww[0];
196                    } else {
197                        $ww0 = $fdec[$k];
198                    }
199
200# If the 'new' declaration is not the same as the old one, then we look for a
201# new implementation line (otherwise we do not).
202
203                    if ( !( $ww0 =~ /^$ww1$/ ) ) {
204                        coll_and_fam();
205                        while ( !( $line =~ /$ww0/ ) ) {
206                            eof( GDF ) && die "$ww0 is declared but there ".
207                                              "is no implementation line\n... ",
208                                              "near line $. of $LIB/$currread\n";
209                            $line = <GDF>;
210                            coll_and_fam();
211                        }
212
213                        $defn = $line;
214                        while ( !( $line  =~ /;/ ) ) {
215                            $line = <GDF>;
216                            $defn .= $line;
217                        }
218                    }
219
220                    @implk = ();
221                    $implk[0] = 0;
222                    $j = 0;
223                    @words = split /,/, $defn;
224                    foreach $w ( @words ) {
225                        if ( !( $w =~ /\(/ ) ) {
226                            ++$implk[0];
227                            ++$j;
228                            $implkj = "";
229                            @wds = split / and /, $w;
230                            foreach $v ( @wds ) {
231                                $v =~ s/\)|\[|\]|;| |\n//g;
232                                if ( $implkj =~ /\w/ ) {
233                                    $implkj .= ", ".$v;
234                                } else {
235                                    $implkj .= $v;
236                                }
237                            }
238
239                            $implk[$j] = $implkj;
240                        }
241                    }
242
243                    $impl[$k] = [ @implk ];
244
245                    @words = split /\(/, $defn;
246                    $w = $words[0];
247                    if ( $w =~ /:=/ ) {
248                        @wds = split /:=/, $w;
249                        $v = $wds[1];
250                    } else {
251                        $v = $words[0];
252                    }
253                    $ipmt[$k] = $v;
254                }
255
256# Some default filling in of tester and setter (if such objects are found
257# later on, they will be inserted).
258
259                @test = ();
260                @sett = ();
261#               $ntes = 0; $nset = 0;
262                $test[0]=0; $sett[0]=0;
263                $tab{$key}{test} = [ @test ];
264                $tab{$key}{sett} = [ @sett ];
265                $tab{$key}{expl} = $expl;
266                $tab{$key}{code} = [ @code ];
267                $tab{$key}{args} = [ @args ];
268                $tab{$key}{fdec} = [ @fdec ];
269                $tab{$key}{ldes} = [ @ldes ];
270                $tab{$key}{impl} = [ @impl ];
271                $tab{$key}{ipmt} = [ @ipmt ];
272                $tab{$key}{file} = $currread;
273            }
274# The arrays sett and test are bags of setters and testers respectively. This
275# means that they can appear in any order, it cannot be assumed that they
276# correspond to the order in which the fdecs appear (for instance).
277
278# setter and tester are now declared automatically
279#           if ( $line =~ /Set/ ) {
280#               ++$nset;
281#               ++$sett[0];
282#               @words = split /:=/, $line;
283#               $w = $words[0];
284#               $w =~ s/ //g;
285#               $sett[$nset] = $w;
286#               $tab{$key}{sett} = [ @sett ];
287#           } elsif ( $line =~ /Has/ ) {
288#               ++$ntes;
289#               ++$test[0];
290#               @words = split /:=/, $line;
291#               $w = $words[0];
292#               $w =~ s/ //g;
293#               $test[$ntes] = $w;
294#               $tab{$key}{test} = [ @test ];
295#           }
296
297            if ( $line =~ /#[0-9]/ ) {
298                @chars = split //, $line;
299                $hnum = $chars[1];
300                for ($k=2; ($c=$chars[$k]) =~ /[0-9]/; ++$k) { $hnum .= $c; }
301
302                $htxt = "";
303                while ( ($line = <GDF>) =~ /^#/ ) {
304                    if ( $line =~ /##/ ) {
305                        $line =~ s/#//g;
306                        # remove 1 or two leading spaces
307                        $line =~ s/^ //g;
308                        $line =~ s/^ //g;
309                        $htxt .= $line;
310                    }
311                }
312                $clef = "_h".$file;
313                $tab{$clef}{$hnum} = $htxt;
314            }
315        }
316
317        if ( open( GIF, "$LIB/$file.gi" ) ) {
318            print "reading $LIB/$file.gi\n";
319            $currread="$file.gi";
320            $key = ""; $gide="";
321            $first = 1;
322            while ( $line = <GIF> ) {
323                if ( $line =~ /#[CAPOFVRM]/ ) {
324                    if ( $first == 1 ) {
325                        $first = 0;
326                        if ( $tab{$key} ) {
327                            $tab{$key}{gide} = $gide;
328                            $tab{$key}{meth} = [ @meth ];
329                        }
330                        @words = split /\(/, $line;
331                        $key = $words[0];
332                        $key =~ s/#[CAPOFVRM]| //g;
333                        $gide = "";
334
335                        @mlines = ();
336                        $nom = 0;
337                        $insm = 0;
338                        @meth = (0);
339                    }
340
341                    if ( $line =~ /#M/ ) {
342                        ++$nom;
343                        $mlines[0] = $nom;
344                        $mlines[$nom] = $line;
345                    }
346                } elsif ( $first == 0 ) {
347                    $first =1;
348                }
349
350# The next lines of code handle the #M declarations that must go into the
351# manual from the .gi file. We assume:
352#
353#    * there are as many #M declarations in the header as Install(Other)Method
354#      lines,
355#    * if a method is installed by InstallOtherMethod, and it contains
356#      comments in the body ( #+ lines ), then the corresponding declaration
357#      goes into the manual.
358#
359# In all comment lines in the body of an InstallOtherMethod, the string
360# NUMBER will be replaced by the number (integer) that reflects the position
361# of this declaration in the list of all declarations.
362
363                if ( $line =~ /Install(Other|)Method/ ) {
364                    ++$insm;
365                    $argres = "";
366
367                    if ( $insm <= $nom ) {
368                        $foundres = 0;
369                        $hascom = 0;
370                        $end = 0;
371                        $occurass = 0;
372
373                        while ( $end == 0 ) {
374                            if ( $line =~ /:=/ ) { $occurass = 1; }
375                            if ( $line =~ /^(#\+)/ ) {
376                                $hascom = 1;
377                                $line =~ s/^(#\+)/ /;
378                                @words = split ' ', $line;
379                                foreach $w ( @words ) {
380                                    if ( !($w=~/\n/) ) {$gide .= ($w." ");}
381                                }
382                                $gide .= "\n";
383                            } elsif ( $foundres == 0 && $line =~ /\[/ ) {
384                                $argres = $line;
385                                while ( !( $line =~ /\]/ ) ) {
386                                    $line = <GIF>; $argres .= $line;
387                                }
388                                $met = $argres;
389                                $met =~ s/\\\[//g;
390                                if ( $met =~ /\[/ ) {
391                                    @words = split /\[|\]/, $met;
392                                    $met = $words[1];
393                                    $met =~ s/,|\n/ /g;
394                                    $meth[0] = $insm;
395                                    $meth[$insm] = $met;
396                                    $foundres = 1;
397                                }
398                            }
399                            if ( ( $line =~ /\);/ && $occurass == 0 )
400                                 || $line =~ /end.*\);/ ) {
401                                $end = 1;
402                            }  else {
403                                $line = <GIF>;
404                            }
405                        }
406
407                        if ( $hascom == 1 ) {
408                            if ( $tab{$key} ) {
409                                @code = @{ $tab{$key}{code} };
410                                @fdec = @{ $tab{$key}{fdec} };
411                                @args = @{ $tab{$key}{args} };
412                                @ldes = @{ $tab{$key}{ldes} };
413                                @impl = @{ $tab{$key}{impl} };
414                            } else {
415                                @code = ();
416                                @fdec = ();
417                                @args = ();
418                                @ldes = ();
419                                @impl = ();
420                                $code[0] = 0;
421                                $tab{$key}{expl} = "";
422                            }
423
424                            $nfun = $code[0];
425                            ++$nfun;
426                            $gide =~ s/NUMBER/$nfun/g;
427                            $code[0] = $nfun;
428                            $code[$nfun] = "M";
429                            $tab{$key}{code} = [ @code ];
430
431                            @words = split /\)/, $mlines[$insm];
432                            $w = $words[0];
433                            $w .= "\)";
434                            $w =~ s/#M| //g;
435                            $fdec[$nfun] = $w;
436                            $fdec[0] = $nfun;
437                            $tab{$key}{fdec} = [ @fdec ];
438
439                            @argsk = ();
440                            $argsk[0] = 0;
441                            @aa = split /</, $w;
442                            $noa = 0;
443
444                            foreach $a ( @aa ) {
445                                if ( $a =~ />/ ) {
446                                    ++$noa;
447                                    $a =~ s/>| |,|\)//g;
448                                    $argsk[$noa] = $a;
449                                }
450                            }
451
452                            $argsk[0] = $noa;
453                            $args[0] = $nfun;
454                            $args[$nfun] = [ @argsk ];
455                            $tab{$key}{args} = [ @args ];
456
457                            $w = $words[1];
458                            $w =~ s/\.|  |\n//g;
459                            $ldes[0] = $nfun;
460                            $ldes[$nfun] = $w;
461                            $tab{$key}{ldes} = [ @ldes ];
462
463                            $argres =~ s/\].*/\]/;
464                            @implk = ();
465                            $implk[0] = 0;
466                            $j = 0;
467                            @words = split /,/, $argres;
468                            foreach $w ( @words ) {
469                                ++$implk[0];
470                                ++$j;
471                                $implkj = "";
472                                @wds = split / and /, $w;
473                                foreach $v ( @wds ) {
474                                    $v =~ s/\)|\[|\]|;| |\n//g;
475                                    if ( $implkj =~ /\w/ ) {
476                                        $implkj .= ", ".$v;
477                                    } else {
478                                        $implkj .= $v;
479                                    }
480                                }
481
482                                $implk[$j] = $implkj;
483                            }
484
485                            $impl[$nfun] = [ @implk ];
486                            $impl[0] = $nfun;
487                            $tab{$key}{impl} = [ @impl ];
488                        }
489                    } else {
490                        $meth[0] = $insm;
491                        $foundres = 0;
492                        while ( $foundres == 0 ) {
493                            while ( !( $line =~ /\[/ ) ) {
494                                $line = <GIF>;
495                            }
496                            $met = "  ".$line;
497                            while ( !( $line =~ /\]/ ) ) {
498                                $line = <GIF>;
499                                $met .= $line;
500                            }
501                            $met =~ s/\\\[//g;
502                            if ( $met =~ /\[/ ) {
503                                @words = split /\[|\]/, $met;
504                                $met = $words[1];
505                                $met =~ s/, |\n//g;
506                                $meth[$insm] = $met;
507                                $foundres = 1;
508                            } else {
509                                $line = <GIF>;
510                            }
511                        }
512                    }
513                }
514
515                if ( $line =~ /^(#\+)/ ) {
516                    $line =~ s/^(#\+)/ /;
517                    @words = split ' ', $line;
518                    foreach $w ( @words ) {
519                        if ( !($w=~/\n/) ) {$gide .= ($w." ");}
520                    }
521                    $gide .= "\n";
522                }
523            }
524            if ( $tab{$key} ) {
525                $tab{$key}{gide} = $gide;
526                $tab{$key}{meth} = [ @meth ];
527            }
528        }
529
530        if ( open( GFI, "$file.g" ) ) {
531            $key = ""; $gdes="";
532            while ( $line = <GFI> ) {
533                if ( $tab{$key} ) { $tab{$key}{gdes} = $gdes; }
534
535                if ( $line =~ /#[CAPOFVR]/ ) {
536                    @words = split /\(/, $line;
537                    $key = $words[0];
538                    $key =~ s/#[CAPOFVR]| //g;
539                    $gdes = "";
540                }
541
542                if ( $line =~ /^(#\+)/ ) {
543                    $line =~ s/^(#\+)/ /;
544                    @words = split ' ', $line;
545                    foreach $w ( @words ) {
546                        if ( !($w=~/\n/) ) {$gdes .= ($w." ");}
547                    }
548                    $gdes .= "\n";
549                }
550            }
551            if ( $tab{$key} ) { $tab{$key}{gdes} = $gdes; }
552        }
553    close GDF;
554    }
555    %tab;
556}
557
558
559sub make_tex {
560
561    print "Reading files...\n";
562    %tab = {};
563    %tab = read_table();
564
565    foreach $msfile (@msfiles) {
566        open( MSK, "<$msfile.msk" )
567            || die "Cannot open manual skeleton file $msfile.msk";
568
569        # if the `tex' file does already exist, make it writable
570        chmod 0644, "$DIR/$msfile.tex";
571
572        open( TEX, ">$DIR/$msfile.tex" )
573            || die "Cannot open TeX output file $DIR/$msfile.tex.";
574
575        print "Composing the TeX file $msfile.tex\n";
576        print TEX "% This file was created automatically from $msfile.msk.\n",
577                  "% DO NOT EDIT!\n";
578
579      SCANMSK: while ( $line = <MSK> ) {
580            # treat the {{...}} replacements
581            while ( $line =~ /{{([^}]*)}}/ ) {
582                $key = $1;
583                if ( $key =~ /date/ ) {
584                    $replace=`date +"%d %B %Y"`;
585                } elsif ( $key =~ /year/ ) {
586                    $replace=`date +"%Y"`;
587                } elsif ( $defaults{$key} ) {
588                    $replace=$defaults{$key};
589                } else {
590                    die "$key has no replacement value";
591                }
592                $line =~ s/{{$key}}/$replace/;
593            }
594
595            # Now deal with the `Declaration' mechanism.
596
597# The following is the most we ever need to match:
598# \Declaration{<func-name>}[<gdfile>]{<label>}!{<sub-entry>}@{<index-entry>}
599# Each of [<gdfile>], {<label>}, !{<sub-entry>} and @{<index-entry>} is
600# optional.
601#
602# [<gdfile>] tells the buildman.pe in which .gd file it should look for
603# <func-name> (useful if it exists in more than one .gd file) ... it is
604# also used as a sub-entry if !{<sub-entry>} is not present.
605            if ( $line =~ /\\Declaration/ ) {
606                ($' =~ /\{([^}]*)\}         # $1 = <func-name>
607                        (\[([^\]]*)\])?     # $3 = <gdfile> (without [])
608                        (\{[^}]*\})?        # $4 = {<label>}
609                        (!\{[^}]*\})?       # $5 = !{<sub-entry>}
610                        (@\{[^}]*\})?       # $6 = @{index-entry>}
611                        \s*$/x )
612                   || die "syntax problem with line:\n$line".
613                          "... line $. of $msfile.msk\n";
614                $key        = $1;                     # <func-name>
615                $gdfile     = (defined $3) ? $3 : ""; # <gdfile>
616                $label      = (defined $4) ? $4 : ""; # {<label>}
617                $subentry   = (defined $5) ? $5 : ""; # !{<sub-entry>}
618                $indexentry = (defined $6) ? $6 : ""; # @{index-entry>}
619                #print STDERR "line: $line", "key: $key\ngdfile: $gdfile\n",
620                #             "label: $label\n", "subentry: $subentry\n",
621                #             "indexentry: $indexentry\n";
622
623                $nokeys = 0;
624                %info = ();
625
626              CHKINFO:
627                foreach $k ( keys %tab ) { #each $k is of form: <key>@<gdfile>
628                    #print STDERR "k: $k, key: $key\n";
629                    if ( $k =~ /^$key\@/ ) {
630
631                        #print STDERR "match ... k: $k, key: $key\n";
632                        if ( $gdfile ne "" ) {
633                            #print STDERR "k: $k, gdfile: $gdfile\n";
634                            if ( $k =~ /\@$gdfile$/ ) {
635                                #print STDERR "match ... k:$k, gdfile:$gdfile\n";
636                                %info = %{ $tab{$k} };
637                                $tab{$k}{used} = 1;
638                                $nokeys++;
639                            }
640                        } else {
641                            # so there was no gd file specified in the decl.
642                            if ( $nokeys > 0 ) {
643                                print STDERR "!!$key on line $. of $msfile.msk ",
644                                             "OCCURS IN MORE THAN ONE .gd FILE",
645                                             "\n... taking first one found.\n";
646                                last CHKINFO;
647                            } else {
648                                %info = %{ $tab{$k} };
649                                $tab{$k}{used}= 1;
650                                $nokeys++;
651                            }
652                        }
653                    }
654                }
655
656                if ( %info == () ) {
657                    print STDERR
658                          "!! key: $key NOT FOUND IN THE .gd FILES LISTED!!\n",
659                          "line: $line", "... line $. of $msfile.msk ignored.\n";
660                    next SCANMSK;
661                }
662
663                # $tab{$key}{used} = 1;
664
665                @code = @{ $info{code} };
666                @fdec = @{ $info{fdec} };
667                @ldes = @{ $info{ldes} };
668
669                for ($k=1; $k <= $fdec[0]; ++$k ) {
670                    $fd = $fdec[$k];
671
672                    # Add M to <code> if an attribute that's mutable
673                    $mut = "";
674                    if ( $code[$k] =~ /A/ ) {
675                        @impl = @{ $info{impl} };
676                        @implk = @{ $impl[$k] };
677                        if ( $implk[$implk[0]] =~ /muta/ ) { $mut = "M"; }
678                    }
679
680                    # Add S to <code> if an attribute or property that's a setter
681                    # Add T to <code> if an attribute or property that's a tester
682                    # ... don't think any of this happens anymore.
683                    $st = ""; $ts = "";
684                    if ( $code[$k] =~ /[AP]/ ) {
685                        ($name = $fd) =~ s/(\w+)\s*\(.*/$1/;
686                        #print STDERR "fd: $fd, name: $name\n";
687                        foreach $s ( @{ $info{sett} } ) {
688                            if ( $s =~ /$fd/ ) {
689                                $st = "S";
690                                last;
691                            }
692                        }
693
694                        foreach $t ( @{ $info{test} } ) {
695                            if ( $t =~ /$name/ ) {
696                                $ts = "T";
697                                last;
698                            }
699                        }
700                    }
701
702                    # A space before the bracket is *bad* for the index
703                    $fd =~ s/\s*\(\s*/\( /;
704                    $fd =~ s/\s*\)/ \)/;
705                    $fd =~ s/,\s*/, /g;
706
707                    #print STDERR "fd: $fd\n";
708                    if ( $label eq "" && $indexentry ne "") {
709                        print STDERR "\Declaration has no {<label>} but has ",
710                                     "\@{<index-entry} on\n", "line: $line",
711                                     "... line $. of $msfile.msk.\n";
712                        # make a guess at what $label ought to be
713                        ($label = $indexentry) =~ s/[@`'<>]//g;
714                    } elsif ( "$subentry" eq "!{}" ) {
715                        # special case to avoid [<gdfile>] sub-entries
716                        $subentry = "";
717                    } elsif ( "$label$subentry" eq "" && $fd =~ /[(]/ &&
718                              $gdfile ne "" ) {
719                        $fd =~ /(\w*)/;
720                        $label = "{$1![$gdfile]}"; # gapmacro.tex treats the
721                                                   # !... part as <sub-entry>
722                        $indexentry = "@\{`$1'!`[$gdfile]'}";
723                    }
724
725                    if ( $label ne "") {
726                        print TEX "\\>`$fd'$label$subentry$indexentry";
727                    } elsif ( $fd =~ /[(]/ ) {
728                        print TEX "\\>$fd$subentry$indexentry";
729                    } elsif ( $code[$k] =~ /V/ ) {
730                        #GG : gapmacro.tex now copes with this specially
731                        print TEX "\\>`$fd'";
732                    } else {
733                        print STDERR "!!Argumentless $code[$k] ",
734                                     "declaration: $fd\n";
735                                     "corresponding to line: $line",
736                                     "... line $. of $msfile.msk.\n";
737                        print TEX "\\>`$fd'{$fd}$subentry@\{`$fd'}",
738                    }
739                    #was: print TEX " $code[$k]$st$ts$mut $ldes[$k]\n";
740                    print TEX " $code[$k]$st$ts$mut\n";
741                }
742
743                print TEX "\n$info{expl}\n";
744
745                if ( $info{gide} ) { print TEX "$info{gide}\n"; }
746
747                if ( $info{gdes} ) { print TEX "$info{gdes}\n"; }
748
749            } elsif ( $line =~ /\\beginexample/ ) {
750                print TEX "\\beginexample\n";
751                while ( !( ($line = <MSK>) =~ /\\endexample/ ) ) {
752                    print TEX $line;
753                }
754
755                print TEX "\\endexample\n";
756            } elsif ( $line =~ /\\(Requirements|Implications)/ ) {
757                @impl = @{ $info{impl} };
758                @args = @{ $info{args} };
759
760                print TEX "\\beginitems\n";
761                $lev = 1;
762                if ( $line =~ /\\Requirements/ ) {
763                    print TEX "Requirements: ";
764                } else {
765                    if ( $line =~ /\[.*\]/ ) {
766                        @words = split /\[/, $line;
767                        $w = $words[1];
768                        @chars = split //, $w;
769                        $lev = "";
770                        for ($k=0; !( ($c=$chars[$k])=~/\]/ ); ++$k) {
771                            $lev .= $c;
772                        }
773                    }
774                    if ( $lev == 1 )    { print TEX "Implies: "; }
775                    elsif ( $lev == 2 ) { print TEX "Implied by: "; }
776                }
777
778                if ( $lev == 1 ) {
779                    for ($k=1; $k <= $args[0]; ++$k ) {
780# If two consecutive function declarations are the same, then we don't want
781# two of the same requirement lines.
782
783                        @words = split /\(/, $fdec[$k];
784                        $w = $words[0];
785                        if ( !( $k>1 && $fdec[$k-1] =~ /^$w\(/ ) ) {
786                            print TEX " & ";
787                            for ($j=1; $j <= $args[$k][0]; ++$j ) {
788                                if ( $j <= $impl[$k][0] ) {
789                                    $arg = $args[$k][$j];
790                                    $con = $impl[$k][$j];
791                                    @cons = split /, /, $con;
792                                    $fl = 1;
793                                    foreach $c ( @cons ) {
794                                        $c .= "\( $arg \)";
795                                        if ($fl==1) { $fl = 0; }
796                                        else        { $c = " and ".$c; }
797                                        print TEX $c;
798                                    }
799                                }
800                                print TEX " ";
801                            }
802                            print TEX "\n";
803                        }
804                    }
805                    print TEX "\\enditems\n";
806                }
807
808                if ( $lev == 2 ) {
809                    @keys = keys %tab;
810                    for ($k=1; $k <= $fdec[0]; ++$k) {
811                        print TEX " & ";
812                        @words = split /\(/, $fdec[$k];
813                        $w = $words[0];
814                        $w =~ s/ //g;
815                        foreach $clef ( @keys ) {
816                            if ( !( $clef =~/^_h/ ) ) {
817                                %tb = %{ $tab{$clef} };
818                                if ( $tb{code}[1] =~ /C/ ) {
819                                    @imp = @{ $tb{impl} };
820                                    for ($j=1; $j<=$tb{code}[0]; ++$j ) {
821                                        $im = $imp[$j][1];
822                                        if ( $im =~ /$w/ ) {
823                                            $fd = $tb{fdec}[$j];
824                                            @fds = split /\(/, $fd;
825                                            $fd = $fds[0];
826                                            print TEX "$fd~";
827                                        }
828                                    }
829                                }
830                            }
831                        }
832                        print TEX "\n";
833                    }
834                    print TEX "\\enditems\n";
835                }
836            } elsif ( $line =~ /\\FileHeader/ ) {
837                if ( $line =~ /\[.+\]/ ) {
838                    @words = split /\[|\]/, $line;
839                    $hnum = $words[1];
840                    $hnum =~ s/ //g;
841                } else {
842                    $hnum = "1";
843                }
844
845                @words = split /{|}/, $line;
846                $file = $words[1];
847                $file =~ s/ //g;
848                $clef = "_h".$file;
849                if (!$tab{$clef}) {
850                    print "THERE DOES NOT SEEM TO BE A HEADER IN $file.gd\n";
851                }
852                print TEX $tab{$clef}{$hnum}."\n";
853
854            } elsif ( $line =~ /\\Methods/ ) {
855                if ( @meth = @{ $info{meth} } ) {
856                    print TEX "\\beginitems\n";
857                    print TEX "Methods\: ";
858                    for ($k=1; $k<=$meth[0]; ++$k) {
859                        print TEX " & ";
860                        print TEX "$meth[$k]\n";
861                    }
862                    print TEX "\\enditems\n";
863                } else {
864                    print "No methods found for $key\n";
865                }
866            } else {
867                print TEX $line;
868            }
869        }
870
871        # change the permission  to forbid writing
872        chmod 0444, "$DIR/$msfile.tex";
873        close MSK;
874    }
875
876    if ( $check!=0 ) {
877        open( ERR, ">notfound" ) || die "Cannot open `notfound'\n";
878
879        @kk = sort(keys %tab);
880        foreach $key (@kk) {
881            if ( ! $tab{$key}{used} ) {
882                print ERR "$tab{$key}{file}: \t$key\n";
883            }
884        }
885        print "\n\nThe file `notfound' contains ",
886              "a list of unused declarations\n";
887    }
888}
889
890make_tex();
891
892