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

Last change on this file was 2175, checked in by westram, 20 years ago

upgrade to PHYLIP 3.6

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