source: branches/properties/GDE/PHYLIP/retree.c

Last change on this file was 19480, checked in by westram, 21 months ago
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 78.0 KB
Line 
1
2#include "phylip.h"
3#include "moves.h"
4
5/* version 3.6. (c) Copyright 1993-2002 by the University of Washington.
6   Written by Joseph Felsenstein and Andrew Keeffe.  Permission is granted to
7   copy and use this program provided no fee is charged for it and provided
8   that this copyright notice is not removed. */
9
10#define maxsp           500   /* maximum number of species               */
11#define maxsz           999   /* size of pointer array.  >= 2*maxsp - 1  */
12                              /* this can be large without eating memory */
13
14#define overr           4
15#define which           1
16
17
18typedef enum {valid, remoov, quit} reslttype;
19
20typedef enum {
21  horiz, vert, up, updel, ch_over, upcorner, midcorner, downcorner, aa, cc, 
22  gg, tt, deleted
23  } chartype;
24
25typedef struct treeset_t {
26  node *root;
27  pointarray nodep;
28  long nonodes;
29  boolean waswritten, hasmult, haslengths, nolengths, initialized;
30} treeset_t;
31
32treeset_t treesets[2];
33treeset_t simplifiedtree;
34
35typedef enum { arb, use, spec } howtree;
36
37typedef enum {BEFORENODE, ATNODE} movet;
38
39movet fromtype;
40
41
42#ifndef OLDC
43/* function prototypes */
44void   initretreenode(node **, node **, node *, long, long, long *,
45        long *, initops, pointarray, pointarray, Char *, Char *, FILE *);
46void   gdispose(node *);
47void   maketriad(node **, long);
48void   maketip(node **, long);
49void   copynode(node *, node *);
50node  *copytrav(node *);
51void   copytree(void);
52void   getoptions(void);
53void   configure(void);
54void   prefix(chartype);
55
56void   postfix(chartype);
57void   ltrav(node *, boolean *);
58boolean ifhaslengths(void);
59void   add_at(node *, node *, node *);
60void   add_before(node *, node *);
61void   add_child(node *, node *);
62void   re_move(node **, node **);
63void   reroot(node *);
64void   ltrav_(node *, double, double, double *, long *, long *);
65
66void   precoord(node *, boolean *, double *, long *);
67void   coordinates(node *, double, long *, long *, double *);
68void   flatcoordinates(node *, long *);
69void   grwrite(chartype, long, long *);
70void   drawline(long, node *, boolean *);
71void   printree(void);
72void   togglelengths(void);
73void   arbitree(void);
74void   yourtree(void);
75void   buildtree(void);
76void   unbuildtree(void);
77void   retree_help(void);
78void   consolidatetree(long);
79void   rearrange(void);
80boolean any_deleted(node *);
81void   fliptrav(node *, boolean);
82void   flip(long);
83void   transpose(long);
84void   ifdeltrav(node *, boolean *);
85double oltrav(node *);
86void   outlength(void);
87void   midpoint(void);
88void   deltrav(node *, boolean );
89void   reg_del(node *, boolean);
90boolean isdeleted(long);
91void   deletebranch(void);
92void   restorebranch(void);
93void   del_or_restore(void);
94void   undo(void);
95void   treetrav(node *);
96void   simcopynode(node *, node *);
97node  *simcopytrav(node *);
98void   simcopytree(void);
99void   writebranchlength(double);
100void   treeout(node *, boolean, double, long);
101void   maketemptriad(node **, long);
102void   roottreeout(boolean *);
103void   notrootedtorooted(void);
104void   rootedtonotrooted(void);
105void   treewrite(boolean *);
106void   retree_window(adjwindow);
107void   getlength(double *, reslttype *, boolean *);
108void   changelength(void);
109void   changename(void);
110void   clade(void);
111void   changeoutgroup(void);
112void   redisplay(void);
113void   treeconstruct(void);
114/* function prototypes */
115#endif
116
117
118node *root, *garbage;
119
120long nonodes, outgrno, screenwidth, vscreenwidth,
121     screenlines, col, treenumber, leftedge, topedge, treelines,
122     hscroll, vscroll, scrollinc, whichtree, othertree,
123     numtrees, treesread;
124
125double     trweight;
126boolean    waswritten, hasmult, haslengths, nolengths, nexus, xmltree;
127
128node **treeone, **treetwo;
129pointarray nodep;           /* pointers to all nodes in current tree */
130
131node *grbg;
132
133boolean    reversed[14];
134boolean    graphic[14];
135unsigned char       cch[14];
136howtree    how;
137
138char       intreename[FNMLNGTH],outtreename[FNMLNGTH];
139
140boolean    subtree, written, readnext;
141node      *nuroot;
142Char      global_ch;
143
144boolean delarray[maxsz];
145
146
147void initretreenode(node **p, node **local_grbg, node *q, long UNUSED_len,
148                long nodei, long *ntips, long *parens, initops whichinit,
149                pointarray UNUSED_treenode, pointarray local_nodep, Char *str,
150                Char *ch, FILE *fp_intree)
151{
152    (void)UNUSED_len;
153    (void)UNUSED_treenode;
154
155  /* initializes a node */
156  long i;
157  boolean minusread;
158  double valyew, divisor;
159
160  switch (whichinit) {
161 
162    case bottom:
163      gnu(local_grbg, p);
164      (*p)->index = nodei;
165      (*p)->tip = false;
166      (*p)->deleted=false;
167      (*p)->deadend=false;
168      (*p)->onebranch=false;
169      (*p)->onebranchhaslength=false;
170      for (i=0;i<MAXNCH;i++)
171        (*p)->nayme[i] = '\0';
172      local_nodep[(*p)->index - 1] = (*p);
173      break;
174 
175    case nonbottom:
176      gnu(local_grbg, p);
177      (*p)->index = nodei;
178      break;
179 
180    case hslength:
181      if ((*p)->back) {
182        (*p)->back->back = *p;
183        (*p)->haslength = (*p)->back->haslength;
184        if ((*p)->haslength)
185          (*p)->length = (*p)->back->length;
186      }
187      break;
188 
189    case tip:
190      (*ntips)++;
191      gnu(local_grbg, p);
192      local_nodep[(*ntips) - 1] = *p;
193      (*p)->index = *ntips;
194      (*p)->tip = true;
195      (*p)->hasname = true;
196      strncpy ((*p)->nayme, str, MAXNCH);
197      break;
198 
199    case length:
200      (*p)->haslength = true;
201      if ((*p)->back != NULL)
202        (*p)->back->haslength = (*p)->haslength;
203      processlength(&valyew, &divisor, ch,
204        &minusread, fp_intree, parens);
205      if (!minusread)
206        (*p)->length = valyew / divisor;
207      else
208        (*p)->length = 0.0;
209      (*p)->back  = q;
210      if (haslengths && q != NULL) {
211        (*p)->back->haslength = (*p)->haslength;
212        (*p)->back->length = (*p)->length;
213      }
214      break;
215 
216    case hsnolength:
217      haslengths = (haslengths && q == NULL);
218      (*p)->haslength = false;
219      (*p)->back  = q;
220      break;
221 
222    default:        /*cases iter, treewt, unttrwt         */
223      break;        /*should not occur                */
224 
225  }
226} /* initretreenode */
227
228
229void gdispose(node *p)
230{
231  /* go through tree throwing away nodes */
232  node *q, *r;
233
234  if (p->tip)
235    return;
236  q = p->next;
237  while (q != p) {
238    gdispose(q->back);
239    q->tip = false;
240    q->hasname = false;
241    q->haslength = false;
242    r = q;
243    q = q->next;
244    chuck(&grbg, r);
245  }
246  q->tip = false;
247  q->hasname = false;
248  q->haslength = false;
249  chuck(&grbg, q);
250}  /*  gdispose */
251
252
253void maketriad(node **p, long index)
254{
255  /* Initiate an internal node with stubs for two children */
256  long i, j;
257  node *q;
258  q = NULL;
259  for (i = 1; i <= 3; i++) {
260    gnu(&grbg, p);
261    (*p)->index = index;
262    (*p)->hasname = false;
263    (*p)->haslength = false;
264    (*p)->deleted=false;
265    (*p)->deadend=false;
266    (*p)->onebranch=false;
267    (*p)->onebranchhaslength=false;
268    for (j=0;j<MAXNCH;j++)
269      (*p)->nayme[j] = '\0';
270    (*p)->next = q;
271    q = *p;
272  }
273  (*p)->next->next->next = *p;
274  q = (*p)->next;
275  while (*p != q) {
276    (*p)->back = NULL;
277    (*p)->tip = false;
278    *p = (*p)->next;
279  }
280  nodep[index - 1] = *p;
281}  /* maketriad */
282
283
284void maketip(node **p, long index)
285{
286  /*  Initiate a tip node */
287  gnu(&grbg, p);
288  (*p)->index = index;
289  (*p)->tip = true;
290  (*p)->hasname = false;
291  (*p)->haslength = false;
292  nodep[index - 1] = *p;
293}  /* maketip */
294
295
296void copynode(node *fromnode, node *tonode)
297{
298  /* Copy the contents of a node from fromnode to tonode. */
299  int i;
300
301  tonode->index   = fromnode->index;
302  tonode->deleted = fromnode->deleted;
303  tonode->tip     = fromnode->tip;
304  tonode->hasname = fromnode->hasname;
305  if (fromnode->hasname)
306    for (i=0;i<MAXNCH;i++)
307      tonode->nayme[i] = fromnode->nayme[i]; 
308  tonode->haslength = fromnode->haslength;
309  if (fromnode->haslength)
310    tonode->length = fromnode->length;
311
312} /* copynode */
313
314
315node *copytrav(node *p)
316{
317  /* Traverse the tree from p on down, copying nodes to the other tree */
318  node *q, *newnode, *newnextnode, *temp;
319
320  gnu(&grbg, &newnode);
321  copynode(p,newnode);
322
323  if (nodep[p->index-1] == p)
324    treesets[othertree].nodep[p->index-1] = newnode;
325
326  /* if this is a tip, return now */
327  if (p->tip)
328    return newnode;
329
330  /* go around the ring, copying as we go */
331
332  q = p->next;
333  gnu(&grbg, &newnextnode);
334  copynode(q, newnextnode);
335  newnode->next = newnextnode;
336
337  do {
338
339    newnextnode->back = copytrav(q->back);
340    newnextnode->back->back = newnextnode;
341    q = q->next;
342    if (q == p)
343      newnextnode->next = newnode;
344    else {
345      temp = newnextnode;
346      gnu(&grbg, &newnextnode);
347      copynode(q, newnextnode);
348      temp->next = newnextnode;
349    }
350  } while (q != p);
351  return newnode;
352} /* copytrav */
353
354
355void copytree()
356{
357  /* Make a complete copy of the current tree for undo purposes */
358  if (whichtree == 1)
359    othertree = 0;
360  else
361    othertree = 1;
362
363  treesets[othertree].root = copytrav(root);
364  treesets[othertree].nonodes = nonodes;
365  treesets[othertree].waswritten = waswritten;
366  treesets[othertree].hasmult = hasmult;
367  treesets[othertree].haslengths = haslengths;
368  treesets[othertree].nolengths = nolengths;
369  treesets[othertree].initialized = true;
370
371} /* copytree */
372
373
374void getoptions()
375{
376  /* interactively set options */
377  long loopcount;
378  Char ch;
379  boolean done, gotopt;
380
381  how = use;
382  outgrno = 1;
383  loopcount = 0;
384  do {
385    cleerhome();
386    printf("\nTree Rearrangement, version %s\n\n",VERSION);
387    printf("Settings for this run:\n");
388    printf("  U          Initial tree (arbitrary, user, specify)?");
389    if (how == arb)
390      printf("  Arbitrary\n");
391    else if (how == use)
392      printf("  User tree from tree file\n");
393    else
394      printf("  Tree you specify\n");
395    printf("  N   Format to write out trees (PHYLIP, Nexus, XML)?");
396    if (nexus)
397      printf("  Nexus\n");
398    else {
399      if (xmltree)
400        printf("  XML\n");
401      else
402        printf("  PHYLIP\n");
403      }
404    printf("  0                     Graphics type (IBM PC, ANSI)?");
405    if (ibmpc)
406      printf("  IBM PC\n");
407    if (ansi )
408      printf("  ANSI\n");
409    if (!(ibmpc || ansi))
410      printf("  (none)\n");
411    printf("  W       Width of terminal screen, of plotting area?");
412    printf("%4ld, %2ld\n", screenwidth, vscreenwidth);
413    printf("  L                        Number of lines on screen?");
414    printf("%4ld\n", screenlines);
415    printf("\nAre these settings correct?");
416    printf(" (type Y or the letter for one to change)\n");
417#ifdef WIN32
418    phyFillScreenColor();
419#endif
420    scanf("%c%*[^\n]", &ch);
421    getchar();
422    if (ch == '\n')
423      ch = ' ';
424    ch = (isupper(ch)) ? ch : toupper(ch);
425    done = (ch == 'Y');
426    gotopt = (ch == 'U' || ch == 'N' || ch == '0' || ch == 'L' || ch == 'W');
427    if (gotopt) {
428      switch (ch) {
429
430      case 'U':
431        if (how == arb)
432          how = use;
433        else if (how == use)
434            how = spec;
435          else
436            how = arb;
437        break;
438
439      case 'N':
440        if (nexus) {
441          nexus = false;
442          xmltree = true;
443        }
444        else if (xmltree)
445            xmltree = false;
446          else
447            nexus = true;
448        break;
449
450      case '0':
451        initterminal(&ibmpc, &ansi);
452        break;
453
454      case 'L':
455        initnumlines(&screenlines);
456        break;
457
458      case 'W':
459        screenwidth= readlong("Width of terminal screen (in characters)?\n");
460        vscreenwidth=readlong("Width of plotting area (in characters)?\n");
461        break;
462      }
463    }
464    if (!(gotopt || done))
465      printf("Not a possible option!\n");
466    countup(&loopcount, 100);
467  } while (!done);
468  if (scrollinc < screenwidth / 2.0)
469    hscroll = scrollinc;
470  else
471    hscroll = screenwidth / 2;
472  if (scrollinc < screenlines / 2.0)
473    vscroll = scrollinc;
474  else
475    vscroll = screenlines / 2;
476}  /* getoptions */
477
478
479void configure()
480{
481  /* configure to machine -- set up special characters */
482  chartype a;
483
484  for (a = horiz; (long)a <= (long)deleted; a = (chartype)((long)a + 1))
485    reversed[(long)a] = false;
486  for (a = horiz; (long)a <= (long)deleted; a = (chartype)((long)a + 1))
487    graphic[(long)a] = false;
488  cch[(long)deleted] = '.';
489  cch[(long)updel] = ':';
490  if (ibmpc) {
491    cch[(long)horiz] = '>';
492    cch[(long)vert] = 186;
493    graphic[(long)vert] = true;
494    cch[(long)up] = 186;
495    graphic[(long)up] = true;
496    cch[(long)ch_over] = 205;
497    graphic[(long)ch_over] = true;
498    cch[(long)upcorner] = 200;
499    graphic[(long)upcorner] = true;
500    cch[(long)midcorner] = 204;
501    graphic[(long)midcorner] = true;
502    cch[(long)downcorner] = 201;
503    graphic[(long)downcorner] = true;
504    return;
505  }
506  if (ansi) {
507    cch[(long)horiz] = '>';
508    cch[(long)vert] = cch[(long)horiz];
509    reversed[(long)vert] = true;
510    cch[(long)up] = 'x';
511    graphic[(long)up] = true;
512    cch[(long)ch_over] = 'q';
513    graphic[(long)ch_over] = true;
514    cch[(long)upcorner] = 'm';
515    graphic[(long)upcorner] = true;
516    cch[(long)midcorner] = 't';
517    graphic[(long)midcorner] = true;
518    cch[(long)downcorner] = 'l';
519    graphic[(long)downcorner] = true;
520    return;
521  }
522  cch[(long)horiz] = '>';
523  cch[(long)vert] = ' ';
524  cch[(long)up] = '!';
525  cch[(long)upcorner] = '`';
526  cch[(long)midcorner] = '+';
527  cch[(long)downcorner] = ',';
528  cch[(long)ch_over] = '-';
529}  /* configure */
530
531
532void prefix(chartype a)
533{
534  /* give prefix appropriate for this character */
535  if (reversed[(long)a])
536    prereverse(ansi);
537  if (graphic[(long)a])
538    pregraph2(ansi);
539}  /* prefix */
540
541
542void postfix(chartype a)
543{
544  /* give postfix appropriate for this character */
545  if (reversed[(long)a])
546    postreverse(ansi);
547  if (graphic[(long)a])
548    postgraph2(ansi);
549}  /* postfix */
550
551
552void ltrav(node *p, boolean *localhl)
553{
554  /* Traversal function for ifhaslengths() */
555  node *q;
556
557  if (p->tip) {
558    (*localhl) = ((*localhl) && p->haslength);
559    return;
560  }
561  q = p->next;
562  do {
563    (*localhl) = ((*localhl) && q->haslength);
564    if ((*localhl))
565      ltrav(q->back, localhl);
566    q = q->next;
567  } while (p != q);
568}  /* ltrav */
569
570
571boolean ifhaslengths()
572{
573  /* return true if every branch in tree has a length */
574  boolean localhl;
575  localhl = true;
576  ltrav(root, &localhl);
577  return localhl;
578}  /* ifhaslengths */
579
580
581void add_at(node *below, node *newtip, node *newfork)
582{
583  /* inserts the nodes newfork and its left descendant, newtip,
584    to the tree.  below becomes newfork's right descendant */
585  node *leftdesc, *rtdesc;
586  double local_length;
587
588  if (below != nodep[below->index - 1])
589    below = nodep[below->index - 1];
590
591  if (newfork == NULL) {
592    nonodes++;
593    maketriad (&newfork, nonodes);
594    if (haslengths) {
595      newfork->haslength = true;
596      newfork->next->haslength = true;
597      newfork->next->next->haslength = true;
598    }
599  }
600  if (below->back != NULL) {
601    below->back->back = newfork;
602  }
603  newfork->back = below->back;
604  leftdesc = newtip;
605  rtdesc = below;
606  rtdesc->back = newfork->next->next;
607  newfork->next->next->back = rtdesc;
608  newfork->next->back = leftdesc;
609  leftdesc->back = newfork->next;
610  if (root == below)
611    root = newfork;
612  root->back = NULL;
613  if (!haslengths)
614    return;
615  if (newfork->back != NULL) {
616    local_length = newfork->back->length / 2.0;
617    newfork->length = local_length;
618    newfork->back->length = local_length;
619    below->length = local_length;
620    below->back->length = local_length;
621  } else {
622    local_length = newtip->length / 2.0;
623    newtip->length = local_length;
624    newtip->back->length = local_length;
625    below->length = local_length;
626    below->back->length = local_length;
627    below->haslength = true;
628  }
629  newtip->back->length = newtip->length;
630}  /* add_at */
631
632
633void add_before(node *atnode, node *newtip)
634{
635  /* inserts the node newtip together with its ancestral fork
636     into the tree next to the node atnode. */
637/*xx ?? debug what to do if no ancestral node -- have to create one */
638/*xx this case is handled by add_at.  However, add_at does not account for
639when there is more than one sibling for the relocated newtip */
640  node *q;
641
642  if (atnode != nodep[atnode->index - 1])
643    atnode = nodep[atnode->index - 1];
644  q = nodep[newtip->index-1]->back;
645  if (q != NULL) {
646    q = nodep[q->index-1];
647    if (newtip == q->next->next->back) {
648      q->next->back = newtip;
649      newtip->back = q->next;
650      q->next->next->back = NULL;
651    }
652  }
653  if (newtip->back != NULL) {
654    add_at(atnode, newtip, nodep[newtip->back->index-1]);
655  } else {
656    add_at(atnode, newtip, NULL);
657  }
658}  /* add_before */
659
660
661void add_child(node *parent, node *newchild)
662{
663  /* adds the node newchild into the tree as the last child of parent */
664
665  int i;
666  node *newnode, *q;
667
668  if (parent != nodep[parent->index - 1])
669    parent = nodep[parent->index - 1];
670  gnu(&grbg, &newnode);
671  newnode->tip = false;
672  newnode->deleted=false;
673  newnode->deadend=false;
674  newnode->onebranch=false;
675  newnode->onebranchhaslength=false;
676  for (i=0;i<MAXNCH;i++)
677    newnode->nayme[i] = '\0';
678  newnode->index = parent->index;
679  q = parent;
680  do {
681    q = q->next;
682  } while (q->next != parent);
683  newnode->next = parent;
684  q->next = newnode;
685  newnode->back = newchild;
686  newchild->back = newnode;
687  if (newchild->haslength) {
688    newnode->length = newchild->length;
689    newnode->haslength = true;
690  } else
691    newnode->haslength = false;
692}  /* add_child */
693
694
695void re_move(node **item, node **fork)
696{
697/* Removes node item from the tree.  If item has one sibling,
698   removes its ancestor, fork, from the tree as well and attach
699   item's sib to fork's ancestor.  In this case, it returns a pointer
700   to the removed fork node which is still attached to item.
701*/
702  node *p =NULL, *q;
703  int nodecount;
704
705  if ((*item)->back == NULL) {
706    *fork = NULL;
707    return;
708  }
709  *fork = nodep[(*item)->back->index - 1];
710  nodecount = 0;
711  if ((*fork)->next->back == *item)
712    p = *fork;
713  q = (*fork)->next;
714  do {
715    nodecount++;
716    if (q->next->back == *item)
717      p = q;
718    q = q->next;
719  } while (*fork != q);
720
721  if (nodecount > 2)
722  {
723    fromtype = ATNODE;
724    p->next = (*item)->back->next;
725    chuck(&grbg, (*item)->back);
726    (*item)->back = NULL;
727/*xx*/ *fork = NULL;
728  } else {
729    /* traditional (binary tree) remove code */
730    if (*item == (*fork)->next->back) {
731      if (root == *fork)
732     root = (*fork)->next->next->back;
733    } else {
734      if (root == *fork)
735     root = (*fork)->next->back;
736    }
737    fromtype = BEFORENODE;
738    /* stitch nodes together, leaving out item */
739    p = (*item)->back->next->back;
740    q = (*item)->back->next->next->back;
741    if (p != NULL)
742      p->back = q;
743    if (q != NULL)
744      q->back = p;
745    if (haslengths) {
746      if (p != NULL && q != NULL) {
747     p->length += q->length;
748     q->length = p->length;
749      } else
750     (*item)->length = (*fork)->next->length + (*fork)->next->next->length;
751    }
752    (*fork)->back = NULL;
753    p = (*fork)->next;
754    while (p != *fork) {
755      p->back = NULL;
756      p = p->next;
757    }
758    (*item)->back = NULL;
759  } /* endif nodecount > 2 else */
760}  /* re_move */
761
762
763void reroot(node *outgroup)
764{
765  /* Reorient tree so that outgroup is by itself on the left of the root */ 
766  node *p, *q, *r;
767  long nodecount = 0;
768  double templen;
769
770  q = root->next;
771  do {                    /* when this loop exits, p points to the internal */
772    p = q;                /* node to the right of root */
773    nodecount++;
774    q = p->next;
775  } while (q != root);
776  r = p;
777
778  /* There is no point in proceeding if
779       1. outgroup is a child of root, and
780       2. the tree bifurcates at the root.
781   */
782  if((outgroup->back->index == root->index) && !(nodecount > 2))
783    return;
784
785  /* reorient nodep array
786
787     The nodep array must point to the ring member of each ring
788     that is closest to the root.  The while loop changes the ring member
789     pointed to by nodep[] for those nodes that will have their
790     orientation changed by the reroot operation.
791  */
792  p = outgroup->back;
793  while (p->index != root->index) {
794    q = nodep[p->index - 1]->back;
795    nodep[p->index - 1] = p;
796    p = q;
797  }
798  if (nodecount > 2)
799    nodep[p->index - 1] = p;
800
801  /* If nodecount > 2, the current node ring to which root is pointing
802     will remain in place and root will point somewhere else. */
803  /* detach root from old location */
804  if (nodecount > 2) {
805    r->next = root->next;
806    root->next = NULL;
807    nonodes++;
808    maketriad(&root, nonodes);
809
810    if (haslengths) {
811      /* root->haslength remains false, or else treeout() will generate
812         a bogus extra length */
813      root->next->haslength = true;
814      root->next->next->haslength = true;
815    }
816  } else { /* if (nodecount > 2) else */
817    q = root->next;
818    q->back->back = r->back;
819    r->back->back = q->back;
820
821    if (haslengths) {
822      r->back->length = r->back->length + q->back->length;
823      q->back->length = r->back->length;
824    }
825  } /* if (nodecount > 2) endif */
826
827  /* tie root into new location */
828  root->next->back = outgroup;
829  root->next->next->back = outgroup->back;
830  outgroup->back->back = root->next->next;
831  outgroup->back = root->next;
832
833  /* place root equidistant between left child (outgroup) and
834     right child by deviding outgroup's length */
835  if (haslengths) {
836    templen = outgroup->length / 2.0;
837    outgroup->length = templen;
838    outgroup->back->length = templen;
839    root->next->next->length = templen;
840    root->next->next->back->length = templen;
841  }
842} /* reroot */
843
844
845void ltrav_(node *p, double lengthsum, double lmin, double *tipmax,
846            long *across, long *maxchar)
847{
848  node *q;
849  long rchar, nl;
850  double sublength;
851
852  if (p->tip) {
853    if (lengthsum > (*tipmax))
854      (*tipmax) = lengthsum;
855    if (lmin == 0.0)
856      return;
857    rchar = (long)(lengthsum / (*tipmax) * (*across) + 0.5);
858
859    nl = strlen(nodep[p->index - 1]->nayme);
860    if (rchar + nl > (*maxchar))
861      (*across) = (*maxchar) - (long)(nl * (*tipmax) / lengthsum + 0.5);
862    return;
863  }
864  q = p->next;
865  do {
866    if (q->length >= lmin)
867      sublength = q->length;
868    else
869      sublength = lmin;
870    ltrav_(q->back, lengthsum + sublength, lmin, tipmax, across, maxchar);
871    q = q->next;
872  } while (p != q);
873}  /* ltrav */
874
875
876void precoord(node *local_nuroot,boolean *local_subtree,double *tipmax,long *across)
877{
878  /* set tipmax and across so that tree is scaled to screenwidth */
879
880  double oldtipmax, minimum;
881  long i, maxchar;
882
883  (*tipmax) = 0.0;
884  if ((*local_subtree))
885    maxchar = vscreenwidth - 13;
886  else
887    maxchar = vscreenwidth - 5;
888  (*across) = maxchar;
889  ltrav_(local_nuroot, 0.0, 0.0, tipmax, across, &maxchar);
890  i = 0;
891  do {
892    oldtipmax = (*tipmax);
893    minimum = 3.0 / (*across) * (*tipmax);
894    ltrav_(local_nuroot, 0.0, minimum, tipmax, across, &maxchar);
895    i++;
896  } while (fabs((*tipmax) - oldtipmax) > 0.01 * oldtipmax && i <= 40);
897}  /* precoord */
898
899
900void coordinates(node *p, double lengthsum, long *across, long *tipy,
901                 double *tipmax)
902{
903  /* establishes coordinates of nodes for display with lengths */
904  node *q, *first, *last;
905
906  if (p->tip) {
907    p->xcoord = (long)((*across) * lengthsum / (*tipmax) + 0.5);
908    p->ycoord = (*tipy);
909    p->ymin   = (*tipy);
910    p->ymax   = (*tipy);
911    (*tipy)  += down;
912    return;
913  }
914  q = p->next;
915  do {
916   coordinates(q->back, lengthsum + q->length, across, tipy, tipmax);
917    q = q->next;
918  } while (p != q);
919  first = p->next->back;
920  q = p;
921  while (q->next != p)
922    q = q->next;
923  last = q->back;
924  p->xcoord = (long)((*across) * lengthsum / (*tipmax) + 0.5);
925  if (p == root) {
926    if (root->next->next->next == root)
927      p->ycoord = (first->ycoord + last->ycoord) / 2;
928    else
929      p->ycoord = p->next->next->back->ycoord;
930  }
931  else
932    p->ycoord = (first->ycoord + last->ycoord) / 2;
933  p->ymin = first->ymin;
934  p->ymax = last->ymax;
935}  /* coordinates */
936
937
938void flatcoordinates(node *p, long *tipy)
939{
940  /* establishes coordinates of nodes for display without lengths */
941  node *q, *first, *last;
942
943  if (p->tip) {
944    p->xcoord = 0;
945    p->ycoord = (*tipy);
946    p->ymin   = (*tipy);
947    p->ymax   = (*tipy);
948    (*tipy) += down;
949    return;
950  }
951  q = p->next;
952  do {
953    flatcoordinates(q->back, tipy);
954    q = q->next;
955  } while (p != q);
956  first = p->next->back;
957  q = p->next;
958  while (q->next != p)
959    q = q->next;
960  last = q->back;
961  p->xcoord = (last->ymax - first->ymin) * 3 / 2;
962  if (p == root) {
963    if (root->next->next->next == root)
964      p->ycoord = (first->ycoord + last->ycoord) / 2;
965    else
966      p->ycoord = p->next->next->back->ycoord;
967  }
968  else
969  p->ycoord = (first->ycoord + last->ycoord) / 2;
970  p->ymin = first->ymin;
971  p->ymax = last->ymax;
972}  /* flatcoordinates */
973
974
975void grwrite(chartype c, long num, long *pos)
976{
977  long i;
978     
979  prefix(c);
980  for (i = 1; i <= num; i++) {
981    if ((*pos) >= leftedge && (*pos) - leftedge + 1 < screenwidth)
982      putchar(cch[(long)c]);
983    (*pos)++;
984  }
985  postfix(c);
986}  /* grwrite */
987
988
989void drawline(long i, node *local_nuroot, boolean *local_subtree)
990{
991  /* draws one row of the tree diagram by moving up tree */
992  long pos;
993  node *p, *q, *r, *s, *first =NULL, *last =NULL;
994  long n, j;
995  long up_nondel, down_nondel;
996  boolean extra, done;
997  chartype c, d;
998  pos = 1;
999  p = local_nuroot;
1000  q = local_nuroot;
1001
1002  extra = false;
1003  if (i == (long)p->ycoord && (p == root || (*local_subtree))) {
1004    c = ch_over;
1005    if ((*local_subtree))
1006      stwrite("Subtree:", 8, &pos, leftedge, screenwidth);
1007    if (p->index >= 100)
1008      nnwrite(p->index, 3, &pos, leftedge, screenwidth);
1009    else if (p->index >= 10) {
1010      grwrite(c, 1, &pos);
1011      nnwrite(p->index, 2, &pos, leftedge, screenwidth);
1012    } else {
1013      grwrite(c, 2, &pos);
1014      nnwrite(p->index, 1, &pos, leftedge, screenwidth);
1015    }
1016    extra = true;
1017  } else {
1018    if ((*local_subtree))
1019      stwrite("          ", 10, &pos, leftedge, screenwidth);
1020    else
1021      stwrite("  ", 2, &pos, leftedge, screenwidth);
1022  }
1023  do {
1024    if (!p->tip) {
1025      r = p->next;
1026      done = false;
1027      do {
1028     if (i >= r->back->ymin && i <= r->back->ymax) {
1029       q = r->back;
1030       done = true;
1031     }
1032     r = r->next;
1033      } while (!(done || r == p));
1034      first = p->next->back;
1035      r = p->next;
1036      while (r->next != p)
1037     r = r->next;
1038      last = r->back;
1039    }
1040    done = (p == q);
1041    if (haslengths && !nolengths)
1042      n = (long)(q->xcoord - p->xcoord);
1043    else
1044      n = (long)(p->xcoord - q->xcoord);
1045    if (n < 3 && !q->tip)
1046      n = 3;
1047    if (extra) {
1048      n--;
1049      extra = false;
1050    }
1051    if ((long)q->ycoord == i && !done) {
1052      c = ch_over;
1053      if (!haslengths && !q->haslength)
1054     c = horiz;
1055      if (q->deleted)
1056        c = deleted;
1057      if (q == first)
1058        d = downcorner;
1059      else if (q == last)
1060        d = upcorner;
1061      else if ((long)q->ycoord == (long)p->ycoord)
1062        d = c;
1063      else
1064        d = midcorner;
1065      if (n > 1 || q->tip) {
1066     grwrite(d, 1, &pos);
1067     grwrite(c, n - 3, &pos);
1068      }
1069      if (q->index >= 100)
1070     nnwrite(q->index, 3, &pos, leftedge, screenwidth);
1071      else if (q->index >= 10) {
1072     grwrite(c, 1, &pos);
1073     nnwrite(q->index, 2, &pos, leftedge, screenwidth);
1074      } else {
1075     grwrite(c, 2, &pos);
1076     nnwrite(q->index, 1, &pos, leftedge, screenwidth);
1077      }
1078      extra = true;
1079    } else if (!q->tip) {
1080      if ((long)last->ycoord > i && (long)first->ycoord < i &&
1081          i != (long)p->ycoord) {
1082     c = up;
1083        if(p->deleted)
1084          c = updel;
1085        if (!p->tip) {
1086          up_nondel = 0;
1087          down_nondel = 0;
1088          r = p->next;
1089          do {
1090            s = r->back;
1091            if ((long)s->ycoord < (long)p->ycoord && !s->deleted)
1092              up_nondel = (long)s->ycoord;
1093            if (s->ycoord > p->ycoord && !s->deleted && 
1094                (down_nondel == 0))
1095              down_nondel = (long)s->ycoord;
1096            if (i < (long)p->ycoord && s->deleted && i > (long)s->ycoord)
1097              c = updel;
1098            if (i > (long)p->ycoord && s->deleted && i < (long)s->ycoord)
1099              c = updel;
1100            r = r->next;
1101          } while (r != p);
1102
1103          if ((up_nondel != 0) && i < (long)p->ycoord && i > up_nondel)
1104            c = up;
1105          if ((down_nondel != 0) && i > (long)p->ycoord && i < down_nondel)
1106            c = up;
1107        }
1108     grwrite(c, 1, &pos);
1109     chwrite(' ', n - 1, &pos, leftedge, screenwidth);
1110      } else
1111     chwrite(' ', n, &pos, leftedge, screenwidth);
1112    } else
1113      chwrite(' ', n, &pos, leftedge, screenwidth);
1114    if (p != q)
1115      p = q;
1116  } while (!done);
1117  if ((long)p->ycoord == i && p->tip) {
1118    if (p->hasname) {
1119      n = 0;
1120      for (j = 1; j <= MAXNCH; j++) {
1121     if (nodep[p->index - 1]->nayme[j - 1] != '\0')
1122       n = j;
1123      }
1124      chwrite(':', 1, &pos, leftedge, screenwidth);
1125      for (j = 0; j < n; j++)
1126     chwrite(nodep[p->index - 1]->nayme[j],
1127                1, &pos, leftedge, screenwidth);
1128    }
1129  }
1130  putchar('\n');
1131}  /* drawline */
1132
1133
1134void printree()
1135{
1136  /* prints out diagram of the tree */
1137  long across;
1138  long tipy;
1139  double tipmax;
1140  long i, rover, dow, vmargin;
1141
1142  haslengths = ifhaslengths();
1143  if (!subtree)
1144    nuroot = root;
1145  cleerhome();
1146  tipy = 1;
1147  rover = 100 / spp;
1148  if (rover > overr)
1149    rover = overr;
1150  dow = down;
1151  if (spp * dow > screenlines && !subtree) {
1152    dow--;
1153    rover--;
1154  }
1155  if (haslengths && !nolengths) {
1156    precoord(nuroot, &subtree, &tipmax, &across);
1157    /* protect coordinates() from div/0 errors if user decides to
1158       examine a tip as a subtree */
1159    if (tipmax == 0)
1160      tipmax = 0.01;
1161    coordinates(nuroot, 0.0, &across, &tipy, &tipmax);
1162  } else
1163    flatcoordinates(nuroot, &tipy);
1164  vmargin = 2;
1165  treelines = tipy - dow;
1166  if (topedge != 1) {
1167    printf("** %ld lines above screen **\n", topedge - 1);
1168    vmargin++;
1169  }
1170  if ((treelines - topedge + 1) > (screenlines - vmargin))
1171    vmargin++;
1172  for (i = 1; i <= treelines; i++) {
1173    if (i >= topedge && i < topedge + screenlines - vmargin)
1174      drawline(i, nuroot,&subtree);
1175  }
1176  if (leftedge > 1)
1177    printf("** %ld characters to left of screen ", leftedge);
1178  if ((treelines - topedge + 1) > (screenlines - vmargin)) {
1179    printf("** %ld", treelines - (topedge - 1 + screenlines - vmargin));
1180    printf(" lines below screen **\n");
1181  }
1182  if (treelines - topedge + vmargin + 1 < screenlines)
1183    putchar('\n');
1184}  /* printree */
1185
1186
1187void togglelengths()
1188{
1189  nolengths = !nolengths;
1190  printree();
1191}  /* togglengths */
1192
1193
1194void arbitree()
1195{
1196  long i, maxinput;
1197  node *newtip, *newfork;
1198
1199  maxinput = 1;
1200  do {
1201    spp = readlong("How many species?\n");
1202    maxinput++;
1203    if (maxinput == 100) {
1204      printf("ERROR: too many tries at choosing species\n");
1205      exxit(-1);
1206    }
1207  } while (spp <= 0);
1208  nonodes = spp * 2 - 1;
1209  maketip(&root, 1);
1210  maketip(&newtip, 2);
1211  maketriad(&newfork, spp + 1);
1212  add_at(root, newtip, newfork);
1213  for (i = 3; i <= spp; i++) {
1214    maketip(&newtip, i);
1215    maketriad(&newfork, spp + i - 1);
1216    add_at(nodep[spp + i - 3], newtip, newfork);
1217  }
1218}  /* arbitree */
1219
1220
1221void yourtree()
1222{
1223  long uniquearray[maxsz];
1224  long uniqueindex = 0;
1225  long i, j, k, k_max, maxinput;
1226  boolean ok, done;
1227  node *newtip, *newfork;
1228  Char ch;
1229
1230  for (i = 0; i < maxsz; i++)
1231    uniquearray[i] = 0;
1232  spp = 2;
1233  nonodes = spp * 2 - 1;
1234  maketip(&root, 1);
1235  maketip(&newtip, 2);
1236  maketriad(&newfork, spp + 3);
1237  add_at(root, newtip, newfork);
1238  i = 2;
1239  maxinput = 1;
1240  do {
1241    i++;
1242    printree();
1243    printf("Enter 0 to stop building tree.\n");
1244    printf("Add species%3ld", i);
1245    do {
1246      printf("\n at or before which node (type number): ");
1247      inpnum(&j, &ok);
1248      ok = (ok && ((j>=0 && j < i) || (j > spp + 2 && j < spp + i + 1)));
1249      if (!ok)
1250        printf("Impossible number. Please try again:\n");
1251      maxinput++;
1252      if (maxinput == 100) {
1253        printf("ERROR: too many tries at choosing number\n");
1254        exxit(-1);
1255      }
1256    } while (!ok);
1257    maxinput = 1;
1258    if (j >= i) {   /* has user chosen a non-tip? if so, offer choice */
1259      do {
1260        printf(" Insert at node (A) or before node (B)? ");
1261#ifdef WIN32
1262        phyFillScreenColor();
1263#endif
1264        scanf("%c%*[^\n]", &ch);
1265        getchar();
1266        if (ch == '\n')
1267          ch = ' ';
1268        ch = isupper(ch) ? ch : toupper(ch);
1269        maxinput++;
1270        if (maxinput == 100) {
1271          printf("ERROR: too many tries at choosing option\n");
1272          exxit(-1);
1273        }
1274      } while (ch != 'A' && ch != 'B');
1275    }
1276    else ch = 'B';   /* if user has chosen a tip, set Before */
1277
1278    if (j != 0) {
1279      if (ch == 'A') {
1280        if (!nodep[j - 1]->tip) {
1281          maketip(&newtip, i);
1282          add_child(nodep[j - 1], nodep[i - 1]);
1283        }
1284      } else {
1285        maketip(&newtip, i);
1286        maketriad(&newfork, spp + i + 1);
1287        nodep[i-1]->back = newfork;
1288        newfork->back = nodep[i-1];
1289        add_before(nodep[j - 1], nodep[i - 1]);
1290      } /* endif (before or at node) */
1291    }
1292
1293    done = (j == 0);
1294    if (!done) {
1295      if (ch == 'B')
1296        k = spp * 2 + 3;
1297      else
1298        k = spp * 2 + 2;
1299
1300      k_max = k;
1301      do {
1302        if (nodep[k - 2] != NULL) {
1303          nodep[k - 1] = nodep[k - 2];
1304          nodep[k - 1]->index = k;
1305          nodep[k - 1]->next->index = k;
1306          nodep[k - 1]->next->next->index = k;
1307        }
1308        k--;
1309      } while (k != spp + 3); 
1310      if (j > spp + 1)
1311        j++;
1312      spp++;
1313      nonodes = spp * 2 - 1;
1314    }
1315  } while (!done);
1316
1317  for (i = spp + 1; i <= k_max; i++) {
1318    if ((nodep[i - 1] != nodep[i]) && (nodep[i - 1] != NULL)) {
1319      uniquearray[uniqueindex++] = i;
1320    }
1321  }
1322
1323  for (i = 0; i < uniqueindex; i++) {
1324    nodep[spp + i] = nodep[uniquearray[i] - 1];
1325    nodep[spp + i]->index = spp + i + 1;
1326    nodep[spp + i]->next->index = spp + i + 1;
1327    nodep[spp + i]->next->next->index = spp + i + 1;
1328  }
1329  for (i = spp + uniqueindex; i <= k_max; i++)
1330    nodep[i] = NULL;
1331
1332  nonodes = spp * 2 - 1;
1333}  /* yourtree */
1334
1335
1336void buildtree()
1337{
1338  /* variables needed to be passed to treeread() */
1339  long    nextnode   = 0;
1340  pointarray dummy_treenode=NULL;  /* Ignore what happens to this */
1341  boolean goteof     = false;
1342  boolean local_haslengths = false;
1343  boolean firsttree;
1344  node *p, *q;
1345  long nodecount = 0;
1346
1347
1348  /* These assignments moved from treeconstruct -- they seem to happen
1349     only here. */
1350/*xx treeone & treetwo assignments should probably happen in
1351treeconstruct.  Memory leak if user reads multiple trees. */
1352  treeone = (node **)Malloc(maxsz*sizeof(node *));
1353  treetwo = (node **)Malloc(maxsz*sizeof(node *));
1354  simplifiedtree.nodep = (node **)Malloc(maxsz*sizeof(node *));
1355  subtree     = false;
1356  topedge     = 1;
1357  leftedge    = 1;
1358  switch (how) {
1359   
1360  case arb:
1361    nodep = treeone;
1362    treesets[othertree].nodep = treetwo;
1363    arbitree();
1364    break;
1365
1366  case use:
1367    printf("\nReading tree file ...\n\n");
1368   
1369    if (!readnext) {
1370      /* This is the first time through here, act accordingly */
1371      firsttree = true;
1372      openfile(&intree,INTREE,"input tree file",
1373            "r","retree",intreename);
1374      numtrees = countsemic(&intree);
1375      treesread = 0;
1376    } else {
1377      /* This isn't the first time through here ... */
1378      firsttree = false;
1379    }
1380    allocate_nodep(&nodep, &intree, &spp);
1381    /*xx*/treesets[whichtree].nodep = nodep;
1382   
1383    if (firsttree)
1384      nayme = (naym *)Malloc(spp*sizeof(naym));
1385    treeread(intree, &root, dummy_treenode, &goteof, &firsttree,
1386             nodep, &nextnode, &local_haslengths,
1387             &grbg, initretreenode);
1388    nonodes = nextnode;
1389    treesread++;
1390    treesets[othertree].nodep = treetwo;
1391    break;
1392
1393  case spec:
1394    nodep = treeone;
1395    treesets[othertree].nodep = treetwo;
1396    yourtree();
1397    break;
1398  }
1399
1400  q = root->next;
1401  do {
1402    p = q;
1403    nodecount++;
1404    q = p->next;
1405  } while (q != root);
1406
1407  outgrno = root->next->back->index;
1408  if(!(nodecount > 2)) {
1409    reroot(nodep[outgrno - 1]);
1410  }
1411}  /* buildtree */
1412
1413
1414void unbuildtree()
1415{
1416  /* throw all nodes of the tree onto the garbage heap */
1417  long i;
1418
1419  gdispose(root);
1420  for (i = 0; i < nonodes; i++)
1421    nodep[i] = NULL;
1422}  /* unbuildtree */
1423
1424
1425void retree_help()
1426{
1427  /* display help information */
1428  char tmp[100];
1429  printf("\n\n . Redisplay the same tree again\n");
1430  if (haslengths) {
1431    printf(" = Redisplay the same tree with");
1432    if (!nolengths)
1433      printf("out/with");
1434    else
1435      printf("/without");
1436    printf(" lengths\n");
1437  }
1438  printf(" U Undo the most recent change in the tree\n");
1439  printf(" W Write tree to a file\n");
1440  printf(" + Read next tree from file (may blow up if none is there)\n");
1441  printf("\n");
1442  printf(" R Rearrange a tree by moving a node or group\n");
1443  printf(" O select an Outgroup for the tree\n");
1444  if (haslengths)
1445    printf(" M Midpoint root the tree\n");
1446  printf(" T Transpose immediate branches at a node\n");
1447  printf(" F Flip (rotate) subtree at a node\n");
1448  printf(" D Delete or restore nodes\n");
1449  printf(" B Change or specify the length of a branch\n");
1450  printf(" N Change or specify the name(s) of tip(s)\n");
1451  printf("\n");
1452  printf(" H Move viewing window to the left\n");
1453  printf(" J Move viewing window downward\n");
1454  printf(" K Move viewing window upward\n");
1455  printf(" L Move viewing window to the right\n");
1456  printf(" C show only one Clade (subtree) (might be useful if tree is ");
1457    printf("too big)\n");
1458  printf(" ? Help (this screen)\n");
1459  printf(" Q (Quit) Exit from program\n");
1460  printf(" X Exit from program\n\n");
1461  printf(" TO CONTINUE, PRESS ON THE Return OR Enter KEY");
1462  getstryng(tmp);
1463  printree();
1464}  /* retree_help */
1465
1466
1467void consolidatetree(long index)
1468{
1469  node *start, *r, *q;
1470  int i;
1471
1472  start = nodep[index - 1];
1473  q = start->next;
1474
1475  while (q != start) {
1476    r = q;
1477    q = q->next;
1478    chuck(&grbg, r);
1479  } 
1480  chuck(&grbg, q);
1481
1482  i = index;
1483  while (nodep[i-1] != NULL) {
1484    r = nodep[i - 1];
1485    if (!(r->tip))
1486       r->index--;
1487    if (!(r->tip)) {
1488      q = r->next;
1489      do {
1490        q->index--;
1491        q = q->next;
1492      } while (r != q && q != NULL);
1493    }
1494    nodep[i - 1] = nodep[i];
1495    i++;
1496  }
1497
1498  nonodes--;
1499} /* consolidatetree */
1500
1501
1502void rearrange()
1503{
1504  long i, j, maxinput;
1505  boolean ok1, ok2;
1506  node *p, *q;
1507  char ch;
1508
1509  printf("Remove everything to the right of which node? ");
1510  inpnum(&i, &ok1);
1511  ok1 = (ok1 && i >= 1 && i <= (spp * 2 - 1) && i != root->index);
1512  if (ok1)
1513    ok1 = !nodep[i - 1]->deleted;
1514  if (ok1) {
1515    printf("Add at or before which node? ");
1516    inpnum(&j, &ok2);
1517    ok2 = (ok2 && j >= 1 && j <= (spp * 2 - 1));
1518    if (ok2) {
1519      if (j != root->index)
1520        ok2 = !nodep[nodep[j - 1]->back->index - 1]->deleted;
1521    }
1522    if (ok2) {
1523/*xx This edit says "j must not be i's parent."
1524     Is this necessary anymore?   */
1525    /*  ok2 = (nodep[j - 1] != nodep[nodep[i - 1]->back->index - 1]);*/
1526      p = nodep[j - 1];
1527      /* make sure that j is not a descendent of i */
1528      while (p != root) {
1529        ok2 = (ok2 && p != nodep[i - 1]);
1530        p = nodep[p->back->index - 1];
1531      }
1532      if (ok1 && ok2) {
1533        maxinput = 1;
1534        do {
1535          printf("Insert at node (A) or before node (B)? ");
1536#ifdef WIN32
1537          phyFillScreenColor();
1538#endif
1539          scanf("%c%*[^\n]", &ch);
1540          getchar();
1541          if (ch == '\n')
1542            ch = ' ';
1543          ch = isupper(ch) ? ch : toupper(ch);
1544          maxinput++;
1545          if (maxinput == 100) {
1546            printf("ERROR: too many tries at choosing option\n");
1547            exxit(-1);
1548          }
1549        } while (ch != 'A' && ch != 'B');
1550        if (ch == 'A') {
1551          if (!(nodep[j - 1]->deleted) && !nodep[j - 1]->tip) {
1552            copytree();
1553            re_move(&nodep[i - 1], &q);
1554            add_child(nodep[j - 1], nodep[i - 1]);
1555            if (fromtype == BEFORENODE)
1556              consolidatetree(q->index);
1557          } else
1558            ok2 = false;
1559        } else {
1560          if (j != root->index) { /* can't insert at root */
1561            copytree();
1562            printf("Insert before node %ld\n",j);
1563            re_move(&nodep[i - 1], &q);
1564            if (q != NULL) {
1565              nodep[q->index-1]->next->back = nodep[i-1];
1566              nodep[i-1]->back = nodep[q->index-1]->next;
1567            }
1568            add_before(nodep[j - 1], nodep[i - 1]);
1569          } else
1570            ok2 = false;
1571        } /* endif (before or at node) */
1572      } /* endif (ok to do move) */
1573    } /* endif (destination node ok) */
1574  } /* endif (from node ok) */
1575  printree();
1576  if (!(ok1 && ok2))
1577    printf("Not a possible rearrangement.  Try again: \n");
1578  else {
1579    written = false;
1580  }
1581}  /* rearrange */
1582
1583
1584boolean any_deleted(node *p)
1585{
1586  /* return true if there are any deleted branches from branch on down */
1587  boolean localdl;
1588  localdl = false;
1589  ifdeltrav(p, &localdl);
1590  return localdl;
1591}  /* any_deleted */
1592
1593
1594void fliptrav(node *p, boolean recurse)
1595{
1596  node *q, *temp, *r =NULL, *rprev =NULL, *l, *lprev;
1597  boolean lprevflag;
1598  int nodecount, loopcount, i;
1599
1600  if (p->tip)
1601    return;
1602
1603  q = p->next;
1604  l = q;
1605  lprev = p;
1606  nodecount = 0;
1607
1608  do {
1609    nodecount++;
1610    if (q->next->next == p) {
1611      rprev = q;
1612      r = q->next;
1613    }
1614    q = q->next;
1615  } while (p != q);
1616
1617  if (nodecount == 1)
1618    return;
1619  loopcount = nodecount / 2;
1620
1621  for (i=0; i<loopcount; i++) {
1622    lprev->next = r;
1623    rprev->next = l;
1624    temp = r->next;
1625    r->next = l->next;
1626    l->next = temp;
1627    if (i < (loopcount - 1)) {
1628      lprevflag = false;
1629      q = p->next;
1630      do {
1631        if (q == lprev->next && !lprevflag) {
1632          lprev = q;
1633          l = q->next;
1634          lprevflag = true;
1635        }
1636        if (q->next == rprev) {
1637          rprev = q;
1638          r = q->next;
1639        }
1640        q = q->next;
1641      } while (p != q);
1642    }
1643  }
1644  if (recurse) {
1645    q = p->next;
1646    do {
1647      fliptrav(q->back, true);
1648      q = q->next;
1649    } while (p != q);
1650  }
1651}  /* fliptrav */
1652
1653
1654void flip(long atnode)
1655{
1656  /* flip at a node left-right */
1657  long i;
1658  boolean ok;
1659
1660  if (atnode == 0) {
1661    printf("Flip branches at which node? ");
1662    inpnum(&i, &ok);
1663    ok = (ok && i > spp && i <= nonodes);
1664    if (ok)
1665      ok = !any_deleted(nodep[i - 1]);
1666  } else {
1667    i = atnode;
1668    ok = true;
1669  }
1670  if (ok) {
1671    copytree();
1672    fliptrav(nodep[i - 1], true);
1673  }
1674  if (atnode == 0)
1675    printree();
1676  if (ok) {
1677    written = false;
1678    return;
1679  }
1680  if ((i >= 1 && i <= spp) ||
1681      (i > spp && i <= nonodes && any_deleted(nodep[i - 1])))
1682    printf("Can't flip there. ");
1683  else
1684    printf("No such node. ");
1685}  /* flip */
1686
1687
1688void transpose(long atnode)
1689{
1690  /* flip at a node left-right */
1691  long i;
1692  boolean ok;
1693
1694  if (atnode == 0) {
1695    printf("Transpose branches at which node? ");
1696    inpnum(&i, &ok);
1697    ok = (ok && i > spp && i <= nonodes);
1698    if (ok)
1699      ok = !nodep[i - 1]->deleted;
1700  } else {
1701    i = atnode;
1702    ok = true;
1703  }
1704  if (ok) {
1705    copytree();
1706    fliptrav(nodep[i - 1], false);
1707  }
1708  if (atnode == 0)
1709    printree();
1710  if (ok) {
1711    written = false;
1712    return;
1713  }
1714  if ((i >= 1 && i <= spp) ||
1715      (i > spp && i <= nonodes && nodep[i - 1]->deleted))
1716    printf("Can't transpose there. ");
1717  else
1718    printf("No such node. ");
1719}  /* transpose */
1720
1721
1722void ifdeltrav(node *p, boolean *localdl)
1723{
1724  node *q;
1725
1726  if (*localdl)
1727    return;
1728
1729  if (p->tip) {
1730    (*localdl) = ((*localdl) || p->deleted);
1731    return;
1732  }
1733  q = p->next;
1734  do {
1735    (*localdl) = ((*localdl) || q->deleted);
1736    ifdeltrav(q->back, localdl);
1737    q = q->next;
1738  } while (p != q);
1739}  /* ifdeltrav */
1740
1741
1742double oltrav(node *p)
1743{
1744  node *q;
1745  double maxlen, templen;
1746  if (p->deleted)
1747    return 0.0;
1748  if (p->tip) {
1749    p->beyond = 0.0;
1750    return 0.0;
1751  } else {
1752    q = p->next;
1753    maxlen = 0;
1754    do {
1755      templen = q->back->deleted ? 0.0 : q->length + oltrav(q->back);
1756      maxlen = (maxlen > templen) ? maxlen : templen;
1757      q->beyond = templen;
1758      q = q->next;
1759    } while (p != q);
1760    p->beyond = maxlen;
1761    return (maxlen);
1762  }
1763}  /* oltrav */
1764
1765
1766void outlength()
1767{
1768/* compute the farthest combined length out from each node */
1769  // double dummy;
1770    /*dummy = */oltrav(root);
1771}  /* outlength */
1772
1773
1774void midpoint()
1775{
1776/* midpoint root the tree */
1777  double balance, greatlen, lesslen, grlen, maxlen;
1778  node *maxnode, *grnode, *lsnode =NULL;
1779  boolean ok = true;
1780  boolean changed = false;
1781  node *p, *q;
1782  long nodecount = 0;
1783  boolean multi = false;
1784
1785  copytree();
1786  p = root;
1787  outlength();
1788  q = p->next;
1789  greatlen = 0;
1790  grnode = q->back;
1791  lesslen = 0;
1792
1793  q = root->next;
1794  do {
1795    p = q;
1796    nodecount++;
1797    q = p->next;
1798  } while (q != root);
1799  if (nodecount > 2)
1800    multi = true;
1801
1802  /* Find the two greatest lengths reaching from root to tips.
1803     Also find the lengths and node pointers of the first nodes in the
1804     direction of those two greatest lengths.  */
1805  p = root;
1806  q = root->next;
1807  do {
1808    if (greatlen <= q->beyond) {
1809      lesslen = greatlen;
1810      lsnode = grnode;
1811      greatlen = q->beyond;
1812      grnode = q->back;
1813    }
1814    if ((greatlen > q->beyond) && (q->beyond > lesslen)) {
1815      lesslen = q->beyond;
1816      lsnode = q->back;
1817    }
1818    q = q->next;
1819  } while (p != q);
1820
1821  /* If we don't have two non-deleted nodes to balance between then
1822     we can't midpoint root the tree */
1823  if (grnode->deleted || lsnode->deleted || grnode == lsnode)
1824    ok = false;
1825  balance = greatlen - (greatlen + lesslen) / 2.0;
1826  grlen = grnode->length;
1827
1828  while ((balance > grlen) && ok) {
1829    /* First, find the most distant immediate child of grnode
1830       and reroot to it. */
1831    p = grnode;
1832    q = p->next;
1833    maxlen = 0;
1834    maxnode = q->back;
1835    do {
1836      if (maxlen <= q->beyond) {
1837        maxlen = q->beyond;
1838        maxnode = q->back;
1839      }
1840      q = q->next;
1841    } while (p != q);
1842    reroot(maxnode);
1843    changed = true;
1844
1845    /* Reassess the situation, using the same "find the two greatest
1846       lengths" code as occurs before the while loop.  If another reroot
1847       is necessary, this while loop will repeat. */
1848    p = root;
1849    outlength();
1850    q = p->next;
1851    greatlen = 0;
1852    grnode = q->back;
1853    lesslen = 0;
1854    do {
1855      if (greatlen <= q->beyond) {
1856        lesslen = greatlen;
1857        lsnode = grnode;
1858        greatlen = q->beyond;
1859        grnode = q->back;
1860      }
1861      if ((greatlen > q->beyond) && (q->beyond > lesslen)) {
1862        lesslen = q->beyond;
1863        lsnode = q->back;
1864      }
1865      q = q->next;
1866    } while (p != q);
1867    if (grnode->deleted || lsnode->deleted || grnode == lsnode)
1868      ok = false;
1869    balance = greatlen - (greatlen + lesslen) / 2.0;
1870    grlen = grnode->length;
1871  }; /* end of while ((balance > grlen) && ok) */
1872
1873  if (ok) {
1874/*xx the following ignores deleted nodes */
1875/*   this may be ok because deleted nodes are omitted from length calculations */
1876    if (multi) {
1877      reroot(grnode); /*xx need length corrections */
1878
1879      p = root;
1880      outlength();
1881      q = p->next;
1882      greatlen = 0;
1883      grnode = q->back;
1884      lesslen = 0;
1885
1886      do {
1887        if (greatlen <= q->beyond) {
1888          lesslen = greatlen;
1889          lsnode = grnode;
1890          greatlen = q->beyond;
1891          grnode = q->back;
1892        }
1893        if ((greatlen > q->beyond) && (q->beyond > lesslen)) {
1894          lesslen = q->beyond;
1895          lsnode = q->back;
1896        }
1897        q = q->next;
1898      } while (p != q);
1899      balance = greatlen - (greatlen + lesslen) / 2.0;
1900    }
1901    grnode->length -= balance;
1902    grnode->back->length = grnode->length;
1903    lsnode->length += balance;
1904    lsnode->back->length = lsnode->length;
1905  }
1906  printree();
1907  if (ok) {
1908    if (any_deleted(root))
1909      printf("Deleted nodes were not used in midpoint calculations.\n");
1910  }
1911  else {
1912    printf("Can't perform midpoint because of deleted branches.\n");
1913    if (changed) {
1914      undo();
1915      printf("Tree restored to original state.  Undo information lost.\n");
1916    }
1917  }
1918} /* midpoint */
1919
1920
1921void deltrav(node *p, boolean value)
1922{
1923  /* register p and p's children as deleted or extant, depending on value */
1924  node *q;
1925
1926  p->deleted = value;
1927
1928  if (p->tip)
1929    return;
1930
1931  q = p->next;
1932  do {
1933    deltrav(q->back, value);
1934    q = q->next;
1935  } while (p != q);
1936}  /* deltrav */
1937
1938
1939void reg_del(node *delp, boolean value)
1940{
1941  /* register delp and all of delp's children as deleted */
1942  deltrav(delp, value);
1943}  /* reg_del */
1944
1945
1946boolean isdeleted(long nodenum)
1947{
1948  /* true if nodenum is a node number in a deleted branch */
1949  return(nodep[nodenum - 1]->deleted);
1950} /* isdeleted */
1951
1952
1953void deletebranch()
1954{
1955  /* delete a node */
1956  long i;
1957  boolean ok1;
1958
1959  printf("Delete everything to the right of which node? ");
1960  inpnum(&i, &ok1);
1961  ok1 = (ok1 && i >= 1 && i <= nonodes && i != root->index && !isdeleted(i));
1962  if (ok1) {
1963    copytree();
1964    reg_del(nodep[i - 1],true);
1965  }
1966  printree();
1967  if (!ok1)
1968    printf("Not a possible deletion.  Try again.\n");
1969  else {
1970    written = false;
1971  }
1972}  /* deletebranch */
1973
1974
1975void restorebranch()
1976{
1977  /* restore deleted branches */
1978  long i;
1979  boolean ok1;
1980
1981  printf("Restore everything to the right of which node? ");
1982  inpnum(&i, &ok1);
1983  ok1 = (ok1 && i >= 1 && i < spp * 2 && i != root->index && isdeleted(i)
1984             && !nodep[nodep[i - 1]->back->index - 1]->deleted);
1985
1986  if (ok1) {
1987    reg_del(nodep[i - 1],false);
1988  }
1989  printree();
1990  if (!ok1)
1991    printf("Not a possible restoration.  Try again: \n");
1992  else {
1993    written = false;
1994  }
1995} /* restorebranch */
1996
1997
1998void del_or_restore()
1999{
2000  /* delete or restore a branch */
2001  long maxinput;
2002  Char ch;
2003
2004  if (any_deleted(root)) {
2005    maxinput = 1;
2006    do {
2007      printf("Enter D to delete a branch\n");
2008      printf("OR enter R to restore a branch: ");
2009#ifdef WIN32
2010      phyFillScreenColor();
2011#endif
2012      scanf("%c%*[^\n]", &ch);
2013      getchar();
2014      if (ch == '\n')
2015        ch = ' ';
2016      ch = (isupper(ch)) ? ch : toupper(ch);
2017      maxinput++;
2018      if (maxinput == 100) {
2019        printf("ERROR: too many tries at choosing option\n");
2020        exxit(-1);
2021      }
2022    } while (ch != 'D' && ch != 'R');
2023    if (ch == 'R')
2024      restorebranch();
2025    else
2026      deletebranch();
2027  }
2028  else
2029    deletebranch();
2030} /* del_or_restore */
2031
2032
2033void undo()
2034{
2035  /* don't undo to an uninitialized tree */
2036  if (!treesets[othertree].initialized) {
2037    printree();
2038    printf("Nothing to undo.\n");
2039    return;
2040  }
2041
2042  treesets[whichtree].root = root;
2043  treesets[whichtree].nodep = nodep;
2044  treesets[whichtree].nonodes = nonodes;
2045  treesets[whichtree].waswritten = waswritten;
2046  treesets[whichtree].hasmult = hasmult;
2047  treesets[whichtree].haslengths = haslengths;
2048  treesets[whichtree].nolengths = nolengths;
2049  treesets[whichtree].initialized = true;
2050
2051  whichtree = othertree;
2052
2053  root = treesets[whichtree].root;
2054  nodep = treesets[whichtree].nodep;
2055  nonodes = treesets[whichtree].nonodes;
2056  waswritten = treesets[whichtree].waswritten;
2057  hasmult = treesets[whichtree].hasmult;
2058  haslengths = treesets[whichtree].haslengths;
2059  nolengths = treesets[whichtree].nolengths;
2060
2061  if (othertree == 0)
2062    othertree = 1;
2063  else
2064    othertree = 0;
2065
2066  printree();
2067}  /* undo */
2068
2069/*
2070   These attributes of nodes in the tree are modified by treetrav()
2071   in preparation for writing a tree to disk.
2072 
2073   boolean deadend      This node is not deleted but all of its children
2074     are, so this node will be treated as such when
2075     the tree is written or displayed.
2076   
2077   boolean onebranch    This node has only one valid child, so that this
2078     node will not be written and its child will be
2079     written as a child of its grandparent with the
2080     appropriate summing of lengths.
2081 
2082   nodep *onebranchnode
2083     Used if onebranch is true.  Onebranchnode points
2084     to the one valid child.  This child may be one or
2085     more generations down from the current node.
2086 
2087   double onebranchlength
2088     Used if onebranch is true.  Onebranchlength is
2089     the length from the current node to the valid
2090     child.
2091*/
2092
2093void treetrav(node *p)
2094{
2095  long branchcount = 0;
2096  node *q, *onebranchp =NULL;
2097 
2098/* Count the non-deleted branches hanging off of this node into branchcount.
2099   If there is only one such branch, onebranchp points to that branch. */
2100 
2101  if (p->tip)
2102    return;
2103 
2104  q = p->next;
2105  do {
2106    if (!q->back->deleted) {
2107      if (!q->back->tip)
2108     treetrav(q->back);
2109     
2110      if (!q->back->deadend && !q->back->deleted) {
2111     branchcount++;
2112     onebranchp = q->back;
2113      }
2114    }
2115    q = q->next;
2116  } while (p != q);
2117
2118  if (branchcount == 0)
2119    p->deadend = true;
2120  else
2121    p->deadend = false;
2122  p->onebranch = false;
2123  if (branchcount == 1 && onebranchp->tip) {
2124    p->onebranch = true;
2125    p->onebranchnode = onebranchp;
2126    p->onebranchhaslength = (p->haslength || (p == root))
2127                            && onebranchp->haslength;
2128    if (p->onebranchhaslength)
2129      p->onebranchlength = onebranchp->length + p->length;
2130  }
2131  if (branchcount == 1 && !onebranchp->tip) {
2132    p->onebranch = true;
2133    if (onebranchp->onebranch) {
2134      p->onebranchnode = onebranchp->onebranchnode;
2135      p->onebranchhaslength = (p->haslength || (p == root))
2136                              && onebranchp->onebranchhaslength;
2137      if (p->onebranchhaslength)
2138        p->onebranchlength = onebranchp->onebranchlength + p->length;
2139    } else {
2140      p->onebranchnode = onebranchp;
2141      p->onebranchhaslength = p->haslength && onebranchp->haslength;
2142      if (p->onebranchhaslength)
2143        p->onebranchlength = onebranchp->length + p->length;
2144    }
2145  }
2146} /* treetrav */
2147
2148
2149void simcopynode(node *fromnode, node *tonode)
2150{
2151  /* Copy the contents of a node from fromnode to tonode. */
2152  int i;
2153
2154  tonode->index   = fromnode->index;
2155  tonode->deleted = fromnode->deleted;
2156  tonode->tip     = fromnode->tip;
2157  tonode->hasname = fromnode->hasname;
2158  if (fromnode->hasname)
2159    for (i=0;i<MAXNCH;i++)
2160      tonode->nayme[i] = fromnode->nayme[i]; 
2161  tonode->haslength = fromnode->haslength;
2162  if (fromnode->haslength)
2163    tonode->length = fromnode->length;
2164
2165} /* simcopynode */
2166
2167
2168node *simcopytrav(node *p)
2169{
2170  /* Traverse the tree from p on down, copying nodes to the other tree */
2171  node *q, *newnode, *newnextnode, *temp;
2172  long lastnodeidx = 0;
2173
2174  gnu(&grbg, &newnode);
2175  simcopynode(p, newnode);
2176
2177  if (nodep[p->index - 1] == p)
2178    simplifiedtree.nodep[p->index - 1] = newnode;
2179
2180  /* if this is a tip, return now */
2181  if (p->tip)
2182    return newnode;
2183  if (p->onebranch && p->onebranchnode->tip) {
2184    simcopynode(p->onebranchnode, newnode);
2185    if (p->onebranchhaslength)
2186      newnode->length = p->onebranchlength;
2187    return newnode;
2188  } else if (p->onebranch && !p->onebranchnode->tip) {
2189    /* recurse down p->onebranchnode */
2190    p->onebranchnode->length = p->onebranchlength;
2191    p->onebranchnode->haslength = p->onebranchnode->haslength;
2192    return simcopytrav(p->onebranchnode);
2193  } else {
2194    /* Multiple non-deleted branch case:  go round the node recursing
2195       down the branches. Don't go down deleted branches or dead ends. */
2196    q = p->next;
2197    while (q != p) {
2198      if (!q->back->deleted && !q->back->deadend)
2199        lastnodeidx = q->back->index;
2200      q = q->next;
2201    }
2202
2203    q = p->next;
2204    gnu(&grbg, &newnextnode);
2205    simcopynode(q, newnextnode);
2206    newnode->next = newnextnode;
2207    do {
2208      /* If branch is deleted or is a dead end, do not recurse
2209         down the branch. */
2210      if (!q->back->deleted && !q->back->deadend) {
2211        newnextnode->back = simcopytrav(q->back);
2212        newnextnode->back->back = newnextnode;
2213        q = q->next;
2214        if (newnextnode->back->index == lastnodeidx) {
2215          newnextnode->next = newnode;
2216          break;
2217        }
2218        if (q == p) {
2219          newnextnode->next = newnode;
2220        } else {
2221          temp = newnextnode;
2222          gnu(&grbg, &newnextnode);
2223          simcopynode(q, newnextnode);
2224          temp->next = newnextnode;
2225        }
2226      } else { /*xx this else and q=q->next are experimental
2227                 (seems to be working) */
2228        q = q->next;
2229      }
2230     
2231    } while (q != p);
2232  }
2233  return newnode;
2234}  /* simcopytrav */
2235
2236
2237void simcopytree()
2238{
2239  /* Make a simplified copy of the current tree for rooting/unrooting
2240     on output.  Deleted notes are removed and lengths are consolidated. */
2241
2242  simplifiedtree.root = simcopytrav(root);
2243  /*xx If there are deleted nodes, nonodes will be different.
2244       However, nonodes is not used in the simplified tree. */
2245  simplifiedtree.nonodes = nonodes;
2246  simplifiedtree.waswritten = waswritten;
2247  simplifiedtree.hasmult = hasmult;
2248  simplifiedtree.haslengths = haslengths;
2249  simplifiedtree.nolengths = nolengths;
2250  simplifiedtree.initialized = true;
2251} /* simcopytree */
2252
2253
2254void writebranchlength(double x)
2255{
2256  long w;
2257
2258  /* write branch length onto output file, keeping track of what
2259     column of line you are in, and writing to correct precision */
2260
2261  if (x > 0.0)
2262    w = (long)(0.43429448222 * log(x));
2263  else if (x == 0.0)
2264    w = 0;
2265  else
2266    w = (long)(0.43429448222 * log(-x)) + 1;
2267  if (w < 0)
2268    w = 0;
2269  if ((long)(100000*x) == 100000*(long)x) {
2270    if (!xmltree)
2271      putc(':', outtree);
2272    fprintf(outtree, "%*.1f", (int)(w + 2), x);
2273    col += w + 3;
2274  }
2275  else {
2276    if ((long)(100000*x) == 10000*(long)(10*x)) {
2277      if (!xmltree)
2278        putc(':', outtree);
2279      fprintf(outtree, "%*.1f", (int)(w + 3), x);
2280      col += w + 4;
2281    }
2282    else {
2283      if ((long)(100000*x) == 1000*(long)(100*x)) {
2284        if (!xmltree)
2285          putc(':', outtree);
2286        fprintf(outtree, "%*.2f", (int)(w + 4), x);
2287        col += w + 5;
2288      }
2289      else {
2290        if ((long)(100000*x) == 100*(long)(1000*x)) {
2291          if (!xmltree)
2292            putc(':', outtree);
2293          fprintf(outtree, "%*.3f", (int)(w + 5), x);
2294          col += w + 6;
2295        }
2296        else {
2297            if ((long)(100000*x) == 10*(long)(10000*x)) {
2298              if (!xmltree)
2299                putc(':', outtree);
2300            fprintf(outtree, "%*.4f", (int)(w + 6), x);
2301            col += w + 7;
2302          }
2303          else {
2304            if (!xmltree)
2305              putc(':', outtree);
2306            fprintf(outtree, "%*.5f", (int)(w + 7), x);
2307            col += w + 8;
2308          }
2309        }
2310      }
2311    }
2312  }
2313} /* writebranchlength */
2314
2315
2316void treeout(node *p, boolean writeparens, double addlength, long indent)
2317{
2318  /* write out file with representation of final tree */
2319  long i, n, lastnodeidx = 0;
2320  Char c;
2321  double x;
2322  boolean comma;
2323  node *q;
2324 
2325/* If this is a tip or there are no non-deleted branches from this node,
2326   render this node as a tip (write its name).  */
2327
2328  if (p == root) {
2329    indent = 0;
2330    if (xmltree) {
2331      fprintf(outtree, "<phylogeny>");  /* assumes no length at root! */
2332    } else putc('(', outtree);
2333  }
2334  if (p->tip) {
2335    if (p->hasname) {
2336      n = 0;
2337      for (i = 1; i <= MAXNCH; i++) {
2338        if ((nodep[p->index - 1]->nayme[i - 1] != '\0')
2339          && (nodep[p->index - 1]->nayme[i - 1] != ' '))
2340          n = i;
2341      }
2342      indent += 2;
2343      if (xmltree) {
2344        putc('\n', outtree);
2345        for (i = 1; i <= indent; i++)
2346          putc(' ', outtree);
2347        fprintf(outtree, "<branch");
2348        if (p->haslength) {
2349          fprintf(outtree, " length=\"");
2350          x = p->length;
2351          writebranchlength(x);
2352          fprintf(outtree, "\"");
2353        }
2354        putc('>', outtree);
2355        fprintf(outtree, "<name>");
2356      }
2357      for (i = 0; i < n; i++) {
2358        c = nodep[p->index - 1]->nayme[i];
2359        if (c == ' ')
2360          c = '_';
2361        putc(c, outtree);
2362      }
2363      col += n;
2364      if (xmltree)
2365        fprintf(outtree, "</name></branch>");
2366    }
2367  } else if (p->onebranch && p->onebranchnode->tip) { 
2368    if (p->onebranchnode->hasname) {
2369      n = 0;
2370      for (i = 1; i <= MAXNCH; i++) {
2371      if ((nodep[p->index - 1]->nayme[i - 1] != '\0')
2372           && (nodep[p->index - 1]->nayme[i - 1] != ' '))
2373        n = i;
2374      indent += 2;
2375      if (xmltree) {
2376        putc('\n', outtree);
2377        for (i = 1; i <= indent; i++)
2378          putc(' ', outtree);
2379        fprintf(outtree, "<branch");
2380        if ((p->haslength && writeparens) || p->onebranch) {
2381          if (!(p->onebranch && !p->onebranchhaslength)) {
2382            fprintf(outtree, " length=");
2383            if (p->onebranch)
2384              x = p->onebranchlength;
2385            else
2386              x = p->length;
2387            x += addlength;
2388            writebranchlength(x);
2389          }
2390          fprintf(outtree, "<name>");
2391        }
2392      }
2393      for (i = 0; i < n; i++) {
2394        c = p->onebranchnode->nayme[i];
2395        if (c == ' ')
2396          c = '_';
2397        putc(c, outtree);
2398      }
2399      col += n;
2400      if (xmltree)
2401        fprintf(outtree, "</name></branch>");
2402    }
2403  }
2404  } else if (p->onebranch && !p->onebranchnode->tip) {
2405    treeout(p->onebranchnode, true, 0.0, indent);
2406  } else {
2407      /* Multiple non-deleted branch case:  go round the node
2408         recursing down the branches.  */
2409    if (xmltree) {
2410      putc('\n', outtree);
2411      indent += 2;
2412      for (i = 1; i <= indent; i++)
2413        putc(' ', outtree);
2414      if (p == root)
2415        fprintf(outtree, "<branch>");
2416    }
2417    if (p != root) {
2418      if (xmltree) {
2419        fprintf(outtree, "<branch");
2420        if ((p->haslength && writeparens) || p->onebranch) {
2421          if (!(p->onebranch && !p->onebranchhaslength)) {
2422            fprintf(outtree, " length=");
2423            if (p->onebranch)
2424              x = p->onebranchlength;
2425            else
2426              x = p->length;
2427            x += addlength;
2428            writebranchlength(x);
2429          }
2430        }
2431        fprintf(outtree, ">");
2432      } else putc('(', outtree); 
2433    }
2434    (col)++;
2435    q = p->next; 
2436    while (q != p) {
2437      if (!q->back->deleted && !q->back->deadend)
2438        lastnodeidx = q->back->index;
2439      q = q->next;
2440    }
2441    q = p->next; 
2442    while (q != p) {
2443      comma = true;
2444/* If branch is deleted or is a dead end, do not recurse
2445   down the branch and do not write a comma afterwards.
2446*/
2447      if (!q->back->deleted && !q->back->deadend)
2448      treeout(q->back, true, 0.0, indent);
2449      else
2450        comma = false;
2451      if (q->back->index == lastnodeidx)
2452        comma = false;
2453      q = q->next;
2454      if (q == p)
2455        break;
2456      if ((q->next == p) && (q->back->deleted || q->back->deadend))
2457        break;
2458      if (comma && !xmltree)
2459        putc(',', outtree);
2460      (col)++;
2461      if ((!xmltree) && col > 65) {
2462        putc('\n', outtree);
2463        col = 0;
2464      }
2465    }
2466/* The right paren ')' closes off this level of recursion. */
2467    if (p != root) {
2468      if (xmltree) {
2469        fprintf(outtree, "\n");
2470        for (i = 1; i <= indent; i++)
2471          putc(' ', outtree);
2472      }
2473      if (xmltree) { 
2474        fprintf(outtree, "</branch>");
2475      } else putc(')', outtree);
2476      indent -= 2;
2477    }
2478    (col)++;
2479  }
2480  if (!xmltree)
2481    if ((p->haslength && writeparens) || p->onebranch) {
2482      if (!(p->onebranch && !p->onebranchhaslength)) {
2483        if (p->onebranch)
2484          x = p->onebranchlength;
2485        else
2486          x = p->length;
2487        x += addlength;
2488        writebranchlength(x);
2489      }
2490    }
2491  if (p == root) {
2492    if (xmltree) {
2493      fprintf(outtree, "\n  </branch>\n</phylogeny>\n");
2494    } else putc(')', outtree); 
2495  }
2496}  /* treeout */
2497
2498
2499void maketemptriad(node **p, long index)
2500{
2501  /* Initiate an internal node with stubs for two children */
2502  long i, j;
2503  node *q;
2504  q = NULL;
2505  for (i = 1; i <= 3; i++) {
2506    gnu(&grbg, p);
2507    (*p)->index = index;
2508    (*p)->hasname = false;
2509    (*p)->haslength = false;
2510    (*p)->deleted=false;
2511    (*p)->deadend=false;
2512    (*p)->onebranch=false;
2513    (*p)->onebranchhaslength=false;
2514    for (j=0;j<MAXNCH;j++)
2515      (*p)->nayme[j] = '\0';
2516    (*p)->next = q;
2517    q = *p;
2518  }
2519  (*p)->next->next->next = *p;
2520  q = (*p)->next;
2521  while (*p != q) {
2522    (*p)->back = NULL;
2523    (*p)->tip = false;
2524    *p = (*p)->next;
2525  }
2526}  /* maketemptriad */
2527
2528
2529void roottreeout(boolean *userwantsrooted)
2530{
2531  /* write out file with representation of final tree */
2532  long trnum, trnumwide;
2533  boolean treeisrooted = false;
2534 
2535  treetrav(root);
2536  simcopytree(); /* Prepare a copy of the going tree without deleted branches */
2537  treesets[whichtree].root = root;        /* Store the current root */
2538
2539  if (nexus) {
2540    trnum = treenumber;
2541    trnumwide = 1;
2542    while (trnum >= 10) {
2543      trnum /= 10;
2544      trnumwide++;
2545    }
2546    fprintf(outtree, "TREE PHYLIP_%*ld = ", (int)trnumwide, treenumber);
2547    if (!(*userwantsrooted))
2548      fprintf(outtree, "[&U] ");
2549    else
2550      fprintf(outtree, "[&R] ");
2551    col += 15;
2552  }
2553  root = simplifiedtree.root;                /* Point root at simplified tree */
2554  root->haslength = false;              /* Root should not have a length */
2555  if (root->tip)
2556    treeisrooted = true;
2557  else {
2558    if (root->next->next->next == root)
2559      treeisrooted = true;
2560    else 
2561      treeisrooted = false;
2562  }
2563  if (*userwantsrooted && !treeisrooted)
2564    notrootedtorooted();
2565  if (!(*userwantsrooted) && treeisrooted)
2566    rootedtonotrooted();
2567  if ((*userwantsrooted && treeisrooted) ||
2568      (!(*userwantsrooted) && !treeisrooted)) {
2569    treeout(root,true,0.0, 0);
2570  }
2571  root = treesets[whichtree].root;     /* Point root at original (real) tree */
2572  if (!xmltree) {
2573    if (hasmult)
2574      fprintf(outtree, "[%6.4f];\n", trweight);
2575    else
2576      fprintf(outtree, ";\n");
2577  }
2578}  /* roottreeout */
2579
2580
2581void notrootedtorooted()
2582{
2583  node *newbase, *temp;
2584
2585  /* root halfway along leftmost branch of unrooted tree */
2586  /* create a new triad for the new base */
2587  maketemptriad(&newbase,nonodes+1);
2588   
2589  /* Take left branch and make it the left branch of newbase */
2590  newbase->next->back = root->next->back;
2591  newbase->next->next->back = root;
2592  /* If needed, divide length between left and right branches */
2593  if (newbase->next->back->haslength) {
2594    newbase->next->back->length /= 2.0;
2595    newbase->next->next->back->length =
2596    newbase->next->back->length;
2597    newbase->next->next->back->haslength = true;
2598  }
2599  /* remove leftmost ring node from old base ring */
2600  temp = root->next->next;
2601  chuck(&grbg, root->next);
2602  root->next = temp;
2603  /* point root at new base and write the tree */
2604  root = newbase;
2605  treeout(root,true,0.0, 0);
2606  /* (since tree mods are to simplified tree and will not be used
2607     for general purpose tree editing, much initialization can be
2608     skipped.) */
2609} /* notrootedtorooted */
2610
2611
2612void rootedtonotrooted()
2613{
2614  node *q, *r, *temp, *newbase;
2615  boolean sumhaslength = false;
2616  double sumlength = 0;
2617
2618  /* Use the leftmost non-tip immediate descendant of the root,
2619   root at that, write a multifurcation with that as the base.
2620  If both descendants are tips, write tree as is. */
2621  root = simplifiedtree.root;
2622  /* first, search for leftmost non-tip immediate descendent of root */
2623  q = root->next->back;
2624  r = root->next->next->back;
2625  if (q->tip && r->tip) {
2626    treeout(root,true,0.0, 0);
2627  } else if (!(q->tip)) {
2628    /* allocate new base pointer */
2629    gnu(&grbg,&newbase);
2630    newbase->next = q->next;
2631    q->next = newbase;
2632    q->back = r;
2633    r->back = q;
2634    if (q->haslength && r->haslength) {
2635      sumlength = q->length + r->length;
2636      sumhaslength = true;
2637    }
2638    if (sumhaslength) {
2639      q->length = sumlength;
2640      q->back->length = sumlength;
2641    } else {
2642      q->haslength = false;
2643      r->haslength = false;
2644    }
2645    chuck(&grbg, root->next->next);
2646    chuck(&grbg, root->next);
2647    chuck(&grbg, root);
2648    root = newbase;
2649    treeout(root, true, 0.0, 0);
2650  } else if (q-tip && !(r->tip)) {
2651    temp = r;
2652    do {
2653      temp = temp->next;
2654    } while (temp->next != r);
2655    gnu(&grbg,&newbase);
2656    newbase->next = temp->next;
2657    temp->next = newbase;     
2658    q->back = r;
2659    r->back = q;
2660    if (q->haslength && r->haslength) {
2661      sumlength = q->length + r->length;
2662      sumhaslength = true;
2663    }
2664    if (sumhaslength) {
2665      q->length = sumlength;
2666      q->back->length = sumlength;
2667    } else {
2668      q->haslength = false;
2669      r->haslength = false;
2670    }
2671    chuck(&grbg, root->next->next);
2672    chuck(&grbg, root->next);
2673    chuck(&grbg, root);
2674    root = newbase;
2675    treeout(root, true, 0.0, 0);
2676   }
2677} /* rootedtonotrooted */
2678
2679
2680void treewrite(boolean *done)
2681{
2682  /* write out tree to a file */
2683  long maxinput;
2684  boolean rooted;
2685
2686  openfile(&outtree,OUTTREE,"output tree file","w","retree",outtreename);
2687  if (nexus) {
2688    fprintf(outtree, "#NEXUS\n");
2689    fprintf(outtree, "BEGIN TREES\n");
2690    fprintf(outtree, "TRANSLATE;\n"); /* MacClade needs this */
2691  }
2692  maxinput = 1;
2693  do {
2694    printf("Enter R if the tree is to be rooted\n");
2695    printf("OR enter U if the tree is to be unrooted: ");
2696#ifdef WIN32
2697    phyFillScreenColor();
2698#endif
2699    scanf("%c%*[^\n]", &global_ch);
2700    getchar();
2701    if (global_ch == '\n')
2702      global_ch = ' ';
2703    global_ch = (isupper(global_ch)) ? global_ch : toupper(global_ch);
2704    maxinput++;
2705    if (maxinput == 100) {
2706      printf("ERROR: too many tries at choosing option\n");
2707      exxit(-1);
2708    }
2709  } while (global_ch != 'R' && global_ch != 'U');
2710  col = 0;
2711  rooted = (global_ch == 'R');
2712  roottreeout(&rooted);
2713  treenumber++;
2714  printf("\nTree written to file \"%s\"\n\n", outtreename);
2715  waswritten = true;
2716  written = true;
2717  if (!(*done))
2718    printree();
2719  if (!readnext && nexus) 
2720    fprintf(outtree, "END;\n");
2721  FClose(outtree);
2722}  /* treewrite */
2723
2724
2725void retree_window(adjwindow action)
2726{
2727  /* move viewing window of tree */
2728  switch (action) {
2729
2730  case left:
2731    if (leftedge != 1)
2732      leftedge -= hscroll;
2733    break;
2734
2735  case downn:
2736    /* The 'topedge + 3' is needed to allow downward scrolling
2737       when part of the tree is above the screen and only 1 or 2 lines
2738       are below it. */
2739    if (treelines - topedge + 3 >= screenlines)
2740      topedge += vscroll;
2741    break;
2742
2743  case upp:
2744    if (topedge != 1)
2745      topedge -= vscroll;
2746    break;
2747
2748  case right:
2749    if (leftedge < vscreenwidth)
2750      leftedge += hscroll;
2751    break;
2752  }
2753  printree();
2754}  /* retree_window */
2755
2756
2757void getlength(double *local_length, reslttype *reslt, boolean *hslngth)
2758{
2759  long maxinput;
2760  double valyew;
2761  char tmp[100];
2762
2763  valyew = 0.0;
2764  maxinput = 1;
2765  do {
2766    printf("\nEnter the new branch length\n");
2767    printf("OR enter U to leave the length unchanged\n");
2768    if (*hslngth)
2769      printf("OR enter R to remove the length from this branch: \n");
2770    getstryng(tmp);
2771
2772    if (tmp[0] == 'u' || tmp[0] == 'U'){
2773      *reslt = quit;
2774      break;
2775    }
2776    else if (tmp[0] == 'r' || tmp[0] == 'R') {
2777      (*reslt) = remoov;
2778      break;}
2779    else if (sscanf(tmp,"%lf",&valyew) == 1){
2780      (*reslt) = valid;
2781      break;}
2782    maxinput++;
2783    if (maxinput == 100) {
2784      printf("ERROR: too many tries at choosing option\n");
2785      exxit(-1);
2786    }
2787  } while (1);
2788  (*local_length) = valyew;
2789}  /* getlength */
2790
2791
2792void changelength()
2793{
2794  /* change or specify the length of a tip */
2795  boolean hslngth;
2796  boolean ok;
2797  long i, w, maxinput;
2798  double local_length, x;
2799  Char ch;
2800  reslttype reslt;
2801  node *p;
2802
2803  maxinput = 1;
2804  do {
2805    printf("Specify length of which branch (0 = all branches)? ");
2806    inpnum(&i, &ok);
2807    ok = (ok && (i>=0 && i <= nonodes));
2808    if (ok && (i != 0))
2809      ok = (ok && !nodep[i - 1]->deleted);
2810    if (i == 0)
2811      ok = (nodep[i - 1] != root);
2812    maxinput++;
2813    if (maxinput == 100) {
2814      printf("ERROR: too many tries at choosing option\n");
2815      exxit(-1);
2816    }
2817  } while (!ok);
2818  if (i != 0) {
2819    p = nodep[i - 1];
2820    putchar('\n');
2821    if (p->haslength) {
2822      x = p->length;
2823      if (x > 0.0)
2824     w = (long)(0.43429448222 * log(x));
2825      else if (x == 0.0)
2826     w = 0;
2827      else
2828     w = (long)(0.43429448222 * log(-x)) + 1;
2829      if (w < 0)
2830     w = 0;
2831      printf("The current length of this branch is %*.5f\n", (int)(w + 7), x);
2832    } else
2833      printf("This branch does not have a length\n");
2834    hslngth = p->haslength;
2835    getlength(&local_length, &reslt, &hslngth);
2836    switch (reslt) {
2837
2838    case valid:
2839      copytree();
2840
2841      p->length = local_length;
2842      p->haslength = true;
2843      if (p->back != NULL) {
2844     p->back->length = local_length;
2845     p->back->haslength = true;
2846      }
2847      break;
2848
2849    case remoov:
2850      copytree();
2851
2852      p->haslength = false;
2853      if (p->back != NULL)
2854     p->back->haslength = false;
2855      break;
2856
2857    case quit:
2858      /* blank case */
2859      break;
2860    }
2861  } else {
2862    printf("\n (this operation cannot be undone)\n");
2863    maxinput = 1;
2864    do {
2865      printf("\n   enter U to leave the lengths unchanged\n");
2866      printf("OR enter R to remove the lengths from all branches: \n");
2867#ifdef WIN32
2868      phyFillScreenColor();
2869#endif
2870      scanf("%c%*[^\n]", &ch);
2871      getchar();
2872      if (ch == '\n')
2873      ch = ' ';
2874      maxinput++;
2875      if (maxinput == 100) {
2876        printf("ERROR: too many tries at choosing option\n");
2877        exxit(-1);
2878      }
2879    } while (ch != 'U' && ch != 'u' && ch != 'R' && ch != 'r');
2880    if (ch == 'R' || ch == 'r') {
2881      copytree();
2882      for (i = 0; i < spp; i++)
2883     nodep[i]->haslength = false;
2884      for (i = spp; i < nonodes; i++) {
2885        if (nodep[i] != NULL) {
2886       nodep[i]->haslength = false;
2887       nodep[i]->next->haslength = false;
2888       nodep[i]->next->next->haslength = false;
2889        }
2890      }
2891    }
2892  }
2893  printree();
2894}  /* changelength */
2895
2896
2897void changename()
2898{
2899  /* change or specify the name of a tip */
2900  boolean ok;
2901  long i, n, tipno;
2902  char tipname[100];
2903
2904  for(;;) {
2905    for(;;) {
2906      printf("Specify name of which tip? (enter its number or 0 to quit): ");
2907      inpnum(&i, &ok);
2908      if (i > 0 && i <= spp && ok)
2909        if (!nodep[i - 1]->deleted) {
2910          tipno = i;
2911          break;
2912        }
2913      if (i == 0) {
2914        tipno = 0;
2915        break;
2916      }
2917    }
2918    if (tipno == 0)
2919      break;
2920    if (nodep[tipno - 1]->hasname) {
2921      n = 0;
2922
2923      /* this is valid because names are padded out to MAXNCH with nulls */
2924      for (i = 1; i <= MAXNCH; i++) {
2925     if (nodep[tipno - 1]->nayme[i - 1] != '\0')
2926       n = i;
2927      }
2928      printf("The current name of tip %ld is \"", tipno);
2929      for (i = 0; i < n; i++)
2930     putchar(nodep[tipno - 1]->nayme[i]);
2931      printf("\"\n");
2932    }
2933    copytree();
2934    for (i = 0; i < MAXNCH; i++)
2935      nodep[tipno - 1]->nayme[i] = ' ';
2936    printf("Enter new tip name: ");
2937    i = 1;
2938    getstryng(tipname);
2939    strncpy(nodep[tipno-1]->nayme,tipname,MAXNCH);
2940    nodep[tipno - 1]->hasname = true;
2941    printree();
2942  }
2943  printree();
2944}  /* changename */
2945
2946
2947void clade()
2948{
2949  /* pick a subtree and show only that on screen */
2950  long i;
2951  boolean ok;
2952
2953  printf("Select subtree rooted at which node (0 for whole tree)? ");
2954  inpnum(&i, &ok);
2955  ok = (ok && i>=0 && i<=nonodes);
2956  if (ok) {
2957    subtree = (i > 0);
2958    if (subtree)
2959      nuroot = nodep[i - 1];
2960    else
2961      nuroot = root;
2962  }
2963  printree();
2964  if (!ok)
2965    printf("Not possible to use this node. ");
2966}  /* clade */
2967
2968
2969void changeoutgroup()
2970{
2971  long i, maxinput;
2972  boolean ok;
2973
2974  maxinput = 1;
2975  do {
2976    printf("Which node should be the new outgroup? ");
2977    inpnum(&i, &ok);
2978    ok = (ok && i >= 1 && i <= nonodes && i != root->index);
2979    if (ok)
2980      ok = (ok && !nodep[i - 1]->deleted);
2981    if (ok)
2982      ok = !nodep[nodep[i - 1]->back->index - 1]->deleted;
2983    if (ok)
2984      outgrno = i;
2985    maxinput++;
2986    if (maxinput == 100) {
2987      printf("ERROR: too many tries at choosing option\n");
2988      exxit(-1);
2989    }
2990  } while (!ok);
2991  copytree();
2992  reroot(nodep[outgrno - 1]);
2993  printree();
2994  written = false;
2995}  /* changeoutgroup */
2996
2997
2998void redisplay()
2999{
3000  long maxinput;
3001  boolean done;
3002  char    ch;
3003
3004  done = false;
3005  maxinput = 1;
3006  do {
3007    printf("\nNEXT? (Options: R . ");
3008    if (haslengths)
3009      printf("= ");
3010    printf("U W O ");
3011    if (haslengths)
3012      printf("M ");
3013    printf("T F D B N H J K L C + ? X Q) (? for Help) ");
3014#ifdef WIN32
3015    phyFillScreenColor();
3016#endif
3017    scanf("%c%*[^\n]", &ch);
3018    getchar();
3019    if (ch == '\n')
3020      ch = ' ';
3021    ch = isupper(ch) ? ch : toupper(ch);
3022    if (ch == 'C' || ch == 'F' || ch == 'O' || ch == 'R' ||
3023      ch == 'U' || ch == 'X' || ch == 'Q' || ch == '.' ||
3024      ch == 'W' || ch == 'B' || ch == 'N' || ch == '?' ||
3025      ch == 'H' || ch == 'J' || ch == 'K' || ch == 'L' ||
3026      ch == '+' || ch == 'T' || ch == 'D' ||
3027      (haslengths && ch == 'M') ||
3028      (haslengths && ch == '=')) {
3029
3030      switch (ch) {
3031
3032        case 'R':
3033          rearrange();
3034          break;
3035
3036        case '.':
3037          printree();
3038          break;
3039
3040        case '=':
3041          togglelengths();
3042          break;
3043
3044        case 'U':
3045          undo();
3046          break;
3047
3048        case 'W':
3049          treewrite(&done);
3050          break;
3051
3052        case 'O':
3053          changeoutgroup();
3054          break;
3055
3056        case 'M':
3057          midpoint();
3058          break;
3059
3060        case 'T':
3061          transpose(0);
3062          break;
3063
3064        case 'F':
3065          flip(0);
3066          break;
3067
3068        case 'C':
3069          clade();
3070          break;
3071
3072        case 'D':
3073          del_or_restore();
3074          break;
3075
3076        case 'B':
3077          changelength();
3078          break;
3079
3080        case 'N':
3081          changename();
3082          break;
3083
3084        case 'H':
3085          retree_window(left);
3086          break;
3087
3088        case 'J':
3089          retree_window(downn);
3090          break;
3091
3092        case 'K':
3093          retree_window(upp);
3094          break;
3095
3096        case 'L':
3097          retree_window(right);
3098          break;
3099
3100        case '?':
3101          retree_help();
3102          break;
3103
3104        case '+':
3105          if (treesread <numtrees) {
3106            readnext = true;
3107            done = true;
3108          } else {
3109            printf("No more trees to read in input file.\n");
3110          }
3111          break;
3112
3113        case 'X':
3114          done = true;
3115          break;
3116
3117        case 'Q':
3118          done = true;
3119          break;
3120      }
3121    } else {
3122      printf("Not a possible option!\n");
3123      maxinput++;
3124      if (maxinput == 100) {
3125        printf("ERROR: too many tries at choosing option\n");
3126        exxit(-1);
3127      }
3128    }
3129  } while (!done);
3130  if (!written) {
3131    maxinput = 1;
3132    do {
3133      printf("Do you want to write out the tree to a file? (Y or N) ");
3134#ifdef WIN32
3135      phyFillScreenColor();
3136#endif
3137      scanf("%c%*[^\n]", &ch);
3138      getchar();
3139      if (ch == '\n')
3140        ch = ' ';
3141      if (ch == 'Y' || ch == 'y')
3142        treewrite(&done);
3143      maxinput++;
3144      if (maxinput == 100) {
3145        printf("ERROR: too many tries at choosing option\n");
3146        exxit(-1);
3147      }
3148    } while (ch != 'Y' && ch != 'y' && ch != 'N' && ch != 'n');
3149  }
3150}  /* redisplay */
3151
3152
3153void treeconstruct()
3154{
3155  /* constructs a tree from the pointers in nodep. */
3156
3157  waswritten = false;
3158  readnext = false;
3159  do {
3160    whichtree = 0;
3161    othertree = 1;
3162    treesets[whichtree].initialized = false;
3163    treesets[othertree].initialized = false;
3164/*xx    nodep = treesets[whichtree].nodep;   debug */
3165    root = treesets[whichtree].root;
3166    subtree = false;
3167    topedge = 1;
3168    leftedge = 1;
3169    buildtree();
3170    readnext = false;
3171    written = false;
3172    waswritten = false;
3173    printree();
3174    redisplay();
3175    if (readnext)
3176      unbuildtree();
3177  } while (readnext);
3178}  /* treeconstruct */
3179
3180
3181int main(int argc, Char *argv[])
3182{
3183  /* reads in spp. Then calls treeconstruct to                              *
3184     construct the tree and query the user                                  */
3185  int i;
3186
3187#ifdef MAC
3188  argc = 1;                /* macsetup("Retree","");        */
3189  argv[0] = "Retree";
3190#endif
3191  init(argc,argv);
3192/*  treesets[0].nodep = treeone;
3193  treesets[1].nodep = treetwo;*/
3194  nexus     = false;
3195  nolengths = false;
3196  grbg = NULL;
3197  scrollinc = 20;
3198  screenlines = 24;
3199  screenwidth = 80;
3200  vscreenwidth = 80;
3201  ibmpc = IBMCRT;
3202  ansi  = ANSICRT;
3203  for(i = 0; i < maxsz; i++)
3204    delarray[i] = false;
3205  treenumber = 1;
3206  getoptions();
3207  configure();
3208  treeconstruct();
3209  if (waswritten)
3210    FClose(outtree);
3211  FClose(intree);
3212  FClose(outtree);
3213#ifdef MAC
3214  fixmacfile(outtreename);
3215#endif
3216#ifdef WIN32
3217  phyRestoreConsoleAttributes();
3218#endif
3219  return 0;
3220}  /* Retree */
3221
Note: See TracBrowser for help on using the repository browser.