// File: /workspace/github_c_makefile_star2_O2/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 0x572c
cmpl $0x0, 0x28(%rdi)
movq %rdi, 0x28(%rsp)
je 0x52eb
movq 0x6cf2(%rip), %rax      # 0xbfd8
movq (%rax), %r15
jmp 0x5306
movq (%rdi), %rdi
leaq 0x2934(%rip), %rsi      # 0x7c29
callq 0x21f0
movq %rax, %r15
testq %rax, %rax
je 0x578b
pushq $0x1
popq %rbx
movl $0x200, %edi            # imm = 0x200
movq %rbx, %rsi
callq 0x2160
movq %rax, %r14
pushq $0x20
popq %rsi
movq %rbx, %rdi
callq 0x2160
movq %rax, %rbx
pushq $0x40
popq %rdi
pushq $0x8
popq %rsi
callq 0x2160
movq %rax, 0x10(%rbx)
testq %r14, %r14
je 0x574d
testq %rbx, %rbx
je 0x574d
testq %rax, %rax
je 0x574d
movq %r15, 0x8(%rsp)
pushq $0x1
popq %rax
movl %eax, 0x1c(%rsp)
movl $0x200, %eax            # imm = 0x200
movq %rax, 0x30(%rsp)
pushq $0x67
popq %r15
xorl %r13d, %r13d
movq $0x0, 0x10(%rsp)
pushq $0x40
popq %rax
movq %rax, 0x20(%rsp)
movq %rbx, %r12
movq %r13, %rbx
movq 0x8(%rsp), %r13
movq %r13, %rdi
callq 0x2130
movl %eax, %ebp
movq %r13, %rdi
callq 0x21a0
testl %eax, %eax
jne 0x56bc
movq %rbx, %r13
movq 0x30(%rsp), %rsi
cmpq %rsi, %rbx
jge 0x53b6
movq %r12, %rbx
jmp 0x53d5
addq %rsi, %rsi
movq %r14, %rdi
movq %rsi, 0x30(%rsp)
callq 0x21e0
movq %rax, %r14
testq %rax, %rax
movq %r12, %rbx
je 0x57c1
movzbl %bpl, %eax
cmpl $0x64, %r15d
je 0x5475
cmpl $0x65, %r15d
je 0x5428
cmpl $0x67, %r15d
jne 0x5869
cmpb $0x20, %bpl
ja 0x5411
movabsq $0x100003e00, %rcx      # imm = 0x100003E00
btq %rax, %rcx
pushq $0x67
popq %r15
jb 0x537f
cmpb $0x3e, %bpl
jne 0x5869
movb $0x3e, (%r14)
pushq $0x64
popq %r15
jmp 0x537f
movl %ebp, %ecx
shll $0x18, %ecx
cmpl $0x3e000000, %ecx       # imm = 0x3E000000
jne 0x553e
cmpl $0x0, 0x1c(%rsp)
je 0x55d7
leaq -0x1(%r13), %r15
movq %r15, 0x8(%rbx)
movq %r15, %rdi
shlq $0x6, %rdi
pushq $0x1
popq %rsi
callq 0x2160
movq %rax, 0x18(%rbx)
pushq $0x40
popq %rcx
movq %rcx, 0x20(%rsp)
testq %rax, %rax
jne 0x55db
jmp 0x5815
cmpb $0xd, %bpl
je 0x5484
cmpl $0xa, %eax
jne 0x55c7
movb $0x0, (%r14,%r13)
movq 0x10(%rbx), %r13
movq 0x10(%rsp), %r15
cmpq 0x20(%rsp), %r15
jne 0x54df
movq %r15, %rsi
shlq $0x4, %rsi
movq %r13, %rdi
callq 0x21e0
movq %rax, 0x10(%rbx)
testq %rax, %rax
je 0x57e5
movq %rax, %r13
leaq (%r15,%r15), %rax
movq 0x18(%rbx), %rdi
movq 0x8(%rbx), %rsi
movq %rax, 0x20(%rsp)
imulq %rax, %rsi
callq 0x21e0
movq %rax, 0x18(%rbx)
testq %rax, %rax
je 0x5815
movq %r14, %rdi
callq 0x20e0
movq %rax, %rdi
pushq $0x1
popq %rsi
callq 0x2160
movq %rax, (%r13,%r15,8)
testq %rax, %rax
je 0x57e5
movl 0x1c(%rsp), %ecx
movl %ecx, %edi
xorl $0x1, %edi
addq %r14, %rdi
movzbl (%rdi), %ecx
cmpl $0x20, %ecx
je 0x5519
cmpl $0x9, %ecx
jne 0x551e
incq %rdi
jmp 0x550c
leaq 0x2754(%rip), %rsi      # 0x7c79
movq %rax, %rdx
xorl %eax, %eax
callq 0x21d0
incq (%rbx)
pushq $0x65
popq %r15
xorl %r13d, %r13d
jmp 0x55cb
cmpb $0x20, %bpl
ja 0x555c
movabsq $0x100003e00, %rcx      # imm = 0x100003E00
btq %rax, %rcx
pushq $0x65
popq %r15
jb 0x537f
cmpl $0x0, 0x1c(%rsp)
jne 0x556d
cmpq 0x8(%rbx), %r13
jg 0x5833
movsbl %bpl, %r12d
movq 0x28(%rsp), %rax
cmpl $0x0, 0x40(%rax)
movsbq %bpl, %rbp
movslq %r12d, %rcx
movq 0x10(%rsp), %r15
je 0x5626
movq %r15, 0x10(%rsp)
movq %rcx, %r15
callq 0x2030
movq (%rax), %rcx
movsbl (%rcx,%rbp,4), %eax
xorl %edx, %edx
leaq 0x24e7(%rip), %rdi      # 0x7a90
cmpq $0x5, %rdx
je 0x566d
movsbl (%rdx,%rdi), %esi
incq %rdx
cmpl %esi, %eax
jne 0x55a9
movb (%rcx,%r15,4), %al
jmp 0x5667
pushq $0x64
popq %r15
movb %bpl, (%r14,%r13)
incq %r13
jmp 0x537f
movq 0x8(%rbx), %r15
cmpq %r15, %r13
jle 0x5833
movq %r15, %rax
imulq 0x10(%rsp), %rax
pushq $0x1
popq %rcx
cmpq %r15, %rcx
jg 0x5609
movb (%r14,%rcx), %dl
movq 0x18(%rbx), %rsi
addq %rax, %rsi
movb %dl, -0x1(%rcx,%rsi)
incq %rcx
jmp 0x55f0
movb %bpl, (%r14)
incq 0x10(%rsp)
movl $0x0, 0x1c(%rsp)
pushq $0x64
popq %r15
pushq $0x1
popq %r13
jmp 0x537f
cmpl $0x0, 0x44(%rax)
pushq $0x65
popq %r15
je 0x537f
movq %rcx, %r15
callq 0x2030
movq (%rax), %rdi
movsbl (%rdi,%rbp,4), %eax
xorl %edx, %edx
movq 0x10(%rsp), %rcx
leaq 0x245f(%rip), %r8       # 0x7ab0
cmpq $0x14, %rdx
je 0x568d
movsbl (%rdx,%r8), %esi
incq %rdx
cmpl %esi, %eax
jne 0x5651
movb (%rdi,%r15,4), %al
movb %al, (%r14,%r13)
jmp 0x56b0
xorl %ecx, %ecx
leaq 0x241f(%rip), %rsi      # 0x7a95
cmpq $0xe, %rcx
je 0x57fa
movsbl (%rcx,%rsi), %edx
incq %rcx
cmpl %edx, %eax
jne 0x5676
jmp 0x56ab
xorl %esi, %esi
leaq 0x242e(%rip), %rdi      # 0x7ac4
cmpq $0x6, %rsi
je 0x584e
movsbl (%rsi,%rdi), %edx
incq %rsi
cmpl %edx, %eax
jne 0x5696
movb $0x3f, (%r14,%r13)
incq %r13
pushq $0x65
popq %r15
jmp 0x537f
cmpl $0x65, %r15d
movq %rbx, %r9
jne 0x56fd
movb $0x0, 0x1(%r9,%r14)
movq %r12, %rbx
movq 0x8(%r12), %rax
movq %rax, %rcx
movq 0x10(%rsp), %rdx
imulq %rdx, %rcx
pushq $0x1
popq %r8
cmpq %rax, %r8
jg 0x570a
movb (%r14,%r8), %sil
movq 0x18(%rbx), %rdi
addq %rcx, %rdi
movb %sil, -0x1(%r8,%rdi)
incq %r8
jmp 0x56e3
movq %r12, %rbx
movq 0x8(%r12), %rax
movq 0x10(%rsp), %rdx
decq %r9
cmpq %rax, %r9
jne 0x576e
movq %rbx, %rdi
callq 0x58bf
testl %eax, %eax
movq 0x8(%rsp), %r15
jne 0x5885
jmp 0x586e
movq 0x68c5(%rip), %rax      # 0xbff8
movq (%rax), %rcx
leaq 0x20fa(%rip), %rdi      # 0x7837
pushq $0x2c
popq %rsi
pushq $0x1
popq %rdx
callq 0x2230
xorl %r14d, %r14d
jmp 0x57ba
movq 0x68a4(%rip), %rax      # 0xbff8
movq (%rax), %rcx
leaq 0x2135(%rip), %rdi      # 0x7893
pushq $0x35
popq %rsi
pushq $0x1
popq %rdx
callq 0x2230
jmp 0x586e
movq 0x6883(%rip), %rax      # 0xbff8
movq (%rax), %rdi
leaq 0x21b0(%rip), %rsi      # 0x792f
xorl %eax, %eax
callq 0x2180
jmp 0x5869
movq 0x6866(%rip), %rax      # 0xbff8
movq (%rax), %rdi
movq 0x28(%rsp), %rax
movq (%rax), %rdx
leaq 0x20c0(%rip), %rsi      # 0x7864
xorl %r14d, %r14d
xorl %eax, %eax
callq 0x2180
leaq 0x1e46(%rip), %rdi      # 0x75fb
callq 0x2200
xorl %ebx, %ebx
jmp 0x5873
movq 0x6830(%rip), %rax      # 0xbff8
movq (%rax), %rcx
leaq 0x20c1(%rip), %rdi      # 0x7893
pushq $0x35
popq %rsi
pushq $0x1
popq %rdx
callq 0x2230
xorl %r14d, %r14d
jmp 0x5869
movq 0x680c(%rip), %rax      # 0xbff8
movq (%rax), %rcx
leaq 0x20d3(%rip), %rdi      # 0x78c9
pushq $0x36
jmp 0x5828
movq 0x67f7(%rip), %rax      # 0xbff8
movq (%rax), %rdi
leaq 0x2170(%rip), %rsi      # 0x797b
movl %r12d, %edx
movq 0x10(%rsp), %rcx
jmp 0x5862
movq 0x67dc(%rip), %rax      # 0xbff8
movq (%rax), %rcx
leaq 0x20da(%rip), %rdi      # 0x7900
pushq $0x2e
popq %rsi
pushq $0x1
popq %rdx
callq 0x2230
jmp 0x5869
movq 0x67be(%rip), %rax      # 0xbff8
movq (%rax), %rdi
leaq 0x20eb(%rip), %rsi      # 0x792f
movq 0x10(%rsp), %rdx
jmp 0x577f
movq 0x67a3(%rip), %rax      # 0xbff8
movq (%rax), %rdi
leaq 0x2157(%rip), %rsi      # 0x79b6
movl %r12d, %edx
xorl %eax, %eax
callq 0x2180
movq 0x8(%rsp), %r15
testq %r15, %r15
jne 0x5897
movq %r14, %rdi
callq 0x2040
movq %rbx, %rdi
callq 0x5950
xorl %ebx, %ebx
movq %rbx, %rax
addq $0x38, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x675a(%rip), %rax      # 0xbff8
movq (%rax), %r12
movq %r15, %rdi
callq 0x2190
leaq 0x213e(%rip), %rsi      # 0x79ee
movq %r12, %rdi
movq %rax, %rdx
xorl %eax, %eax
callq 0x2180
jmp 0x5873