// File: /workspace/github_c_makefile_star2_O1/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
movq %rax, %r14
testq %rax, %rax
je 0x54f4
movq $0x20, 0x8(%r14)
movl $0x20, %edi
movl $0x1, %esi
callq 0x2160
movq %rax, (%r14)
testq %rbx, %rbx
movq %r15, 0x20(%rsp)
je 0x595a
testq %r14, %r14
je 0x595a
cmpq $0x0, (%r14)
je 0x595a
cmpl $0x0, 0x28(%r15)
je 0x5528
movq 0x7ab5(%rip), %rax      # 0xcfd8
movq (%rax), %r12
jmp 0x5543
movq (%r15), %rdi
leaq 0x36f7(%rip), %rsi      # 0x8c29
callq 0x2200
movq %rax, %r12
testq %rax, %rax
je 0x598c
leaq 0x32a7(%rip), %rsi      # 0x87f1
movq %r12, %rdi
movq %rbx, %rdx
xorl %eax, %eax
callq 0x20a0
movq (%rbx), %r13
cmpq $0x1, %r13
jle 0x5964
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 0x596b
movl $0x8, %esi
movq %r13, %rdi
callq 0x2160
movq %rax, 0x10(%rbx)
testq %rax, %rax
je 0x5972
movq %rbx, 0x28(%rsp)
movb $0x1, %r15b
movl $0x0, 0x14(%rsp)
movl $0xffffffff, %ebx       # imm = 0xFFFFFFFF
movl $0x67, %ebp
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
movq %rax, 0x18(%rsp)
movl %ebx, 0x4(%rsp)
movslq %ebx, %r13
movq %r13, 0x8(%rsp)
notq %r13
movq %rbp, 0x30(%rsp)
leal -0x64(%rbp), %eax
movq %rax, 0x40(%rsp)
xorl %ebp, %ebp
movq 0x28(%rsp), %rbx
movq %r12, %rdi
movq %r14, %rsi
callq 0x5a45
cmpl $0x66, %eax
je 0x55eb
cmpl $0x67, %eax
je 0x58ca
cmpl $0x65, %eax
je 0x5619
cmpl $0x64, %eax
je 0x57b9
callq 0x254f
jmp 0x55eb
testb $0x1, %r15b
jne 0x599d
movq (%r14), %rdi
callq 0x20c0
movsd %xmm0, 0x38(%rsp)
callq 0x2060
cmpl $0x0, (%rax)
jne 0x5a03
xorps %xmm0, %xmm0
cvtsd2ss 0x38(%rsp), %xmm0
leaq 0x2f2d(%rip), %rcx      # 0x857c
movq 0x40(%rsp), %rax
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movl %ebp, %eax
cmpq %rax, (%rbx)
movq 0x8(%rsp), %rsi
jle 0x5a1d
cmpl %ebp, %esi
jge 0x5757
movq 0x8(%rbx), %rcx
leaq (,%rcx,2), %rcx
addq %r13, %rcx
imulq %rsi, %rcx
jmp 0x56ee
movl %ebp, %eax
movq (%rbx), %rcx
movq 0x8(%rsp), %rdx
subq %rdx, %rcx
cmpq %rax, %rcx
jl 0x5a27
leal (%rdx,%rbp), %eax
movq 0x8(%rbx), %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(%rbx), %rdx
cltq
leaq (%rdx,%rax,4), %rax
addq $0x4, %rax
jmp 0x5745
movl %ebp, %eax
movq 0x8(%rbx), %rcx
leaq (,%rcx,2), %rcx
addq %r13, %rcx
imulq 0x8(%rsp), %rcx
movq %rcx, %rdx
shrq $0x3f, %rdx
addq %rcx, %rdx
andq $-0x2, %rdx
addq %rdx, %rdx
addq 0x18(%rbx), %rdx
leaq (%rdx,%rax,4), %rax
jmp 0x5745
cmpl 0x4(%rsp), %ebp
movq 0x8(%rsp), %rsi
jge 0x5a16
movl %ebp, %eax
movq 0x8(%rbx), %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(%rbx), %rax
leaq (%rax,%rsi,4), %rax
movss %xmm0, (%rax)
incl %ebp
incl 0x14(%rsp)
xorl %r15d, %r15d
jmp 0x55eb
cmpl %ebp, %esi
jle 0x57a0
movq 0x8(%rbx), %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(%rbx), %rax
subss (%rax,%rsi,4), %xmm0
andps 0x2892(%rip), %xmm0     # 0x8020
movss 0x2872(%rip), %xmm1     # 0x8008
ucomiss %xmm0, %xmm1
ja 0x5749
jmp 0x5a3b
andps 0x2879(%rip), %xmm0     # 0x8020
movss 0x2859(%rip), %xmm1     # 0x8008
ucomiss %xmm0, %xmm1
ja 0x5749
jmp 0x5a31
movq 0x8(%rsp), %r15
testl %r15d, %r15d
setns %al
movq 0x30(%rsp), %rdx
cmpl $0x67, %edx
sete %cl
andb %al, %cl
cmpb $0x1, %cl
jne 0x5866
movl %ebp, %edx
movq (%rbx), %rax
cmpq %rdx, %rax
jne 0x57f3
imull %eax, %eax
movl $0x64, %edx
movq %rax, 0x18(%rsp)
jmp 0x5866
leaq -0x1(%rax), %rcx
cmpq %rdx, %rcx
jne 0x5843
imulq %rax, %rcx
movq %rcx, %rdx
shrq $0x3f, %rdx
addq %rcx, %rdx
shrq %rdx
movq %rdx, 0x18(%rsp)
movl $0x66, %edx
movl %eax, %ecx
addl $-0x2, %ecx
js 0x5866
movq 0x18(%rbx), %rsi
leaq 0x4(%rsi), %rdi
movabsq $0x3fffffffc, %rcx      # imm = 0x3FFFFFFFC
leaq (%rcx,%rax,4), %rdx
andq %rcx, %rdx
callq 0x21f0
movl $0x66, %edx
jmp 0x5866
testl %ebp, %ebp
jne 0x599d
imulq %rax, %rcx
movq %rcx, %rax
shrq $0x3f, %rax
addq %rcx, %rax
shrq %rax
movq %rax, 0x18(%rsp)
movl $0x65, %edx
movq %rbx, %rbp
leal 0x1(%r15), %ebx
movslq %ebx, %r15
cmpq %r15, (%rbp)
jle 0x5987
movl %ebx, 0x4(%rsp)
movq %rdx, %rbx
movq (%r14), %r13
movq %r13, %rdi
callq 0x20e0
leaq 0x1(%rax), %rdi
movl $0x1, %esi
callq 0x2160
movq 0x10(%rbp), %rcx
movq %rax, (%rcx,%r15,8)
movq 0x10(%rbp), %rax
movq (%rax,%r15,8), %rdi
testq %rdi, %rdi
je 0x5a0a
movq %r13, %rsi
callq 0x2090
xorl %r15d, %r15d
movq %rbx, %rbp
movl 0x4(%rsp), %ebx
jmp 0x55c8
movq 0x18(%rsp), %rax
cmpl %eax, 0x14(%rsp)
jne 0x5979
cmpl $0x64, 0x30(%rsp)
jne 0x5900
movq 0x18(%rbx), %rax
movss (%rax), %xmm0
andps 0x2731(%rip), %xmm0     # 0x8020
movss 0x2711(%rip), %xmm1     # 0x8008
ucomiss %xmm0, %xmm1
jbe 0x5998
movq (%rbx), %rbp
movl $0x4, %esi
movq %rbp, %rdi
callq 0x2160
movq %rax, %r13
movq %rax, 0x28(%rbx)
movl $0x4, %esi
movq %rbp, %rdi
callq 0x2160
movq %rax, 0x30(%rbx)
testq %r13, %r13
je 0x5980
testq %rax, %rax
je 0x5980
movq %r13, 0x38(%rbx)
movq %rax, 0x40(%rbx)
movq 0x18(%rbx), %rax
movq %rax, 0x20(%rbx)
movq 0x20(%rsp), %rax
cmpl $0x0, 0x28(%rax)
jne 0x5955
movq %r12, %rdi
callq 0x20d0
movq (%r14), %rdi
jmp 0x59d1
callq 0x25eb
xorl %r12d, %r12d
jmp 0x599d
callq 0x25a3
jmp 0x599d
callq 0x2587
jmp 0x599d
callq 0x256b
jmp 0x599d
callq 0x24fb
jmp 0x599d
callq 0x2517
jmp 0x599d
movq %rbp, %rbx
jmp 0x599d
movq 0x20(%rsp), %rdi
callq 0x25bf
jmp 0x595f
callq 0x2533
testq %r12, %r12
jne 0x59f9
testq %r12, %r12
je 0x59ba
movq 0x20(%rsp), %rax
cmpl $0x0, 0x28(%rax)
jne 0x59ba
movq %r12, %rdi
callq 0x20d0
testq %rbx, %rbx
je 0x59c7
movq %rbx, %rdi
callq 0x3c50
testq %r14, %r14
je 0x59f5
movq (%r14), %rdi
xorl %ebx, %ebx
testq %rdi, %rdi
je 0x59db
callq 0x2040
movq %r14, %rdi
callq 0x2040
movq %rbx, %rax
addq $0x48, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
xorl %ebx, %ebx
jmp 0x59e3
movq %r12, %rdi
callq 0x2607
jmp 0x59a2
callq 0x2437
jmp 0x599d
callq 0x24df
movq 0x28(%rsp), %rbx
jmp 0x599d
callq 0x2453
jmp 0x599d
callq 0x248b
jmp 0x599d
callq 0x246f
jmp 0x599d
callq 0x24a7
jmp 0x599d
callq 0x24c3
jmp 0x599d