// File: /workspace/github_c_makefile_star2_O3/sheneman[P]clearcut/dmat.c
// Function: NJ_parse_distance_matrix
DMAT *
NJ_parse_distance_matrix(NJ_ARGS *nj_args) {
  
  DMAT *dmat           = NULL;
  FILE *fp            = NULL;
  NJ_DIST_TOKEN *token = NULL;

  int state, dmat_type;
  int row;
  int fltcnt;
  int x, y, i;
  int numvalread;
  int expectedvalues = -1;
  float val;
  int first_state = 0;


  /* allocate our distance matrix and token structure */
  dmat = (DMAT *)calloc(1, sizeof(DMAT));
  token = (NJ_DIST_TOKEN *)calloc(1, sizeof(NJ_DIST_TOKEN));
  if(token) {
    token->bufsize = NJ_INITIAL_BUFSIZE;
    token->buf     = (char *)calloc(token->bufsize, sizeof(char));
  }
  if(!dmat || !token || !token->buf) {
    fprintf(stderr, "Clearcut: Memory allocation error in NJ_parse_distance_matrix()\n");
    goto XIT_BAD;
  }
  
  /* open distance matrix file here */
  if(nj_args->stdin_flag) {
    fp = stdin;
  } else {
    fp = fopen(nj_args->infilename, "r");
    if(!fp) {
      fprintf(stderr, "Clearcut: Could not open distance matrix: %s\n", nj_args->infilename);
      perror("Clearcut");
      goto XIT_BAD;
    }
  }

  /* get the number of taxa in this file */
  fscanf(fp, "%ld\n", &dmat->ntaxa);
  if(dmat->ntaxa < 2) {
    fprintf(stderr, "Clearcut: Invalid number of taxa in distance matrix\n");

    goto XIT_BAD;
  }

  /* set our initial working size according to the # of taxa */
  dmat->size = dmat->ntaxa;

  /* allocate space for the distance matrix values here */
  dmat->val = 
    (float *)calloc(NJ_NCELLS(dmat->ntaxa), sizeof(float));
  if(!dmat->val) {
    fprintf(stderr, "Clearcut: Memory allocation error in NJ_parse_distance_matrix()\n");
    goto XIT_BAD;
  }

  /*  taxa names */
  dmat->taxaname = (char **)calloc(dmat->ntaxa, sizeof(char *));
  if(!dmat->taxaname) {
    fprintf(stderr, "Clearcut: Memory allocation error in NJ_parse_distance_matrix()\n");
    goto XIT_BAD;
  }

  /* set the initial state of our state machine */
  dmat_type   = NJ_PARSE_UNKNOWN;
  row         = -1;
  fltcnt      = 0;
  numvalread  = 0;


  /* read the input one character at a time to drive simple state machine */
  state = NJ_get_token(fp, token);
  while(state != NJ_EOF_STATE) {
    
    switch(state) {

    case NJ_NAME_STATE:
      
      if(first_state == 0) {
	first_state = 1;
      }

      row++;

      if(row > 0 && dmat_type == NJ_PARSE_UNKNOWN) {

	if(fltcnt == dmat->ntaxa) {

	  dmat_type = NJ_PARSE_SYMMETRIC;
	  expectedvalues = dmat->ntaxa * dmat->ntaxa;

	} else if (fltcnt == dmat->ntaxa-1) {

	  dmat_type = NJ_PARSE_UPPER;
	  expectedvalues = ((dmat->ntaxa) * (dmat->ntaxa-1)) / 2;

	  /* shift everything in first row by one char */
	  for(i=dmat->ntaxa-2;i>=0;i--) {
	    dmat->val[i+1] = dmat->val[i];
	  }

	} else if (fltcnt == 0) {

	  dmat_type = NJ_PARSE_LOWER;
	  expectedvalues = ((dmat->ntaxa) * (dmat->ntaxa-1)) / 2;

	} else {
	  goto XIT_BAD;
	}
      }
      
      if(row >= dmat->ntaxa) {
	goto XIT_BAD;
      }
      
      /* allocate space for this taxon label */
      dmat->taxaname[row] = (char *)calloc(strlen(token->buf)+1, sizeof(char));
      if(!dmat->taxaname[row]) {
	fprintf(stderr, "Clearcut: Memory allocation error in NJ_parse_distance_matrix()\n");
	goto XIT_BAD;
      }
      
      strcpy(dmat->taxaname[row], token->buf); 
      
      fltcnt = 0;

      break;


    case NJ_FLOAT_STATE:

      if(first_state == 0) {
	goto XIT_BAD;
      }

      val = atof(token->buf);
      if(errno) {
	fprintf(stderr, "Clearcut: Distance value out-of-range.\n");
	goto XIT_BAD;
      }
      
      x = row;
      y = fltcnt;

      switch(dmat_type) {

      case NJ_PARSE_UNKNOWN:

	dmat->val[NJ_MAP(x, y, dmat->size)] = val;

	break;

      case NJ_PARSE_SYMMETRIC:
	
	if(fltcnt >= dmat->ntaxa) {
	  fprintf(stderr, "Clearcut: Incorrect number of distance values on row.\n");
	  goto XIT_BAD;
	}

	if(x < y) {
	  dmat->val[NJ_MAP(x, y, dmat->size)] = val;
	} else if(x > y) {
	  if(!NJ_FLT_EQ(val, dmat->val[NJ_MAP(y, x, dmat->size)])) {
	    fprintf(stderr, "Clearcut: Full matrices must be symmetric.\n");
	    goto XIT_BAD;
	  }
	} else {
	  if(!NJ_FLT_EQ(val, 0.0)) {
	    fprintf(stderr, "Clearcut: Values along the diagonal in a symmetric matrix must be zero.\n");
	    goto XIT_BAD;

            }
	}

	break;
	
      case NJ_PARSE_UPPER:

	if(fltcnt > dmat->ntaxa-row) {
	  fprintf(stderr, "Clearcut: Incorrect number of distance values on row.\n");
	  goto XIT_BAD;
	}
	
	dmat->val[NJ_MAP(x, x+y+1, dmat->size)] = val;
	
	break;

      case NJ_PARSE_LOWER:
	
	if(fltcnt > row-1) {
	  fprintf(stderr, "Clearcut: Incorrect number of distance values on row.\n");
	  goto XIT_BAD;
	}

	dmat->val[NJ_MAP(y, x, dmat->size)] = val;
	
	break;
	
      default:
	
	goto XIT_BAD;
	
	break;
      }

      fltcnt++;
      numvalread++;
      
      break;

    case NJ_WS_STATE:

      break;

    case NJ_EOF_STATE:

      if(first_state == 0) {
	goto XIT_BAD;
      }

      break;

    default:

      fprintf(stderr, "Clearcut: Unknown state in distance matrix parser.\n");
      break;

    }

    /* get next token from stream */
    state = NJ_get_token(fp, token);
  }


  /* 
   * At the end, if we have not read the number of values that we predicted
   * we would need, then there was a problem and we need to punt.
   */
  if(numvalread != expectedvalues) {
    fprintf(stderr, "Clearcut: Incorrect number of values in the distance matrix.\n");
    goto XIT_BAD;
  }
  
  /* special check to make sure first value read is 0.0 */
  if(dmat_type == NJ_PARSE_SYMMETRIC) {
    if(!NJ_FLT_EQ(dmat->val[NJ_MAP(0, 0, dmat->size)], 0.0)) {
      fprintf(stderr, "Clearcut: Values along the diagonal in a symmetric matrix must be zero.\n");
      goto XIT_BAD;
    }
  }

  
  /* now lets allocate space for the r and r2 columns */
  dmat->r  = (float *)calloc(dmat->ntaxa, sizeof(float));
  dmat->r2 = (float *)calloc(dmat->ntaxa, sizeof(float));
  if(!dmat->r || !dmat->r2) {
    fprintf(stderr, "Clearcut: Memory allocation error in NJ_parse_distance_matrix()\n");
    goto XIT_BAD;
  }
  
  /* track some memory addresses */
  dmat->rhandle   = dmat->r;
  dmat->r2handle  = dmat->r2;
  dmat->valhandle = dmat->val;

  /* close matrix file here */
  if(!nj_args->stdin_flag) {
    fclose(fp);
  }
  
  if(token) {
    if(token->buf) {
      free(token->buf);
    }
    free(token);
  }

  return(dmat);



  /* clean up our partial progress */
 XIT_BAD:

  if(fp) {
    fprintf(stderr, "Clearcut: Syntax error in distance matrix at offset %ld.\n", ftell(fp));
  }

  /* close matrix file here */
  if(!nj_args->stdin_flag) {
    if(fp) {
      fclose(fp);
    }
  }

  /* if we have a valid dmat (partial or complete), we need to free it */
  if(dmat) {
    NJ_free_dmat(dmat);
  }
  
  if(token) {
    if(token->buf) {
      free(token->buf);
    }
    free(token);
  }
  
  return(NULL);
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x48, %rsp
movq %rdi, %r15
movl $0x1, %edi
movl $0x48, %esi
callq 0x2160
movq %rax, %rbx
movl $0x1, %edi
movl $0x18, %esi
callq 0x2160
testq %rax, %rax
je 0x5b4e
movq %rax, %r14
movq $0x20, 0x8(%rax)
movl $0x20, %edi
movl $0x1, %esi
callq 0x2160
movq %rax, %r12
movq %rax, (%r14)
testq %rbx, %rbx
je 0x5b7d
testq %r12, %r12
je 0x5b84
cmpl $0x0, 0x28(%r15)
je 0x56b8
movq 0x7925(%rip), %rax      # 0xcfd8
movq (%rax), %r12
jmp 0x56d3
movq (%r15), %rdi
leaq 0x3597(%rip), %rsi      # 0x8c59
callq 0x2200
movq %rax, %r12
testq %rax, %rax
je 0x5bae
addq $0x28, %r15
leaq 0x313b(%rip), %rsi      # 0x8819
movq %r12, %rdi
movq %rbx, %rdx
xorl %eax, %eax
callq 0x20a0
movq (%rbx), %r13
cmpq $0x1, %r13
movq %r15, 0x30(%rsp)
movq %rbx, 0x8(%rsp)
jle 0x5b8b
movq %r13, 0x8(%rbx)
leaq 0x1(%r13), %rdi
imulq %r13, %rdi
shrq %rdi
movl $0x4, %esi
callq 0x2160
movq %rax, 0x18(%rbx)
testq %rax, %rax
je 0x5b92
movl $0x8, %esi
movq %r13, %rdi
callq 0x2160
movq %rax, 0x10(%rbx)
testq %rax, %rax
je 0x5b99
movb $0x1, %r15b
movl $0x0, 0x1c(%rsp)
movl $0xffffffff, %ebp       # imm = 0xFFFFFFFF
movl $0x67, %ebx
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
movq %rax, 0x20(%rsp)
movl %ebp, 0x2c(%rsp)
movslq %ebp, %r13
movq %r13, 0x10(%rsp)
notq %r13
movq %rbx, 0x38(%rsp)
addl $-0x64, %ebx
xorl %ebp, %ebp
movq %r12, %rdi
movq %r14, %rsi
callq 0x5c45
cmpl $0x66, %eax
je 0x577a
cmpl $0x67, %eax
je 0x5a8e
cmpl $0x65, %eax
je 0x57a8
cmpl $0x64, %eax
je 0x596f
callq 0x254f
jmp 0x577a
testb $0x1, %r15b
jne 0x5bc5
movq (%r14), %rdi
callq 0x20c0
movsd %xmm0, 0x40(%rsp)
callq 0x2060
cmpl $0x0, (%rax)
jne 0x5c14
xorps %xmm0, %xmm0
cvtsd2ss 0x40(%rsp), %xmm0
leaq 0x2dc6(%rip), %rcx      # 0x85a4
movslq (%rcx,%rbx,4), %rax
addq %rcx, %rax
jmpq *%rax
movl %ebp, %eax
movq 0x8(%rsp), %rdi
cmpq %rax, (%rdi)
movq 0x10(%rsp), %rsi
jle 0x5c29
cmpl %ebp, %esi
jge 0x590d
movq 0x8(%rdi), %rcx
leaq (,%rcx,2), %rcx
addq %r13, %rcx
imulq %rsi, %rcx
movq %rcx, %rdx
shrq $0x3f, %rdx
addq %rcx, %rdx
andq $-0x2, %rdx
addq %rdx, %rdx
addq 0x18(%rdi), %rdx
jmp 0x58b4
movl %ebp, %eax
movq 0x8(%rsp), %rsi
movq (%rsi), %rcx
movq 0x10(%rsp), %rdx
subq %rdx, %rcx
cmpq %rax, %rcx
jl 0x5c22
leal (%rdx,%rbp), %eax
movq 0x8(%rsi), %rcx
leaq (,%rcx,2), %rcx
addq %r13, %rcx
imulq %rdx, %rcx
movq %rcx, %rdx
shrq $0x3f, %rdx
addq %rcx, %rdx
andq $-0x2, %rdx
addq %rdx, %rdx
addq 0x18(%rsi), %rdx
cltq
leaq (%rdx,%rax,4), %rax
addq $0x4, %rax
jmp 0x58fb
movl %ebp, %eax
movq 0x8(%rsp), %rsi
movq 0x8(%rsi), %rcx
leaq (,%rcx,2), %rcx
addq %r13, %rcx
imulq 0x10(%rsp), %rcx
movq %rcx, %rdx
shrq $0x3f, %rdx
addq %rcx, %rdx
andq $-0x2, %rdx
addq %rdx, %rdx
addq 0x18(%rsi), %rdx
leaq (%rdx,%rax,4), %rax
jmp 0x58fb
cmpl 0x2c(%rsp), %ebp
movq 0x10(%rsp), %rsi
movq 0x8(%rsp), %rdi
jge 0x5c30
movl %ebp, %eax
movq 0x8(%rdi), %rcx
movq %rax, %rdx
notq %rdx
leaq (%rdx,%rcx,2), %rcx
imulq %rax, %rcx
movq %rcx, %rax
shrq $0x3f, %rax
addq %rcx, %rax
andq $-0x2, %rax
addq %rax, %rax
addq 0x18(%rdi), %rax
leaq (%rax,%rsi,4), %rax
movss %xmm0, (%rax)
incl %ebp
incl 0x1c(%rsp)
xorl %r15d, %r15d
jmp 0x577a
cmpl %ebp, %esi
jle 0x5956
movq 0x8(%rdi), %rcx
movq %rax, %rdx
notq %rdx
leaq (%rdx,%rcx,2), %rcx
imulq %rax, %rcx
movq %rcx, %rax
shrq $0x3f, %rax
addq %rcx, %rax
andq $-0x2, %rax
addq %rax, %rax
addq 0x18(%rdi), %rax
subss (%rax,%rsi,4), %xmm0
andps 0x26fc(%rip), %xmm0     # 0x8040
movss 0x2728(%rip), %xmm1     # 0x8074
ucomiss %xmm0, %xmm1
ja 0x58ff
jmp 0x5c3e
andps 0x26e3(%rip), %xmm0     # 0x8040
movss 0x270f(%rip), %xmm1     # 0x8074
ucomiss %xmm0, %xmm1
ja 0x58ff
jmp 0x5c37
movq 0x10(%rsp), %rdx
testl %edx, %edx
setns %al
movq 0x38(%rsp), %rbx
cmpl $0x67, %ebx
sete %cl
andb %al, %cl
movq 0x8(%rsp), %rax
movq (%rax), %r13
cmpb $0x1, %cl
jne 0x5a36
movl %ebp, %eax
cmpq %rax, %r13
jne 0x59b3
imull %ebp, %ebp
movl $0x64, %ebx
movl %ebp, %r15d
movq %r15, 0x20(%rsp)
jmp 0x5a36
leaq -0x1(%r13), %rcx
cmpq %rax, %rcx
jne 0x5a0e
imulq %r13, %rax
movq %rax, %rcx
shrq $0x3f, %rcx
addq %rax, %rcx
shrq %rcx
movq %rcx, 0x20(%rsp)
movl $0x66, %ebx
movl %r13d, %eax
addl $-0x2, %eax
js 0x5a36
movq 0x8(%rsp), %rax
movq 0x18(%rax), %rsi
leaq 0x4(%rsi), %rdi
movabsq $0x3fffffffc, %rax      # imm = 0x3FFFFFFFC
leaq (%rax,%r13,4), %rdx
andq %rax, %rdx
callq 0x21f0
movq 0x10(%rsp), %rdx
movl $0x66, %ebx
jmp 0x5a36
testl %ebp, %ebp
jne 0x5bc5
imulq %r13, %rcx
movq %rcx, %rax
shrq $0x3f, %rax
addq %rcx, %rax
shrq %rax
movq %rax, 0x20(%rsp)
movl $0x65, %ebx
movq 0x10(%rsp), %rdx
leal 0x1(%rdx), %eax
movslq %eax, %r15
cmpq %r15, %r13
jle 0x5bc5
movl %eax, %ebp
movq (%r14), %r13
movq %r13, %rdi
callq 0x20e0
leaq 0x1(%rax), %rdi
movl $0x1, %esi
callq 0x2160
movq 0x8(%rsp), %rdx
movq 0x10(%rdx), %rcx
movq %rax, (%rcx,%r15,8)
movq 0x10(%rdx), %rax
movq (%rax,%r15,8), %rdi
testq %rdi, %rdi
je 0x5c1b
movq %r13, %rsi
callq 0x2090
xorl %r15d, %r15d
jmp 0x5761
movq 0x20(%rsp), %rax
cmpl %eax, 0x1c(%rsp)
jne 0x5ba0
cmpl $0x64, 0x38(%rsp)
movq 0x8(%rsp), %rcx
jne 0x5ac9
movq 0x18(%rcx), %rax
movss (%rax), %xmm0
andps 0x2588(%rip), %xmm0     # 0x8040
movss 0x25b4(%rip), %xmm1     # 0x8074
ucomiss %xmm0, %xmm1
jbe 0x5bc0
movq 0x8(%rsp), %rax
movq (%rax), %rbp
movl $0x4, %esi
movq %rbp, %rdi
callq 0x2160
movq %rax, %r13
movq 0x8(%rsp), %rax
movq %r13, 0x28(%rax)
movl $0x4, %esi
movq %rbp, %rdi
movq 0x8(%rsp), %rbx
callq 0x2160
movq %rax, 0x30(%rbx)
testq %r13, %r13
je 0x5ba7
testq %rax, %rax
je 0x5ba7
movq %r13, 0x38(%rbx)
movq %rax, 0x40(%rbx)
movq 0x18(%rbx), %rax
movq %rax, 0x20(%rbx)
movq 0x30(%rsp), %rax
cmpl $0x0, (%rax)
jne 0x5b34
movq %r12, %rdi
callq 0x20d0
movq (%r14), %rdi
testq %rdi, %rdi
je 0x5b41
callq 0x2040
movq %r14, %rdi
callq 0x2040
jmp 0x5bf3
movq 0x74a3(%rip), %rax      # 0xcff8
movq (%rax), %rcx
leaq 0x2a55(%rip), %rdi      # 0x85b4
movl $0x40, %esi
movl $0x1, %edx
callq 0x2240
testq %rbx, %rbx
je 0x5bf1
movq %rbx, %rdi
callq 0x3e2f
jmp 0x5bf1
callq 0x264e
jmp 0x5bdc
callq 0x2632
jmp 0x5bb6
callq 0x25a3
jmp 0x5bc5
callq 0x2587
jmp 0x5bc5
callq 0x256b
jmp 0x5bc5
callq 0x24fb
jmp 0x5bc5
callq 0x2517
jmp 0x5bc5
movq %r15, %rdi
callq 0x2606
movq %rbx, %rdi
callq 0x3e2f
jmp 0x5bd9
callq 0x2533
testq %r12, %r12
jne 0x5c05
movq 0x8(%rsp), %rdi
callq 0x3e2f
testq %r14, %r14
je 0x5bf1
movq (%r14), %r12
testq %r12, %r12
je 0x5be9
movq %r12, %rdi
callq 0x2040
movq %r14, %rdi
callq 0x2040
xorl %ebx, %ebx
movq %rbx, %rax
addq $0x48, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %r12, %rdi
movq 0x30(%rsp), %rsi
callq 0x25bf
jmp 0x5bca
callq 0x2437
jmp 0x5bc5
callq 0x24df
jmp 0x5bc5
callq 0x246f
jmp 0x5bc5
callq 0x248b
jmp 0x5bc5
callq 0x2453
jmp 0x5bc5
callq 0x24a7
jmp 0x5bc5
callq 0x24c3
jmp 0x5bc5