| 1 | |
|---|
| 2 | /* version 3.6. (c) Copyright 1993-2002 by the University of Washington. |
|---|
| 3 | Written by Joseph Felsenstein, Akiko Fuseki, Sean Lamont, Andrew Keeffe, |
|---|
| 4 | and Dan Fineman. |
|---|
| 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. */ |
|---|
| 7 | |
|---|
| 8 | #include <stdio.h> |
|---|
| 9 | #include <signal.h> |
|---|
| 10 | #ifdef WIN32 |
|---|
| 11 | #include <windows.h> |
|---|
| 12 | /* for console code (clear screen, text color settings) */ |
|---|
| 13 | CONSOLE_SCREEN_BUFFER_INFO savecsbi; |
|---|
| 14 | HANDLE hConsoleOutput; |
|---|
| 15 | |
|---|
| 16 | void phyClearScreen(); |
|---|
| 17 | void phySaveConsoleAttributes(); |
|---|
| 18 | void phySetConsoleAttributes(); |
|---|
| 19 | void phyRestoreConsoleAttributes(); |
|---|
| 20 | void phyFillScreenColor(); |
|---|
| 21 | #endif |
|---|
| 22 | |
|---|
| 23 | #include "phylip.h" |
|---|
| 24 | |
|---|
| 25 | #ifndef OLDC |
|---|
| 26 | static void crash_handler(int signum); |
|---|
| 27 | |
|---|
| 28 | #endif |
|---|
| 29 | |
|---|
| 30 | FILE *infile, *outfile, *intree, *intree2, *outtree, *weightfile, *catfile, *ancfile, *mixfile, *factfile; |
|---|
| 31 | long spp, words, bits; |
|---|
| 32 | boolean ibmpc, ansi, tranvsp; |
|---|
| 33 | naym *nayme; /* names of species */ |
|---|
| 34 | |
|---|
| 35 | static void crash_handler(int sig_num) |
|---|
| 36 | { /* when we crash, lets print out something usefull */ |
|---|
| 37 | printf("ERROR: "); |
|---|
| 38 | switch(sig_num) { |
|---|
| 39 | #ifdef SIGSEGV |
|---|
| 40 | case SIGSEGV: |
|---|
| 41 | puts("This program has caused a Segmentation fault."); |
|---|
| 42 | break; |
|---|
| 43 | #endif /* SIGSEGV */ |
|---|
| 44 | #ifdef SIGFPE |
|---|
| 45 | case SIGFPE: |
|---|
| 46 | puts("This program has caused a Floating Point Exception"); |
|---|
| 47 | break; |
|---|
| 48 | #endif /* SIGFPE */ |
|---|
| 49 | #ifdef SIGILL |
|---|
| 50 | case SIGILL: |
|---|
| 51 | puts("This program has attempted an illegal instruction"); |
|---|
| 52 | break; |
|---|
| 53 | #endif /* SIGILL */ |
|---|
| 54 | #ifdef SIGPIPE |
|---|
| 55 | case SIGPIPE: |
|---|
| 56 | puts("This program tried to write to a broken pipe"); |
|---|
| 57 | break; |
|---|
| 58 | #endif /* SIGPIPE */ |
|---|
| 59 | #ifdef SIGBUS |
|---|
| 60 | case SIGBUS: |
|---|
| 61 | puts("This program had a bus error"); |
|---|
| 62 | break; |
|---|
| 63 | #endif /* SIGBUS */ |
|---|
| 64 | } |
|---|
| 65 | if (sig_num == SIGSEGV) { |
|---|
| 66 | puts(" This may have been caused by an incorrectly formatted"); |
|---|
| 67 | puts(" input tree file or input file. You should check those"); |
|---|
| 68 | puts(" files carefully."); |
|---|
| 69 | puts(" If this seems to be a bug, please mail joe@gs.washington.edu"); |
|---|
| 70 | } |
|---|
| 71 | else { |
|---|
| 72 | puts(" Most likely, you have encountered a bug in the program."); |
|---|
| 73 | puts(" Since this seems to be a bug, please mail joe@gs.washington.edu"); |
|---|
| 74 | } |
|---|
| 75 | puts(" with the name of the program, your computer system type,"); |
|---|
| 76 | puts(" a full description of the problem, and with the input data file."); |
|---|
| 77 | puts(" (which should be in the body of the message, not as an Attachment)."); |
|---|
| 78 | |
|---|
| 79 | #ifdef WIN32 |
|---|
| 80 | puts ("Hit Enter or Return to close program."); |
|---|
| 81 | puts(" You may have to hit Enter or Return twice."); |
|---|
| 82 | getchar (); |
|---|
| 83 | getchar (); |
|---|
| 84 | phyRestoreConsoleAttributes(); |
|---|
| 85 | #endif |
|---|
| 86 | abort(); |
|---|
| 87 | } |
|---|
| 88 | |
|---|
| 89 | |
|---|
| 90 | void init(int UNUSED_argc, char** UNUSED_argv) |
|---|
| 91 | { /* initialization routine for all programs |
|---|
| 92 | * anything done at the beginig for every program should be done here */ |
|---|
| 93 | |
|---|
| 94 | /* set up signal handler for |
|---|
| 95 | * segfault,floating point exception, illeagal instruction, bad pipe, bus error |
|---|
| 96 | * there are more signals that can cause a crash, but these are the most common |
|---|
| 97 | * even these aren't found on all machines. */ |
|---|
| 98 | |
|---|
| 99 | (void)UNUSED_argc; |
|---|
| 100 | (void)UNUSED_argv; |
|---|
| 101 | |
|---|
| 102 | #ifdef SIGSEGV |
|---|
| 103 | signal(SIGSEGV, crash_handler); |
|---|
| 104 | #endif /* SIGSEGV */ |
|---|
| 105 | #ifdef SIGFPE |
|---|
| 106 | signal(SIGFPE, crash_handler); |
|---|
| 107 | #endif /* SIGFPE */ |
|---|
| 108 | #ifdef SIGILL |
|---|
| 109 | signal(SIGILL, crash_handler); |
|---|
| 110 | #endif /* SIGILL */ |
|---|
| 111 | #ifdef SIGPIPE |
|---|
| 112 | signal(SIGPIPE, crash_handler); |
|---|
| 113 | #endif /* SIGPIPE */ |
|---|
| 114 | #ifdef SIGBUS |
|---|
| 115 | signal(SIGBUS, crash_handler); |
|---|
| 116 | #endif /* SIGBUS */ |
|---|
| 117 | |
|---|
| 118 | #ifdef WIN32 |
|---|
| 119 | phySetConsoleAttributes(); |
|---|
| 120 | phyClearScreen(); |
|---|
| 121 | #endif |
|---|
| 122 | |
|---|
| 123 | } |
|---|
| 124 | |
|---|
| 125 | void scan_eoln(FILE *f) |
|---|
| 126 | { /* eat everything to the end of line or eof*/ |
|---|
| 127 | char ch; |
|---|
| 128 | |
|---|
| 129 | while (!eoff(f) && !eoln(f)) |
|---|
| 130 | gettc(f); |
|---|
| 131 | if (!eoff(f)) |
|---|
| 132 | ch = gettc(f); |
|---|
| 133 | if (ch == '\r' && !eoff(f) && eoln(f)) |
|---|
| 134 | gettc(f); |
|---|
| 135 | } |
|---|
| 136 | |
|---|
| 137 | |
|---|
| 138 | boolean eoff(FILE *f) |
|---|
| 139 | { /* check for end of file */ |
|---|
| 140 | int ch; |
|---|
| 141 | |
|---|
| 142 | if (feof(f)) |
|---|
| 143 | return true; |
|---|
| 144 | ch = getc(f); |
|---|
| 145 | if (ch == EOF) { |
|---|
| 146 | ungetc(ch, f); |
|---|
| 147 | return true; |
|---|
| 148 | } |
|---|
| 149 | ungetc(ch, f); |
|---|
| 150 | return false; |
|---|
| 151 | } /*eoff*/ |
|---|
| 152 | |
|---|
| 153 | |
|---|
| 154 | boolean eoln(FILE *f) |
|---|
| 155 | { /* check for end of line or eof*/ |
|---|
| 156 | register int ch; |
|---|
| 157 | |
|---|
| 158 | ch = getc(f); |
|---|
| 159 | if (ch == EOF) |
|---|
| 160 | return true; |
|---|
| 161 | ungetc(ch, f); |
|---|
| 162 | return ((ch == '\n') || (ch == '\r')); |
|---|
| 163 | } /*eoln*/ |
|---|
| 164 | |
|---|
| 165 | |
|---|
| 166 | int filexists(char *filename) |
|---|
| 167 | { /* check whether file already exists */ |
|---|
| 168 | FILE *fp; |
|---|
| 169 | fp =fopen(filename,"r"); |
|---|
| 170 | if (fp) { |
|---|
| 171 | fclose(fp); |
|---|
| 172 | return 1; |
|---|
| 173 | } else |
|---|
| 174 | return 0; |
|---|
| 175 | } /*filexists*/ |
|---|
| 176 | |
|---|
| 177 | |
|---|
| 178 | const char* get_command_name (const char *vektor) |
|---|
| 179 | { /* returns the name of the program from vektor without the whole path */ |
|---|
| 180 | char *last_slash; |
|---|
| 181 | |
|---|
| 182 | /* Point to the last slash... */ |
|---|
| 183 | last_slash = strrchr (vektor, DELIMITER); |
|---|
| 184 | |
|---|
| 185 | if (last_slash) |
|---|
| 186 | /* If there was a last slash, return the character after it */ |
|---|
| 187 | return last_slash + 1; |
|---|
| 188 | else |
|---|
| 189 | /* If not, return the vector */ |
|---|
| 190 | return vektor; |
|---|
| 191 | |
|---|
| 192 | } /*get_command_name*/ |
|---|
| 193 | |
|---|
| 194 | |
|---|
| 195 | void getstryng(char *fname) |
|---|
| 196 | { /* read in a file name from stdin and take off newline if any */ |
|---|
| 197 | |
|---|
| 198 | fname = fgets(fname, 100, stdin); |
|---|
| 199 | if (strchr(fname, '\n') != NULL) |
|---|
| 200 | *strchr(fname, '\n') = '\0'; |
|---|
| 201 | } /* getstryng */ |
|---|
| 202 | |
|---|
| 203 | |
|---|
| 204 | void countup(long *loopcount, long maxcount) |
|---|
| 205 | { /* count how many times this loop has tried to read data, bail out |
|---|
| 206 | if exceeds maxcount */ |
|---|
| 207 | |
|---|
| 208 | (*loopcount)++; |
|---|
| 209 | if ((*loopcount) >= maxcount) { |
|---|
| 210 | printf("\nERROR: Made %ld attempts to read input in loop. Aborting run.\n", |
|---|
| 211 | *loopcount); |
|---|
| 212 | exxit(-1); |
|---|
| 213 | } |
|---|
| 214 | } /* countup */ |
|---|
| 215 | |
|---|
| 216 | |
|---|
| 217 | void openfile(FILE **fp,const char *filename,const char *filedesc, |
|---|
| 218 | const char *mode,const char *application, char *perm) |
|---|
| 219 | { /* open a file, testing whether it exists etc. */ |
|---|
| 220 | FILE *of; |
|---|
| 221 | char file[FNMLNGTH]; |
|---|
| 222 | char filemode[2]; |
|---|
| 223 | char input[FNMLNGTH]; |
|---|
| 224 | char ch; |
|---|
| 225 | const char *progname_without_path; |
|---|
| 226 | long loopcount, loopcount2; |
|---|
| 227 | |
|---|
| 228 | progname_without_path = get_command_name(application); |
|---|
| 229 | |
|---|
| 230 | strcpy(file,filename); |
|---|
| 231 | strcpy(filemode,mode); |
|---|
| 232 | loopcount = 0; |
|---|
| 233 | while (1){ |
|---|
| 234 | if (filemode[0] == 'w' && filexists(file)){ |
|---|
| 235 | printf("\n%s: the file \"%s\" that you wanted to\n", |
|---|
| 236 | progname_without_path, file); |
|---|
| 237 | printf(" use as %s already exists.\n", filedesc); |
|---|
| 238 | printf(" Do you want to Replace it, Append to it,\n"); |
|---|
| 239 | printf(" write to a new File, or Quit?\n"); |
|---|
| 240 | loopcount2 = 0; |
|---|
| 241 | do { |
|---|
| 242 | printf(" (please type R, A, F, or Q) \n"); |
|---|
| 243 | #ifdef WIN32 |
|---|
| 244 | phyFillScreenColor(); |
|---|
| 245 | #endif |
|---|
| 246 | fgets(input, sizeof(input), stdin); |
|---|
| 247 | ch = input[0]; |
|---|
| 248 | uppercase(&ch); |
|---|
| 249 | countup(&loopcount2, 10); |
|---|
| 250 | } while (ch != 'A' && ch != 'R' && ch != 'F' && ch != 'Q'); |
|---|
| 251 | if (ch == 'Q') |
|---|
| 252 | exxit(-1); |
|---|
| 253 | if (ch == 'A') { |
|---|
| 254 | strcpy(filemode,"a"); |
|---|
| 255 | continue; |
|---|
| 256 | } |
|---|
| 257 | else if (ch == 'F') { |
|---|
| 258 | file[0] = '\0'; |
|---|
| 259 | loopcount2 = 0; |
|---|
| 260 | while (file[0] =='\0') { |
|---|
| 261 | printf("Please enter a new file name> "); |
|---|
| 262 | getstryng(file); |
|---|
| 263 | countup(&loopcount2, 10); |
|---|
| 264 | } |
|---|
| 265 | strcpy(filemode,"w"); |
|---|
| 266 | continue; |
|---|
| 267 | } |
|---|
| 268 | } |
|---|
| 269 | of = fopen(file,filemode); |
|---|
| 270 | if (of) |
|---|
| 271 | break; |
|---|
| 272 | else { |
|---|
| 273 | switch (filemode[0]){ |
|---|
| 274 | |
|---|
| 275 | case 'r': |
|---|
| 276 | printf("%s: can't find %s \"%s\"\n", progname_without_path, |
|---|
| 277 | filedesc, file); |
|---|
| 278 | file[0] = '\0'; |
|---|
| 279 | loopcount2 = 0; |
|---|
| 280 | while (file[0] =='\0'){ |
|---|
| 281 | printf("Please enter a new file name> "); |
|---|
| 282 | countup(&loopcount2, 10); |
|---|
| 283 | getstryng(file);} |
|---|
| 284 | break; |
|---|
| 285 | |
|---|
| 286 | case 'w': |
|---|
| 287 | case 'a': |
|---|
| 288 | printf("%s: can't write %s file %s\n", progname_without_path, |
|---|
| 289 | filedesc, file); |
|---|
| 290 | file[0] = '\0'; |
|---|
| 291 | loopcount2 = 0; |
|---|
| 292 | while (file[0] =='\0'){ |
|---|
| 293 | printf("Please enter a new file name> "); |
|---|
| 294 | countup(&loopcount2, 10); |
|---|
| 295 | getstryng(file);} |
|---|
| 296 | continue; |
|---|
| 297 | default: |
|---|
| 298 | printf("There is some error in the call of openfile. Unknown mode.\n"); |
|---|
| 299 | exxit(-1); |
|---|
| 300 | } |
|---|
| 301 | } |
|---|
| 302 | countup(&loopcount, 20); |
|---|
| 303 | } |
|---|
| 304 | *fp = of; |
|---|
| 305 | if (perm != NULL) |
|---|
| 306 | strcpy(perm,file); |
|---|
| 307 | } /* openfile */ |
|---|
| 308 | |
|---|
| 309 | |
|---|
| 310 | void cleerhome() |
|---|
| 311 | { /* home cursor and clear screen, if possible */ |
|---|
| 312 | printf("%s", ((ibmpc || ansi) ? ("\033[2J\033[H") : "\n\n")); |
|---|
| 313 | } /* cleerhome */ |
|---|
| 314 | |
|---|
| 315 | |
|---|
| 316 | double randum(longer seed) |
|---|
| 317 | { /* random number generator -- slow but machine independent |
|---|
| 318 | This is a multiplicative congruential 32-bit generator |
|---|
| 319 | x(t+1) = 1664525 * x(t) mod 2^32, one that passes the |
|---|
| 320 | Coveyou-Macpherson and Lehmer tests, see Knuth ACP vol. 2 */ |
|---|
| 321 | long i, j, k, sum; |
|---|
| 322 | longer mult, newseed; |
|---|
| 323 | double x; |
|---|
| 324 | |
|---|
| 325 | mult[0] = 13; /* these four statements set the multiplier */ |
|---|
| 326 | mult[1] = 24; /* -- they are its "digits" in a base-64 */ |
|---|
| 327 | mult[2] = 22; /* notation: 1664525 = 13*64^3+24*64^2 */ |
|---|
| 328 | mult[3] = 6; /* +22*64+6 */ |
|---|
| 329 | for (i = 0; i <= 5; i++) |
|---|
| 330 | newseed[i] = 0; |
|---|
| 331 | for (i = 0; i <= 5; i++) { |
|---|
| 332 | sum = newseed[i]; |
|---|
| 333 | k = i; |
|---|
| 334 | if (i > 3) |
|---|
| 335 | k = 3; |
|---|
| 336 | for (j = 0; j <= k; j++) |
|---|
| 337 | sum += mult[j] * seed[i - j]; |
|---|
| 338 | newseed[i] = sum; |
|---|
| 339 | for (j = i; j <= 4; j++) { |
|---|
| 340 | newseed[j + 1] += newseed[j] / 64; |
|---|
| 341 | newseed[j] &= 63; |
|---|
| 342 | } |
|---|
| 343 | } |
|---|
| 344 | memcpy(seed, newseed, sizeof(longer)); |
|---|
| 345 | seed[5] &= 3; |
|---|
| 346 | x = 0.0; |
|---|
| 347 | for (i = 0; i <= 5; i++) |
|---|
| 348 | x = x / 64.0 + seed[i]; |
|---|
| 349 | x /= 4.0; |
|---|
| 350 | return x; |
|---|
| 351 | } /* randum */ |
|---|
| 352 | |
|---|
| 353 | |
|---|
| 354 | void randumize(longer seed, long *enterorder) |
|---|
| 355 | { /* randomize input order of species */ |
|---|
| 356 | long i, j, k; |
|---|
| 357 | |
|---|
| 358 | for (i = 0; i < spp; i++) { |
|---|
| 359 | j = (long)(randum(seed) * (i+1)); |
|---|
| 360 | k = enterorder[j]; |
|---|
| 361 | enterorder[j] = enterorder[i]; |
|---|
| 362 | enterorder[i] = k; |
|---|
| 363 | } |
|---|
| 364 | } /* randumize */ |
|---|
| 365 | |
|---|
| 366 | |
|---|
| 367 | double normrand(longer seed) |
|---|
| 368 | {/* standardized Normal random variate */ |
|---|
| 369 | double x; |
|---|
| 370 | |
|---|
| 371 | x = randum(seed)+randum(seed)+randum(seed)+randum(seed) |
|---|
| 372 | + randum(seed)+randum(seed)+randum(seed)+randum(seed) |
|---|
| 373 | + randum(seed)+randum(seed)+randum(seed)+randum(seed)-6.0; |
|---|
| 374 | return(x); |
|---|
| 375 | } /* normrand */ |
|---|
| 376 | |
|---|
| 377 | |
|---|
| 378 | long readlong(const char *prompt) |
|---|
| 379 | { /* read a long */ |
|---|
| 380 | long res, loopcount; |
|---|
| 381 | char string[100]; |
|---|
| 382 | |
|---|
| 383 | loopcount = 0; |
|---|
| 384 | do { |
|---|
| 385 | printf("%s",prompt); |
|---|
| 386 | getstryng(string); |
|---|
| 387 | if (sscanf(string,"%ld",&res) == 1) |
|---|
| 388 | break; |
|---|
| 389 | countup(&loopcount, 10); |
|---|
| 390 | } while (1); |
|---|
| 391 | return res; |
|---|
| 392 | } /* readlong */ |
|---|
| 393 | |
|---|
| 394 | |
|---|
| 395 | void uppercase(Char *ch) |
|---|
| 396 | { /* convert ch to upper case */ |
|---|
| 397 | *ch = (islower (*ch) ? toupper(*ch) : (*ch)); |
|---|
| 398 | } /* uppercase */ |
|---|
| 399 | |
|---|
| 400 | |
|---|
| 401 | void initseed(long *inseed, long *inseed0, longer seed) |
|---|
| 402 | { /* input random number seed */ |
|---|
| 403 | long i, loopcount; |
|---|
| 404 | |
|---|
| 405 | loopcount = 0; |
|---|
| 406 | do { |
|---|
| 407 | printf("Random number seed (must be odd)?\n"); |
|---|
| 408 | scanf("%ld%*[^\n]", inseed); |
|---|
| 409 | getchar(); |
|---|
| 410 | countup(&loopcount, 10); |
|---|
| 411 | } while (((*inseed) < 0) || ((*inseed) & 1) == 0); |
|---|
| 412 | *inseed0 = *inseed; |
|---|
| 413 | for (i = 0; i <= 5; i++) |
|---|
| 414 | seed[i] = 0; |
|---|
| 415 | i = 0; |
|---|
| 416 | do { |
|---|
| 417 | seed[i] = *inseed & 63; |
|---|
| 418 | *inseed /= 64; |
|---|
| 419 | i++; |
|---|
| 420 | } while (*inseed != 0); |
|---|
| 421 | } /*initseed*/ |
|---|
| 422 | |
|---|
| 423 | |
|---|
| 424 | void initjumble(long *inseed, long *inseed0, longer seed, long *njumble) |
|---|
| 425 | { /* input number of jumblings for jumble option */ |
|---|
| 426 | long loopcount; |
|---|
| 427 | |
|---|
| 428 | initseed(inseed, inseed0, seed); |
|---|
| 429 | loopcount = 0; |
|---|
| 430 | do { |
|---|
| 431 | printf("Number of times to jumble?\n"); |
|---|
| 432 | scanf("%ld%*[^\n]", njumble); |
|---|
| 433 | getchar(); |
|---|
| 434 | countup(&loopcount, 10); |
|---|
| 435 | } while ((*njumble) < 1); |
|---|
| 436 | } /*initjumble*/ |
|---|
| 437 | |
|---|
| 438 | |
|---|
| 439 | void initoutgroup(long *outgrno, long local_spp) |
|---|
| 440 | { /* input outgroup number */ |
|---|
| 441 | long loopcount; |
|---|
| 442 | boolean done; |
|---|
| 443 | |
|---|
| 444 | loopcount = 0; |
|---|
| 445 | do { |
|---|
| 446 | printf("Type number of the outgroup:\n"); |
|---|
| 447 | scanf("%ld%*[^\n]", outgrno); |
|---|
| 448 | getchar(); |
|---|
| 449 | done = (*outgrno >= 1 && *outgrno <= local_spp); |
|---|
| 450 | if (!done) { |
|---|
| 451 | printf("BAD OUTGROUP NUMBER: %ld\n", *outgrno); |
|---|
| 452 | printf(" Must be in range 1 - %ld\n", local_spp); |
|---|
| 453 | } |
|---|
| 454 | countup(&loopcount, 10); |
|---|
| 455 | } while (done != true); |
|---|
| 456 | } /*initoutgroup*/ |
|---|
| 457 | |
|---|
| 458 | |
|---|
| 459 | void initthreshold(double *threshold) |
|---|
| 460 | { /* input threshold for threshold parsimony option */ |
|---|
| 461 | long loopcount; |
|---|
| 462 | boolean done; |
|---|
| 463 | |
|---|
| 464 | loopcount = 0; |
|---|
| 465 | do { |
|---|
| 466 | printf("What will be the threshold value?\n"); |
|---|
| 467 | scanf("%lf%*[^\n]", threshold); |
|---|
| 468 | getchar(); |
|---|
| 469 | done = (*threshold >= 1.0); |
|---|
| 470 | if (!done) |
|---|
| 471 | printf("BAD THRESHOLD VALUE: it must be greater than 1\n"); |
|---|
| 472 | else |
|---|
| 473 | *threshold = (long)(*threshold * 10.0 + 0.5) / 10.0; |
|---|
| 474 | countup(&loopcount, 10); |
|---|
| 475 | } while (done != true); |
|---|
| 476 | } /*initthreshold*/ |
|---|
| 477 | |
|---|
| 478 | |
|---|
| 479 | void initcatn(long *categs) |
|---|
| 480 | { /* initialize category number for rate categories */ |
|---|
| 481 | long loopcount; |
|---|
| 482 | |
|---|
| 483 | loopcount = 0; |
|---|
| 484 | do { |
|---|
| 485 | printf("Number of categories (1-%d)?\n", maxcategs); |
|---|
| 486 | scanf("%ld%*[^\n]", categs); |
|---|
| 487 | getchar(); |
|---|
| 488 | countup(&loopcount, 10); |
|---|
| 489 | } while (*categs > maxcategs || *categs < 1); |
|---|
| 490 | } /*initcatn*/ |
|---|
| 491 | |
|---|
| 492 | |
|---|
| 493 | void initcategs(long categs, double *rate) |
|---|
| 494 | { /* initialize category rates for HMM rates */ |
|---|
| 495 | long i, loopcount, scanned; |
|---|
| 496 | char line[100], rest[100]; |
|---|
| 497 | boolean done; |
|---|
| 498 | |
|---|
| 499 | loopcount = 0; |
|---|
| 500 | for (;;){ |
|---|
| 501 | printf("Rate for each category? (use a space to separate)\n"); |
|---|
| 502 | getstryng(line); |
|---|
| 503 | done = true; |
|---|
| 504 | for (i = 0; i < categs; i++){ |
|---|
| 505 | scanned = sscanf(line,"%lf %[^\n]", &rate[i],rest); |
|---|
| 506 | if ((scanned < 2 && i < (categs - 1)) || |
|---|
| 507 | (scanned < 1 && i == (categs - 1))){ |
|---|
| 508 | printf("Please enter exactly %ld values.\n",categs); |
|---|
| 509 | done = false; |
|---|
| 510 | break; |
|---|
| 511 | } |
|---|
| 512 | strcpy(line,rest); |
|---|
| 513 | } |
|---|
| 514 | if (done) |
|---|
| 515 | break; |
|---|
| 516 | countup(&loopcount, 100); |
|---|
| 517 | } |
|---|
| 518 | } /*initcategs*/ |
|---|
| 519 | |
|---|
| 520 | |
|---|
| 521 | void initprobcat(long categs, double *probsum, double *probcat) |
|---|
| 522 | { /* input probabilities of rate categores for HMM rates */ |
|---|
| 523 | long i, loopcount, scanned; |
|---|
| 524 | boolean done; |
|---|
| 525 | char line[100], rest[100]; |
|---|
| 526 | |
|---|
| 527 | loopcount = 0; |
|---|
| 528 | do { |
|---|
| 529 | printf("Probability for each category?"); |
|---|
| 530 | printf(" (use a space to separate)\n"); |
|---|
| 531 | getstryng(line); |
|---|
| 532 | done = true; |
|---|
| 533 | for (i = 0; i < categs; i++){ |
|---|
| 534 | scanned = sscanf(line,"%lf %[^\n]",&probcat[i],rest); |
|---|
| 535 | if ((scanned < 2 && i < (categs - 1)) || |
|---|
| 536 | (scanned < 1 && i == (categs - 1))){ |
|---|
| 537 | done = false; |
|---|
| 538 | printf("Please enter exactly %ld values.\n",categs); |
|---|
| 539 | break;} |
|---|
| 540 | strcpy(line,rest); |
|---|
| 541 | } |
|---|
| 542 | if (!done) |
|---|
| 543 | continue; |
|---|
| 544 | *probsum = 0.0; |
|---|
| 545 | for (i = 0; i < categs; i++) |
|---|
| 546 | *probsum += probcat[i]; |
|---|
| 547 | if (fabs(1.0 - (*probsum)) > 0.001) { |
|---|
| 548 | done = false; |
|---|
| 549 | printf("Probabilities must add up to"); |
|---|
| 550 | printf(" 1.0, plus or minus 0.001.\n"); |
|---|
| 551 | } |
|---|
| 552 | countup(&loopcount, 100); |
|---|
| 553 | } while (!done); |
|---|
| 554 | } /*initprobcat*/ |
|---|
| 555 | |
|---|
| 556 | |
|---|
| 557 | void lgr(long m, double b, raterootarray lgroot) |
|---|
| 558 | { /* For use by initgammacat. Get roots of m-th Generalized Laguerre |
|---|
| 559 | polynomial, given roots of (m-1)-th, these are to be |
|---|
| 560 | stored in lgroot[m][] */ |
|---|
| 561 | long i; |
|---|
| 562 | double upper, lower, x, y; |
|---|
| 563 | boolean dwn; /* is function declining in this interval? */ |
|---|
| 564 | |
|---|
| 565 | if (m == 1) { |
|---|
| 566 | lgroot[1][1] = 1.0+b; |
|---|
| 567 | } else { |
|---|
| 568 | dwn = true; |
|---|
| 569 | for (i=1; i<=m; i++) { |
|---|
| 570 | if (i < m) { |
|---|
| 571 | if (i == 1) |
|---|
| 572 | lower = 0.0; |
|---|
| 573 | else |
|---|
| 574 | lower = lgroot[m-1][i-1]; |
|---|
| 575 | upper = lgroot[m-1][i]; |
|---|
| 576 | } else { /* i == m, must search above */ |
|---|
| 577 | lower = lgroot[m-1][i-1]; |
|---|
| 578 | x = lgroot[m-1][m-1]; |
|---|
| 579 | do { |
|---|
| 580 | x = 2.0*x; |
|---|
| 581 | y = glaguerre(m, b,x); |
|---|
| 582 | } while ((dwn && (y > 0.0)) || ((!dwn) && (y < 0.0))); |
|---|
| 583 | upper = x; |
|---|
| 584 | } |
|---|
| 585 | while (upper-lower > 0.000000001) { |
|---|
| 586 | x = (upper+lower)/2.0; |
|---|
| 587 | if (glaguerre(m, b, x) > 0.0) { |
|---|
| 588 | if (dwn) |
|---|
| 589 | lower = x; |
|---|
| 590 | else |
|---|
| 591 | upper = x; |
|---|
| 592 | } else { |
|---|
| 593 | if (dwn) |
|---|
| 594 | upper = x; |
|---|
| 595 | else |
|---|
| 596 | lower = x; |
|---|
| 597 | } |
|---|
| 598 | } |
|---|
| 599 | lgroot[m][i] = (lower+upper)/2.0; |
|---|
| 600 | dwn = !dwn; /* switch for next one */ |
|---|
| 601 | } |
|---|
| 602 | } |
|---|
| 603 | } /* lgr */ |
|---|
| 604 | |
|---|
| 605 | |
|---|
| 606 | double logfac (long n) |
|---|
| 607 | { /* log(n!) values were calculated with Mathematica |
|---|
| 608 | with a precision of 30 digits */ |
|---|
| 609 | long i; |
|---|
| 610 | double x; |
|---|
| 611 | |
|---|
| 612 | switch (n) |
|---|
| 613 | { |
|---|
| 614 | case 0: |
|---|
| 615 | return 0.; |
|---|
| 616 | case 1: |
|---|
| 617 | return 0.; |
|---|
| 618 | case 2: |
|---|
| 619 | return 0.693147180559945309417232121458; |
|---|
| 620 | case 3: |
|---|
| 621 | return 1.791759469228055000812477358381; |
|---|
| 622 | case 4: |
|---|
| 623 | return 3.1780538303479456196469416013; |
|---|
| 624 | case 5: |
|---|
| 625 | return 4.78749174278204599424770093452; |
|---|
| 626 | case 6: |
|---|
| 627 | return 6.5792512120101009950601782929; |
|---|
| 628 | case 7: |
|---|
| 629 | return 8.52516136106541430016553103635; |
|---|
| 630 | case 8: |
|---|
| 631 | return 10.60460290274525022841722740072; |
|---|
| 632 | case 9: |
|---|
| 633 | return 12.80182748008146961120771787457; |
|---|
| 634 | case 10: |
|---|
| 635 | return 15.10441257307551529522570932925; |
|---|
| 636 | case 11: |
|---|
| 637 | return 17.50230784587388583928765290722; |
|---|
| 638 | case 12: |
|---|
| 639 | return 19.98721449566188614951736238706; |
|---|
| 640 | default: |
|---|
| 641 | x = 19.98721449566188614951736238706; |
|---|
| 642 | for (i = 13; i <= n; i++) |
|---|
| 643 | x += log(i); |
|---|
| 644 | return x; |
|---|
| 645 | } |
|---|
| 646 | } |
|---|
| 647 | |
|---|
| 648 | |
|---|
| 649 | double glaguerre(long m, double b, double x) |
|---|
| 650 | { /* Generalized Laguerre polynomial computed recursively. |
|---|
| 651 | For use by initgammacat */ |
|---|
| 652 | long i; |
|---|
| 653 | double local_gln, glnm1, glnp1; /* L_n, L_(n-1), L_(n+1) */ |
|---|
| 654 | |
|---|
| 655 | if (m == 0) |
|---|
| 656 | return 1.0; |
|---|
| 657 | else { |
|---|
| 658 | if (m == 1) |
|---|
| 659 | return 1.0 + b - x; |
|---|
| 660 | else { |
|---|
| 661 | local_gln = 1.0+b-x; |
|---|
| 662 | glnm1 = 1.0; |
|---|
| 663 | for (i=2; i <= m; i++) { |
|---|
| 664 | glnp1 = ((2*(i-1)+b+1.0-x)*local_gln - (i-1+b)*glnm1)/i; |
|---|
| 665 | glnm1 = local_gln; |
|---|
| 666 | local_gln = glnp1; |
|---|
| 667 | } |
|---|
| 668 | return local_gln; |
|---|
| 669 | } |
|---|
| 670 | } |
|---|
| 671 | } /* glaguerre */ |
|---|
| 672 | |
|---|
| 673 | |
|---|
| 674 | void initlaguerrecat(long categs, double alpha, double *rate, double *probcat) |
|---|
| 675 | { /* calculate rates and probabilities to approximate Gamma distribution |
|---|
| 676 | of rates with "categs" categories and shape parameter "alpha" using |
|---|
| 677 | rates and weights from Generalized Laguerre quadrature */ |
|---|
| 678 | long i; |
|---|
| 679 | raterootarray lgroot; /* roots of GLaguerre polynomials */ |
|---|
| 680 | double f, x, xi, y; |
|---|
| 681 | |
|---|
| 682 | alpha = alpha - 1.0; |
|---|
| 683 | lgroot[1][1] = 1.0+alpha; |
|---|
| 684 | for (i = 2; i <= categs; i++) |
|---|
| 685 | lgr(i, alpha, lgroot); /* get roots for L^(a)_n */ |
|---|
| 686 | /* here get weights */ |
|---|
| 687 | /* Gamma weights are (1+a)(1+a/2) ... (1+a/n)*x_i/((n+1)^2 [L_{n+1}^a(x_i)]^2) */ |
|---|
| 688 | f = 1; |
|---|
| 689 | for (i = 1; i <= categs; i++) |
|---|
| 690 | f *= (1.0+alpha/i); |
|---|
| 691 | for (i = 1; i <= categs; i++) { |
|---|
| 692 | xi = lgroot[categs][i]; |
|---|
| 693 | y = glaguerre(categs+1, alpha, xi); |
|---|
| 694 | x = f*xi/((categs+1)*(categs+1)*y*y); |
|---|
| 695 | rate[i-1] = xi/(1.0+alpha); |
|---|
| 696 | probcat[i-1] = x; |
|---|
| 697 | } |
|---|
| 698 | } /* initlaguerrecat */ |
|---|
| 699 | |
|---|
| 700 | |
|---|
| 701 | double hermite(long n, double x) |
|---|
| 702 | { /* calculates hermite polynomial with degree n and parameter x */ |
|---|
| 703 | /* seems to be unprecise for n>13 -> root finder does not converge*/ |
|---|
| 704 | double h1 = 1.; |
|---|
| 705 | double h2 = 2. * x; |
|---|
| 706 | double xx = 2. * x; |
|---|
| 707 | long i; |
|---|
| 708 | |
|---|
| 709 | for (i = 1; i < n; i++) { |
|---|
| 710 | xx = 2. * x * h2 - 2. * (i) * h1; |
|---|
| 711 | h1 = h2; |
|---|
| 712 | h2 = xx; |
|---|
| 713 | } |
|---|
| 714 | return xx; |
|---|
| 715 | } /* hermite */ |
|---|
| 716 | |
|---|
| 717 | |
|---|
| 718 | void root_hermite(long n, double *hroot) |
|---|
| 719 | { /* find roots of Hermite polynmials */ |
|---|
| 720 | long z; |
|---|
| 721 | long ii; |
|---|
| 722 | long start; |
|---|
| 723 | |
|---|
| 724 | if (n % 2 == 0) { |
|---|
| 725 | start = n/2; |
|---|
| 726 | z = 1; |
|---|
| 727 | } else { |
|---|
| 728 | start = n/2 + 1; |
|---|
| 729 | z=2; |
|---|
| 730 | hroot[start-1] = 0.0; |
|---|
| 731 | } |
|---|
| 732 | for (ii = start; ii < n; ii++) { /* search only upwards*/ |
|---|
| 733 | hroot[ii] = halfroot(hermite,n,hroot[ii-1]+EPSILON, 1./n); |
|---|
| 734 | hroot[start - z] = -hroot[ii]; |
|---|
| 735 | z++; |
|---|
| 736 | } |
|---|
| 737 | } /* root_hermite */ |
|---|
| 738 | |
|---|
| 739 | |
|---|
| 740 | double halfroot(double (*func)(long m, double x), long n, double startx, |
|---|
| 741 | double delta) |
|---|
| 742 | { /* searches from the bound (startx) only in one direction |
|---|
| 743 | (by positive or negative delta, which results in |
|---|
| 744 | other-bound=startx+delta) |
|---|
| 745 | delta should be small. |
|---|
| 746 | (*func) is a function with two arguments */ |
|---|
| 747 | double xl; |
|---|
| 748 | double xu; |
|---|
| 749 | double xm; |
|---|
| 750 | double fu; |
|---|
| 751 | double fl; |
|---|
| 752 | double fm = 100000.; |
|---|
| 753 | double gradient; |
|---|
| 754 | boolean dwn; |
|---|
| 755 | |
|---|
| 756 | /* decide if we search above or below startx and escapes to trace back |
|---|
| 757 | to the starting point that most often will be |
|---|
| 758 | the root from the previous calculation */ |
|---|
| 759 | if (delta < 0) { |
|---|
| 760 | xu = startx; |
|---|
| 761 | xl = xu + delta; |
|---|
| 762 | } else { |
|---|
| 763 | xl = startx; |
|---|
| 764 | xu = xl + delta; |
|---|
| 765 | } |
|---|
| 766 | delta = fabs(delta); |
|---|
| 767 | fu = (*func)(n, xu); |
|---|
| 768 | fl = (*func)(n, xl); |
|---|
| 769 | gradient = (fl-fu)/(xl-xu); |
|---|
| 770 | while(fabs(fm) > EPSILON) { /* is root outside of our bracket?*/ |
|---|
| 771 | if ((fu<0.0 && fl<0.0) || (fu>0.0 && fl > 0.0)) { |
|---|
| 772 | xu += delta; |
|---|
| 773 | fu = (*func)(n, xu); |
|---|
| 774 | fl = (*func)(n, xl); |
|---|
| 775 | gradient = (fl-fu)/(xl-xu); |
|---|
| 776 | dwn = (gradient < 0.0) ? true : false; |
|---|
| 777 | } else { |
|---|
| 778 | xm = xl - fl / gradient; |
|---|
| 779 | fm = (*func)(n, xm); |
|---|
| 780 | if (dwn) { |
|---|
| 781 | if (fm > 0.) { |
|---|
| 782 | xl = xm; |
|---|
| 783 | fl = fm; |
|---|
| 784 | } else { |
|---|
| 785 | xu = xm; |
|---|
| 786 | fu = fm; |
|---|
| 787 | } |
|---|
| 788 | } else { |
|---|
| 789 | if (fm > 0.) { |
|---|
| 790 | xu = xm; |
|---|
| 791 | fu = fm; |
|---|
| 792 | } else { |
|---|
| 793 | xl = xm; |
|---|
| 794 | fl = fm; |
|---|
| 795 | } |
|---|
| 796 | } |
|---|
| 797 | gradient = (fl-fu)/(xl-xu); |
|---|
| 798 | } |
|---|
| 799 | } |
|---|
| 800 | return xm; |
|---|
| 801 | } /* halfroot */ |
|---|
| 802 | |
|---|
| 803 | |
|---|
| 804 | void hermite_weight(long n, double * hroot, double * weights) |
|---|
| 805 | { |
|---|
| 806 | /* calculate the weights for the hermite polynomial at the roots |
|---|
| 807 | using formula Abramowitz and Stegun chapter 25.4.46 p.890 */ |
|---|
| 808 | long i; |
|---|
| 809 | double hr2; |
|---|
| 810 | double numerator; |
|---|
| 811 | |
|---|
| 812 | numerator = exp(0.6931471805599 * ( n-1.) + logfac(n)) / (n*n); |
|---|
| 813 | for (i = 0; i < n; i++) { |
|---|
| 814 | hr2 = hermite(n-1, hroot[i]); |
|---|
| 815 | weights[i] = numerator / (hr2*hr2); |
|---|
| 816 | } |
|---|
| 817 | } /* hermiteweight */ |
|---|
| 818 | |
|---|
| 819 | |
|---|
| 820 | void inithermitcat(long categs, double alpha, double *rate, double *probcat) |
|---|
| 821 | { /* calculates rates and probabilities */ |
|---|
| 822 | long i; |
|---|
| 823 | double *hroot; |
|---|
| 824 | double std; |
|---|
| 825 | |
|---|
| 826 | std = SQRT2 /sqrt(alpha); |
|---|
| 827 | hroot = (double *) Malloc((categs+1) * sizeof(double)); |
|---|
| 828 | root_hermite(categs, hroot); /* calculate roots */ |
|---|
| 829 | hermite_weight(categs, hroot, probcat); /* set weights */ |
|---|
| 830 | for (i=0; i<categs; i++) { /* set rates */ |
|---|
| 831 | rate[i] = 1.0 + std * hroot[i]; |
|---|
| 832 | probcat[i] = probcat[i]; |
|---|
| 833 | } |
|---|
| 834 | free(hroot); |
|---|
| 835 | } /* inithermitcat */ |
|---|
| 836 | |
|---|
| 837 | |
|---|
| 838 | void initgammacat (long categs, double alpha, double *rate, double *probcat) |
|---|
| 839 | { /* calculate rates and probabilities to approximate Gamma distribution |
|---|
| 840 | of rates with "categs" categories and shape parameter "alpha" using |
|---|
| 841 | rates and weights from Generalized Laguerre quadrature or from |
|---|
| 842 | Hermite quadrature */ |
|---|
| 843 | |
|---|
| 844 | if (alpha >= 100.0) |
|---|
| 845 | inithermitcat(categs, alpha, rate, probcat); |
|---|
| 846 | else |
|---|
| 847 | initlaguerrecat(categs, alpha, rate, probcat); |
|---|
| 848 | } /* initgammacat */ |
|---|
| 849 | |
|---|
| 850 | |
|---|
| 851 | void inithowmany(long *howmany, long howoften) |
|---|
| 852 | {/* input how many cycles */ |
|---|
| 853 | long loopcount; |
|---|
| 854 | |
|---|
| 855 | loopcount = 0; |
|---|
| 856 | do { |
|---|
| 857 | printf("How many cycles of %4ld trees?\n", howoften); |
|---|
| 858 | scanf("%ld%*[^\n]", howmany); |
|---|
| 859 | getchar(); |
|---|
| 860 | countup(&loopcount, 10); |
|---|
| 861 | } while (*howmany <= 0); |
|---|
| 862 | } /*inithowmany*/ |
|---|
| 863 | |
|---|
| 864 | |
|---|
| 865 | |
|---|
| 866 | void inithowoften(long *howoften) |
|---|
| 867 | { /* input how many trees per cycle */ |
|---|
| 868 | long loopcount; |
|---|
| 869 | |
|---|
| 870 | loopcount = 0; |
|---|
| 871 | do { |
|---|
| 872 | printf("How many trees per cycle?\n"); |
|---|
| 873 | scanf("%ld%*[^\n]", howoften); |
|---|
| 874 | getchar(); |
|---|
| 875 | countup(&loopcount, 10); |
|---|
| 876 | } while (*howoften <= 0); |
|---|
| 877 | } /*inithowoften*/ |
|---|
| 878 | |
|---|
| 879 | |
|---|
| 880 | void initlambda(double *lambda) |
|---|
| 881 | { /* input patch length parameter for autocorrelated HMM rates */ |
|---|
| 882 | long loopcount; |
|---|
| 883 | |
|---|
| 884 | loopcount = 0; |
|---|
| 885 | do { |
|---|
| 886 | printf("Mean block length of sites having the same rate (greater than 1)?\n"); |
|---|
| 887 | scanf("%lf%*[^\n]", lambda); |
|---|
| 888 | getchar(); |
|---|
| 889 | countup(&loopcount, 10); |
|---|
| 890 | } while (*lambda <= 1.0); |
|---|
| 891 | *lambda = 1.0 / *lambda; |
|---|
| 892 | } /*initlambda*/ |
|---|
| 893 | |
|---|
| 894 | |
|---|
| 895 | void initfreqs(double *freqa, double *freqc, double *freqg, double *freqt) |
|---|
| 896 | { /* input frequencies of the four bases */ |
|---|
| 897 | char input[100]; |
|---|
| 898 | long scanned, loopcount; |
|---|
| 899 | |
|---|
| 900 | printf("Base frequencies for A, C, G, T/U (use blanks to separate)?\n"); |
|---|
| 901 | loopcount = 0; |
|---|
| 902 | do { |
|---|
| 903 | getstryng(input); |
|---|
| 904 | scanned = sscanf(input,"%lf%lf%lf%lf%*[^\n]", freqa, freqc, freqg, freqt); |
|---|
| 905 | if (scanned == 4) |
|---|
| 906 | break; |
|---|
| 907 | else |
|---|
| 908 | printf("Please enter exactly 4 values.\n"); |
|---|
| 909 | countup(&loopcount, 100); |
|---|
| 910 | } while (1); |
|---|
| 911 | } /* initfreqs */ |
|---|
| 912 | |
|---|
| 913 | |
|---|
| 914 | void initratio(double *ttratio) |
|---|
| 915 | { /* input transition/transversion ratio */ |
|---|
| 916 | long loopcount; |
|---|
| 917 | |
|---|
| 918 | loopcount = 0; |
|---|
| 919 | do { |
|---|
| 920 | printf("Transition/transversion ratio?\n"); |
|---|
| 921 | scanf("%lf%*[^\n]", ttratio); |
|---|
| 922 | getchar(); |
|---|
| 923 | countup(&loopcount, 10); |
|---|
| 924 | } while (*ttratio < 0.0); |
|---|
| 925 | } /* initratio */ |
|---|
| 926 | |
|---|
| 927 | |
|---|
| 928 | void initpower(double *power) |
|---|
| 929 | { |
|---|
| 930 | printf("New power?\n"); |
|---|
| 931 | scanf("%lf%*[^\n]", power); |
|---|
| 932 | getchar(); |
|---|
| 933 | } /*initpower*/ |
|---|
| 934 | |
|---|
| 935 | |
|---|
| 936 | void initdatasets(long *datasets) |
|---|
| 937 | { |
|---|
| 938 | /* handle multi-data set option */ |
|---|
| 939 | long loopcount; |
|---|
| 940 | boolean done; |
|---|
| 941 | |
|---|
| 942 | loopcount = 0; |
|---|
| 943 | do { |
|---|
| 944 | printf("How many data sets?\n"); |
|---|
| 945 | scanf("%ld%*[^\n]", datasets); |
|---|
| 946 | getchar(); |
|---|
| 947 | done = (*datasets > 1); |
|---|
| 948 | if (!done) |
|---|
| 949 | printf("Bad data sets number: it must be greater than 1\n"); |
|---|
| 950 | countup(&loopcount, 10); |
|---|
| 951 | } while (!done); |
|---|
| 952 | } /* initdatasets */ |
|---|
| 953 | |
|---|
| 954 | |
|---|
| 955 | void justweights(long *datasets) |
|---|
| 956 | { |
|---|
| 957 | /* handle multi-data set option by weights */ |
|---|
| 958 | long loopcount; |
|---|
| 959 | boolean done; |
|---|
| 960 | |
|---|
| 961 | loopcount = 0; |
|---|
| 962 | do { |
|---|
| 963 | printf("How many sets of weights?\n"); |
|---|
| 964 | scanf("%ld%*[^\n]", datasets); |
|---|
| 965 | getchar(); |
|---|
| 966 | done = (*datasets >= 1); |
|---|
| 967 | if (!done) |
|---|
| 968 | printf("BAD NUMBER: it must be greater than 1\n"); |
|---|
| 969 | countup(&loopcount, 10); |
|---|
| 970 | } while (!done); |
|---|
| 971 | } /* justweights */ |
|---|
| 972 | |
|---|
| 973 | |
|---|
| 974 | void initterminal(boolean *local_ibmpc, boolean *local_ansi) |
|---|
| 975 | { |
|---|
| 976 | /* handle terminal option */ |
|---|
| 977 | if (*local_ibmpc) { |
|---|
| 978 | *local_ibmpc = false; |
|---|
| 979 | *local_ansi = true; |
|---|
| 980 | } else if (*local_ansi) |
|---|
| 981 | *local_ansi = false; |
|---|
| 982 | else |
|---|
| 983 | *local_ibmpc = true; |
|---|
| 984 | } /*initterminal*/ |
|---|
| 985 | |
|---|
| 986 | |
|---|
| 987 | void initnumlines(long *screenlines) |
|---|
| 988 | { |
|---|
| 989 | long loopcount; |
|---|
| 990 | |
|---|
| 991 | loopcount = 0; |
|---|
| 992 | do { |
|---|
| 993 | *screenlines = readlong("Number of lines on screen?\n"); |
|---|
| 994 | countup(&loopcount, 10); |
|---|
| 995 | } while (*screenlines <= 12); |
|---|
| 996 | } /*initnumlines*/ |
|---|
| 997 | |
|---|
| 998 | |
|---|
| 999 | void initbestrees(bestelm *bestrees, long maxtrees, boolean glob) |
|---|
| 1000 | { |
|---|
| 1001 | /* initializes either global or local field of each array in bestrees */ |
|---|
| 1002 | long i; |
|---|
| 1003 | |
|---|
| 1004 | if (glob) |
|---|
| 1005 | for (i = 0; i < maxtrees; i++) |
|---|
| 1006 | bestrees[i].gloreange = false; |
|---|
| 1007 | else |
|---|
| 1008 | for (i = 0; i < maxtrees; i++) |
|---|
| 1009 | bestrees[i].locreange = false; |
|---|
| 1010 | } /* initbestrees */ |
|---|
| 1011 | |
|---|
| 1012 | |
|---|
| 1013 | void newline(FILE *filename, long i, long j, long k) |
|---|
| 1014 | { |
|---|
| 1015 | /* go to new line if i is a multiple of j, indent k spaces */ |
|---|
| 1016 | long m; |
|---|
| 1017 | |
|---|
| 1018 | if ((i - 1) % j != 0 || i <= 1) |
|---|
| 1019 | return; |
|---|
| 1020 | putc('\n', filename); |
|---|
| 1021 | for (m = 1; m <= k; m++) |
|---|
| 1022 | putc(' ', filename); |
|---|
| 1023 | } /* newline */ |
|---|
| 1024 | |
|---|
| 1025 | void inputnumbersold(long *local_spp, long *chars, long *nonodes, long n) |
|---|
| 1026 | { |
|---|
| 1027 | /* input the numbers of species and of characters */ |
|---|
| 1028 | |
|---|
| 1029 | if (fscanf(infile, "%ld%ld", local_spp, chars) != 2 || *local_spp <= 0 || *chars <= 0) { |
|---|
| 1030 | printf( |
|---|
| 1031 | "ERROR: Unable to read the number of species or characters in data set\n"); |
|---|
| 1032 | printf( |
|---|
| 1033 | "The input file is incorrect (perhaps it was not saved text only).\n"); |
|---|
| 1034 | } |
|---|
| 1035 | *nonodes = *local_spp * 2 - n; |
|---|
| 1036 | } /* inputnumbersold */ |
|---|
| 1037 | |
|---|
| 1038 | |
|---|
| 1039 | |
|---|
| 1040 | void inputnumbers(long *local_spp, long *chars, long *nonodes, long n) |
|---|
| 1041 | { |
|---|
| 1042 | /* input the numbers of species and of characters */ |
|---|
| 1043 | |
|---|
| 1044 | if (fscanf(infile, "%ld%ld", local_spp, chars) != 2 || *local_spp <= 0 || *chars <= 0) { |
|---|
| 1045 | printf( |
|---|
| 1046 | "ERROR: Unable to read the number of species or characters in data set\n"); |
|---|
| 1047 | printf( |
|---|
| 1048 | "The input file is incorrect (perhaps it was not saved text only).\n"); |
|---|
| 1049 | } |
|---|
| 1050 | fscanf(infile, "%*[^\n]"); |
|---|
| 1051 | *nonodes = *local_spp * 2 - n; |
|---|
| 1052 | } /* inputnumbers */ |
|---|
| 1053 | |
|---|
| 1054 | |
|---|
| 1055 | void inputnumbers2(long *local_spp, long *nonodes, long n) |
|---|
| 1056 | { |
|---|
| 1057 | /* read species number */ |
|---|
| 1058 | |
|---|
| 1059 | if (fscanf(infile, "%ld", local_spp) != 1 || *local_spp <= 0) { |
|---|
| 1060 | printf("ERROR: Unable to read the number of species in data set\n"); |
|---|
| 1061 | printf( |
|---|
| 1062 | "The input file is incorrect (perhaps it was not saved text only).\n"); |
|---|
| 1063 | } |
|---|
| 1064 | fscanf(infile, "%*[^\n]"); |
|---|
| 1065 | fprintf(outfile, "\n%4ld Populations\n", *local_spp); |
|---|
| 1066 | *nonodes = *local_spp * 2 - n; |
|---|
| 1067 | } /* inputnumbers2 */ |
|---|
| 1068 | |
|---|
| 1069 | |
|---|
| 1070 | void inputnumbers3(long *local_spp, long *chars) |
|---|
| 1071 | { |
|---|
| 1072 | /* input the numbers of species and of characters */ |
|---|
| 1073 | |
|---|
| 1074 | if (fscanf(infile, "%ld%ld", local_spp, chars) != 2 || *local_spp <= 0 || *chars <= 0) { |
|---|
| 1075 | printf( |
|---|
| 1076 | "ERROR: Unable to read the number of species or characters in data set\n"); |
|---|
| 1077 | printf( |
|---|
| 1078 | "The input file is incorrect (perhaps it was not saved text only).\n"); |
|---|
| 1079 | exxit(-1); |
|---|
| 1080 | } |
|---|
| 1081 | } /* inputnumbers3 */ |
|---|
| 1082 | |
|---|
| 1083 | |
|---|
| 1084 | void samenumsp(long *chars, long ith) |
|---|
| 1085 | { |
|---|
| 1086 | /* check if spp is same as the first set in other data sets */ |
|---|
| 1087 | long cursp, curchs; |
|---|
| 1088 | |
|---|
| 1089 | if (eoln(infile)) |
|---|
| 1090 | scan_eoln(infile); |
|---|
| 1091 | fscanf(infile, "%ld%ld", &cursp, &curchs); |
|---|
| 1092 | if (cursp != spp) { |
|---|
| 1093 | printf( |
|---|
| 1094 | "\n\nERROR: Inconsistent number of species in data set %ld\n\n", ith); |
|---|
| 1095 | exxit(-1); |
|---|
| 1096 | } |
|---|
| 1097 | *chars = curchs; |
|---|
| 1098 | } /* samenumsp */ |
|---|
| 1099 | |
|---|
| 1100 | |
|---|
| 1101 | void samenumsp2(long ith) |
|---|
| 1102 | { |
|---|
| 1103 | /* check if spp is same as the first set in other data sets */ |
|---|
| 1104 | long cursp; |
|---|
| 1105 | |
|---|
| 1106 | if (eoln(infile)) |
|---|
| 1107 | scan_eoln(infile); |
|---|
| 1108 | if (fscanf(infile, "%ld", &cursp) != 1) { |
|---|
| 1109 | printf("\n\nERROR: Unable to read number of species in data set %ld\n", |
|---|
| 1110 | ith); |
|---|
| 1111 | printf( |
|---|
| 1112 | "The input file is incorrect (perhaps it was not saved text only).\n"); |
|---|
| 1113 | exxit(-1); |
|---|
| 1114 | } |
|---|
| 1115 | if (cursp != spp) { |
|---|
| 1116 | printf( |
|---|
| 1117 | "\n\nERROR: Inconsistent number of species in data set %ld\n\n", ith); |
|---|
| 1118 | exxit(-1); |
|---|
| 1119 | } |
|---|
| 1120 | } /* samenumsp2 */ |
|---|
| 1121 | |
|---|
| 1122 | |
|---|
| 1123 | void readoptions(long *extranum, const char *options) |
|---|
| 1124 | { /* read option characters from input file */ |
|---|
| 1125 | Char ch; |
|---|
| 1126 | |
|---|
| 1127 | while (!(eoln(infile))) { |
|---|
| 1128 | ch = gettc(infile); |
|---|
| 1129 | uppercase(&ch); |
|---|
| 1130 | if (strchr(options, ch) != NULL) |
|---|
| 1131 | (* extranum)++; |
|---|
| 1132 | else if (!(ch == ' ' || ch == '\t')) { |
|---|
| 1133 | printf("BAD OPTION CHARACTER: %c\n", ch); |
|---|
| 1134 | exxit(-1); |
|---|
| 1135 | } |
|---|
| 1136 | } |
|---|
| 1137 | scan_eoln(infile); |
|---|
| 1138 | } /* readoptions */ |
|---|
| 1139 | |
|---|
| 1140 | |
|---|
| 1141 | void matchoptions(Char *ch, const char *options) |
|---|
| 1142 | { /* match option characters to those in auxiliary options line */ |
|---|
| 1143 | |
|---|
| 1144 | *ch = gettc(infile); |
|---|
| 1145 | uppercase(ch); |
|---|
| 1146 | if (strchr(options, *ch) == NULL) { |
|---|
| 1147 | printf("ERROR: Incorrect auxiliary options line"); |
|---|
| 1148 | printf(" which starts with %c\n", *ch); |
|---|
| 1149 | exxit(-1); |
|---|
| 1150 | } |
|---|
| 1151 | } /* matchoptions */ |
|---|
| 1152 | |
|---|
| 1153 | |
|---|
| 1154 | void inputweightsold(long chars, steptr weight, boolean *weights) |
|---|
| 1155 | { |
|---|
| 1156 | Char ch; |
|---|
| 1157 | int i; |
|---|
| 1158 | |
|---|
| 1159 | for (i = 1; i < nmlngth ; i++) |
|---|
| 1160 | getc(infile); |
|---|
| 1161 | |
|---|
| 1162 | for (i = 0; i < chars; i++) { |
|---|
| 1163 | do { |
|---|
| 1164 | if (eoln(infile)) |
|---|
| 1165 | scan_eoln(infile); |
|---|
| 1166 | ch = gettc(infile); |
|---|
| 1167 | if (ch == '\n') |
|---|
| 1168 | ch = ' '; |
|---|
| 1169 | } while (ch == ' '); |
|---|
| 1170 | weight[i] = 1; |
|---|
| 1171 | if (isdigit(ch)) |
|---|
| 1172 | weight[i] = ch - '0'; |
|---|
| 1173 | else if (isalpha(ch)) { |
|---|
| 1174 | uppercase(&ch); |
|---|
| 1175 | weight[i] = ch - 'A' + 10; |
|---|
| 1176 | } else { |
|---|
| 1177 | printf("\n\nERROR: Bad weight character: %c\n\n", ch); |
|---|
| 1178 | exxit(-1); |
|---|
| 1179 | } |
|---|
| 1180 | } |
|---|
| 1181 | scan_eoln(infile); |
|---|
| 1182 | *weights = true; |
|---|
| 1183 | } /*inputweightsold*/ |
|---|
| 1184 | |
|---|
| 1185 | void inputweights(long chars, steptr weight, boolean *weights) |
|---|
| 1186 | { |
|---|
| 1187 | /* input the character weights, 0-9 and A-Z for weights 0 - 35 */ |
|---|
| 1188 | Char ch; |
|---|
| 1189 | long i; |
|---|
| 1190 | |
|---|
| 1191 | for (i = 0; i < chars; i++) { |
|---|
| 1192 | do { |
|---|
| 1193 | if (eoln(weightfile)) |
|---|
| 1194 | scan_eoln(weightfile); |
|---|
| 1195 | ch = gettc(weightfile); |
|---|
| 1196 | if (ch == '\n') |
|---|
| 1197 | ch = ' '; |
|---|
| 1198 | } while (ch == ' '); |
|---|
| 1199 | weight[i] = 1; |
|---|
| 1200 | if (isdigit(ch)) |
|---|
| 1201 | weight[i] = ch - '0'; |
|---|
| 1202 | else if (isalpha(ch)) { |
|---|
| 1203 | uppercase(&ch); |
|---|
| 1204 | weight[i] = ch - 'A' + 10; |
|---|
| 1205 | } else { |
|---|
| 1206 | printf("\n\nERROR: Bad weight character: %c\n\n", ch); |
|---|
| 1207 | exxit(-1); |
|---|
| 1208 | } |
|---|
| 1209 | } |
|---|
| 1210 | scan_eoln(weightfile); |
|---|
| 1211 | *weights = true; |
|---|
| 1212 | } /* inputweights */ |
|---|
| 1213 | |
|---|
| 1214 | |
|---|
| 1215 | void inputweights2(long a, long b, long *weightsum, |
|---|
| 1216 | steptr weight, boolean *weights, const char *prog) |
|---|
| 1217 | { |
|---|
| 1218 | /* input the character weights, 0 or 1 */ |
|---|
| 1219 | Char ch; |
|---|
| 1220 | long i; |
|---|
| 1221 | |
|---|
| 1222 | *weightsum = 0; |
|---|
| 1223 | for (i = a; i < b; i++) { |
|---|
| 1224 | do { |
|---|
| 1225 | if (eoln(weightfile)) |
|---|
| 1226 | scan_eoln(weightfile); |
|---|
| 1227 | ch = gettc(weightfile); |
|---|
| 1228 | } while (ch == ' '); |
|---|
| 1229 | weight[i] = 1; |
|---|
| 1230 | if (ch == '0' || ch == '1') |
|---|
| 1231 | weight[i] = ch - '0'; |
|---|
| 1232 | else { |
|---|
| 1233 | printf("\n\nERROR: Bad weight character: %c -- ", ch); |
|---|
| 1234 | printf("weights in %s must be 0 or 1\n", prog); |
|---|
| 1235 | exxit(-1); |
|---|
| 1236 | } |
|---|
| 1237 | *weightsum += weight[i]; |
|---|
| 1238 | } |
|---|
| 1239 | *weights = true; |
|---|
| 1240 | scan_eoln(weightfile); |
|---|
| 1241 | } /* inputweights2 */ |
|---|
| 1242 | |
|---|
| 1243 | |
|---|
| 1244 | void printweights(FILE *filename, long inc, long chars, |
|---|
| 1245 | steptr weight, const char *letters) |
|---|
| 1246 | { |
|---|
| 1247 | /* print out the weights of sites */ |
|---|
| 1248 | long i, j; |
|---|
| 1249 | boolean letterweights; |
|---|
| 1250 | |
|---|
| 1251 | letterweights = false; |
|---|
| 1252 | for (i = 0; i < chars; i++) |
|---|
| 1253 | if (weight[i] > 9) |
|---|
| 1254 | letterweights = true; |
|---|
| 1255 | fprintf(filename, "\n %s are weighted as follows:",letters); |
|---|
| 1256 | if (letterweights) |
|---|
| 1257 | fprintf(filename, " (A = 10, B = 11, etc.)\n"); |
|---|
| 1258 | else |
|---|
| 1259 | putc('\n', filename); |
|---|
| 1260 | for (i = 0; i < chars; i++) { |
|---|
| 1261 | if (i % 60 == 0) { |
|---|
| 1262 | putc('\n', filename); |
|---|
| 1263 | for (j = 1; j <= nmlngth + 3; j++) |
|---|
| 1264 | putc(' ', filename); |
|---|
| 1265 | } |
|---|
| 1266 | if (weight[i+inc] < 10) |
|---|
| 1267 | fprintf(filename, "%ld", weight[i + inc]); |
|---|
| 1268 | else |
|---|
| 1269 | fprintf(filename, "%c", 'A'-10+(int)weight[i + inc]); |
|---|
| 1270 | if ((i+1) % 5 == 0 && (i+1) % 60 != 0) |
|---|
| 1271 | putc(' ', filename); |
|---|
| 1272 | } |
|---|
| 1273 | fprintf(filename, "\n\n"); |
|---|
| 1274 | } /* printweights */ |
|---|
| 1275 | |
|---|
| 1276 | |
|---|
| 1277 | void inputcategs(long a, long b, steptr category, long categs,const char *prog) |
|---|
| 1278 | { |
|---|
| 1279 | /* input the categories, 1-9 */ |
|---|
| 1280 | Char ch; |
|---|
| 1281 | long i; |
|---|
| 1282 | |
|---|
| 1283 | for (i = a; i < b; i++) { |
|---|
| 1284 | do { |
|---|
| 1285 | if (eoln(catfile)) |
|---|
| 1286 | scan_eoln(catfile); |
|---|
| 1287 | ch = gettc(catfile); |
|---|
| 1288 | } while (ch == ' '); |
|---|
| 1289 | if ((ch >= '1') && (ch <= ('0'+categs))) |
|---|
| 1290 | category[i] = ch - '0'; |
|---|
| 1291 | else { |
|---|
| 1292 | printf("\n\nERROR: Bad category character: %c", ch); |
|---|
| 1293 | printf(" -- categories in %s are currently 1-%ld\n", prog, categs); |
|---|
| 1294 | exxit(-1); |
|---|
| 1295 | } |
|---|
| 1296 | } |
|---|
| 1297 | scan_eoln(catfile); |
|---|
| 1298 | } /* inputcategs */ |
|---|
| 1299 | |
|---|
| 1300 | |
|---|
| 1301 | void printcategs(FILE *filename, long chars, steptr category, |
|---|
| 1302 | const char *letters) |
|---|
| 1303 | { |
|---|
| 1304 | /* print out the sitewise categories */ |
|---|
| 1305 | long i, j; |
|---|
| 1306 | |
|---|
| 1307 | fprintf(filename, "\n %s are:\n",letters); |
|---|
| 1308 | for (i = 0; i < chars; i++) { |
|---|
| 1309 | if (i % 60 == 0) { |
|---|
| 1310 | putc('\n', filename); |
|---|
| 1311 | for (j = 1; j <= nmlngth + 3; j++) |
|---|
| 1312 | putc(' ', filename); |
|---|
| 1313 | } |
|---|
| 1314 | fprintf(filename, "%ld", category[i]); |
|---|
| 1315 | if ((i+1) % 10 == 0 && (i+1) % 60 != 0) |
|---|
| 1316 | putc(' ', filename); |
|---|
| 1317 | } |
|---|
| 1318 | fprintf(filename, "\n\n"); |
|---|
| 1319 | } /* printcategs */ |
|---|
| 1320 | |
|---|
| 1321 | |
|---|
| 1322 | void inputfactors(long chars, Char *factor, boolean *factors) |
|---|
| 1323 | { |
|---|
| 1324 | /* reads the factor symbols */ |
|---|
| 1325 | long i; |
|---|
| 1326 | |
|---|
| 1327 | for (i = 1; i < nmlngth; i++) |
|---|
| 1328 | gettc(infile); |
|---|
| 1329 | for (i = 0; i < (chars); i++) { |
|---|
| 1330 | if (eoln(infile)) |
|---|
| 1331 | scan_eoln(infile); |
|---|
| 1332 | factor[i] = gettc(infile); |
|---|
| 1333 | if (factor[i] == '\n') |
|---|
| 1334 | factor[i] = ' '; |
|---|
| 1335 | } |
|---|
| 1336 | scan_eoln(infile); |
|---|
| 1337 | *factors = true; |
|---|
| 1338 | } /* inputfactors */ |
|---|
| 1339 | |
|---|
| 1340 | void inputfactorsnew(long chars, Char *factor, boolean *factors) |
|---|
| 1341 | { |
|---|
| 1342 | /* reads the factor symbols */ |
|---|
| 1343 | long i; |
|---|
| 1344 | |
|---|
| 1345 | for (i = 0; i < (chars); i++) { |
|---|
| 1346 | if (eoln(factfile)) |
|---|
| 1347 | scan_eoln(factfile); |
|---|
| 1348 | factor[i] = gettc(factfile); |
|---|
| 1349 | if (factor[i] == '\n') |
|---|
| 1350 | factor[i] = ' '; |
|---|
| 1351 | } |
|---|
| 1352 | scan_eoln(factfile); |
|---|
| 1353 | *factors = true; |
|---|
| 1354 | } /* inputfactorsnew */ |
|---|
| 1355 | |
|---|
| 1356 | void printfactors(FILE *filename, long chars, Char *factor, const char *letters) |
|---|
| 1357 | { |
|---|
| 1358 | /* print out list of factor symbols */ |
|---|
| 1359 | long i; |
|---|
| 1360 | |
|---|
| 1361 | fprintf(filename, "Factors%s:\n\n", letters); |
|---|
| 1362 | for (i = 1; i <= nmlngth - 5; i++) |
|---|
| 1363 | putc(' ', filename); |
|---|
| 1364 | for (i = 1; i <= (chars); i++) { |
|---|
| 1365 | newline(filename, i, 55, nmlngth + 3); |
|---|
| 1366 | putc(factor[i - 1], filename); |
|---|
| 1367 | if (i % 5 == 0) |
|---|
| 1368 | putc(' ', filename); |
|---|
| 1369 | } |
|---|
| 1370 | putc('\n', filename); |
|---|
| 1371 | } /* printfactors */ |
|---|
| 1372 | |
|---|
| 1373 | |
|---|
| 1374 | void headings(long chars, const char *letters1, const char *letters2) |
|---|
| 1375 | { |
|---|
| 1376 | long i, j; |
|---|
| 1377 | |
|---|
| 1378 | putc('\n', outfile); |
|---|
| 1379 | j = nmlngth + (chars + (chars - 1) / 10) / 2 - 5; |
|---|
| 1380 | if (j < nmlngth - 1) |
|---|
| 1381 | j = nmlngth - 1; |
|---|
| 1382 | if (j > 37) |
|---|
| 1383 | j = 37; |
|---|
| 1384 | fprintf(outfile, "Name"); |
|---|
| 1385 | for (i = 1; i <= j; i++) |
|---|
| 1386 | putc(' ', outfile); |
|---|
| 1387 | fprintf(outfile, "%s\n", letters1); |
|---|
| 1388 | fprintf(outfile, "----"); |
|---|
| 1389 | for (i = 1; i <= j; i++) |
|---|
| 1390 | putc(' ', outfile); |
|---|
| 1391 | fprintf(outfile, "%s\n\n", letters2); |
|---|
| 1392 | } /* headings */ |
|---|
| 1393 | |
|---|
| 1394 | |
|---|
| 1395 | void initname(long i) |
|---|
| 1396 | { |
|---|
| 1397 | /* read in species name */ |
|---|
| 1398 | long j; |
|---|
| 1399 | |
|---|
| 1400 | for (j = 0; j < nmlngth; j++) { |
|---|
| 1401 | if (eoff(infile) || eoln(infile)) { |
|---|
| 1402 | int j2; |
|---|
| 1403 | if (eoff(infile)) { |
|---|
| 1404 | printf("\n\nERROR: end-of-file"); |
|---|
| 1405 | } |
|---|
| 1406 | else { |
|---|
| 1407 | printf("\n\nERROR: end-of-line"); |
|---|
| 1408 | } |
|---|
| 1409 | |
|---|
| 1410 | printf(" in the middle of species name for species %ld (got '", i+1); |
|---|
| 1411 | for (j2 = 0; j2<j; ++j2) fputc(nayme[i][j2], stdout); |
|---|
| 1412 | printf("')\n\n"); |
|---|
| 1413 | exxit(-1); |
|---|
| 1414 | } |
|---|
| 1415 | nayme[i][j] = gettc(infile); |
|---|
| 1416 | if ((nayme[i][j] == '(') || (nayme[i][j] == ')') || (nayme[i][j] == ':') |
|---|
| 1417 | || (nayme[i][j] == ',') || (nayme[i][j] == ';') || (nayme[i][j] == '[') |
|---|
| 1418 | || (nayme[i][j] == ']')) { |
|---|
| 1419 | printf("\nERROR: Species name may not contain characters ( ) : ; , [ ] \n"); |
|---|
| 1420 | printf(" In name of species number %ld there is character %c\n\n", |
|---|
| 1421 | i+1, nayme[i][j]); |
|---|
| 1422 | exxit(-1); |
|---|
| 1423 | } |
|---|
| 1424 | } |
|---|
| 1425 | } /* initname */ |
|---|
| 1426 | |
|---|
| 1427 | |
|---|
| 1428 | void findtree(boolean *found,long *pos,long nextree,long *place,bestelm *bestrees) |
|---|
| 1429 | { |
|---|
| 1430 | /* finds tree given by array place in array bestrees by binary search */ |
|---|
| 1431 | /* used by dnacomp, dnapars, dollop, mix, & protpars */ |
|---|
| 1432 | long i, lower, upper; |
|---|
| 1433 | boolean below, done; |
|---|
| 1434 | |
|---|
| 1435 | below = false; |
|---|
| 1436 | lower = 1; |
|---|
| 1437 | upper = nextree - 1; |
|---|
| 1438 | (*found) = false; |
|---|
| 1439 | while (!(*found) && lower <= upper) { |
|---|
| 1440 | (*pos) = (lower + upper) / 2; |
|---|
| 1441 | i = 3; |
|---|
| 1442 | done = false; |
|---|
| 1443 | while (!done) { |
|---|
| 1444 | done = (i > spp); |
|---|
| 1445 | if (!done) |
|---|
| 1446 | done = (place[i - 1] != bestrees[(*pos) - 1].btree[i - 1]); |
|---|
| 1447 | if (!done) |
|---|
| 1448 | i++; |
|---|
| 1449 | } |
|---|
| 1450 | (*found) = (i > spp); |
|---|
| 1451 | if (*found) |
|---|
| 1452 | break; |
|---|
| 1453 | below = (place[i - 1] < bestrees[(*pos )- 1].btree[i - 1]); |
|---|
| 1454 | if (below) |
|---|
| 1455 | upper = (*pos) - 1; |
|---|
| 1456 | else |
|---|
| 1457 | lower = (*pos) + 1; |
|---|
| 1458 | } |
|---|
| 1459 | if (!(*found) && !below) |
|---|
| 1460 | (*pos)++; |
|---|
| 1461 | } /* findtree */ |
|---|
| 1462 | |
|---|
| 1463 | |
|---|
| 1464 | void addtree(long pos,long *nextree,boolean collapse,long *place,bestelm *bestrees) |
|---|
| 1465 | { |
|---|
| 1466 | /* puts tree from array place in its proper position in array bestrees */ |
|---|
| 1467 | /* used by dnacomp, dnapars, dollop, mix, & protpars */ |
|---|
| 1468 | long i; |
|---|
| 1469 | |
|---|
| 1470 | for (i = *nextree - 1; i >= pos; i--){ |
|---|
| 1471 | memcpy(bestrees[i].btree, bestrees[i - 1].btree, spp * sizeof(long)); |
|---|
| 1472 | bestrees[i].gloreange = bestrees[i - 1].gloreange; |
|---|
| 1473 | bestrees[i - 1].gloreange = false; |
|---|
| 1474 | bestrees[i].locreange = bestrees[i - 1].locreange; |
|---|
| 1475 | bestrees[i - 1].locreange = false; |
|---|
| 1476 | bestrees[i].collapse = bestrees[i - 1].collapse; |
|---|
| 1477 | } |
|---|
| 1478 | for (i = 0; i < spp; i++) |
|---|
| 1479 | bestrees[pos - 1].btree[i] = place[i]; |
|---|
| 1480 | bestrees[pos - 1].collapse = collapse; |
|---|
| 1481 | (*nextree)++; |
|---|
| 1482 | } /* addtree */ |
|---|
| 1483 | |
|---|
| 1484 | |
|---|
| 1485 | long findunrearranged(bestelm *bestrees, long nextree, boolean glob) |
|---|
| 1486 | { |
|---|
| 1487 | /* finds bestree with either global or local field false */ |
|---|
| 1488 | long i; |
|---|
| 1489 | |
|---|
| 1490 | if (glob) { |
|---|
| 1491 | for (i = 0; i < nextree - 1; i++) |
|---|
| 1492 | if (!bestrees[i].gloreange) |
|---|
| 1493 | return i; |
|---|
| 1494 | } else { |
|---|
| 1495 | for (i = 0; i < nextree - 1; i++) |
|---|
| 1496 | if (!bestrees[i].locreange) |
|---|
| 1497 | return i; |
|---|
| 1498 | } |
|---|
| 1499 | return -1; |
|---|
| 1500 | } /* findunrearranged */ |
|---|
| 1501 | |
|---|
| 1502 | |
|---|
| 1503 | boolean torearrange(bestelm *bestrees, long nextree) |
|---|
| 1504 | { /* sees if any best tree is yet to be rearranged */ |
|---|
| 1505 | |
|---|
| 1506 | if (findunrearranged(bestrees, nextree, true) >= 0) |
|---|
| 1507 | return true; |
|---|
| 1508 | else if (findunrearranged(bestrees, nextree, false) >= 0) |
|---|
| 1509 | return true; |
|---|
| 1510 | else |
|---|
| 1511 | return false; |
|---|
| 1512 | } /* torearrange */ |
|---|
| 1513 | |
|---|
| 1514 | |
|---|
| 1515 | void reducebestrees(bestelm *bestrees, long *nextree) |
|---|
| 1516 | { |
|---|
| 1517 | /* finds best trees with collapsible branches and deletes them */ |
|---|
| 1518 | long i, j; |
|---|
| 1519 | |
|---|
| 1520 | i = 0; |
|---|
| 1521 | j = *nextree - 2; |
|---|
| 1522 | do { |
|---|
| 1523 | while (!bestrees[i].collapse && i < *nextree - 1) i++; |
|---|
| 1524 | while (bestrees[j].collapse && j >= 0) j--; |
|---|
| 1525 | if (i < j) { |
|---|
| 1526 | memcpy(bestrees[i].btree, bestrees[j].btree, spp * sizeof(long)); |
|---|
| 1527 | bestrees[i].gloreange = bestrees[j].gloreange; |
|---|
| 1528 | bestrees[i].locreange = bestrees[j].locreange; |
|---|
| 1529 | bestrees[i].collapse = false; |
|---|
| 1530 | bestrees[j].collapse = true; |
|---|
| 1531 | } |
|---|
| 1532 | } while (i < j); |
|---|
| 1533 | *nextree = i + 1; |
|---|
| 1534 | } /* reducebestrees */ |
|---|
| 1535 | |
|---|
| 1536 | |
|---|
| 1537 | void shellsort(double *a, long *b, long n) |
|---|
| 1538 | { /* Shell sort keeping a, b in same order */ |
|---|
| 1539 | /* used by dnapenny, dolpenny, & penny */ |
|---|
| 1540 | long gap, i, j, itemp; |
|---|
| 1541 | double rtemp; |
|---|
| 1542 | |
|---|
| 1543 | gap = n / 2; |
|---|
| 1544 | while (gap > 0) { |
|---|
| 1545 | for (i = gap + 1; i <= n; i++) { |
|---|
| 1546 | j = i - gap; |
|---|
| 1547 | while (j > 0) { |
|---|
| 1548 | if (a[j - 1] > a[j + gap - 1]) { |
|---|
| 1549 | rtemp = a[j - 1]; |
|---|
| 1550 | a[j - 1] = a[j + gap - 1]; |
|---|
| 1551 | a[j + gap - 1] = rtemp; |
|---|
| 1552 | itemp = b[j - 1]; |
|---|
| 1553 | b[j - 1] = b[j + gap - 1]; |
|---|
| 1554 | b[j + gap - 1] = itemp; |
|---|
| 1555 | } |
|---|
| 1556 | j -= gap; |
|---|
| 1557 | } |
|---|
| 1558 | } |
|---|
| 1559 | gap /= 2; |
|---|
| 1560 | } |
|---|
| 1561 | } /* shellsort */ |
|---|
| 1562 | |
|---|
| 1563 | |
|---|
| 1564 | void getch(Char *c, long *parens, FILE *treefile) |
|---|
| 1565 | { /* get next nonblank character */ |
|---|
| 1566 | |
|---|
| 1567 | do { |
|---|
| 1568 | if (eoln(treefile)) |
|---|
| 1569 | scan_eoln(treefile); |
|---|
| 1570 | (*c) = gettc(treefile); |
|---|
| 1571 | |
|---|
| 1572 | if ((*c) == '\n' || (*c) == '\t') |
|---|
| 1573 | (*c) = ' '; |
|---|
| 1574 | } while ( *c == ' ' && !eoff(treefile) ); |
|---|
| 1575 | if ((*c) == '(') |
|---|
| 1576 | (*parens)++; |
|---|
| 1577 | if ((*c) == ')') |
|---|
| 1578 | (*parens)--; |
|---|
| 1579 | } /* getch */ |
|---|
| 1580 | |
|---|
| 1581 | |
|---|
| 1582 | void getch2(Char *c, long *parens) |
|---|
| 1583 | { /* get next nonblank character */ |
|---|
| 1584 | do { |
|---|
| 1585 | if (eoln(intree)) |
|---|
| 1586 | scan_eoln(intree); |
|---|
| 1587 | *c = gettc(intree); |
|---|
| 1588 | if (*c == '\n' || *c == '\t') |
|---|
| 1589 | *c = ' '; |
|---|
| 1590 | } while (!(*c != ' ' || eoff(intree))); |
|---|
| 1591 | if (*c == '(') |
|---|
| 1592 | (*parens)++; |
|---|
| 1593 | if (*c == ')') |
|---|
| 1594 | (*parens)--; |
|---|
| 1595 | } /* getch2 */ |
|---|
| 1596 | |
|---|
| 1597 | |
|---|
| 1598 | void findch(Char c, Char *ch, long which) |
|---|
| 1599 | { /* scan forward until find character c */ |
|---|
| 1600 | boolean done; |
|---|
| 1601 | long dummy_parens; |
|---|
| 1602 | done = false; |
|---|
| 1603 | while (!done) { |
|---|
| 1604 | if (c == ',') { |
|---|
| 1605 | if (*ch == '(' || *ch == ')' || *ch == ';') { |
|---|
| 1606 | printf( |
|---|
| 1607 | "\n\nERROR in user tree %ld: unmatched parenthesis or missing comma\n\n", |
|---|
| 1608 | which); |
|---|
| 1609 | exxit(-1); |
|---|
| 1610 | } else if (*ch == ',') |
|---|
| 1611 | done = true; |
|---|
| 1612 | } else if (c == ')') { |
|---|
| 1613 | if (*ch == '(' || *ch == ',' || *ch == ';') { |
|---|
| 1614 | printf("\n\nERROR in user tree %ld: ", which); |
|---|
| 1615 | printf("unmatched parenthesis or non-bifurcated node\n\n"); |
|---|
| 1616 | exxit(-1); |
|---|
| 1617 | } else { |
|---|
| 1618 | if (*ch == ')') |
|---|
| 1619 | done = true; |
|---|
| 1620 | } |
|---|
| 1621 | } else if (c == ';') { |
|---|
| 1622 | if (*ch != ';') { |
|---|
| 1623 | printf("\n\nERROR in user tree %ld: ", which); |
|---|
| 1624 | printf("unmatched parenthesis or missing semicolon\n\n"); |
|---|
| 1625 | exxit(-1); |
|---|
| 1626 | } else |
|---|
| 1627 | done = true; |
|---|
| 1628 | } |
|---|
| 1629 | if (*ch != ')' && done) |
|---|
| 1630 | continue; |
|---|
| 1631 | getch(ch, &dummy_parens, intree); |
|---|
| 1632 | } |
|---|
| 1633 | } /* findch */ |
|---|
| 1634 | |
|---|
| 1635 | |
|---|
| 1636 | void findch2(Char c, long *lparens, long *rparens, Char *ch) |
|---|
| 1637 | { /* skip forward in user tree until find character c */ |
|---|
| 1638 | boolean done; |
|---|
| 1639 | long dummy_parens; |
|---|
| 1640 | done = false; |
|---|
| 1641 | while (!done) { |
|---|
| 1642 | if (c == ',') { |
|---|
| 1643 | if (*ch == '(' || *ch == ')' || *ch == ':' || *ch == ';') { |
|---|
| 1644 | printf("\n\nERROR in user tree: "); |
|---|
| 1645 | printf("unmatched parenthesis, missing comma"); |
|---|
| 1646 | printf(" or non-trifurcated base\n\n"); |
|---|
| 1647 | exxit(-1); |
|---|
| 1648 | } else if (*ch == ',') |
|---|
| 1649 | done = true; |
|---|
| 1650 | } else if (c == ')') { |
|---|
| 1651 | if (*ch == '(' || *ch == ',' || *ch == ':' || *ch == ';') { |
|---|
| 1652 | printf( |
|---|
| 1653 | "\n\nERROR in user tree: unmatched parenthesis or non-bifurcated node\n\n"); |
|---|
| 1654 | exxit(-1); |
|---|
| 1655 | } else if (*ch == ')') { |
|---|
| 1656 | (*rparens)++; |
|---|
| 1657 | if ((*lparens) > 0 && (*lparens) == (*rparens)) { |
|---|
| 1658 | if ((*lparens) == spp - 2) { |
|---|
| 1659 | getch(ch, &dummy_parens, intree); |
|---|
| 1660 | if (*ch != ';') { |
|---|
| 1661 | printf( "\n\nERROR in user tree: "); |
|---|
| 1662 | printf("unmatched parenthesis or missing semicolon\n\n"); |
|---|
| 1663 | exxit(-1); |
|---|
| 1664 | } |
|---|
| 1665 | } |
|---|
| 1666 | } |
|---|
| 1667 | done = true; |
|---|
| 1668 | } |
|---|
| 1669 | } |
|---|
| 1670 | if (*ch != ')' && done) |
|---|
| 1671 | continue; |
|---|
| 1672 | if (*ch == ')') |
|---|
| 1673 | getch(ch, &dummy_parens, intree); |
|---|
| 1674 | } |
|---|
| 1675 | } /* findch2 */ |
|---|
| 1676 | |
|---|
| 1677 | void processlength(double *valyew, double *divisor, Char *ch, |
|---|
| 1678 | boolean *minusread, FILE *treefile, long *parens) |
|---|
| 1679 | { /* read a branch length from a treefile */ |
|---|
| 1680 | long digit, ordzero; |
|---|
| 1681 | boolean pointread; |
|---|
| 1682 | |
|---|
| 1683 | ordzero = '0'; |
|---|
| 1684 | *minusread = false; |
|---|
| 1685 | pointread = false; |
|---|
| 1686 | *valyew = 0.0; |
|---|
| 1687 | *divisor = 1.0; |
|---|
| 1688 | getch(ch, parens, treefile); |
|---|
| 1689 | digit = (long)(*ch - ordzero); |
|---|
| 1690 | while ( ((digit <= 9) && (digit >= 0)) || *ch == '.' || *ch == '-') { |
|---|
| 1691 | if (*ch == '.' ) |
|---|
| 1692 | pointread = true; |
|---|
| 1693 | else if (*ch == '-' ) |
|---|
| 1694 | *minusread = true; |
|---|
| 1695 | else { |
|---|
| 1696 | *valyew = *valyew * 10.0 + digit; |
|---|
| 1697 | if (pointread) |
|---|
| 1698 | *divisor *= 10.0; |
|---|
| 1699 | } |
|---|
| 1700 | getch(ch, parens, treefile); |
|---|
| 1701 | digit = (long)(*ch - ordzero); |
|---|
| 1702 | } |
|---|
| 1703 | if (*minusread) |
|---|
| 1704 | *valyew = -(*valyew); |
|---|
| 1705 | } /* processlength */ |
|---|
| 1706 | |
|---|
| 1707 | |
|---|
| 1708 | void writename(long start, long n, long *enterorder) |
|---|
| 1709 | { /* write species name and number in entry order */ |
|---|
| 1710 | long i, j; |
|---|
| 1711 | |
|---|
| 1712 | for (i = start; i < start+n; i++) { |
|---|
| 1713 | printf(" %3ld. ", i+1); |
|---|
| 1714 | for (j = 0; j < nmlngth; j++) |
|---|
| 1715 | putchar(nayme[enterorder[i] - 1][j]); |
|---|
| 1716 | putchar('\n'); |
|---|
| 1717 | fflush(stdout); |
|---|
| 1718 | } |
|---|
| 1719 | } /* writename */ |
|---|
| 1720 | |
|---|
| 1721 | |
|---|
| 1722 | void memerror() |
|---|
| 1723 | { |
|---|
| 1724 | printf("Error allocating memory\n"); |
|---|
| 1725 | exxit(-1); |
|---|
| 1726 | } /* memerror */ |
|---|
| 1727 | |
|---|
| 1728 | |
|---|
| 1729 | void odd_malloc(long x) |
|---|
| 1730 | { /* error message if attempt to malloc too little or too much memory */ |
|---|
| 1731 | printf ("ERROR: a function asked for an inappropriate amount of memory:"); |
|---|
| 1732 | printf (" %ld bytes\n", x); |
|---|
| 1733 | printf (" This can mean one of two things:\n"); |
|---|
| 1734 | printf (" 1. The input file is incorrect"); |
|---|
| 1735 | printf (" (perhaps it was not saved as Text Only),\n"); |
|---|
| 1736 | printf (" 2. There is a bug in the program.\n"); |
|---|
| 1737 | printf (" Please check your input file carefully.\n"); |
|---|
| 1738 | printf (" If it seems to be a bug, please mail joe@gs.washington.edu\n"); |
|---|
| 1739 | printf (" with the name of the program, your computer system type,\n"); |
|---|
| 1740 | printf (" a full description of the problem, and with the input data file.\n"); |
|---|
| 1741 | printf (" (which should be in the body of the message, not as an Attachment).\n"); |
|---|
| 1742 | |
|---|
| 1743 | /* abort() can be used to crash |
|---|
| 1744 | * for debugging */ |
|---|
| 1745 | |
|---|
| 1746 | exxit(-1); |
|---|
| 1747 | } |
|---|
| 1748 | |
|---|
| 1749 | |
|---|
| 1750 | MALLOCRETURN *mymalloc(long x) |
|---|
| 1751 | { /* wrapper for malloc, allowing error message if too little, too much */ |
|---|
| 1752 | MALLOCRETURN *new_block; |
|---|
| 1753 | |
|---|
| 1754 | if ((x <= 0) || |
|---|
| 1755 | (x > TOO_MUCH_MEMORY)) |
|---|
| 1756 | odd_malloc(x); |
|---|
| 1757 | |
|---|
| 1758 | new_block = (MALLOCRETURN *)calloc(1,x); |
|---|
| 1759 | |
|---|
| 1760 | if (!new_block) { |
|---|
| 1761 | memerror(); |
|---|
| 1762 | return (MALLOCRETURN *) new_block; |
|---|
| 1763 | } else |
|---|
| 1764 | return (MALLOCRETURN *) new_block; |
|---|
| 1765 | } /* mymalloc */ |
|---|
| 1766 | |
|---|
| 1767 | |
|---|
| 1768 | void gnu(node **grbg, node **p) |
|---|
| 1769 | { /* this and the following are do-it-yourself garbage collectors. |
|---|
| 1770 | Make a new node or pull one off the garbage list */ |
|---|
| 1771 | |
|---|
| 1772 | if (*grbg != NULL) { |
|---|
| 1773 | *p = *grbg; |
|---|
| 1774 | *grbg = (*grbg)->next; |
|---|
| 1775 | } else |
|---|
| 1776 | *p = (node *)Malloc(sizeof(node)); |
|---|
| 1777 | |
|---|
| 1778 | (*p)->back = NULL; |
|---|
| 1779 | (*p)->next = NULL; |
|---|
| 1780 | (*p)->tip = false; |
|---|
| 1781 | (*p)->times_in_tree = 0.0; |
|---|
| 1782 | (*p)->r = 0.0; |
|---|
| 1783 | (*p)->theta = 0.0; |
|---|
| 1784 | (*p)->x = NULL; |
|---|
| 1785 | (*p)->protx = NULL; /* for the sake of proml */ |
|---|
| 1786 | } /* gnu */ |
|---|
| 1787 | |
|---|
| 1788 | |
|---|
| 1789 | void chuck(node **grbg, node *p) |
|---|
| 1790 | { /* collect garbage on p -- put it on front of garbage list */ |
|---|
| 1791 | p->back = NULL; |
|---|
| 1792 | p->next = *grbg; |
|---|
| 1793 | *grbg = p; |
|---|
| 1794 | } /* chuck */ |
|---|
| 1795 | |
|---|
| 1796 | |
|---|
| 1797 | void zeronumnuc(node *p, long endsite) |
|---|
| 1798 | { |
|---|
| 1799 | long i,j; |
|---|
| 1800 | |
|---|
| 1801 | for (i = 0; i < endsite; i++) |
|---|
| 1802 | for (j = (long)A; j <= (long)O; j++) |
|---|
| 1803 | p->numnuc[i][j] = 0; |
|---|
| 1804 | } /* zeronumnuc */ |
|---|
| 1805 | |
|---|
| 1806 | |
|---|
| 1807 | void zerodiscnumnuc(node *p, long endsite) |
|---|
| 1808 | { |
|---|
| 1809 | long i,j; |
|---|
| 1810 | |
|---|
| 1811 | for (i = 0; i < endsite; i++) |
|---|
| 1812 | for (j = (long)ZERO; j <= (long)SEVEN; j++) |
|---|
| 1813 | p->discnumnuc[i][j] = 0; |
|---|
| 1814 | } /* zerodiscnumnuc */ |
|---|
| 1815 | |
|---|
| 1816 | |
|---|
| 1817 | void allocnontip(node *p, long *zeros, long endsite) |
|---|
| 1818 | { /* allocate an interior node */ |
|---|
| 1819 | /* used by dnacomp, dnapars, & dnapenny */ |
|---|
| 1820 | |
|---|
| 1821 | p->numsteps = (steptr)Malloc(endsite*sizeof(long)); |
|---|
| 1822 | p->oldnumsteps = (steptr)Malloc(endsite*sizeof(long)); |
|---|
| 1823 | p->base = (baseptr)Malloc(endsite*sizeof(long)); |
|---|
| 1824 | p->oldbase = (baseptr)Malloc(endsite*sizeof(long)); |
|---|
| 1825 | p->numnuc = (nucarray *)Malloc(endsite*sizeof(nucarray)); |
|---|
| 1826 | memcpy(p->base, zeros, endsite*sizeof(long)); |
|---|
| 1827 | memcpy(p->numsteps, zeros, endsite*sizeof(long)); |
|---|
| 1828 | memcpy(p->oldbase, zeros, endsite*sizeof(long)); |
|---|
| 1829 | memcpy(p->oldnumsteps, zeros, endsite*sizeof(long)); |
|---|
| 1830 | zeronumnuc(p, endsite); |
|---|
| 1831 | } /* allocnontip */ |
|---|
| 1832 | |
|---|
| 1833 | |
|---|
| 1834 | void allocdiscnontip(node *p, long *zeros, unsigned char *zeros2, long endsite) |
|---|
| 1835 | { /* allocate an interior node */ |
|---|
| 1836 | /* used by pars */ |
|---|
| 1837 | |
|---|
| 1838 | p->numsteps = (steptr)Malloc(endsite*sizeof(long)); |
|---|
| 1839 | p->oldnumsteps = (steptr)Malloc(endsite*sizeof(long)); |
|---|
| 1840 | p->discbase = (discbaseptr)Malloc(endsite*sizeof(unsigned char)); |
|---|
| 1841 | p->olddiscbase = (discbaseptr)Malloc(endsite*sizeof(unsigned char)); |
|---|
| 1842 | p->discnumnuc = (discnucarray *)Malloc(endsite*sizeof(discnucarray)); |
|---|
| 1843 | memcpy(p->discbase, zeros2, endsite*sizeof(unsigned char)); |
|---|
| 1844 | memcpy(p->numsteps, zeros, endsite*sizeof(long)); |
|---|
| 1845 | memcpy(p->olddiscbase, zeros2, endsite*sizeof(unsigned char)); |
|---|
| 1846 | memcpy(p->oldnumsteps, zeros, endsite*sizeof(long)); |
|---|
| 1847 | zerodiscnumnuc(p, endsite); |
|---|
| 1848 | } /* allocdiscnontip */ |
|---|
| 1849 | |
|---|
| 1850 | |
|---|
| 1851 | void allocnode(node **anode, long *zeros, long endsite) |
|---|
| 1852 | { /* allocate a node */ |
|---|
| 1853 | /* used by dnacomp, dnapars, & dnapenny */ |
|---|
| 1854 | |
|---|
| 1855 | *anode = (node *)Malloc(sizeof(node)); |
|---|
| 1856 | allocnontip(*anode, zeros, endsite); |
|---|
| 1857 | } /* allocnode */ |
|---|
| 1858 | |
|---|
| 1859 | |
|---|
| 1860 | void allocdiscnode(node **anode, long *zeros, unsigned char *zeros2, |
|---|
| 1861 | long endsite) |
|---|
| 1862 | { /* allocate a node */ |
|---|
| 1863 | /* used by pars */ |
|---|
| 1864 | |
|---|
| 1865 | *anode = (node *)Malloc(sizeof(node)); |
|---|
| 1866 | allocdiscnontip(*anode, zeros, zeros2, endsite); |
|---|
| 1867 | } /* allocdiscnontip */ |
|---|
| 1868 | |
|---|
| 1869 | |
|---|
| 1870 | void gnutreenode(node **grbg, node **p, long i, long endsite, long *zeros) |
|---|
| 1871 | { /* this and the following are do-it-yourself garbage collectors. |
|---|
| 1872 | Make a new node or pull one off the garbage list */ |
|---|
| 1873 | |
|---|
| 1874 | if (*grbg != NULL) { |
|---|
| 1875 | *p = *grbg; |
|---|
| 1876 | *grbg = (*grbg)->next; |
|---|
| 1877 | memcpy((*p)->numsteps, zeros, endsite*sizeof(long)); |
|---|
| 1878 | memcpy((*p)->oldnumsteps, zeros, endsite*sizeof(long)); |
|---|
| 1879 | memcpy((*p)->base, zeros, endsite*sizeof(long)); |
|---|
| 1880 | memcpy((*p)->oldbase, zeros, endsite*sizeof(long)); |
|---|
| 1881 | zeronumnuc(*p, endsite); |
|---|
| 1882 | } else |
|---|
| 1883 | allocnode(p, zeros, endsite); |
|---|
| 1884 | (*p)->back = NULL; |
|---|
| 1885 | (*p)->next = NULL; |
|---|
| 1886 | (*p)->tip = false; |
|---|
| 1887 | (*p)->visited = false; |
|---|
| 1888 | (*p)->index = i; |
|---|
| 1889 | (*p)->numdesc = 0; |
|---|
| 1890 | (*p)->sumsteps = 0.0; |
|---|
| 1891 | } /* gnutreenode */ |
|---|
| 1892 | |
|---|
| 1893 | |
|---|
| 1894 | void gnudisctreenode(node **grbg, node **p, long i, |
|---|
| 1895 | long endsite, long *zeros, unsigned char *zeros2) |
|---|
| 1896 | { /* this and the following are do-it-yourself garbage collectors. |
|---|
| 1897 | Make a new node or pull one off the garbage list */ |
|---|
| 1898 | |
|---|
| 1899 | if (*grbg != NULL) { |
|---|
| 1900 | *p = *grbg; |
|---|
| 1901 | *grbg = (*grbg)->next; |
|---|
| 1902 | memcpy((*p)->numsteps, zeros, endsite*sizeof(long)); |
|---|
| 1903 | memcpy((*p)->oldnumsteps, zeros, endsite*sizeof(long)); |
|---|
| 1904 | memcpy((*p)->discbase, zeros2, endsite*sizeof(unsigned char)); |
|---|
| 1905 | memcpy((*p)->olddiscbase, zeros2, endsite*sizeof(unsigned char)); |
|---|
| 1906 | zerodiscnumnuc(*p, endsite); |
|---|
| 1907 | } else |
|---|
| 1908 | allocdiscnode(p, zeros, zeros2, endsite); |
|---|
| 1909 | (*p)->back = NULL; |
|---|
| 1910 | (*p)->next = NULL; |
|---|
| 1911 | (*p)->tip = false; |
|---|
| 1912 | (*p)->visited = false; |
|---|
| 1913 | (*p)->index = i; |
|---|
| 1914 | (*p)->numdesc = 0; |
|---|
| 1915 | (*p)->sumsteps = 0.0; |
|---|
| 1916 | } /* gnudisctreenode */ |
|---|
| 1917 | |
|---|
| 1918 | |
|---|
| 1919 | void chucktreenode(node **grbg, node *p) |
|---|
| 1920 | { /* collect garbage on p -- put it on front of garbage list */ |
|---|
| 1921 | |
|---|
| 1922 | p->back = NULL; |
|---|
| 1923 | p->next = *grbg; |
|---|
| 1924 | *grbg = p; |
|---|
| 1925 | } /* chucktreenode */ |
|---|
| 1926 | |
|---|
| 1927 | |
|---|
| 1928 | void setupnode(node *p, long i) |
|---|
| 1929 | { /* initialization of node pointers, variables */ |
|---|
| 1930 | |
|---|
| 1931 | p->next = NULL; |
|---|
| 1932 | p->back = NULL; |
|---|
| 1933 | p->times_in_tree = (double) i * 1.0; |
|---|
| 1934 | p->index = i; |
|---|
| 1935 | p->tip = false; |
|---|
| 1936 | } /* setupnode */ |
|---|
| 1937 | |
|---|
| 1938 | |
|---|
| 1939 | long count_sibs (node *p) |
|---|
| 1940 | { /* Count the number of nodes in a ring, return the total number of */ |
|---|
| 1941 | /* nodes excluding the one passed into the function (siblings) */ |
|---|
| 1942 | node *q; |
|---|
| 1943 | long return_int = 0; |
|---|
| 1944 | |
|---|
| 1945 | if (p->tip) { |
|---|
| 1946 | printf ("Error: the function count_sibs called on a tip. This is a bug.\n"); |
|---|
| 1947 | exxit (-1); |
|---|
| 1948 | } |
|---|
| 1949 | |
|---|
| 1950 | q = p->next; |
|---|
| 1951 | while (q != p) { |
|---|
| 1952 | if (q == NULL) { |
|---|
| 1953 | printf ("Error: a loop of nodes was not closed.\n"); |
|---|
| 1954 | exxit (-1); |
|---|
| 1955 | } else { |
|---|
| 1956 | return_int++; |
|---|
| 1957 | q = q->next; |
|---|
| 1958 | } |
|---|
| 1959 | } |
|---|
| 1960 | |
|---|
| 1961 | return return_int; |
|---|
| 1962 | } /* count_sibs */ |
|---|
| 1963 | |
|---|
| 1964 | |
|---|
| 1965 | void inittrav (node *p) |
|---|
| 1966 | { /* traverse to set pointers uninitialized on inserting */ |
|---|
| 1967 | long i, num_sibs; |
|---|
| 1968 | node *sib_ptr; |
|---|
| 1969 | |
|---|
| 1970 | if (p == NULL) |
|---|
| 1971 | return; |
|---|
| 1972 | if (p->tip) |
|---|
| 1973 | return; |
|---|
| 1974 | num_sibs = count_sibs (p); |
|---|
| 1975 | sib_ptr = p; |
|---|
| 1976 | for (i=0; i < num_sibs; i++) { |
|---|
| 1977 | sib_ptr = sib_ptr->next; |
|---|
| 1978 | sib_ptr->initialized = false; |
|---|
| 1979 | inittrav(sib_ptr->back); |
|---|
| 1980 | } |
|---|
| 1981 | } /* inittrav */ |
|---|
| 1982 | |
|---|
| 1983 | |
|---|
| 1984 | void commentskipper(FILE ***fppp_intree, long *bracket) |
|---|
| 1985 | { /* skip over comment bracket contents in reading tree */ |
|---|
| 1986 | char c; |
|---|
| 1987 | |
|---|
| 1988 | c = gettc(**fppp_intree); |
|---|
| 1989 | |
|---|
| 1990 | while (c != ']') { |
|---|
| 1991 | |
|---|
| 1992 | if(feof(**fppp_intree)) { |
|---|
| 1993 | printf("\n\nERROR: Unmatched comment brackets\n\n"); |
|---|
| 1994 | exxit(-1); |
|---|
| 1995 | } |
|---|
| 1996 | |
|---|
| 1997 | if(c == '[') { |
|---|
| 1998 | (*bracket)++; |
|---|
| 1999 | commentskipper(fppp_intree, bracket); |
|---|
| 2000 | } |
|---|
| 2001 | c = gettc(**fppp_intree); |
|---|
| 2002 | } |
|---|
| 2003 | (*bracket)--; |
|---|
| 2004 | } /* commentskipper */ |
|---|
| 2005 | |
|---|
| 2006 | |
|---|
| 2007 | long countcomma(FILE **treefile, long *comma) |
|---|
| 2008 | { |
|---|
| 2009 | /* Modified by Dan F. 11/10/96 */ |
|---|
| 2010 | |
|---|
| 2011 | /* The next line inserted so this function leaves the file pointing |
|---|
| 2012 | to where it found it, not just re-winding it. */ |
|---|
| 2013 | long orig_position = ftell (*treefile); |
|---|
| 2014 | |
|---|
| 2015 | Char c; |
|---|
| 2016 | long lparen = 0; |
|---|
| 2017 | long bracket = 0; |
|---|
| 2018 | (*comma) = 0; |
|---|
| 2019 | |
|---|
| 2020 | |
|---|
| 2021 | for (;;){ |
|---|
| 2022 | c = getc(*treefile); |
|---|
| 2023 | if (feof(*treefile)) |
|---|
| 2024 | break; |
|---|
| 2025 | if (c == ';') |
|---|
| 2026 | break; |
|---|
| 2027 | if (c == ',') |
|---|
| 2028 | (*comma)++; |
|---|
| 2029 | if (c == '(') |
|---|
| 2030 | lparen++; |
|---|
| 2031 | if (c == '[') { |
|---|
| 2032 | bracket++; |
|---|
| 2033 | commentskipper(&treefile, &bracket); |
|---|
| 2034 | } |
|---|
| 2035 | } |
|---|
| 2036 | |
|---|
| 2037 | /* Don't just rewind, */ |
|---|
| 2038 | /* rewind (*treefile); */ |
|---|
| 2039 | /* Re-set to where it pointed when the function was called */ |
|---|
| 2040 | |
|---|
| 2041 | fseek (*treefile, orig_position, SEEK_SET); |
|---|
| 2042 | |
|---|
| 2043 | return lparen + (*comma); |
|---|
| 2044 | } /*countcomma*/ |
|---|
| 2045 | /* countcomma rewritten so it passes back both lparen+comma to allocate nodep |
|---|
| 2046 | and a pointer to the comma variable. This allows the tree to know how many |
|---|
| 2047 | species exist, and the tips to be placed in the front of the nodep array */ |
|---|
| 2048 | |
|---|
| 2049 | |
|---|
| 2050 | long countsemic(FILE **treefile) |
|---|
| 2051 | { /* Used to determine the number of user trees. Return |
|---|
| 2052 | either a: the number of semicolons in the file outside comments |
|---|
| 2053 | or b: the first integer in the file */ |
|---|
| 2054 | Char c; |
|---|
| 2055 | long return_val, semic = 0; |
|---|
| 2056 | long bracket = 0; |
|---|
| 2057 | |
|---|
| 2058 | /* Eat all whitespace */ |
|---|
| 2059 | c = gettc(*treefile); |
|---|
| 2060 | while ((c == ' ') || |
|---|
| 2061 | (c == '\t') || |
|---|
| 2062 | (c == '\n')) { |
|---|
| 2063 | c = gettc(*treefile); |
|---|
| 2064 | } |
|---|
| 2065 | |
|---|
| 2066 | /* Then figure out if the first non-white character is a digit; if |
|---|
| 2067 | so, return it */ |
|---|
| 2068 | if (isdigit (c)) { |
|---|
| 2069 | return_val = atoi(&c); |
|---|
| 2070 | } else { |
|---|
| 2071 | |
|---|
| 2072 | /* Loop past all characters, count the number of semicolons |
|---|
| 2073 | outside of comments */ |
|---|
| 2074 | for (;;){ |
|---|
| 2075 | c = fgetc(*treefile); |
|---|
| 2076 | if (feof(*treefile)) |
|---|
| 2077 | break; |
|---|
| 2078 | if (c == ';') |
|---|
| 2079 | semic++; |
|---|
| 2080 | if (c == '[') { |
|---|
| 2081 | bracket++; |
|---|
| 2082 | commentskipper(&treefile, &bracket); |
|---|
| 2083 | } |
|---|
| 2084 | } |
|---|
| 2085 | return_val = semic; |
|---|
| 2086 | } |
|---|
| 2087 | |
|---|
| 2088 | rewind (*treefile); |
|---|
| 2089 | return return_val; |
|---|
| 2090 | } /* countsemic */ |
|---|
| 2091 | |
|---|
| 2092 | |
|---|
| 2093 | void hookup(node *p, node *q) |
|---|
| 2094 | { /* hook together two nodes */ |
|---|
| 2095 | |
|---|
| 2096 | p->back = q; |
|---|
| 2097 | q->back = p; |
|---|
| 2098 | } /* hookup */ |
|---|
| 2099 | |
|---|
| 2100 | |
|---|
| 2101 | void link_trees(long local_nextnum, long nodenum, long local_nodenum, |
|---|
| 2102 | pointarray nodep) |
|---|
| 2103 | { |
|---|
| 2104 | if(local_nextnum == 0) |
|---|
| 2105 | hookup(nodep[nodenum],nodep[local_nodenum]); |
|---|
| 2106 | else if(local_nextnum == 1) |
|---|
| 2107 | hookup(nodep[nodenum], nodep[local_nodenum]->next); |
|---|
| 2108 | else if(local_nextnum == 2) |
|---|
| 2109 | hookup(nodep[nodenum],nodep[local_nodenum]->next->next); |
|---|
| 2110 | else |
|---|
| 2111 | printf("Error in Link_Trees()"); |
|---|
| 2112 | } /* link_trees() */ |
|---|
| 2113 | |
|---|
| 2114 | |
|---|
| 2115 | void allocate_nodep(pointarray *nodep, FILE **treefile, long *precalc_tips) |
|---|
| 2116 | { /* pre-compute space and allocate memory for nodep */ |
|---|
| 2117 | |
|---|
| 2118 | long numnodes; /* returns number commas & ( */ |
|---|
| 2119 | long numcom = 0; /* returns number commas */ |
|---|
| 2120 | |
|---|
| 2121 | numnodes = countcomma(treefile, &numcom) + 1; |
|---|
| 2122 | *nodep = (pointarray)Malloc(2*numnodes*sizeof(node *)); |
|---|
| 2123 | |
|---|
| 2124 | (*precalc_tips) = numcom + 1; /* this will be used in placing the |
|---|
| 2125 | tip nodes in the front region of |
|---|
| 2126 | nodep. Used for species check? */ |
|---|
| 2127 | } /* allocate_nodep -plc */ |
|---|
| 2128 | |
|---|
| 2129 | |
|---|
| 2130 | void malloc_pheno (node *p, long endsite, long rcategs) |
|---|
| 2131 | { /* Allocate the phenotype arrays; used by dnaml */ |
|---|
| 2132 | long i; |
|---|
| 2133 | |
|---|
| 2134 | p->x = (phenotype)Malloc(endsite*sizeof(ratelike)); |
|---|
| 2135 | for (i = 0; i < endsite; i++) |
|---|
| 2136 | p->x[i] = (ratelike)Malloc(rcategs*sizeof(sitelike)); |
|---|
| 2137 | } /* malloc_pheno */ |
|---|
| 2138 | |
|---|
| 2139 | |
|---|
| 2140 | void malloc_ppheno (node *p,long endsite, long rcategs) |
|---|
| 2141 | { |
|---|
| 2142 | /* Allocate the phenotype arrays; used by proml */ |
|---|
| 2143 | long i; |
|---|
| 2144 | |
|---|
| 2145 | p->protx = (pphenotype)Malloc(endsite*sizeof(pratelike)); |
|---|
| 2146 | for (i = 0; i < endsite; i++) |
|---|
| 2147 | p->protx[i] = (pratelike)Malloc(rcategs*sizeof(psitelike)); |
|---|
| 2148 | } /* malloc_ppheno */ |
|---|
| 2149 | |
|---|
| 2150 | |
|---|
| 2151 | long take_name_from_tree (Char *ch, Char *str, FILE *treefile) |
|---|
| 2152 | { |
|---|
| 2153 | /* This loop takes in the name from the tree. |
|---|
| 2154 | Return the length of the name string. */ |
|---|
| 2155 | |
|---|
| 2156 | long name_length = 0; |
|---|
| 2157 | |
|---|
| 2158 | do { |
|---|
| 2159 | if ((*ch) == '_') |
|---|
| 2160 | (*ch) = ' '; |
|---|
| 2161 | str[name_length++] = (*ch); |
|---|
| 2162 | if (eoln(treefile)) |
|---|
| 2163 | scan_eoln(treefile); |
|---|
| 2164 | (*ch) = gettc(treefile); |
|---|
| 2165 | if (*ch == '\n') |
|---|
| 2166 | *ch = ' '; |
|---|
| 2167 | } while ((*ch) != ':' && (*ch) != ',' && (*ch) != ')' && |
|---|
| 2168 | (*ch) != '[' && (*ch) != ';' && name_length <= MAXNCH); |
|---|
| 2169 | return name_length; |
|---|
| 2170 | } /* take_name_from_tree */ |
|---|
| 2171 | |
|---|
| 2172 | |
|---|
| 2173 | void match_names_to_data (Char *str, pointarray treenode, node **p, long local_spp) |
|---|
| 2174 | { |
|---|
| 2175 | /* This loop matches names taken from treefile to indexed names in |
|---|
| 2176 | the data file */ |
|---|
| 2177 | |
|---|
| 2178 | boolean found; |
|---|
| 2179 | long i, n; |
|---|
| 2180 | |
|---|
| 2181 | n = 1; |
|---|
| 2182 | do { |
|---|
| 2183 | found = true; |
|---|
| 2184 | for (i = 0; i < nmlngth; i++) { |
|---|
| 2185 | found = (found && ((str[i] == nayme[n - 1][i]) || |
|---|
| 2186 | (((nayme[n - 1][i] == '_') && (str[i] == ' ')) || |
|---|
| 2187 | ((nayme[n - 1][i] == ' ') && (str[i] == '\0'))))); |
|---|
| 2188 | } |
|---|
| 2189 | |
|---|
| 2190 | if (found) |
|---|
| 2191 | *p = treenode[n - 1]; |
|---|
| 2192 | else |
|---|
| 2193 | n++; |
|---|
| 2194 | |
|---|
| 2195 | } while (!(n > local_spp || found)); |
|---|
| 2196 | |
|---|
| 2197 | if (n > local_spp) { |
|---|
| 2198 | printf("\n\nERROR: Cannot find species: "); |
|---|
| 2199 | for (i = 0; (str[i] != '\0') && (i < MAXNCH); i++) |
|---|
| 2200 | putchar(str[i]); |
|---|
| 2201 | printf(" in data file\n\n"); |
|---|
| 2202 | exxit(-1); |
|---|
| 2203 | } |
|---|
| 2204 | } /* match_names_to_data */ |
|---|
| 2205 | |
|---|
| 2206 | |
|---|
| 2207 | void addelement(node **p, node *q, Char *ch, long *parens, FILE *treefile, |
|---|
| 2208 | pointarray treenode, boolean *goteof, boolean *first, pointarray nodep, |
|---|
| 2209 | long *nextnode, long *ntips, boolean *haslengths, node **grbg, |
|---|
| 2210 | initptr initnode) |
|---|
| 2211 | { |
|---|
| 2212 | /* Recursive procedure adds nodes to user-defined tree |
|---|
| 2213 | This is the main (new) tree-reading procedure */ |
|---|
| 2214 | |
|---|
| 2215 | node *pfirst; |
|---|
| 2216 | long i, len = 0, nodei = 0; |
|---|
| 2217 | boolean notlast; |
|---|
| 2218 | Char str[MAXNCH]; |
|---|
| 2219 | node *r; |
|---|
| 2220 | |
|---|
| 2221 | if ((*ch) == '(') { |
|---|
| 2222 | (*nextnode)++; /* get ready to use new interior node */ |
|---|
| 2223 | nodei = *nextnode; /* do what needs to be done at bottom */ |
|---|
| 2224 | (*initnode)(p, grbg, q, len, nodei, ntips, |
|---|
| 2225 | parens, bottom, treenode, nodep, str, ch, treefile); |
|---|
| 2226 | pfirst = (*p); |
|---|
| 2227 | notlast = true; |
|---|
| 2228 | while (notlast) { /* loop through immediate descendants */ |
|---|
| 2229 | (*initnode)(&(*p)->next, grbg, q, |
|---|
| 2230 | len, nodei, ntips, parens, nonbottom, treenode, |
|---|
| 2231 | nodep, str, ch, treefile); |
|---|
| 2232 | /* ... doing what is done before each */ |
|---|
| 2233 | r = (*p)->next; |
|---|
| 2234 | getch(ch, parens, treefile); /* look for next character */ |
|---|
| 2235 | |
|---|
| 2236 | addelement(&(*p)->next->back, (*p)->next, ch, parens, treefile, |
|---|
| 2237 | treenode, goteof, first, nodep, nextnode, ntips, |
|---|
| 2238 | haslengths, grbg, initnode); /* call self recursively */ |
|---|
| 2239 | |
|---|
| 2240 | (*initnode)(&r, grbg, q, len, nodei, ntips, |
|---|
| 2241 | parens, hslength, treenode, nodep, str, ch, treefile); |
|---|
| 2242 | /* do what is done after each about length */ |
|---|
| 2243 | pfirst->numdesc++; /* increment number of descendants */ |
|---|
| 2244 | *p = r; /* make r point back to p */ |
|---|
| 2245 | |
|---|
| 2246 | if ((*ch) == ')') { |
|---|
| 2247 | notlast = false; |
|---|
| 2248 | do { |
|---|
| 2249 | getch(ch, parens, treefile); |
|---|
| 2250 | } while ((*ch) != ',' && (*ch) != ')' && |
|---|
| 2251 | (*ch) != '[' && (*ch) != ';' && (*ch) != ':'); |
|---|
| 2252 | } |
|---|
| 2253 | } |
|---|
| 2254 | |
|---|
| 2255 | (*p)->next = pfirst; |
|---|
| 2256 | (*p) = pfirst; |
|---|
| 2257 | |
|---|
| 2258 | } else if ((*ch) != ')') { /* if it's a species name */ |
|---|
| 2259 | for (i = 0; i < MAXNCH; i++) /* fill string with nulls */ |
|---|
| 2260 | str[i] = '\0'; |
|---|
| 2261 | |
|---|
| 2262 | len = take_name_from_tree (ch, str, treefile); /* get the name */ |
|---|
| 2263 | |
|---|
| 2264 | if ((*ch) == ')') |
|---|
| 2265 | (*parens)--; /* decrement count of open parentheses */ |
|---|
| 2266 | (*initnode)(p, grbg, q, len, nodei, ntips, |
|---|
| 2267 | parens, tip, treenode, nodep, str, ch, treefile); |
|---|
| 2268 | /* do what needs to be done at a tip */ |
|---|
| 2269 | } else |
|---|
| 2270 | getch(ch, parens, treefile); |
|---|
| 2271 | if (q != NULL) |
|---|
| 2272 | hookup(q, (*p)); /* now hook up */ |
|---|
| 2273 | (*initnode)(p, grbg, q, len, nodei, ntips, |
|---|
| 2274 | parens, iter, treenode, nodep, str, ch, treefile); |
|---|
| 2275 | if ((*ch) == ':') |
|---|
| 2276 | (*initnode)(p, grbg, q, len, nodei, ntips, |
|---|
| 2277 | parens, length, treenode, nodep, str, ch, treefile); |
|---|
| 2278 | /* do what needs to be done with length */ |
|---|
| 2279 | else if ((*ch) != ';' && (*ch) != '[') |
|---|
| 2280 | (*initnode)(p, grbg, q, len, nodei, ntips, |
|---|
| 2281 | parens, hsnolength, treenode, nodep, str, ch, treefile); |
|---|
| 2282 | /* ... or what needs to be done when no length */ |
|---|
| 2283 | if ((*ch) == '[') |
|---|
| 2284 | (*initnode)(p, grbg, q, len, nodei, ntips, |
|---|
| 2285 | parens, treewt, treenode, nodep, str, ch, treefile); |
|---|
| 2286 | /* ... for processing a tree weight */ |
|---|
| 2287 | else if ((*ch) == ';') /* ... and at end of tree */ |
|---|
| 2288 | (*initnode)(p, grbg, q, len, nodei, ntips, |
|---|
| 2289 | parens, unittrwt, treenode, nodep, str, ch, treefile); |
|---|
| 2290 | } /* addelement */ |
|---|
| 2291 | |
|---|
| 2292 | |
|---|
| 2293 | void treeread (FILE *treefile, node **root, pointarray treenode, |
|---|
| 2294 | boolean *goteof, boolean *first, pointarray nodep, |
|---|
| 2295 | long *nextnode, boolean *haslengths, node **grbg, initptr initnode) |
|---|
| 2296 | { |
|---|
| 2297 | /* read in user-defined tree and set it up */ |
|---|
| 2298 | char ch; |
|---|
| 2299 | long parens = 0; |
|---|
| 2300 | long ntips = 0; |
|---|
| 2301 | |
|---|
| 2302 | (*goteof) = false; |
|---|
| 2303 | (*nextnode) = spp; |
|---|
| 2304 | |
|---|
| 2305 | /* eat blank lines */ |
|---|
| 2306 | while (eoln(treefile) && !eoff(treefile)) |
|---|
| 2307 | scan_eoln(treefile); |
|---|
| 2308 | |
|---|
| 2309 | if (eoff(treefile)) { |
|---|
| 2310 | (*goteof) = true; |
|---|
| 2311 | return; |
|---|
| 2312 | } |
|---|
| 2313 | |
|---|
| 2314 | getch(&ch, &parens, treefile); |
|---|
| 2315 | |
|---|
| 2316 | while (ch != '(') { |
|---|
| 2317 | /* Eat everything in the file (i.e. digits, tabs) until you |
|---|
| 2318 | encounter an open-paren */ |
|---|
| 2319 | getch(&ch, &parens, treefile); |
|---|
| 2320 | } |
|---|
| 2321 | (*haslengths) = true; |
|---|
| 2322 | addelement(root, NULL, &ch, &parens, treefile, |
|---|
| 2323 | treenode, goteof, first, nodep, nextnode, &ntips, |
|---|
| 2324 | haslengths, grbg, initnode); |
|---|
| 2325 | |
|---|
| 2326 | /* Eat blank lines and end of current line*/ |
|---|
| 2327 | do { |
|---|
| 2328 | scan_eoln(treefile); |
|---|
| 2329 | } |
|---|
| 2330 | while (eoln(treefile) && !eoff(treefile)); |
|---|
| 2331 | |
|---|
| 2332 | (*first) = false; |
|---|
| 2333 | if (parens != 0) { |
|---|
| 2334 | printf("\n\nERROR in tree file: unmatched parentheses\n\n"); |
|---|
| 2335 | exxit(-1); |
|---|
| 2336 | } |
|---|
| 2337 | } /* treeread */ |
|---|
| 2338 | |
|---|
| 2339 | |
|---|
| 2340 | void addelement2(node *q, Char *ch, long *parens, FILE *treefile, |
|---|
| 2341 | pointarray treenode, boolean lngths, double *trweight, boolean *goteof, |
|---|
| 2342 | long *nextnode, long *ntips, long no_species, boolean *haslengths) |
|---|
| 2343 | { |
|---|
| 2344 | /* recursive procedure adds nodes to user-defined tree |
|---|
| 2345 | -- old-style bifurcating-only version */ |
|---|
| 2346 | node *pfirst = NULL, *p; |
|---|
| 2347 | long i, len, current_loop_index; |
|---|
| 2348 | boolean notlast, minusread; |
|---|
| 2349 | Char str[MAXNCH]; |
|---|
| 2350 | double valyew, divisor; |
|---|
| 2351 | |
|---|
| 2352 | if ((*ch) == '(') { |
|---|
| 2353 | |
|---|
| 2354 | current_loop_index = (*nextnode) + spp; |
|---|
| 2355 | (*nextnode)++; |
|---|
| 2356 | |
|---|
| 2357 | /* This is an assignment of an interior node */ |
|---|
| 2358 | p = treenode[current_loop_index]; |
|---|
| 2359 | pfirst = p; |
|---|
| 2360 | notlast = true; |
|---|
| 2361 | while (notlast) { |
|---|
| 2362 | /* This while loop goes through a circle (triad for |
|---|
| 2363 | bifurcations) of nodes */ |
|---|
| 2364 | p = p->next; |
|---|
| 2365 | /* added to ensure that non base nodes in loops have indices */ |
|---|
| 2366 | p->index = current_loop_index + 1; |
|---|
| 2367 | |
|---|
| 2368 | getch(ch, parens, treefile); |
|---|
| 2369 | |
|---|
| 2370 | addelement2(p, ch, parens, treefile, treenode, lngths, trweight, |
|---|
| 2371 | goteof, nextnode, ntips, no_species, haslengths); |
|---|
| 2372 | |
|---|
| 2373 | if ((*ch) == ')') { |
|---|
| 2374 | notlast = false; |
|---|
| 2375 | do { |
|---|
| 2376 | getch(ch, parens, treefile); |
|---|
| 2377 | } while ((*ch) != ',' && (*ch) != ')' && |
|---|
| 2378 | (*ch) != '[' && (*ch) != ';' && (*ch) != ':'); |
|---|
| 2379 | } |
|---|
| 2380 | } |
|---|
| 2381 | |
|---|
| 2382 | } else if ((*ch) != ')') { |
|---|
| 2383 | for (i = 0; i < MAXNCH; i++) |
|---|
| 2384 | str[i] = '\0'; |
|---|
| 2385 | len = take_name_from_tree (ch, str, treefile); |
|---|
| 2386 | match_names_to_data (str, treenode, &p, spp); |
|---|
| 2387 | pfirst = p; |
|---|
| 2388 | if ((*ch) == ')') |
|---|
| 2389 | (*parens)--; |
|---|
| 2390 | (*ntips)++; |
|---|
| 2391 | strncpy (p->nayme, str, len); |
|---|
| 2392 | } else |
|---|
| 2393 | getch(ch, parens, treefile); |
|---|
| 2394 | |
|---|
| 2395 | if ((*ch) == '[') { /* getting tree weight from last comment field */ |
|---|
| 2396 | if (!eoln(treefile)) { |
|---|
| 2397 | fscanf(treefile, "%lf", trweight); |
|---|
| 2398 | getch(ch, parens, treefile); |
|---|
| 2399 | if (*ch != ']') { |
|---|
| 2400 | printf("\n\nERROR: Missing right square bracket\n\n"); |
|---|
| 2401 | exxit(-1); |
|---|
| 2402 | } |
|---|
| 2403 | else { |
|---|
| 2404 | getch(ch, parens, treefile); |
|---|
| 2405 | if (*ch != ';') { |
|---|
| 2406 | printf("\n\nERROR: Missing semicolon after square brackets\n\n"); |
|---|
| 2407 | exxit(-1); |
|---|
| 2408 | } |
|---|
| 2409 | } |
|---|
| 2410 | } |
|---|
| 2411 | } |
|---|
| 2412 | else if ((*ch) == ';') { |
|---|
| 2413 | (*trweight) = 1.0 ; |
|---|
| 2414 | if (!eoln(treefile)) |
|---|
| 2415 | printf("WARNING: tree weight set to 1.0\n"); |
|---|
| 2416 | } |
|---|
| 2417 | else |
|---|
| 2418 | (*haslengths) = ((*haslengths) && q == NULL); |
|---|
| 2419 | |
|---|
| 2420 | if (q != NULL) |
|---|
| 2421 | hookup(q, pfirst); |
|---|
| 2422 | if (q != NULL) { |
|---|
| 2423 | if (q->branchnum < pfirst->branchnum) |
|---|
| 2424 | pfirst->branchnum = q->branchnum; |
|---|
| 2425 | else |
|---|
| 2426 | q->branchnum = pfirst->branchnum; |
|---|
| 2427 | } |
|---|
| 2428 | |
|---|
| 2429 | if ((*ch) == ':') { |
|---|
| 2430 | processlength(&valyew, &divisor, ch, |
|---|
| 2431 | &minusread, treefile, parens); |
|---|
| 2432 | if (q != NULL) { |
|---|
| 2433 | if (!minusread) |
|---|
| 2434 | q->oldlen = valyew / divisor; |
|---|
| 2435 | else |
|---|
| 2436 | q->oldlen = 0.0; |
|---|
| 2437 | if (lngths) { |
|---|
| 2438 | q->v = valyew / divisor; |
|---|
| 2439 | q->back->v = q->v; |
|---|
| 2440 | q->iter = false; |
|---|
| 2441 | q->back->iter = false; |
|---|
| 2442 | q->back->iter = false; |
|---|
| 2443 | } |
|---|
| 2444 | } |
|---|
| 2445 | } |
|---|
| 2446 | |
|---|
| 2447 | } /* addelement2 */ |
|---|
| 2448 | |
|---|
| 2449 | |
|---|
| 2450 | void treeread2 (FILE *treefile, node **root, pointarray treenode, |
|---|
| 2451 | boolean lngths, double *trweight, boolean *goteof, |
|---|
| 2452 | boolean *haslengths, long *no_species) |
|---|
| 2453 | { |
|---|
| 2454 | /* read in user-defined tree and set it up |
|---|
| 2455 | -- old-style bifurcating-only version */ |
|---|
| 2456 | char ch; |
|---|
| 2457 | long parens = 0; |
|---|
| 2458 | long ntips = 0; |
|---|
| 2459 | long nextnode; |
|---|
| 2460 | |
|---|
| 2461 | (*goteof) = false; |
|---|
| 2462 | nextnode = 0; |
|---|
| 2463 | |
|---|
| 2464 | /* Eats all blank lines at start of file */ |
|---|
| 2465 | while (eoln(treefile) && !eoff(treefile)) |
|---|
| 2466 | scan_eoln(treefile); |
|---|
| 2467 | |
|---|
| 2468 | if (eoff(treefile)) { |
|---|
| 2469 | (*goteof) = true; |
|---|
| 2470 | return; |
|---|
| 2471 | } |
|---|
| 2472 | |
|---|
| 2473 | getch(&ch, &parens, treefile); |
|---|
| 2474 | |
|---|
| 2475 | while (ch != '(') { |
|---|
| 2476 | /* Eat everything in the file (i.e. digits, tabs) until you |
|---|
| 2477 | encounter an open-paren */ |
|---|
| 2478 | getch(&ch, &parens, treefile); |
|---|
| 2479 | } |
|---|
| 2480 | |
|---|
| 2481 | addelement2(NULL, &ch, &parens, treefile, treenode, lngths, trweight, |
|---|
| 2482 | goteof, &nextnode, &ntips, (*no_species), haslengths); |
|---|
| 2483 | (*root) = treenode[*no_species]; |
|---|
| 2484 | |
|---|
| 2485 | /*eat blank lines */ |
|---|
| 2486 | while (eoln(treefile) && !eoff(treefile)) |
|---|
| 2487 | scan_eoln(treefile); |
|---|
| 2488 | |
|---|
| 2489 | (*root)->oldlen = 0.0; |
|---|
| 2490 | |
|---|
| 2491 | if (parens != 0) { |
|---|
| 2492 | printf("\n\nERROR in tree file: unmatched parentheses\n\n"); |
|---|
| 2493 | exxit(-1); |
|---|
| 2494 | } |
|---|
| 2495 | } /* treeread2 */ |
|---|
| 2496 | |
|---|
| 2497 | void exxit(int exitcode) |
|---|
| 2498 | { |
|---|
| 2499 | #ifdef WIN32 |
|---|
| 2500 | if (exitcode == 0) |
|---|
| 2501 | #endif |
|---|
| 2502 | exit (exitcode); |
|---|
| 2503 | #ifdef WIN32 |
|---|
| 2504 | else { |
|---|
| 2505 | puts ("Hit Enter or Return to close program."); |
|---|
| 2506 | puts(" You may have to hit Enter or Return twice."); |
|---|
| 2507 | getchar (); |
|---|
| 2508 | getchar (); |
|---|
| 2509 | phyRestoreConsoleAttributes(); |
|---|
| 2510 | exit (exitcode); |
|---|
| 2511 | } |
|---|
| 2512 | #endif |
|---|
| 2513 | } /* exxit */ |
|---|
| 2514 | |
|---|
| 2515 | |
|---|
| 2516 | char gettc(FILE* file) |
|---|
| 2517 | { /* catch eof's so that other functions not expecting an eof |
|---|
| 2518 | * won't have to worry about it */ |
|---|
| 2519 | int ch; |
|---|
| 2520 | |
|---|
| 2521 | ch = getc(file); |
|---|
| 2522 | |
|---|
| 2523 | if (ch == EOF ) { |
|---|
| 2524 | puts("Unexpected End of File"); |
|---|
| 2525 | exxit(-1); |
|---|
| 2526 | } |
|---|
| 2527 | /* printf("ch='%c'\n", (char)ch); */ |
|---|
| 2528 | return ch; |
|---|
| 2529 | } /* gettc */ |
|---|
| 2530 | |
|---|
| 2531 | |
|---|
| 2532 | #ifdef WIN32 |
|---|
| 2533 | void phySaveConsoleAttributes() |
|---|
| 2534 | { |
|---|
| 2535 | GetConsoleScreenBufferInfo( hConsoleOutput, &savecsbi ); |
|---|
| 2536 | } /* PhySaveConsoleAttributes */ |
|---|
| 2537 | |
|---|
| 2538 | |
|---|
| 2539 | void phySetConsoleAttributes() |
|---|
| 2540 | { |
|---|
| 2541 | hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE); |
|---|
| 2542 | |
|---|
| 2543 | phySaveConsoleAttributes(); |
|---|
| 2544 | |
|---|
| 2545 | SetConsoleTextAttribute(hConsoleOutput, |
|---|
| 2546 | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY); |
|---|
| 2547 | } /* phySetConsoleAttributes */ |
|---|
| 2548 | |
|---|
| 2549 | |
|---|
| 2550 | void phyRestoreConsoleAttributes() |
|---|
| 2551 | { |
|---|
| 2552 | COORD coordScreen = { 0, 0 }; |
|---|
| 2553 | DWORD cCharsWritten; |
|---|
| 2554 | DWORD dwConSize; |
|---|
| 2555 | |
|---|
| 2556 | dwConSize = savecsbi.dwSize.X * savecsbi.dwSize.Y; |
|---|
| 2557 | |
|---|
| 2558 | SetConsoleTextAttribute(hConsoleOutput, savecsbi.wAttributes); |
|---|
| 2559 | |
|---|
| 2560 | FillConsoleOutputAttribute( hConsoleOutput, savecsbi.wAttributes, |
|---|
| 2561 | dwConSize, coordScreen, &cCharsWritten ); |
|---|
| 2562 | } /* phyRestoreConsoleAttributes */ |
|---|
| 2563 | |
|---|
| 2564 | |
|---|
| 2565 | void phyFillScreenColor() |
|---|
| 2566 | { |
|---|
| 2567 | COORD coordScreen = { 0, 0 }; |
|---|
| 2568 | DWORD cCharsWritten; |
|---|
| 2569 | CONSOLE_SCREEN_BUFFER_INFO csbi; /* to get buffer info */ |
|---|
| 2570 | DWORD dwConSize; |
|---|
| 2571 | |
|---|
| 2572 | GetConsoleScreenBufferInfo( hConsoleOutput, &csbi ); |
|---|
| 2573 | dwConSize = csbi.dwSize.X * csbi.dwSize.Y; |
|---|
| 2574 | |
|---|
| 2575 | FillConsoleOutputAttribute( hConsoleOutput, csbi.wAttributes, |
|---|
| 2576 | dwConSize, coordScreen, &cCharsWritten ); |
|---|
| 2577 | } /* PhyFillScreenColor */ |
|---|
| 2578 | |
|---|
| 2579 | |
|---|
| 2580 | void phyClearScreen() |
|---|
| 2581 | { |
|---|
| 2582 | COORD coordScreen = { 0, 0 }; /* here's where we'll home the |
|---|
| 2583 | cursor */ |
|---|
| 2584 | DWORD cCharsWritten; |
|---|
| 2585 | CONSOLE_SCREEN_BUFFER_INFO csbi; /* to get buffer info */ |
|---|
| 2586 | DWORD dwConSize; /* number of character cells in |
|---|
| 2587 | the current buffer */ |
|---|
| 2588 | |
|---|
| 2589 | /* get the number of character cells in the current buffer */ |
|---|
| 2590 | |
|---|
| 2591 | GetConsoleScreenBufferInfo( hConsoleOutput, &csbi ); |
|---|
| 2592 | dwConSize = csbi.dwSize.X * csbi.dwSize.Y; |
|---|
| 2593 | |
|---|
| 2594 | /* fill the entire screen with blanks */ |
|---|
| 2595 | |
|---|
| 2596 | FillConsoleOutputCharacter( hConsoleOutput, (TCHAR) ' ', |
|---|
| 2597 | dwConSize, coordScreen, &cCharsWritten ); |
|---|
| 2598 | |
|---|
| 2599 | /* get the current text attribute */ |
|---|
| 2600 | |
|---|
| 2601 | GetConsoleScreenBufferInfo( hConsoleOutput, &csbi ); |
|---|
| 2602 | |
|---|
| 2603 | /* now set the buffer's attributes accordingly */ |
|---|
| 2604 | |
|---|
| 2605 | FillConsoleOutputAttribute( hConsoleOutput, csbi.wAttributes, |
|---|
| 2606 | dwConSize, coordScreen, &cCharsWritten ); |
|---|
| 2607 | |
|---|
| 2608 | /* put the cursor at (0, 0) */ |
|---|
| 2609 | |
|---|
| 2610 | SetConsoleCursorPosition( hConsoleOutput, coordScreen ); |
|---|
| 2611 | return; |
|---|
| 2612 | } /* PhyClearScreen */ |
|---|
| 2613 | #endif |
|---|
| 2614 | |
|---|