Todo notes for feature issue: 0011711
[jalview.git] / src / jalview / io / NewickFile.java
1 /*\r
2 * Jalview - A Sequence Alignment Editor and Viewer\r
3 * Copyright (C) 2005 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
4 *\r
5 * This program is free software; you can redistribute it and/or\r
6 * modify it under the terms of the GNU General Public License\r
7 * as published by the Free Software Foundation; either version 2\r
8 * of the License, or (at your option) any later version.\r
9 *\r
10 * This program is distributed in the hope that it will be useful,\r
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13 * GNU General Public License for more details.\r
14 *\r
15 * You should have received a copy of the GNU General Public License\r
16 * along with this program; if not, write to the Free Software\r
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA\r
18 */\r
19 \r
20 // NewickFile.java\r
21 // Tree I/O\r
22 // http://evolution.genetics.washington.edu/phylip/newick_doc.html\r
23 // TODO: Implement Basic NHX tag parsing and preservation\r
24 // TODO: http://evolution.genetics.wustl.edu/eddy/forester/NHX.html\r
25 // TODO: Extended SequenceNodeI to hold parsed NHX strings\r
26 package jalview.io;\r
27 \r
28 import jalview.datamodel.*;\r
29 \r
30 import java.io.*;\r
31 \r
32 \r
33 /**\r
34  * DOCUMENT ME!\r
35  *\r
36  * @author $author$\r
37  * @version $Revision$\r
38  */\r
39 public class NewickFile extends FileParse\r
40 {\r
41     SequenceNode root;\r
42     private boolean HasBootstrap = false;\r
43     private boolean HasDistances = false;\r
44     private boolean RootHasDistance = false;\r
45 \r
46     // File IO Flags\r
47     boolean ReplaceUnderscores = false;\r
48     boolean printRootInfo = false;\r
49     private com.stevesoft.pat.Regex[] NodeSafeName = new com.stevesoft.pat.Regex[]\r
50         {\r
51             new com.stevesoft.pat.Regex().perlCode("m/[\\[,:'()]/"), // test for requiring quotes\r
52             new com.stevesoft.pat.Regex().perlCode("s/'/''/"), // escaping quote characters\r
53             new com.stevesoft.pat.Regex().perlCode("s/\\/w/_/") // unqoted whitespace transformation\r
54         };\r
55     char QuoteChar = '\'';\r
56 \r
57     /**\r
58      * Creates a new NewickFile object.\r
59      *\r
60      * @param inStr DOCUMENT ME!\r
61      *\r
62      * @throws IOException DOCUMENT ME!\r
63      */\r
64     public NewickFile(String inStr) throws IOException\r
65     {\r
66         super(inStr, "Paste");\r
67     }\r
68 \r
69     /**\r
70      * Creates a new NewickFile object.\r
71      *\r
72      * @param inFile DOCUMENT ME!\r
73      * @param type DOCUMENT ME!\r
74      *\r
75      * @throws IOException DOCUMENT ME!\r
76      */\r
77     public NewickFile(String inFile, String type) throws IOException\r
78     {\r
79         super(inFile, type);\r
80     }\r
81 \r
82     /**\r
83      * Creates a new NewickFile object.\r
84      *\r
85      * @param newtree DOCUMENT ME!\r
86      */\r
87     public NewickFile(SequenceNode newtree)\r
88     {\r
89         root = newtree;\r
90     }\r
91 \r
92     /**\r
93      * Creates a new NewickFile object.\r
94      *\r
95      * @param newtree DOCUMENT ME!\r
96      * @param bootstrap DOCUMENT ME!\r
97      */\r
98     public NewickFile(SequenceNode newtree, boolean bootstrap)\r
99     {\r
100         HasBootstrap = bootstrap;\r
101         root = newtree;\r
102     }\r
103 \r
104     /**\r
105      * Creates a new NewickFile object.\r
106      *\r
107      * @param newtree DOCUMENT ME!\r
108      * @param bootstrap DOCUMENT ME!\r
109      * @param distances DOCUMENT ME!\r
110      */\r
111     public NewickFile(SequenceNode newtree, boolean bootstrap, boolean distances)\r
112     {\r
113         root = newtree;\r
114         HasBootstrap = bootstrap;\r
115         HasDistances = distances;\r
116     }\r
117 \r
118     /**\r
119      * Creates a new NewickFile object.\r
120      *\r
121      * @param newtree DOCUMENT ME!\r
122      * @param bootstrap DOCUMENT ME!\r
123      * @param distances DOCUMENT ME!\r
124      * @param rootdistance DOCUMENT ME!\r
125      */\r
126     public NewickFile(SequenceNode newtree, boolean bootstrap,\r
127         boolean distances, boolean rootdistance)\r
128     {\r
129         root = newtree;\r
130         HasBootstrap = bootstrap;\r
131         HasDistances = distances;\r
132         RootHasDistance = rootdistance;\r
133     }\r
134 \r
135     /**\r
136      * DOCUMENT ME!\r
137      *\r
138      * @param Error DOCUMENT ME!\r
139      * @param Er DOCUMENT ME!\r
140      * @param r DOCUMENT ME!\r
141      * @param p DOCUMENT ME!\r
142      * @param s DOCUMENT ME!\r
143      *\r
144      * @return DOCUMENT ME!\r
145      */\r
146     private String ErrorStringrange(String Error, String Er, int r, int p,\r
147         String s)\r
148     {\r
149         return ((Error == null) ? "" : Error) + Er + " at position " + p +\r
150         " ( " +\r
151         s.substring(((p - r) < 0) ? 0 : (p - r),\r
152             ((p + r) > s.length()) ? s.length() : (p + r)) + " )\n";\r
153     }\r
154 \r
155     // @tree annotations\r
156     // These are set automatically by the reader\r
157     public boolean HasBootstrap()\r
158     {\r
159         return HasBootstrap;\r
160     }\r
161 \r
162     /**\r
163      * DOCUMENT ME!\r
164      *\r
165      * @return DOCUMENT ME!\r
166      */\r
167     public boolean HasDistances()\r
168     {\r
169         return HasDistances;\r
170     }\r
171 \r
172     public boolean HasRootDistance()\r
173     {\r
174         return RootHasDistance;\r
175     }\r
176     /**\r
177      * DOCUMENT ME!\r
178      *\r
179      * @throws IOException DOCUMENT ME!\r
180      */\r
181     public void parse() throws IOException\r
182     {\r
183         String nf;\r
184 \r
185         { // fill nf with complete tree file\r
186 \r
187             StringBuffer file = new StringBuffer();\r
188 \r
189             while ((nf = nextLine()) != null)\r
190             {\r
191                 file.append(nf);\r
192             }\r
193 \r
194             nf = file.toString();\r
195         }\r
196 \r
197         root = new SequenceNode();\r
198 \r
199         SequenceNode realroot = null;\r
200         SequenceNode c = root;\r
201 \r
202         int d = -1;\r
203         int cp = 0;\r
204         //int flen = nf.length();\r
205 \r
206         String Error = null;\r
207         String nodename = null;\r
208 \r
209         float DefDistance = (float) 0.001; // @param Default distance for a node - very very small\r
210         int DefBootstrap = 0; // @param Default bootstrap for a node\r
211 \r
212         float distance = DefDistance;\r
213         int bootstrap = DefBootstrap;\r
214 \r
215         boolean ascending = false; // flag indicating that we are leaving the current node\r
216 \r
217         com.stevesoft.pat.Regex majorsyms = new com.stevesoft.pat.Regex(\r
218                 "[(\\['),;]");\r
219 \r
220         while (majorsyms.searchFrom(nf, cp) && (Error == null))\r
221         {\r
222             int fcp = majorsyms.matchedFrom();\r
223 \r
224             switch (nf.charAt(fcp))\r
225             {\r
226             case '[': // Comment or structured/extended NH format info\r
227 \r
228                 com.stevesoft.pat.Regex comment = new com.stevesoft.pat.Regex(\r
229                         "]");\r
230 \r
231                 if (comment.searchFrom(nf, fcp))\r
232                 {\r
233                     // Skip the comment field\r
234                     cp = 1 + comment.matchedFrom();\r
235                 }\r
236                 else\r
237                 {\r
238                     Error = ErrorStringrange(Error, "Unterminated comment", 3,\r
239                             fcp, nf);\r
240                 }\r
241 \r
242                 ;\r
243 \r
244                 break;\r
245 \r
246             case '(':\r
247 \r
248                 // ascending should not be set\r
249                 // New Internal node\r
250                 if (ascending)\r
251                 {\r
252                     Error = ErrorStringrange(Error, "Unexpected '('", 7, fcp, nf);\r
253 \r
254                     continue;\r
255                 }\r
256 \r
257                 ;\r
258                 d++;\r
259 \r
260                 if (c.right() == null)\r
261                 {\r
262                     c.setRight(new SequenceNode(null, c, null, DefDistance,\r
263                             DefBootstrap, false));\r
264                     c = (SequenceNode) c.right();\r
265                 }\r
266                 else\r
267                 {\r
268                     if (c.left() != null)\r
269                     {\r
270                         // Dummy node for polytomy - keeps c.left free for new node\r
271                         SequenceNode tmpn = new SequenceNode(null, c, null, 0,\r
272                                 0, true);\r
273                         tmpn.SetChildren(c.left(), c.right());\r
274                         c.setRight(tmpn);\r
275                     }\r
276 \r
277                     c.setLeft(new SequenceNode(null, c, null, DefDistance,\r
278                             DefBootstrap, false));\r
279                     c = (SequenceNode) c.left();\r
280                 }\r
281 \r
282                 if (realroot == null)\r
283                 {\r
284                     realroot = c;\r
285                 }\r
286 \r
287                 nodename = null;\r
288                 distance = DefDistance;\r
289                 bootstrap = DefBootstrap;\r
290                 cp = fcp + 1;\r
291 \r
292                 break;\r
293 \r
294             // Deal with quoted fields\r
295             case '\'':\r
296 \r
297                 com.stevesoft.pat.Regex qnodename = new com.stevesoft.pat.Regex(\r
298                         "([^']|'')+'");\r
299 \r
300                 if (qnodename.searchFrom(nf, fcp))\r
301                 {\r
302                     int nl = qnodename.stringMatched().length();\r
303                     nodename = new String(qnodename.stringMatched().substring(0,\r
304                                 nl - 1));\r
305                     cp = fcp + nl + 1;\r
306                 }\r
307                 else\r
308                 {\r
309                     Error = ErrorStringrange(Error,\r
310                             "Unterminated quotes for nodename", 7, fcp, nf);\r
311                 }\r
312 \r
313                 break;\r
314 \r
315             case ';':\r
316 \r
317                 if (d != -1)\r
318                 {\r
319                     Error = ErrorStringrange(Error,\r
320                             "Wayward semicolon (depth=" + d + ")", 7, fcp, nf);\r
321                 }\r
322 \r
323             // cp advanced at the end of default\r
324             default:\r
325 \r
326                 // Parse simpler field strings\r
327                 String fstring = nf.substring(cp, fcp);\r
328                 com.stevesoft.pat.Regex uqnodename = new com.stevesoft.pat.Regex(\r
329                         "\\b([^' :;\\](),]+)");\r
330                 com.stevesoft.pat.Regex nbootstrap = new com.stevesoft.pat.Regex(\r
331                         "\\S+([0-9+]+)\\S*:");\r
332                 com.stevesoft.pat.Regex ndist = new com.stevesoft.pat.Regex(\r
333                         ":([-0-9Ee.+]+)");\r
334 \r
335                 if (uqnodename.search(fstring) &&\r
336                         ((uqnodename.matchedFrom(1) == 0) ||\r
337                         (fstring.charAt(uqnodename.matchedFrom(1) - 1) != ':'))) // JBPNote HACK!\r
338                 {\r
339                     if (nodename == null)\r
340                     {\r
341                         if (ReplaceUnderscores)\r
342                         {\r
343                             nodename = uqnodename.stringMatched(1).replace('_',\r
344                                     ' ');\r
345                         }\r
346                         else\r
347                         {\r
348                             nodename = uqnodename.stringMatched(1);\r
349                         }\r
350                     }\r
351                     else\r
352                     {\r
353                         Error = ErrorStringrange(Error,\r
354                                 "File has broken algorithm - overwritten nodename",\r
355                                 10, fcp, nf);\r
356                     }\r
357                 }\r
358 \r
359                 if (nbootstrap.search(fstring) &&\r
360                         (nbootstrap.matchedFrom(1) > (uqnodename.matchedFrom(1) +\r
361                         uqnodename.stringMatched().length())))\r
362                 {\r
363                     try\r
364                     {\r
365                         bootstrap = (new Integer(nbootstrap.stringMatched(1))).intValue();\r
366                         HasBootstrap = true;\r
367                     }\r
368                     catch (Exception e)\r
369                     {\r
370                         Error = ErrorStringrange(Error,\r
371                                 "Can't parse bootstrap value", 4,\r
372                                 cp + nbootstrap.matchedFrom(), nf);\r
373                     }\r
374                 }\r
375 \r
376                 boolean nodehasdistance = false;\r
377 \r
378                 if (ndist.search(fstring))\r
379                 {\r
380                     try\r
381                     {\r
382                         distance = (new Float(ndist.stringMatched(1))).floatValue();\r
383                         HasDistances = true;\r
384                         nodehasdistance = true;\r
385                     }\r
386                     catch (Exception e)\r
387                     {\r
388                         Error = ErrorStringrange(Error,\r
389                                 "Can't parse node distance value", 7,\r
390                                 cp + ndist.matchedFrom(), nf);\r
391                     }\r
392                 }\r
393 \r
394                 if (ascending)\r
395                 {\r
396                     // Write node info here\r
397                     c.setName(nodename);\r
398                     // Trees without distances still need a render distance\r
399                     c.dist = (HasDistances) ? distance : DefDistance;\r
400                     // be consistent for internal bootstrap defaults too\r
401                     c.setBootstrap((HasBootstrap) ? bootstrap : DefBootstrap);\r
402                     if (c == realroot)\r
403                     {\r
404                         RootHasDistance = nodehasdistance; // JBPNote This is really UGLY!!! Ensure root node gets its given distance\r
405                     }\r
406                 }\r
407                 else\r
408                 {\r
409                     // Find a place to put the leaf\r
410                     SequenceNode newnode = new SequenceNode(null, c, nodename,\r
411                             (HasDistances) ? distance : DefDistance,\r
412                             (HasBootstrap) ? bootstrap : DefBootstrap, false);\r
413 \r
414                     if (c.right() == null)\r
415                     {\r
416                         c.setRight(newnode);\r
417                     }\r
418                     else\r
419                     {\r
420                         if (c.left() == null)\r
421                         {\r
422                             c.setLeft(newnode);\r
423                         }\r
424                         else\r
425                         {\r
426                             // Insert a dummy node for polytomy\r
427                             // dummy nodes have distances\r
428                             SequenceNode newdummy = new SequenceNode(null, c,\r
429                                     null, (HasDistances ? 0 : DefDistance), 0, true);\r
430                             newdummy.SetChildren(c.left(), newnode);\r
431                             c.setLeft(newdummy);\r
432                         }\r
433                     }\r
434                 }\r
435 \r
436                 if (ascending)\r
437                 {\r
438                     // move back up the tree from preceding closure\r
439                     c = c.AscendTree();\r
440 \r
441                     if ((d > -1) && (c == null))\r
442                     {\r
443                         Error = ErrorStringrange(Error,\r
444                                 "File broke algorithm: Lost place in tree (is there an extra ')' ?)",\r
445                                 7, fcp, nf);\r
446                     }\r
447                 }\r
448 \r
449                 if (nf.charAt(fcp) == ')')\r
450                 {\r
451                     d--;\r
452                     ascending = true;\r
453                 }\r
454                 else\r
455                 {\r
456                     if (nf.charAt(fcp) == ',')\r
457                     {\r
458                         if (ascending)\r
459                         {\r
460                             ascending = false;\r
461                         }\r
462                         else\r
463                         {\r
464                             // Just advance focus, if we need to\r
465                             if ((c.left() != null) && (!c.left().isLeaf()))\r
466                             {\r
467                                 c = (SequenceNode) c.left();\r
468                             }\r
469                         }\r
470                     }\r
471 \r
472                     // else : We do nothing if ';' is encountered.\r
473                 }\r
474 \r
475                 // Reset new node properties to obvious fakes\r
476                 nodename = null;\r
477                 distance = DefDistance;\r
478                 bootstrap = DefBootstrap;\r
479 \r
480                 cp = fcp + 1;\r
481             }\r
482         }\r
483 \r
484         if (Error != null)\r
485         {\r
486             throw (new IOException("NewickFile: " + Error + "\n"));\r
487         }\r
488 \r
489         root = (SequenceNode) root.right().detach(); // remove the imaginary root.\r
490 \r
491         if (!RootHasDistance)\r
492         {\r
493             root.dist = (HasDistances) ? 0 : DefDistance;\r
494         }\r
495     }\r
496 \r
497     /**\r
498      * DOCUMENT ME!\r
499      *\r
500      * @return DOCUMENT ME!\r
501      */\r
502     public SequenceNode getTree()\r
503     {\r
504         return root;\r
505     }\r
506 \r
507     /**\r
508      * Generate a newick format tree according to internal flags\r
509      * for bootstraps, distances and root distances.\r
510      *\r
511      * @return new hampshire tree in a single line\r
512      */\r
513     public String print()\r
514     {\r
515         synchronized (this)\r
516         {\r
517             StringBuffer tf = new StringBuffer();\r
518             print(tf, root);\r
519 \r
520             return (tf.append(";").toString());\r
521         }\r
522     }\r
523 \r
524     /**\r
525      *\r
526      *\r
527      * Generate a newick format tree according to internal flags\r
528      * for distances and root distances and user specificied writing of\r
529      * bootstraps.\r
530      * @param withbootstraps controls if bootstrap values are explicitly written.\r
531      *\r
532      * @return new hampshire tree in a single line\r
533      */\r
534     public String print(boolean withbootstraps)\r
535     {\r
536         synchronized (this)\r
537         {\r
538             boolean boots = this.HasBootstrap;\r
539             this.HasBootstrap = withbootstraps;\r
540 \r
541             String rv = print();\r
542             this.HasBootstrap = boots;\r
543 \r
544             return rv;\r
545         }\r
546     }\r
547 \r
548     /**\r
549      *\r
550      * Generate newick format tree according to internal flags\r
551      * for writing root node distances.\r
552      *\r
553      * @param withbootstraps explicitly write bootstrap values\r
554      * @param withdists explicitly write distances\r
555      *\r
556      * @return new hampshire tree in a single line\r
557      */\r
558     public String print(boolean withbootstraps, boolean withdists)\r
559     {\r
560         synchronized (this)\r
561         {\r
562             boolean dists = this.HasDistances;\r
563             this.HasDistances = withdists;\r
564 \r
565             String rv = print(withbootstraps);\r
566             this.HasDistances = dists;\r
567 \r
568             return rv;\r
569         }\r
570     }\r
571 \r
572     /**\r
573      * Generate newick format tree according to user specified flags\r
574      *\r
575      * @param withbootstraps explicitly write bootstrap values\r
576      * @param withdists explicitly write distances\r
577      * @param printRootInfo explicitly write root distance\r
578      *\r
579      * @return new hampshire tree in a single line\r
580      */\r
581     public String print(boolean withbootstraps, boolean withdists,\r
582         boolean printRootInfo)\r
583     {\r
584         synchronized (this)\r
585         {\r
586             boolean rootinfo = printRootInfo;\r
587             this.printRootInfo = printRootInfo;\r
588 \r
589             String rv = print(withbootstraps, withdists);\r
590             this.printRootInfo = rootinfo;\r
591 \r
592             return rv;\r
593         }\r
594     }\r
595 \r
596     /**\r
597      * DOCUMENT ME!\r
598      *\r
599      * @return DOCUMENT ME!\r
600      */\r
601     char getQuoteChar()\r
602     {\r
603         return QuoteChar;\r
604     }\r
605 \r
606     /**\r
607      * DOCUMENT ME!\r
608      *\r
609      * @param c DOCUMENT ME!\r
610      *\r
611      * @return DOCUMENT ME!\r
612      */\r
613     char setQuoteChar(char c)\r
614     {\r
615         char old = QuoteChar;\r
616         QuoteChar = c;\r
617 \r
618         return old;\r
619     }\r
620 \r
621     /**\r
622      * DOCUMENT ME!\r
623      *\r
624      * @param name DOCUMENT ME!\r
625      *\r
626      * @return DOCUMENT ME!\r
627      */\r
628     private String nodeName(String name)\r
629     {\r
630         if (NodeSafeName[0].search(name))\r
631         {\r
632             return QuoteChar + NodeSafeName[1].replaceAll(name) + QuoteChar;\r
633         }\r
634         else\r
635         {\r
636             return NodeSafeName[2].replaceAll(name);\r
637         }\r
638     }\r
639 \r
640     /**\r
641      * DOCUMENT ME!\r
642      *\r
643      * @param c DOCUMENT ME!\r
644      *\r
645      * @return DOCUMENT ME!\r
646      */\r
647     private String printNodeField(SequenceNode c)\r
648     {\r
649         return ((c.getName() == null) ? "" : nodeName(c.getName())) +\r
650         ((HasBootstrap)\r
651         ? ((c.getBootstrap() > -1) ? (" " + c.getBootstrap()) : "") : "") +\r
652         ((HasDistances) ? (":" + c.dist) : "");\r
653     }\r
654 \r
655     /**\r
656      * DOCUMENT ME!\r
657      *\r
658      * @param root DOCUMENT ME!\r
659      *\r
660      * @return DOCUMENT ME!\r
661      */\r
662     private String printRootField(SequenceNode root)\r
663     {\r
664         return (printRootInfo)\r
665         ? (((root.getName() == null) ? "" : nodeName(root.getName())) +\r
666         ((HasBootstrap)\r
667         ? ((root.getBootstrap() > -1) ? (" " + root.getBootstrap()) : "") : "") +\r
668         ((RootHasDistance) ? (":" + root.dist) : "")) : "";\r
669     }\r
670 \r
671     // Non recursive call deals with root node properties\r
672     public void print(StringBuffer tf, SequenceNode root)\r
673     {\r
674         if (root != null)\r
675         {\r
676             if (root.isLeaf() && printRootInfo)\r
677             {\r
678                 tf.append(printRootField(root));\r
679             }\r
680             else\r
681             {\r
682                 if (root.isDummy())\r
683                 {\r
684                     _print(tf, (SequenceNode) root.right());\r
685                     _print(tf, (SequenceNode) root.left());\r
686                 }\r
687                 else\r
688                 {\r
689                     tf.append("(");\r
690                     _print(tf, (SequenceNode) root.right());\r
691 \r
692                     if (root.left() != null)\r
693                     {\r
694                         tf.append(",");\r
695                     }\r
696 \r
697                     _print(tf, (SequenceNode) root.left());\r
698                     tf.append(")" + printRootField(root));\r
699                 }\r
700             }\r
701         }\r
702     }\r
703 \r
704     // Recursive call for non-root nodes\r
705     public void _print(StringBuffer tf, SequenceNode c)\r
706     {\r
707         if (c != null)\r
708         {\r
709             if (c.isLeaf())\r
710             {\r
711                 tf.append(printNodeField(c));\r
712             }\r
713             else\r
714             {\r
715                 if (c.isDummy())\r
716                 {\r
717                     _print(tf, (SequenceNode) c.left());\r
718                     if (c.left() != null)\r
719                     {\r
720                       tf.append(",");\r
721                     }\r
722                     _print(tf, (SequenceNode) c.right());\r
723                 }\r
724                 else\r
725                 {\r
726                     tf.append("(");\r
727                     _print(tf, (SequenceNode) c.right());\r
728 \r
729                     if (c.left() != null)\r
730                     {\r
731                         tf.append(",");\r
732                     }\r
733 \r
734                     _print(tf, (SequenceNode) c.left());\r
735                     tf.append(")" + printNodeField(c));\r
736                 }\r
737             }\r
738         }\r
739     }\r
740 \r
741     // Test\r
742     public static void main(String[] args)\r
743     {\r
744         try\r
745         {\r
746             if (args==null || args.length!=1) {\r
747               System.err.println("Takes one argument - file name of a newick tree file.");\r
748               System.exit(0);\r
749             }\r
750 \r
751             File fn = new File(args[0]);\r
752 \r
753             StringBuffer newickfile = new StringBuffer();\r
754             BufferedReader treefile = new BufferedReader(new FileReader(fn));\r
755             String l;\r
756 \r
757             while ((l = treefile.readLine()) != null)\r
758             {\r
759                 newickfile.append(l);\r
760             }\r
761 \r
762             treefile.close();\r
763             System.out.println("Read file :\n");\r
764 \r
765             NewickFile trf = new NewickFile(args[0], "File");\r
766             trf.parse();\r
767             System.out.println("Original file :\n");\r
768 \r
769             com.stevesoft.pat.Regex nonl = new com.stevesoft.pat.Regex("\n+", "");\r
770             System.out.println(nonl.replaceAll(newickfile.toString()) + "\n");\r
771 \r
772             System.out.println("Parsed file.\n");\r
773             System.out.println("Default output type for original input.\n");\r
774             System.out.println(trf.print());\r
775             System.out.println("Without bootstraps.\n");\r
776             System.out.println(trf.print(false));\r
777             System.out.println("Without distances.\n");\r
778             System.out.println(trf.print(true, false));\r
779             System.out.println("Without bootstraps but with distanecs.\n");\r
780             System.out.println(trf.print(false, true));\r
781             System.out.println("Without bootstraps or distanecs.\n");\r
782             System.out.println(trf.print(false, false));\r
783             System.out.println("With bootstraps and with distances.\n");\r
784             System.out.println(trf.print(true, true));\r
785         }\r
786         catch (java.io.IOException e)\r
787         {\r
788             System.err.println("Exception\n" + e);\r
789             e.printStackTrace();\r
790         }\r
791     }\r
792 }\r