2 //#if defined(FOUNDATION10) || defined(J2SE13)
\r
5 *******************************************************************************
\r
6 * Copyright (C) 2002-2009, International Business Machines Corporation and *
\r
7 * others. All Rights Reserved. *
\r
8 *******************************************************************************
\r
10 package com.ibm.icu.dev.test.util;
\r
12 import java.io.BufferedReader;
\r
13 import java.io.BufferedWriter;
\r
14 import java.io.File;
\r
15 import java.io.FileInputStream;
\r
16 import java.io.FileOutputStream;
\r
17 import java.io.IOException;
\r
18 import java.io.InputStreamReader;
\r
19 import java.io.OutputStreamWriter;
\r
20 import java.io.PrintWriter;
\r
21 import java.io.StringWriter;
\r
22 import java.text.MessageFormat;
\r
23 import java.util.Collection;
\r
24 import java.util.HashMap;
\r
25 import java.util.HashSet;
\r
26 import java.util.Locale;
\r
27 import java.util.Map;
\r
29 import com.ibm.icu.impl.Utility;
\r
30 import com.ibm.icu.text.NumberFormat;
\r
31 import com.ibm.icu.text.Transliterator;
\r
32 import com.ibm.icu.text.UTF16;
\r
33 import com.ibm.icu.text.UnicodeSet;
\r
35 public class BagFormatter {
\r
36 static final boolean DEBUG = false;
\r
37 public static final boolean SHOW_FILES;
\r
39 boolean showFiles = false;
\r
41 showFiles = System.getProperty("SHOW_FILES") != null;
\r
43 catch (SecurityException e) {
\r
45 SHOW_FILES = showFiles;
\r
48 public static final PrintWriter CONSOLE = new PrintWriter(System.out,true);
\r
50 private static PrintWriter log = CONSOLE;
\r
52 private boolean abbreviated = false;
\r
53 private String separator = ",";
\r
54 private String prefix = "[";
\r
55 private String suffix = "]";
\r
56 private UnicodeProperty.Factory source;
\r
57 private UnicodeLabel nameSource;
\r
58 private UnicodeLabel labelSource;
\r
59 private UnicodeLabel rangeBreakSource;
\r
60 private UnicodeLabel valueSource;
\r
61 private String propName = "";
\r
62 private boolean showCount = true;
\r
63 //private boolean suppressReserved = true;
\r
64 private boolean hexValue = false;
\r
65 private static final String NULL_VALUE = "_NULL_VALUE_";
\r
66 private int fullTotal = -1;
\r
67 private boolean showTotal = true;
\r
68 private String lineSeparator = "\r\n";
\r
69 private Tabber tabber = new Tabber.MonoTabber();
\r
72 * Compare two UnicodeSets, and show the differences
\r
73 * @param name1 name of first set to be compared
\r
74 * @param set1 first set
\r
75 * @param name2 name of second set to be compared
\r
76 * @param set2 second set
\r
77 * @return formatted string
\r
79 public String showSetDifferences(
\r
85 StringWriter result = new StringWriter();
\r
86 showSetDifferences(new PrintWriter(result),name1,set1,name2,set2);
\r
88 return result.getBuffer().toString();
\r
91 public String showSetDifferences(
\r
97 StringWriter result = new StringWriter();
\r
98 showSetDifferences(new PrintWriter(result), name1, set1, name2, set2);
\r
100 return result.getBuffer().toString();
\r
103 public void showSetDifferences(
\r
109 showSetDifferences(pw, name1, set1, name2, set2, -1);
\r
112 * Compare two UnicodeSets, and show the differences
\r
113 * @param name1 name of first set to be compared
\r
114 * @param set1 first set
\r
115 * @param name2 name of second set to be compared
\r
116 * @param set2 second set
\r
118 public void showSetDifferences(
\r
126 if (pw == null) pw = CONSOLE;
\r
127 String[] names = { name1, name2 };
\r
131 if ((flags&1) != 0) {
\r
132 temp = new UnicodeSet(set1).removeAll(set2);
\r
133 pw.print(lineSeparator);
\r
134 pw.print(inOut.format(names));
\r
135 pw.print(lineSeparator);
\r
136 showSetNames(pw, temp);
\r
139 if ((flags&2) != 0) {
\r
140 temp = new UnicodeSet(set2).removeAll(set1);
\r
141 pw.print(lineSeparator);
\r
142 pw.print(outIn.format(names));
\r
143 pw.print(lineSeparator);
\r
144 showSetNames(pw, temp);
\r
147 if ((flags&4) != 0) {
\r
148 temp = new UnicodeSet(set2).retainAll(set1);
\r
149 pw.print(lineSeparator);
\r
150 pw.print(inIn.format(names));
\r
151 pw.print(lineSeparator);
\r
152 showSetNames(pw, temp);
\r
157 public void showSetDifferences(
\r
164 if (pw == null) pw = CONSOLE;
\r
165 String[] names = { name1, name2 };
\r
166 // damn'd collection doesn't have a clone, so
\r
167 // we go with Set, even though that
\r
168 // may not preserve order and duplicates
\r
169 Collection temp = new HashSet(set1);
\r
170 temp.removeAll(set2);
\r
172 pw.println(inOut.format(names));
\r
173 showSetNames(pw, temp);
\r
177 temp.removeAll(set1);
\r
179 pw.println(outIn.format(names));
\r
180 showSetNames(pw, temp);
\r
184 temp.retainAll(set2);
\r
186 pw.println(inIn.format(names));
\r
187 showSetNames(pw, temp);
\r
191 * Returns a list of items in the collection, with each separated by the separator.
\r
192 * Each item must not be null; its toString() is called for a printable representation
\r
193 * @param c source collection
\r
194 * @return a String representation of the list
\r
197 public String showSetNames(Object c) {
\r
198 StringWriter buffer = new StringWriter();
\r
199 PrintWriter output = new PrintWriter(buffer);
\r
200 showSetNames(output,c);
\r
201 return buffer.toString();
\r
205 * Returns a list of items in the collection, with each separated by the separator.
\r
206 * Each item must not be null; its toString() is called for a printable representation
\r
207 * @param output destination to which to write names
\r
208 * @param c source collection
\r
211 public void showSetNames(PrintWriter output, Object c) {
\r
212 mainVisitor.doAt(c, output);
\r
217 * Returns a list of items in the collection, with each separated by the separator.
\r
218 * Each item must not be null; its toString() is called for a printable representation
\r
219 * @param filename destination to which to write names
\r
220 * @param c source collection
\r
223 public void showSetNames(String filename, Object c) throws IOException {
\r
224 PrintWriter pw = new PrintWriter(
\r
225 new OutputStreamWriter(
\r
226 new FileOutputStream(filename),"utf-8"));
\r
227 showSetNames(log,c);
\r
231 public String getAbbreviatedName(
\r
234 String substitute) {
\r
236 int matchEnd = NameIterator.findMatchingEnd(src, pattern);
\r
237 int sdiv = src.length() - matchEnd;
\r
238 int pdiv = pattern.length() - matchEnd;
\r
239 StringBuffer result = new StringBuffer();
\r
241 src.substring(0, sdiv),
\r
242 pattern.substring(0, pdiv),
\r
246 src.substring(sdiv),
\r
247 pattern.substring(pdiv),
\r
250 return result.toString();
\r
253 abstract public static class Relation {
\r
254 abstract public String getRelation(String a, String b);
\r
257 static class NullRelation extends Relation {
\r
258 public String getRelation(String a, String b) { return ""; }
\r
261 private Relation r = new NullRelation();
\r
263 public BagFormatter setRelation(Relation r) {
\r
265 return this; // for chaining
\r
268 public Relation getRelation() {
\r
273 r.getRelati on(last, s) + quote(s) + "\t#" + UnicodeSetFormatter.getResolvedName(s)
\r
276 static final UnicodeSet NO_NAME =
\r
277 new UnicodeSet("[\\u0080\\u0081\\u0084\\u0099\\p{Cn}\\p{Co}]");
\r
278 static final UnicodeSet HAS_NAME = new UnicodeSet(NO_NAME).complement();
\r
279 static final UnicodeSet NAME_CHARACTERS =
\r
280 new UnicodeSet("[A-Za-z0-9\\<\\>\\-\\ ]");
\r
282 public UnicodeSet getSetForName(String namePattern) {
\r
283 UnicodeSet result = new UnicodeSet();
\r
284 Matcher m = Pattern.compile(namePattern).matcher("");
\r
285 // check for no-name items, and add in bulk
\r
286 m.reset("<no name>");
\r
288 result.addAll(NO_NAME);
\r
290 // check all others
\r
291 UnicodeSetIterator usi = new UnicodeSetIterator(HAS_NAME);
\r
292 while (usi.next()) {
\r
293 String name = getName(usi.codepoint);
\r
298 result.add(usi.codepoint);
\r
301 // Note: if Regex had some API so that if we could tell that
\r
302 // an initial substring couldn't match, e.g. "CJK IDEOGRAPH-"
\r
303 // then we could optimize by skipping whole swathes of characters
\r
308 public BagFormatter setMergeRanges(boolean in) {
\r
312 public BagFormatter setShowSetAlso(boolean b) {
\r
317 public String getName(int codePoint) {
\r
318 return getName("", codePoint, codePoint);
\r
321 public String getName(String sep, int start, int end) {
\r
322 if (getNameSource() == null || getNameSource() == UnicodeLabel.NULL) return "";
\r
323 String result = getName(start, false);
\r
324 if (start == end) return sep + result;
\r
325 String endString = getName(end, false);
\r
326 if (result.length() == 0 && endString.length() == 0) return sep;
\r
327 if (abbreviated) endString = getAbbreviatedName(endString,result,"~");
\r
328 return sep + result + ".." + endString;
\r
331 public String getName(String s) {
\r
332 return getName(s, false);
\r
335 public static class NameLabel extends UnicodeLabel {
\r
336 UnicodeProperty nameProp;
\r
337 UnicodeSet control;
\r
338 UnicodeSet private_use;
\r
339 UnicodeSet noncharacter;
\r
340 UnicodeSet surrogate;
\r
342 public NameLabel(UnicodeProperty.Factory source) {
\r
343 nameProp = source.getProperty("Name");
\r
344 control = source.getSet("gc=Cc");
\r
345 private_use = source.getSet("gc=Co");
\r
346 surrogate = source.getSet("gc=Cs");
\r
347 noncharacter = source.getSet("noncharactercodepoint=yes");
\r
350 public String getValue(int codePoint, boolean isShort) {
\r
351 String hcp = !isShort
\r
352 ? "U+" + Utility.hex(codePoint, 4) + " "
\r
354 String result = nameProp.getValue(codePoint);
\r
355 if (result != null)
\r
356 return hcp + result;
\r
357 if (control.contains(codePoint)) {
\r
358 return "<control-" + Utility.hex(codePoint, 4) + ">";
\r
360 if (private_use.contains(codePoint)) {
\r
361 return "<private-use-" + Utility.hex(codePoint, 4) + ">";
\r
363 if (surrogate.contains(codePoint)) {
\r
364 return "<surrogate-" + Utility.hex(codePoint, 4) + ">";
\r
366 if (noncharacter.contains(codePoint)) {
\r
367 return "<noncharacter-" + Utility.hex(codePoint, 4) + ">";
\r
369 //if (suppressReserved) return "";
\r
370 return hcp + "<reserved-" + Utility.hex(codePoint, 4) + ">";
\r
376 public String getName(int codePoint, boolean withCodePoint) {
\r
377 String result = getNameSource().getValue(codePoint, !withCodePoint);
\r
378 return fixName == null ? result : fixName.transliterate(result);
\r
381 public String getName(String s, boolean withCodePoint) {
\r
382 String result = getNameSource().getValue(s, separator, !withCodePoint);
\r
383 return fixName == null ? result : fixName.transliterate(result);
\r
386 public String hex(String s) {
\r
387 return hex(s,separator);
\r
390 public String hex(String s, String sep) {
\r
391 return UnicodeLabel.HEX.getValue(s, sep, true);
\r
394 public String hex(int start, int end) {
\r
395 String s = Utility.hex(start,4);
\r
396 if (start == end) return s;
\r
397 return s + ".." + Utility.hex(end,4);
\r
400 public BagFormatter setUnicodePropertyFactory(UnicodeProperty.Factory source) {
\r
401 this.source = source;
\r
405 public UnicodeProperty.Factory getUnicodePropertyFactory() {
\r
406 if (source == null) source = ICUPropertyFactory.make();
\r
410 public BagFormatter () {
\r
413 public BagFormatter (UnicodeProperty.Factory source) {
\r
414 setUnicodePropertyFactory(source);
\r
417 public String join(Object o) {
\r
418 return labelVisitor.join(o);
\r
421 // ===== PRIVATES =====
\r
423 private Join labelVisitor = new Join();
\r
425 private boolean mergeRanges = true;
\r
426 private Transliterator showLiteral = null;
\r
427 private Transliterator fixName = null;
\r
428 private boolean showSetAlso = false;
\r
430 private RangeFinder rf = new RangeFinder();
\r
432 private MessageFormat inOut = new MessageFormat("In {0}, but not in {1}:");
\r
433 private MessageFormat outIn = new MessageFormat("Not in {0}, but in {1}:");
\r
434 private MessageFormat inIn = new MessageFormat("In both {0}, and in {1}:");
\r
436 private MyVisitor mainVisitor = new MyVisitor();
\r
439 private String getLabels(int start, int end) {
\r
440 Set names = new TreeSet();
\r
441 for (int cp = start; cp <= end; ++cp) {
\r
442 names.add(getLabel(cp));
\r
444 return labelVisitor.join(names);
\r
448 private void addMatching(
\r
452 StringBuffer result) {
\r
453 NameIterator n1 = new NameIterator(src);
\r
454 NameIterator n2 = new NameIterator(pattern);
\r
455 boolean first = true;
\r
457 String s1 = n1.next();
\r
460 String s2 = n2.next();
\r
462 result.append(" ");
\r
465 result.append(substitute);
\r
471 private static NumberFormat nf =
\r
472 NumberFormat.getIntegerInstance(Locale.ENGLISH);
\r
474 nf.setGroupingUsed(false);
\r
477 private class MyVisitor extends Visitor {
\r
478 private PrintWriter output;
\r
479 String commentSeparator;
\r
484 boolean inTable = false;
\r
486 public void toOutput(String s) {
\r
489 output.print("</table>");
\r
492 output.print("<p>");
\r
496 output.println("</p>");
\r
498 output.print(lineSeparator);
\r
501 public void toTable(String s) {
\r
502 if (isHtml && !inTable) {
\r
503 output.print("<table>");
\r
506 output.print(tabber.process(s) + lineSeparator);
\r
509 public void doAt(Object c, PrintWriter out) {
\r
511 isHtml = tabber instanceof Tabber.HTMLTabber;
\r
516 // 0009..000D ; White_Space # Cc [5] <control-0009>..<control-000D>
\r
518 // 0009..000D ; White_Space #Cc [5] <control>..<control>
\r
519 tabber.add(mergeRanges ? 14 : 6,Tabber.LEFT);
\r
521 if (propName.length() > 0) {
\r
522 tabber.add(propName.length() + 2,Tabber.LEFT);
\r
525 valueSize = getValueSource().getMaxWidth(shortValue);
\r
526 if (DEBUG) System.out.println("ValueSize: " + valueSize);
\r
527 if (valueSize > 0) {
\r
528 tabber.add(valueSize + 2,Tabber.LEFT); // value
\r
531 tabber.add(3,Tabber.LEFT); // comment character
\r
533 labelSize = getLabelSource(true).getMaxWidth(shortLabel);
\r
534 if (labelSize > 0) {
\r
535 tabber.add(labelSize + 1,Tabber.LEFT); // value
\r
538 if (mergeRanges && showCount) {
\r
539 tabber.add(5,Tabber.RIGHT);
\r
542 if (showLiteral != null) {
\r
543 tabber.add(4,Tabber.LEFT);
\r
545 //myTabber.add(7,Tabber.LEFT);
\r
547 commentSeparator = (showCount || showLiteral != null
\r
548 || getLabelSource(true) != UnicodeLabel.NULL
\r
549 || getNameSource() != UnicodeLabel.NULL)
\r
552 if (DEBUG) System.out.println("Tabber: " + tabber.toString());
\r
553 if (DEBUG) System.out.println("Tabber: " + tabber.process(
\r
554 "200C..200D\t; White_Space\t #\tCf\t [2]\t ZERO WIDTH NON-JOINER..ZERO WIDTH JOINER"));
\r
558 public String format(Object o) {
\r
559 StringWriter sw = new StringWriter();
\r
560 PrintWriter pw = new PrintWriter(sw);
\r
563 String result = sw.getBuffer().toString();
\r
568 protected void doBefore(Object container, Object o) {
\r
569 if (showSetAlso && container instanceof UnicodeSet) {
\r
570 toOutput("#" + container);
\r
574 protected void doBetween(Object container, Object lastItem, Object nextItem) {
\r
577 protected void doAfter(Object container, Object o) {
\r
578 if (fullTotal != -1 && fullTotal != counter) {
\r
581 toOutput("# The above property value applies to " + nf.format(fullTotal-counter) + " code points not listed here.");
\r
582 toOutput("# Total code points: " + nf.format(fullTotal));
\r
585 } else if (showTotal) {
\r
587 toOutput("# Total code points: " + nf.format(counter));
\r
591 protected void doSimpleAt(Object o) {
\r
592 if (o instanceof Map.Entry) {
\r
593 Map.Entry oo = (Map.Entry)o;
\r
594 Object key = oo.getKey();
\r
595 Object value = oo.getValue();
\r
598 output.println("\u2192");
\r
602 } else if (o instanceof Visitor.CodePointRange) {
\r
603 doAt((Visitor.CodePointRange) o);
\r
605 String thing = o.toString();
\r
606 String value = getValueSource() == UnicodeLabel.NULL ? "" : getValueSource().getValue(thing, ",", true);
\r
607 if (getValueSource() != UnicodeLabel.NULL) value = "\t; " + value;
\r
608 String label = getLabelSource(true) == UnicodeLabel.NULL ? "" : getLabelSource(true).getValue(thing, ",", true);
\r
609 if (label.length() != 0) label = " " + label;
\r
615 + insertLiteral(thing)
\r
622 protected void doAt(Visitor.CodePointRange usi) {
\r
623 if (!mergeRanges) {
\r
624 for (int cp = usi.codepoint; cp <= usi.codepointEnd; ++cp) {
\r
628 rf.reset(usi.codepoint, usi.codepointEnd + 1);
\r
629 while (rf.next()) {
\r
630 showLine(rf.start, rf.limit - 1);
\r
635 private void showLine(int start, int end) {
\r
636 String label = getLabelSource(true).getValue(start, shortLabel);
\r
637 String value = getValue(start, shortValue);
\r
638 if (value == NULL_VALUE) return;
\r
640 counter += end - start + 1;
\r
641 String pn = propName;
\r
642 if (pn.length() != 0) {
\r
645 if (valueSize > 0) {
\r
646 value = "\t; " + value;
\r
647 } else if (value.length() > 0) {
\r
648 throw new IllegalArgumentException("maxwidth bogus " + value + "," + getValueSource().getMaxWidth(shortValue));
\r
650 if (labelSize > 0) {
\r
651 label = "\t" + label;
\r
652 } else if (label.length() > 0) {
\r
653 throw new IllegalArgumentException("maxwidth bogus " + label + ", " + getLabelSource(true).getMaxWidth(shortLabel));
\r
657 if (mergeRanges && showCount) {
\r
658 if (end == start) count = "\t";
\r
659 else count = "\t ["+ nf.format(end - start + 1)+ "]";
\r
669 + insertLiteral(start, end)
\r
670 + getName("\t ", start, end));
\r
673 private String insertLiteral(String thing) {
\r
674 return (showLiteral == null ? ""
\r
675 : " \t(" + showLiteral.transliterate(thing) + ") ");
\r
678 private String insertLiteral(int start, int end) {
\r
679 return (showLiteral == null ? "" :
\r
680 " \t(" + showLiteral.transliterate(UTF16.valueOf(start))
\r
682 ? (".." + showLiteral.transliterate(UTF16.valueOf(end)))
\r
687 private String insertLiteral(int cp) {
\r
688 return (showLiteral == null ? ""
\r
689 : " \t(" + showLiteral.transliterate(UTF16.valueOf(cp)) + ") ");
\r
695 * Iterate through a string, breaking at words.
\r
698 private static class NameIterator {
\r
704 NameIterator(String source) {
\r
705 this.source = source;
\r
707 this.limit = source.length();
\r
710 * Find next word, including trailing spaces
\r
711 * @return the next word
\r
714 if (position >= limit)
\r
716 int pos = source.indexOf(' ', position);
\r
717 if (pos < 0 || pos >= limit)
\r
719 String result = source.substring(position, pos);
\r
720 position = pos + 1;
\r
724 static int findMatchingEnd(String s1, String s2) {
\r
725 int i = s1.length();
\r
726 int j = s2.length();
\r
729 --i; // decrement both before calling function!
\r
731 if (s1.charAt(i) != s2.charAt(j))
\r
734 } catch (Exception e) {} // run off start
\r
736 ++i; // counteract increment
\r
737 i = s1.indexOf(' ', i); // move forward to space
\r
740 return s1.length() - i;
\r
744 private class RangeFinder {
\r
746 private int veryLimit;
\r
747 //String label, value;
\r
748 void reset(int rangeStart, int rangeLimit) {
\r
749 limit = rangeStart;
\r
750 veryLimit = rangeLimit;
\r
753 if (limit >= veryLimit)
\r
755 start = limit; // set to end of last
\r
756 String label = getLabelSource(false).getValue(limit, true);
\r
757 String value = getValue(limit, true);
\r
758 String breaker = getRangeBreakSource().getValue(limit,true);
\r
759 if (DEBUG && limit < 0x7F) System.out.println("Label: " + label + ", Value: " + value + ", Break: " + breaker);
\r
761 for (; limit < veryLimit; limit++) {
\r
762 String s = getLabelSource(false).getValue(limit, true);
\r
763 String v = getValue(limit, true);
\r
764 String b = getRangeBreakSource().getValue(limit, true);
\r
765 if (DEBUG && limit < 0x7F) System.out.println("*Label: " + label + ", Value: " + value + ", Break: " + breaker);
\r
766 if (!equalTo(s, label) || !equalTo(v, value) || !equalTo(b, breaker)) break;
\r
768 // at this point, limit is the first item that has a different label than source
\r
769 // OR, we got to the end, and limit == veryLimit
\r
774 boolean equalTo(Object a, Object b) {
\r
775 if (a == b) return true;
\r
776 if (a == null) return false;
\r
777 return a.equals(b);
\r
780 boolean shortLabel = true;
\r
781 boolean shortValue = true;
\r
783 public String getPrefix() {
\r
787 public String getSuffix() {
\r
791 public BagFormatter setPrefix(String string) {
\r
796 public BagFormatter setSuffix(String string) {
\r
801 public boolean isAbbreviated() {
\r
802 return abbreviated;
\r
805 public BagFormatter setAbbreviated(boolean b) {
\r
810 public UnicodeLabel getLabelSource(boolean visible) {
\r
811 if (labelSource == null) {
\r
812 Map labelMap = new HashMap();
\r
813 //labelMap.put("Lo","L&");
\r
814 labelMap.put("Lu","L&");
\r
815 labelMap.put("Lt","L&");
\r
816 labelMap.put("Ll","L&");
\r
817 labelSource = new UnicodeProperty.FilteredProperty(
\r
818 getUnicodePropertyFactory().getProperty("General_Category"),
\r
819 new UnicodeProperty.MapFilter(labelMap)
\r
820 ).setAllowValueAliasCollisions(true);
\r
822 return labelSource;
\r
828 public static void addAll(UnicodeSet source, Collection target) {
\r
829 source.addAllTo(target);
\r
834 public static final Transliterator hex = Transliterator.getInstance(
\r
835 "[^\\u0009\\u0020-\\u007E\\u00A0-\\u00FF] hex");
\r
837 public static BufferedReader openUTF8Reader(String dir, String filename) throws IOException {
\r
838 return openReader(dir,filename,"UTF-8");
\r
841 public static BufferedReader openReader(String dir, String filename, String encoding) throws IOException {
\r
842 File file = new File(dir, filename);
\r
843 if (SHOW_FILES && log != null) {
\r
844 log.println("Opening File: "
\r
845 + file.getCanonicalPath());
\r
847 return new BufferedReader(
\r
848 new InputStreamReader(
\r
849 new FileInputStream(file),
\r
854 public static PrintWriter openUTF8Writer(String dir, String filename) throws IOException {
\r
855 return openWriter(dir,filename,"UTF-8");
\r
858 public static PrintWriter openWriter(String dir, String filename, String encoding) throws IOException {
\r
859 File file = new File(dir, filename);
\r
860 if (SHOW_FILES && log != null) {
\r
861 log.println("Creating File: "
\r
862 + file.getCanonicalPath());
\r
864 String parentName = file.getParent();
\r
865 if (parentName != null) {
\r
866 File parent = new File(parentName);
\r
869 return new PrintWriter(
\r
870 new BufferedWriter(
\r
871 new OutputStreamWriter(
\r
872 new FileOutputStream(file),
\r
876 public static PrintWriter getLog() {
\r
879 public BagFormatter setLog(PrintWriter writer) {
\r
883 public String getSeparator() {
\r
886 public BagFormatter setSeparator(String string) {
\r
887 separator = string;
\r
890 public Transliterator getShowLiteral() {
\r
891 return showLiteral;
\r
893 public BagFormatter setShowLiteral(Transliterator transliterator) {
\r
894 showLiteral = transliterator;
\r
898 // ===== CONVENIENCES =====
\r
899 private class Join extends Visitor {
\r
900 StringBuffer output = new StringBuffer();
\r
902 String join (Object o) {
\r
903 output.setLength(0);
\r
905 return output.toString();
\r
907 protected void doBefore(Object container, Object item) {
\r
909 output.append(prefix);
\r
911 protected void doAfter(Object container, Object item) {
\r
912 output.append(suffix);
\r
915 protected void doBetween(Object container, Object lastItem, Object nextItem) {
\r
916 output.append(separator);
\r
918 protected void doSimpleAt(Object o) {
\r
919 if (o != null) output.append(o.toString());
\r
926 public BagFormatter setLabelSource(UnicodeLabel label) {
\r
927 if (label == null) label = UnicodeLabel.NULL;
\r
928 labelSource = label;
\r
933 * @return the NameLable representing the source
\r
935 public UnicodeLabel getNameSource() {
\r
936 if (nameSource == null) {
\r
937 nameSource = new NameLabel(getUnicodePropertyFactory());
\r
945 public BagFormatter setNameSource(UnicodeLabel label) {
\r
946 if (label == null) label = UnicodeLabel.NULL;
\r
947 nameSource = label;
\r
952 * @return the UnicodeLabel representing the value
\r
954 public UnicodeLabel getValueSource() {
\r
955 if (valueSource == null) valueSource = UnicodeLabel.NULL;
\r
956 return valueSource;
\r
959 private String getValue(int cp, boolean shortVal) {
\r
960 String result = getValueSource().getValue(cp, shortVal);
\r
961 if (result == null) return NULL_VALUE;
\r
962 if (hexValue) result = hex(result, " ");
\r
969 public BagFormatter setValueSource(UnicodeLabel label) {
\r
970 if (label == null) label = UnicodeLabel.NULL;
\r
971 valueSource = label;
\r
975 public BagFormatter setValueSource(String label) {
\r
976 return setValueSource(new UnicodeLabel.Constant(label));
\r
980 * @return true if showCount is true
\r
982 public boolean isShowCount() {
\r
987 * @param b true to show the count
\r
988 * @return this (for chaining)
\r
990 public BagFormatter setShowCount(boolean b) {
\r
996 * @return the property name
\r
998 public String getPropName() {
\r
1004 * @return this (for chaining)
\r
1006 public BagFormatter setPropName(String string) {
\r
1007 if (string == null) string = "";
\r
1008 propName = string;
\r
1013 * @return true if this is a hexValue
\r
1015 public boolean isHexValue() {
\r
1021 * @return this (for chaining)
\r
1023 public BagFormatter setHexValue(boolean b) {
\r
1029 * @return the full total
\r
1031 public int getFullTotal() {
\r
1036 * @param i set the full total
\r
1037 * @return this (for chaining)
\r
1039 public BagFormatter setFullTotal(int i) {
\r
1045 * @return the line separator
\r
1047 public String getLineSeparator() {
\r
1048 return lineSeparator;
\r
1053 * @return this (for chaining)
\r
1055 public BagFormatter setLineSeparator(String string) {
\r
1056 lineSeparator = string;
\r
1061 * @return the UnicodeLabel representing the range break source
\r
1063 public UnicodeLabel getRangeBreakSource() {
\r
1064 if (rangeBreakSource == null) {
\r
1065 Map labelMap = new HashMap();
\r
1066 // reflects the code point types on p 25
\r
1067 labelMap.put("Lo", "G&");
\r
1068 labelMap.put("Lm", "G&");
\r
1069 labelMap.put("Lu", "G&");
\r
1070 labelMap.put("Lt", "G&");
\r
1071 labelMap.put("Ll", "G&");
\r
1072 labelMap.put("Mn", "G&");
\r
1073 labelMap.put("Me", "G&");
\r
1074 labelMap.put("Mc", "G&");
\r
1075 labelMap.put("Nd", "G&");
\r
1076 labelMap.put("Nl", "G&");
\r
1077 labelMap.put("No", "G&");
\r
1078 labelMap.put("Zs", "G&");
\r
1079 labelMap.put("Pd", "G&");
\r
1080 labelMap.put("Ps", "G&");
\r
1081 labelMap.put("Pe", "G&");
\r
1082 labelMap.put("Pc", "G&");
\r
1083 labelMap.put("Po", "G&");
\r
1084 labelMap.put("Pi", "G&");
\r
1085 labelMap.put("Pf", "G&");
\r
1086 labelMap.put("Sm", "G&");
\r
1087 labelMap.put("Sc", "G&");
\r
1088 labelMap.put("Sk", "G&");
\r
1089 labelMap.put("So", "G&");
\r
1091 labelMap.put("Zl", "Cf");
\r
1092 labelMap.put("Zp", "Cf");
\r
1094 rangeBreakSource =
\r
1095 new UnicodeProperty
\r
1096 .FilteredProperty(
\r
1097 getUnicodePropertyFactory().getProperty(
\r
1098 "General_Category"),
\r
1099 new UnicodeProperty.MapFilter(labelMap))
\r
1100 .setAllowValueAliasCollisions(true);
\r
1103 "Cn", // = Other, Not Assigned 0
\r
1104 "Cc", // = Other, Control 15
\r
1105 "Cf", // = Other, Format 16
\r
1106 UnicodeProperty.UNUSED, // missing
\r
1107 "Co", // = Other, Private Use 18
\r
1108 "Cs", // = Other, Surrogate 19
\r
1111 return rangeBreakSource;
\r
1117 public BagFormatter setRangeBreakSource(UnicodeLabel label) {
\r
1118 if (label == null) label = UnicodeLabel.NULL;
\r
1119 rangeBreakSource = label;
\r
1124 * @return Returns the fixName.
\r
1126 public Transliterator getFixName() {
\r
1130 * @param fixName The fixName to set.
\r
1132 public void setFixName(Transliterator fixName) {
\r
1133 this.fixName = fixName;
\r
1136 public Tabber getTabber() {
\r
1140 public void setTabber(Tabber tabber) {
\r
1141 this.tabber = tabber;
\r
1144 public boolean isShowTotal() {
\r
1148 public void setShowTotal(boolean showTotal) {
\r
1149 this.showTotal = showTotal;
\r