1 package gnu.kawa.functions; 2 import gnu.text.*; 3 import gnu.lists.*; 4 import java.text.Format ; 5 import java.text.FieldPosition ; 6 import java.text.ParseException ; 7 import java.io.Writer ; 8 import gnu.math.*; 9 import gnu.mapping.OutPort; 10 11 12 13 public class LispFormat extends CompoundFormat 14 { 15 public static final String paramFromList = "<from list>"; 16 public static final String paramFromCount = "<from count>"; 17 public static final String paramUnspecified = "<unspecified>"; 18 19 public LispFormat(char[] format, int offset, int length) 20 throws ParseException 21 { 22 super(null, 0); 23 int start_nesting = -1; 25 int choices_seen = 0; 27 StringBuffer litbuf = new StringBuffer (100); 28 java.util.Stack stack = new java.util.Stack (); 29 30 int limit = offset + length; 31 int i = offset; 32 for (;;) 33 { 34 if ((i >= limit || format[i] == '~') && litbuf.length() > 0) 35 { 36 stack.push(new LiteralFormat(litbuf)); 37 litbuf.setLength(0); 38 } 39 if (i >= limit) 40 break; 41 char ch = format[i++]; 42 if (ch != '~') 43 { 44 litbuf.append(ch); 45 continue; 46 } 47 int speci = stack.size(); 48 ch = format[i++]; 49 for (;;) 50 { 51 if (ch == '#') 52 { 53 stack.push(paramFromCount); 54 ch = format[i++]; 55 } 56 else if (ch == 'v' || ch == 'V') 57 { 58 stack.push(paramFromList); 59 ch = format[i++]; 60 } 61 else if (ch == '-' || Character.digit(ch, 10) >= 0) 62 { 63 boolean neg = (ch == '-'); 64 if (neg) 65 ch = format[i++]; 66 int val = 0; 67 int start = i; 68 for (;;) 69 { 70 int dig = Character.digit(ch, 10); 71 if (dig < 0) 72 break; 73 val = 10 * val + dig; 74 ch = format[i++]; 75 } 76 stack.push(i - start < 8 ? IntNum.make(neg ? - val : val) 77 : IntNum.valueOf(format, start, i-start, 10, neg)); 78 } 79 else if (ch == '\'') 80 { 81 stack.push(Char.make(format[i++])); 82 ch = format[i++]; 83 } 84 else if (ch == ',') 85 { 86 stack.push(paramUnspecified); 87 } 88 else 89 break; 90 if (ch != ',') 91 break; 92 ch = format[i++]; 93 } 94 boolean seenColon = false; 95 boolean seenAt = false; 96 for (;;) 97 { 98 if (ch == ':') 99 seenColon = true; 100 else if (ch == '@') 101 seenAt = true; 102 else 103 break; 104 ch = format[i++]; 105 } 106 ch = Character.toUpperCase(ch); 107 int numParams = stack.size() - speci; 108 Format fmt; 109 int minWidth, padChar, charVal, param1, param2, param3, count; 110 switch (ch) 111 { 112 case 'R': case 'D': case 'O': case 'B': case 'X': 113 int argstart = speci; 114 int base; 115 if (ch == 'R') base = getParam(stack, argstart++); 116 else if (ch == 'D') base = 10; 117 else if (ch == 'O') base = 8; 118 else if (ch == 'X') base = 16; 119 else base = 2; 120 minWidth = getParam(stack, argstart); 121 padChar = getParam(stack, argstart+1); 122 int commaChar = getParam(stack, argstart+2); 123 int commaInterval = getParam(stack, argstart+3); 124 int flags = 0; 125 if (seenColon) 126 flags |= IntegerFormat.SHOW_GROUPS; 127 if (seenAt) 128 flags |= IntegerFormat.SHOW_PLUS; 129 fmt = IntegerFormat.getInstance(base, minWidth, padChar, 130 commaChar, commaInterval, flags); 131 break; 132 case 'P': 133 fmt = LispPluralFormat.getInstance(seenColon, seenAt); 134 break; 135 case 'E': 136 case 'F': 137 case 'G': 138 case '$': 139 LispRealFormat dfmt = new LispRealFormat(); 140 dfmt.op = ch; 141 dfmt.arg1 = getParam(stack, speci); 142 dfmt.arg2 = getParam(stack, speci+1); 143 dfmt.arg3 = getParam(stack, speci+2); 144 dfmt.arg4 = getParam(stack, speci+3); 145 if (ch != '$') 146 { 147 dfmt.arg5 = getParam(stack, speci+4); 148 if (ch == 'E' || ch == 'G') 149 { 150 dfmt.arg6 = getParam(stack, speci+5); 151 dfmt.arg7 = getParam(stack, speci+6); 152 } 153 } 154 dfmt.showPlus = seenAt; 155 dfmt.internalPad = seenColon; 156 if (dfmt.argsUsed == 0) 157 fmt = dfmt.resolve(null, 0); 158 else 159 fmt = dfmt; 160 break; 161 case 'A': case 'S': case 'W': 162 case 'Y': fmt = ObjectFormat.getInstance(ch != 'A'); 165 if (numParams > 0) 166 { 167 minWidth = getParam(stack, speci); 168 int colInc = getParam(stack, speci+1); 169 int minPad = getParam(stack, speci+2); 170 padChar = getParam(stack, speci+3); 171 fmt = new LispObjectFormat((ReportFormat) fmt, 172 minWidth, colInc, minPad, 173 padChar, seenAt ? 0 : 100); 174 } 175 break; 176 case 'C': 177 charVal = numParams > 0 ? getParam(stack, speci) 178 : PARAM_FROM_LIST; 179 fmt = LispCharacterFormat.getInstance(charVal, 1, 180 seenAt, seenColon); 181 break; 182 case '*': 183 fmt = new LispRepositionFormat(getParam(stack, speci), 184 seenColon, seenAt); 185 break; 186 case '(': 187 ch = seenColon ? (seenAt ? 'U' : 'C') : (seenAt ? 'T': 'L'); 188 CaseConvertFormat cfmt = new CaseConvertFormat(null, ch); 189 stack.setSize(speci); 190 stack.push(cfmt); 191 stack.push(IntNum.make(start_nesting)); 192 start_nesting = speci; 193 continue; 194 case ')': 195 if (start_nesting < 0 196 || ! (stack.elementAt(start_nesting) 197 instanceof CaseConvertFormat)) 198 throw new ParseException ("saw ~) without matching ~(", i); 199 cfmt = (CaseConvertFormat) stack.elementAt(start_nesting); 200 cfmt.setBaseFormat(popFormats(stack, start_nesting + 2, speci)); 201 start_nesting = ((IntNum) stack.pop()).intValue(); 202 continue; 203 case '?': 204 LispIterationFormat lfmt = new LispIterationFormat(); 205 lfmt.seenAt = seenAt; 206 lfmt.maxIterations = 1; 207 lfmt.atLeastOnce = true; 208 fmt = lfmt; 209 break; 210 case '{': 211 lfmt = new LispIterationFormat(); 212 lfmt.seenAt = seenAt; 213 lfmt.seenColon = seenColon; 214 lfmt.maxIterations = getParam(stack, speci); 215 stack.setSize(speci); 216 stack.push(lfmt); 217 stack.push(IntNum.make(start_nesting)); 218 start_nesting = speci; 219 continue; 220 case '}': 221 if (start_nesting < 0 222 || ! (stack.elementAt(start_nesting) 223 instanceof LispIterationFormat)) 224 throw new ParseException ("saw ~} without matching ~{", i); 225 lfmt = (LispIterationFormat) stack.elementAt(start_nesting); 226 lfmt.atLeastOnce = seenColon; 227 if (speci > start_nesting + 2) 228 lfmt.body = popFormats(stack, start_nesting + 2, speci); 229 start_nesting = ((IntNum) stack.pop()).intValue(); 230 continue; 231 case '<': 232 LispPrettyFormat pfmt = new LispPrettyFormat(); 233 pfmt.seenAt = seenAt; 234 if (seenColon) 235 { 236 pfmt.prefix = "("; 237 pfmt.suffix = ")"; 238 } 239 else 240 { 241 pfmt.prefix = ""; 242 pfmt.suffix = ""; 243 } 244 stack.setSize(speci); 245 stack.push(pfmt); 246 stack.push(IntNum.make(start_nesting)); 247 stack.push(IntNum.make(choices_seen)); 248 start_nesting = speci; 249 choices_seen = 0; 250 continue; 251 case '>': 252 if (start_nesting < 0 253 || ! (stack.elementAt(start_nesting) 254 instanceof LispPrettyFormat)) 255 throw new ParseException ("saw ~> without matching ~<", i); 256 fmt = popFormats(stack, start_nesting + 3 + choices_seen, speci); 257 stack.push(fmt); 258 pfmt = (LispPrettyFormat) stack.elementAt(start_nesting); 259 pfmt.segments = getFormats(stack, start_nesting + 3, stack.size()); 260 stack.setSize(start_nesting + 3); 261 start_nesting = ((IntNum) stack.pop()).intValue(); 262 start_nesting = ((IntNum) stack.pop()).intValue(); 263 if (seenColon) 264 { int nsegments = pfmt.segments.length; 266 if (nsegments > 3) 267 throw new ParseException ("too many segments in Logical Block format", i); 268 if (nsegments >= 2) 269 { 270 if (! (pfmt.segments[0] instanceof LiteralFormat)) 271 throw new ParseException ("prefix segment is not literal", i); 272 pfmt.prefix = ((LiteralFormat) pfmt.segments[0]).content(); 273 pfmt.body = pfmt.segments[1]; 274 } 275 else 276 pfmt.body = pfmt.segments[0]; 277 if (nsegments >=3) 278 { 279 if (! (pfmt.segments[2] instanceof LiteralFormat)) 280 throw new ParseException ("suffix segment is not literal", i); 281 pfmt.suffix = ((LiteralFormat) pfmt.segments[2]).content(); 282 } 283 } 284 else throw new ParseException ("not implemented: justfication i.e. ~<...~>", i); 286 continue; 287 case '[': 288 LispChoiceFormat afmt = new LispChoiceFormat(); 289 afmt.param = getParam(stack, speci); 290 if (afmt.param == PARAM_UNSPECIFIED) 291 afmt.param = PARAM_FROM_LIST; 292 if (seenColon) 293 afmt.testBoolean = true; 294 if (seenAt) 295 afmt.skipIfFalse = true; 296 stack.setSize(speci); 297 stack.push(afmt); 298 stack.push(IntNum.make(start_nesting)); 299 stack.push(IntNum.make(choices_seen)); 300 start_nesting = speci; 301 choices_seen = 0; 302 continue; 303 case ';': 304 if (start_nesting >= 0) 305 { 306 if (stack.elementAt(start_nesting) 307 instanceof LispChoiceFormat) 308 { 309 afmt = (LispChoiceFormat) stack.elementAt(start_nesting); 310 if (seenColon) 311 afmt.lastIsDefault = true; 312 fmt = popFormats(stack, 313 start_nesting + 3 + choices_seen, speci); 314 stack.push(fmt); 315 choices_seen++; 316 continue; 317 } 318 else if (stack.elementAt(start_nesting) 319 instanceof LispPrettyFormat) 320 { 321 pfmt = (LispPrettyFormat) stack.elementAt(start_nesting); 322 if (seenAt) 323 pfmt.perLine = true; 324 fmt = popFormats(stack, 325 start_nesting + 3 + choices_seen, speci); 326 stack.push(fmt); 327 choices_seen++; 328 continue; 329 } 330 } 332 throw new ParseException ("saw ~; without matching ~[ or ~<", i); 333 case ']': 334 if (start_nesting < 0 335 || ! (stack.elementAt(start_nesting) 336 instanceof LispChoiceFormat)) 337 throw new ParseException ("saw ~] without matching ~[", i); 338 fmt = popFormats(stack, start_nesting + 3 + choices_seen, speci); 339 stack.push(fmt); 340 afmt = (LispChoiceFormat) stack.elementAt(start_nesting); 341 afmt.choices = getFormats(stack, start_nesting + 3, stack.size()); 342 stack.setSize(start_nesting + 3); 343 choices_seen = ((IntNum) stack.pop()).intValue(); 344 start_nesting = ((IntNum) stack.pop()).intValue(); 345 continue; 346 case '^': 347 param1 = getParam(stack, speci); 348 param2 = getParam(stack, speci+1); 349 param3 = getParam(stack, speci+2); 350 fmt = new LispEscapeFormat(param1, param2, param3); 351 break; 352 case '\n': 353 if (seenAt) 354 litbuf.append(ch); 355 if (! seenColon) 356 { 357 while (i < limit) 358 { 359 ch = format[i++]; 360 if (! Character.isWhitespace(ch)) 361 { 362 i--; 363 break; 364 } 365 } 366 } 367 continue; 368 case '!': 369 fmt = FlushFormat.getInstance(); 370 break; 371 case 'T': 372 param1 = getParam(stack, speci); 373 param2 = getParam(stack, speci+1); 374 param3 = getParam(stack, speci+2); 375 fmt = new LispTabulateFormat(param1, param2, param3, seenAt); 376 break; 377 case '&': 378 param1 = getParam(stack, speci); 379 fmt = new LispFreshlineFormat(param1); 380 break; 381 case 'I': param1 = getParam(stack, speci); 383 if (param1 == PARAM_UNSPECIFIED) 384 param1 = 0; 385 fmt = LispIndentFormat.getInstance(param1, seenColon); 386 break; 387 case '_': param1 = getParam(stack, speci); 389 if (param1 == PARAM_UNSPECIFIED) 390 param1 = 1; 391 charVal = seenColon && seenAt ? '\n' : ' '; 392 int kind; 393 if (seenAt && seenColon) kind = PrettyWriter.NEWLINE_MANDATORY; 394 else if (seenAt) kind = PrettyWriter.NEWLINE_MISER; 395 else if (seenColon) kind = PrettyWriter.NEWLINE_FILL; 396 else kind = PrettyWriter.NEWLINE_LINEAR; 397 fmt = LispNewlineFormat.getInstance(param1, kind); 398 break; 399 case '~': 400 if (numParams == 0) 401 { 402 litbuf.append(ch); 403 continue; 404 } 405 406 case '|': 407 count = getParam(stack, speci); 408 if (count == PARAM_UNSPECIFIED) 409 count = 1; 410 charVal = getParam(stack, speci+1); 412 if (charVal == PARAM_UNSPECIFIED) 413 charVal = ch == '|' ? '\f' : '~'; 414 fmt = LispCharacterFormat.getInstance(charVal, count, 415 false, false); 416 break; 417 case '%': 418 count = getParam(stack, speci); 419 if (count == PARAM_UNSPECIFIED) 420 count = 1; 421 fmt = LispNewlineFormat.getInstance(count, 422 PrettyWriter.NEWLINE_LITERAL); 423 break; 424 default: 425 throw new ParseException ("unrecognized format specifier ~"+ch, i); 426 } 427 stack.setSize(speci); 428 stack.push(fmt); 429 } 430 if (i > limit) 431 throw new IndexOutOfBoundsException (); 432 if (start_nesting >= 0) 433 { 434 throw new ParseException ("missing ~] or ~}", i); 435 } 436 this.length = stack.size(); 437 this.formats = new Format[this.length]; 438 stack.copyInto(this.formats); 439 } 440 441 static Format[] getFormats(java.util.Vector vector, int start, int end) 442 { 443 Format[] f = new Format[end - start]; 444 for (int i = start; i < end; i++) 445 f[i - start] = (Format) vector.elementAt(i); 446 return f; 447 } 448 449 static Format popFormats(java.util.Vector vector, int start, int end) 450 { 451 Format f; 452 if (end == start + 1) 453 f = (Format) vector.elementAt(start); 454 else 455 f = new CompoundFormat(getFormats(vector, start, end)); 456 vector.setSize(start); 457 return f; 458 } 459 460 public LispFormat (String str) 461 throws ParseException 462 { 463 this(str.toCharArray()); 464 } 465 466 475 476 495 496 510 511 public LispFormat(char[] format) 512 throws ParseException 513 { 514 this(format, 0, format.length); 515 } 516 517 public static int getParam(java.util.Vector vec, int index) 518 { 519 if (index >= vec.size()) 520 return PARAM_UNSPECIFIED; 521 Object arg = vec.elementAt(index); 522 if (arg == paramFromList) 523 return PARAM_FROM_LIST; 524 if (arg == paramFromCount) 525 return PARAM_FROM_COUNT; 526 if (arg == paramUnspecified) 527 return PARAM_UNSPECIFIED; 528 return getParam(arg, PARAM_UNSPECIFIED); 529 } 530 531 533 public static Object [] asArray (Object arg) 534 { 535 if (arg instanceof Object []) 536 return (Object []) arg; 537 if (!(arg instanceof Sequence)) 538 return null; 539 int count = ((Sequence) arg).size(); 540 Object [] arr = new Object [count]; 541 int i = 0; 542 while (arg instanceof Pair) 543 { 544 Pair pair = (Pair) arg; 545 arr[i++] = pair.car; 546 arg = pair.cdr; 547 } 548 if (i < count) 549 { 550 if (! (arg instanceof Sequence)) 551 return null; 552 int npairs = i; 553 Sequence seq = (Sequence) arg; 554 for (; i < count; i++) 555 arr[i] = seq.get(npairs + i); 556 } 557 return arr; 558 } 559 } 560 561 563 564 class LispPluralFormat extends ReportFormat 565 { 566 boolean backup; 567 boolean y; 568 569 public static LispPluralFormat getInstance (boolean backup, boolean y) 570 { 571 LispPluralFormat fmt = new LispPluralFormat(); 572 fmt.backup = backup; 573 fmt.y = y; 574 return fmt; 575 } 576 577 public int format(Object [] args, int start, 578 Writer dst, FieldPosition fpos) 579 throws java.io.IOException 580 { 581 if (backup) 582 start--; 583 Object arg = args[start++]; 584 boolean plural = arg != IntNum.one(); 585 if (y) 586 print(dst, plural ? "ies" : "y"); 587 else if (plural) 588 dst.write('s'); 589 return start; 590 } 591 } 592 593 594 597 598 class LispCharacterFormat extends ReportFormat 599 { 600 boolean seenAt; 601 boolean seenColon; 602 int count; 603 int charVal; 604 605 public static LispCharacterFormat 606 getInstance(int charVal, int count, boolean seenAt, boolean seenColon) 607 { 608 LispCharacterFormat fmt = new LispCharacterFormat(); 609 fmt.count = count; 610 fmt.charVal = charVal; 611 fmt.seenAt = seenAt; 612 fmt.seenColon = seenColon; 613 return fmt; 614 } 615 616 public int format(Object [] args, int start, 617 Writer dst, FieldPosition fpos) 618 throws java.io.IOException 619 { 620 int count = getParam(this.count, 1, args, start); 621 if (this.count == LispFormat.PARAM_FROM_LIST) start++; 622 int charVal = getParam(this.charVal, '?', args, start); 623 if (this.charVal == LispFormat.PARAM_FROM_LIST) start++; 624 while (--count >= 0) 625 printChar (charVal, seenAt, seenColon, dst); 626 return start; 627 } 628 629 public static void printChar(int ch, boolean seenAt, boolean seenColon, 630 Writer dst) 631 throws java.io.IOException 632 { 633 if (seenAt) 634 { 635 print(dst, Char.toScmReadableString(ch)); 636 } 637 else if (seenColon) 638 { 639 if (ch < ' ') 640 { 641 dst.write('^'); 642 dst.write(ch + 0x40); 643 } 644 else if (ch >= 0x7f) 645 { 646 print(dst, "#\\"); 647 print(dst, Integer.toString(ch, 8)); 648 } 649 else 650 dst.write(ch); 651 } 652 else 653 { 654 dst.write(ch); 656 } 657 } 658 } 659 660 661 662 class LispNewlineFormat extends ReportFormat 663 { 664 static final String line_separator 665 = System.getProperty("line.separator", "\n"); 666 667 669 int kind; 670 671 int count; 672 673 public static LispNewlineFormat 674 getInstance(int count, int kind) 675 { 676 LispNewlineFormat fmt = new LispNewlineFormat(); 677 fmt.count = count; 678 fmt.kind = kind; 679 return fmt; 680 } 681 682 public int format(Object [] args, int start, 683 Writer dst, FieldPosition fpos) 684 throws java.io.IOException 685 { 686 int count = getParam(this.count, 1, args, start); 687 if (this.count == LispFormat.PARAM_FROM_LIST) start++; 688 while (--count >= 0) 689 printNewline (kind, dst); 690 return start; 691 } 692 693 public static void printNewline(int kind, Writer dst) 694 throws java.io.IOException 695 { 696 if (dst instanceof OutPort && kind != PrettyWriter.NEWLINE_LITERAL) 697 ((OutPort) dst).writeBreak(kind); 698 else if (dst instanceof java.io.PrintWriter ) 699 ((java.io.PrintWriter ) dst).println(); 701 else 702 dst.write(line_separator); 703 } 704 } 705 706 707 708 class LispIndentFormat extends ReportFormat 709 { 710 boolean current; 711 712 int columns; 713 714 public static LispIndentFormat 715 getInstance(int columns, boolean current) 716 { 717 LispIndentFormat fmt = new LispIndentFormat(); 718 fmt.columns = columns; 719 fmt.current = current; 720 return fmt; 721 } 722 723 public int format(Object [] args, int start, 724 Writer dst, FieldPosition fpos) 725 throws java.io.IOException 726 { 727 int columns = getParam(this.columns, 0, args, start); 728 if (this.columns == LispFormat.PARAM_FROM_LIST) start++; 729 if (dst instanceof OutPort) 730 ((OutPort) dst).setIndentation(columns, current); 731 return start; 732 } 733 } 734 735 738 739 class LispObjectFormat extends ReportFormat 740 { 741 int minWidth; 742 int colInc; 743 int minPad; 744 int padChar; 745 int where; 746 ReportFormat base; 747 748 public LispObjectFormat(ReportFormat base, 749 int minWidth, int colInc, int minPad, int padChar, 750 int where) 751 { 752 this.base = base; 753 this.minWidth = minWidth; 754 this.colInc = colInc; 755 this.minPad = minPad; 756 this.padChar = padChar; 757 this.where = where; 758 } 759 760 public int format(Object [] args, int start, 761 Writer dst, FieldPosition fpos) 762 throws java.io.IOException 763 { 764 int minWidth = getParam(this.minWidth, 0, args, start); 765 if (this.minWidth == LispFormat.PARAM_FROM_LIST) start++; 766 int colInc = getParam(this.colInc, 1, args, start); 767 if (this.colInc == LispFormat.PARAM_FROM_LIST) start++; 768 int minPad = getParam(this.minPad, 0, args, start); 769 if (this.minPad == LispFormat.PARAM_FROM_LIST) start++; 770 char padChar = getParam(this.padChar, ' ', args, start); 771 if (this.padChar == LispFormat.PARAM_FROM_LIST) start++; 772 return gnu.text.PadFormat.format(base, args, start, dst, 773 padChar, minWidth, colInc, minPad, 774 where, fpos); 775 } 776 } 777 778 class LispEscapeFormat extends ReportFormat 779 { 780 int param1; 781 int param2; 782 int param3; 783 boolean escapeAll; 784 785 public final static LispEscapeFormat alwaysTerminate 786 = new LispEscapeFormat(0, LispFormat.PARAM_UNSPECIFIED); 787 788 public LispEscapeFormat(int param1, int param2) 789 { 790 this.param1 = param1; 791 this.param2 = param2; 792 this.param3 = LispFormat.PARAM_UNSPECIFIED; 793 } 794 795 public LispEscapeFormat(int param1, int param2, int param3) 796 { 797 this.param1 = param1; 798 this.param2 = param2; 799 this.param3 = param3; 800 } 801 802 static Numeric getParam(int param, Object [] args, int start) 803 { 804 if (param == LispFormat.PARAM_FROM_COUNT) 805 return IntNum.make(args.length - start); 806 if (param == LispFormat.PARAM_FROM_LIST) 807 { 808 Object arg = args[start]; 809 if (arg instanceof Numeric) 810 return (Numeric) arg; 811 if (arg instanceof Number ) 812 { 813 if (arg instanceof Float || arg instanceof Double ) 814 return new DFloNum(((Number ) arg).doubleValue()); 815 return IntNum.make(((Number ) arg).longValue()); 816 } 817 if (arg instanceof Char) 818 return new IntNum(((Char) arg).intValue()); 819 if (arg instanceof Character ) 820 return new IntNum((int) ((Character ) arg).charValue()); 821 return new DFloNum(Double.NaN); 822 } 823 return IntNum.make(param); 824 } 825 826 831 public int format(Object [] args, int start, Writer dst, FieldPosition fpos) 832 throws java.io.IOException 833 { 834 int orig_start = start; 835 boolean do_terminate; 836 if (param1 == LispFormat.PARAM_UNSPECIFIED) 837 do_terminate = start == args.length; 838 else if (param2 == LispFormat.PARAM_UNSPECIFIED && param1 == 0) 839 do_terminate = true; else 841 { 842 Numeric arg1 = getParam(param1, args, start); 843 if (param1 == LispFormat.PARAM_FROM_LIST) start++; 844 if (param2 == LispFormat.PARAM_UNSPECIFIED) 845 { 846 do_terminate = arg1.isZero(); 847 } 848 else 849 { 850 Numeric arg2 = getParam(param2, args, start); 851 if (param2 == LispFormat.PARAM_FROM_LIST) start++; 852 if (param3 == LispFormat.PARAM_UNSPECIFIED) 853 { 854 do_terminate = arg1.equals(arg2); 855 } 856 else 857 { 858 Numeric arg3 = getParam(param3, args, start); 859 if (param3 == LispFormat.PARAM_FROM_LIST) start++; 860 do_terminate = arg2.geq(arg1) && arg3.geq(arg2); 861 } 862 } 863 } 864 return result(! do_terminate ? 0 : escapeAll ? ESCAPE_ALL : ESCAPE_NORMAL, 865 start); 866 } 867 868 public final static int ESCAPE_NORMAL = 0xF1; 869 public final static int ESCAPE_ALL = 0xF2; 870 } 871 872 874 875 class LispPrettyFormat extends ReportFormat 876 { 877 Format[] segments; 878 Format body; 879 String prefix; 880 String suffix; 881 boolean perLine; 882 boolean seenAt; 883 884 public int format(Object [] args, int start, 885 Writer dst, FieldPosition fpos) 886 throws java.io.IOException 887 { 888 String pre = prefix; 889 String suf = suffix; 890 OutPort out = dst instanceof OutPort ? (OutPort) dst : null; 891 try 892 { 893 if (seenAt) 894 { 895 if (out != null) 896 out.startLogicalBlock(pre, perLine, suffix); 897 start = ReportFormat.format(body, args, start, dst, fpos); 898 } 899 else 900 { 901 Object curArg = args[start]; 902 Object [] curArr = LispFormat.asArray(curArg); 903 if (curArr == null) 904 pre = suf = ""; 905 if (out != null) 906 out.startLogicalBlock(pre, perLine, suffix); 907 if (curArr == null) 908 ObjectFormat.format(curArg, dst, -1, true); 909 else 910 ReportFormat.format(body, curArr, 0, dst, fpos); 911 start++; 912 } 913 } 914 finally 915 { 916 if (out != null) 917 out.endLogicalBlock(suf); 918 } 919 return start; 920 } 921 922 public String toString () 923 { 924 StringBuffer sbuf = new StringBuffer (); 925 sbuf.append("LispPrettyFormat["); 926 sbuf.append("prefix: \""); sbuf.append(prefix); 927 sbuf.append("\", suffix: \""); sbuf.append(suffix); 928 sbuf.append("\", body: "); 929 sbuf.append(body); 930 sbuf.append("]"); 931 return sbuf.toString(); 932 } 933 } 934 935 class LispIterationFormat extends ReportFormat 936 { 937 int maxIterations; 938 boolean seenAt; 939 boolean seenColon; 940 boolean atLeastOnce; 941 942 Format body; 943 944 public static int format(Format body, int maxIterations, 945 Object [] args, int start, 946 Writer dst, boolean seenColon, boolean atLeastOnce) 947 throws java.io.IOException 948 { 949 for (int i = 0; ; i++) 950 { 951 if (i == maxIterations && maxIterations != -1) 952 break; 953 if (start == args.length && (i > 0 || ! atLeastOnce)) 954 break; 955 if (seenColon) 956 { 957 Object curArg = args[start]; 958 Object [] curArr = LispFormat.asArray(curArg); 959 if (curArr == null) 960 { } 962 int result = ReportFormat.format(body, curArr, 0, dst, null); 963 start++; 964 if (ReportFormat.resultCode(result) == LispEscapeFormat.ESCAPE_ALL) 965 break; 966 } 967 else 968 { 969 start = ReportFormat.format(body, args, start, dst, null); 970 if (start < 0) 971 { 972 start = ReportFormat.nextArg(start); 973 break; 974 } 975 } 976 } 977 return start; 978 } 979 980 public int format(Object [] args, int start, 981 Writer dst, FieldPosition fpos) 982 throws java.io.IOException 983 { 984 int maxIterations = getParam(this.maxIterations, -1, 985 args, start); 986 if (this.maxIterations == LispFormat.PARAM_FROM_LIST) start++; 987 988 Format body = this.body; 989 if (body == null) 990 { 991 Object arg = args[start++]; 993 if (arg instanceof java.text.Format ) 994 body = (java.text.Format ) arg; 995 else 996 { 997 try 998 { 999 body = new LispFormat(arg.toString()); 1000 } 1001 catch (Exception ex) 1002 { 1003 print(dst, "<invalid argument for \"~{~}\" format>"); 1004 return args.length; } 1006 } 1007 } 1008 if (seenAt) 1009 { 1010 return format(body, maxIterations, args, start, 1011 dst, seenColon, atLeastOnce); 1012 } 1013 else 1014 { 1015 Object arg = args[start]; 1016 Object [] curArgs = LispFormat.asArray(arg); 1017 if (curArgs == null) 1018 dst.write("{"+arg+"}".toString()); 1019 else 1020 format(body, maxIterations, curArgs, 0, 1021 dst, seenColon, atLeastOnce); 1022 return start + 1; 1023 } 1024 } 1025 1026 public String toString () 1027 { 1028 StringBuffer sbuf = new StringBuffer (); 1029 sbuf.append("LispIterationFormat["); 1030 sbuf.append(body); 1031 sbuf.append("]"); 1032 return sbuf.toString(); 1033 } 1034} 1035 1036class LispChoiceFormat extends ReportFormat 1037{ 1038 int param; 1039 boolean lastIsDefault; 1040 boolean testBoolean; boolean skipIfFalse; 1042 Format[] choices; 1043 1044 public int format(Object [] args, int start, Writer dst, FieldPosition fpos) 1045 throws java.io.IOException 1046 { 1047 Format fmt; 1048 if (testBoolean) { 1050 fmt = choices[args[start] == Boolean.FALSE ? 0 : 1]; 1051 start++; 1052 } 1053 else if (! skipIfFalse) 1054 { 1055 int index = getParam(this.param, LispFormat.PARAM_FROM_LIST, 1056 args, start); 1057 if (param == LispFormat.PARAM_FROM_LIST) start++; 1058 if (index < 0 || index >= choices.length) 1059 { 1060 if (lastIsDefault) 1061 index = choices.length - 1; 1062 else 1063 return start; 1064 } 1065 fmt = choices[index]; 1066 } 1067 else 1068 { 1069 if (args[start] == Boolean.FALSE) 1070 return start + 1; 1071 fmt = choices[0]; 1072 } 1073 return ReportFormat.format(fmt, args, start, dst, fpos); 1074 } 1075} 1076 1077class LispRepositionFormat extends ReportFormat 1078{ 1079 boolean backwards; 1080 boolean absolute; 1081 int count; 1082 1083 public LispRepositionFormat(int count, boolean backwards, boolean absolute) 1084 { 1085 this.count = count; 1086 this.backwards = backwards; 1087 this.absolute = absolute; 1088 } 1089 1090 public int format(Object [] args, int start, Writer dst, FieldPosition fpos) 1091 throws java.io.IOException 1092 { 1093 int count = getParam(this.count, absolute ? 0 : 1, 1094 args, start); 1095 if (!absolute) 1096 { 1097 if (backwards) 1098 count = -count; 1099 count += start; 1100 } 1101 return count < 0 ? 0 : count > args.length ? args.length : count; 1102 } 1103} 1104 1105class LispFreshlineFormat extends ReportFormat 1106{ 1107 int count; 1108 1109 public LispFreshlineFormat (int count) 1110 { 1111 this.count = count; 1112 } 1113 1114 public int format(Object [] args, int start, Writer dst, FieldPosition fpos) 1115 throws java.io.IOException 1116 { 1117 int count = getParam(this.count, 1, args, start); 1118 if (this.count == LispFormat.PARAM_FROM_LIST) start++; 1119 if (count > 0) 1120 { 1121 if (dst instanceof OutPort) 1122 { 1123 ((OutPort) dst).freshLine(); 1124 count--; 1125 } 1126 while (--count >= 0) 1127 dst.write('\n'); 1128 } 1129 return start; 1130 } 1131} 1132 1133class LispTabulateFormat extends ReportFormat 1134{ 1135 boolean relative; 1136 int colnum; 1137 int colinc; 1138 int padChar; 1139 1140 public LispTabulateFormat(int colnum, int colinc, 1141 int padChar, boolean relative) 1142 { 1143 this.colnum = colnum; 1144 this.colinc = colinc; 1145 this.relative = relative; 1146 this.padChar = padChar; 1147 } 1148 1149 public int format(Object [] args, int start, Writer dst, FieldPosition fpos) 1150 throws java.io.IOException 1151 { 1152 int colnum = getParam(this.colnum, 1, args, start); 1153 if (this.colnum == LispFormat.PARAM_FROM_LIST) start++; 1154 int colinc = getParam(this.colinc, 1, args, start); 1155 if (this.colinc == LispFormat.PARAM_FROM_LIST) start++; 1156 char padChar = getParam(this.padChar, ' ', args, start); 1158 if (this.padChar == LispFormat.PARAM_FROM_LIST) start++; 1159 int column = -1; 1160 if (dst instanceof OutPort) 1161 column = ((OutPort) dst).getColumnNumber(); 1162 int spaces; 1163 if (column >= 0) 1164 { 1165 if (! relative) 1166 { 1167 if (column < colnum) 1168 spaces = colnum - column; 1169 else if (colinc <= 0) 1170 spaces = 0; 1171 else 1172 spaces = colinc - (column - colnum) % colinc; 1173 } 1174 else 1175 { 1176 spaces = colnum + colinc - (column + colnum) % colinc; 1177 } 1178 } 1179 else 1180 { 1181 spaces = relative ? colnum : 2; 1182 } 1183 while (--spaces >= 0) 1184 dst.write(padChar); 1185 return start; 1186 } 1187} 1188 1189 1190 1191class LispRealFormat extends ReportFormat 1192{ 1193 char op; 1194 int arg1; 1195 int arg2; 1196 int arg3; 1197 int arg4; 1198 int arg5; 1199 int arg6; 1200 int arg7; 1201 boolean showPlus; 1202 boolean internalPad; 1203 1204 int argsUsed; 1205 1206 LispRealFormat() 1207 { 1208 argsUsed = (arg1 == LispFormat.PARAM_FROM_COUNT 1209 || arg2 == LispFormat.PARAM_FROM_COUNT 1210 || arg3 == LispFormat.PARAM_FROM_COUNT 1211 || arg4 == LispFormat.PARAM_FROM_COUNT 1212 || arg5 == LispFormat.PARAM_FROM_COUNT 1213 || arg6 == LispFormat.PARAM_FROM_COUNT 1214 || arg7 == LispFormat.PARAM_FROM_COUNT) ? 1 : 0; 1215 if (arg1 == LispFormat.PARAM_FROM_LIST) argsUsed += 2; 1216 if (arg2 == LispFormat.PARAM_FROM_LIST) argsUsed += 2; 1217 if (arg3 == LispFormat.PARAM_FROM_LIST) argsUsed += 2; 1218 if (arg4 == LispFormat.PARAM_FROM_LIST) argsUsed += 2; 1219 if (arg5 == LispFormat.PARAM_FROM_LIST) argsUsed += 2; 1220 if (arg6 == LispFormat.PARAM_FROM_LIST) argsUsed += 2; 1221 if (arg7 == LispFormat.PARAM_FROM_LIST) argsUsed += 2; 1222 } 1223 1224 public Format resolve (Object [] args, int start) 1225 { 1226 if (op == '$') 1227 { 1228 FixedRealFormat mfmt = new FixedRealFormat(); 1229 int decimals = getParam(this.arg1, 2, args, start); 1230 if (this.arg1 == LispFormat.PARAM_FROM_LIST) start++; 1231 int digits = getParam(this.arg2, 1, args, start); 1232 if (this.arg2 == LispFormat.PARAM_FROM_LIST) start++; 1233 int width = getParam(this.arg3, 0, args, start); 1234 if (this.arg3 == LispFormat.PARAM_FROM_LIST) start++; 1235 char padChar = getParam(this.arg4, ' ', args, start); 1236 if (this.arg4 == LispFormat.PARAM_FROM_LIST) start++; 1237 1238 mfmt.setMaximumFractionDigits(decimals); 1239 mfmt.setMinimumIntegerDigits(digits); 1240 mfmt.width = width; 1241 mfmt.padChar = padChar; 1242 mfmt.internalPad = internalPad; 1243 mfmt.showPlus = showPlus; 1244 return mfmt; 1245 } 1246 else if (op == 'F') 1247 { 1248 FixedRealFormat mfmt = new FixedRealFormat(); 1249 int width = getParam(this.arg1, 0, args, start); 1250 if (this.arg1 == LispFormat.PARAM_FROM_LIST) start++; 1251 int decimals = getParam(this.arg2, -1, args, start); 1252 if (this.arg2 == LispFormat.PARAM_FROM_LIST) start++; 1253 int scale = getParam(this.arg3, 0, args, start); 1254 if (this.arg3 == LispFormat.PARAM_FROM_LIST) start++; 1255 mfmt.overflowChar = getParam(this.arg4, '\0', args, start); 1256 if (this.arg4 == LispFormat.PARAM_FROM_LIST) start++; 1257 char padChar = getParam(this.arg5, ' ', args, start); 1258 if (this.arg5 == LispFormat.PARAM_FROM_LIST) start++; 1259 mfmt.setMaximumFractionDigits(decimals); 1260 mfmt.setMinimumIntegerDigits(0); 1261 mfmt.width = width; 1262 mfmt.scale = scale; 1263 mfmt.padChar = padChar; 1264 mfmt.internalPad = internalPad; 1265 mfmt.showPlus = showPlus; 1266 return mfmt; 1267 } 1268 else { 1270 ExponentialFormat efmt = new ExponentialFormat(); 1271 efmt.exponentShowSign = true; 1272 efmt.width = getParam(this.arg1, 0, args, start); 1273 if (this.arg1 == LispFormat.PARAM_FROM_LIST) start++; 1274 efmt.fracDigits = getParam(this.arg2, -1, args, start); 1275 if (this.arg2 == LispFormat.PARAM_FROM_LIST) start++; 1276 efmt.expDigits = getParam(this.arg3, 0, args, start); 1277 if (this.arg3 == LispFormat.PARAM_FROM_LIST) start++; 1278 efmt.intDigits = getParam(this.arg4, 1, args, start); 1279 if (this.arg4 == LispFormat.PARAM_FROM_LIST) start++; 1280 efmt.overflowChar = getParam(this.arg5, '\0', args, start); 1281 if (this.arg5 == LispFormat.PARAM_FROM_LIST) start++; 1282 efmt.padChar = getParam(this.arg6, ' ', args, start); 1283 if (this.arg6 == LispFormat.PARAM_FROM_LIST) start++; 1284 efmt.exponentChar = getParam(this.arg7, 'E', args, start); 1285 if (this.arg7 == LispFormat.PARAM_FROM_LIST) start++; 1286 efmt.general = op == 'G'; 1287 efmt.showPlus = showPlus; 1288 return efmt; 1289 } 1290 } 1291 1292 public int format(Object [] args, int start, Writer dst, FieldPosition fpos) 1293 throws java.io.IOException 1294 { 1295 StringBuffer sbuf = new StringBuffer (100); 1296 Format fmt = resolve(args, start); 1297 start += argsUsed >> 1; 1298 RealNum value = (RealNum) args[start++]; 1299 fmt.format(value, sbuf, fpos); 1300 dst.write(sbuf.toString()); 1301 return start; 1302 } 1303} 1304 | Popular Tags |