// File: /workspace/github_c_makefile_star2_O3/sheneman[P]clearcut/fasta.c
// Function: NJ_read_fasta
NJ_alignment *
NJ_read_fasta(NJ_ARGS *nj_args) {

  FILE *fp  = NULL;
  char *buf = NULL;
  char *ptr = NULL;
  NJ_alignment *alignment = NULL;

  char c;
  int state;
  long int index, x, seq;
  long int i;
  long int bufsize, nseqs = NJ_INITIAL_NSEQS;
  int first_sequence_flag;


  

  /* 
   * In this function, we implement a FASTA alignment parser which
   * reads in an alignment character-by-character, maintaining state
   * information which guides the parser.
   *
   * The program reads either DNA or Protein alignments.  All title lines
   * and sequences can be arbitrarily long.  Gaps can be represented by 
   * "-" or "." characters.  
   *
   * Ambiguity codes are also handled.
   * 
   */

  /* 
   * We can't handle reading fasta input unless the user explicity 
   * specifies the input type...just to be sure.
   */
  if( (!nj_args->dna_flag && !nj_args->protein_flag) ||
      (nj_args->dna_flag  &&  nj_args->protein_flag) ) {
    fprintf(stderr, "Clearcut: Explicitly specify protein or DNA\n");
    goto XIT_BAD;
  }

  /* open specified fasta file here */
  if(nj_args->stdin_flag) {
    fp = stdin;
  } else {
    fp = fopen(nj_args->infilename, "r");
    if(!fp) {
      fprintf(stderr, "Clearcut: Failed to open input FASTA file: %s\n", nj_args->infilename);
      perror("Clearcut");
      goto XIT_BAD;
    }
  }

  /* allocate the initial buffer */
  bufsize = NJ_INITIAL_BUFFER_SIZE;
  buf = (char *)calloc(bufsize, sizeof(char));
  
  /* allocate the alignment container here */
  alignment = (NJ_alignment *)calloc(1, sizeof(NJ_alignment));
  
  /* allocate initial title array */
  //  printf("allocating initial title array\n");
  alignment->titles = (char **)calloc(NJ_INITIAL_NSEQS, sizeof(char *));

  /* make sure that we successfully allocated memory */
  if(!buf || !alignment || !alignment->titles) {
    fprintf(stderr, "Clearcut: Memory allocation error in NJ_read_fasta()\n");
    goto XIT_BAD;
  }

  /* a flag */
  first_sequence_flag = 1;  
  
  index  = 0;  /* tracks the position in buffer     */
  x      = 0;  /* tracks the position on sequence   */
  seq    = 0;  /* tracks the active sequence        */

  /* intitial state of state machine */
  state  = NJ_FASTA_MODE_UNKNOWN;

  while(1) {
    
    /* get the next character */
    c = fgetc(fp);
    if(feof(fp)) {

      if(state == NJ_FASTA_MODE_SEQUENCE) {
	buf[index+1] = '\0';

	/* copy buf to alignment */
	for(i=1;i<=alignment->length;i++) {
	  alignment->data[seq*alignment->length+i-1] = buf[i];
	}
      }

      break;
    }

    /* make sure our dynamic buffer is big enough */
    if(index >= bufsize) {
      bufsize *= 2;
      buf = (char *)realloc(buf, bufsize);
      if(!buf) {
	fprintf(stderr, "Clearcut: Memory allocation error in NJ_read_fasta()\n");
	goto XIT_BAD;
      }
    }

    switch(state) {
      
    case NJ_FASTA_MODE_UNKNOWN:
      
      if(!NJ_is_whitespace(c)) {
	if(c == '>') {
	  state = NJ_FASTA_MODE_TITLE;
	  buf[0] = '>';
	} else {
	  goto XIT_BAD;
	}
      }

      break;

    case NJ_FASTA_MODE_TITLE:

      if( c == '\n' ||
	  c == '\r' ) {

	buf[index] = '\0';
	state = NJ_FASTA_MODE_SEQUENCE;
	index = 0;
	x     = -1;

	/* make sure we've allocated enough space for titles and sequences */
	if(seq == nseqs) {

	  //	  printf("realloc().  seq = %d, nseqs = %d\n", seq, nseqs);

	  nseqs *= 2;

	  alignment->titles = (char **)realloc(alignment->titles, nseqs*sizeof(char *));
	  if(!alignment->titles) {
	    fprintf(stderr, "Clearcut:  Memory allocation error in NJ_read_fasta()\n");
	    goto XIT_BAD;
	  }

	  alignment->data = (char *)realloc(alignment->data, alignment->length*nseqs*sizeof(char));
	  if(!alignment->data) {
	    fprintf(stderr, "Clearcut: Allocation error in NJ_read_fasta()\n");
	    goto XIT_BAD;
	  }
	}

	// printf("Allocating %d bytes for title %d: %s\n", (int)strlen(buf), (int)seq, buf);

	alignment->titles[seq] = (char *)calloc(strlen(buf), sizeof(char));
	if(!alignment->titles[seq]) {
	  fprintf(stderr, "Clearcut:  Memory allocation error in NJ_read_fasta()\n");
	  goto XIT_BAD;
	}

	/* lets forward to the first non-space (space/tab) character after the '>' */

	if(first_sequence_flag) {
	  ptr = buf;
	} else {
	  ptr = &buf[1];
	}
	while(*ptr == '\t' || *ptr == ' ') {
	  ptr++;
	}
	sscanf(ptr, "%s", alignment->titles[seq]);  /* get the first word and use as the title */

	alignment->nseq++;
      }
	
      buf[index++] = c;

      break;


    case NJ_FASTA_MODE_SEQUENCE:

      if(c == '>') {

	if(first_sequence_flag) {
	  first_sequence_flag = 0;

	  /* allocate our alignment data section here */
	  alignment->length = index-1;

	  nseqs = NJ_INITIAL_NSEQS;
	  alignment->data = (char *)calloc(alignment->length*nseqs, sizeof(char));
	  if(!alignment->data) {
	    fprintf(stderr, "Clearcut: Allocation error in NJ_read_fasta()\n");
	    goto XIT_BAD;
	  }
	} 
	
	if(!first_sequence_flag) {
	  if(index-1 < alignment->length) {
	    fprintf(stderr, "Clearcut: Sequences must be of uniform length in alignment at sequence %ld\n", seq);
	    goto XIT_BAD;
	  }
	}

	/* re-allocate if necessary */
	/*
	if(seq >= nseqs) {
	  nseqs *= 2;
	  alignment->data = (char *)realloc(alignment->data, alignment->length*nseqs*sizeof(char));
	  if(!alignment->data) {
	    fprintf(stderr, "Clearcut: Allocation error in NJ_read_fasta()\n");
	    goto XIT_BAD;
	  }
	}
	*/

	/* copy buf to alignment */
	for(i=1;i<=alignment->length;i++) {
	  alignment->data[seq*alignment->length+i-1] = buf[i];
	}
	  
	state = NJ_FASTA_MODE_TITLE;
	index = 1;
	x     = 1;
	  
	buf[0] = c;
	
	seq++;

      } else {
	  
	if(NJ_is_whitespace(c)) {
	  break;
	}
		
	if(!first_sequence_flag) {
	  if(index-1 >= alignment->length) {
	    fprintf(stderr, "Clearcut: Sequences must be of uniform length in alignment at sequence %ld\n", seq);
	    goto XIT_BAD;
	  }
	}


	/* 
	 * Here we check to make sure that the symbol read is appropriate
	 * for the type of data the user specified.  (dna or protein).
	 * We also handle ambiguity codes by converting them to a specific
	 * assigned ambiguity code character.  Ambiguity codes are ignored
	 * when computing distances
	 */

	if(nj_args->dna_flag) {
	  if(NJ_is_dna(c)) {
	    buf[index++] = toupper(c);
	  } else {
	    if(NJ_is_dna_ambiguity(c)) {
	      buf[index++] = NJ_AMBIGUITY_CHAR;
	    } else {
	      fprintf(stderr, "Clearcut: Unknown symbol '%c' in nucleotide sequence %ld.\n", c, seq);
	      goto XIT_BAD;
	    }
	  }
	} else if(nj_args->protein_flag) {
	  if(NJ_is_protein(c)) {
	    buf[index++] = toupper(c);
	  } else {
	    if(NJ_is_protein_ambiguity(c)) {
	      buf[index++] = NJ_AMBIGUITY_CHAR;
	    } else {
	      fprintf(stderr, "Clearcut: Unknown symbol '%c' in protein sequence %ld.\n", c, seq);
	      goto XIT_BAD;
	    }
	  }
	}

      }

      break;
	
    default:
      goto XIT_BAD;
	
      break;

    }
  }
  
  if(index-1 != alignment->length) {
    fprintf(stderr, "Clearcut: Sequences must be of uniform length in alignment at sequence %ld\n", seq);
    goto XIT_BAD;
  }
  
  /* check for duplicate taxon labels */
  if(!NJ_taxaname_unique(alignment)) {
    goto XIT_BAD;
  }
  
  return(alignment);

  
 XIT_BAD:

  if(fp) {
    fprintf(stderr, "Clearcut: Fatal error parsing FASTA file at file offset %ld.\n", ftell(fp));
  }
  
  if(buf) {
    free(buf);
  }
  
  NJ_free_alignment(alignment);

  return(NULL);
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x38, %rsp
cmpl $0x0, 0x40(%rdi)
sete %al
cmpl $0x0, 0x44(%rdi)
sete %cl
xorb %al, %cl
je 0x64cb
movq %rdi, %r12
cmpl $0x0, 0x28(%rdi)
je 0x606e
movq 0x6f74(%rip), %rax      # 0xcfd8
movq (%rax), %rax
movq %rax, 0x20(%rsp)
jmp 0x608c
movq (%r12), %rdi
leaq 0x2be0(%rip), %rsi      # 0x8c59
callq 0x2200
movq %rax, 0x20(%rsp)
testq %rax, %rax
je 0x64fe
movl $0x200, %edi            # imm = 0x200
movl $0x1, %esi
callq 0x2160
movq %rax, %r15
movl $0x1, %edi
movl $0x20, %esi
callq 0x2160
movq %rax, %rbx
movl $0x40, %edi
movl $0x8, %esi
callq 0x2160
movq %rax, 0x10(%rbx)
testq %r15, %r15
je 0x64d2
testq %rbx, %rbx
je 0x64d2
testq %rax, %rax
je 0x64d2
movq 0x20(%rsp), %r14
movq %r14, %rdi
callq 0x2130
movl %eax, %r13d
movq %r14, %rdi
callq 0x21a0
testl %eax, %eax
je 0x612b
movq $0x0, 0x10(%rsp)
xorl %r12d, %r12d
movq 0x8(%rbx), %rax
decq %r12
cmpq %rax, %r12
jne 0x64dc
movq %rbx, %rdi
callq 0x65c7
testl %eax, %eax
jne 0x65a9
jmp 0x658a
movq %r12, 0x30(%rsp)
movq %rbx, 0x8(%rsp)
movl $0x67, %ebx
movl $0x200, %ebp            # imm = 0x200
movl $0x40, %ecx
movl $0x1, 0x1c(%rsp)
movq $0x0, 0x10(%rsp)
xorl %r12d, %r12d
cmpq %rbp, %r12
movq %rcx, 0x28(%rsp)
jl 0x6181
addq %rbp, %rbp
movq %r15, %rdi
movq %rbp, %rsi
callq 0x21e0
movq 0x28(%rsp), %rcx
movq %rax, %r15
testq %rax, %rax
je 0x650d
cmpl $0x64, %ebx
je 0x621b
cmpl $0x65, %ebx
je 0x61c9
cmpl $0x67, %ebx
jne 0x6585
movzbl %r13b, %eax
movl $0x67, %ebx
leal -0x9(%rax), %ecx
cmpl $0x5, %ecx
jb 0x63f0
cmpl $0x20, %eax
je 0x63f0
cmpb $0x3e, %r13b
jne 0x6585
movb $0x3e, (%r15)
jmp 0x63eb
movl %r13d, %eax
shll $0x18, %eax
cmpl $0x3e000000, %eax       # imm = 0x3E000000
jne 0x62fd
cmpl $0x0, 0x1c(%rsp)
je 0x6395
leaq -0x1(%r12), %rbx
movq 0x8(%rsp), %r14
movq %rbx, 0x8(%r14)
movq %rbx, %rdi
shlq $0x6, %rdi
movl $0x1, %esi
callq 0x2160
movq %rax, 0x18(%r14)
movl $0x40, %ecx
testq %rax, %rax
jne 0x639e
jmp 0x655e
cmpb $0xd, %r13b
je 0x6233
movzbl %r13b, %eax
movl $0x64, %ebx
cmpl $0xa, %eax
jne 0x62f1
movb $0x0, (%r15,%r12)
movq 0x8(%rsp), %rbx
movq 0x10(%rbx), %r12
cmpq %rcx, 0x10(%rsp)
jne 0x6290
movq %rcx, %rsi
shlq $0x4, %rsi
movq %r12, %rdi
movq %rcx, %r14
callq 0x21e0
movq %rax, 0x10(%rbx)
testq %rax, %rax
je 0x6550
movq %rax, %r12
addq %r14, %r14
movq 0x18(%rbx), %rdi
movq 0x8(%rbx), %rsi
movq %r14, 0x28(%rsp)
imulq %r14, %rsi
callq 0x21e0
movq %rax, 0x18(%rbx)
testq %rax, %rax
je 0x6557
movq %r15, %rdi
callq 0x20e0
movl $0x1, %esi
movq %rax, %rdi
callq 0x2160
movq 0x10(%rsp), %rcx
movq %rax, (%r12,%rcx,8)
testq %rax, %rax
je 0x6517
cmpl $0x1, 0x1c(%rsp)
movq %r15, %rdi
adcq $0x0, %rdi
movzbl (%rdi), %ecx
cmpl $0x20, %ecx
je 0x62d0
cmpl $0x9, %ecx
jne 0x62d5
incq %rdi
jmp 0x62c3
leaq 0x29cd(%rip), %rsi      # 0x8ca9
movq %rax, %rdx
xorl %eax, %eax
callq 0x21d0
incq (%rbx)
movl $0x65, %ebx
xorl %r12d, %r12d
movb %r13b, (%r15,%r12)
incq %r12
jmp 0x63f0
movzbl %r13b, %eax
movl $0x65, %ebx
leal -0x9(%rax), %ecx
cmpl $0x5, %ecx
jb 0x63f0
cmpl $0x20, %eax
je 0x63f0
cmpl $0x0, 0x1c(%rsp)
jne 0x6331
movq 0x8(%rsp), %rax
cmpq 0x8(%rax), %r12
jg 0x6531
movsbl %r13b, %r14d
movq 0x30(%rsp), %rax
cmpl $0x0, 0x40(%rax)
je 0x6417
callq 0x2030
movq (%rax), %rcx
movsbq %r13b, %rax
movsbl (%rcx,%rax,4), %eax
xorl %edx, %edx
leaq 0x2763(%rip), %rdi      # 0x8ac0
movsbl (%rdx,%rdi), %esi
cmpl %esi, %eax
je 0x6466
incq %rdx
cmpq $0x5, %rdx
jne 0x635d
xorl %ecx, %ecx
leaq 0x274a(%rip), %rsi      # 0x8ac5
movsbl (%rcx,%rsi), %edx
cmpl %edx, %eax
je 0x6475
incq %rcx
cmpq $0xe, %rcx
jne 0x637b
jmp 0x651e
movq 0x8(%rsp), %rax
movq 0x8(%rax), %rbx
cmpq %rbx, %r12
jle 0x6531
movq %rcx, 0x28(%rsp)
testq %rbx, %rbx
jle 0x63d5
movq %rbx, %rax
imulq 0x10(%rsp), %rax
movq 0x8(%rsp), %rcx
addq 0x18(%rcx), %rax
xorl %ecx, %ecx
movb 0x1(%r15,%rcx), %dl
movb %dl, (%rax,%rcx)
incq %rcx
cmpq %rbx, %rcx
jl 0x63c5
movb %r13b, (%r15)
incq 0x10(%rsp)
movl $0x0, 0x1c(%rsp)
movl $0x1, %r12d
movl $0x64, %ebx
movq 0x20(%rsp), %r14
movq %r14, %rdi
callq 0x2130
movl %eax, %r13d
movq %r14, %rdi
callq 0x21a0
testl %eax, %eax
movq 0x28(%rsp), %rcx
je 0x6158
jmp 0x647f
cmpl $0x0, 0x44(%rax)
je 0x63f0
callq 0x2030
movq (%rax), %rcx
movsbq %r13b, %rax
movsbl (%rcx,%rax,4), %eax
xorl %edx, %edx
leaq 0x26aa(%rip), %rdi      # 0x8ae0
movsbl (%rdx,%rdi), %esi
cmpl %esi, %eax
je 0x6466
incq %rdx
cmpq $0x14, %rdx
jne 0x6436
xorl %ecx, %ecx
leaq 0x26a4(%rip), %rsi      # 0x8af4
movsbl (%rcx,%rsi), %edx
cmpl %edx, %eax
je 0x6475
incq %rcx
cmpq $0x6, %rcx
jne 0x6450
jmp 0x6565
movslq %r14d, %rax
movb (%rcx,%rax,4), %al
movb %al, (%r15,%r12)
jmp 0x62f5
movb $0x3f, (%r15,%r12)
jmp 0x62f5
cmpl $0x65, %ebx
jne 0x64c1
movb $0x0, 0x1(%r12,%r15)
movq 0x8(%rsp), %rbx
movq 0x8(%rbx), %rax
testq %rax, %rax
jle 0x610a
movq %rax, %rcx
imulq 0x10(%rsp), %rcx
addq 0x18(%rbx), %rcx
xorl %edx, %edx
movb 0x1(%r15,%rdx), %sil
movb %sil, (%rcx,%rdx)
incq %rdx
cmpq %rax, %rdx
jl 0x64ab
jmp 0x610a
movq 0x8(%rsp), %rbx
jmp 0x6106
callq 0x26ad
jmp 0x6506
callq 0x2755
jmp 0x658a
movq 0x6b15(%rip), %rax      # 0xcff8
movq (%rax), %rdi
leaq 0x246a(%rip), %rsi      # 0x8957
movq 0x10(%rsp), %rdx
xorl %eax, %eax
callq 0x2180
jmp 0x658a
movq %r12, %rdi
callq 0x2796
xorl %ebx, %ebx
jmp 0x659f
callq 0x26c9
xorl %r15d, %r15d
jmp 0x6585
callq 0x2701
jmp 0x658a
movq 0x6ad3(%rip), %rax      # 0xcff8
movq (%rax), %rdi
leaq 0x2474(%rip), %rsi      # 0x89a3
jmp 0x6576
movq 0x6ac0(%rip), %rax      # 0xcff8
movq (%rax), %rdi
leaq 0x2415(%rip), %rsi      # 0x8957
movq 0x10(%rsp), %rdx
xorl %eax, %eax
callq 0x2180
jmp 0x6585
callq 0x2739
jmp 0x658a
callq 0x271d
jmp 0x658a
callq 0x26e5
jmp 0x6585
movq 0x6a8c(%rip), %rax      # 0xcff8
movq (%rax), %rdi
leaq 0x2468(%rip), %rsi      # 0x89de
movl %r14d, %edx
movq 0x10(%rsp), %rcx
xorl %eax, %eax
callq 0x2180
movq 0x8(%rsp), %rbx
cmpq $0x0, 0x20(%rsp)
jne 0x65bb
testq %r15, %r15
je 0x659f
movq %r15, %rdi
callq 0x2040
movq %rbx, %rdi
callq 0x665c
xorl %ebx, %ebx
movq %rbx, %rax
addq $0x38, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x20(%rsp), %rdi
callq 0x2771
jmp 0x6592