2 /* version 3.6. (c) Copyright 1993-2004 by the University of Washington.
3 Written by Joseph Felsenstein, Akiko Fuseki, Sean Lamont, Andrew Keeffe,
5 Permission is granted to copy and use this program provided no fee is
6 charged for it and provided that this copyright notice is not removed. */
9 #include <Carbon/Carbon.h>
16 /* for console code (clear screen, text color settings) */
17 CONSOLE_SCREEN_BUFFER_INFO savecsbi;
18 HANDLE hConsoleOutput;
20 void phyClearScreen();
21 void phySaveConsoleAttributes();
22 void phySetConsoleAttributes();
23 void phyRestoreConsoleAttributes();
24 void phyFillScreenColor();
30 static void crash_handler(int signum);
33 #if defined(OSX_CARBON) && defined(__MWERKS__)
34 boolean fixedpath = false;
36 FILE *infile, *outfile, *intree, *intree2, *outtree, *weightfile, *catfile, *ancfile, *mixfile, *factfile;
37 long spp, words, bits;
38 boolean ibmpc, ansi, tranvsp;
39 naym *nayme; /* names of species */
41 static void crash_handler(int sig_num)
42 { /* when we crash, lets print out something usefull */
47 puts("This program has caused a Segmentation fault.");
52 puts("This program has caused a Floating Point Exception");
57 puts("This program has attempted an illegal instruction");
62 puts("This program tried to write to a broken pipe");
67 puts("This program had a bus error");
71 if (sig_num == SIGSEGV) {
73 " This may have been caused by an incorrectly formatted input file");
75 " or input tree file. You should check those files carefully.");
76 puts(" If this seems to be a bug, please mail joe@gs.washington.edu");
79 puts(" Most likely, you have encountered a bug in the program.");
80 puts(" Since this seems to be a bug, please mail joe@gs.washington.edu");
82 puts(" with the name of the program, your computer system type,");
83 puts(" a full description of the problem, and with the input data file.");
84 puts(" (which should be in the body of the message, not as an Attachment).");
87 puts ("Press Enter or Return to close program.");
88 puts(" You may have to press Enter or Return twice.");
91 phyRestoreConsoleAttributes();
97 void init(int argc, char** argv)
98 { /* initialization routine for all programs
99 * anything done at the beginig for every program should be done here */
101 /* set up signal handler for
102 * segfault,floating point exception, illeagal instruction, bad pipe, bus error
103 * there are more signals that can cause a crash, but these are the most common
104 * even these aren't found on all machines. */
106 signal(SIGSEGV, crash_handler);
109 signal(SIGFPE, crash_handler);
112 signal(SIGILL, crash_handler);
115 signal(SIGPIPE, crash_handler);
118 signal(SIGBUS, crash_handler);
122 phySetConsoleAttributes();
128 void scan_eoln(FILE *f)
129 { /* eat everything to the end of line or eof*/
132 while (!eoff(f) && !eoln(f))
139 boolean eoff(FILE *f)
140 { /* check for end of file */
155 boolean eoln(FILE *f)
156 { /* check for end of line or eof*/
163 return ((ch == '\n') || (ch == '\r'));
167 int filexists(char *filename)
168 { /* check whether file already exists */
170 fp =fopen(filename,"rb");
179 const char* get_command_name (const char *vektor)
180 { /* returns the name of the program from vektor without the whole path */
183 /* Point to the last slash... */
184 last_slash = strrchr (vektor, DELIMITER);
187 /* If there was a last slash, return the character after it */
188 return last_slash + 1;
190 /* If not, return the vector */
193 } /*get_command_name*/
196 void getstryng(char *fname)
197 { /* read in a file name from stdin and take off newline if any */
199 fname = fgets(fname, 100, stdin);
200 if (strchr(fname, '\n') != NULL)
201 *strchr(fname, '\n') = '\0';
205 void countup(long *loopcount, long maxcount)
206 { /* count how many times this loop has tried to read data, bail out
207 if exceeds maxcount */
210 if ((*loopcount) >= maxcount) {
211 printf("\nERROR: Made %ld attempts to read input in loop. Aborting run.\n",
218 void openfile(FILE **fp,const char *filename,const char *filedesc,
219 const char *mode,const char *application, char *perm)
220 { /* open a file, testing whether it exists etc. */
224 char input[FNMLNGTH];
226 const char *progname_without_path;
227 long loopcount, loopcount2;
228 #if defined(OSX_CARBON) && defined(__MWERKS__)
229 ProcessSerialNumber myProcess;
230 FSRef bundleLocation;
231 unsigned char bundlePath[FNMLNGTH];
234 /* change path to the bundle location instead of root directory */
235 GetCurrentProcess(&myProcess);
236 GetProcessBundleLocation(&myProcess, &bundleLocation);
237 FSRefMakePath(&bundleLocation, bundlePath, FNMLNGTH);
238 chdir((const char*)bundlePath);
239 chdir(".."); /* get out of the .app directory */
245 progname_without_path = get_command_name(application);
247 strcpy(file,filename);
248 strcpy(filemode,mode);
249 strcat(filemode,"b");
252 if (filemode[0] == 'w' && filexists(file)){
253 printf("\n%s: the file \"%s\" that you wanted to\n",
254 progname_without_path, file);
255 printf(" use as %s already exists.\n", filedesc);
256 printf(" Do you want to Replace it, Append to it,\n");
257 printf(" write to a new File, or Quit?\n");
260 printf(" (please type R, A, F, or Q) \n");
262 phyFillScreenColor();
264 fgets(input, sizeof(input), stdin);
267 countup(&loopcount2, 10);
268 } while (ch != 'A' && ch != 'R' && ch != 'F' && ch != 'Q');
272 strcpy(filemode,"ab");
275 else if (ch == 'F') {
278 while (file[0] =='\0') {
279 printf("Please enter a new file name> ");
281 countup(&loopcount2, 10);
283 strcpy(filemode,"wb");
287 of = fopen(file,filemode);
291 switch (filemode[0]){
294 printf("%s: can't find %s \"%s\"\n", progname_without_path,
298 while (file[0] =='\0'){
299 printf("Please enter a new file name> ");
300 countup(&loopcount2, 10);
306 printf("%s: can't write %s \"%s\"\n", progname_without_path,
310 while (file[0] =='\0'){
311 printf("Please enter a new file name> ");
312 countup(&loopcount2, 10);
316 printf("There is some error in the call of openfile. Unknown mode.\n");
320 countup(&loopcount, 20);
329 { /* home cursor and clear screen, if possible */
337 printf("%s", ((ibmpc || ansi) ? ("\033[2J\033[H") : "\n\n"));
342 double randum(longer seed)
343 { /* random number generator -- slow but machine independent
344 This is a multiplicative congruential 32-bit generator
345 x(t+1) = 1664525 * x(t) mod 2^32, one that passes the
346 Coveyou-Macpherson and Lehmer tests, see Knuth ACP vol. 2
347 We here implement it representing each integer in base-64
348 notation -- i.e. as an array of 6 six-bit chunks */
350 longer mult, newseed;
353 mult[0] = 13; /* these four statements set the multiplier */
354 mult[1] = 24; /* -- they are its "digits" in a base-64 */
355 mult[2] = 22; /* notation: 1664525 = 13*64^3+24*64^2 */
356 mult[3] = 6; /* +22*64+6 */
357 for (i = 0; i <= 5; i++)
359 for (i = 0; i <= 5; i++) {
364 for (j = 0; j <= k; j++)
365 sum += mult[j] * seed[i - j];
367 for (j = i; j <= 4; j++) {
368 newseed[j + 1] += newseed[j] / 64;
372 memcpy(seed, newseed, sizeof(longer));
375 for (i = 0; i <= 5; i++)
376 x = x / 64.0 + seed[i];
382 void randumize(longer seed, long *enterorder)
383 { /* randomize input order of species */
386 for (i = 0; i < spp; i++) {
387 j = (long)(randum(seed) * (i+1));
389 enterorder[j] = enterorder[i];
395 double normrand(longer seed)
396 {/* standardized Normal random variate */
399 x = randum(seed)+randum(seed)+randum(seed)+randum(seed)
400 + randum(seed)+randum(seed)+randum(seed)+randum(seed)
401 + randum(seed)+randum(seed)+randum(seed)+randum(seed)-6.0;
406 long readlong(const char *prompt)
415 if (sscanf(string,"%ld",&res) == 1)
417 countup(&loopcount, 10);
423 void uppercase(Char *ch)
424 { /* convert ch to upper case */
425 *ch = (islower (*ch) ? toupper(*ch) : (*ch));
429 void initseed(long *inseed, long *inseed0, longer seed)
430 { /* input random number seed */
435 printf("Random number seed (must be odd)?\n");
436 scanf("%ld%*[^\n]", inseed);
438 countup(&loopcount, 10);
439 } while (((*inseed) < 0) || ((*inseed) & 1) == 0);
441 for (i = 0; i <= 5; i++)
445 seed[i] = *inseed & 63;
448 } while (*inseed != 0);
452 void initjumble(long *inseed, long *inseed0, longer seed, long *njumble)
453 { /* input number of jumblings for jumble option */
456 initseed(inseed, inseed0, seed);
459 printf("Number of times to jumble?\n");
460 scanf("%ld%*[^\n]", njumble);
462 countup(&loopcount, 10);
463 } while ((*njumble) < 1);
467 void initoutgroup(long *outgrno, long spp)
468 { /* input outgroup number */
474 printf("Type number of the outgroup:\n");
475 scanf("%ld%*[^\n]", outgrno);
477 done = (*outgrno >= 1 && *outgrno <= spp);
479 printf("BAD OUTGROUP NUMBER: %ld\n", *outgrno);
480 printf(" Must be in range 1 - %ld\n", spp);
482 countup(&loopcount, 10);
483 } while (done != true);
487 void initthreshold(double *threshold)
488 { /* input threshold for threshold parsimony option */
494 printf("What will be the threshold value?\n");
495 scanf("%lf%*[^\n]", threshold);
497 done = (*threshold >= 1.0);
499 printf("BAD THRESHOLD VALUE: it must be greater than 1\n");
501 *threshold = (long)(*threshold * 10.0 + 0.5) / 10.0;
502 countup(&loopcount, 10);
503 } while (done != true);
507 void initcatn(long *categs)
508 { /* initialize category number for rate categories */
514 printf("Number of categories (1-%d)?\n", maxcategs);
515 scanf("%ld%*[^\n]", categs);
517 countup(&loopcount, 10);
518 } while (*categs > maxcategs || *categs < 1);
522 void initcategs(long categs, double *rate)
523 { /* initialize category rates for HMM rates */
524 long i, loopcount, scanned;
525 char line[100], rest[100];
530 printf("Rate for each category? (use a space to separate)\n");
533 for (i = 0; i < categs; i++){
534 scanned = sscanf(line,"%lf %[^\n]", &rate[i],rest);
535 if ((scanned < 2 && i < (categs - 1)) ||
536 (scanned < 1 && i == (categs - 1))){
537 printf("Please enter exactly %ld values.\n",categs);
545 countup(&loopcount, 100);
550 void initprobcat(long categs, double *probsum, double *probcat)
551 { /* input probabilities of rate categores for HMM rates */
552 long i, loopcount, scanned;
554 char line[100], rest[100];
558 printf("Probability for each category?");
559 printf(" (use a space to separate)\n");
562 for (i = 0; i < categs; i++){
563 scanned = sscanf(line,"%lf %[^\n]",&probcat[i],rest);
564 if ((scanned < 2 && i < (categs - 1)) ||
565 (scanned < 1 && i == (categs - 1))){
567 printf("Please enter exactly %ld values.\n",categs);
574 for (i = 0; i < categs; i++)
575 *probsum += probcat[i];
576 if (fabs(1.0 - (*probsum)) > 0.001) {
578 printf("Probabilities must add up to");
579 printf(" 1.0, plus or minus 0.001.\n");
581 countup(&loopcount, 100);
586 void lgr(long m, double b, raterootarray lgroot)
587 { /* For use by initgammacat. Get roots of m-th Generalized Laguerre
588 polynomial, given roots of (m-1)-th, these are to be
589 stored in lgroot[m][] */
591 double upper, lower, x, y;
592 boolean dwn; /* is function declining in this interval? */
595 lgroot[1][1] = 1.0+b;
598 for (i=1; i<=m; i++) {
603 lower = lgroot[m-1][i-1];
604 upper = lgroot[m-1][i];
605 } else { /* i == m, must search above */
606 lower = lgroot[m-1][i-1];
607 x = lgroot[m-1][m-1];
610 y = glaguerre(m, b,x);
611 } while ((dwn && (y > 0.0)) || ((!dwn) && (y < 0.0)));
614 while (upper-lower > 0.000000001) {
615 x = (upper+lower)/2.0;
616 if (glaguerre(m, b, x) > 0.0) {
628 lgroot[m][i] = (lower+upper)/2.0;
629 dwn = !dwn; /* switch for next one */
635 double logfac (long n)
636 { /* log(n!) values were calculated with Mathematica
637 with a precision of 30 digits */
648 return 0.693147180559945309417232121458;
650 return 1.791759469228055000812477358381;
652 return 3.1780538303479456196469416013;
654 return 4.78749174278204599424770093452;
656 return 6.5792512120101009950601782929;
658 return 8.52516136106541430016553103635;
660 return 10.60460290274525022841722740072;
662 return 12.80182748008146961120771787457;
664 return 15.10441257307551529522570932925;
666 return 17.50230784587388583928765290722;
668 return 19.98721449566188614951736238706;
670 x = 19.98721449566188614951736238706;
671 for (i = 13; i <= n; i++)
678 double glaguerre(long m, double b, double x)
679 { /* Generalized Laguerre polynomial computed recursively.
680 For use by initgammacat */
682 double gln, glnm1, glnp1; /* L_n, L_(n-1), L_(n+1) */
692 for (i=2; i <= m; i++) {
693 glnp1 = ((2*(i-1)+b+1.0-x)*gln - (i-1+b)*glnm1)/i;
703 void initlaguerrecat(long categs, double alpha, double *rate, double *probcat)
704 { /* calculate rates and probabilities to approximate Gamma distribution
705 of rates with "categs" categories and shape parameter "alpha" using
706 rates and weights from Generalized Laguerre quadrature */
708 raterootarray lgroot; /* roots of GLaguerre polynomials */
712 lgroot[1][1] = 1.0+alpha;
713 for (i = 2; i <= categs; i++)
714 lgr(i, alpha, lgroot); /* get roots for L^(a)_n */
715 /* here get weights */
716 /* Gamma weights are (1+a)(1+a/2) ... (1+a/n)*x_i/((n+1)^2 [L_{n+1}^a(x_i)]^2) */
718 for (i = 1; i <= categs; i++)
720 for (i = 1; i <= categs; i++) {
721 xi = lgroot[categs][i];
722 y = glaguerre(categs+1, alpha, xi);
723 x = f*xi/((categs+1)*(categs+1)*y*y);
724 rate[i-1] = xi/(1.0+alpha);
727 } /* initlaguerrecat */
730 double hermite(long n, double x)
731 { /* calculates hermite polynomial with degree n and parameter x */
732 /* seems to be unprecise for n>13 -> root finder does not converge*/
738 for (i = 1; i < n; i++) {
739 xx = 2. * x * h2 - 2. * (i) * h1;
747 void root_hermite(long n, double *hroot)
748 { /* find roots of Hermite polynmials */
759 hroot[start-1] = 0.0;
761 for (ii = start; ii < n; ii++) { /* search only upwards*/
762 hroot[ii] = halfroot(hermite,n,hroot[ii-1]+EPSILON, 1./n);
763 hroot[start - z] = -hroot[ii];
769 double halfroot(double (*func)(long m, double x), long n, double startx,
771 { /* searches from the bound (startx) only in one direction
772 (by positive or negative delta, which results in
773 other-bound=startx+delta)
774 delta should be small.
775 (*func) is a function with two arguments */
785 /* decide if we search above or below startx and escapes to trace back
786 to the starting point that most often will be
787 the root from the previous calculation */
798 gradient = (fl-fu)/(xl-xu);
799 while(fabs(fm) > EPSILON) { /* is root outside of our bracket?*/
800 if ((fu<0.0 && fl<0.0) || (fu>0.0 && fl > 0.0)) {
804 gradient = (fl-fu)/(xl-xu);
805 dwn = (gradient < 0.0) ? true : false;
807 xm = xl - fl / gradient;
826 gradient = (fl-fu)/(xl-xu);
833 void hermite_weight(long n, double * hroot, double * weights)
835 /* calculate the weights for the hermite polynomial at the roots
836 using formula from Abramowitz and Stegun chapter 25.4.46 p.890 */
841 numerator = exp(0.6931471805599 * ( n-1.) + logfac(n)) / (n*n);
842 for (i = 0; i < n; i++) {
843 hr2 = hermite(n-1, hroot[i]);
844 weights[i] = numerator / (hr2*hr2);
846 } /* hermiteweight */
849 void inithermitcat(long categs, double alpha, double *rate, double *probcat)
850 { /* calculates rates and probabilities */
855 std = SQRT2 /sqrt(alpha);
856 hroot = (double *) Malloc((categs+1) * sizeof(double));
857 root_hermite(categs, hroot); /* calculate roots */
858 hermite_weight(categs, hroot, probcat); /* set weights */
859 for (i=0; i<categs; i++) { /* set rates */
860 rate[i] = 1.0 + std * hroot[i];
861 probcat[i] = probcat[i];
864 } /* inithermitcat */
867 void initgammacat (long categs, double alpha, double *rate, double *probcat)
868 { /* calculate rates and probabilities to approximate Gamma distribution
869 of rates with "categs" categories and shape parameter "alpha" using
870 rates and weights from Generalized Laguerre quadrature or from
871 Hermite quadrature */
874 inithermitcat(categs, alpha, rate, probcat);
876 initlaguerrecat(categs, alpha, rate, probcat);
880 void inithowmany(long *howmanny, long howoften)
881 {/* input how many cycles */
886 printf("How many cycles of %4ld trees?\n", howoften);
887 scanf("%ld%*[^\n]", howmanny);
889 countup(&loopcount, 10);
890 } while (*howmanny <= 0);
895 void inithowoften(long *howoften)
896 { /* input how many trees per cycle */
901 printf("How many trees per cycle?\n");
902 scanf("%ld%*[^\n]", howoften);
904 countup(&loopcount, 10);
905 } while (*howoften <= 0);
909 void initlambda(double *lambda)
910 { /* input patch length parameter for autocorrelated HMM rates */
915 printf("Mean block length of sites having the same rate (greater than 1)?\n");
916 scanf("%lf%*[^\n]", lambda);
918 countup(&loopcount, 10);
919 } while (*lambda <= 1.0);
920 *lambda = 1.0 / *lambda;
924 void initfreqs(double *freqa, double *freqc, double *freqg, double *freqt)
925 { /* input frequencies of the four bases */
927 long scanned, loopcount;
929 printf("Base frequencies for A, C, G, T/U (use blanks to separate)?\n");
933 scanned = sscanf(input,"%lf%lf%lf%lf%*[^\n]", freqa, freqc, freqg, freqt);
937 printf("Please enter exactly 4 values.\n");
938 countup(&loopcount, 100);
943 void initratio(double *ttratio)
944 { /* input transition/transversion ratio */
949 printf("Transition/transversion ratio?\n");
950 scanf("%lf%*[^\n]", ttratio);
952 countup(&loopcount, 10);
953 } while (*ttratio < 0.0);
957 void initpower(double *power)
959 printf("New power?\n");
960 scanf("%lf%*[^\n]", power);
965 void initdatasets(long *datasets)
967 /* handle multi-data set option */
973 printf("How many data sets?\n");
974 scanf("%ld%*[^\n]", datasets);
976 done = (*datasets > 1);
978 printf("Bad data sets number: it must be greater than 1\n");
979 countup(&loopcount, 10);
984 void justweights(long *datasets)
986 /* handle multi-data set option by weights */
992 printf("How many sets of weights?\n");
993 scanf("%ld%*[^\n]", datasets);
995 done = (*datasets >= 1);
997 printf("BAD NUMBER: it must be greater than 1\n");
998 countup(&loopcount, 10);
1003 void initterminal(boolean *ibmpc, boolean *ansi)
1005 /* handle terminal option */
1016 void initnumlines(long *screenlines)
1022 *screenlines = readlong("Number of lines on screen?\n");
1023 countup(&loopcount, 10);
1024 } while (*screenlines <= 12);
1028 void initbestrees(bestelm *bestrees, long maxtrees, boolean glob)
1030 /* initializes either global or local field of each array in bestrees */
1034 for (i = 0; i < maxtrees; i++)
1035 bestrees[i].gloreange = false;
1037 for (i = 0; i < maxtrees; i++)
1038 bestrees[i].locreange = false;
1039 } /* initbestrees */
1042 void newline(FILE *filename, long i, long j, long k)
1044 /* go to new line if i is a multiple of j, indent k spaces */
1047 if ((i - 1) % j != 0 || i <= 1)
1049 putc('\n', filename);
1050 for (m = 1; m <= k; m++)
1051 putc(' ', filename);
1055 void inputnumbersold(long *spp, long *chars, long *nonodes, long n)
1057 /* input the numbers of species and of characters */
1059 if (fscanf(infile, "%ld%ld", spp, chars) != 2 || *spp <= 0 || *chars <= 0) {
1061 "ERROR: Unable to read the number of species or characters in data set\n");
1063 "The input file is incorrect (perhaps it was not saved text only).\n");
1065 *nonodes = *spp * 2 - n;
1066 } /* inputnumbersold */
1069 void inputnumbers(long *spp, long *chars, long *nonodes, long n)
1071 /* input the numbers of species and of characters */
1073 if (fscanf(infile, "%ld%ld", spp, chars) != 2 || *spp <= 0 || *chars <= 0) {
1075 "ERROR: Unable to read the number of species or characters in data set\n");
1077 "The input file is incorrect (perhaps it was not saved text only).\n");
1079 *nonodes = *spp * 2 - n;
1080 } /* inputnumbers */
1083 void inputnumbers2(long *spp, long *nonodes, long n)
1085 /* read species number */
1087 if (fscanf(infile, "%ld", spp) != 1 || *spp <= 0) {
1088 printf("ERROR: Unable to read the number of species in data set\n");
1090 "The input file is incorrect (perhaps it was not saved text only).\n");
1092 fprintf(outfile, "\n%4ld Populations\n", *spp);
1093 *nonodes = *spp * 2 - n;
1094 } /* inputnumbers2 */
1097 void inputnumbers3(long *spp, long *chars)
1099 /* input the numbers of species and of characters */
1101 if (fscanf(infile, "%ld%ld", spp, chars) != 2 || *spp <= 0 || *chars <= 0) {
1103 "ERROR: Unable to read the number of species or characters in data set\n");
1105 "The input file is incorrect (perhaps it was not saved text only).\n");
1108 } /* inputnumbers3 */
1111 void samenumsp(long *chars, long ith)
1113 /* check if spp is same as the first set in other data sets */
1118 fscanf(infile, "%ld%ld", &cursp, &curchs);
1121 "\n\nERROR: Inconsistent number of species in data set %ld\n\n", ith);
1128 void samenumsp2(long ith)
1130 /* check if spp is same as the first set in other data sets */
1135 if (fscanf(infile, "%ld", &cursp) != 1) {
1136 printf("\n\nERROR: Unable to read number of species in data set %ld\n",
1139 "The input file is incorrect (perhaps it was not saved text only).\n");
1144 "\n\nERROR: Inconsistent number of species in data set %ld\n\n", ith);
1150 void readoptions(long *extranum, const char *options)
1151 { /* read option characters from input file */
1154 while (!(eoln(infile))) {
1157 if (strchr(options, ch) != NULL)
1159 else if (!(ch == ' ' || ch == '\t')) {
1160 printf("BAD OPTION CHARACTER: %c\n", ch);
1168 void matchoptions(Char *ch, const char *options)
1169 { /* match option characters to those in auxiliary options line */
1171 *ch = gettc(infile);
1173 if (strchr(options, *ch) == NULL) {
1174 printf("ERROR: Incorrect auxiliary options line");
1175 printf(" which starts with %c\n", *ch);
1178 } /* matchoptions */
1181 void inputweightsold(long chars, steptr weight, boolean *weights)
1186 for (i = 1; i < nmlngth ; i++)
1189 for (i = 0; i < chars; i++) {
1196 } while (ch == ' ');
1199 weight[i] = ch - '0';
1200 else if (isalpha(ch)) {
1202 weight[i] = ch - 'A' + 10;
1204 printf("\n\nERROR: Bad weight character: %c\n\n", ch);
1210 } /*inputweightsold*/
1213 void inputweights(long chars, steptr weight, boolean *weights)
1215 /* input the character weights, 0-9 and A-Z for weights 0 - 35 */
1219 for (i = 0; i < chars; i++) {
1221 if (eoln(weightfile))
1222 scan_eoln(weightfile);
1223 ch = gettc(weightfile);
1226 } while (ch == ' ');
1229 weight[i] = ch - '0';
1230 else if (isalpha(ch)) {
1232 weight[i] = ch - 'A' + 10;
1234 printf("\n\nERROR: Bad weight character: %c\n\n", ch);
1238 scan_eoln(weightfile);
1240 } /* inputweights */
1243 void inputweights2(long a, long b, long *weightsum,
1244 steptr weight, boolean *weights, const char *prog)
1246 /* input the character weights, 0 or 1 */
1251 for (i = a; i < b; i++) {
1253 if (eoln(weightfile))
1254 scan_eoln(weightfile);
1255 ch = gettc(weightfile);
1256 } while (ch == ' ');
1258 if (ch == '0' || ch == '1')
1259 weight[i] = ch - '0';
1261 printf("\n\nERROR: Bad weight character: %c -- ", ch);
1262 printf("weights in %s must be 0 or 1\n", prog);
1265 *weightsum += weight[i];
1268 scan_eoln(weightfile);
1269 } /* inputweights2 */
1272 void printweights(FILE *filename, long inc, long chars,
1273 steptr weight, const char *letters)
1275 /* print out the weights of sites */
1277 boolean letterweights;
1279 letterweights = false;
1280 for (i = 0; i < chars; i++)
1282 letterweights = true;
1283 fprintf(filename, "\n %s are weighted as follows:",letters);
1285 fprintf(filename, " (A = 10, B = 11, etc.)\n");
1287 putc('\n', filename);
1288 for (i = 0; i < chars; i++) {
1290 putc('\n', filename);
1291 for (j = 1; j <= nmlngth + 3; j++)
1292 putc(' ', filename);
1294 if (weight[i+inc] < 10)
1295 fprintf(filename, "%ld", weight[i + inc]);
1297 fprintf(filename, "%c", 'A'-10+(int)weight[i + inc]);
1298 if ((i+1) % 5 == 0 && (i+1) % 60 != 0)
1299 putc(' ', filename);
1301 fprintf(filename, "\n\n");
1302 } /* printweights */
1305 void inputcategs(long a, long b, steptr category, long categs,const char *prog)
1307 /* input the categories, 1-9 */
1311 for (i = a; i < b; i++) {
1315 ch = gettc(catfile);
1316 } while (ch == ' ');
1317 if ((ch >= '1') && (ch <= ('0'+categs)))
1318 category[i] = ch - '0';
1320 printf("\n\nERROR: Bad category character: %c", ch);
1321 printf(" -- categories in %s are currently 1-%ld\n", prog, categs);
1329 void printcategs(FILE *filename, long chars, steptr category,
1330 const char *letters)
1332 /* print out the sitewise categories */
1335 fprintf(filename, "\n %s are:\n",letters);
1336 for (i = 0; i < chars; i++) {
1338 putc('\n', filename);
1339 for (j = 1; j <= nmlngth + 3; j++)
1340 putc(' ', filename);
1342 fprintf(filename, "%ld", category[i]);
1343 if ((i+1) % 10 == 0 && (i+1) % 60 != 0)
1344 putc(' ', filename);
1346 fprintf(filename, "\n\n");
1350 void inputfactors(long chars, Char *factor, boolean *factors)
1352 /* reads the factor symbols */
1355 for (i = 0; i < (chars); i++) {
1357 scan_eoln(factfile);
1358 factor[i] = gettc(factfile);
1359 if (factor[i] == '\n')
1362 scan_eoln(factfile);
1364 } /* inputfactors */
1367 void printfactors(FILE *filename, long chars, Char *factor, const char *letters)
1369 /* print out list of factor symbols */
1372 fprintf(filename, "Factors%s:\n\n", letters);
1373 for (i = 1; i <= nmlngth - 5; i++)
1374 putc(' ', filename);
1375 for (i = 1; i <= (chars); i++) {
1376 newline(filename, i, 55, nmlngth + 3);
1377 putc(factor[i - 1], filename);
1379 putc(' ', filename);
1381 putc('\n', filename);
1382 } /* printfactors */
1385 void headings(long chars, const char *letters1, const char *letters2)
1389 putc('\n', outfile);
1390 j = nmlngth + (chars + (chars - 1) / 10) / 2 - 5;
1391 if (j < nmlngth - 1)
1395 fprintf(outfile, "Name");
1396 for (i = 1; i <= j; i++)
1398 fprintf(outfile, "%s\n", letters1);
1399 fprintf(outfile, "----");
1400 for (i = 1; i <= j; i++)
1402 fprintf(outfile, "%s\n\n", letters2);
1406 void initname(long i)
1408 /* read in species name */
1411 for (j = 0; j < nmlngth; j++) {
1412 if (eoff(infile) | eoln(infile)){
1413 printf("\n\nERROR: end-of-line or end-of-file");
1414 printf(" in the middle of species name for species %ld\n\n", i+1);
1417 nayme[i][j] = gettc(infile);
1418 if ((nayme[i][j] == '(') || (nayme[i][j] == ')') || (nayme[i][j] == ':')
1419 || (nayme[i][j] == ',') || (nayme[i][j] == ';') || (nayme[i][j] == '[')
1420 || (nayme[i][j] == ']')) {
1421 printf("\nERROR: Species name may not contain characters ( ) : ; , [ ] \n");
1422 printf(" In name of species number %ld there is character %c\n\n",
1430 void findtree(boolean *found,long *pos,long nextree,long *place,bestelm *bestrees)
1432 /* finds tree given by array place in array bestrees by binary search */
1433 /* used by dnacomp, dnapars, dollop, mix, & protpars */
1434 long i, lower, upper;
1435 boolean below, done;
1439 upper = nextree - 1;
1441 while (!(*found) && lower <= upper) {
1442 (*pos) = (lower + upper) / 2;
1448 done = (place[i - 1] != bestrees[(*pos) - 1].btree[i - 1]);
1452 (*found) = (i > spp);
1455 below = (place[i - 1] < bestrees[(*pos )- 1].btree[i - 1]);
1461 if (!(*found) && !below)
1466 void addtree(long pos,long *nextree,boolean collapse,long *place,bestelm *bestrees)
1468 /* puts tree from array place in its proper position in array bestrees */
1469 /* used by dnacomp, dnapars, dollop, mix, & protpars */
1472 for (i = *nextree - 1; i >= pos; i--){
1473 memcpy(bestrees[i].btree, bestrees[i - 1].btree, spp * sizeof(long));
1474 bestrees[i].gloreange = bestrees[i - 1].gloreange;
1475 bestrees[i - 1].gloreange = false;
1476 bestrees[i].locreange = bestrees[i - 1].locreange;
1477 bestrees[i - 1].locreange = false;
1478 bestrees[i].collapse = bestrees[i - 1].collapse;
1480 for (i = 0; i < spp; i++)
1481 bestrees[pos - 1].btree[i] = place[i];
1482 bestrees[pos - 1].collapse = collapse;
1487 long findunrearranged(bestelm *bestrees, long nextree, boolean glob)
1489 /* finds bestree with either global or local field false */
1493 for (i = 0; i < nextree - 1; i++)
1494 if (!bestrees[i].gloreange)
1497 for (i = 0; i < nextree - 1; i++)
1498 if (!bestrees[i].locreange)
1502 } /* findunrearranged */
1505 boolean torearrange(bestelm *bestrees, long nextree)
1506 { /* sees if any best tree is yet to be rearranged */
1508 if (findunrearranged(bestrees, nextree, true) >= 0)
1510 else if (findunrearranged(bestrees, nextree, false) >= 0)
1517 void reducebestrees(bestelm *bestrees, long *nextree)
1519 /* finds best trees with collapsible branches and deletes them */
1525 while (!bestrees[i].collapse && i < *nextree - 1) i++;
1526 while (bestrees[j].collapse && j >= 0) j--;
1528 memcpy(bestrees[i].btree, bestrees[j].btree, spp * sizeof(long));
1529 bestrees[i].gloreange = bestrees[j].gloreange;
1530 bestrees[i].locreange = bestrees[j].locreange;
1531 bestrees[i].collapse = false;
1532 bestrees[j].collapse = true;
1536 } /* reducebestrees */
1539 void shellsort(double *a, long *b, long n)
1540 { /* Shell sort keeping a, b in same order */
1541 /* used by dnapenny, dolpenny, & penny */
1542 long gap, i, j, itemp;
1547 for (i = gap + 1; i <= n; i++) {
1550 if (a[j - 1] > a[j + gap - 1]) {
1552 a[j - 1] = a[j + gap - 1];
1553 a[j + gap - 1] = rtemp;
1555 b[j - 1] = b[j + gap - 1];
1556 b[j + gap - 1] = itemp;
1566 void getch(Char *c, long *parens, FILE *treefile)
1567 { /* get next nonblank character */
1571 scan_eoln(treefile);
1572 (*c) = gettc(treefile);
1574 if ((*c) == '\n' || (*c) == '\t')
1576 } while ( *c == ' ' && !eoff(treefile) );
1584 void getch2(Char *c, long *parens)
1585 { /* get next nonblank character */
1590 if (*c == '\n' || *c == '\t')
1592 } while (!(*c != ' ' || eoff(intree)));
1600 void findch(Char c, Char *ch, long which)
1601 { /* scan forward until find character c */
1607 if (*ch == '(' || *ch == ')' || *ch == ';') {
1609 "\n\nERROR in user tree %ld: unmatched parenthesis or missing comma\n\n",
1612 } else if (*ch == ',')
1614 } else if (c == ')') {
1615 if (*ch == '(' || *ch == ',' || *ch == ';') {
1616 printf("\n\nERROR in user tree %ld: ", which);
1617 printf("unmatched parenthesis or non-bifurcated node\n\n");
1623 } else if (c == ';') {
1625 printf("\n\nERROR in user tree %ld: ", which);
1626 printf("unmatched parenthesis or missing semicolon\n\n");
1631 if (*ch != ')' && done)
1633 getch(ch, &dummy_parens, intree);
1638 void findch2(Char c, long *lparens, long *rparens, Char *ch)
1639 { /* skip forward in user tree until find character c */
1645 if (*ch == '(' || *ch == ')' || *ch == ':' || *ch == ';') {
1646 printf("\n\nERROR in user tree: ");
1647 printf("unmatched parenthesis, missing comma");
1648 printf(" or non-trifurcated base\n\n");
1650 } else if (*ch == ',')
1652 } else if (c == ')') {
1653 if (*ch == '(' || *ch == ',' || *ch == ':' || *ch == ';') {
1655 "\n\nERROR in user tree: unmatched parenthesis or non-bifurcated node\n\n");
1657 } else if (*ch == ')') {
1659 if ((*lparens) > 0 && (*lparens) == (*rparens)) {
1660 if ((*lparens) == spp - 2) {
1661 getch(ch, &dummy_parens, intree);
1663 printf( "\n\nERROR in user tree: ");
1664 printf("unmatched parenthesis or missing semicolon\n\n");
1672 if (*ch != ')' && done)
1675 getch(ch, &dummy_parens, intree);
1680 void processlength(double *valyew, double *divisor, Char *ch,
1681 boolean *minusread, FILE *treefile, long *parens)
1682 { /* read a branch length from a treefile */
1683 long digit, ordzero;
1691 getch(ch, parens, treefile);
1692 digit = (long)(*ch - ordzero);
1693 while ( ((digit <= 9) && (digit >= 0)) || *ch == '.' || *ch == '-') {
1696 else if (*ch == '-' )
1699 *valyew = *valyew * 10.0 + digit;
1703 getch(ch, parens, treefile);
1704 digit = (long)(*ch - ordzero);
1707 *valyew = -(*valyew);
1708 } /* processlength */
1711 void writename(long start, long n, long *enterorder)
1712 { /* write species name and number in entry order */
1715 for (i = start; i < start+n; i++) {
1716 printf(" %3ld. ", i+1);
1717 for (j = 0; j < nmlngth; j++)
1718 putchar(nayme[enterorder[i] - 1][j]);
1727 printf("Error allocating memory\n");
1732 void odd_malloc(long x)
1733 { /* error message if attempt to malloc too little or too much memory */
1734 printf ("ERROR: a function asked for an inappropriate amount of memory:");
1735 printf (" %ld bytes\n", x);
1736 printf (" This can mean one of two things:\n");
1737 printf (" 1. The input file is incorrect");
1738 printf (" (perhaps it was not saved as Text Only),\n");
1739 printf (" 2. There is a bug in the program.\n");
1740 printf (" Please check your input file carefully.\n");
1741 printf (" If it seems to be a bug, please mail joe@gs.washington.edu\n");
1742 printf (" with the name of the program, your computer system type,\n");
1743 printf (" a full description of the problem, and with the input data file.\n");
1744 printf (" (which should be in the body of the message, not as an Attachment).\n");
1746 /* abort() can be used to crash */
1752 MALLOCRETURN *mymalloc(long x)
1753 { /* wrapper for malloc, allowing error message if too little, too much */
1754 MALLOCRETURN *new_block;
1757 (x > TOO_MUCH_MEMORY))
1760 new_block = (MALLOCRETURN *)calloc(1,x);
1764 return (MALLOCRETURN *) new_block;
1766 return (MALLOCRETURN *) new_block;
1770 void gnu(node **grbg, node **p)
1771 { /* this and the following are do-it-yourself garbage collectors.
1772 Make a new node or pull one off the garbage list */
1774 if (*grbg != NULL) {
1776 *grbg = (*grbg)->next;
1778 *p = (node *)Malloc(sizeof(node));
1783 (*p)->times_in_tree = 0.0;
1787 (*p)->protx = NULL; /* for the sake of proml */
1791 void chuck(node **grbg, node *p)
1792 { /* collect garbage on p -- put it on front of garbage list */
1799 void zeronumnuc(node *p, long endsite)
1803 for (i = 0; i < endsite; i++)
1804 for (j = (long)A; j <= (long)O; j++)
1805 p->numnuc[i][j] = 0;
1809 void zerodiscnumnuc(node *p, long endsite)
1813 for (i = 0; i < endsite; i++)
1814 for (j = (long)zero; j <= (long)seven; j++)
1815 p->discnumnuc[i][j] = 0;
1816 } /* zerodiscnumnuc */
1819 void allocnontip(node *p, long *zeros, long endsite)
1820 { /* allocate an interior node */
1821 /* used by dnacomp, dnapars, & dnapenny */
1823 p->numsteps = (steptr)Malloc(endsite*sizeof(long));
1824 p->oldnumsteps = (steptr)Malloc(endsite*sizeof(long));
1825 p->base = (baseptr)Malloc(endsite*sizeof(long));
1826 p->oldbase = (baseptr)Malloc(endsite*sizeof(long));
1827 p->numnuc = (nucarray *)Malloc(endsite*sizeof(nucarray));
1828 memcpy(p->base, zeros, endsite*sizeof(long));
1829 memcpy(p->numsteps, zeros, endsite*sizeof(long));
1830 memcpy(p->oldbase, zeros, endsite*sizeof(long));
1831 memcpy(p->oldnumsteps, zeros, endsite*sizeof(long));
1832 zeronumnuc(p, endsite);
1836 void allocdiscnontip(node *p, long *zeros, unsigned char *zeros2, long endsite)
1837 { /* allocate an interior node */
1840 p->numsteps = (steptr)Malloc(endsite*sizeof(long));
1841 p->oldnumsteps = (steptr)Malloc(endsite*sizeof(long));
1842 p->discbase = (discbaseptr)Malloc(endsite*sizeof(unsigned char));
1843 p->olddiscbase = (discbaseptr)Malloc(endsite*sizeof(unsigned char));
1844 p->discnumnuc = (discnucarray *)Malloc(endsite*sizeof(discnucarray));
1845 memcpy(p->discbase, zeros2, endsite*sizeof(unsigned char));
1846 memcpy(p->numsteps, zeros, endsite*sizeof(long));
1847 memcpy(p->olddiscbase, zeros2, endsite*sizeof(unsigned char));
1848 memcpy(p->oldnumsteps, zeros, endsite*sizeof(long));
1849 zerodiscnumnuc(p, endsite);
1850 } /* allocdiscnontip */
1853 void allocnode(node **anode, long *zeros, long endsite)
1854 { /* allocate a node */
1855 /* used by dnacomp, dnapars, & dnapenny */
1857 *anode = (node *)Malloc(sizeof(node));
1858 allocnontip(*anode, zeros, endsite);
1862 void allocdiscnode(node **anode, long *zeros, unsigned char *zeros2,
1864 { /* allocate a node */
1867 *anode = (node *)Malloc(sizeof(node));
1868 allocdiscnontip(*anode, zeros, zeros2, endsite);
1869 } /* allocdiscnontip */
1872 void gnutreenode(node **grbg, node **p, long i, long endsite, long *zeros)
1873 { /* this and the following are do-it-yourself garbage collectors.
1874 Make a new node or pull one off the garbage list */
1876 if (*grbg != NULL) {
1878 *grbg = (*grbg)->next;
1879 memcpy((*p)->numsteps, zeros, endsite*sizeof(long));
1880 memcpy((*p)->oldnumsteps, zeros, endsite*sizeof(long));
1881 memcpy((*p)->base, zeros, endsite*sizeof(long));
1882 memcpy((*p)->oldbase, zeros, endsite*sizeof(long));
1883 zeronumnuc(*p, endsite);
1885 allocnode(p, zeros, endsite);
1889 (*p)->visited = false;
1892 (*p)->sumsteps = 0.0;
1896 void gnudisctreenode(node **grbg, node **p, long i,
1897 long endsite, long *zeros, unsigned char *zeros2)
1898 { /* this and the following are do-it-yourself garbage collectors.
1899 Make a new node or pull one off the garbage list */
1901 if (*grbg != NULL) {
1903 *grbg = (*grbg)->next;
1904 memcpy((*p)->numsteps, zeros, endsite*sizeof(long));
1905 memcpy((*p)->oldnumsteps, zeros, endsite*sizeof(long));
1906 memcpy((*p)->discbase, zeros2, endsite*sizeof(unsigned char));
1907 memcpy((*p)->olddiscbase, zeros2, endsite*sizeof(unsigned char));
1908 zerodiscnumnuc(*p, endsite);
1910 allocdiscnode(p, zeros, zeros2, endsite);
1914 (*p)->visited = false;
1917 (*p)->sumsteps = 0.0;
1918 } /* gnudisctreenode */
1921 void chucktreenode(node **grbg, node *p)
1922 { /* collect garbage on p -- put it on front of garbage list */
1927 } /* chucktreenode */
1930 void setupnode(node *p, long i)
1931 { /* initialization of node pointers, variables */
1935 p->times_in_tree = (double) i * 1.0;
1941 long count_sibs (node *p)
1942 { /* Count the number of nodes in a ring, return the total number of */
1943 /* nodes excluding the one passed into the function (siblings) */
1945 long return_int = 0;
1948 printf ("Error: the function count_sibs called on a tip. This is a bug.\n");
1955 printf ("Error: a loop of nodes was not closed.\n");
1967 void inittrav (node *p)
1968 { /* traverse to set pointers uninitialized on inserting */
1976 num_sibs = count_sibs (p);
1978 for (i=0; i < num_sibs; i++) {
1979 sib_ptr = sib_ptr->next;
1980 sib_ptr->initialized = false;
1981 inittrav(sib_ptr->back);
1986 void commentskipper(FILE ***intree, long *bracket)
1987 { /* skip over comment bracket contents in reading tree */
1990 c = gettc(**intree);
1994 if(feof(**intree)) {
1995 printf("\n\nERROR: Unmatched comment brackets\n\n");
2001 commentskipper(intree, bracket);
2003 c = gettc(**intree);
2006 } /* commentskipper */
2009 long countcomma(FILE **treefile, long *comma)
2011 /* Modified by Dan F. 11/10/96 */
2013 /* The next line inserted so this function leaves the file pointing
2014 to where it found it, not just re-winding it. */
2015 long orig_position = ftell (*treefile);
2024 c = getc(*treefile);
2025 if (feof(*treefile))
2035 commentskipper(&treefile, &bracket);
2039 /* Don't just rewind, */
2040 /* rewind (*treefile); */
2041 /* Re-set to where it pointed when the function was called */
2043 fseek (*treefile, orig_position, SEEK_SET);
2045 return lparen + (*comma);
2047 /* countcomma rewritten so it passes back both lparen+comma to allocate nodep
2048 and a pointer to the comma variable. This allows the tree to know how many
2049 species exist, and the tips to be placed in the front of the nodep array */
2052 long countsemic(FILE **treefile)
2053 { /* Used to determine the number of user trees. Return
2054 either a: the number of semicolons in the file outside comments
2055 or b: the first integer in the file */
2057 long return_val, semic = 0;
2060 /* Eat all whitespace */
2061 c = gettc(*treefile);
2062 while ((c == ' ') ||
2065 c = gettc(*treefile);
2068 /* Then figure out if the first non-white character is a digit; if
2071 ungetc(c, *treefile);
2072 fscanf((*treefile), "%ld", &return_val);
2075 /* Loop past all characters, count the number of semicolons
2076 outside of comments */
2078 c = fgetc(*treefile);
2079 if (feof(*treefile))
2085 commentskipper(&treefile, &bracket);
2096 void hookup(node *p, node *q)
2097 { /* hook together two nodes */
2104 void link_trees(long local_nextnum, long nodenum, long local_nodenum,
2107 if(local_nextnum == 0)
2108 hookup(nodep[nodenum],nodep[local_nodenum]);
2109 else if(local_nextnum == 1)
2110 hookup(nodep[nodenum], nodep[local_nodenum]->next);
2111 else if(local_nextnum == 2)
2112 hookup(nodep[nodenum],nodep[local_nodenum]->next->next);
2114 printf("Error in Link_Trees()");
2115 } /* link_trees() */
2118 void allocate_nodep(pointarray *nodep, FILE **treefile, long *precalc_tips)
2119 { /* pre-compute space and allocate memory for nodep */
2121 long numnodes; /* returns number commas & ( */
2122 long numcom = 0; /* returns number commas */
2124 numnodes = countcomma(treefile, &numcom) + 1;
2125 *nodep = (pointarray)Malloc(2*numnodes*sizeof(node *));
2127 (*precalc_tips) = numcom + 1; /* this will be used in placing the
2128 tip nodes in the front region of
2129 nodep. Used for species check? */
2130 } /* allocate_nodep -plc */
2133 void malloc_pheno (node *p, long endsite, long rcategs)
2134 { /* Allocate the phenotype arrays; used by dnaml */
2137 p->x = (phenotype)Malloc(endsite*sizeof(ratelike));
2138 p->underflows = Malloc(endsite * sizeof(double));
2139 for (i = 0; i < endsite; i++)
2140 p->x[i] = (ratelike)Malloc(rcategs*sizeof(sitelike));
2141 } /* malloc_pheno */
2144 void malloc_ppheno (node *p,long endsite, long rcategs)
2146 /* Allocate the phenotype arrays; used by proml */
2149 p->protx = (pphenotype)Malloc(endsite*sizeof(pratelike));
2150 p->underflows = Malloc(endsite*sizeof(double));
2152 for (i = 0; i < endsite; i++)
2153 p->protx[i] = (pratelike)Malloc(rcategs*sizeof(psitelike));
2154 } /* malloc_ppheno */
2157 long take_name_from_tree (Char *ch, Char *str, FILE *treefile)
2159 /* This loop takes in the name from the tree.
2160 Return the length of the name string. */
2162 long name_length = 0;
2167 str[name_length++] = (*ch);
2169 scan_eoln(treefile);
2170 (*ch) = gettc(treefile);
2173 } while ((*ch) != ':' && (*ch) != ',' && (*ch) != ')' &&
2174 (*ch) != '[' && (*ch) != ';' && name_length <= MAXNCH);
2176 } /* take_name_from_tree */
2179 void match_names_to_data (Char *str, pointarray treenode, node **p, long spp)
2181 /* This loop matches names taken from treefile to indexed names in
2190 for (i = 0; i < nmlngth; i++) {
2191 found = (found && ((str[i] == nayme[n - 1][i]) ||
2192 (((nayme[n - 1][i] == '_') && (str[i] == ' ')) ||
2193 ((nayme[n - 1][i] == ' ') && (str[i] == '\0')))));
2197 *p = treenode[n - 1];
2201 } while (!(n > spp || found));
2204 printf("\n\nERROR: Cannot find species: ");
2205 for (i = 0; (str[i] != '\0') && (i < MAXNCH); i++)
2207 printf(" in data file\n\n");
2210 } /* match_names_to_data */
2213 void addelement(node **p, node *q, Char *ch, long *parens, FILE *treefile,
2214 pointarray treenode, boolean *goteof, boolean *first, pointarray nodep,
2215 long *nextnode, long *ntips, boolean *haslengths, node **grbg,
2216 initptr initnode,boolean unifok, long maxnodes)
2218 /* Recursive procedure adds nodes to user-defined tree
2219 This is the main (new) tree-reading procedure */
2222 long i, len = 0, nodei = 0;
2229 (*nextnode)++; /* get ready to use new interior node */
2230 nodei = *nextnode; /* do what needs to be done at bottom */
2231 if ( maxnodes != -1 && nodei > maxnodes) {
2232 printf("ERROR in input tree file: Attempting to allocate too\n");
2233 printf("many nodes. This is usually caused by a unifurcation.");
2234 printf("To use this tree with this program use Retree to read\n");
2235 printf("and write this tree.\n");
2238 (*initnode)(p, grbg, q, len, nodei, ntips,
2239 parens, bottom, treenode, nodep, str, ch, treefile);
2242 while (notlast) { /* loop through immediate descendants */
2244 (*initnode)(&(*p)->next, grbg, q,
2245 len, nodei, ntips, parens, nonbottom, treenode,
2246 nodep, str, ch, treefile);
2247 /* ... doing what is done before each */
2249 getch(ch, parens, treefile); /* look for next character */
2251 /* handle blank names */
2252 if((*ch) == ',' || (*ch) == ':'){
2253 ungetc((*ch), treefile);
2255 } else if((*ch)==')'){
2256 ungetc((*ch), treefile);
2261 addelement(&(*p)->next->back, (*p)->next, ch, parens, treefile,
2262 treenode, goteof, first, nodep, nextnode, ntips,
2263 haslengths, grbg, initnode,unifok,maxnodes);
2265 (*initnode)(&r, grbg, q, len, nodei, ntips,
2266 parens, hslength, treenode, nodep, str, ch, treefile);
2267 /* do what is done after each about length */
2268 pfirst->numdesc++; /* increment number of descendants */
2269 *p = r; /* make r point back to p */
2274 getch(ch, parens, treefile);
2275 } while ((*ch) != ',' && (*ch) != ')' &&
2276 (*ch) != '[' && (*ch) != ';' && (*ch) != ':');
2279 if ( furs <= 1 && !unifok ) {
2280 printf("ERROR in input tree file: A Unifurcation was detetected.\n");
2281 printf("To use this tree with this program use retree to read and");
2282 printf(" write this tree\n");
2286 (*p)->next = pfirst;
2289 } else if ((*ch) != ')') { /* if it's a species name */
2290 for (i = 0; i < MAXNCH; i++) /* fill string with nulls */
2293 len = take_name_from_tree (ch, str, treefile); /* get the name */
2296 (*parens)--; /* decrement count of open parentheses */
2297 (*initnode)(p, grbg, q, len, nodei, ntips,
2298 parens, tip, treenode, nodep, str, ch, treefile);
2299 /* do what needs to be done at a tip */
2301 getch(ch, parens, treefile);
2303 hookup(q, (*p)); /* now hook up */
2304 (*initnode)(p, grbg, q, len, nodei, ntips,
2305 parens, iter, treenode, nodep, str, ch, treefile);
2306 /* do what needs to be done to variable iter */
2308 (*initnode)(p, grbg, q, len, nodei, ntips,
2309 parens, length, treenode, nodep, str, ch, treefile);
2310 /* do what needs to be done with length */
2311 else if ((*ch) != ';' && (*ch) != '[')
2312 (*initnode)(p, grbg, q, len, nodei, ntips,
2313 parens, hsnolength, treenode, nodep, str, ch, treefile);
2314 /* ... or what needs to be done when no length */
2316 (*initnode)(p, grbg, q, len, nodei, ntips,
2317 parens, treewt, treenode, nodep, str, ch, treefile);
2318 /* ... for processing a tree weight */
2319 else if ((*ch) == ';') /* ... and at end of tree */
2320 (*initnode)(p, grbg, q, len, nodei, ntips,
2321 parens, unittrwt, treenode, nodep, str, ch, treefile);
2325 void treeread (FILE *treefile, node **root, pointarray treenode,
2326 boolean *goteof, boolean *first, pointarray nodep,
2327 long *nextnode, boolean *haslengths, node **grbg, initptr initnode,
2328 boolean unifok,long maxnodes)
2330 /* read in user-defined tree and set it up */
2338 /* eat blank lines */
2339 while (eoln(treefile) && !eoff(treefile))
2340 scan_eoln(treefile);
2342 if (eoff(treefile)) {
2347 getch(&ch, &parens, treefile);
2350 /* Eat everything in the file (i.e. digits, tabs) until you
2351 encounter an open-paren */
2352 getch(&ch, &parens, treefile);
2354 (*haslengths) = true;
2355 addelement(root, NULL, &ch, &parens, treefile,
2356 treenode, goteof, first, nodep, nextnode, &ntips,
2357 haslengths, grbg, initnode,unifok,maxnodes);
2359 /* Eat blank lines and end of current line*/
2361 scan_eoln(treefile);
2363 while (eoln(treefile) && !eoff(treefile));
2367 printf("\n\nERROR in tree file: unmatched parentheses\n\n");
2373 void addelement2(node *q, Char *ch, long *parens, FILE *treefile,
2374 pointarray treenode, boolean lngths, double *trweight, boolean *goteof,
2375 long *nextnode, long *ntips, long no_species, boolean *haslengths,
2376 boolean unifok,long maxnodes)
2378 /* recursive procedure adds nodes to user-defined tree
2379 -- old-style bifurcating-only version */
2380 node *pfirst = NULL, *p;
2381 long i, len, current_loop_index;
2382 boolean notlast, minusread;
2384 double valyew, divisor;
2389 current_loop_index = (*nextnode) + spp;
2392 if ( maxnodes != -1 && current_loop_index > maxnodes) {
2393 printf("ERROR in intree file: Attempting to allocate too many nodes\n");
2394 printf("This is usually caused by a unifurcation. To use this\n");
2395 printf("intree with this program use retree to read and write\n");
2396 printf("this tree.\n");
2399 /* This is an assignment of an interior node */
2400 p = treenode[current_loop_index];
2405 /* This while loop goes through a circle (triad for
2406 bifurcations) of nodes */
2408 /* added to ensure that non base nodes in loops have indices */
2409 p->index = current_loop_index + 1;
2411 getch(ch, parens, treefile);
2413 addelement2(p, ch, parens, treefile, treenode, lngths, trweight,
2414 goteof, nextnode, ntips, no_species, haslengths,unifok,maxnodes);
2419 getch(ch, parens, treefile);
2420 } while ((*ch) != ',' && (*ch) != ')' &&
2421 (*ch) != '[' && (*ch) != ';' && (*ch) != ':');
2424 if ( furs <= 1 && !unifok ) {
2425 printf("ERROR in intree file: A Unifurcation was detetected.\n");
2426 printf("To use this intree with this program use retree to read and");
2427 printf(" write this tree\n");
2431 } else if ((*ch) != ')') {
2432 for (i = 0; i < MAXNCH; i++)
2434 len = take_name_from_tree (ch, str, treefile);
2435 match_names_to_data (str, treenode, &p, spp);
2440 strncpy (p->nayme, str, len);
2442 getch(ch, parens, treefile);
2444 if ((*ch) == '[') { /* getting tree weight from last comment field */
2445 if (!eoln(treefile)) {
2446 fscanf(treefile, "%lf", trweight);
2447 getch(ch, parens, treefile);
2449 printf("\n\nERROR: Missing right square bracket\n\n");
2453 getch(ch, parens, treefile);
2455 printf("\n\nERROR: Missing semicolon after square brackets\n\n");
2461 else if ((*ch) == ';') {
2463 if (!eoln(treefile))
2464 printf("WARNING: tree weight set to 1.0\n");
2467 (*haslengths) = ((*haslengths) && q == NULL);
2473 processlength(&valyew, &divisor, ch,
2474 &minusread, treefile, parens);
2477 q->oldlen = valyew / divisor;
2481 q->v = valyew / divisor;
2484 q->back->iter = false;
2485 q->back->iter = false;
2493 void treeread2 (FILE *treefile, node **root, pointarray treenode,
2494 boolean lngths, double *trweight, boolean *goteof,
2495 boolean *haslengths, long *no_species,boolean unifok,long maxnodes)
2497 /* read in user-defined tree and set it up
2498 -- old-style bifurcating-only version */
2507 /* Eats all blank lines at start of file */
2508 while (eoln(treefile) && !eoff(treefile))
2509 scan_eoln(treefile);
2511 if (eoff(treefile)) {
2516 getch(&ch, &parens, treefile);
2519 /* Eat everything in the file (i.e. digits, tabs) until you
2520 encounter an open-paren */
2521 getch(&ch, &parens, treefile);
2524 addelement2(NULL, &ch, &parens, treefile, treenode, lngths, trweight,
2525 goteof, &nextnode, &ntips, (*no_species), haslengths,unifok,maxnodes);
2526 (*root) = treenode[*no_species];
2528 /*eat blank lines */
2529 while (eoln(treefile) && !eoff(treefile))
2530 scan_eoln(treefile);
2532 (*root)->oldlen = 0.0;
2535 printf("\n\nERROR in tree file: unmatched parentheses\n\n");
2541 void exxit(int exitcode)
2549 puts ("Hit Enter or Return to close program.");
2550 puts(" You may have to hit Enter or Return twice.");
2553 phyRestoreConsoleAttributes();
2560 char gettc(FILE* file)
2561 { /* catch eof's so that other functions not expecting an eof
2562 * won't have to worry about it */
2568 puts("Unexpected End of File");
2581 void unroot(tree *t, long nonodes)
2583 /* used by fitch, restml and contml */
2584 if (t->start->back == NULL) {
2585 if (t->start->next->back->tip)
2586 t->start = t->start->next->next->back;
2587 else t->start = t->start->next->back;
2589 if (t->start->next->back == NULL) {
2590 if (t->start->back->tip)
2591 t->start = t->start->next->next->back;
2592 else t->start = t->start->back;
2594 if (t->start->next->next->back == NULL) {
2595 if (t->start->back->tip)
2596 t->start = t->start->next->back;
2597 else t->start = t->start->back;
2601 unroot_r(t->start,t->nodep,nonodes);
2602 unroot_r(t->start->back, t->nodep, nonodes);
2605 void unroot_here(node* root, node** nodep, long nonodes)
2609 /* used by unroot */
2610 /* assumes bifurcation this is ok in the programs that use it */
2613 newl = root->next->oldlen + root->next->next->oldlen;
2614 root->next->back->oldlen = newl;
2615 root->next->next->back->oldlen = newl;
2617 newl = root->next->v + root->next->next->v;
2618 root->next->back->v = newl;
2619 root->next->next->back->v = newl;
2621 root->next->back->back=root->next->next->back;
2622 root->next->next->back->back = root->next->back;
2624 while ( root->index != nonodes ) {
2625 tmpnode = nodep[ root->index ];
2626 nodep[root->index] = root;
2628 root->next->index++;
2629 root->next->next->index++;
2630 nodep[root->index - 2] = tmpnode;
2632 tmpnode->next->index--;
2633 tmpnode->next->next->index--;
2637 void unroot_r(node* p, node** nodep, long nonodes)
2639 /* used by unroot */
2642 if ( p->tip) return;
2646 if (q->back == NULL)
2647 unroot_here(q,nodep,nonodes);
2648 else unroot_r(q->back,nodep,nonodes);
2653 void clear_connections(tree *t, long nonodes)
2656 for ( i = 0 ; i < nonodes ; i++) {
2658 t->nodep[i]->next->back = NULL;
2659 t->nodep[i]->next->v = 0;
2660 t->nodep[i]->next->next->back = NULL;
2661 t->nodep[i]->next->next->v = 0;
2663 t->nodep[i]->back = NULL;
2669 void phySaveConsoleAttributes()
2671 GetConsoleScreenBufferInfo( hConsoleOutput, &savecsbi );
2672 } /* PhySaveConsoleAttributes */
2675 void phySetConsoleAttributes()
2677 hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
2679 phySaveConsoleAttributes();
2681 SetConsoleTextAttribute(hConsoleOutput,
2682 BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY);
2683 } /* phySetConsoleAttributes */
2686 void phyRestoreConsoleAttributes()
2688 COORD coordScreen = { 0, 0 };
2689 DWORD cCharsWritten;
2692 dwConSize = savecsbi.dwSize.X * savecsbi.dwSize.Y;
2694 SetConsoleTextAttribute(hConsoleOutput, savecsbi.wAttributes);
2696 FillConsoleOutputAttribute( hConsoleOutput, savecsbi.wAttributes,
2697 dwConSize, coordScreen, &cCharsWritten );
2698 } /* phyRestoreConsoleAttributes */
2701 void phyFillScreenColor()
2703 COORD coordScreen = { 0, 0 };
2704 DWORD cCharsWritten;
2705 CONSOLE_SCREEN_BUFFER_INFO csbi; /* to get buffer info */
2708 GetConsoleScreenBufferInfo( hConsoleOutput, &csbi );
2709 dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
2711 FillConsoleOutputAttribute( hConsoleOutput, csbi.wAttributes,
2712 dwConSize, coordScreen, &cCharsWritten );
2713 } /* PhyFillScreenColor */
2716 void phyClearScreen()
2718 COORD coordScreen = { 0, 0 }; /* here's where we'll home the
2720 DWORD cCharsWritten;
2721 CONSOLE_SCREEN_BUFFER_INFO csbi; /* to get buffer info */
2722 DWORD dwConSize; /* number of character cells in
2723 the current buffer */
2725 /* get the number of character cells in the current buffer */
2727 GetConsoleScreenBufferInfo( hConsoleOutput, &csbi );
2728 dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
2730 /* fill the entire screen with blanks */
2732 FillConsoleOutputCharacter( hConsoleOutput, (TCHAR) ' ',
2733 dwConSize, coordScreen, &cCharsWritten );
2735 /* get the current text attribute */
2737 GetConsoleScreenBufferInfo( hConsoleOutput, &csbi );
2739 /* now set the buffer's attributes accordingly */
2741 FillConsoleOutputAttribute( hConsoleOutput, csbi.wAttributes,
2742 dwConSize, coordScreen, &cCharsWritten );
2744 /* put the cursor at (0, 0) */
2746 SetConsoleCursorPosition( hConsoleOutput, coordScreen );
2748 } /* PhyClearScreen */