[BACK]Return to tex2mail CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / pari-2.2 / misc

Annotation of OpenXM_contrib/pari-2.2/misc/tex2mail, Revision 1.2

1.1       noro        1: #!/usr/bin/perl
                      2:
1.2     ! noro        3: # $Id: tex2mail.in,v 1.2 2002/04/27 21:00:46 karim Exp $
1.1       noro        4: #
                      5: # Features:
                      6: #      % at the end of a line followed by \n\n is recognized as end of
                      7: #      paragraph :-(
                      8: #
                      9: # Change log is at bottom.
                     10: #
                     11: # Options:
                     12: #      linelength=75           # Cut at this line
                     13: #      maxdef=400              # definition loops: croak if many substitutions
                     14: #      debug=0
                     15: #      by_par=0                # Expect each paragraph to be terminated
                     16: #                              # by *exactly* 2 "\n", and do not print
                     17: #                              # an extra "\n" between paragraphs
                     18: #      TeX                     # Assume it is not LaTeX
                     19: #      ragged                  # leave right ragged
                     20: #      noindent                # assume \noindent everywhere
                     21:
                     22: eval 'require "newgetopt.pl";
                     23:   &NGetOpt("linelength=i","maxdef=i","debug=i","by_par", "TeX",
                     24:           "ragged", "noindent")'
                     25:     || warn "Errors during parsing command line options" .
                     26:        ($@ ? ": $@" : '') . ".\n";
                     27: $linelength= $opt_linelength || 75;
                     28: $maxdef= $opt_maxdef || 400;
                     29: $debug=$opt_debug;
                     30:
                     31: $notusualtoks="\\\\" . '\${}^_~&@';
                     32: $notusualtokenclass="[$notusualtoks]";
                     33: $usualtokenclass="[^$notusualtoks]";
                     34: $macro='\\\\([^a-zA-Z]|([a-zA-Z]+\s*))'; # Why \\\\? double interpretation!
                     35: $active="$macro|\\\$\\\$|$notusualtokenclass";
                     36: $tokenpattern="$usualtokenclass|$active";
                     37: $multitokenpattern="$usualtokenclass+|$active";
                     38:
                     39:
                     40: # Format of the record: height,length,baseline,expandable-spaces,string
                     41: # The string is not terminated by \n, but separated into rows by \n.
                     42: # height=0 denotes expandable string
                     43: # Baseline=3 means the 4th row is the baseline
                     44:
                     45: sub debug_print_record {
                     46:   local($h,$l,$b,$xs,$s) = split /,/, shift, 5;
                     47:   local(@arr) = split /\n/, $s;
                     48:   print STDERR "len=$l, h=$h, b=$b, exp_sp=$xs.\n";
                     49:   local($i) = 0;
                     50:   for (@arr) {
                     51:     local($lead) = ($i++ == $b) ? 'b [' : '  [';
                     52:     print STDERR "$lead$_]\n";
                     53:   }
                     54:   while ($i < $h) {            # Empty lines may skipped
                     55:     local($lead) = ($i++ == $b) ? 'b' : '';
                     56:     print STDERR "$lead\n";
                     57:   }
                     58: }
                     59:
                     60: # Takes length and a record, returns 2 records
                     61:
                     62: sub cut {
                     63:   local($length)=(shift);
                     64:   local($h,$l,$b,$sp,$str)=split(/,/,shift,5);
                     65:   local($st1,$st2)=("","");
                     66:   local($sp1,$sp2,$first,$l2)=(0,0,1,$l-$length);
                     67:   return (shift,&empty) if $l2<0;
                     68:   if ($h) {
                     69:     for (split(/\n/,$str,$h)) {
                     70:       if (!$first) {
                     71:         $st1 .= "\n";
                     72:         $st2 .= "\n";
                     73:       } else {$first=0;}
                     74:       $st1 .= substr($_,0,$length);
                     75:       $st2 .= substr($_,$length);
                     76:     }
                     77:   } else {
                     78:     $st1 = substr($str,0,$length);
                     79:     $st2 = substr($str,$length);
                     80:     #if ($sp && ($st1 =~ /(\S)(\s+\S*)$/)) {
                     81:     # $st2 = $2 . $st2;
                     82:     # $st1 = $` . $1;
                     83:     # $sp1 = ($st1 =~ /(\s)/g);
                     84:     # $sp2 = ($st2 =~ /(\s)/g);
                     85:     #}
                     86:   }
                     87:   return ("$h,$length,$b,$sp1,$st1","$h,$l2,$b,$sp2,$st2");
                     88: }
                     89:
                     90: # Outputs a record
                     91:
                     92: sub printrecord {
                     93:   warn "Printing $_[0]\n__ENDPRINT__\n" if $debug & $debug_record;
                     94:   local($h,$l,$b,$sp,$str)=split(/,/,shift,5);
                     95:   print $str,"\n";
                     96: }
                     97:
                     98: # Joins two records
                     99:
                    100: sub join {
                    101:   local($h1,$l1,$b1,$sp1,$str1)=split(/,/,shift,5);
                    102:   local($h2,$l2,$b2,$sp2,$str2)=split(/,/,shift,5);
                    103:   $h1 || $h1++;
                    104:   $h2 || $h2++;
                    105:   local($h,$l,$b,$sp,$str,@str,@str2)=(0,0,0,$sp1+$sp2,"");
                    106:   $b = $b1 > $b2 ? $b1 : $b2;
                    107:   # Calculate space below baseline
                    108:   $h = $h1-$b1 > $h2-$b2 ? $h1-$b1 : $h2-$b2;
                    109:   # And height
                    110:   $h += $b;
                    111:   $l=$l1+$l2;
                    112:   @str="" x $h;
                    113:   @str[$b-$b1 .. $b-$b1+$h1-1]=split(/\n/,$str1,$h1);
                    114:   @str2[0..$h2-1]=split(/\n/,$str2,$h2);
                    115:   unless (length($str2[$b2])) {
                    116:     $str2[$b2] = ' ' x $l2;    # Needed for length=0 "color" strings
                    117:                                 # in the baseline.
                    118:   }
                    119:   if ($debug & $debug_record && (grep(/\n/,@str) || grep(/\n/,@str2))) {
                    120:     warn "\\n found in \@str or \@str2";
                    121:     warn "`$str1', need $h1 rows\n";
                    122:     warn "`$str2', need $h2 rows\n";
                    123:   }
                    124:   # This is may be wrong if a zero-length record with escape sequences
                    125:   # is appended to with something not on the same row...  But
                    126:   # apparently, it should be OK for PARI...
                    127:   for (0..$h2-1) {
                    128:     $str[$b-$b2+$_] .= " " x ($l1 - length ($str[$b-$b2+$_])) . $str2[$_];
                    129:   }
                    130:   return "$h,$l,$b,$sp," . join("\n",@str);
                    131: }
                    132:
                    133: # The current line is contained in the array @out of records and, possibly,
                    134: # one additional record $last. If $last exists, $islast is set to 1.
                    135: # The output channel length is contained in $linelength, the accumulated
                    136: # length of @out and $last is contained in $curlength.
                    137: # We guaranty that if $curlength>$linelength, then @out is empty.
                    138:
                    139: # Gets a length of a record
                    140:
                    141: sub length {
                    142:   (warn "Wrong format of a record `$_[0]'", return 0)
                    143:       unless $_[0] =~ /^\d+,(\d+)/;
                    144:   $1;
                    145: }
                    146:
                    147: # Gets a height of a record
                    148:
                    149: sub height {
                    150:   (warn "Wrong format of a record `$_[0]'", return 0)
                    151:       unless $_[0] =~ /^(\d+),/;
                    152:   $1;
                    153: }
                    154:
                    155: # Sets baseline of a record, Usage s...(rec,base)
                    156:
                    157: sub setbaseline {
                    158:   (warn("Wrong format of a record `$_[0]'"), return undef)
                    159:       unless $_[0] =~ s/^(\d+,\d+,)(\d+)/\1$_[1]/;
                    160: }
                    161:
                    162: # The hierarchical structure: the records to work are in the array @out.
                    163: # The array @chunks keeps the beginning record of the chunks,
                    164: # The array @level keeps the beginning chunks of the given level.
                    165: # The last chunk can begin after the last record if this chunk is still empty.
                    166:
                    167: # We do not keep the inner structure of the chunk unless it is the last
                    168: # chunk on the given level.
                    169:
                    170: # Each record is a rectangle to output to the "page".
                    171:
                    172: # Each chunk is a sequence of records which reflect one finished subgroup
                    173: # on the given level.
                    174:
                    175: # Each level is a sequence of chunks which correspond to a
                    176: # not-yet-finished group in TeX input.
                    177:
                    178:
                    179: # The parallel to @level array @wait
                    180: # contains an event we wait to complete the given level of array.
                    181:
                    182: # Chunks on a given level
                    183:
                    184: # Used to expand spaces
                    185:
                    186: sub exp_sp {$c1++;$c2=0 if $c1>$re; return " " x ($c2+$fr+1);}
                    187:
                    188: # Outputs the outermost level of the output list (until the start of level 1)
                    189: # If gets a true argument, does not expand spaces
                    190:
                    191: sub print {
                    192:   warn "Printing...\n" if $debug & $debug_flow;
                    193:   local($last,$l,$exp) = ($#level? $chunks[$level[1]]-1: $#out);
                    194:   ($last >=0) || return;
                    195:   $l=&length($out[0]);
                    196:   if ($last >= 1) {
                    197:     for (1..$last) {
                    198:       $l += &length($out[$_]);
                    199:     }
                    200:   }
                    201:   if ($debug & $debug_length)  {
                    202:     if ($l != $curlength) {
                    203:       for (0..$last) {
                    204:         warn "Wrong lengths Record $_ $out[$_]\n__ENDREC__\n" ;
                    205:       }
                    206:     }
                    207:   }
                    208:   $curlength=$l;
                    209:   warn "l=$l, linelength=$linelength, curlength=$curlength\n"
                    210:     if $debug & $debug_length;
                    211:  IF_L:
                    212:  {
                    213:   if (!shift && ($l=$linelength-$curlength)>=0) {
                    214:     warn "entered branch for long string\n"
                    215:       if $debug & $debug_length;
                    216:     $exp=0;
                    217:     (($out[$last] =~ s/\s+$//) && ($l+=length($&)))
                    218:         if $out[$last] =~ /^0,/;
                    219:     warn "l=$l with whitespace\n"
                    220:       if $debug & $debug_length;
                    221:     last IF_L if $l<=0;
                    222:     local($str,$h,$fr,$re,$c1,$c2,@t);
                    223:     for (0..$last) {
                    224:       ($str,$h)=(split(/,/,$out[$_],5))[4,0];
                    225:       (@t = ($str =~ /( )/g), $exp+=@t) if (!$h);
                    226:     }
                    227:     if ($exp) {
                    228:       $re=$l % $exp;
                    229:       $fr=int(($l-$re)/$exp);
                    230:       warn "$l Extra spaces in $exp places, Fr=$fr," .
                    231:           " Remainder=$re, LL=$linelength, CL=$curlength\n" if $debug & $debug_length;
                    232:       $c1=0;
                    233:       $c2=1;
                    234:       for (0..$last) {
                    235:         ($str,$h)=(split(/,/,$out[$_],5))[4,0];
                    236:         unless ($h || $opt_ragged) {
                    237:           $str =~ s/ /&exp_sp/ge;
                    238:           $out[$_]=&string2record($str);
                    239:         }
                    240:       }
                    241:     }
                    242:   }
                    243:   else {warn "Do not want to expand $l spaces\n" if $debug & $debug_length;}
                    244:  }
                    245:   if ($last >= 1) {
                    246:     for (1..$last) {
                    247:       $out[0] = &join($out[0],$out[$_]);
                    248:     }
                    249:   }
                    250:   $l=&length($out[0]);
                    251:   warn "LL=$linelength, CurL=$curlength, OutL=$l\n" if $debug & $debug_length;
                    252:   &printrecord($out[0]);
                    253:   $curlength=0;
                    254:   if ($#out>$last) {
                    255:     @out=@out[$last+1..$#out];
                    256:     for (0..$#chunks) {$chunks[$_] -= $last+1;}
                    257:   } else {
                    258:     @out=();
                    259:   }
                    260:   if ($#level) {
                    261:     splice(@chunks,1,$level[1]-2);
                    262:   } else {
                    263:     @chunks=(0);
                    264:   }
                    265: }
                    266:
                    267: # Cuts prepared piece and arg into printable parts (unfinished)
                    268: # Suppose that level==0
                    269:
                    270: sub prepare_cut {
                    271:   warn "Preparing to cut $_[0]\n" if $debug & $debug_flow;
                    272:   warn "B:Last chunk number $#chunks, last record $#out\n" if $debug & $debug_flow;
                    273:   (warn "\$#level non 0", return $_[0]) if ($#level!=0);
                    274:   local($lenadd)=(&length($_[0]));
                    275:   local($lenrem)=($linelength-$curlength);
                    276:   if ($lenadd+$curlength<=$linelength) {
                    277:     warn "No need to cut, extra=$lenrem\n" if $debug & $debug_flow;
                    278:     return $_[0];
                    279:   }
                    280:   # Try to find a cut in the added record before $lenrem
                    281:   local($rec)=@_;
                    282:   local($h,$str,$ind,@p)=(split(/,/,$rec,5))[0,4];
                    283:   local($good)=(0);
                    284:   if ($h<2) {
                    285:     while ($lenrem<$lenadd && ($ind=rindex($str," ",$lenrem))>-1) {
                    286:       warn "Cut found at $ind, lenrem=$lenrem\n" if $debug & $debug_flow;
                    287:       $good=1;
                    288:       # $ind=1 means we can cut 2 chars
                    289:       @p= &cut($ind+1,$rec);
                    290:       warn "After cut: @p\n" if $debug & $debug_record;
                    291:       push(@out,$p[0]);
                    292:       $curlength+=$ind+1;
                    293:       #if ($#out!=$chunks[$#chunks]) {push(@chunks,$#out);}
                    294:       &print();
                    295:       $rec=$p[1];
                    296:       ($lenadd,$str)=(split(/,/,$rec,5))[1,4];
                    297:       $lenrem=$linelength;
                    298:     }
                    299:     return $rec if $good;
                    300:   }
                    301:   # If the added record is too long, there is no sense in cutting
                    302:   # things we have already, since we will cut the added record anyway...
                    303:   local($forcedcut);
                    304:   if ($lenadd > $linelength && $lenrem) {
                    305:       @p= &cut($lenrem,$rec);
                    306:       warn "After forced cut: @p\n" if $debug & $debug_record;
                    307:       push(@out,$p[0]);
                    308:       $curlength+=$lenrem;
                    309:       &print();
                    310:       $rec=$p[1];
                    311:       ($lenadd,$str)=(split(/,/,$rec,5))[1,4];
                    312:       $lenrem=$linelength;
                    313:   }
                    314:   # Now try to find a cut before the added record
                    315:   if ($#out>=0 && !$forcedcut) {
                    316:     for (0..$#out) {
                    317:       ($h,$str)=(split(/,/,$out[$#out-$_],5))[0,4];
                    318:       if ($h<2 && ($ind=rindex($str," "))>-1 && ($ind>0 || $_<$#out)) {
                    319:         warn "Cut found at $ind, in chunk $#out-$_\n"
                    320:             if $debug & $debug_flow;
                    321:         # split at given position
                    322:         @p=&cut($ind+1,$out[$#out-$_]);
                    323:         $out[$#out-$_]=$p[0];
                    324:         @p=($p[1],@out[$#out-$_+1..$#out]);
                    325:         @out=@out[0..$#out-$_];
                    326: warn "\@p is !", join('!', @p), "!\n\@out is !", join('!', @out), "!\n"
                    327:             if $debug & $debug_flow;
                    328:         &print();
                    329:        warn "did reach that\n"
                    330:          if $debug & $debug_length;
                    331:         @out=@p;
                    332:         $good=1;
                    333:         $curlength=0;
                    334:         for (@out) {$curlength+=&length($_);}
                    335:         last;
                    336:       }
                    337:       warn "did reach wow-this\n"
                    338:        if $debug & $debug_length;
                    339:     }
                    340:     warn "did reach this\n"
                    341:       if $debug & $debug_length;
                    342:   }
                    343:   return &prepare_cut if $good;
                    344:   warn "No cut found!\n" if $debug & $debug_flow;
                    345:   # If anything else fails use force
                    346:   &print();
                    347:   while (&length($rec)>$linelength) {
                    348:     @p=&cut($linelength,$rec);
                    349:     @out=($p[0]);
                    350:     &print();
                    351:     $rec=$p[1];
                    352:   }
                    353:   $curlength=0;
                    354:   return $rec;
                    355: }
                    356:
                    357: # Adds a record to the output list
                    358:
                    359: sub commit {
                    360:   warn "Adding $_[0]\n" if $debug & $debug_flow;
                    361:   warn "B:Last chunk number $#chunks, last record $#out\n" if $debug & $debug_flow;
                    362:   local($rec)=@_;
                    363:   if ($#level==0) {
                    364:     local($len)=&length($_[0]);
                    365:     if ($curlength+$len>$linelength) {
                    366:       $rec=&prepare_cut;
                    367:       $len=&length($rec);
                    368:     }
                    369:     $curlength+=$len;
                    370:   }
                    371:   push(@out,$rec);
                    372:   if ($#out!=$chunks[$#chunks]) {push(@chunks,$#out);}
                    373:   warn "a:Last chunk number $#chunks, last record $#out, the first chunk\n" if $debug & $debug_flow;
                    374:   warn " on the last level=$#level is $level[$#level], waiting for $wait[$#level]\n" if $debug & $debug_flow;
                    375:   if ($#level && $wait[$#level] == $#chunks-$level[$#level]+1) {
                    376:     local($sub,$arg)=($action[$#level]);
                    377:     if ($sub eq "") {&finish($wait[$#level]);}
                    378:     else {
                    379:       &callsub($sub);
                    380:     }
                    381:   }
                    382:   warn "curlength=$curlength on level=$#level\n" if $debug & $debug_length;
                    383: }
                    384:
                    385: # Calls a subroutine, possibly with arguments
                    386:
                    387: sub callsub {
                    388:   local($sub)=(shift);
                    389:   index($sub,";")>=0?
                    390:     (($sub,$arg)=split(";",$sub,2), &$sub($arg)):
                    391:       &$sub;
                    392: }
                    393:
                    394: # Simulates Removing a record from the output list (unfinished)
                    395:
                    396: sub uncommit {
                    397:   warn "Deleting...\n" if $debug & $debug_flow;
                    398:   warn "B:Last chunk number $#chunks, last record $#out\n" if $debug & $debug_flow;
                    399:   (warn "Nothing to uncommit", return) if $#out<0;
                    400:   if ($#level==0) {
                    401:     local($len)=&length($out[$#out]);
                    402:     $curlength-=$len;
                    403:   }
                    404:   local($rec);
                    405:   $rec=$out[$#out];
                    406:   $out[$#out]=&empty();
                    407:   warn "UnCommit: now $chunks[$#chunks] $rec\n__ENDREC__\n"
                    408:       if $debug & $debug_record;
                    409:   #if ($#out<$chunks[$#chunks]) {pop(@chunks);}
                    410:   warn "a:Last chunk number $#chunks, last record $#out, the first chunk\n" if $debug & $debug_flow;
                    411:   warn " on the last level=$#level is $level[$#level], waiting for $wait[$#level]" if $debug & $debug_flow;
                    412:   warn "curlength=$curlength on level=$#level\n" if $debug & $debug_length;
                    413:   return $rec;
                    414: }
                    415:
                    416: # finish($event, $force_one_group)
                    417:
                    418: # Finish the inner scope with the event $event. If this scope is empty,
                    419: # add an empty record.  If finishing the group would bring us to toplevel
                    420: # and $force_one_group is not set, can break things into chunks to improve
                    421: # line-breaking.
                    422:
                    423: # No additional action is executed
                    424:
                    425: sub finish {
                    426:   warn "Finishing with $_[0]\n" if $debug & $debug_flow;
                    427:   local($event,$len,$rec)=(shift);
                    428:   if (($wait[$#level] ne "") && ($wait[$#level] ne $event)) {
                    429:     warn "Got `$event' while waiting for `$wait[$#wait]', rest=$par";
                    430:   }
                    431:   warn "Got finishing event `$event' in the outermost block, rest=$par"
                    432:       unless $#level;
                    433:   if ($#out<$chunks[$level[$#level]]) {push(@out,&empty);}
                    434:   # Make anything after $level[$#level] one chunk if there is anything
                    435:   warn "B:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow;
                    436:   $#chunks=$level[$#level]; #if $chunks[$level[$#level]]<=$#out;
                    437:   local(@t);
                    438:   if ($#level==1 && !$_[0]) {
                    439:     @t=@out[$chunks[$#chunks]..$#out];
                    440:     $#out=$chunks[$#chunks]-1;
                    441:   }
                    442:   #  $#chunks-- if $chunks[$#chunks-1]==$chunks[$#chunks];
                    443:   $#level--;
                    444:   $#action--;
                    445:   $#tokenByToken--;
                    446:   $#wait--;
                    447:   if ($#level==0 && !$_[0]) {
                    448:     for (@t) {&commit($_);}
                    449:   }
                    450:   warn
                    451:       "a:Last $#chunks, the first on the last level=$#level is $level[$#level]"
                    452:            if $debug & $debug_flow;
                    453:   if ($wait[$#level] == $#chunks-$level[$#level]+1) {
                    454:     local($sub)=($action[$#level]);
                    455:     if ($sub eq "") {&finish($wait[$#level]);}
                    456:     else {&callsub($sub);}
                    457:   }
                    458: }
                    459:
                    460: # finish level and discard it
                    461:
                    462: sub finish_ignore {
                    463:         warn "Finish_ignoring with $_[0]\n" if $debug & $debug_flow;
                    464:         local($event,$len)=(shift);
                    465:         if (($wait[$#level] ne "") && ($wait[$#level] ne $event)) {
                    466:                 warn "Got `$event' while waiting for `$wait[$#wait]', rest=$par";
                    467:         }
                    468:         warn "Got finishing event `$event' in the outermost block, rest=$par" unless $#level;
                    469:   $#out=$chunks[$level[$#level]]-1;
                    470:   pop(@level);
                    471:   pop(@tokenByToken);
                    472:   pop(@action);
                    473:   pop(@wait);
                    474: }
                    475:
                    476: # Begin a new level with waiting for $event
                    477:
                    478: # Special events: If number, wait this number of chunks
                    479:
                    480: sub start {
                    481:   warn "Beginning with $_[0], $_[1]\n" if $debug & $debug_flow;
                    482:   warn "B:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow;
                    483:   if ($chunks[$level[$#level]]<=$#out && $chunks[$#chunks]<=$#out) {
                    484:     # the last level is non empty
                    485:     push(@chunks,$#out+1);
                    486:   }
                    487:   push(@level,$#chunks);
                    488:   push(@tokenByToken,0);
                    489:   $wait[$#level]=shift;
                    490:   if ($#_<0) {$action[$#level]="";} else {$action[$#level]=shift;}
                    491:   warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow;
                    492: }
                    493:
                    494: # Asserts that the given number of chunks exists in the last level
                    495:
                    496: sub assertHave {
                    497:   local($i,$ii)=(shift);
                    498:   if (($ii=$#chunks-$level[$#level]+1)<$i) {
                    499:     warn "Too few chunks ($ii) in inner level, expecting $i";
                    500:     return 0;
                    501:   }
                    502:   return 1;
                    503: }
                    504:
                    505: # Takes the last ARGUMENT chunks, collapse them to records
                    506:
                    507: sub collapse {
                    508:   warn "Collapsing $_[0]...\n" if $debug & $debug_flow;
                    509:   local($i,$ii,$_)=(shift);
                    510:   if (($ii=$#chunks-$level[$#level]+1)<$i) {
                    511:     warn "Too few chunks ($ii) in inner level, expecting $i";
                    512:     $i=$ii;
                    513:   }
                    514:   if ($i>0) {
                    515:     for (0..$i-1) {
                    516:       &collapseOne($#chunks-$_);
                    517:     }
                    518:     for (1..$i-1) {
                    519:       $chunks[$#chunks-$_+1]=$chunks[$#chunks-$i+1]+$i-$_;
                    520:     }
                    521:   }
                    522: }
                    523:
                    524: # Collapses all the chunks on given level
                    525:
                    526: sub collapseAll {&collapse($#chunks-$level[$#level]+1);}
                    527:
                    528: # Collapses a given chunk in the array @out. No correction of @chunks is
                    529: # performed
                    530:
                    531: sub collapseOne {
                    532:   local($n)=(shift);
                    533:   local($out,$last,$_)=($out[$chunks[$n]]);
                    534:   if ($n==$#chunks) {$last=$#out;} else {$last=$chunks[$n+1]-1;}
                    535:         warn "Collapsing_one $n, records $chunks[$n]..$last\n"
                    536:                 if $debug & $debug_flow;
                    537:   return unless $last>$chunks[$n];
                    538:   warn "Collapsing chunk $n beginning at $chunks[$n], ending at $last\n" if $debug & $debug_flow;
                    539:   for ($chunks[$n]+1..$last) {
                    540:     $out=&join($out,$out[$_]);
                    541:   }
                    542:   splice(@out,$chunks[$n],$last+1-$chunks[$n],$out);
                    543:   # $#out-=$last-$chunks[$n]; #bug in perl?
                    544:   warn "Collapsed $chunks[$n]: $out[$chunks[$n]]\n__END__\n" if $debug & $debug_record;
                    545: }
                    546:
                    547: # Return an empty record
                    548:
                    549: sub empty {
                    550:   return "0,0,0,0,";
                    551: }
                    552:
                    553: # Commits a record with a sum symbol
                    554:
                    555: sub sum {
                    556:   &commit("4,3,2,0," . <<'EOF');
                    557: ___
                    558: \
                    559:  >
                    560: /__
                    561: EOF
                    562: }
                    563:
                    564: # Additional argument specifies if to make not-expandable, not-trimmable
                    565:
                    566: sub string2record {
                    567:   local($h,$sp)=(0);
                    568:   if ($_[1]) {$h=1;$sp=0;}
                    569:   else {
                    570:     $sp=($_[0] =~ /(\s)/g);
                    571:     $sp || ($sp=0); # Sometimes it is undef?
                    572:   }
                    573:   return "$h," . length($_[0]) . ",0,$sp,$_[0]";
                    574: }
                    575:
                    576: # The second argument forces the block length no matter what is the
                    577: # length the string (for strings with screen escapes).
                    578:
                    579: sub record_forcelength {
                    580:   $_[0] =~ s/^(\d+),(\d+)/$1,$_[1]/;
                    581: }
                    582:
                    583: sub finishBuffer {
                    584:   while ($#level>0) {&finish("");}
                    585:   &print(1);
                    586: }
                    587:
                    588: # Takes two records, returns a record that concatenates them vertically
                    589: # To make fraction simpler, baseline is the last line of the first record
                    590:
                    591: sub vStack {
                    592:   local($h1,$l1,$b1,$sp1,$str1)=split(/,/,shift,5);
                    593:   local($h2,$l2,$b2,$sp2,$str2)=split(/,/,shift,5);
                    594:   $h1 || $h1++;
                    595:   $h2 || $h2++;
                    596:   local($h,$l,$b)=($h1+$h2, ($l1>$l2 ? $l1: $l2), $h1-1);
                    597:   warn "\$h1=$h1, \$h2=$h2, Vstacked: $h,$l,$b,0,$str1\n$str2\n__END__\n" if $debug & $debug_record;
                    598:   return "$h,$l,$b,0,$str1\n$str2";
                    599: }
                    600:
                    601: # Takes two records, returns a record that contains them and forms
                    602: # SupSub block
                    603:
                    604: sub superSub {
                    605:   local($h1,$l1,$b1,$sp1,$str1)=split(/,/,shift,5);
                    606:   local($h2,$l2,$b2,$sp2,$str2)=split(/,/,shift,5);
                    607:   $h1 || $h1++;
                    608:   $h2 || $h2++;
                    609:   local($h,$l)=($h1+$h2+1, ($l1>$l2 ? $l1: $l2));
                    610:   return "$h,$l,$h1,0,$str1\n\n$str2";
                    611: }
                    612:
                    613: # Takes two records, returns a record that contains them and forms
                    614: # SupSub block
                    615:
                    616: sub subSuper {
                    617:   local($h1,$l1,$b1,$sp1,$str1)=split(/,/,shift,5);
                    618:   local($h2,$l2,$b2,$sp2,$str2)=split(/,/,shift,5);
                    619:   $h1 || $h1++;
                    620:   $h2 || $h2++;
                    621:   local($h,$l)=($h1+$h2+1, ($l1>$l2 ? $l1: $l2));
                    622:   return "$h,$l,$h1,0,$str2\n\n$str1";
                    623: }
                    624:
                    625: # Takes the last two records, returns a record that contains them and forms
                    626: # SupSub block
                    627:
                    628: sub f_subSuper {
                    629:   warn "Entering f_subSuper...\n" if $debug & $debug_flow;
                    630:   &trim(2);
                    631:   &collapse(2);
                    632:   &assertHave(2) || &finish("",1);
                    633:   &sup_sub(0,1);
                    634: }
                    635:
                    636: sub sup_sub {
                    637:   local($p1,$p2)=($#out-shift,$#out-shift);
                    638:   warn "Super $p1 $out[$p1]\nSub $p2 $out[$p2]\n__END__\n" if $debug & $debug_record;
                    639:   local($h1,$l1,$b1,$sp1,$str1)=split(/,/,$out[$p1],5);
                    640:   local($h2,$l2,$b2,$sp2,$str2)=split(/,/,$out[$p2],5);
                    641:   if ($l1==0 && $l2==0) {return;}
                    642:   $h1 || $h1++;
                    643:   $h2 || $h2++;
                    644:   local($h,$l)=($h1+$h2+1, ($l1>$l2 ? $l1: $l2));
                    645:   $#chunks--;
                    646:   $#out--;
                    647:   if ($l1==0) {
                    648:     $h2++;
                    649:     $out[$#out]="$h2,$l,0,0,\n$str2";
                    650:   } elsif ($l2==0) {
                    651:     $h=$h1+1;
                    652:     $out[$#out]="$h,$l,$h1,0,$str1\n";
                    653:   } else {
                    654:     $out[$#out]="$h,$l,$h1,0,$str1\n\n$str2";
                    655:   }
                    656:   warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow;
                    657:   &finish(2,1);
                    658: }
                    659:
                    660: # Takes the last two records, returns a record that contains them and forms
                    661: # SupSub block
                    662:
                    663: sub f_superSub {
                    664:   warn "Entering f_superSub...\n" if $debug & $debug_flow;
                    665:   &trim(2);
                    666:   &collapse(2);
                    667:   &assertHave(2) || &finish("",1);
                    668:   &sup_sub(1,0);
                    669: }
                    670:
                    671: # digest \begin{...} and similar: handles argument to a subroutine
                    672: # given as argument
                    673:
                    674: sub f_get1 {
                    675:   warn "Entering f_get1...\n" if $debug & $debug_flow;
                    676:   (warn "Argument of f_get1 consists of 2 or more chunks", return)
                    677:       if $#out != $chunks[$#chunks];
                    678:   local($rec,$sub);
                    679:   #$rec=&uncommit;
                    680:   $rec=$out[$#out];
                    681:   $rec=~s/.*,//;
                    682:   $sub=shift;
                    683:   defined $sub ? return &$sub($rec): return $rec;
                    684: }
                    685:
                    686: sub f_begin {
                    687:   warn "Entering f_begin...\n" if $debug & $debug_flow;
                    688:   &collapse(1);
                    689:   &assertHave(1) || &finish("");
                    690:   local($arg,$env)=(&f_get1());
                    691:   &finish_ignore(1);
                    692:   $arg=~s/^\s+//;
                    693:   $arg=~s/\s+$//;
                    694:   return if defined $environment_none{$arg};
                    695:   if (defined ($env=$environment{$arg})) {
                    696:     local($b,$e)=split(/,/,$env);
                    697:     for (split(":",$b)) {&callsub($_);}
                    698:   } else {&puts("\\begin{$arg}");}
                    699: }
                    700:
                    701: sub f_end {
                    702:   warn "Entering f_end...\n" if $debug & $debug_flow;
                    703:   &collapse(1);
                    704:   &assertHave(1) || &finish("");
                    705:   local($arg,$env)=(&f_get1());
                    706:   &finish_ignore(1);
                    707:   $arg=~s/^\s+//;
                    708:   $arg=~s/\s+$//;
                    709:   return if defined $environment_none{$arg};
                    710:   if (defined ($env=$environment{$arg})) {
                    711:     local($b,$e)=split(/,/,$env,2);
                    712:     for (split(":",$e)) {&callsub($_);}
                    713:   } else {&puts("\\end{$arg}");}
                    714: }
                    715:
                    716:
                    717: sub f_literal_no_length {
                    718:   warn "Entering f_literal_with_length...\n" if $debug & $debug_flow;
                    719:   # &trim(1);
                    720:   &collapse(1);
                    721:   &assertHave(1) || &finish("",1);
                    722:   record_forcelength($out[$#out], 0);
                    723:   &finish(1,1);
                    724: }
                    725:
                    726: sub f_discard {
                    727:   warn "Entering f_discard...\n" if $debug & $debug_flow;
                    728:   &finish_ignore($wait[$#level]);
                    729: }
                    730:
                    731: # Takes a number and a record, returns a centered record
                    732:
                    733: sub center {
                    734:   local($len,$left)=(shift,0);
                    735:         warn "Entering center, ll=$len, rec=$_[0]\n__ENDREC__\n" if $debug & $debug_flow;
                    736:   #$_[0]; # bug in perl?
                    737:   local($h1,$l1,$b1,$sp1,$str1)=split(/,/,$_[0],5);
                    738:   $h1 || $h1++;
                    739:   if (($left=$len-$l1)<=0) {return $_[0];}
1.2     ! noro      740:   local($LHS,$RHS);
        !           741:   $LHS = int($left/2); $RHS = $left - $LHS;
1.1       noro      742:   local($out,$first)=("",1);
                    743:   for (split(/\n/,$str1,$h1)) {
                    744:     if ($first) {$first=0;}
                    745:     else {$out .= "\n";}
1.2     ! noro      746:     $out .= " " x $LHS. $_ . " " x $RHS;
1.1       noro      747:   }
                    748:   return "$h1,$len,$b1,0,$out";
                    749: }
                    750:
                    751: # Example of radical
                    752: #<<'EOF';
                    753: # +--+
                    754: #\|12
                    755: #EOF
                    756: <<EOF;                         # To hide HERE-DOC start above  from old CPerl
                    757: EOF
                    758:
                    759: # Takes the last record, returns a record that contains it and forms
                    760: # radical block
                    761:
                    762: sub f_radical {
                    763:   warn "Entering f_radical...\n" if $debug & $debug_flow;
                    764:   &trim(1);
                    765:   &collapse(1);
                    766:   &assertHave(1) || &finish("",1);
                    767:   warn "Radical of $out[$#out]\n__END__\n" if $debug & $debug_record;
                    768:   local($h,$l,$b)=($out[$#out] =~ /^(\d+),(\d+),(\d+)/g);
                    769:   $h || $h++;
                    770:   local($out,$b1,$h1);
                    771:   $out=&vStack(&string2record(("-" x $l)."+" ),$out[$#out]);
                    772:   $b1=$b+1;
                    773:   $h1=$h+1;
                    774:   #$out =~ s/^(\d+,\d+,)(\d+)/\1$b1/;
                    775:   &setbaseline($out,$b1);
                    776:   $out[$#out]=&join("$h1,2,$b1,0, +\n" . (" |\n" x ($h-1)) . '\|',$out);
                    777:   warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow;
                    778:   &finish(1,1);
                    779: }
                    780:
                    781: # Takes the last two records, returns a record that contains them and forms
                    782: # fraction block
                    783:
                    784: sub f_fraction {
                    785:   warn "Entering f_fraction...\n" if $debug & $debug_flow;
                    786:   &trim(2);
                    787:   &collapse(2);
                    788:   &assertHave(2) || &finish("",1);
                    789:   warn "Numer `$out[$#out-1]'\nDenom `$out[$#out]'\n__END__\n" if $debug & $debug_record;
                    790:   local($l1,$l2)=(&length($out[$#out-1]),&length($out[$#out]));
                    791:   local($len)=(($l1>$l2 ? $l1: $l2));
                    792:   $out[$#out-1]=&vStack(&vStack(&center($len,$out[$#out-1]),
                    793:                          &string2record("-" x $len)),
                    794:                  &center($len,$out[$#out]));
                    795:   $#chunks--;
                    796:   $#out--;
                    797:   warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow;
                    798:   &finish(2,1);
                    799: }
                    800:
                    801: sub f_choose {
                    802:   warn "Entering f_choose...\n" if $debug & $debug_flow;
                    803:   &trim(2);
                    804:   &collapse(2);
                    805:   &assertHave(2) || &finish("",1);
                    806:   warn "Numer `$out[$#out-1]'\nDenom `$out[$#out]'\n__END__\n" if $debug & $debug_record;
                    807:   local($l1,$l2)=(&length($out[$#out-1]),&length($out[$#out]));
                    808:   local($len)=(($l1>$l2 ? $l1: $l2));
                    809:   $out[$#out]=&vStack(&vStack(&center($len,$out[$#out-1]),
                    810:                          &string2record(" " x $len)),
                    811:                  &center($len,$out[$#out]));
                    812:   $#chunks++;
                    813:   $#out++;
                    814:   #warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow;
                    815:   $out[$#out - 2] = &string2record("(");
                    816:   $out[$#out] = &string2record(")");
                    817:   local($h,$b)=($out[$#out-1] =~ /^(\d+),\d+,(\d+)/)[0,1];
                    818:   &makehigh($out[$#out-2],$h,$b,0,1);
                    819:   &makehigh($out[$#out],$h,$b,1,0);
                    820:   &finish(2,1);
                    821: }
                    822:
                    823:
                    824: sub f_buildrel {
                    825:         warn "Entering f_buildrel...\n" if $debug & $debug_flow;
                    826:   &trim(3);
                    827:         &collapse(3);
                    828:         &assertHave(3) || &finish("",1);
                    829:         warn "What: $out[$#out-2]\nOver $out[$#out]\n__END__\n" if $debug & $debug_record;
                    830:         local($rec)=($out[$#out-2]);
                    831:         $out[$#out-2]=$out[$#out];
                    832:         $#chunks-=2;
                    833:         $#out-=2;
                    834:   &f_putover($rec,1);
                    835:         warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow;
                    836:         &finish(3,1);
                    837: }
                    838:
                    839: # Takes two records, returns a record that contains them and forms a
                    840: # fraction block
                    841:
                    842: sub fraction {
                    843:   local($l1,$l2)=(&length($_[0]),&length($_[1]));
                    844:   local($len)=(($l1>$l2 ? $l1: $l2));
                    845:   return &vStack(&vStack(&center($len,shift),
                    846:                          &string2record("-" x $len)),
                    847:                  &center($len,shift));
                    848: }
                    849:
                    850: # Commits a given string
                    851:
                    852: sub puts {
                    853:   &commit(&string2record);
                    854: }
                    855:
                    856: # digests an eaten paragraph
                    857:
                    858: sub paragraph {
                    859:   local($par);
                    860:   $par=<>;
                    861:   return 0 unless defined $par;
                    862:   return 1 unless $par =~ /\S/;                        # whitespace only
                    863:   print "\n" if $secondtime++ && !$opt_by_par;
                    864:   #$par =~ s/(^|[^\\])%.*\n[ \t]*/\1/g;
                    865:   $par =~ s/((^|[^\\])(\\\\)*)(%.*\n[ \t]*)+/\1/g;
                    866:   $par =~ s/\n\s*\n/\\par /g;
                    867:   $par =~ s/\s+/ /g;
                    868:   $par =~ s/\s+$//;
                    869:   $par =~ s/(\$\$)\s+/\1/g;
                    870:   $par =~ s/\\par\s*$//;
                    871:   local($defcount,$piece,$pure,$type,$sub,@t,$arg)=(0);
                    872:   &commit("1,5,0,0,     ")
                    873:     unless $opt_noindent || ($par =~ s/^\s*\\noindent\s*([^a-zA-Z\s]|$)/\1/);
                    874:   while ($tokenByToken[$#level] ?
                    875:       ($par =~ s/^\s*($tokenpattern)//o): ($par =~ s/^($multitokenpattern)//o)) {
                    876:     warn "tokenByToken=$tokenByToken[$#level], eaten=`$1'\n"
                    877:         if $debug & $debug_parsing;
                    878:     if (($piece=$1) =~ /^$usualtokenclass/o) {
                    879:       # plain piece
                    880:       &puts($piece);
                    881:     } else {
                    882:       # macro or delimiter
                    883:       ($pure = $piece) =~ s/\s+$//;
                    884:       if (defined ($type=$type{$pure})) {
                    885:         if ($type eq "def") {
                    886:     warn "To many def expansions in a paragraph" if $defcount++==$maxdef;
                    887:     last if $defcount>$maxdef;
                    888:     @t=(0);
                    889:     for (1..$args{$pure}) {
                    890:       push(@t,&get_balanced());
                    891:     }
                    892:     warn "Defined token `$pure' found with $args{$pure} arguments @t[1..$#t]\n"
                    893:     if $debug & $debug_parsing;
                    894:     $sub=$def{$pure};
                    895:     $sub =~ s/(^|[^\\#])#(\d)/$1 . $t[$2]/ge if $args{$pure};
                    896:     $par=$sub . $par;
                    897:         } elsif ($type eq "sub") {
                    898:          $sub=$contents{$pure};
                    899:          index($sub,";")>=0?
                    900:            (($sub,$arg)=split(";",$sub,2), &$sub($pure,$arg)):
                    901:              &$sub($pure);
                    902:         } elsif ($type =~ /^sub(\d+)$/) {
                    903:           &start($1,"f_$contents{$pure}");
                    904:           $tokenByToken[$#level]=1;
                    905:         } elsif ($type =~ /^get(\d+)$/) {
                    906:           &start($1+1);
                    907:           &puts($piece);
                    908:           $tokenByToken[$#level]=1;
                    909:         } elsif ($type =~ /^discard(\d+)$/) {
                    910:           &start($1,"f_discard");
                    911:           $tokenByToken[$#level]=1;
                    912:         } elsif ($type eq "record") {
                    913:           &commit($contents{$pure});
                    914:         } elsif ($type eq "self") {
                    915:           &puts(substr($pure,1) . ($pure =~ /^\\[a-zA-Z]/ ? " ": ""));
                    916:         } elsif ($type eq "par_self") {
                    917:          &finishBuffer;
                    918:          &commit("1,5,0,0,     ");
                    919:           &puts($pure . ($pure =~ /^\\[a-zA-Z]/ ? " ": ""));
                    920:         } elsif ($type eq "self_par") {
                    921:           &puts($pure . ($pure =~ /^\\[a-zA-Z]/ ? " ": ""));
                    922:          &finishBuffer;
                    923:          &commit("1,5,0,0,     ")
                    924:            unless $par =~ s/^\s*\\noindent(\s+|([^a-zA-Z\s])|$)/\2/;
                    925:         } elsif ($type eq "string") {
                    926:           &puts($contents{$pure},1);
                    927:         } elsif ($type eq "nothing") {
                    928:         } else {
                    929:           warn "Error with type `$type' while interpreting `$pure'";
                    930:         }
                    931:       } else {
                    932:         &puts($piece);
                    933:       }
                    934:     }
                    935:   }
                    936:   warn "Unrecognized part of input `$par',\n\ttoken-by-token[$#level]=$tokenByToken[$#level]"
                    937:     if $par ne "";
                    938:   &finishBuffer if $#out>=0;
                    939: # return 0 if eof();
                    940:   1;
                    941: }
                    942:
                    943: sub subscript {
                    944:   &start(1,"f_subscript");
                    945:   $tokenByToken[$#level]=1;
                    946: }
                    947:
                    948: sub superscript {
                    949:   &start(1,"f_superscript");
                    950:   $tokenByToken[$#level]=1;
                    951: }
                    952:
                    953:
                    954: sub f_subscript {
                    955:   $wait[$#level]=2;
                    956:   $action[$#level]="f_subSuper";
                    957:   if (($par !~ s/^\s*\^//) &&
                    958:       ($par !~ s:^\s*\\begin\s*\{Sp\}:\\begin\{matrix\}:)) {
                    959:     &commit(&empty);
                    960:   }
                    961: }
                    962:
                    963: sub f_overline {
                    964:   warn "Entering f_overline...\n" if $debug & $debug_flow;
                    965:   &trim(1);
                    966:   &collapse(1);
                    967:   &assertHave(1) || &finish("",1);
                    968:   warn "Overlining $out[$#out]\n__END__\n" if $debug & $debug_record;
                    969:   local($h,$len,$b)=($out[$#out] =~ /^(\d+),(\d+),(\d+)/);
                    970:   $out[$#out]=&vStack(&string2record("_" x $len),
                    971:                       $out[$#out]);
                    972:   $b++;
                    973:   #$out[$#out] =~ s/^(\d+,\d+,)(\d+)/\1$b/;
                    974:   &setbaseline($out[$#out],$b);
                    975:   warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow;
                    976:   &finish(1,1);
                    977: }
                    978:
                    979: sub f_underline {
                    980:   warn "Entering f_underline...\n" if $debug & $debug_flow;
                    981:   &trim(1);
                    982:   &collapse(1);
                    983:   &assertHave(1) || &finish("",1);
                    984:   warn "Underlining $out[$#out]\n__END__\n" if $debug & $debug_record;
                    985:   local($h,$len,$b)=($out[$#out] =~ /^(\d+),(\d+),(\d+)/);
                    986:   $out[$#out]=&vStack($out[$#out],&string2record("_" x $len));
                    987:   #$out[$#out] =~ s/^(\d+,\d+,)(\d+)/\1$b/;
                    988:   &setbaseline($out[$#out],$b);
                    989:   warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow;
                    990:   &finish(1,1);
                    991: }
                    992:
                    993: sub f_not {
                    994:   warn "Entering f_not...\n" if $debug & $debug_flow;
                    995:   &collapse(1);
                    996:   &assertHave(1) || &finish("",1);
                    997:   warn "Negating $out[$#out]\n__END__\n" if $debug & $debug_record;
                    998:   local($str)=(split(/,/,$out[$#out]))[4];
                    999:   if ($str eq "=") {
                   1000:     $out[$#out]=$contents{"\\neq"};
                   1001:   } elsif ($str =~ /^\s*\|\s*$/) {
                   1002:     $out[$#out]=$contents{"\\nmid"};
                   1003:   } elsif ($out[$#out] eq $contents{"\\in"}) {
                   1004:     $out[$#out]=$contents{"\\notin"};
                   1005:   } else {
                   1006:     $out[$#out]=&join(&string2record("\\not"),$out[$#out]);
                   1007:   }
                   1008:   warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow;
                   1009:   &finish(1,1);
                   1010: }
                   1011:
                   1012: sub f_putunder {
                   1013:   warn "Entering f_putunder...\n" if $debug & $debug_flow;
                   1014:   &trim(1);
                   1015:   &collapse(1);
                   1016:   &assertHave(1) || &finish("",1);
                   1017:   warn "Putting Under $out[$#out]\n__END__\n" if $debug & $debug_record;
                   1018:   local($h,$len,$b)=($out[$#out] =~ /^(\d+),(\d+),(\d+)/);
                   1019:         local($l2)=(&length($_[0]));
                   1020:         local($len)=(($l1>$l2 ? $l1: $l2));
                   1021:   $out[$#out]=&vStack(&center($len,$out[$#out]),&center($len,shift));
                   1022:   #$out[$#out] =~ s/^(\d+,\d+,)(\d+)/\1$b/;
                   1023:   &setbaseline($out[$#out],$b);
                   1024:   warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow;
                   1025:   &finish(1,1);
                   1026: }
                   1027:
                   1028: # if has additional true argument will not finish
                   1029: # Takes record to put over
                   1030:
                   1031: sub f_putover {
                   1032:   warn "Entering f_putover...\n" if $debug & $debug_flow;
                   1033:   &trim(1);
                   1034:   &collapse(1);
                   1035:   &assertHave(1) || &finish("",1);
                   1036:   warn "Putting Over $out[$#out]\n__END__\n" if $debug & $debug_record;
                   1037:   local($h,$l1,$b,$b1)=($out[$#out] =~ /^(\d+),(\d+),(\d+)/);
                   1038:         local($l2)=(&length($_[0]));
                   1039:         local($len)=(($l1>$l2 ? $l1: $l2));
                   1040:   ($b1)=($_[0] =~ /^(\d+)/);
                   1041:   $b+=$b1+1;
                   1042:   $out[$#out]=&vStack(&center($len,shift),&center($len,$out[$#out]));
                   1043:   #$out[$#out] =~ s/^(\d+,\d+,)(\d+)/\1$b/;
                   1044:   &setbaseline($out[$#out],$b);
                   1045:   warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow;
                   1046:   &finish(1,1) unless shift;
                   1047: }
                   1048:
                   1049: sub f_putpar {
                   1050:         warn "Entering f_putpar...\n" if $debug & $debug_flow;
                   1051:   &trim(1);
                   1052:   local($l,$r)=split(";",shift);
                   1053:         &collapse(1);
                   1054:         &assertHave(1) || &finish("",1);
                   1055:         warn "Putting Parentheses $out[$#out]\n__END__\n" if $debug & $debug_record;
                   1056:   $out[$#out]=&join(&string2record($l),
                   1057:       &join($out[$#out],&string2record($r)));
                   1058:         &finish(1,1);
                   1059: }
                   1060:
                   1061: sub f_putover_string {
                   1062:   &f_putover(&string2record);
                   1063: }
                   1064:
                   1065: sub f_widehat {
                   1066:         &trim(1);
                   1067:   &collapse(1);
                   1068:         local($l)=(&length($out[$#out]));
                   1069:         if ($l<=1) {&f_putover(&string2record("^"));}
                   1070:         else {&f_putover(&string2record("/" . "~" x ($l-2) . "\\"));}
                   1071: }
                   1072:
                   1073: sub f_widetilde {
                   1074:         &trim(1);
                   1075:   &collapse(1);
                   1076:   local($l,$l1)=(&length($out[$#out]));
                   1077:   if ($l<=1) {&f_putover(&string2record("~"));}
                   1078:         elsif ($l<=3) {&f_putover(&string2record("/\\/"));}
                   1079:         else {&f_putover(&string2record("/" . "~" x ($l1=int($l/2-1)) .
                   1080:      "\\" . "_" x ($l-3-$l1) . "/"));}
                   1081: }
                   1082:
                   1083: sub f_superscript {
                   1084:   $wait[$#level]=2;
                   1085:   $action[$#level]="f_superSub";
                   1086:   if (($par !~ s/^\s*\_//) &&
                   1087:       ($par !~ s:^\s*\\begin\s*\{Sb\}:\\begin\{matrix\}:)) {
                   1088:     &commit(&empty);
                   1089:   }
                   1090: }
                   1091:
                   1092: sub let {
                   1093:         $par =~ s/^($tokenpattern)(= ?)?($tokenpattern)//o;
                   1094: }
                   1095:
                   1096: sub let_exp {
                   1097:         $par =~ s/^($tokenpattern)(= ?)?($tokenpattern)//o;
                   1098:   return if index($&,'@')>=0;
                   1099:   local($what)=$1;
                   1100:   $type{$what}='def';
                   1101:   $& =~ /($tokenpattern)$/;
                   1102:   $def{$what}=$1;
                   1103:   $args{$what}=0;
                   1104:         warn "Definition of `$what' with $args{$what} args is `$def{$what}'\n"
                   1105:                         if $debug & $debug_parsing;
                   1106: }
                   1107:
                   1108:
                   1109: sub def {
                   1110:   $par =~ s/^[^{]*//;
                   1111:   &start(1,"f_discard");
                   1112:   $tokenByToken[$#level]=1;
                   1113: }
                   1114:
                   1115: sub def_exp {
                   1116:   return unless $par =~ s:^(([^\\{]|\\.)*)\{:\{:;
                   1117:   local($arg)=($1);
                   1118:   local($def,$act)=(&get_balanced());
                   1119:   return unless defined $def;
                   1120:   return if index("$arg$def",'@')>=0;
                   1121:   return if $def =~ /\\([egx]?def|fi)([^a-zA-Z]|$)/;
                   1122:   $def .= " "  if $def =~ /($macro)$/o;
                   1123:   &define($arg,$def);
                   1124: }
                   1125:
                   1126: # Arguments: Token . Parameters, Expansion
                   1127:
                   1128: sub define {
                   1129:   local($arg,$def,$act)=(shift,shift);
                   1130:   return unless $arg =~ /^($active)/o;
                   1131:   $act=$1;
                   1132:   $args{$act}=$';
                   1133:   return unless $args{$act} =~ /^(#\d)*$/;
                   1134:   $args{$act}=length($args{$act})/2;
                   1135:   $def{$act}=$def;
                   1136:   $type{$act}='def';
                   1137:   warn "Definition of `$act' with $args{$act} args is `$def'\n"
                   1138:       if $debug & $debug_parsing;
                   1139: }
                   1140:
                   1141: sub defb {
                   1142:   for (@_) {
                   1143:     &define("\\$_","\\begin{$_}");&define("\\end$_","\\end{$_}");
                   1144:   }
                   1145: }
                   1146:
                   1147: # Discards surrounding {}
                   1148:
                   1149: sub get_balanced {
                   1150:         return undef unless $par =~ s/^($tokenpattern)//;
                   1151:   return $1 unless $1 eq '{';
                   1152:         local($def,$lev)=('',1);
                   1153:         while ($lev) {
                   1154:                 last unless $par =~ s/^[^\\{}]|\\.|[{}]//;
                   1155:                 $lev++ if $& eq '{';
                   1156:                 $lev-- if $& eq '}';
                   1157:                 $def .= $& if $lev;
                   1158:         }
                   1159:         (warn "Balanced text not finished!",return undef) if $lev;
                   1160:         return $def;
                   1161: }
                   1162:
                   1163:
                   1164: sub open_curly {
                   1165:   #&puts("{") unless $tokenByToken[$#level];
                   1166:   &start("}");
                   1167: }
                   1168:
                   1169: # Deletes extra spaces at the end of a record
                   1170:
                   1171: sub trim_end {
                   1172:   local($h,$str)=(split(/,/,$_[0],5))[0,4];
                   1173:   if (!$h) {
                   1174:     $str =~ s/\s+$//;
                   1175:     $_[0]=&string2record($str);
                   1176:     warn "Trimmed End `$_[0]'\n__END__\n" if $debug & $debug_record;
                   1177:   }
                   1178: }
                   1179:
                   1180: # Deletes extra spaces at the beginning of a record
                   1181:
                   1182: sub trim_beg {
                   1183:   local($h,$str)=(split(/,/,$_[0],5))[0,4];
                   1184:   if (!$h) {
                   1185:     $str =~ s/^\s+//;
                   1186:     $_[0]=&string2record($str);
                   1187:     warn "Trimmed Beg `$_[0]'\n__END__\n" if $debug & $debug_record;
                   1188:   }
                   1189: }
                   1190:
                   1191: # Deletes extra spaces at the ends of a chunk with given number
                   1192:
                   1193: sub trim_one {
                   1194:   &trim_beg($out[$chunks[$_[0]]]);
                   1195:   &trim_end($_[0]==$#chunks? $out[$#out]: $out[$chunks[$_[0]+1]-1]);
                   1196: }
                   1197:
                   1198: # Deletes extra spaces at the ends of a given number of chunks
                   1199:
                   1200: sub trim {
                   1201:   for ($#chunks-$_[0]+1..$#chunks) {&trim_one($_);}
                   1202: }
                   1203:
                   1204: sub dollar {
                   1205:   if ($wait[$#level] eq '$') {        # ';
                   1206:     &trim_end($out[$#out]);
                   1207:     &finish('$');
                   1208:   }
                   1209:   else {
                   1210:     &start('$');
                   1211:     $par =~ s/^\s+//;
                   1212:   }
                   1213: }
                   1214:
                   1215: sub ddollar {
                   1216:   if ($wait[$#level] eq '$$') {
                   1217:     &trim_end($out[$#out]);
                   1218:     &finish('$$');
                   1219:     return unless $#out>=0;
                   1220:     $#chunks=0;
                   1221:     $chunks[0]=0;
                   1222:     &trim(1);
                   1223:     &collapse(1);
                   1224:     &printrecord(&center($linelength,$out[0]));
                   1225:     @level=(0);
                   1226:     @chunks=(0);
                   1227:     @tokenByToken=(0);
                   1228:     @out=();
                   1229:     $curlength=0;
                   1230:     # Maybe after \begin{align}
                   1231:   }
                   1232:   else {
                   1233:     &finishBuffer;
                   1234:     &start('$$');
                   1235:   }
                   1236:   $par =~ s/^\s+//;
                   1237: }
                   1238:
                   1239: sub item {
                   1240:   &finishBuffer;
                   1241:   # To make unexpandable:
                   1242:   &commit("1,11,0,0,     (\@)   ");
                   1243: }
                   1244:
                   1245: sub bbackslash {
                   1246:   if ($wait[$#level] eq '$$') {
                   1247:     &ddollar();
                   1248:     &ddollar();
                   1249:   } elsif ($wait[$#level] eq 'endCell') {
                   1250:     return if $par =~ /^\s*\\end/;             # Ignore the last one
                   1251:     &finish('endCell', 1);
                   1252:     &trim(1);
                   1253:     &collapse(1);
                   1254:     &finish('endRow', 1);
                   1255:     &start('endRow');
                   1256:     &start('endCell');
                   1257:   } else {
                   1258:     #&puts(" \\\\ ");
                   1259:     &par;
                   1260:   }
                   1261: }
                   1262:
                   1263: sub ampersand {
                   1264:   if ($wait[$#level] eq 'endCell') {
                   1265:     &finish('endCell',1);
                   1266:     &trim(1);
                   1267:     &collapse(1);
                   1268:     &start('endCell');
                   1269:   }
                   1270: }
                   1271:
                   1272: sub matrix {
                   1273:   &start('endMatrix');
                   1274:   &start('endRow');
                   1275:   &start('endCell');
                   1276: }
                   1277:
                   1278: sub endmatrix {
                   1279:   &finish('endCell',1);
                   1280:   &trim(1);
                   1281:   &collapse(1);
                   1282:   &finish('endRow',1);
                   1283:   # Now chunks correspond to rows of the matrix, records inside chunks to
                   1284:   # Cells
                   1285:   &halign(split(";",shift));
                   1286:   &finish('endMatrix',1);
                   1287: }
                   1288:
                   1289: sub endmatrixArg {
                   1290:   &endmatrix(join(";",($_[0],split("",pop(@argStack)))));
                   1291: }
                   1292:
                   1293: # Takes a matrix in the following form: chunks on the last level
                   1294: # are row of the matrix, records inside chunks are cells.
                   1295: # Puts the resulting matrix in the first record on the given level
                   1296: # and truncates the rest
                   1297:
                   1298: # I'm trying to add parameters:
                   1299: #      length to insert between columns
                   1300: #      Array of centering options one for a column (last one repeated if needed)
                   1301: #              Currently supported:    c for center
                   1302: #                                      r for right
                   1303: #                                      l for left
                   1304:
                   1305: sub halign {
                   1306:   local($explength)=(shift);
                   1307:   local(@c)=@_;
                   1308:   local($last,$le,$b,$h);
                   1309:   local(@w)=();
                   1310:   #warn "levels @level, chunks @chunks, records @out\n";
                   1311:   # Find metrics of cells
                   1312:   for $r (0..$#chunks-$level[$#level]) {
                   1313:     $last= ($r==$#chunks-$level[$#level]) ? $#out:
                   1314:                                             $chunks[$r+1+$level[$#level]]-1;
                   1315:   warn "Row $r: last column " . ($last-$chunks[$r+$level[$#level]]) ."\n"
                   1316:                                 if $debug & $debug_matrix;
                   1317:     for $c (0..$last-$chunks[$r+$level[$#level]]) {
                   1318:       ($h,$le,$b)=
                   1319:                 ($out[$chunks[$r+$level[$#level]]+$c] =~ /(\d+),(\d+),(\d+)/);
                   1320:         # Format is Height:Length:Baseline
                   1321:       $w[$c]=$le unless $w[$c]>$le;
                   1322:     }
                   1323:   }
                   1324:   # expand the height and depth
                   1325:   for $c (0..$#w-1) {$w[$c]+=$explength;}
                   1326:   # Extend the @c array by the last element or "c" if it is empty
                   1327:   @c=("c") x @w unless @c;
                   1328:   @c=(@c,($c[$#c]) x (@w-@c));
                   1329:   # Now expand the cells
                   1330:   warn "Widths of columns @w\n" if $debug & $debug_matrix;
                   1331:   for $r (0..$#chunks-$level[$#level]) {
                   1332:     $last= ($r==$#chunks-$level[$#level]) ? $#out:
                   1333:                                             $chunks[$r+1+$level[$#level]]-1;
                   1334:     warn "Row $r: last column " . ($last-$chunks[$r+$level[$#level]]) ."\n"
                   1335:         if $debug & $debug_matrix;
                   1336:     for $c (0..$last-$chunks[$r+$level[$#level]]) {
                   1337:       if ($c[$c] eq "c") {
                   1338:         warn "Centering row $r col $c to width $w[$c]\n"
                   1339:             if $debug & $debug_matrix;
                   1340:         $out[$chunks[$r+$level[$#level]]+$c]=
                   1341:           &center($w[$c],$out[$chunks[$r+$level[$#level]]+$c]);
                   1342:       } elsif ($c[$c] eq "l") {
                   1343:         warn "Expanding row $r col $c to width $w[$c]\n"
                   1344:             if $debug & $debug_matrix;
                   1345:         $out[$chunks[$r+$level[$#level]]+$c]=
                   1346:           &join($out[$chunks[$r+$level[$#level]]+$c],
                   1347:                 &string2record(" " x
                   1348:                   ($w[$c] - &length($out[$chunks[$r+$level[$#level]]+$c]))));
                   1349:       } elsif ($c[$c] eq "r") {
                   1350:         warn "Expanding row $r col $c to width $w[$c] on the left\n"
                   1351:             if $debug & $debug_matrix;
                   1352:         $out[$chunks[$r+$level[$#level]]+$c]=
                   1353:           &join(&string2record(" " x
                   1354:                   ($w[$c]-$explength-
                   1355:                        &length($out[$chunks[$r+$level[$#level]]+$c]))),
                   1356:                 $out[$chunks[$r+$level[$#level]]+$c]);
                   1357:         $out[$chunks[$r+$level[$#level]]+$c]=
                   1358:           &join($out[$chunks[$r+$level[$#level]]+$c],
                   1359:                 &string2record(" " x $explength));
                   1360:       } else {warn "Unknown centering option `$c[$c]' for halign";}
                   1361:     }
                   1362:   }
                   1363:   # Now we creat rows
                   1364:   &collapseAll;
                   1365:   # And stack them vertically
                   1366:   for ($chunks[$level[$#level]]+1..$#out) {
                   1367:     $out[$chunks[$level[$#level]]]=&vStack($out[$chunks[$level[$#level]]],
                   1368:                                            $out[$_]);
                   1369:   }
                   1370:   &setbaseline($out[$chunks[$level[$#level]]],
                   1371:                int((&height($out[$chunks[$level[$#level]]])-1)/2));
                   1372:   $#chunks=$level[$#level];
                   1373:   $#out=$chunks[$level[$#level]];
                   1374: }
                   1375:
                   1376: sub close_curly {
                   1377:   &finish("}");
                   1378:   #&puts("}") unless $tokenByToken[$#level]; # well, this can change under our foot...
                   1379: }
                   1380:
                   1381: sub at {
                   1382:   local($c,$first,$second,$t,$m)=($par =~ /^(.)/);
                   1383:   if ($c eq '@') {&puts('@');$par =~ s/^.//;}
                   1384:   elsif (index("<>AV",$c)>=0) {
                   1385:     $m="&" if ($wait[$#level] eq 'endCell');
                   1386:     $m="&&" if $m eq "&" && index("AV",$c)>=0;
                   1387:     &ampersand if $m eq "&";
                   1388:     $par =~ s/^.//;
                   1389:     $first=$second="";
                   1390:     while (($t=&get_balanced()) ne $c && defined $t) {
                   1391:       $first .= $t;
                   1392:     }
                   1393:     while (($t=&get_balanced()) ne $c && defined $t) {
                   1394:       $second .= $t;
                   1395:     }
                   1396:     $par="{$first}{$second}$m" . $par;
                   1397:     local($l,$r);
                   1398:     ($l=$c) =~ tr/A>V/^/d;
                   1399:     ($r=$c) =~ tr/<A//d;
                   1400:     index("<>",$c)>=0 ?
                   1401:        &start(2,"f_arrow;$l;$r"):
                   1402:        &start(2,"f_arrow_v;$l;$r");
                   1403:   }
                   1404:   elsif ($c eq "." && $wait[$#level] eq 'endCell') {
                   1405:     &ampersand;
                   1406:     &ampersand;
                   1407:     $par =~ s/^.//;
                   1408:   }
                   1409:   else {&puts('@');}
                   1410: }
                   1411:
                   1412: # takes two tips of arrow as argument separated by ";",
                   1413: # we assume that total length is 1
                   1414:
                   1415: sub f_arrow {
                   1416:   warn "Entering f_arrow...\n" if $debug & $debug_flow;
                   1417:   local($l,$r)=split(";",shift);
                   1418:   &trim(2);
                   1419:   &collapse(2);
                   1420:   &assertHave(2) || &finish("",1);
                   1421:   warn "Over: $out[$#out-1]\nUnder: $out[$#out]\n__END__\n" if $debug & $debug_record;
                   1422:   local($l1,$l2)=(&length($out[$#out-1]),&length($out[$#out]));
                   1423:   local($len)=(($l1>$l2 ? $l1: $l2));
                   1424:   $out[$#out-1]=&vStack(&vStack(&center($len+4,$out[$#out-1]),
                   1425:                          &string2record(" $l" ."-" x ($len+1) . "$r ")),
                   1426:                  &center($len+4,$out[$#out]));
                   1427:   $#chunks--;
                   1428:   $#out--;
                   1429:   warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow;
                   1430:   &finish(2,1);
                   1431: }
                   1432:
                   1433: # takes two tips of arrow as argument separated by ";",
                   1434: # we assume that total length is 1
                   1435:
                   1436: sub f_arrow_v {
                   1437:   warn "Entering f_arrow_v...\n" if $debug & $debug_flow;
                   1438:   local($l,$r)=split(";",shift);
                   1439:   &trim(2);
                   1440:   &collapse(2);
                   1441:   &assertHave(2) || &finish("",1);
                   1442:   warn "Over: $out[$#out-1]\nUnder: $out[$#out]\n__END__\n" if $debug & $debug_record;
                   1443:   local($h1,$b1)=($out[$#out-1] =~ /^(\d+),\d+,(\d+)/);
                   1444:   local($h2,$b2)=($out[$#out] =~ /^(\d+),\d+,(\d+)/);
                   1445:   local($b)=(($b1>$b2 ? $b1: $b2));
                   1446:   local($res)=(&join($out[$#out-1],$out[$#out]));
                   1447:   local($h,$bb)=($res =~ /^(\d+),\d+,(\d+)/);
                   1448:   $bb=$b+1;
                   1449:   $out[$#out-1]=&vStack(&vputs(" " x ($b-$b1+1)),
                   1450:                         $out[$#out-1]);
                   1451:   #$out[$#out-1] =~ s/^(\d+,\d+,)(\d+)/\1$bb/;
                   1452:   &setbaseline($out[$#out-1],$bb);
                   1453:   $out[$#out]=&vStack(&vputs(" " x ($b-$b2+1)),
                   1454:                                      $out[$#out]);
                   1455:   #$out[$#out] =~ s/^(\d+,\d+,)(\d+)/\1$bb/;
                   1456:   &setbaseline($out[$#out],$bb);
                   1457:   $out[$#out-1]=&join(&join($out[$#out-1],
                   1458:                          &vputs($l ."|" x ($h+1) . $r,$b+1)),
                   1459:                       $out[$#out]);
                   1460:   $#chunks--;
                   1461:   $#out--;
                   1462:   warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow;
                   1463:   &finish(2,1);
                   1464: }
                   1465:
                   1466: sub noindent {
                   1467:   if ($#out == 0 && $#chunks == 0 && $out[$#out] eq '1,5,0,0,     ') {
                   1468:     $#out--;
                   1469:     $#chunks--;
                   1470:   } else {
                   1471:     &puts('\\noindent');
                   1472:   }
                   1473: }
                   1474:
                   1475: # put strings vertically, returns a record with the second argument as baseline
                   1476:
                   1477: sub vputs {
                   1478:   local($b)=($_[1]);
                   1479:   $b=0 unless defined $b;
                   1480:   return length($_[0]) . ",1,$b,0," . join("\n",split('',$_[0]));
                   1481: }
                   1482:
                   1483: sub choose {
                   1484:   if ($wait[$#level] eq '}') {
                   1485:     local($prevw)=($wait[$#level-1]);
                   1486:     $wait[$#level-1]="junk";
                   1487:     &finish("}",1);
                   1488:           &collapse(1);
                   1489:           &assertHave(1) || &finish("",1);
                   1490:     local($rec)=$out[$#out];
                   1491:     $#out--;
                   1492:     $#chunks--;
                   1493:     &start(2,"f_choose");
                   1494:     $wait[$#level-1]=$prevw;
                   1495:     &start("}");
                   1496:     &commit($rec);
                   1497:     &finish("}",1);
                   1498:     &start("}");
                   1499:   } else {&puts("\\choose");}
                   1500: }
                   1501:
                   1502: sub over {
                   1503:   if ($wait[$#level] eq '}') {
                   1504:     local($prevw)=($wait[$#level-1]);
                   1505:     $wait[$#level-1]="junk";
                   1506:     &finish("}", 1);
                   1507:           &collapse(1);
                   1508:           &assertHave(1) || &finish("",1);
                   1509:     local($rec)=$out[$#out];
                   1510:     $#out--;
                   1511:     $#chunks--;
                   1512:     &start(2,"f_fraction");
                   1513:     $wait[$#level-1]=$prevw;
                   1514:     &start("}");
                   1515:     &commit($rec);
                   1516:     &finish("}",1);
                   1517:     &start("}");
                   1518:   } else {&puts("\\over");}
                   1519: }
                   1520:
                   1521: # Takes a record, height, baseline, spaces_toleft and _toright
                   1522: # and makes this record this high
                   1523:
                   1524: sub makehigh {
                   1525:   local($str)=(split(",",$_[0],5))[4];
                   1526:   local($h,$b,$d)=($_[1],$_[2]+1);
                   1527:   warn "Entering makehigh(@_)\n" if $debug & $debug_flow;
                   1528:   if ($str eq ".") {$_[0] =~ s/\.$/ /;return;}
                   1529:   #$str="<" if $str eq "\\langle";
                   1530:   #$str=">" if $str eq "\\rangle";
                   1531:   $h=1 unless $h;
                   1532:   $d=$h-$b;
                   1533:   return if $h<2 || $h==2 && index("()<>",$str)>=0;
                   1534:   local(@c);
                   1535:   if    ($str eq "(") {@c=split(":",'(: :|:/:\:|');}
                   1536:   elsif ($str eq ")") {@c=split(":",'): :|:\:/:|');}
                   1537:   elsif ($str eq "{") {@c=split(":",'{: :|:/:\:<');}
                   1538:   elsif ($str eq "}") {@c=split(":",'}: :|:\:/:>');}
                   1539:   elsif ($str eq "|" && $str eq "||")
                   1540:                       {@c=split(":",'|:|:|:|:|:|');}
                   1541:   elsif ($str eq "[") {@c=split(":",'[:[:|:[:[:|');}
                   1542:   elsif ($str eq "]") {@c=split(":",']:]:|:]:]:|');}
                   1543:   elsif ($str eq "<" || $str eq ">") {
                   1544:     return if $h==2;
                   1545:     local($l)=($b);
                   1546:     $l=$d+1 if $b<$d+1;
                   1547:     for (2..$l) {
                   1548:       $_[0]=&join($_[0],
                   1549:                   &vputs("/" . " " x (2*$_-3) . "\\",$_-1)) if $str eq "<";
                   1550:       $_[0]=&join(&vputs("\\" . " " x (2*$_-3) . "/",$_-1),
                   1551:                   $_[0]) if $str eq ">";
                   1552:     }
                   1553:     $_[0]=&join($_[0],&string2record(" ")) if $str eq "<";
                   1554:     $_[0]=&join(&string2record(" "),$_[0]) if $str eq ">";
                   1555:     return;
                   1556:   }
                   1557:   else {return;}
                   1558:   $_[0]=&vputs(&makecompound($b,$d,@c),$b-1);
                   1559:   $_[0]=&join($_[0],$_[0]) if length($str)==2;
                   1560:   $_[0]=&join(&string2record(" " x $_[3]),$_[0]) if $_[3];
                   1561:   $_[0]=&join($_[0],&string2record(" " x $_[4])) if $_[4];
                   1562: }
                   1563:
                   1564:
                   1565: sub right {
                   1566:   &finish("LeftRight",1);
                   1567:   &trim(1);
                   1568:   &collapse(1);
                   1569: }
                   1570:
                   1571: sub f_left {
                   1572:   &trim(1);
                   1573:   &collapse(1);
                   1574:   &finish(1);
                   1575:   &start("LeftRight");
                   1576: }
                   1577:
                   1578: sub left {
                   1579:   &start(3,"f_leftright");
                   1580:   $tokenByToken[$#level]=1;
                   1581:   &start(1,"f_left");
                   1582:   $tokenByToken[$#level]=1;
                   1583: }
                   1584:
                   1585: sub f_leftright_go {
                   1586:   &trim(1);
                   1587:   &collapse(1);
                   1588:   local($l,$r)=split(";",shift);
                   1589:   &assertHave(1) || warn "Left-Right not balanced";
                   1590:   local($rec)=($out[$#out]);
                   1591:   $#out--;
                   1592:   $wait[$#level]="junk";
                   1593:   &start(3,"f_leftright");
                   1594:   &puts($l);
                   1595:   &commit($rec);
                   1596:   &puts($r);
                   1597:   &finish("junk");
                   1598: }
                   1599:
                   1600: sub beg_lr {
                   1601:   &start(1,"f_leftright_go" . ";" . shift);
                   1602:   $tokenByToken[$#level]=1;
                   1603: }
                   1604:
                   1605: sub f_leftright {
                   1606:   &trim(1);
                   1607:   &collapse(1);
                   1608:   &assertHave(3) || warn "Left-Right not balanced";
                   1609:   local($h,$b)=($out[$#out-1] =~ /^(\d+),\d+,(\d+)/)[0,1];
                   1610:   &makehigh($out[$#out-2],$h,$b,0,1);
                   1611:   &makehigh($out[$#out],$h,$b,1,0);
                   1612:   &finish(3);
                   1613: }
                   1614:
                   1615: # Arguments: Ascent, descent, base string, oneside expander, real expander
                   1616: #            0       1        2            3                 4
                   1617: #            Top tip, Bottom tip, Mid
                   1618: #            5        6           7
                   1619: # All component should be one character long
                   1620:
                   1621: sub makecompound {
                   1622:   # If Mid is the same as real expander, all depends on the height only
                   1623:   # if there is extend on both sides
                   1624:   # If it is 3 or more
                   1625:   if ($_[0]>1 && $_[1]>0 && $_[4] eq $_[7]) {
                   1626:     return $_[5] . $_[4] x ($_[0]+$_[1]-2) . $_[6];
                   1627:   }
                   1628:   # No descent:
                   1629:   if ($_[1] <= 0) {return $_[3] x ($_[0]-1) . $_[2];}
                   1630:   # No ascent:
                   1631:   if ($_[0] <= 1) {return $_[2] . $_[3] x $_[1];}
                   1632:   local($mid,$asc,$des)=($_[2]);
                   1633:   # descent == 1
                   1634:   $des = ($_[1]==1) ? $_[2]: $_[4] x ($_[1]-1) . $_[6];
                   1635:   $asc  = ($_[0]==2) ? $_[2]: $_[5] . $_[4] x ($_[0]-2);
                   1636:   $mid = $_[7] unless $_[0]==2 || $_[1]==1;
                   1637:   return "$asc$mid$des";
                   1638: }
                   1639:
                   1640: sub arg2stack {push(@argStack,&get_balanced());}
                   1641:
                   1642: sub par {&finishBuffer;&commit("1,5,0,0,     ")
                   1643:           unless $par =~ s/^\s*\\noindent\s*(\s+|([^a-zA-Z\s])|$)/\2/;}
                   1644:
                   1645: $type{"\\sum"}="record";
                   1646: $contents{"\\sum"}="3,4,1,0," . <<'EOF';
                   1647: \~~
                   1648:  >
                   1649: /__
                   1650: EOF
                   1651:
                   1652: $type{"\\int"}="record";
                   1653: $contents{"\\int"}="3,3,1,0," . <<'EOF';
                   1654:  ,-
                   1655:  |
                   1656: -'
                   1657: EOF
                   1658:
                   1659: $type{"\\prod"}="record";
                   1660: $contents{"\\prod"}="3,3,1,0," . <<'EOF';
                   1661: ___
                   1662: | |
                   1663: | |
                   1664: EOF
                   1665:
                   1666: $type{"\\Pi"}="record";
                   1667: $contents{"\\Pi"}="2,3,1,0," . <<'EOF';
                   1668:  _
                   1669: | |
                   1670: EOF
                   1671:
                   1672: $type{"\\Sigma"}="record";
                   1673: $contents{"\\Sigma"}="3,2,1,0," . <<'EOF';
                   1674: __
                   1675: >
                   1676: ~~
                   1677: EOF
                   1678:
                   1679: $type{"\\Delta"}="record";
                   1680: $contents{"\\Delta"}="2,2,0,0," . <<'EOF';
                   1681: /\
                   1682: ~~
                   1683: EOF
                   1684:
                   1685: $type{"\\oplus"}="record";
                   1686: $contents{"\\oplus"}="3,5,1,0," . <<'EOF';
                   1687:   _
                   1688:  (+)
                   1689:   ~
                   1690: EOF
                   1691:
                   1692: $type{"\\otimes"}="record";
                   1693: $contents{"\\otimes"}="3,5,1,0," . <<'EOF';
                   1694:   _
                   1695:  (x)
                   1696:   ~
                   1697: EOF
                   1698:
                   1699: $type{"\\ominus"}="record";
                   1700: $contents{"\\ominus"}="3,5,1,0," . <<'EOF';
                   1701:   _
                   1702:  (-)
                   1703:   ~
                   1704: EOF
                   1705:
                   1706: $type{"\\leq"}="record";
                   1707: $contents{"\\leq"}="2,4,1,0," . <<'EOF';
                   1708:  _
                   1709:  <
                   1710: EOF
                   1711:
                   1712: $type{"\\equiv"}="record";
                   1713: $contents{"\\equiv"}="2,4,1,0," . <<'EOF';
                   1714:  _
                   1715:  =
                   1716: EOF
                   1717:
                   1718: $type{"\\geq"}="record";
                   1719: $contents{"\\geq"}="2,4,1,0," . <<'EOF';
                   1720:  _
                   1721:  >
                   1722: EOF
                   1723:
                   1724: $type{"\\partial"}="record";
                   1725: $contents{"\\partial"}="2,2,1,0," . <<'EOF';
                   1726: \
                   1727: d
                   1728: EOF
                   1729:
                   1730: $type{"\\forall"}="record";
                   1731: $contents{"\\forall"}="3,4,1,0," . <<'EOF';
                   1732: \__/
                   1733:  \/
                   1734: EOF
                   1735:
                   1736: $type{"\\exists"}="record";
                   1737: $contents{"\\exists"}="3,2,1,0," . <<'EOF';
                   1738: _.
                   1739: -|
                   1740: ~'
                   1741: EOF
                   1742:
                   1743: $type{"\\owns"}="record";
                   1744: $contents{"\\owns"}="3,4,1,0," . <<'EOF';
                   1745:  _
                   1746:  -)
                   1747:  ~
                   1748: EOF
                   1749:
                   1750: $type{"\\ni"}="record";
                   1751: $contents{"\\ni"}="3,4,1,0," . <<'EOF';
                   1752:  _
                   1753:  -)
                   1754:  ~
                   1755: EOF
                   1756:
                   1757: $type{"\\in"}="record";
                   1758: $contents{"\\in"}="3,4,1,0," . <<'EOF';
                   1759:   _
                   1760:  (-
                   1761:   ~
                   1762: EOF
                   1763:
                   1764: $type{"\\notin"}="record";
                   1765: $contents{"\\notin"}="3,5,1,0," . <<'EOF';
                   1766:   |_
                   1767:  (|-
                   1768:   |~
                   1769: EOF
                   1770:
                   1771: $type{"\\qed"}="record";
                   1772: $contents{"\\qed"}="2,6,1,0," . <<'EOF';
                   1773:     _
                   1774:    |_|
                   1775: EOF
                   1776:
                   1777: $type{"\\pm"}="record";
                   1778: $contents{"\\pm"}="2,1,0,0," . <<'EOF';
                   1779: +
                   1780: -
                   1781: EOF
                   1782:
                   1783: $type{"\\mp"}="record";
                   1784: $contents{"\\mp"}="2,1,1,0," . <<'EOF';
                   1785: _
                   1786: +
                   1787: EOF
                   1788:
                   1789: $type{"\\cong"}="record";
                   1790: $contents{"\\cong"}="2,1,0,0," . <<'EOF';
                   1791: =
                   1792: ~
                   1793: EOF
                   1794:
                   1795: $type{"\\neq"}="record";
                   1796: $contents{"\\neq"}="1,5,0,0," . <<'EOF';
                   1797:  =/=
                   1798: EOF
                   1799:
                   1800: $type{"\\nmid"}="record";
                   1801: $contents{"\\nmid"}="3,3,1,0," . <<'EOF';
                   1802:  |/
                   1803:  |
                   1804: /|
                   1805: EOF
                   1806:
                   1807: $type{"\\subset"}="record";
                   1808: $contents{"\\subset"}="2,4,1,0," . <<'EOF';
                   1809:   _
                   1810:  (_
                   1811: EOF
                   1812:
                   1813: $type{"\\subseteq"}="record";
                   1814: $contents{"\\subseteq"}="3,4,1,0," . <<'EOF';
                   1815:   _
                   1816:  (_
                   1817:   ~
                   1818: EOF
                   1819:
                   1820: $type{"\\supseteq"}="record";
                   1821: $contents{"\\subseteq"}="3,4,1,0," . <<'EOF';
                   1822:  _
                   1823:  _)
                   1824:  ~
                   1825: EOF
                   1826:
                   1827: $type{"\\supset"}="record";
                   1828: $contents{"\\supset"}="2,4,1,0," . <<'EOF';
                   1829:  _
                   1830:  _)
                   1831: EOF
                   1832:
                   1833: $type{"\\sqrt"}="sub1";
                   1834: $contents{"\\sqrt"}="radical";
                   1835:
                   1836: $type{"\\buildrel"}="sub3";
                   1837: $contents{"\\buildrel"}="buildrel";
                   1838:
                   1839: $type{"\\frac"}="sub2";
                   1840: $contents{"\\frac"}="fraction";
                   1841:
                   1842: $type{"\\LITERALnoLENGTH"}="sub1";
                   1843: $contents{"\\LITERALnoLENGTH"}="literal_no_length";
                   1844:
                   1845: for ("text","operatorname","operatornamewithlimits","relax","-",
                   1846:      "notag","!","/","protect","mathcal","Bbb","bf","it","em","boldsymbol",
                   1847:      "cal","Cal","goth","ref","maketitle","expandafter","csname","endcsname",
                   1848:      "makeatletter","makeatother","topmatter","endtopmatter","rm",
                   1849:      "NoBlackBoxes","document","TagsOnRight","bold","dsize","roster",
                   1850:      "endroster","endkey","endRefs","enddocument","displaystyle",
                   1851:      "twelverm","tenrm","twelvefm","tenfm","hbox","mbox") {
                   1852:   $type{"\\$_"}="nothing";
                   1853: }
                   1854: for ("par","endtitle","endauthor","endaffil","endaddress","endemail",
                   1855:      "endhead","key","medskip","smallskip","bigskip","newpage",
                   1856:      "vfill","eject","endgraph") {
                   1857:   $type{"\\$_"}="sub";
                   1858:   $contents{"\\$_"}="par";
                   1859: }
                   1860:
                   1861: for ("proclaim","demo",) {
                   1862:   $type{"\\$_"}="par_self";
                   1863: }
                   1864:
                   1865: for ("endproclaim","enddemo",) {
                   1866:   $type{"\\$_"}="self_par";
                   1867: }
                   1868:
                   1869: #$type{"&"}="nothing";
                   1870:
                   1871: $type{"\\let"}="sub";
                   1872: $contents{"\\let"}="let_exp";
                   1873:
                   1874: $type{"\\def"}="sub";
                   1875: $contents{"\\def"}="def_exp";
                   1876:
                   1877: $type{"\\item"}="sub";
                   1878: $contents{"\\item"}="item";
                   1879:
                   1880: $type{"{"}="sub";
                   1881: $contents{"{"}="open_curly";
                   1882:
                   1883: $type{"}"}="sub";
                   1884: $contents{"}"}="close_curly";
                   1885:
                   1886: $type{"&"}="sub";
                   1887: $contents{"&"}="ampersand";
                   1888:
                   1889: $type{'$'}="sub";
                   1890: $contents{'$'}="dollar";
                   1891:
                   1892: $type{'$$'}="sub";
                   1893: $contents{'$$'}="ddollar";
                   1894:
                   1895: $type{'\\\\'}="sub";
                   1896: $contents{'\\\\'}="bbackslash";
                   1897:
                   1898: $type{"^"}="sub1";
                   1899: $contents{"^"}="superscript";
                   1900:
                   1901: $type{"_"}="sub1";
                   1902: $contents{"_"}="subscript";
                   1903:
                   1904: $type{"@"}="sub";
                   1905: $contents{"@"}="at";
                   1906:
                   1907: $type{"\\over"}="sub";
                   1908: $contents{"\\over"}="over";
                   1909:
                   1910:
                   1911: $type{"\\choose"}="sub";
                   1912: $contents{"\\choose"}="choose";
                   1913:
                   1914: $type{"\\noindent"}="sub";
                   1915: $contents{"\\noindent"}="noindent";
                   1916:
                   1917:
                   1918: $type{"\\left"}="sub";
                   1919: $contents{"\\left"}="left";
                   1920:
                   1921: $type{"\\right"}="sub";
                   1922: $contents{"\\right"}="right";
                   1923:
                   1924: $type{"\\underline"}="sub1";
                   1925: $contents{"\\underline"}="underline";
                   1926:
                   1927: $type{"\\overline"}="sub1";
                   1928: $contents{"\\overline"}="overline";
                   1929:
                   1930: $type{"\\bar"}="sub1";
                   1931: $contents{"\\bar"}="overline";
                   1932:
                   1933: $type{"\\v"}="sub1";
                   1934: $contents{"\\v"}="putover_string;v";
                   1935:
                   1936: $type{"\\widetilde"}="sub1";
                   1937: $contents{"\\widetilde"}="widetilde";
                   1938:
                   1939: $type{"\\~"}="sub1";
                   1940: $contents{"\\~"}="putover_string;~";
                   1941:
                   1942: $type{"\\tilde"}="sub1";
                   1943: $contents{"\\tilde"}="putover_string;~";
                   1944:
                   1945: $type{"\\widehat"}="sub1";
                   1946: $contents{"\\widehat"}="widehat";
                   1947:
                   1948: $type{"\\hat"}="sub1";
                   1949: $contents{"\\hat"}="putover_string;^";
                   1950:
                   1951: $type{"\\^"}="sub1";
                   1952: $contents{"\\^"}="putover_string;^";
                   1953:
                   1954: $type{'\\"'}="sub1";
                   1955: $contents{'\\"'}='putover_string;"';
                   1956:
                   1957: $type{'\\dot'}="sub1";
                   1958: $contents{'\\dot'}='putover_string;.';
                   1959:
                   1960: $type{"\\not"}="sub1";
                   1961: $contents{"\\not"}="not";
                   1962:
                   1963: $type{"\\label"}="sub1";
                   1964: $contents{"\\label"}="putpar;(;)";
                   1965:
                   1966: $type{"\\eqref"}="sub1";
                   1967: $contents{"\\eqref"}="putpar;(;)";
                   1968:
                   1969: $type{"\\cite"}="sub1";
                   1970: $contents{"\\cite"}="putpar;[;]";
                   1971:
                   1972: $type{"\\begin"}="sub1";
                   1973: $contents{"\\begin"}="begin";
                   1974:
                   1975: $type{"\\end"}="sub1";
                   1976: $contents{"\\end"}="end";
                   1977:
                   1978: for ('@',"_","\$","{","}","#","&","arccos","arcsin","arctan","arg","cos",
                   1979:     "cosh","cot","coth","csc","deg","det","dim","exp","gcd","hom",
                   1980:     "inf","ker","lg","lim","liminf","limsup","ln","log","max","min",
                   1981:     "mod","Pr","sec","sin","sinh","sup","tan","tanh", "%") {
                   1982:   $type{"\\$_"}="self";
                   1983: }
                   1984:
                   1985: for ("bibliography","myLabel","theoremstyle","theorembodyfont",
                   1986:      "bibliographystyle","hphantom","vphantom","phantom","hspace") {
                   1987:   $type{"\\$_"}="discard1";
                   1988: }
                   1989:
                   1990: for ("numberwithin","newtheorem","renewcommand","setcounter"
                   1991:     ) {
                   1992:   $type{"\\$_"}="discard2";
                   1993: }
                   1994:
                   1995: for ("equation","gather","align"
                   1996:      ) {$environment{"$_"}="ddollar,ddollar";}
                   1997:
                   1998: for ("matrix","CD","smallmatrix"
                   1999:      ) {$environment{"$_"}="matrix,endmatrix;1;c";}
                   2000:
                   2001: for ("document","split","enumerate"
                   2002:      ) {$environment_none{"$_"}++;}
                   2003:
                   2004: $environment{"Sb"}="subscript:matrix,endmatrix;1;l";
                   2005:
                   2006: $environment{"Sp"}="superscript:matrix,endmatrix;1;l";
                   2007:
                   2008: $environment{"eqnarray"}="ddollar:matrix,endmatrix;0;r;c;l:ddollar";
                   2009: $environment{"split"}="ddollar:matrix,endmatrix;0;r;l:ddollar";
                   2010: $environment{"multiline"}="ddollar:matrix,endmatrix;0;r;l:ddollar";
                   2011: $environment{"align"}="ddollar:matrix,endmatrix;0;r;l:ddollar";
                   2012: $environment{"aligned"}="matrix,endmatrix;0;r;l";
                   2013: $environment{"gather"}="ddollar:matrix,endmatrix;0;c:ddollar";
                   2014: $environment{"gathered"}="matrix,endmatrix;0;c";
                   2015: $environment{"array"}="arg2stack:matrix,endmatrixArg;1";
                   2016:
                   2017: # $environment{"pmatrix"}="beg_lr;(;):matrix,endmatrix;1;c";
                   2018: $environment{"bmatrix"}="beg_lr;[;]:matrix,endmatrix;1;c";
                   2019: $environment{"vmatrix"}="beg_lr;|;|:matrix,endmatrix;1;c";
                   2020:
                   2021: $type{"~"}="string";
                   2022: $contents{"~"}=" ";
                   2023:
                   2024: $type{"\\,"}="string";
                   2025: $contents{"\\,"}=" ";
                   2026:
                   2027: $type{"\\dots"}="string";
                   2028: $contents{"\\dots"}="...";
                   2029:
                   2030: $type{"\\ldots"}="string";
                   2031: $contents{"\\ldots"}="...";
                   2032:
                   2033: $type{"\\cdots"}="string";
                   2034: $contents{"\\cdots"}="...";
                   2035:
                   2036: $type{"\\colon"}="string";
                   2037: $contents{"\\colon"}=": ";
                   2038:
                   2039: $type{"\\mid"}="string";
                   2040: $contents{"\\mid"}=" | ";
                   2041:
                   2042: $type{"\\smallsetminus"}="string";
                   2043: $contents{"\\smallsetminus"}=" \\ ";
                   2044:
                   2045: $type{"\\setminus"}="string";
                   2046: $contents{"\\setminus"}=" \\ ";
                   2047:
                   2048: $type{"\\backslash"}="string";
                   2049: $contents{"\\backslash"}="\\";
                   2050:
                   2051: $type{"\\approx"}="string";
                   2052: $contents{"\\approx"}=" ~ ";
                   2053:
                   2054: $type{"\\simeq"}="string";
                   2055: $contents{"\\simeq"}=" ~ ";
                   2056:
                   2057: $type{"\\quad"}="string";
                   2058: $contents{"\\quad"}="   ";
                   2059:
                   2060: $type{"\\qquad"}="string";
                   2061: $contents{"\\qquad"}="     ";
                   2062:
                   2063: $type{"\\to"}="string";
                   2064: $contents{"\\to"}=" --> ";
                   2065:
                   2066: $type{"\\from"}="string";
                   2067: $contents{"\\from"}=" <-- ";
                   2068:
                   2069: $type{"\\wedge"}="string";
                   2070: $contents{"\\wedge"}="/\\";
                   2071:
                   2072: $type{"\\Lambda"}="string";
                   2073: $contents{"\\Lambda"}="/\\";
                   2074:
                   2075: $type{"\\ltimes"}="string";
                   2076: $contents{"\\ltimes"}=" |>< ";
                   2077:
                   2078: $type{"\\lhd"}="string";
                   2079: $contents{"\\lhd"}=" <| ";
                   2080:
                   2081: $type{"\\rhd"}="string";
                   2082: $contents{"\\rhd"}=" |> ";
                   2083:
                   2084: $type{"\\cdot"}="string";
                   2085: $contents{"\\cdot"}=" . ";
                   2086:
                   2087: # $type{"\dot"}="string";
                   2088: # $contents{"\\dot"}=" . ";
                   2089:
                   2090: $type{"\\circ"}="string";
                   2091: $contents{"\\circ"}=" o ";
                   2092:
                   2093: $type{"\\bullet"}="string";
                   2094: $contents{"\\bullet"}="\@";
                   2095:
                   2096: $type{"\\infty"}="string";
                   2097: $contents{"\\infty"}="oo";
                   2098:
                   2099: $type{"\\rtimes"}="string";
                   2100: $contents{"\\rtimes"}=" ><| ";
                   2101:
                   2102: $type{"\\times"}="string";
                   2103: $contents{"\\times"}=" >< ";
                   2104:
                   2105: $type{"\\hookrightarrow"}="string";
                   2106: $contents{"\\hookrightarrow"}=" c--> ";
                   2107:
                   2108: $type{"\\hookleftarrow"}="string";
                   2109: $contents{"\\hookleftarrow"}=" <--j ";
                   2110:
                   2111: $type{"\\longleftarrow"}="string";
                   2112: $contents{"\\longleftarrow"}=" <----- ";
                   2113:
                   2114: $type{"\\longleftrightarrow"}="string";
                   2115: $contents{"\\longleftrightarrow"}=" <----> ";
                   2116:
                   2117: $type{"\\longrightarrow"}="string";
                   2118: $contents{"\\longrightarrow"}=" -----> ";
                   2119:
                   2120: $type{"\\rightarrow"}="string";
                   2121: $contents{"\\rightarrow"}=" ---> ";
                   2122:
                   2123: $type{"\\leftarrow"}="string";
                   2124: $contents{"\\leftarrow"}=" <--- ";
                   2125:
                   2126: $type{"\\mapsto"}="string";
                   2127: $contents{"\\mapsto"}=" |--> ";
                   2128:
                   2129: $type{"\\longmapsto"}="string";
                   2130: $contents{"\\longmapsto"}=" |----> ";
                   2131:
                   2132: $type{"\\cap"}="string";
                   2133: $contents{"\\cap"}=" /~\\ ";
                   2134:
                   2135: $type{"\\cup"}="string";
                   2136: $contents{"\\cup"}=" \\_/ ";
                   2137:
                   2138: $type{"\\section"}="string";
                   2139: $contents{"\\section"}="Section ";
                   2140:
                   2141: $type{"\\subsection"}="string";
                   2142: $contents{"\\subsection"}="Subsection ";
                   2143:
                   2144: $type{"\|"}="string";
                   2145: $contents{"\|"}="||";
                   2146:
                   2147: $type{'\;'}="string";
                   2148: $contents{'\;'}=" ";
                   2149:
                   2150: $type{'\noindent'}="string";
                   2151: $contents{'\noindent'}="";
                   2152:
                   2153:
                   2154: &define('\\define','\\def');
                   2155: &define('\\ge','\\geq');
                   2156: &define('\\le','\\leq');
                   2157: &define('\\ne','\\neq');
                   2158: &define('\\langle','<');
                   2159: &define('\\rangle','>');
                   2160: &define('\\subheading','\\par\\underline');
                   2161: &define('\\(','$');
                   2162: &define('\\)','$');
                   2163: &define('\\[','$$');
                   2164: &define('\\]','$$');
                   2165: &define('\\centerline#1','$$#1$$');
                   2166: &define('\\eqalign#1','\\aligned #1 \\endaligned');
                   2167: &define('\\cr','\\\\');
                   2168: &define('\\sb','_');
                   2169: &define('\\sp','^');
                   2170: &define('\\proclaim','\\noindent ');
                   2171: &defb("matrix","vmatrix","Vmatrix","smallmatrix","bmatrix","Sp","Sb",
                   2172:       "CD","align","aligned","split","multiline","gather","gathered");
                   2173:
                   2174: if ($opt_TeX) {
                   2175:   &define('\pmatrix#1','\left(\begin{matrix}#1\end{matrix}\right)');
                   2176: } else {
                   2177:   $environment{"pmatrix"}="beg_lr;(;):matrix,endmatrix;1;c";
                   2178:   &defb("pmatrix") unless $opt_TeX;
                   2179: }
                   2180:
                   2181:
                   2182:   ## All the records should be specified before this point
                   2183:   {local(@a)=grep("record" eq $type{$_},keys %type);
                   2184:                for (@a) {chop $contents{$_} if
                   2185:       substr($contents{$_},length($contents{$_})-1,1) eq "\n";}}
                   2186:
                   2187: for ("oplus","otimes","cup","wedge") {
                   2188:   $type{"\\big$_"}=$type{"\\$_"};
                   2189:   $contents{"\\big$_"}=$contents{"\\$_"};
                   2190: }
                   2191:
                   2192:
                   2193: @level=(0);
                   2194: @chunks=(0);
                   2195: @tokenByToken=(0);
                   2196: @out=();
                   2197: $curlength=0;
                   2198: $debug_flow=1;
                   2199: $debug_record=2;
                   2200: $debug_parsing=4;
                   2201: $debug_length=8;
                   2202: $debug_matrix=16;
                   2203: #$debug |= $debug_flow | $debug_record | $debug_parsing | $debug_length;
                   2204: #$debug |= $debug_flow;
                   2205: #$debug |= $debug_record;
                   2206: #$debug |= $debug_parsing;
                   2207: #$debug |= $debug_length;
                   2208: #$debug |= $debug_matrix;
                   2209:
                   2210:
                   2211: $/ = $opt_by_par ? "\n\n" : ''; # whole paragraph mode
                   2212: while (&paragraph()) { 1 }
                   2213: &finishBuffer;
                   2214:
                   2215: __END__
                   2216:
                   2217: # History: Jul 98: \choose added, fixed RE for \noindent, \eqalign and \cr.
                   2218: #                      \proclaim and better \noindent added.
                   2219: # Sep 98: last was used inside an if block, was leaking out.
                   2220: # Jan 00: \sb \sp
                   2221: # Feb 00: remove extraneous second EOF needed at end.
                   2222:          remove an empty line at end of output
                   2223:          New option -by_par to support per-paragraph processing
                   2224:          New option -TeX which support a different \pmatrix
                   2225:          New option -ragged to not insert whitespace to align right margin.
                   2226:          New option -noindent to not insert whitespace at beginning.
                   2227:          Ignore \\ and \cr if followed by \end{whatever}.
                   2228:          Ignore \noindent if not important.
                   2229:          Ignore whitespace paragraphs.
                   2230: # Apr 00: Finishing a level 1 would not merge things into one chunk.
                   2231: # May 00: Additional argument to finish() to distinguish finishing
                   2232:          things which cannot be broken between lines.
                   2233: # Sep 00: Add support for new macro for strings with screen escapes sequences:
                   2234:          \LITERALnoLENGTH{escapeseq}.
                   2235: # Oct 00: \LITERALnoLENGTH can have a chance to work in the baseline only;
                   2236:           in fact the previous version did not work even there...
                   2237:          If the added record is longer than line length, do not try to
                   2238:          break the line before it...

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>