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