2 *******************************************************************************
\r
3 * Copyright (C) 2002-2010, International Business Machines Corporation and *
\r
4 * others. All Rights Reserved. *
\r
5 *******************************************************************************
\r
7 package com.ibm.icu.dev.test.util;
\r
9 import java.io.BufferedReader;
\r
10 import java.io.BufferedWriter;
\r
11 import java.io.File;
\r
12 import java.io.FileInputStream;
\r
13 import java.io.FileOutputStream;
\r
14 import java.io.IOException;
\r
15 import java.io.InputStreamReader;
\r
16 import java.io.OutputStreamWriter;
\r
17 import java.io.PrintWriter;
\r
18 import java.io.StringWriter;
\r
19 import java.text.MessageFormat;
\r
20 import java.util.Collection;
\r
21 import java.util.HashMap;
\r
22 import java.util.HashSet;
\r
23 import java.util.Locale;
\r
24 import java.util.Map;
\r
26 import com.ibm.icu.impl.Utility;
\r
27 import com.ibm.icu.text.NumberFormat;
\r
28 import com.ibm.icu.text.Transliterator;
\r
29 import com.ibm.icu.text.UTF16;
\r
30 import com.ibm.icu.text.UnicodeSet;
\r
32 public class BagFormatter {
\r
33 static final boolean DEBUG = false;
\r
34 public static final boolean SHOW_FILES;
\r
36 boolean showFiles = false;
\r
38 showFiles = System.getProperty("SHOW_FILES") != null;
\r
40 catch (SecurityException e) {
\r
42 SHOW_FILES = showFiles;
\r
45 public static final PrintWriter CONSOLE = new PrintWriter(System.out,true);
\r
47 private static PrintWriter log = CONSOLE;
\r
49 private boolean abbreviated = false;
\r
50 private String separator = ",";
\r
51 private String prefix = "[";
\r
52 private String suffix = "]";
\r
53 private UnicodeProperty.Factory source;
\r
54 private UnicodeLabel nameSource;
\r
55 private UnicodeLabel labelSource;
\r
56 private UnicodeLabel rangeBreakSource;
\r
57 private UnicodeLabel valueSource;
\r
58 private String propName = "";
\r
59 private boolean showCount = true;
\r
60 //private boolean suppressReserved = true;
\r
61 private boolean hexValue = false;
\r
62 private static final String NULL_VALUE = "_NULL_VALUE_";
\r
63 private int fullTotal = -1;
\r
64 private boolean showTotal = true;
\r
65 private String lineSeparator = "\r\n";
\r
66 private Tabber tabber = new Tabber.MonoTabber();
\r
69 * Compare two UnicodeSets, and show the differences
\r
70 * @param name1 name of first set to be compared
\r
71 * @param set1 first set
\r
72 * @param name2 name of second set to be compared
\r
73 * @param set2 second set
\r
74 * @return formatted string
\r
76 public String showSetDifferences(
\r
82 StringWriter result = new StringWriter();
\r
83 showSetDifferences(new PrintWriter(result),name1,set1,name2,set2);
\r
85 return result.getBuffer().toString();
\r
88 public String showSetDifferences(
\r
94 StringWriter result = new StringWriter();
\r
95 showSetDifferences(new PrintWriter(result), name1, set1, name2, set2);
\r
97 return result.getBuffer().toString();
\r
100 public void showSetDifferences(
\r
106 showSetDifferences(pw, name1, set1, name2, set2, -1);
\r
109 * Compare two UnicodeSets, and show the differences
\r
110 * @param name1 name of first set to be compared
\r
111 * @param set1 first set
\r
112 * @param name2 name of second set to be compared
\r
113 * @param set2 second set
\r
115 public void showSetDifferences(
\r
123 if (pw == null) pw = CONSOLE;
\r
124 String[] names = { name1, name2 };
\r
128 if ((flags&1) != 0) {
\r
129 temp = new UnicodeSet(set1).removeAll(set2);
\r
130 pw.print(lineSeparator);
\r
131 pw.print(inOut.format(names));
\r
132 pw.print(lineSeparator);
\r
133 showSetNames(pw, temp);
\r
136 if ((flags&2) != 0) {
\r
137 temp = new UnicodeSet(set2).removeAll(set1);
\r
138 pw.print(lineSeparator);
\r
139 pw.print(outIn.format(names));
\r
140 pw.print(lineSeparator);
\r
141 showSetNames(pw, temp);
\r
144 if ((flags&4) != 0) {
\r
145 temp = new UnicodeSet(set2).retainAll(set1);
\r
146 pw.print(lineSeparator);
\r
147 pw.print(inIn.format(names));
\r
148 pw.print(lineSeparator);
\r
149 showSetNames(pw, temp);
\r
154 public void showSetDifferences(
\r
161 if (pw == null) pw = CONSOLE;
\r
162 String[] names = { name1, name2 };
\r
163 // damn'd collection doesn't have a clone, so
\r
164 // we go with Set, even though that
\r
165 // may not preserve order and duplicates
\r
166 Collection temp = new HashSet(set1);
\r
167 temp.removeAll(set2);
\r
169 pw.println(inOut.format(names));
\r
170 showSetNames(pw, temp);
\r
174 temp.removeAll(set1);
\r
176 pw.println(outIn.format(names));
\r
177 showSetNames(pw, temp);
\r
181 temp.retainAll(set2);
\r
183 pw.println(inIn.format(names));
\r
184 showSetNames(pw, temp);
\r
188 * Returns a list of items in the collection, with each separated by the separator.
\r
189 * Each item must not be null; its toString() is called for a printable representation
\r
190 * @param c source collection
\r
191 * @return a String representation of the list
\r
193 public String showSetNames(Object c) {
\r
194 StringWriter buffer = new StringWriter();
\r
195 PrintWriter output = new PrintWriter(buffer);
\r
196 showSetNames(output,c);
\r
197 return buffer.toString();
\r
201 * Returns a list of items in the collection, with each separated by the separator.
\r
202 * Each item must not be null; its toString() is called for a printable representation
\r
203 * @param output destination to which to write names
\r
204 * @param c source collection
\r
206 public void showSetNames(PrintWriter output, Object c) {
\r
207 mainVisitor.doAt(c, output);
\r
212 * Returns a list of items in the collection, with each separated by the separator.
\r
213 * Each item must not be null; its toString() is called for a printable representation
\r
214 * @param filename destination to which to write names
\r
215 * @param c source collection
\r
217 public void showSetNames(String filename, Object c) throws IOException {
\r
218 PrintWriter pw = new PrintWriter(
\r
219 new OutputStreamWriter(
\r
220 new FileOutputStream(filename),"utf-8"));
\r
221 showSetNames(log,c);
\r
225 public String getAbbreviatedName(
\r
228 String substitute) {
\r
230 int matchEnd = NameIterator.findMatchingEnd(src, pattern);
\r
231 int sdiv = src.length() - matchEnd;
\r
232 int pdiv = pattern.length() - matchEnd;
\r
233 StringBuffer result = new StringBuffer();
\r
235 src.substring(0, sdiv),
\r
236 pattern.substring(0, pdiv),
\r
240 src.substring(sdiv),
\r
241 pattern.substring(pdiv),
\r
244 return result.toString();
\r
247 abstract public static class Relation {
\r
248 abstract public String getRelation(String a, String b);
\r
251 static class NullRelation extends Relation {
\r
252 public String getRelation(String a, String b) { return ""; }
\r
255 private Relation r = new NullRelation();
\r
257 public BagFormatter setRelation(Relation r) {
\r
259 return this; // for chaining
\r
262 public Relation getRelation() {
\r
267 r.getRelati on(last, s) + quote(s) + "\t#" + UnicodeSetFormatter.getResolvedName(s)
\r
270 static final UnicodeSet NO_NAME =
\r
271 new UnicodeSet("[\\u0080\\u0081\\u0084\\u0099\\p{Cn}\\p{Co}]");
\r
272 static final UnicodeSet HAS_NAME = new UnicodeSet(NO_NAME).complement();
\r
273 static final UnicodeSet NAME_CHARACTERS =
\r
274 new UnicodeSet("[A-Za-z0-9\\<\\>\\-\\ ]");
\r
276 public UnicodeSet getSetForName(String namePattern) {
\r
277 UnicodeSet result = new UnicodeSet();
\r
278 Matcher m = Pattern.compile(namePattern).matcher("");
\r
279 // check for no-name items, and add in bulk
\r
280 m.reset("<no name>");
\r
282 result.addAll(NO_NAME);
\r
284 // check all others
\r
285 UnicodeSetIterator usi = new UnicodeSetIterator(HAS_NAME);
\r
286 while (usi.next()) {
\r
287 String name = getName(usi.codepoint);
\r
292 result.add(usi.codepoint);
\r
295 // Note: if Regex had some API so that if we could tell that
\r
296 // an initial substring couldn't match, e.g. "CJK IDEOGRAPH-"
\r
297 // then we could optimize by skipping whole swathes of characters
\r
302 public BagFormatter setMergeRanges(boolean in) {
\r
306 public BagFormatter setShowSetAlso(boolean b) {
\r
311 public String getName(int codePoint) {
\r
312 return getName("", codePoint, codePoint);
\r
315 public String getName(String sep, int start, int end) {
\r
316 if (getNameSource() == null || getNameSource() == UnicodeLabel.NULL) return "";
\r
317 String result = getName(start, false);
\r
318 if (start == end) return sep + result;
\r
319 String endString = getName(end, false);
\r
320 if (result.length() == 0 && endString.length() == 0) return sep;
\r
321 if (abbreviated) endString = getAbbreviatedName(endString,result,"~");
\r
322 return sep + result + ".." + endString;
\r
325 public String getName(String s) {
\r
326 return getName(s, false);
\r
329 public static class NameLabel extends UnicodeLabel {
\r
330 UnicodeProperty nameProp;
\r
331 UnicodeSet control;
\r
332 UnicodeSet private_use;
\r
333 UnicodeSet noncharacter;
\r
334 UnicodeSet surrogate;
\r
336 public NameLabel(UnicodeProperty.Factory source) {
\r
337 nameProp = source.getProperty("Name");
\r
338 control = source.getSet("gc=Cc");
\r
339 private_use = source.getSet("gc=Co");
\r
340 surrogate = source.getSet("gc=Cs");
\r
341 noncharacter = source.getSet("noncharactercodepoint=yes");
\r
344 public String getValue(int codePoint, boolean isShort) {
\r
345 String hcp = !isShort
\r
346 ? "U+" + Utility.hex(codePoint, 4) + " "
\r
348 String result = nameProp.getValue(codePoint);
\r
349 if (result != null)
\r
350 return hcp + result;
\r
351 if (control.contains(codePoint)) {
\r
352 return "<control-" + Utility.hex(codePoint, 4) + ">";
\r
354 if (private_use.contains(codePoint)) {
\r
355 return "<private-use-" + Utility.hex(codePoint, 4) + ">";
\r
357 if (surrogate.contains(codePoint)) {
\r
358 return "<surrogate-" + Utility.hex(codePoint, 4) + ">";
\r
360 if (noncharacter.contains(codePoint)) {
\r
361 return "<noncharacter-" + Utility.hex(codePoint, 4) + ">";
\r
363 //if (suppressReserved) return "";
\r
364 return hcp + "<reserved-" + Utility.hex(codePoint, 4) + ">";
\r
370 public String getName(int codePoint, boolean withCodePoint) {
\r
371 String result = getNameSource().getValue(codePoint, !withCodePoint);
\r
372 return fixName == null ? result : fixName.transliterate(result);
\r
375 public String getName(String s, boolean withCodePoint) {
\r
376 String result = getNameSource().getValue(s, separator, !withCodePoint);
\r
377 return fixName == null ? result : fixName.transliterate(result);
\r
380 public String hex(String s) {
\r
381 return hex(s,separator);
\r
384 public String hex(String s, String sep) {
\r
385 return UnicodeLabel.HEX.getValue(s, sep, true);
\r
388 public String hex(int start, int end) {
\r
389 String s = Utility.hex(start,4);
\r
390 if (start == end) return s;
\r
391 return s + ".." + Utility.hex(end,4);
\r
394 public BagFormatter setUnicodePropertyFactory(UnicodeProperty.Factory source) {
\r
395 this.source = source;
\r
399 public UnicodeProperty.Factory getUnicodePropertyFactory() {
\r
400 if (source == null) source = ICUPropertyFactory.make();
\r
404 public BagFormatter () {
\r
407 public BagFormatter (UnicodeProperty.Factory source) {
\r
408 setUnicodePropertyFactory(source);
\r
411 public String join(Object o) {
\r
412 return labelVisitor.join(o);
\r
415 // ===== PRIVATES =====
\r
417 private Join labelVisitor = new Join();
\r
419 private boolean mergeRanges = true;
\r
420 private Transliterator showLiteral = null;
\r
421 private Transliterator fixName = null;
\r
422 private boolean showSetAlso = false;
\r
424 private RangeFinder rf = new RangeFinder();
\r
426 private MessageFormat inOut = new MessageFormat("In {0}, but not in {1}:");
\r
427 private MessageFormat outIn = new MessageFormat("Not in {0}, but in {1}:");
\r
428 private MessageFormat inIn = new MessageFormat("In both {0}, and in {1}:");
\r
430 private MyVisitor mainVisitor = new MyVisitor();
\r
433 private String getLabels(int start, int end) {
\r
434 Set names = new TreeSet();
\r
435 for (int cp = start; cp <= end; ++cp) {
\r
436 names.add(getLabel(cp));
\r
438 return labelVisitor.join(names);
\r
442 private void addMatching(
\r
446 StringBuffer result) {
\r
447 NameIterator n1 = new NameIterator(src);
\r
448 NameIterator n2 = new NameIterator(pattern);
\r
449 boolean first = true;
\r
451 String s1 = n1.next();
\r
454 String s2 = n2.next();
\r
456 result.append(" ");
\r
459 result.append(substitute);
\r
465 private static NumberFormat nf =
\r
466 NumberFormat.getIntegerInstance(Locale.ENGLISH);
\r
468 nf.setGroupingUsed(false);
\r
471 private class MyVisitor extends Visitor {
\r
472 private PrintWriter output;
\r
473 String commentSeparator;
\r
478 boolean inTable = false;
\r
480 public void toOutput(String s) {
\r
483 output.print("</table>");
\r
486 output.print("<p>");
\r
490 output.println("</p>");
\r
492 output.print(lineSeparator);
\r
495 public void toTable(String s) {
\r
496 if (isHtml && !inTable) {
\r
497 output.print("<table>");
\r
500 output.print(tabber.process(s) + lineSeparator);
\r
503 public void doAt(Object c, PrintWriter out) {
\r
505 isHtml = tabber instanceof Tabber.HTMLTabber;
\r
510 // 0009..000D ; White_Space # Cc [5] <control-0009>..<control-000D>
\r
512 // 0009..000D ; White_Space #Cc [5] <control>..<control>
\r
513 tabber.add(mergeRanges ? 14 : 6,Tabber.LEFT);
\r
515 if (propName.length() > 0) {
\r
516 tabber.add(propName.length() + 2,Tabber.LEFT);
\r
519 valueSize = getValueSource().getMaxWidth(shortValue);
\r
520 if (DEBUG) System.out.println("ValueSize: " + valueSize);
\r
521 if (valueSize > 0) {
\r
522 tabber.add(valueSize + 2,Tabber.LEFT); // value
\r
525 tabber.add(3,Tabber.LEFT); // comment character
\r
527 labelSize = getLabelSource(true).getMaxWidth(shortLabel);
\r
528 if (labelSize > 0) {
\r
529 tabber.add(labelSize + 1,Tabber.LEFT); // value
\r
532 if (mergeRanges && showCount) {
\r
533 tabber.add(5,Tabber.RIGHT);
\r
536 if (showLiteral != null) {
\r
537 tabber.add(4,Tabber.LEFT);
\r
539 //myTabber.add(7,Tabber.LEFT);
\r
541 commentSeparator = (showCount || showLiteral != null
\r
542 || getLabelSource(true) != UnicodeLabel.NULL
\r
543 || getNameSource() != UnicodeLabel.NULL)
\r
546 if (DEBUG) System.out.println("Tabber: " + tabber.toString());
\r
547 if (DEBUG) System.out.println("Tabber: " + tabber.process(
\r
548 "200C..200D\t; White_Space\t #\tCf\t [2]\t ZERO WIDTH NON-JOINER..ZERO WIDTH JOINER"));
\r
552 @SuppressWarnings("unused")
\r
553 public String format(Object o) {
\r
554 StringWriter sw = new StringWriter();
\r
555 PrintWriter pw = new PrintWriter(sw);
\r
558 String result = sw.getBuffer().toString();
\r
563 protected void doBefore(Object container, Object o) {
\r
564 if (showSetAlso && container instanceof UnicodeSet) {
\r
565 toOutput("#" + container);
\r
569 protected void doBetween(Object container, Object lastItem, Object nextItem) {
\r
572 protected void doAfter(Object container, Object o) {
\r
573 if (fullTotal != -1 && fullTotal != counter) {
\r
576 toOutput("# The above property value applies to " + nf.format(fullTotal-counter) + " code points not listed here.");
\r
577 toOutput("# Total code points: " + nf.format(fullTotal));
\r
580 } else if (showTotal) {
\r
582 toOutput("# Total code points: " + nf.format(counter));
\r
586 protected void doSimpleAt(Object o) {
\r
587 if (o instanceof Map.Entry) {
\r
588 Map.Entry oo = (Map.Entry)o;
\r
589 Object key = oo.getKey();
\r
590 Object value = oo.getValue();
\r
593 output.println("\u2192");
\r
597 } else if (o instanceof Visitor.CodePointRange) {
\r
598 doAt((Visitor.CodePointRange) o);
\r
600 String thing = o.toString();
\r
601 String value = getValueSource() == UnicodeLabel.NULL ? "" : getValueSource().getValue(thing, ",", true);
\r
602 if (getValueSource() != UnicodeLabel.NULL) value = "\t; " + value;
\r
603 String label = getLabelSource(true) == UnicodeLabel.NULL ? "" : getLabelSource(true).getValue(thing, ",", true);
\r
604 if (label.length() != 0) label = " " + label;
\r
610 + insertLiteral(thing)
\r
617 protected void doAt(Visitor.CodePointRange usi) {
\r
618 if (!mergeRanges) {
\r
619 for (int cp = usi.codepoint; cp <= usi.codepointEnd; ++cp) {
\r
623 rf.reset(usi.codepoint, usi.codepointEnd + 1);
\r
624 while (rf.next()) {
\r
625 showLine(rf.start, rf.limit - 1);
\r
630 private void showLine(int start, int end) {
\r
631 String label = getLabelSource(true).getValue(start, shortLabel);
\r
632 String value = getValue(start, shortValue);
\r
633 if (value == NULL_VALUE) return;
\r
635 counter += end - start + 1;
\r
636 String pn = propName;
\r
637 if (pn.length() != 0) {
\r
640 if (valueSize > 0) {
\r
641 value = "\t; " + value;
\r
642 } else if (value.length() > 0) {
\r
643 throw new IllegalArgumentException("maxwidth bogus " + value + "," + getValueSource().getMaxWidth(shortValue));
\r
645 if (labelSize > 0) {
\r
646 label = "\t" + label;
\r
647 } else if (label.length() > 0) {
\r
648 throw new IllegalArgumentException("maxwidth bogus " + label + ", " + getLabelSource(true).getMaxWidth(shortLabel));
\r
652 if (mergeRanges && showCount) {
\r
653 if (end == start) count = "\t";
\r
654 else count = "\t ["+ nf.format(end - start + 1)+ "]";
\r
664 + insertLiteral(start, end)
\r
665 + getName("\t ", start, end));
\r
668 private String insertLiteral(String thing) {
\r
669 return (showLiteral == null ? ""
\r
670 : " \t(" + showLiteral.transliterate(thing) + ") ");
\r
673 private String insertLiteral(int start, int end) {
\r
674 return (showLiteral == null ? "" :
\r
675 " \t(" + showLiteral.transliterate(UTF16.valueOf(start))
\r
677 ? (".." + showLiteral.transliterate(UTF16.valueOf(end)))
\r
682 private String insertLiteral(int cp) {
\r
683 return (showLiteral == null ? ""
\r
684 : " \t(" + showLiteral.transliterate(UTF16.valueOf(cp)) + ") ");
\r
690 * Iterate through a string, breaking at words.
\r
693 private static class NameIterator {
\r
698 NameIterator(String source) {
\r
699 this.source = source;
\r
700 this.limit = source.length();
\r
703 * Find next word, including trailing spaces
\r
704 * @return the next word
\r
707 if (position >= limit)
\r
709 int pos = source.indexOf(' ', position);
\r
710 if (pos < 0 || pos >= limit)
\r
712 String result = source.substring(position, pos);
\r
713 position = pos + 1;
\r
717 static int findMatchingEnd(String s1, String s2) {
\r
718 int i = s1.length();
\r
719 int j = s2.length();
\r
722 --i; // decrement both before calling function!
\r
724 if (s1.charAt(i) != s2.charAt(j))
\r
727 } catch (Exception e) {} // run off start
\r
729 ++i; // counteract increment
\r
730 i = s1.indexOf(' ', i); // move forward to space
\r
733 return s1.length() - i;
\r
737 private class RangeFinder {
\r
739 private int veryLimit;
\r
740 //String label, value;
\r
741 void reset(int rangeStart, int rangeLimit) {
\r
742 limit = rangeStart;
\r
743 veryLimit = rangeLimit;
\r
746 if (limit >= veryLimit)
\r
748 start = limit; // set to end of last
\r
749 String label = getLabelSource(false).getValue(limit, true);
\r
750 String value = getValue(limit, true);
\r
751 String breaker = getRangeBreakSource().getValue(limit,true);
\r
752 if (DEBUG && limit < 0x7F) System.out.println("Label: " + label + ", Value: " + value + ", Break: " + breaker);
\r
754 for (; limit < veryLimit; limit++) {
\r
755 String s = getLabelSource(false).getValue(limit, true);
\r
756 String v = getValue(limit, true);
\r
757 String b = getRangeBreakSource().getValue(limit, true);
\r
758 if (DEBUG && limit < 0x7F) System.out.println("*Label: " + label + ", Value: " + value + ", Break: " + breaker);
\r
759 if (!equalTo(s, label) || !equalTo(v, value) || !equalTo(b, breaker)) break;
\r
761 // at this point, limit is the first item that has a different label than source
\r
762 // OR, we got to the end, and limit == veryLimit
\r
767 boolean equalTo(Object a, Object b) {
\r
768 if (a == b) return true;
\r
769 if (a == null) return false;
\r
770 return a.equals(b);
\r
773 boolean shortLabel = true;
\r
774 boolean shortValue = true;
\r
776 public String getPrefix() {
\r
780 public String getSuffix() {
\r
784 public BagFormatter setPrefix(String string) {
\r
789 public BagFormatter setSuffix(String string) {
\r
794 public boolean isAbbreviated() {
\r
795 return abbreviated;
\r
798 public BagFormatter setAbbreviated(boolean b) {
\r
803 public UnicodeLabel getLabelSource(boolean visible) {
\r
804 if (labelSource == null) {
\r
805 Map labelMap = new HashMap();
\r
806 //labelMap.put("Lo","L&");
\r
807 labelMap.put("Lu","L&");
\r
808 labelMap.put("Lt","L&");
\r
809 labelMap.put("Ll","L&");
\r
810 labelSource = new UnicodeProperty.FilteredProperty(
\r
811 getUnicodePropertyFactory().getProperty("General_Category"),
\r
812 new UnicodeProperty.MapFilter(labelMap)
\r
813 ).setAllowValueAliasCollisions(true);
\r
815 return labelSource;
\r
821 public static void addAll(UnicodeSet source, Collection target) {
\r
822 source.addAllTo(target);
\r
827 public static final Transliterator hex = Transliterator.getInstance(
\r
828 "[^\\u0009\\u0020-\\u007E\\u00A0-\\u00FF] hex");
\r
830 public static BufferedReader openUTF8Reader(String dir, String filename) throws IOException {
\r
831 return openReader(dir,filename,"UTF-8");
\r
834 public static BufferedReader openReader(String dir, String filename, String encoding) throws IOException {
\r
835 File file = dir.length() == 0 ? new File(filename) : new File(dir, filename);
\r
836 if (SHOW_FILES && log != null) {
\r
837 log.println("Opening File: "
\r
838 + file.getCanonicalPath());
\r
840 return new BufferedReader(
\r
841 new InputStreamReader(
\r
842 new FileInputStream(file),
\r
847 public static PrintWriter openUTF8Writer(String dir, String filename) throws IOException {
\r
848 return openWriter(dir,filename,"UTF-8");
\r
851 public static PrintWriter openWriter(String dir, String filename, String encoding) throws IOException {
\r
852 File file = new File(dir, filename);
\r
853 if (SHOW_FILES && log != null) {
\r
854 log.println("Creating File: "
\r
855 + file.getCanonicalPath());
\r
857 String parentName = file.getParent();
\r
858 if (parentName != null) {
\r
859 File parent = new File(parentName);
\r
862 return new PrintWriter(
\r
863 new BufferedWriter(
\r
864 new OutputStreamWriter(
\r
865 new FileOutputStream(file),
\r
869 public static PrintWriter getLog() {
\r
872 public BagFormatter setLog(PrintWriter writer) {
\r
876 public String getSeparator() {
\r
879 public BagFormatter setSeparator(String string) {
\r
880 separator = string;
\r
883 public Transliterator getShowLiteral() {
\r
884 return showLiteral;
\r
886 public BagFormatter setShowLiteral(Transliterator transliterator) {
\r
887 showLiteral = transliterator;
\r
891 // ===== CONVENIENCES =====
\r
892 private class Join extends Visitor {
\r
893 StringBuffer output = new StringBuffer();
\r
895 String join (Object o) {
\r
896 output.setLength(0);
\r
898 return output.toString();
\r
900 protected void doBefore(Object container, Object item) {
\r
902 output.append(prefix);
\r
904 protected void doAfter(Object container, Object item) {
\r
905 output.append(suffix);
\r
908 protected void doBetween(Object container, Object lastItem, Object nextItem) {
\r
909 output.append(separator);
\r
911 protected void doSimpleAt(Object o) {
\r
912 if (o != null) output.append(o.toString());
\r
919 public BagFormatter setLabelSource(UnicodeLabel label) {
\r
920 if (label == null) label = UnicodeLabel.NULL;
\r
921 labelSource = label;
\r
926 * @return the NameLable representing the source
\r
928 public UnicodeLabel getNameSource() {
\r
929 if (nameSource == null) {
\r
930 nameSource = new NameLabel(getUnicodePropertyFactory());
\r
938 public BagFormatter setNameSource(UnicodeLabel label) {
\r
939 if (label == null) label = UnicodeLabel.NULL;
\r
940 nameSource = label;
\r
945 * @return the UnicodeLabel representing the value
\r
947 public UnicodeLabel getValueSource() {
\r
948 if (valueSource == null) valueSource = UnicodeLabel.NULL;
\r
949 return valueSource;
\r
952 private String getValue(int cp, boolean shortVal) {
\r
953 String result = getValueSource().getValue(cp, shortVal);
\r
954 if (result == null) return NULL_VALUE;
\r
955 if (hexValue) result = hex(result, " ");
\r
962 public BagFormatter setValueSource(UnicodeLabel label) {
\r
963 if (label == null) label = UnicodeLabel.NULL;
\r
964 valueSource = label;
\r
968 public BagFormatter setValueSource(String label) {
\r
969 return setValueSource(new UnicodeLabel.Constant(label));
\r
973 * @return true if showCount is true
\r
975 public boolean isShowCount() {
\r
980 * @param b true to show the count
\r
981 * @return this (for chaining)
\r
983 public BagFormatter setShowCount(boolean b) {
\r
989 * @return the property name
\r
991 public String getPropName() {
\r
997 * @return this (for chaining)
\r
999 public BagFormatter setPropName(String string) {
\r
1000 if (string == null) string = "";
\r
1001 propName = string;
\r
1006 * @return true if this is a hexValue
\r
1008 public boolean isHexValue() {
\r
1014 * @return this (for chaining)
\r
1016 public BagFormatter setHexValue(boolean b) {
\r
1022 * @return the full total
\r
1024 public int getFullTotal() {
\r
1029 * @param i set the full total
\r
1030 * @return this (for chaining)
\r
1032 public BagFormatter setFullTotal(int i) {
\r
1038 * @return the line separator
\r
1040 public String getLineSeparator() {
\r
1041 return lineSeparator;
\r
1046 * @return this (for chaining)
\r
1048 public BagFormatter setLineSeparator(String string) {
\r
1049 lineSeparator = string;
\r
1054 * @return the UnicodeLabel representing the range break source
\r
1056 public UnicodeLabel getRangeBreakSource() {
\r
1057 if (rangeBreakSource == null) {
\r
1058 Map labelMap = new HashMap();
\r
1059 // reflects the code point types on p 25
\r
1060 labelMap.put("Lo", "G&");
\r
1061 labelMap.put("Lm", "G&");
\r
1062 labelMap.put("Lu", "G&");
\r
1063 labelMap.put("Lt", "G&");
\r
1064 labelMap.put("Ll", "G&");
\r
1065 labelMap.put("Mn", "G&");
\r
1066 labelMap.put("Me", "G&");
\r
1067 labelMap.put("Mc", "G&");
\r
1068 labelMap.put("Nd", "G&");
\r
1069 labelMap.put("Nl", "G&");
\r
1070 labelMap.put("No", "G&");
\r
1071 labelMap.put("Zs", "G&");
\r
1072 labelMap.put("Pd", "G&");
\r
1073 labelMap.put("Ps", "G&");
\r
1074 labelMap.put("Pe", "G&");
\r
1075 labelMap.put("Pc", "G&");
\r
1076 labelMap.put("Po", "G&");
\r
1077 labelMap.put("Pi", "G&");
\r
1078 labelMap.put("Pf", "G&");
\r
1079 labelMap.put("Sm", "G&");
\r
1080 labelMap.put("Sc", "G&");
\r
1081 labelMap.put("Sk", "G&");
\r
1082 labelMap.put("So", "G&");
\r
1084 labelMap.put("Zl", "Cf");
\r
1085 labelMap.put("Zp", "Cf");
\r
1087 rangeBreakSource =
\r
1088 new UnicodeProperty
\r
1089 .FilteredProperty(
\r
1090 getUnicodePropertyFactory().getProperty(
\r
1091 "General_Category"),
\r
1092 new UnicodeProperty.MapFilter(labelMap))
\r
1093 .setAllowValueAliasCollisions(true);
\r
1096 "Cn", // = Other, Not Assigned 0
\r
1097 "Cc", // = Other, Control 15
\r
1098 "Cf", // = Other, Format 16
\r
1099 UnicodeProperty.UNUSED, // missing
\r
1100 "Co", // = Other, Private Use 18
\r
1101 "Cs", // = Other, Surrogate 19
\r
1104 return rangeBreakSource;
\r
1110 public BagFormatter setRangeBreakSource(UnicodeLabel label) {
\r
1111 if (label == null) label = UnicodeLabel.NULL;
\r
1112 rangeBreakSource = label;
\r
1117 * @return Returns the fixName.
\r
1119 public Transliterator getFixName() {
\r
1123 * @param fixName The fixName to set.
\r
1125 public BagFormatter setFixName(Transliterator fixName) {
\r
1126 this.fixName = fixName;
\r
1130 public Tabber getTabber() {
\r
1134 public void setTabber(Tabber tabber) {
\r
1135 this.tabber = tabber;
\r
1138 public boolean isShowTotal() {
\r
1142 public void setShowTotal(boolean showTotal) {
\r
1143 this.showTotal = showTotal;
\r