Annotation of OpenXM_contrib/pari-2.2/misc/tex2mail, Revision 1.1
1.1 ! noro 1: #!/usr/bin/perl
! 2:
! 3: # $Id: tex2mail.in,v 1.1 2000/10/27 19:13:53 karim Exp $
! 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];}
! 740: $left=int($left/2);
! 741: local($out,$first)=("",1);
! 742: for (split(/\n/,$str1,$h1)) {
! 743: if ($first) {$first=0;}
! 744: else {$out .= "\n";}
! 745: $out .= " " x $left . $_;
! 746: }
! 747: return "$h1,$len,$b1,0,$out";
! 748: }
! 749:
! 750: # Example of radical
! 751: #<<'EOF';
! 752: # +--+
! 753: #\|12
! 754: #EOF
! 755: <<EOF; # To hide HERE-DOC start above from old CPerl
! 756: EOF
! 757:
! 758: # Takes the last record, returns a record that contains it and forms
! 759: # radical block
! 760:
! 761: sub f_radical {
! 762: warn "Entering f_radical...\n" if $debug & $debug_flow;
! 763: &trim(1);
! 764: &collapse(1);
! 765: &assertHave(1) || &finish("",1);
! 766: warn "Radical of $out[$#out]\n__END__\n" if $debug & $debug_record;
! 767: local($h,$l,$b)=($out[$#out] =~ /^(\d+),(\d+),(\d+)/g);
! 768: $h || $h++;
! 769: local($out,$b1,$h1);
! 770: $out=&vStack(&string2record(("-" x $l)."+" ),$out[$#out]);
! 771: $b1=$b+1;
! 772: $h1=$h+1;
! 773: #$out =~ s/^(\d+,\d+,)(\d+)/\1$b1/;
! 774: &setbaseline($out,$b1);
! 775: $out[$#out]=&join("$h1,2,$b1,0, +\n" . (" |\n" x ($h-1)) . '\|',$out);
! 776: warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow;
! 777: &finish(1,1);
! 778: }
! 779:
! 780: # Takes the last two records, returns a record that contains them and forms
! 781: # fraction block
! 782:
! 783: sub f_fraction {
! 784: warn "Entering f_fraction...\n" if $debug & $debug_flow;
! 785: &trim(2);
! 786: &collapse(2);
! 787: &assertHave(2) || &finish("",1);
! 788: warn "Numer `$out[$#out-1]'\nDenom `$out[$#out]'\n__END__\n" if $debug & $debug_record;
! 789: local($l1,$l2)=(&length($out[$#out-1]),&length($out[$#out]));
! 790: local($len)=(($l1>$l2 ? $l1: $l2));
! 791: $out[$#out-1]=&vStack(&vStack(¢er($len,$out[$#out-1]),
! 792: &string2record("-" x $len)),
! 793: ¢er($len,$out[$#out]));
! 794: $#chunks--;
! 795: $#out--;
! 796: warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow;
! 797: &finish(2,1);
! 798: }
! 799:
! 800: sub f_choose {
! 801: warn "Entering f_choose...\n" if $debug & $debug_flow;
! 802: &trim(2);
! 803: &collapse(2);
! 804: &assertHave(2) || &finish("",1);
! 805: warn "Numer `$out[$#out-1]'\nDenom `$out[$#out]'\n__END__\n" if $debug & $debug_record;
! 806: local($l1,$l2)=(&length($out[$#out-1]),&length($out[$#out]));
! 807: local($len)=(($l1>$l2 ? $l1: $l2));
! 808: $out[$#out]=&vStack(&vStack(¢er($len,$out[$#out-1]),
! 809: &string2record(" " x $len)),
! 810: ¢er($len,$out[$#out]));
! 811: $#chunks++;
! 812: $#out++;
! 813: #warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow;
! 814: $out[$#out - 2] = &string2record("(");
! 815: $out[$#out] = &string2record(")");
! 816: local($h,$b)=($out[$#out-1] =~ /^(\d+),\d+,(\d+)/)[0,1];
! 817: &makehigh($out[$#out-2],$h,$b,0,1);
! 818: &makehigh($out[$#out],$h,$b,1,0);
! 819: &finish(2,1);
! 820: }
! 821:
! 822:
! 823: sub f_buildrel {
! 824: warn "Entering f_buildrel...\n" if $debug & $debug_flow;
! 825: &trim(3);
! 826: &collapse(3);
! 827: &assertHave(3) || &finish("",1);
! 828: warn "What: $out[$#out-2]\nOver $out[$#out]\n__END__\n" if $debug & $debug_record;
! 829: local($rec)=($out[$#out-2]);
! 830: $out[$#out-2]=$out[$#out];
! 831: $#chunks-=2;
! 832: $#out-=2;
! 833: &f_putover($rec,1);
! 834: warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow;
! 835: &finish(3,1);
! 836: }
! 837:
! 838: # Takes two records, returns a record that contains them and forms a
! 839: # fraction block
! 840:
! 841: sub fraction {
! 842: local($l1,$l2)=(&length($_[0]),&length($_[1]));
! 843: local($len)=(($l1>$l2 ? $l1: $l2));
! 844: return &vStack(&vStack(¢er($len,shift),
! 845: &string2record("-" x $len)),
! 846: ¢er($len,shift));
! 847: }
! 848:
! 849: # Commits a given string
! 850:
! 851: sub puts {
! 852: &commit(&string2record);
! 853: }
! 854:
! 855: # digests an eaten paragraph
! 856:
! 857: sub paragraph {
! 858: local($par);
! 859: $par=<>;
! 860: return 0 unless defined $par;
! 861: return 1 unless $par =~ /\S/; # whitespace only
! 862: print "\n" if $secondtime++ && !$opt_by_par;
! 863: #$par =~ s/(^|[^\\])%.*\n[ \t]*/\1/g;
! 864: $par =~ s/((^|[^\\])(\\\\)*)(%.*\n[ \t]*)+/\1/g;
! 865: $par =~ s/\n\s*\n/\\par /g;
! 866: $par =~ s/\s+/ /g;
! 867: $par =~ s/\s+$//;
! 868: $par =~ s/(\$\$)\s+/\1/g;
! 869: $par =~ s/\\par\s*$//;
! 870: local($defcount,$piece,$pure,$type,$sub,@t,$arg)=(0);
! 871: &commit("1,5,0,0, ")
! 872: unless $opt_noindent || ($par =~ s/^\s*\\noindent\s*([^a-zA-Z\s]|$)/\1/);
! 873: while ($tokenByToken[$#level] ?
! 874: ($par =~ s/^\s*($tokenpattern)//o): ($par =~ s/^($multitokenpattern)//o)) {
! 875: warn "tokenByToken=$tokenByToken[$#level], eaten=`$1'\n"
! 876: if $debug & $debug_parsing;
! 877: if (($piece=$1) =~ /^$usualtokenclass/o) {
! 878: # plain piece
! 879: &puts($piece);
! 880: } else {
! 881: # macro or delimiter
! 882: ($pure = $piece) =~ s/\s+$//;
! 883: if (defined ($type=$type{$pure})) {
! 884: if ($type eq "def") {
! 885: warn "To many def expansions in a paragraph" if $defcount++==$maxdef;
! 886: last if $defcount>$maxdef;
! 887: @t=(0);
! 888: for (1..$args{$pure}) {
! 889: push(@t,&get_balanced());
! 890: }
! 891: warn "Defined token `$pure' found with $args{$pure} arguments @t[1..$#t]\n"
! 892: if $debug & $debug_parsing;
! 893: $sub=$def{$pure};
! 894: $sub =~ s/(^|[^\\#])#(\d)/$1 . $t[$2]/ge if $args{$pure};
! 895: $par=$sub . $par;
! 896: } elsif ($type eq "sub") {
! 897: $sub=$contents{$pure};
! 898: index($sub,";")>=0?
! 899: (($sub,$arg)=split(";",$sub,2), &$sub($pure,$arg)):
! 900: &$sub($pure);
! 901: } elsif ($type =~ /^sub(\d+)$/) {
! 902: &start($1,"f_$contents{$pure}");
! 903: $tokenByToken[$#level]=1;
! 904: } elsif ($type =~ /^get(\d+)$/) {
! 905: &start($1+1);
! 906: &puts($piece);
! 907: $tokenByToken[$#level]=1;
! 908: } elsif ($type =~ /^discard(\d+)$/) {
! 909: &start($1,"f_discard");
! 910: $tokenByToken[$#level]=1;
! 911: } elsif ($type eq "record") {
! 912: &commit($contents{$pure});
! 913: } elsif ($type eq "self") {
! 914: &puts(substr($pure,1) . ($pure =~ /^\\[a-zA-Z]/ ? " ": ""));
! 915: } elsif ($type eq "par_self") {
! 916: &finishBuffer;
! 917: &commit("1,5,0,0, ");
! 918: &puts($pure . ($pure =~ /^\\[a-zA-Z]/ ? " ": ""));
! 919: } elsif ($type eq "self_par") {
! 920: &puts($pure . ($pure =~ /^\\[a-zA-Z]/ ? " ": ""));
! 921: &finishBuffer;
! 922: &commit("1,5,0,0, ")
! 923: unless $par =~ s/^\s*\\noindent(\s+|([^a-zA-Z\s])|$)/\2/;
! 924: } elsif ($type eq "string") {
! 925: &puts($contents{$pure},1);
! 926: } elsif ($type eq "nothing") {
! 927: } else {
! 928: warn "Error with type `$type' while interpreting `$pure'";
! 929: }
! 930: } else {
! 931: &puts($piece);
! 932: }
! 933: }
! 934: }
! 935: warn "Unrecognized part of input `$par',\n\ttoken-by-token[$#level]=$tokenByToken[$#level]"
! 936: if $par ne "";
! 937: &finishBuffer if $#out>=0;
! 938: # return 0 if eof();
! 939: 1;
! 940: }
! 941:
! 942: sub subscript {
! 943: &start(1,"f_subscript");
! 944: $tokenByToken[$#level]=1;
! 945: }
! 946:
! 947: sub superscript {
! 948: &start(1,"f_superscript");
! 949: $tokenByToken[$#level]=1;
! 950: }
! 951:
! 952:
! 953: sub f_subscript {
! 954: $wait[$#level]=2;
! 955: $action[$#level]="f_subSuper";
! 956: if (($par !~ s/^\s*\^//) &&
! 957: ($par !~ s:^\s*\\begin\s*\{Sp\}:\\begin\{matrix\}:)) {
! 958: &commit(&empty);
! 959: }
! 960: }
! 961:
! 962: sub f_overline {
! 963: warn "Entering f_overline...\n" if $debug & $debug_flow;
! 964: &trim(1);
! 965: &collapse(1);
! 966: &assertHave(1) || &finish("",1);
! 967: warn "Overlining $out[$#out]\n__END__\n" if $debug & $debug_record;
! 968: local($h,$len,$b)=($out[$#out] =~ /^(\d+),(\d+),(\d+)/);
! 969: $out[$#out]=&vStack(&string2record("_" x $len),
! 970: $out[$#out]);
! 971: $b++;
! 972: #$out[$#out] =~ s/^(\d+,\d+,)(\d+)/\1$b/;
! 973: &setbaseline($out[$#out],$b);
! 974: warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow;
! 975: &finish(1,1);
! 976: }
! 977:
! 978: sub f_underline {
! 979: warn "Entering f_underline...\n" if $debug & $debug_flow;
! 980: &trim(1);
! 981: &collapse(1);
! 982: &assertHave(1) || &finish("",1);
! 983: warn "Underlining $out[$#out]\n__END__\n" if $debug & $debug_record;
! 984: local($h,$len,$b)=($out[$#out] =~ /^(\d+),(\d+),(\d+)/);
! 985: $out[$#out]=&vStack($out[$#out],&string2record("_" x $len));
! 986: #$out[$#out] =~ s/^(\d+,\d+,)(\d+)/\1$b/;
! 987: &setbaseline($out[$#out],$b);
! 988: warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow;
! 989: &finish(1,1);
! 990: }
! 991:
! 992: sub f_not {
! 993: warn "Entering f_not...\n" if $debug & $debug_flow;
! 994: &collapse(1);
! 995: &assertHave(1) || &finish("",1);
! 996: warn "Negating $out[$#out]\n__END__\n" if $debug & $debug_record;
! 997: local($str)=(split(/,/,$out[$#out]))[4];
! 998: if ($str eq "=") {
! 999: $out[$#out]=$contents{"\\neq"};
! 1000: } elsif ($str =~ /^\s*\|\s*$/) {
! 1001: $out[$#out]=$contents{"\\nmid"};
! 1002: } elsif ($out[$#out] eq $contents{"\\in"}) {
! 1003: $out[$#out]=$contents{"\\notin"};
! 1004: } else {
! 1005: $out[$#out]=&join(&string2record("\\not"),$out[$#out]);
! 1006: }
! 1007: warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow;
! 1008: &finish(1,1);
! 1009: }
! 1010:
! 1011: sub f_putunder {
! 1012: warn "Entering f_putunder...\n" if $debug & $debug_flow;
! 1013: &trim(1);
! 1014: &collapse(1);
! 1015: &assertHave(1) || &finish("",1);
! 1016: warn "Putting Under $out[$#out]\n__END__\n" if $debug & $debug_record;
! 1017: local($h,$len,$b)=($out[$#out] =~ /^(\d+),(\d+),(\d+)/);
! 1018: local($l2)=(&length($_[0]));
! 1019: local($len)=(($l1>$l2 ? $l1: $l2));
! 1020: $out[$#out]=&vStack(¢er($len,$out[$#out]),¢er($len,shift));
! 1021: #$out[$#out] =~ s/^(\d+,\d+,)(\d+)/\1$b/;
! 1022: &setbaseline($out[$#out],$b);
! 1023: warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow;
! 1024: &finish(1,1);
! 1025: }
! 1026:
! 1027: # if has additional true argument will not finish
! 1028: # Takes record to put over
! 1029:
! 1030: sub f_putover {
! 1031: warn "Entering f_putover...\n" if $debug & $debug_flow;
! 1032: &trim(1);
! 1033: &collapse(1);
! 1034: &assertHave(1) || &finish("",1);
! 1035: warn "Putting Over $out[$#out]\n__END__\n" if $debug & $debug_record;
! 1036: local($h,$l1,$b,$b1)=($out[$#out] =~ /^(\d+),(\d+),(\d+)/);
! 1037: local($l2)=(&length($_[0]));
! 1038: local($len)=(($l1>$l2 ? $l1: $l2));
! 1039: ($b1)=($_[0] =~ /^(\d+)/);
! 1040: $b+=$b1+1;
! 1041: $out[$#out]=&vStack(¢er($len,shift),¢er($len,$out[$#out]));
! 1042: #$out[$#out] =~ s/^(\d+,\d+,)(\d+)/\1$b/;
! 1043: &setbaseline($out[$#out],$b);
! 1044: warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow;
! 1045: &finish(1,1) unless shift;
! 1046: }
! 1047:
! 1048: sub f_putpar {
! 1049: warn "Entering f_putpar...\n" if $debug & $debug_flow;
! 1050: &trim(1);
! 1051: local($l,$r)=split(";",shift);
! 1052: &collapse(1);
! 1053: &assertHave(1) || &finish("",1);
! 1054: warn "Putting Parentheses $out[$#out]\n__END__\n" if $debug & $debug_record;
! 1055: $out[$#out]=&join(&string2record($l),
! 1056: &join($out[$#out],&string2record($r)));
! 1057: &finish(1,1);
! 1058: }
! 1059:
! 1060: sub f_putover_string {
! 1061: &f_putover(&string2record);
! 1062: }
! 1063:
! 1064: sub f_widehat {
! 1065: &trim(1);
! 1066: &collapse(1);
! 1067: local($l)=(&length($out[$#out]));
! 1068: if ($l<=1) {&f_putover(&string2record("^"));}
! 1069: else {&f_putover(&string2record("/" . "~" x ($l-2) . "\\"));}
! 1070: }
! 1071:
! 1072: sub f_widetilde {
! 1073: &trim(1);
! 1074: &collapse(1);
! 1075: local($l,$l1)=(&length($out[$#out]));
! 1076: if ($l<=1) {&f_putover(&string2record("~"));}
! 1077: elsif ($l<=3) {&f_putover(&string2record("/\\/"));}
! 1078: else {&f_putover(&string2record("/" . "~" x ($l1=int($l/2-1)) .
! 1079: "\\" . "_" x ($l-3-$l1) . "/"));}
! 1080: }
! 1081:
! 1082: sub f_superscript {
! 1083: $wait[$#level]=2;
! 1084: $action[$#level]="f_superSub";
! 1085: if (($par !~ s/^\s*\_//) &&
! 1086: ($par !~ s:^\s*\\begin\s*\{Sb\}:\\begin\{matrix\}:)) {
! 1087: &commit(&empty);
! 1088: }
! 1089: }
! 1090:
! 1091: sub let {
! 1092: $par =~ s/^($tokenpattern)(= ?)?($tokenpattern)//o;
! 1093: }
! 1094:
! 1095: sub let_exp {
! 1096: $par =~ s/^($tokenpattern)(= ?)?($tokenpattern)//o;
! 1097: return if index($&,'@')>=0;
! 1098: local($what)=$1;
! 1099: $type{$what}='def';
! 1100: $& =~ /($tokenpattern)$/;
! 1101: $def{$what}=$1;
! 1102: $args{$what}=0;
! 1103: warn "Definition of `$what' with $args{$what} args is `$def{$what}'\n"
! 1104: if $debug & $debug_parsing;
! 1105: }
! 1106:
! 1107:
! 1108: sub def {
! 1109: $par =~ s/^[^{]*//;
! 1110: &start(1,"f_discard");
! 1111: $tokenByToken[$#level]=1;
! 1112: }
! 1113:
! 1114: sub def_exp {
! 1115: return unless $par =~ s:^(([^\\{]|\\.)*)\{:\{:;
! 1116: local($arg)=($1);
! 1117: local($def,$act)=(&get_balanced());
! 1118: return unless defined $def;
! 1119: return if index("$arg$def",'@')>=0;
! 1120: return if $def =~ /\\([egx]?def|fi)([^a-zA-Z]|$)/;
! 1121: $def .= " " if $def =~ /($macro)$/o;
! 1122: &define($arg,$def);
! 1123: }
! 1124:
! 1125: # Arguments: Token . Parameters, Expansion
! 1126:
! 1127: sub define {
! 1128: local($arg,$def,$act)=(shift,shift);
! 1129: return unless $arg =~ /^($active)/o;
! 1130: $act=$1;
! 1131: $args{$act}=$';
! 1132: return unless $args{$act} =~ /^(#\d)*$/;
! 1133: $args{$act}=length($args{$act})/2;
! 1134: $def{$act}=$def;
! 1135: $type{$act}='def';
! 1136: warn "Definition of `$act' with $args{$act} args is `$def'\n"
! 1137: if $debug & $debug_parsing;
! 1138: }
! 1139:
! 1140: sub defb {
! 1141: for (@_) {
! 1142: &define("\\$_","\\begin{$_}");&define("\\end$_","\\end{$_}");
! 1143: }
! 1144: }
! 1145:
! 1146: # Discards surrounding {}
! 1147:
! 1148: sub get_balanced {
! 1149: return undef unless $par =~ s/^($tokenpattern)//;
! 1150: return $1 unless $1 eq '{';
! 1151: local($def,$lev)=('',1);
! 1152: while ($lev) {
! 1153: last unless $par =~ s/^[^\\{}]|\\.|[{}]//;
! 1154: $lev++ if $& eq '{';
! 1155: $lev-- if $& eq '}';
! 1156: $def .= $& if $lev;
! 1157: }
! 1158: (warn "Balanced text not finished!",return undef) if $lev;
! 1159: return $def;
! 1160: }
! 1161:
! 1162:
! 1163: sub open_curly {
! 1164: #&puts("{") unless $tokenByToken[$#level];
! 1165: &start("}");
! 1166: }
! 1167:
! 1168: # Deletes extra spaces at the end of a record
! 1169:
! 1170: sub trim_end {
! 1171: local($h,$str)=(split(/,/,$_[0],5))[0,4];
! 1172: if (!$h) {
! 1173: $str =~ s/\s+$//;
! 1174: $_[0]=&string2record($str);
! 1175: warn "Trimmed End `$_[0]'\n__END__\n" if $debug & $debug_record;
! 1176: }
! 1177: }
! 1178:
! 1179: # Deletes extra spaces at the beginning of a record
! 1180:
! 1181: sub trim_beg {
! 1182: local($h,$str)=(split(/,/,$_[0],5))[0,4];
! 1183: if (!$h) {
! 1184: $str =~ s/^\s+//;
! 1185: $_[0]=&string2record($str);
! 1186: warn "Trimmed Beg `$_[0]'\n__END__\n" if $debug & $debug_record;
! 1187: }
! 1188: }
! 1189:
! 1190: # Deletes extra spaces at the ends of a chunk with given number
! 1191:
! 1192: sub trim_one {
! 1193: &trim_beg($out[$chunks[$_[0]]]);
! 1194: &trim_end($_[0]==$#chunks? $out[$#out]: $out[$chunks[$_[0]+1]-1]);
! 1195: }
! 1196:
! 1197: # Deletes extra spaces at the ends of a given number of chunks
! 1198:
! 1199: sub trim {
! 1200: for ($#chunks-$_[0]+1..$#chunks) {&trim_one($_);}
! 1201: }
! 1202:
! 1203: sub dollar {
! 1204: if ($wait[$#level] eq '$') { # ';
! 1205: &trim_end($out[$#out]);
! 1206: &finish('$');
! 1207: }
! 1208: else {
! 1209: &start('$');
! 1210: $par =~ s/^\s+//;
! 1211: }
! 1212: }
! 1213:
! 1214: sub ddollar {
! 1215: if ($wait[$#level] eq '$$') {
! 1216: &trim_end($out[$#out]);
! 1217: &finish('$$');
! 1218: return unless $#out>=0;
! 1219: $#chunks=0;
! 1220: $chunks[0]=0;
! 1221: &trim(1);
! 1222: &collapse(1);
! 1223: &printrecord(¢er($linelength,$out[0]));
! 1224: @level=(0);
! 1225: @chunks=(0);
! 1226: @tokenByToken=(0);
! 1227: @out=();
! 1228: $curlength=0;
! 1229: # Maybe after \begin{align}
! 1230: }
! 1231: else {
! 1232: &finishBuffer;
! 1233: &start('$$');
! 1234: }
! 1235: $par =~ s/^\s+//;
! 1236: }
! 1237:
! 1238: sub item {
! 1239: &finishBuffer;
! 1240: # To make unexpandable:
! 1241: &commit("1,11,0,0, (\@) ");
! 1242: }
! 1243:
! 1244: sub bbackslash {
! 1245: if ($wait[$#level] eq '$$') {
! 1246: &ddollar();
! 1247: &ddollar();
! 1248: } elsif ($wait[$#level] eq 'endCell') {
! 1249: return if $par =~ /^\s*\\end/; # Ignore the last one
! 1250: &finish('endCell', 1);
! 1251: &trim(1);
! 1252: &collapse(1);
! 1253: &finish('endRow', 1);
! 1254: &start('endRow');
! 1255: &start('endCell');
! 1256: } else {
! 1257: #&puts(" \\\\ ");
! 1258: ∥
! 1259: }
! 1260: }
! 1261:
! 1262: sub ampersand {
! 1263: if ($wait[$#level] eq 'endCell') {
! 1264: &finish('endCell',1);
! 1265: &trim(1);
! 1266: &collapse(1);
! 1267: &start('endCell');
! 1268: }
! 1269: }
! 1270:
! 1271: sub matrix {
! 1272: &start('endMatrix');
! 1273: &start('endRow');
! 1274: &start('endCell');
! 1275: }
! 1276:
! 1277: sub endmatrix {
! 1278: &finish('endCell',1);
! 1279: &trim(1);
! 1280: &collapse(1);
! 1281: &finish('endRow',1);
! 1282: # Now chunks correspond to rows of the matrix, records inside chunks to
! 1283: # Cells
! 1284: &halign(split(";",shift));
! 1285: &finish('endMatrix',1);
! 1286: }
! 1287:
! 1288: sub endmatrixArg {
! 1289: &endmatrix(join(";",($_[0],split("",pop(@argStack)))));
! 1290: }
! 1291:
! 1292: # Takes a matrix in the following form: chunks on the last level
! 1293: # are row of the matrix, records inside chunks are cells.
! 1294: # Puts the resulting matrix in the first record on the given level
! 1295: # and truncates the rest
! 1296:
! 1297: # I'm trying to add parameters:
! 1298: # length to insert between columns
! 1299: # Array of centering options one for a column (last one repeated if needed)
! 1300: # Currently supported: c for center
! 1301: # r for right
! 1302: # l for left
! 1303:
! 1304: sub halign {
! 1305: local($explength)=(shift);
! 1306: local(@c)=@_;
! 1307: local($last,$le,$b,$h);
! 1308: local(@w)=();
! 1309: #warn "levels @level, chunks @chunks, records @out\n";
! 1310: # Find metrics of cells
! 1311: for $r (0..$#chunks-$level[$#level]) {
! 1312: $last= ($r==$#chunks-$level[$#level]) ? $#out:
! 1313: $chunks[$r+1+$level[$#level]]-1;
! 1314: warn "Row $r: last column " . ($last-$chunks[$r+$level[$#level]]) ."\n"
! 1315: if $debug & $debug_matrix;
! 1316: for $c (0..$last-$chunks[$r+$level[$#level]]) {
! 1317: ($h,$le,$b)=
! 1318: ($out[$chunks[$r+$level[$#level]]+$c] =~ /(\d+),(\d+),(\d+)/);
! 1319: # Format is Height:Length:Baseline
! 1320: $w[$c]=$le unless $w[$c]>$le;
! 1321: }
! 1322: }
! 1323: # expand the height and depth
! 1324: for $c (0..$#w-1) {$w[$c]+=$explength;}
! 1325: # Extend the @c array by the last element or "c" if it is empty
! 1326: @c=("c") x @w unless @c;
! 1327: @c=(@c,($c[$#c]) x (@w-@c));
! 1328: # Now expand the cells
! 1329: warn "Widths of columns @w\n" if $debug & $debug_matrix;
! 1330: for $r (0..$#chunks-$level[$#level]) {
! 1331: $last= ($r==$#chunks-$level[$#level]) ? $#out:
! 1332: $chunks[$r+1+$level[$#level]]-1;
! 1333: warn "Row $r: last column " . ($last-$chunks[$r+$level[$#level]]) ."\n"
! 1334: if $debug & $debug_matrix;
! 1335: for $c (0..$last-$chunks[$r+$level[$#level]]) {
! 1336: if ($c[$c] eq "c") {
! 1337: warn "Centering row $r col $c to width $w[$c]\n"
! 1338: if $debug & $debug_matrix;
! 1339: $out[$chunks[$r+$level[$#level]]+$c]=
! 1340: ¢er($w[$c],$out[$chunks[$r+$level[$#level]]+$c]);
! 1341: } elsif ($c[$c] eq "l") {
! 1342: warn "Expanding row $r col $c to width $w[$c]\n"
! 1343: if $debug & $debug_matrix;
! 1344: $out[$chunks[$r+$level[$#level]]+$c]=
! 1345: &join($out[$chunks[$r+$level[$#level]]+$c],
! 1346: &string2record(" " x
! 1347: ($w[$c] - &length($out[$chunks[$r+$level[$#level]]+$c]))));
! 1348: } elsif ($c[$c] eq "r") {
! 1349: warn "Expanding row $r col $c to width $w[$c] on the left\n"
! 1350: if $debug & $debug_matrix;
! 1351: $out[$chunks[$r+$level[$#level]]+$c]=
! 1352: &join(&string2record(" " x
! 1353: ($w[$c]-$explength-
! 1354: &length($out[$chunks[$r+$level[$#level]]+$c]))),
! 1355: $out[$chunks[$r+$level[$#level]]+$c]);
! 1356: $out[$chunks[$r+$level[$#level]]+$c]=
! 1357: &join($out[$chunks[$r+$level[$#level]]+$c],
! 1358: &string2record(" " x $explength));
! 1359: } else {warn "Unknown centering option `$c[$c]' for halign";}
! 1360: }
! 1361: }
! 1362: # Now we creat rows
! 1363: &collapseAll;
! 1364: # And stack them vertically
! 1365: for ($chunks[$level[$#level]]+1..$#out) {
! 1366: $out[$chunks[$level[$#level]]]=&vStack($out[$chunks[$level[$#level]]],
! 1367: $out[$_]);
! 1368: }
! 1369: &setbaseline($out[$chunks[$level[$#level]]],
! 1370: int((&height($out[$chunks[$level[$#level]]])-1)/2));
! 1371: $#chunks=$level[$#level];
! 1372: $#out=$chunks[$level[$#level]];
! 1373: }
! 1374:
! 1375: sub close_curly {
! 1376: &finish("}");
! 1377: #&puts("}") unless $tokenByToken[$#level]; # well, this can change under our foot...
! 1378: }
! 1379:
! 1380: sub at {
! 1381: local($c,$first,$second,$t,$m)=($par =~ /^(.)/);
! 1382: if ($c eq '@') {&puts('@');$par =~ s/^.//;}
! 1383: elsif (index("<>AV",$c)>=0) {
! 1384: $m="&" if ($wait[$#level] eq 'endCell');
! 1385: $m="&&" if $m eq "&" && index("AV",$c)>=0;
! 1386: &ersand if $m eq "&";
! 1387: $par =~ s/^.//;
! 1388: $first=$second="";
! 1389: while (($t=&get_balanced()) ne $c && defined $t) {
! 1390: $first .= $t;
! 1391: }
! 1392: while (($t=&get_balanced()) ne $c && defined $t) {
! 1393: $second .= $t;
! 1394: }
! 1395: $par="{$first}{$second}$m" . $par;
! 1396: local($l,$r);
! 1397: ($l=$c) =~ tr/A>V/^/d;
! 1398: ($r=$c) =~ tr/<A//d;
! 1399: index("<>",$c)>=0 ?
! 1400: &start(2,"f_arrow;$l;$r"):
! 1401: &start(2,"f_arrow_v;$l;$r");
! 1402: }
! 1403: elsif ($c eq "." && $wait[$#level] eq 'endCell') {
! 1404: &ersand;
! 1405: &ersand;
! 1406: $par =~ s/^.//;
! 1407: }
! 1408: else {&puts('@');}
! 1409: }
! 1410:
! 1411: # takes two tips of arrow as argument separated by ";",
! 1412: # we assume that total length is 1
! 1413:
! 1414: sub f_arrow {
! 1415: warn "Entering f_arrow...\n" if $debug & $debug_flow;
! 1416: local($l,$r)=split(";",shift);
! 1417: &trim(2);
! 1418: &collapse(2);
! 1419: &assertHave(2) || &finish("",1);
! 1420: warn "Over: $out[$#out-1]\nUnder: $out[$#out]\n__END__\n" if $debug & $debug_record;
! 1421: local($l1,$l2)=(&length($out[$#out-1]),&length($out[$#out]));
! 1422: local($len)=(($l1>$l2 ? $l1: $l2));
! 1423: $out[$#out-1]=&vStack(&vStack(¢er($len+4,$out[$#out-1]),
! 1424: &string2record(" $l" ."-" x ($len+1) . "$r ")),
! 1425: ¢er($len+4,$out[$#out]));
! 1426: $#chunks--;
! 1427: $#out--;
! 1428: warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow;
! 1429: &finish(2,1);
! 1430: }
! 1431:
! 1432: # takes two tips of arrow as argument separated by ";",
! 1433: # we assume that total length is 1
! 1434:
! 1435: sub f_arrow_v {
! 1436: warn "Entering f_arrow_v...\n" if $debug & $debug_flow;
! 1437: local($l,$r)=split(";",shift);
! 1438: &trim(2);
! 1439: &collapse(2);
! 1440: &assertHave(2) || &finish("",1);
! 1441: warn "Over: $out[$#out-1]\nUnder: $out[$#out]\n__END__\n" if $debug & $debug_record;
! 1442: local($h1,$b1)=($out[$#out-1] =~ /^(\d+),\d+,(\d+)/);
! 1443: local($h2,$b2)=($out[$#out] =~ /^(\d+),\d+,(\d+)/);
! 1444: local($b)=(($b1>$b2 ? $b1: $b2));
! 1445: local($res)=(&join($out[$#out-1],$out[$#out]));
! 1446: local($h,$bb)=($res =~ /^(\d+),\d+,(\d+)/);
! 1447: $bb=$b+1;
! 1448: $out[$#out-1]=&vStack(&vputs(" " x ($b-$b1+1)),
! 1449: $out[$#out-1]);
! 1450: #$out[$#out-1] =~ s/^(\d+,\d+,)(\d+)/\1$bb/;
! 1451: &setbaseline($out[$#out-1],$bb);
! 1452: $out[$#out]=&vStack(&vputs(" " x ($b-$b2+1)),
! 1453: $out[$#out]);
! 1454: #$out[$#out] =~ s/^(\d+,\d+,)(\d+)/\1$bb/;
! 1455: &setbaseline($out[$#out],$bb);
! 1456: $out[$#out-1]=&join(&join($out[$#out-1],
! 1457: &vputs($l ."|" x ($h+1) . $r,$b+1)),
! 1458: $out[$#out]);
! 1459: $#chunks--;
! 1460: $#out--;
! 1461: warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow;
! 1462: &finish(2,1);
! 1463: }
! 1464:
! 1465: sub noindent {
! 1466: if ($#out == 0 && $#chunks == 0 && $out[$#out] eq '1,5,0,0, ') {
! 1467: $#out--;
! 1468: $#chunks--;
! 1469: } else {
! 1470: &puts('\\noindent');
! 1471: }
! 1472: }
! 1473:
! 1474: # put strings vertically, returns a record with the second argument as baseline
! 1475:
! 1476: sub vputs {
! 1477: local($b)=($_[1]);
! 1478: $b=0 unless defined $b;
! 1479: return length($_[0]) . ",1,$b,0," . join("\n",split('',$_[0]));
! 1480: }
! 1481:
! 1482: sub choose {
! 1483: if ($wait[$#level] eq '}') {
! 1484: local($prevw)=($wait[$#level-1]);
! 1485: $wait[$#level-1]="junk";
! 1486: &finish("}",1);
! 1487: &collapse(1);
! 1488: &assertHave(1) || &finish("",1);
! 1489: local($rec)=$out[$#out];
! 1490: $#out--;
! 1491: $#chunks--;
! 1492: &start(2,"f_choose");
! 1493: $wait[$#level-1]=$prevw;
! 1494: &start("}");
! 1495: &commit($rec);
! 1496: &finish("}",1);
! 1497: &start("}");
! 1498: } else {&puts("\\choose");}
! 1499: }
! 1500:
! 1501: sub over {
! 1502: if ($wait[$#level] eq '}') {
! 1503: local($prevw)=($wait[$#level-1]);
! 1504: $wait[$#level-1]="junk";
! 1505: &finish("}", 1);
! 1506: &collapse(1);
! 1507: &assertHave(1) || &finish("",1);
! 1508: local($rec)=$out[$#out];
! 1509: $#out--;
! 1510: $#chunks--;
! 1511: &start(2,"f_fraction");
! 1512: $wait[$#level-1]=$prevw;
! 1513: &start("}");
! 1514: &commit($rec);
! 1515: &finish("}",1);
! 1516: &start("}");
! 1517: } else {&puts("\\over");}
! 1518: }
! 1519:
! 1520: # Takes a record, height, baseline, spaces_toleft and _toright
! 1521: # and makes this record this high
! 1522:
! 1523: sub makehigh {
! 1524: local($str)=(split(",",$_[0],5))[4];
! 1525: local($h,$b,$d)=($_[1],$_[2]+1);
! 1526: warn "Entering makehigh(@_)\n" if $debug & $debug_flow;
! 1527: if ($str eq ".") {$_[0] =~ s/\.$/ /;return;}
! 1528: #$str="<" if $str eq "\\langle";
! 1529: #$str=">" if $str eq "\\rangle";
! 1530: $h=1 unless $h;
! 1531: $d=$h-$b;
! 1532: return if $h<2 || $h==2 && index("()<>",$str)>=0;
! 1533: local(@c);
! 1534: if ($str eq "(") {@c=split(":",'(: :|:/:\:|');}
! 1535: elsif ($str eq ")") {@c=split(":",'): :|:\:/:|');}
! 1536: elsif ($str eq "{") {@c=split(":",'{: :|:/:\:<');}
! 1537: elsif ($str eq "}") {@c=split(":",'}: :|:\:/:>');}
! 1538: elsif ($str eq "|" && $str eq "||")
! 1539: {@c=split(":",'|:|:|:|:|:|');}
! 1540: elsif ($str eq "[") {@c=split(":",'[:[:|:[:[:|');}
! 1541: elsif ($str eq "]") {@c=split(":",']:]:|:]:]:|');}
! 1542: elsif ($str eq "<" || $str eq ">") {
! 1543: return if $h==2;
! 1544: local($l)=($b);
! 1545: $l=$d+1 if $b<$d+1;
! 1546: for (2..$l) {
! 1547: $_[0]=&join($_[0],
! 1548: &vputs("/" . " " x (2*$_-3) . "\\",$_-1)) if $str eq "<";
! 1549: $_[0]=&join(&vputs("\\" . " " x (2*$_-3) . "/",$_-1),
! 1550: $_[0]) if $str eq ">";
! 1551: }
! 1552: $_[0]=&join($_[0],&string2record(" ")) if $str eq "<";
! 1553: $_[0]=&join(&string2record(" "),$_[0]) if $str eq ">";
! 1554: return;
! 1555: }
! 1556: else {return;}
! 1557: $_[0]=&vputs(&makecompound($b,$d,@c),$b-1);
! 1558: $_[0]=&join($_[0],$_[0]) if length($str)==2;
! 1559: $_[0]=&join(&string2record(" " x $_[3]),$_[0]) if $_[3];
! 1560: $_[0]=&join($_[0],&string2record(" " x $_[4])) if $_[4];
! 1561: }
! 1562:
! 1563:
! 1564: sub right {
! 1565: &finish("LeftRight",1);
! 1566: &trim(1);
! 1567: &collapse(1);
! 1568: }
! 1569:
! 1570: sub f_left {
! 1571: &trim(1);
! 1572: &collapse(1);
! 1573: &finish(1);
! 1574: &start("LeftRight");
! 1575: }
! 1576:
! 1577: sub left {
! 1578: &start(3,"f_leftright");
! 1579: $tokenByToken[$#level]=1;
! 1580: &start(1,"f_left");
! 1581: $tokenByToken[$#level]=1;
! 1582: }
! 1583:
! 1584: sub f_leftright_go {
! 1585: &trim(1);
! 1586: &collapse(1);
! 1587: local($l,$r)=split(";",shift);
! 1588: &assertHave(1) || warn "Left-Right not balanced";
! 1589: local($rec)=($out[$#out]);
! 1590: $#out--;
! 1591: $wait[$#level]="junk";
! 1592: &start(3,"f_leftright");
! 1593: &puts($l);
! 1594: &commit($rec);
! 1595: &puts($r);
! 1596: &finish("junk");
! 1597: }
! 1598:
! 1599: sub beg_lr {
! 1600: &start(1,"f_leftright_go" . ";" . shift);
! 1601: $tokenByToken[$#level]=1;
! 1602: }
! 1603:
! 1604: sub f_leftright {
! 1605: &trim(1);
! 1606: &collapse(1);
! 1607: &assertHave(3) || warn "Left-Right not balanced";
! 1608: local($h,$b)=($out[$#out-1] =~ /^(\d+),\d+,(\d+)/)[0,1];
! 1609: &makehigh($out[$#out-2],$h,$b,0,1);
! 1610: &makehigh($out[$#out],$h,$b,1,0);
! 1611: &finish(3);
! 1612: }
! 1613:
! 1614: # Arguments: Ascent, descent, base string, oneside expander, real expander
! 1615: # 0 1 2 3 4
! 1616: # Top tip, Bottom tip, Mid
! 1617: # 5 6 7
! 1618: # All component should be one character long
! 1619:
! 1620: sub makecompound {
! 1621: # If Mid is the same as real expander, all depends on the height only
! 1622: # if there is extend on both sides
! 1623: # If it is 3 or more
! 1624: if ($_[0]>1 && $_[1]>0 && $_[4] eq $_[7]) {
! 1625: return $_[5] . $_[4] x ($_[0]+$_[1]-2) . $_[6];
! 1626: }
! 1627: # No descent:
! 1628: if ($_[1] <= 0) {return $_[3] x ($_[0]-1) . $_[2];}
! 1629: # No ascent:
! 1630: if ($_[0] <= 1) {return $_[2] . $_[3] x $_[1];}
! 1631: local($mid,$asc,$des)=($_[2]);
! 1632: # descent == 1
! 1633: $des = ($_[1]==1) ? $_[2]: $_[4] x ($_[1]-1) . $_[6];
! 1634: $asc = ($_[0]==2) ? $_[2]: $_[5] . $_[4] x ($_[0]-2);
! 1635: $mid = $_[7] unless $_[0]==2 || $_[1]==1;
! 1636: return "$asc$mid$des";
! 1637: }
! 1638:
! 1639: sub arg2stack {push(@argStack,&get_balanced());}
! 1640:
! 1641: sub par {&finishBuffer;&commit("1,5,0,0, ")
! 1642: unless $par =~ s/^\s*\\noindent\s*(\s+|([^a-zA-Z\s])|$)/\2/;}
! 1643:
! 1644: $type{"\\sum"}="record";
! 1645: $contents{"\\sum"}="3,4,1,0," . <<'EOF';
! 1646: \~~
! 1647: >
! 1648: /__
! 1649: EOF
! 1650:
! 1651: $type{"\\int"}="record";
! 1652: $contents{"\\int"}="3,3,1,0," . <<'EOF';
! 1653: ,-
! 1654: |
! 1655: -'
! 1656: EOF
! 1657:
! 1658: $type{"\\prod"}="record";
! 1659: $contents{"\\prod"}="3,3,1,0," . <<'EOF';
! 1660: ___
! 1661: | |
! 1662: | |
! 1663: EOF
! 1664:
! 1665: $type{"\\Pi"}="record";
! 1666: $contents{"\\Pi"}="2,3,1,0," . <<'EOF';
! 1667: _
! 1668: | |
! 1669: EOF
! 1670:
! 1671: $type{"\\Sigma"}="record";
! 1672: $contents{"\\Sigma"}="3,2,1,0," . <<'EOF';
! 1673: __
! 1674: >
! 1675: ~~
! 1676: EOF
! 1677:
! 1678: $type{"\\Delta"}="record";
! 1679: $contents{"\\Delta"}="2,2,0,0," . <<'EOF';
! 1680: /\
! 1681: ~~
! 1682: EOF
! 1683:
! 1684: $type{"\\oplus"}="record";
! 1685: $contents{"\\oplus"}="3,5,1,0," . <<'EOF';
! 1686: _
! 1687: (+)
! 1688: ~
! 1689: EOF
! 1690:
! 1691: $type{"\\otimes"}="record";
! 1692: $contents{"\\otimes"}="3,5,1,0," . <<'EOF';
! 1693: _
! 1694: (x)
! 1695: ~
! 1696: EOF
! 1697:
! 1698: $type{"\\ominus"}="record";
! 1699: $contents{"\\ominus"}="3,5,1,0," . <<'EOF';
! 1700: _
! 1701: (-)
! 1702: ~
! 1703: EOF
! 1704:
! 1705: $type{"\\leq"}="record";
! 1706: $contents{"\\leq"}="2,4,1,0," . <<'EOF';
! 1707: _
! 1708: <
! 1709: EOF
! 1710:
! 1711: $type{"\\equiv"}="record";
! 1712: $contents{"\\equiv"}="2,4,1,0," . <<'EOF';
! 1713: _
! 1714: =
! 1715: EOF
! 1716:
! 1717: $type{"\\geq"}="record";
! 1718: $contents{"\\geq"}="2,4,1,0," . <<'EOF';
! 1719: _
! 1720: >
! 1721: EOF
! 1722:
! 1723: $type{"\\partial"}="record";
! 1724: $contents{"\\partial"}="2,2,1,0," . <<'EOF';
! 1725: \
! 1726: d
! 1727: EOF
! 1728:
! 1729: $type{"\\forall"}="record";
! 1730: $contents{"\\forall"}="3,4,1,0," . <<'EOF';
! 1731: \__/
! 1732: \/
! 1733: EOF
! 1734:
! 1735: $type{"\\exists"}="record";
! 1736: $contents{"\\exists"}="3,2,1,0," . <<'EOF';
! 1737: _.
! 1738: -|
! 1739: ~'
! 1740: EOF
! 1741:
! 1742: $type{"\\owns"}="record";
! 1743: $contents{"\\owns"}="3,4,1,0," . <<'EOF';
! 1744: _
! 1745: -)
! 1746: ~
! 1747: EOF
! 1748:
! 1749: $type{"\\ni"}="record";
! 1750: $contents{"\\ni"}="3,4,1,0," . <<'EOF';
! 1751: _
! 1752: -)
! 1753: ~
! 1754: EOF
! 1755:
! 1756: $type{"\\in"}="record";
! 1757: $contents{"\\in"}="3,4,1,0," . <<'EOF';
! 1758: _
! 1759: (-
! 1760: ~
! 1761: EOF
! 1762:
! 1763: $type{"\\notin"}="record";
! 1764: $contents{"\\notin"}="3,5,1,0," . <<'EOF';
! 1765: |_
! 1766: (|-
! 1767: |~
! 1768: EOF
! 1769:
! 1770: $type{"\\qed"}="record";
! 1771: $contents{"\\qed"}="2,6,1,0," . <<'EOF';
! 1772: _
! 1773: |_|
! 1774: EOF
! 1775:
! 1776: $type{"\\pm"}="record";
! 1777: $contents{"\\pm"}="2,1,0,0," . <<'EOF';
! 1778: +
! 1779: -
! 1780: EOF
! 1781:
! 1782: $type{"\\mp"}="record";
! 1783: $contents{"\\mp"}="2,1,1,0," . <<'EOF';
! 1784: _
! 1785: +
! 1786: EOF
! 1787:
! 1788: $type{"\\cong"}="record";
! 1789: $contents{"\\cong"}="2,1,0,0," . <<'EOF';
! 1790: =
! 1791: ~
! 1792: EOF
! 1793:
! 1794: $type{"\\neq"}="record";
! 1795: $contents{"\\neq"}="1,5,0,0," . <<'EOF';
! 1796: =/=
! 1797: EOF
! 1798:
! 1799: $type{"\\nmid"}="record";
! 1800: $contents{"\\nmid"}="3,3,1,0," . <<'EOF';
! 1801: |/
! 1802: |
! 1803: /|
! 1804: EOF
! 1805:
! 1806: $type{"\\subset"}="record";
! 1807: $contents{"\\subset"}="2,4,1,0," . <<'EOF';
! 1808: _
! 1809: (_
! 1810: EOF
! 1811:
! 1812: $type{"\\subseteq"}="record";
! 1813: $contents{"\\subseteq"}="3,4,1,0," . <<'EOF';
! 1814: _
! 1815: (_
! 1816: ~
! 1817: EOF
! 1818:
! 1819: $type{"\\supseteq"}="record";
! 1820: $contents{"\\subseteq"}="3,4,1,0," . <<'EOF';
! 1821: _
! 1822: _)
! 1823: ~
! 1824: EOF
! 1825:
! 1826: $type{"\\supset"}="record";
! 1827: $contents{"\\supset"}="2,4,1,0," . <<'EOF';
! 1828: _
! 1829: _)
! 1830: EOF
! 1831:
! 1832: $type{"\\sqrt"}="sub1";
! 1833: $contents{"\\sqrt"}="radical";
! 1834:
! 1835: $type{"\\buildrel"}="sub3";
! 1836: $contents{"\\buildrel"}="buildrel";
! 1837:
! 1838: $type{"\\frac"}="sub2";
! 1839: $contents{"\\frac"}="fraction";
! 1840:
! 1841: $type{"\\LITERALnoLENGTH"}="sub1";
! 1842: $contents{"\\LITERALnoLENGTH"}="literal_no_length";
! 1843:
! 1844: for ("text","operatorname","operatornamewithlimits","relax","-",
! 1845: "notag","!","/","protect","mathcal","Bbb","bf","it","em","boldsymbol",
! 1846: "cal","Cal","goth","ref","maketitle","expandafter","csname","endcsname",
! 1847: "makeatletter","makeatother","topmatter","endtopmatter","rm",
! 1848: "NoBlackBoxes","document","TagsOnRight","bold","dsize","roster",
! 1849: "endroster","endkey","endRefs","enddocument","displaystyle",
! 1850: "twelverm","tenrm","twelvefm","tenfm","hbox","mbox") {
! 1851: $type{"\\$_"}="nothing";
! 1852: }
! 1853: for ("par","endtitle","endauthor","endaffil","endaddress","endemail",
! 1854: "endhead","key","medskip","smallskip","bigskip","newpage",
! 1855: "vfill","eject","endgraph") {
! 1856: $type{"\\$_"}="sub";
! 1857: $contents{"\\$_"}="par";
! 1858: }
! 1859:
! 1860: for ("proclaim","demo",) {
! 1861: $type{"\\$_"}="par_self";
! 1862: }
! 1863:
! 1864: for ("endproclaim","enddemo",) {
! 1865: $type{"\\$_"}="self_par";
! 1866: }
! 1867:
! 1868: #$type{"&"}="nothing";
! 1869:
! 1870: $type{"\\let"}="sub";
! 1871: $contents{"\\let"}="let_exp";
! 1872:
! 1873: $type{"\\def"}="sub";
! 1874: $contents{"\\def"}="def_exp";
! 1875:
! 1876: $type{"\\item"}="sub";
! 1877: $contents{"\\item"}="item";
! 1878:
! 1879: $type{"{"}="sub";
! 1880: $contents{"{"}="open_curly";
! 1881:
! 1882: $type{"}"}="sub";
! 1883: $contents{"}"}="close_curly";
! 1884:
! 1885: $type{"&"}="sub";
! 1886: $contents{"&"}="ampersand";
! 1887:
! 1888: $type{'$'}="sub";
! 1889: $contents{'$'}="dollar";
! 1890:
! 1891: $type{'$$'}="sub";
! 1892: $contents{'$$'}="ddollar";
! 1893:
! 1894: $type{'\\\\'}="sub";
! 1895: $contents{'\\\\'}="bbackslash";
! 1896:
! 1897: $type{"^"}="sub1";
! 1898: $contents{"^"}="superscript";
! 1899:
! 1900: $type{"_"}="sub1";
! 1901: $contents{"_"}="subscript";
! 1902:
! 1903: $type{"@"}="sub";
! 1904: $contents{"@"}="at";
! 1905:
! 1906: $type{"\\over"}="sub";
! 1907: $contents{"\\over"}="over";
! 1908:
! 1909:
! 1910: $type{"\\choose"}="sub";
! 1911: $contents{"\\choose"}="choose";
! 1912:
! 1913: $type{"\\noindent"}="sub";
! 1914: $contents{"\\noindent"}="noindent";
! 1915:
! 1916:
! 1917: $type{"\\left"}="sub";
! 1918: $contents{"\\left"}="left";
! 1919:
! 1920: $type{"\\right"}="sub";
! 1921: $contents{"\\right"}="right";
! 1922:
! 1923: $type{"\\underline"}="sub1";
! 1924: $contents{"\\underline"}="underline";
! 1925:
! 1926: $type{"\\overline"}="sub1";
! 1927: $contents{"\\overline"}="overline";
! 1928:
! 1929: $type{"\\bar"}="sub1";
! 1930: $contents{"\\bar"}="overline";
! 1931:
! 1932: $type{"\\v"}="sub1";
! 1933: $contents{"\\v"}="putover_string;v";
! 1934:
! 1935: $type{"\\widetilde"}="sub1";
! 1936: $contents{"\\widetilde"}="widetilde";
! 1937:
! 1938: $type{"\\~"}="sub1";
! 1939: $contents{"\\~"}="putover_string;~";
! 1940:
! 1941: $type{"\\tilde"}="sub1";
! 1942: $contents{"\\tilde"}="putover_string;~";
! 1943:
! 1944: $type{"\\widehat"}="sub1";
! 1945: $contents{"\\widehat"}="widehat";
! 1946:
! 1947: $type{"\\hat"}="sub1";
! 1948: $contents{"\\hat"}="putover_string;^";
! 1949:
! 1950: $type{"\\^"}="sub1";
! 1951: $contents{"\\^"}="putover_string;^";
! 1952:
! 1953: $type{'\\"'}="sub1";
! 1954: $contents{'\\"'}='putover_string;"';
! 1955:
! 1956: $type{'\\dot'}="sub1";
! 1957: $contents{'\\dot'}='putover_string;.';
! 1958:
! 1959: $type{"\\not"}="sub1";
! 1960: $contents{"\\not"}="not";
! 1961:
! 1962: $type{"\\label"}="sub1";
! 1963: $contents{"\\label"}="putpar;(;)";
! 1964:
! 1965: $type{"\\eqref"}="sub1";
! 1966: $contents{"\\eqref"}="putpar;(;)";
! 1967:
! 1968: $type{"\\cite"}="sub1";
! 1969: $contents{"\\cite"}="putpar;[;]";
! 1970:
! 1971: $type{"\\begin"}="sub1";
! 1972: $contents{"\\begin"}="begin";
! 1973:
! 1974: $type{"\\end"}="sub1";
! 1975: $contents{"\\end"}="end";
! 1976:
! 1977: for ('@',"_","\$","{","}","#","&","arccos","arcsin","arctan","arg","cos",
! 1978: "cosh","cot","coth","csc","deg","det","dim","exp","gcd","hom",
! 1979: "inf","ker","lg","lim","liminf","limsup","ln","log","max","min",
! 1980: "mod","Pr","sec","sin","sinh","sup","tan","tanh", "%") {
! 1981: $type{"\\$_"}="self";
! 1982: }
! 1983:
! 1984: for ("bibliography","myLabel","theoremstyle","theorembodyfont",
! 1985: "bibliographystyle","hphantom","vphantom","phantom","hspace") {
! 1986: $type{"\\$_"}="discard1";
! 1987: }
! 1988:
! 1989: for ("numberwithin","newtheorem","renewcommand","setcounter"
! 1990: ) {
! 1991: $type{"\\$_"}="discard2";
! 1992: }
! 1993:
! 1994: for ("equation","gather","align"
! 1995: ) {$environment{"$_"}="ddollar,ddollar";}
! 1996:
! 1997: for ("matrix","CD","smallmatrix"
! 1998: ) {$environment{"$_"}="matrix,endmatrix;1;c";}
! 1999:
! 2000: for ("document","split","enumerate"
! 2001: ) {$environment_none{"$_"}++;}
! 2002:
! 2003: $environment{"Sb"}="subscript:matrix,endmatrix;1;l";
! 2004:
! 2005: $environment{"Sp"}="superscript:matrix,endmatrix;1;l";
! 2006:
! 2007: $environment{"eqnarray"}="ddollar:matrix,endmatrix;0;r;c;l:ddollar";
! 2008: $environment{"split"}="ddollar:matrix,endmatrix;0;r;l:ddollar";
! 2009: $environment{"multiline"}="ddollar:matrix,endmatrix;0;r;l:ddollar";
! 2010: $environment{"align"}="ddollar:matrix,endmatrix;0;r;l:ddollar";
! 2011: $environment{"aligned"}="matrix,endmatrix;0;r;l";
! 2012: $environment{"gather"}="ddollar:matrix,endmatrix;0;c:ddollar";
! 2013: $environment{"gathered"}="matrix,endmatrix;0;c";
! 2014: $environment{"array"}="arg2stack:matrix,endmatrixArg;1";
! 2015:
! 2016: # $environment{"pmatrix"}="beg_lr;(;):matrix,endmatrix;1;c";
! 2017: $environment{"bmatrix"}="beg_lr;[;]:matrix,endmatrix;1;c";
! 2018: $environment{"vmatrix"}="beg_lr;|;|:matrix,endmatrix;1;c";
! 2019:
! 2020: $type{"~"}="string";
! 2021: $contents{"~"}=" ";
! 2022:
! 2023: $type{"\\,"}="string";
! 2024: $contents{"\\,"}=" ";
! 2025:
! 2026: $type{"\\dots"}="string";
! 2027: $contents{"\\dots"}="...";
! 2028:
! 2029: $type{"\\ldots"}="string";
! 2030: $contents{"\\ldots"}="...";
! 2031:
! 2032: $type{"\\cdots"}="string";
! 2033: $contents{"\\cdots"}="...";
! 2034:
! 2035: $type{"\\colon"}="string";
! 2036: $contents{"\\colon"}=": ";
! 2037:
! 2038: $type{"\\mid"}="string";
! 2039: $contents{"\\mid"}=" | ";
! 2040:
! 2041: $type{"\\smallsetminus"}="string";
! 2042: $contents{"\\smallsetminus"}=" \\ ";
! 2043:
! 2044: $type{"\\setminus"}="string";
! 2045: $contents{"\\setminus"}=" \\ ";
! 2046:
! 2047: $type{"\\backslash"}="string";
! 2048: $contents{"\\backslash"}="\\";
! 2049:
! 2050: $type{"\\approx"}="string";
! 2051: $contents{"\\approx"}=" ~ ";
! 2052:
! 2053: $type{"\\simeq"}="string";
! 2054: $contents{"\\simeq"}=" ~ ";
! 2055:
! 2056: $type{"\\quad"}="string";
! 2057: $contents{"\\quad"}=" ";
! 2058:
! 2059: $type{"\\qquad"}="string";
! 2060: $contents{"\\qquad"}=" ";
! 2061:
! 2062: $type{"\\to"}="string";
! 2063: $contents{"\\to"}=" --> ";
! 2064:
! 2065: $type{"\\from"}="string";
! 2066: $contents{"\\from"}=" <-- ";
! 2067:
! 2068: $type{"\\wedge"}="string";
! 2069: $contents{"\\wedge"}="/\\";
! 2070:
! 2071: $type{"\\Lambda"}="string";
! 2072: $contents{"\\Lambda"}="/\\";
! 2073:
! 2074: $type{"\\ltimes"}="string";
! 2075: $contents{"\\ltimes"}=" |>< ";
! 2076:
! 2077: $type{"\\lhd"}="string";
! 2078: $contents{"\\lhd"}=" <| ";
! 2079:
! 2080: $type{"\\rhd"}="string";
! 2081: $contents{"\\rhd"}=" |> ";
! 2082:
! 2083: $type{"\\cdot"}="string";
! 2084: $contents{"\\cdot"}=" . ";
! 2085:
! 2086: # $type{"\dot"}="string";
! 2087: # $contents{"\\dot"}=" . ";
! 2088:
! 2089: $type{"\\circ"}="string";
! 2090: $contents{"\\circ"}=" o ";
! 2091:
! 2092: $type{"\\bullet"}="string";
! 2093: $contents{"\\bullet"}="\@";
! 2094:
! 2095: $type{"\\infty"}="string";
! 2096: $contents{"\\infty"}="oo";
! 2097:
! 2098: $type{"\\rtimes"}="string";
! 2099: $contents{"\\rtimes"}=" ><| ";
! 2100:
! 2101: $type{"\\times"}="string";
! 2102: $contents{"\\times"}=" >< ";
! 2103:
! 2104: $type{"\\hookrightarrow"}="string";
! 2105: $contents{"\\hookrightarrow"}=" c--> ";
! 2106:
! 2107: $type{"\\hookleftarrow"}="string";
! 2108: $contents{"\\hookleftarrow"}=" <--j ";
! 2109:
! 2110: $type{"\\longleftarrow"}="string";
! 2111: $contents{"\\longleftarrow"}=" <----- ";
! 2112:
! 2113: $type{"\\longleftrightarrow"}="string";
! 2114: $contents{"\\longleftrightarrow"}=" <----> ";
! 2115:
! 2116: $type{"\\longrightarrow"}="string";
! 2117: $contents{"\\longrightarrow"}=" -----> ";
! 2118:
! 2119: $type{"\\rightarrow"}="string";
! 2120: $contents{"\\rightarrow"}=" ---> ";
! 2121:
! 2122: $type{"\\leftarrow"}="string";
! 2123: $contents{"\\leftarrow"}=" <--- ";
! 2124:
! 2125: $type{"\\mapsto"}="string";
! 2126: $contents{"\\mapsto"}=" |--> ";
! 2127:
! 2128: $type{"\\longmapsto"}="string";
! 2129: $contents{"\\longmapsto"}=" |----> ";
! 2130:
! 2131: $type{"\\cap"}="string";
! 2132: $contents{"\\cap"}=" /~\\ ";
! 2133:
! 2134: $type{"\\cup"}="string";
! 2135: $contents{"\\cup"}=" \\_/ ";
! 2136:
! 2137: $type{"\\section"}="string";
! 2138: $contents{"\\section"}="Section ";
! 2139:
! 2140: $type{"\\subsection"}="string";
! 2141: $contents{"\\subsection"}="Subsection ";
! 2142:
! 2143: $type{"\|"}="string";
! 2144: $contents{"\|"}="||";
! 2145:
! 2146: $type{'\;'}="string";
! 2147: $contents{'\;'}=" ";
! 2148:
! 2149: $type{'\noindent'}="string";
! 2150: $contents{'\noindent'}="";
! 2151:
! 2152:
! 2153: &define('\\define','\\def');
! 2154: &define('\\ge','\\geq');
! 2155: &define('\\le','\\leq');
! 2156: &define('\\ne','\\neq');
! 2157: &define('\\langle','<');
! 2158: &define('\\rangle','>');
! 2159: &define('\\subheading','\\par\\underline');
! 2160: &define('\\(','$');
! 2161: &define('\\)','$');
! 2162: &define('\\[','$$');
! 2163: &define('\\]','$$');
! 2164: &define('\\centerline#1','$$#1$$');
! 2165: &define('\\eqalign#1','\\aligned #1 \\endaligned');
! 2166: &define('\\cr','\\\\');
! 2167: &define('\\sb','_');
! 2168: &define('\\sp','^');
! 2169: &define('\\proclaim','\\noindent ');
! 2170: &defb("matrix","vmatrix","Vmatrix","smallmatrix","bmatrix","Sp","Sb",
! 2171: "CD","align","aligned","split","multiline","gather","gathered");
! 2172:
! 2173: if ($opt_TeX) {
! 2174: &define('\pmatrix#1','\left(\begin{matrix}#1\end{matrix}\right)');
! 2175: } else {
! 2176: $environment{"pmatrix"}="beg_lr;(;):matrix,endmatrix;1;c";
! 2177: &defb("pmatrix") unless $opt_TeX;
! 2178: }
! 2179:
! 2180:
! 2181: ## All the records should be specified before this point
! 2182: {local(@a)=grep("record" eq $type{$_},keys %type);
! 2183: for (@a) {chop $contents{$_} if
! 2184: substr($contents{$_},length($contents{$_})-1,1) eq "\n";}}
! 2185:
! 2186: for ("oplus","otimes","cup","wedge") {
! 2187: $type{"\\big$_"}=$type{"\\$_"};
! 2188: $contents{"\\big$_"}=$contents{"\\$_"};
! 2189: }
! 2190:
! 2191:
! 2192: @level=(0);
! 2193: @chunks=(0);
! 2194: @tokenByToken=(0);
! 2195: @out=();
! 2196: $curlength=0;
! 2197: $debug_flow=1;
! 2198: $debug_record=2;
! 2199: $debug_parsing=4;
! 2200: $debug_length=8;
! 2201: $debug_matrix=16;
! 2202: #$debug |= $debug_flow | $debug_record | $debug_parsing | $debug_length;
! 2203: #$debug |= $debug_flow;
! 2204: #$debug |= $debug_record;
! 2205: #$debug |= $debug_parsing;
! 2206: #$debug |= $debug_length;
! 2207: #$debug |= $debug_matrix;
! 2208:
! 2209:
! 2210: $/ = $opt_by_par ? "\n\n" : ''; # whole paragraph mode
! 2211: while (¶graph()) { 1 }
! 2212: &finishBuffer;
! 2213:
! 2214: __END__
! 2215:
! 2216: # History: Jul 98: \choose added, fixed RE for \noindent, \eqalign and \cr.
! 2217: # \proclaim and better \noindent added.
! 2218: # Sep 98: last was used inside an if block, was leaking out.
! 2219: # Jan 00: \sb \sp
! 2220: # Feb 00: remove extraneous second EOF needed at end.
! 2221: remove an empty line at end of output
! 2222: New option -by_par to support per-paragraph processing
! 2223: New option -TeX which support a different \pmatrix
! 2224: New option -ragged to not insert whitespace to align right margin.
! 2225: New option -noindent to not insert whitespace at beginning.
! 2226: Ignore \\ and \cr if followed by \end{whatever}.
! 2227: Ignore \noindent if not important.
! 2228: Ignore whitespace paragraphs.
! 2229: # Apr 00: Finishing a level 1 would not merge things into one chunk.
! 2230: # May 00: Additional argument to finish() to distinguish finishing
! 2231: things which cannot be broken between lines.
! 2232: # Sep 00: Add support for new macro for strings with screen escapes sequences:
! 2233: \LITERALnoLENGTH{escapeseq}.
! 2234: # Oct 00: \LITERALnoLENGTH can have a chance to work in the baseline only;
! 2235: in fact the previous version did not work even there...
! 2236: If the added record is longer than line length, do not try to
! 2237: break the line before it...
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>