Ejemplo n.º 1
0
/* See comments in p3_seq_lib.h */
seq_lib *
read_and_create_seq_lib(const char * filename, const char *errfrag) {
    char  *p;
    FILE *file;
    char *seq_id_plus = NULL;
    char *seq = NULL;
    size_t seq_storage_size;
    size_t seq_len;

    seq_lib *lib = create_empty_seq_lib();
    if (NULL == lib) return NULL; /* ENOMEM */

    if (setjmp(_jmp_buf) != 0)
      return NULL; /* If we get here, there was an error in
		      p3sl_safe_malloc or p3sl_safe_realloc. */


    lib->repeat_file = (char*) p3sl_safe_malloc(strlen(filename) + 1);
    strcpy(lib->repeat_file, filename);

    if((file = fopen(lib->repeat_file,"r")) == NULL) {
	p3sl_append_new_chunk(&lib->error,
			    "Cannot open ");
	goto ERROR;
    }

    seq = (char*) p3sl_safe_malloc(P3SL_INIT_BUF_SIZE);
    seq_storage_size = P3SL_INIT_BUF_SIZE;
    seq_len = 0;
    *seq = '\0';

    /* Read in the lines from the file */
    while(1) {
      p = p3_read_line(file);

      if (NULL == p) {
	/* End of file */
	if (seq_id_plus != NULL) {
	    if (seq_len == 0) {
	      p3sl_append_new_chunk(&lib->error,
				    "Empty sequence in ");
	      goto ERROR;
	    } else {
	      if (add_seq_to_seq_lib(lib, seq, seq_id_plus, errfrag)) {
		p3sl_append(&lib->error, " in ");
		goto ERROR;
	      }
	    }
	    free(seq_id_plus);
	    seq_id_plus = NULL;
	}
	break;
      }

      if ('>' == *p) {
	/* We found an id line */
	/* There are two possibilities */
	if (seq_id_plus == NULL) {
	  /* 1. This is the first id line in the file,
	     in which case seq_id_plus == NULL
	     (and seq_len == 0). */
	  seq_id_plus = (char*) p3sl_safe_malloc(strlen(p) + 1);
	  p++;  /* skip past the '>' */
	  strcpy(seq_id_plus, p);
	} else {
	  /* 2. This is NOT the first id line in the
	     file, in which case seq_id_plus != NULL */
	  if (seq_id_plus != NULL) {
	    if (seq_len == 0) {
	      p3sl_append_new_chunk(&lib->error,
				    "Empty sequence in ");
	      goto ERROR;
	    } else {
	      if (add_seq_to_seq_lib(lib, seq, seq_id_plus, errfrag)) {
		p3sl_append(&lib->error, " in ");
		goto ERROR;
	      }
	      /*"emtpy" the buffer */
	      seq_len = 0;
	      *seq = '\0';
	    }
	    free(seq_id_plus);
	    seq_id_plus = (char*) p3sl_safe_malloc(strlen(p));
	    p++;  /* skip past the '>' */
	    strcpy(seq_id_plus, p);
	  }
	}
      } else {
	/* A sequence line */
	if (seq_id_plus == NULL) {
	  p3sl_append_new_chunk(&lib->error,
				    "Missing id line (expected '>') in ");
	  goto ERROR;
	}
	while ( strlen(p)+ seq_len + 1 > seq_storage_size ) {
	  seq_storage_size *= 2;
	  seq = (char*) p3sl_safe_realloc(seq, seq_storage_size);
	}
	strcat(seq, p);
	seq_len += strlen(p);
      }
    }

    if (lib->seq_num == 0) {
      	p3sl_append_new_chunk(&lib->error, "Empty ");
	goto ERROR;
    }

    reverse_complement_seq_lib(lib);

    if (file) fclose(file);
    free(seq);
    free(seq_id_plus);
    return lib;

 ERROR:
    free(seq);
    free(seq_id_plus);
    p3sl_append(&lib->error, errfrag);
    p3sl_append(&lib->error, " ");
    p3sl_append(&lib->error, lib->repeat_file);
    if (file) fclose(file);
    return lib;
}
Ejemplo n.º 2
0
int 
read_p3_file(const char *file_name,
	     const p3_file_type expected_file_type,
	     int echo_output,
	     int strict_tags,
	     p3_global_settings *pa, 
	     seq_args *sa,
	     pr_append_str *fatal_err,
	     pr_append_str *nonfatal_err,
	     pr_append_str *warnings,
	     read_boulder_record_results *read_boulder_record_res) 
{
  FILE *file;
  int ret_par = 0;
  int io_version = 4;
  char *line1;
  char *line2;
  char *line3;
  p3_file_type file_type = all_parameters;
    
  /* Check if a file name was provided */
  PR_ASSERT(NULL != file_name);

  /* Open the file */
  if (!(file = fopen(file_name,"r"))) {
    pr_append2(fatal_err, "Cannot open ", file_name);
    return ret_par;
  }

  /* Parse and interpret the first 3 lines */

  /* Line 1 */
  line1 = p3_read_line(file);
  if (!line1) {
    pr_append2(fatal_err, 
	       "Settings file is empty: ", 
	       file_name);
    return ret_par;
  }
  if (strcmp(line1,
	     "Primer3 File - http://primer3.sourceforge.net")) {
      pr_append2(fatal_err,
		 "First line must be \"Primer3 File - http://primer3.sourceforge.net\" in ",
		 file_name);
      return ret_par;
  }

  /* Line 2 */
  line2 = p3_read_line(file);
  if (!line2) {
    pr_append2(fatal_err, 
	       "Incorrect file format (too few lines) in ", 
	       file_name);
    return ret_par;
  }
  if (!strcmp(line2,"P3_FILE_TYPE=all_parameters")) {
    file_type = all_parameters;
  } else if (!strcmp(line2,"P3_FILE_TYPE=sequence")) {
    file_type = sequence;
  } else if (!strcmp(line2,"P3_FILE_TYPE=settings")) {
    file_type = settings;
  } else {
    pr_append2(fatal_err, 
	       "Unknown file type in at line 2 (line2='", line2);
    pr_append(fatal_err, "') in ");
    pr_append(fatal_err, file_name);
    return ret_par;
  }
  if (echo_output) {
    printf("P3_SETTINGS_FILE_USED=%s\n", file_name);
    printf("%s\n", line2);
  }

  /* Line 3 */
  line3 = p3_read_line(file);
  if (!line3) {
    pr_append2(fatal_err, 
	       "Incorrect file format (too few lines) in ", 
	       file_name);
      return ret_par;
  }
  if (strcmp(line3, "")) {
    pr_append2(fatal_err, "Line 3 must be empty in ",
	       file_name);
    return ret_par;
  }

  /* Check if the file type matches the expected type */
  if (file_type != expected_file_type){
    pr_append_new_chunk(nonfatal_err, 
			"Unexpected P3 file type parsed");
  }

  /* read the file */
  ret_par = read_boulder_record(file, &strict_tags, &io_version, 
				echo_output, expected_file_type,
				pa, sa, fatal_err, 
				nonfatal_err, warnings, 
				read_boulder_record_res);

  if (echo_output) printf("P3_SETTINGS_FILE_END=\n");
  if (file) fclose(file);
         
  return ret_par;
}
Ejemplo n.º 3
0
/* 
 * See read_boulder.h for description.
 */
int
read_record(FILE *file_input,
		const int *strict_tags,
	    const int *io_version,
	    int   echo_output,
	    const p3_file_type read_file_type,
	    p3_global_settings *pa, 
	    seq_args *sa, 
	    pr_append_str *glob_err,  /* Really should be called fatal_parse_err */
	    pr_append_str *nonfatal_parse_err) { 
    int line_len; /* seq_len; n_quality; */
    int tag_len, datum_len;
    int data_found = 0;
    p3_file_type file_type = all_parameters;
    int pick_internal_oligo = 2;
    char *s, *n, *datum, *task_tmp = NULL;
    const char *p;
    pr_append_str *parse_err;
    pr_append_str *non_fatal_err;
    char *repeat_file_path = NULL, *int_repeat_file_path = NULL;

    /* FIX ME call p3_create_seq_args inside read_boulder? */

    non_fatal_err = nonfatal_parse_err;

    while ((s = p3_read_line(file_input)) != NULL && strcmp(s,"=")) {
    /* Deal with the file headers */
    if ((strcmp(s,"Primer3 File - http://primer3.sourceforge.net")) == 0) {
    	/* read FILE_TYPE */
    	if ((s = p3_read_line(file_input)) == NULL && !(strcmp(s,"=")))
    		break;
    	if ((strcmp(s,"P3_FILE_TYPE=all_parameters")) == 0) {
    		file_type = all_parameters;
    	}
    	else if ((strcmp(s,"P3_FILE_TYPE=sequence")) == 0) {
    		file_type = sequence;
    	}
    	else if ((strcmp(s,"P3_FILE_TYPE=settings")) == 0) {
    		file_type = settings;
    	}
    	else {
    	    pr_append_new_chunk(glob_err, "Unknown P3_FILE_TYPE");
    	}
    	/* read the empty line */
    	if ((s = p3_read_line(file_input)) == NULL && !(strcmp(s,"=")))
    		break;
    	/* Check if the file type matches the expected type */
    	if (file_type != read_file_type && echo_output){
    		pr_append_new_chunk(nonfatal_parse_err, 
    				"Unexpected P3 file type parsed");
    	}
    	continue;
    }
    /* Read only the PRIMER tags if settings is selected */
    if (read_file_type == settings && strncmp(s, "PRIMER_", 7)
    			&& strncmp(s, "P3_FILE_ID", 10)) {
    	continue;
    }
    /* Silently ignore all primer3plus tags */
    if (!(strncmp(s, "P3P_", 4))) {
    	continue;
    }
    
    
	data_found = 1;
	/* Print out the input */
	if (echo_output) printf("%s\n", s);
	line_len = strlen(s);
	/* If the line has an "=" read the tag in the right place */
	if ((n=strchr(s,'=')) == NULL) {
	    /* The input line is illegal because it has no
	     * "=" in it, but we still will read to the end
	     * of the record. */
	    pr_append_new_chunk(glob_err, "Input line with no '=': ");
	    pr_append(glob_err, s);
	} else {
	    /* Get the tag and the value pointers */
	    tag_len = n - s;
	    datum = n + 1;
	    datum_len = line_len - tag_len - 1;
	    
	    /* Process "Sequence" (i.e. Per-Record) Arguments". */
	    parse_err = non_fatal_err;
	    
	    /* Process the old sequence Tags*/
	    if (*io_version == 0) {
		    /* COMPARE_AND_MALLOC("SEQUENCE", sa->sequence); */
		    if (COMPARE("SEQUENCE")) {   /* NEW WAY */
		      if (/* p3_get_seq_arg_sequence(sa) */ sa->sequence) {
			    pr_append_new_chunk(parse_err, "Duplicate tag: ");
			    pr_append(parse_err, "SEQUENCE"); 
		      } else {
			if (p3_set_sa_sequence(sa, datum)) exit(-2);
		      }
		      continue;
		    }
		
		    if (COMPARE("PRIMER_SEQUENCE_QUALITY")) {
		      if ((sa->n_quality = parse_seq_quality(datum, &sa->quality)) == 0) {
			pr_append_new_chunk(parse_err,
					    "Error in sequence quality data");
			/* continue;  // FIX ME superfluous ? */
		      }
		      continue;
		    }
		
		
		    COMPARE_AND_MALLOC("PRIMER_SEQUENCE_ID", sa->sequence_name);
		    COMPARE_AND_MALLOC("MARKER_NAME", sa->sequence_name);
		    COMPARE_AND_MALLOC("PRIMER_LEFT_INPUT", sa->left_input);
		    COMPARE_AND_MALLOC("PRIMER_RIGHT_INPUT", sa->right_input);
		    COMPARE_AND_MALLOC("PRIMER_INTERNAL_OLIGO_INPUT", sa->internal_input);
		
		    COMPARE_INTERVAL_LIST("TARGET", &sa->tar2);
		    COMPARE_INTERVAL_LIST("EXCLUDED_REGION", &sa->excl2);
		    COMPARE_INTERVAL_LIST("PRIMER_INTERNAL_OLIGO_EXCLUDED_REGION",
					  &sa->excl_internal2);
		
		    if (COMPARE("INCLUDED_REGION")) {
			    p = parse_int_pair("INCLUDED_REGION", datum, ',',
					   &sa->incl_s, &sa->incl_l, parse_err);
			    if (NULL == p) /* 
		                            * An error; the message is already
		                            * in parse_err.
		                            */
			        continue;
		
			    while (' ' == *p || '\t' == *p) p++;
			    if (*p != '\n' && *p != '\0')
			       tag_syntax_error("INCLUDED_REGION", datum,
					     parse_err);
			    continue;
		    }
		    COMPARE_INT("PRIMER_START_CODON_POSITION", sa->start_codon_pos);
	    }
	    /* Process the new sequence Tags*/
	    else {
		    /* COMPARE_AND_MALLOC("SEQUENCE", sa->sequence); */
		    if (COMPARE("SEQUENCE_DNA")) {   /* NEW WAY */
		      if (/* p3_get_seq_arg_sequence(sa) */ sa->sequence) {
			    pr_append_new_chunk(parse_err, "Duplicate tag: ");
			    pr_append(parse_err, "SEQUENCE_DNA"); 
		      } else {
			if (p3_set_sa_sequence(sa, datum)) exit(-2);
		      }
		      continue;
		    }
		
		    if (COMPARE("SEQUENCE_QUALITY")) {
		      if ((sa->n_quality = parse_seq_quality(datum, &sa->quality)) == 0) {
			pr_append_new_chunk(parse_err,
					    "Error in sequence quality data");
			/* continue;  // FIX ME superfluous ? */
		      }
		      continue;
		    }
		
		
		    COMPARE_AND_MALLOC("SEQUENCE_ID", sa->sequence_name);
		    COMPARE_AND_MALLOC("SEQUENCE_PRIMER", sa->left_input);
		    COMPARE_AND_MALLOC("SEQUENCE_PRIMER_REVCOMP", sa->right_input);
		    COMPARE_AND_MALLOC("SEQUENCE_OLIGO", sa->internal_input);
		
		    COMPARE_INTERVAL_LIST("SEQUENCE_TARGET", &sa->tar2);
		    COMPARE_INTERVAL_LIST("SEQUENCE_EXCLUDED_REGION", &sa->excl2);
		    COMPARE_INTERVAL_LIST("SEQUENCE_INTERNAL_EXCLUDED_REGION",
					  &sa->excl_internal2);
		
		    if (COMPARE("SEQUENCE_INCLUDED_REGION")) {
			    p = parse_int_pair("SEQUENCE_INCLUDED_REGION", datum, ',',
					   &sa->incl_s, &sa->incl_l, parse_err);
			    if (NULL == p) /* 
		                            * An error; the message is already
		                            * in parse_err.
		                            */
			        continue;
		
			    while (' ' == *p || '\t' == *p) p++;
			    if (*p != '\n' && *p != '\0')
			       tag_syntax_error("SEQUENCE_INCLUDED_REGION", datum,
					     parse_err);
			    continue;
		    }
		    COMPARE_INT("SEQUENCE_START_CODON_POSITION", sa->start_codon_pos);
	    }
	    
	    /* 
	     * Process "Global" Arguments (those that persist between boulder
	     * records).
	     */
	    parse_err = glob_err;  /* These errors are considered fatal. */
	    if (COMPARE("PRIMER_PRODUCT_SIZE_RANGE")
		|| COMPARE("PRIMER_DEFAULT_PRODUCT")) {
		    parse_product_size("PRIMER_PRODUCT_SIZE_RANGE", datum, pa,
				   parse_err);
		    continue;
	    }
	    COMPARE_INT("PRIMER_DEFAULT_SIZE", pa->p_args.opt_size);
	    COMPARE_INT("PRIMER_OPT_SIZE", pa->p_args.opt_size);
	    COMPARE_INT("PRIMER_MIN_SIZE", pa->p_args.min_size);
	    COMPARE_INT("PRIMER_MAX_SIZE", pa->p_args.max_size);
	    COMPARE_INT("PRIMER_MAX_POLY_X", pa->p_args.max_poly_x);
	    COMPARE_FLOAT("PRIMER_OPT_TM", pa->p_args.opt_tm);
	    COMPARE_FLOAT("PRIMER_OPT_GC_PERCENT", pa->p_args.opt_gc_content);
	    COMPARE_FLOAT("PRIMER_MIN_TM", pa->p_args.min_tm);
	    COMPARE_FLOAT("PRIMER_MAX_TM", pa->p_args.max_tm);
	    COMPARE_FLOAT("PRIMER_MAX_DIFF_TM", pa->max_diff_tm);

	    if (*io_version == 0) {
	    	COMPARE_INT("PRIMER_TM_SANTALUCIA",	pa->tm_santalucia);    /* added by T.Koressaar */
	    } else {
	    	COMPARE_INT("PRIMER_TM_FORMULA",	pa->tm_santalucia);    /* added by T.Koressaar */
	    }
	    COMPARE_INT("PRIMER_SALT_CORRECTIONS", pa->salt_corrections); /* added by T.Koressaar */
	    COMPARE_FLOAT("PRIMER_MIN_GC", pa->p_args.min_gc);
	    COMPARE_FLOAT("PRIMER_MAX_GC", pa->p_args.max_gc);
	    
	    /* begin of added by T.Koressaar: */
	    if (*io_version == 0) {
	    	COMPARE_FLOAT("PRIMER_SALT_CONC", pa->p_args.salt_conc);
		    COMPARE_FLOAT("PRIMER_DIVALENT_CONC", pa->p_args.divalent_conc);
	    } else {
	    	COMPARE_FLOAT("PRIMER_SALT_MONOVALENT", pa->p_args.salt_conc);
		    COMPARE_FLOAT("PRIMER_SALT_DIVALENT", pa->p_args.divalent_conc);
	    }
	    COMPARE_FLOAT("PRIMER_DNTP_CONC", pa->p_args.dntp_conc);

	    /* end of added by T.Koressaar: */
    
	    COMPARE_FLOAT("PRIMER_DNA_CONC", pa->p_args.dna_conc);
	    COMPARE_INT("PRIMER_NUM_NS_ACCEPTED", pa->p_args.num_ns_accepted);
	    COMPARE_INT("PRIMER_PRODUCT_OPT_SIZE", pa->product_opt_size);
	    COMPARE_ALIGN_SCORE("PRIMER_SELF_ANY", pa->p_args.max_self_any);
	    COMPARE_ALIGN_SCORE("PRIMER_SELF_END", pa->p_args.max_self_end);
	    COMPARE_ALIGN_SCORE("PRIMER_PAIR_ANY", pa->pair_compl_any);
	    COMPARE_ALIGN_SCORE("PRIMER_PAIR_END", pa->pair_compl_end);
	    if (*io_version == 0) {
	    	COMPARE_INT("PRIMER_FILE_FLAG", pa->file_flag);
	    } else {
	    	COMPARE_INT("P3_FILE_FLAG", pa->file_flag);
	    }
	    COMPARE_INT("PRIMER_PICK_ANYWAY", pa->pick_anyway);
	    COMPARE_INT("PRIMER_GC_CLAMP", pa->gc_clamp);
	    COMPARE_INT("PRIMER_EXPLAIN_FLAG", pa->explain_flag);
	    COMPARE_INT("PRIMER_LIBERAL_BASE", pa->liberal_base);
	    COMPARE_INT("PRIMER_FIRST_BASE_INDEX", pa->first_base_index);
	    COMPARE_INT("PRIMER_NUM_RETURN", pa->num_return);
	    COMPARE_INT("PRIMER_MIN_QUALITY", pa->p_args.min_quality);
	    COMPARE_INT("PRIMER_MIN_END_QUALITY", pa->p_args.min_end_quality);
	    COMPARE_INT("PRIMER_MIN_THREE_PRIME_DISTANCE", 
			pa->min_three_prime_distance);
	    if (*io_version > 0 && file_type == settings) {
	    	COMPARE_AND_MALLOC("P3_FILE_ID", pa->settings_file_id);
	    }
	    COMPARE_INT("PRIMER_QUALITY_RANGE_MIN", pa->quality_range_min);
        COMPARE_INT("PRIMER_QUALITY_RANGE_MAX", pa->quality_range_max);
	    COMPARE_FLOAT("PRIMER_PRODUCT_MAX_TM", pa->product_max_tm);
	    COMPARE_FLOAT("PRIMER_PRODUCT_MIN_TM", pa->product_min_tm);
	    COMPARE_FLOAT("PRIMER_PRODUCT_OPT_TM", pa->product_opt_tm);
	    COMPARE_AND_MALLOC("PRIMER_TASK", task_tmp);

	    if (0 < *io_version) {
		    COMPARE_INT("PRIMER_PICK_RIGHT_PRIMER", pa->pick_right_primer);
		    COMPARE_INT("PRIMER_PICK_INTERNAL_OLIGO", pa->pick_internal_oligo);
		    COMPARE_INT("PRIMER_PICK_LEFT_PRIMER", pa->pick_left_primer);
	    }
	    else {
		    COMPARE_INT("PRIMER_PICK_INTERNAL_OLIGO", pick_internal_oligo);
	    }
	    
	    COMPARE_INT("PRIMER_INTERNAL_OLIGO_OPT_SIZE", pa->o_args.opt_size);
	    COMPARE_INT("PRIMER_INTERNAL_OLIGO_MAX_SIZE", pa->o_args.max_size);
	    COMPARE_INT("PRIMER_INTERNAL_OLIGO_MIN_SIZE", pa->o_args.min_size);
	    COMPARE_INT("PRIMER_INTERNAL_OLIGO_MAX_POLY_X", pa->o_args.max_poly_x);
	    COMPARE_FLOAT("PRIMER_INTERNAL_OLIGO_OPT_TM", pa->o_args.opt_tm);
	    COMPARE_FLOAT("PRIMER_INTERNAL_OLIGO_OPT_GC_PERCENT",
			  pa->o_args.opt_gc_content);
	    COMPARE_FLOAT("PRIMER_INTERNAL_OLIGO_MAX_TM", pa->o_args.max_tm);
	    COMPARE_FLOAT("PRIMER_INTERNAL_OLIGO_MIN_TM", pa->o_args.min_tm);
	    COMPARE_FLOAT("PRIMER_INTERNAL_OLIGO_MIN_GC", pa->o_args.min_gc);
            COMPARE_FLOAT("PRIMER_INTERNAL_OLIGO_MAX_GC", pa->o_args.max_gc);
	    COMPARE_FLOAT("PRIMER_INTERNAL_OLIGO_SALT_CONC",  pa->o_args.salt_conc);

	    COMPARE_FLOAT("PRIMER_INTERNAL_OLIGO_DIVALENT_CONC",
			  pa->o_args.divalent_conc); /* added by T.Koressaar */
	    COMPARE_FLOAT("PRIMER_INTERNAL_OLIGO_DNTP_CONC",
			  pa->o_args.dntp_conc); /* added by T.Koressaar */

	    COMPARE_FLOAT("PRIMER_INTERNAL_OLIGO_DNA_CONC", pa->o_args.dna_conc);
	    COMPARE_INT("PRIMER_INTERNAL_OLIGO_NUM_NS", pa->o_args.num_ns_accepted);
	    COMPARE_INT("PRIMER_INTERNAL_OLIGO_MIN_QUALITY", pa->o_args.min_quality);

	    COMPARE_ALIGN_SCORE("PRIMER_INTERNAL_OLIGO_SELF_ANY",
				pa->o_args.max_self_any);
	    COMPARE_ALIGN_SCORE("PRIMER_INTERNAL_OLIGO_SELF_END", 
				pa->o_args.max_self_end);
	    COMPARE_ALIGN_SCORE("PRIMER_MAX_MISPRIMING",
				pa->p_args.max_repeat_compl);
	    COMPARE_ALIGN_SCORE("PRIMER_INTERNAL_OLIGO_MAX_MISHYB",
				pa->o_args.max_repeat_compl);
	    COMPARE_ALIGN_SCORE("PRIMER_PAIR_MAX_MISPRIMING",
				pa->pair_repeat_compl);

	    /* Mispriming / mishybing in the template. */
	    COMPARE_ALIGN_SCORE("PRIMER_MAX_TEMPLATE_MISPRIMING",
				pa->p_args.max_template_mispriming);
	    COMPARE_ALIGN_SCORE("PRIMER_PAIR_MAX_TEMPLATE_MISPRIMING",
				pa->pair_max_template_mispriming);
	    COMPARE_ALIGN_SCORE("PRIMER_INTERNAL_OLIGO_MAX_TEMPLATE_MISHYB",
				pa->o_args.max_template_mispriming);

            /* Control interpretation of ambiguity codes in mispriming
               and mishyb libraries. */
	    COMPARE_INT("PRIMER_LIB_AMBIGUITY_CODES_CONSENSUS",
			pa->lib_ambiguity_codes_consensus);


	    COMPARE_FLOAT("PRIMER_INSIDE_PENALTY", pa->inside_penalty);
	    COMPARE_FLOAT("PRIMER_OUTSIDE_PENALTY", pa->outside_penalty);
        if (COMPARE("PRIMER_MISPRIMING_LIBRARY")) {
		if (repeat_file_path != NULL) {
		    pr_append_new_chunk(glob_err,
					"Duplicate PRIMER_MISPRIMING_LIBRARY tag");
		    free(repeat_file_path);
		    repeat_file_path = NULL;
		} else {
		    repeat_file_path = _rb_safe_malloc(strlen(datum) + 1);
		    strcpy(repeat_file_path, datum);
		}
		continue;
	    }
        if (COMPARE("PRIMER_INTERNAL_OLIGO_MISHYB_LIBRARY")) {
		if (int_repeat_file_path != NULL) {
		    pr_append_new_chunk(glob_err,
					"Duplicate PRIMER_INTERNAL_OLIGO_MISHYB_LIBRARY tag");
		    free(int_repeat_file_path);
		    int_repeat_file_path = NULL;
		} else {
		    int_repeat_file_path = _rb_safe_malloc(strlen(datum) + 1);
		    strcpy(int_repeat_file_path, datum);
		}
		continue;
	    }
	    if (COMPARE("PRIMER_COMMENT") || COMPARE("COMMENT")) continue;
	    COMPARE_FLOAT("PRIMER_MAX_END_STABILITY", pa->max_end_stability);

	    COMPARE_INT("PRIMER_LOWERCASE_MASKING",
			pa->lowercase_masking); /* added by T. Koressaar */

	    /* weights for objective functions  */
            /* CHANGE TEMP/temp -> TM/tm */
	    COMPARE_FLOAT("PRIMER_WT_TM_GT", pa->p_args.weights.temp_gt);
	    COMPARE_FLOAT("PRIMER_WT_TM_LT", pa->p_args.weights.temp_lt);
	    COMPARE_FLOAT("PRIMER_WT_GC_PERCENT_GT", pa->p_args.weights.gc_content_gt);
	    COMPARE_FLOAT("PRIMER_WT_GC_PERCENT_LT", pa->p_args.weights.gc_content_lt);
	    COMPARE_FLOAT("PRIMER_WT_SIZE_LT", pa->p_args.weights.length_lt);
	    COMPARE_FLOAT("PRIMER_WT_SIZE_GT", pa->p_args.weights.length_gt);
	    COMPARE_FLOAT("PRIMER_WT_COMPL_ANY", pa->p_args.weights.compl_any);
	    COMPARE_FLOAT("PRIMER_WT_COMPL_END", pa->p_args.weights.compl_end);
	    COMPARE_FLOAT("PRIMER_WT_NUM_NS", pa->p_args.weights.num_ns);
	    COMPARE_FLOAT("PRIMER_WT_REP_SIM", pa->p_args.weights.repeat_sim);
	    COMPARE_FLOAT("PRIMER_WT_SEQ_QUAL", pa->p_args.weights.seq_quality);
	    COMPARE_FLOAT("PRIMER_WT_END_QUAL", pa->p_args.weights.end_quality);
	    COMPARE_FLOAT("PRIMER_WT_POS_PENALTY", pa->p_args.weights.pos_penalty);
	    COMPARE_FLOAT("PRIMER_WT_END_STABILITY",
			  pa->p_args.weights.end_stability);
	    COMPARE_FLOAT("PRIMER_WT_TEMPLATE_MISPRIMING",
			  pa->p_args.weights.template_mispriming);

	    COMPARE_FLOAT("PRIMER_IO_WT_TM_GT", pa->o_args.weights.temp_gt);
	    COMPARE_FLOAT("PRIMER_IO_WT_TM_LT", pa->o_args.weights.temp_lt);
	    COMPARE_FLOAT("PRIMER_IO_WT_GC_PERCENT_GT", pa->o_args.weights.gc_content_gt);
	    COMPARE_FLOAT("PRIMER_IO_WT_GC_PERCENT_LT", pa->o_args.weights.gc_content_lt);
	    COMPARE_FLOAT("PRIMER_IO_WT_SIZE_LT", pa->o_args.weights.length_lt);
	    COMPARE_FLOAT("PRIMER_IO_WT_SIZE_GT", pa->o_args.weights.length_gt);
	    COMPARE_FLOAT("PRIMER_IO_WT_COMPL_ANY", pa->o_args.weights.compl_any);
	    COMPARE_FLOAT("PRIMER_IO_WT_COMPL_END", pa->o_args.weights.compl_end);
	    COMPARE_FLOAT("PRIMER_IO_WT_NUM_NS", pa->o_args.weights.num_ns);
	    COMPARE_FLOAT("PRIMER_IO_WT_REP_SIM", pa->o_args.weights.repeat_sim);
	    COMPARE_FLOAT("PRIMER_IO_WT_SEQ_QUAL", pa->o_args.weights.seq_quality);
	    COMPARE_FLOAT("PRIMER_IO_WT_END_QUAL", pa->o_args.weights.end_quality);
	    COMPARE_FLOAT("PRIMER_IO_WT_TEMPLATE_MISHYB",
			  pa->o_args.weights.template_mispriming);

	    COMPARE_FLOAT("PRIMER_PAIR_WT_PR_PENALTY", 
				      pa->pr_pair_weights.primer_quality);
        COMPARE_FLOAT("PRIMER_PAIR_WT_IO_PENALTY",
				      pa->pr_pair_weights.io_quality);
        COMPARE_FLOAT("PRIMER_PAIR_WT_DIFF_TM",
				      pa->pr_pair_weights.diff_tm);
        COMPARE_FLOAT("PRIMER_PAIR_WT_COMPL_ANY",
				      pa->pr_pair_weights.compl_any);
        COMPARE_FLOAT("PRIMER_PAIR_WT_COMPL_END",
				      pa->pr_pair_weights.compl_end);

	    COMPARE_FLOAT("PRIMER_PAIR_WT_PRODUCT_TM_LT",
				      pa->pr_pair_weights.product_tm_lt);
	    COMPARE_FLOAT("PRIMER_PAIR_WT_PRODUCT_TM_GT",
				      pa->pr_pair_weights.product_tm_gt);
	    COMPARE_FLOAT("PRIMER_PAIR_WT_PRODUCT_SIZE_GT",
					   pa->pr_pair_weights.product_size_gt);
        COMPARE_FLOAT("PRIMER_PAIR_WT_PRODUCT_SIZE_LT",
					   pa->pr_pair_weights.product_size_lt);

	    COMPARE_FLOAT("PRIMER_PAIR_WT_REP_SIM",
					   pa->pr_pair_weights.repeat_sim);

	    COMPARE_FLOAT("PRIMER_PAIR_WT_TEMPLATE_MISPRIMING",
			  pa->pr_pair_weights.template_mispriming);
	}
	/* End of reading the tags in the right place */
	
	/*  Complain about unrecognized tags */
	if (*strict_tags == 1) {
	    pr_append_new_chunk(glob_err, "Unrecognized tag: ");
	    pr_append(glob_err, s);
	    fprintf(stderr, "Unrecognized tag: %s\n", s);
	}
    }  /* while ((s = p3_read_line(stdin)) != NULL && strcmp(s,"=")) { */

    /* Check if the record was terminated by "=" */
    if (NULL == s) { /* End of file. */
	    if (data_found) {
	        pr_append_new_chunk(glob_err, 
			    	"Final record not terminated by '='");
	        return 1;
	    } else return 0;
    }
    
    /* Figure out the right settings for the tasks*/
	if (task_tmp != NULL) {
      if (!strcmp_nocase(task_tmp, "pick_pcr_primers")) {
		pa->primer_task = pick_detection_primers;
		pa->pick_left_primer = 1;
		pa->pick_right_primer = 1;
		pa->pick_internal_oligo = 0;
      } else if (!strcmp_nocase(task_tmp, "pick_pcr_primers_and_hyb_probe")) {
		pa->primer_task = pick_detection_primers; 
		pa->pick_left_primer = 1;
		pa->pick_right_primer = 1;
		pa->pick_internal_oligo = 1;
      } else if (!strcmp_nocase(task_tmp, "pick_left_only")) {
		pa->primer_task = pick_detection_primers;
		pa->pick_left_primer = 1;
		pa->pick_right_primer = 0;
		pa->pick_internal_oligo = 0;
      } else if (!strcmp_nocase(task_tmp, "pick_right_only")) {
		pa->primer_task = pick_detection_primers;
		pa->pick_left_primer = 0;
		pa->pick_right_primer = 1;
		pa->pick_internal_oligo = 0;
      } else if (!strcmp_nocase(task_tmp, "pick_hyb_probe_only")) {
		pa->primer_task = pick_detection_primers;
		pa->pick_left_primer = 0;
		pa->pick_right_primer = 0;
		pa->pick_internal_oligo = 1;
      } else if (*io_version == 0) {
	    	pr_append_new_chunk(glob_err, "Unrecognized PRIMER_TASK");
      } else if (!strcmp_nocase(task_tmp, "pick_detection_primers")) {
		pa->primer_task = pick_detection_primers;
      } else if (!strcmp_nocase(task_tmp, "pick_cloning_primers")) {
		pa->primer_task = pick_cloning_primers;
      } else if (!strcmp_nocase(task_tmp, "pick_discriminative_primers")) {
		pa->primer_task = pick_discriminative_primers;
      } else if (!strcmp_nocase(task_tmp, "pick_sequencing_primers")) {
		pa->primer_task = pick_sequencing_primers;
      } else if (!strcmp_nocase(task_tmp, "pick_primer_list")) {
		pa->primer_task = pick_primer_list;
      } else if (!strcmp_nocase(task_tmp, "check_primers")) {
		pa->primer_task = check_primers;
      } else 
    	pr_append_new_chunk(glob_err,
			    "Unrecognized PRIMER_TASK");
	  free(task_tmp);
    }

   /* WARNING: read_seq_lib uses p3_read_line, so repeat files cannot be read
    * inside the while ((s = p3_read_line(stdin))...)  loop above.
    * FIX ME, in fact the reading of the library contents probably
    * belongs inside primer3_boulder_main.c or libprimer3.c. */
   /* Reading in the repeat libraries */
    if (NULL != repeat_file_path) {
      destroy_seq_lib(pa->p_args.repeat_lib);
      if ('\0' == *repeat_file_path) {
	    /* Input now specifies no repeat library. */
	    pa->p_args.repeat_lib = NULL;
      }
      else {
	    pa->p_args.repeat_lib
	      = read_and_create_seq_lib(repeat_file_path, 
				    "mispriming library");
	    if(pa->p_args.repeat_lib->error.data != NULL) {
	      pr_append_new_chunk(glob_err, pa->p_args.repeat_lib->error.data);
	}
      }
      free(repeat_file_path);
      repeat_file_path = NULL;
    }

    /* Reading in the repeat libraries for internal oligo */
    if (NULL != int_repeat_file_path) {
      destroy_seq_lib(pa->o_args.repeat_lib);
      if ('\0' == *int_repeat_file_path) {
	    /* Input now specifies no mishybridization library. */
	    pa->o_args.repeat_lib = NULL;
      }
      else {
	    pa->o_args.repeat_lib = 
	    read_and_create_seq_lib(int_repeat_file_path,
				  "internal oligo mishyb library");
	    if(pa->o_args.repeat_lib->error.data != NULL) {
	       pr_append_new_chunk(glob_err, pa->o_args.repeat_lib->error.data);
	    }
      }
      free(int_repeat_file_path);
      int_repeat_file_path = NULL;
    }
    

    /* Fix very old tags for backward compatibility */
    if (*io_version == 0) {
      /* This next belongs here rather than libprimer3, because it deals
	 with potential incompatibility with old tags (kept for backward
	 compatibility, and new tags.  */
      if (pa->primer_task == pick_pcr_primers_and_hyb_probe) {
	PR_ASSERT(pa->pick_internal_oligo);
      }
      /* Give a error if the tasks don't match */
      if((pick_internal_oligo == 1 || pick_internal_oligo == 0) &&
	 (pa->primer_task == pick_left_only || 
	  pa->primer_task == pick_right_only ||
	  pa->primer_task == pick_hyb_probe_only)) {
	pr_append_new_chunk(glob_err, 
			    "Contradiction in primer_task definition");
      if (pa->primer_task == pick_pcr_primers_and_hyb_probe) {
	PR_ASSERT(pa->pick_internal_oligo);
      }
      } else if (pick_internal_oligo == 1) {
	pa->pick_left_primer = 1;
	pa->pick_right_primer = 1;
	pa->pick_internal_oligo = 1;
	if (pa->primer_task == pick_pcr_primers_and_hyb_probe) {
	  PR_ASSERT(pa->pick_internal_oligo);
	}
      } else if (pick_internal_oligo == 0) {
	pa->pick_left_primer = 1;
	pa->pick_right_primer = 1;
	pa->pick_internal_oligo = 0;
	if (pa->primer_task == pick_pcr_primers_and_hyb_probe) {
	  PR_ASSERT(pa->pick_internal_oligo);
	}
      }
      if (pa->primer_task == pick_pcr_primers_and_hyb_probe) {
	PR_ASSERT(pa->pick_internal_oligo);
      }

    }
		
    if (pa->primer_task == pick_pcr_primers_and_hyb_probe) {
      PR_ASSERT(pa->pick_internal_oligo);
    }

    return 1;
}
Ejemplo n.º 4
0
/* 
 * See read_boulder.h for description.
 */
int
read_boulder_record(FILE *file_input,
                    const int *strict_tags,
                    const int *io_version,
                    int   echo_output, /* should be echo_input */
                    const p3_file_type file_type,
                    p3_global_settings *pa, 
                    seq_args *sa, 
                    pr_append_str *glob_err,  /* Really should be called fatal_parse_err */
                    pr_append_str *nonfatal_parse_err,
		    pr_append_str *warnings,
                    read_boulder_record_results *res) 
{
  int line_len;
  int tag_len, datum_len;
  int data_found = 0;
  char *s, *n, *datum, *task_tmp = NULL;
  const char *p;
  pr_append_str *parse_err;
  pr_append_str *non_fatal_err;
  char *repeat_file_path = NULL, *int_repeat_file_path = NULL;
  int tmp_int;
  /* int min_3_prime = 0, min_5_prime = 0; Removed 10/20/2010 */
  int min_3_prime_distance_global = 0;    /* needed to check if both global and specific*/
  int min_3_prime_distance_specific = 0;  /* are given in same boulder record */
  int min_three_prime_distance;           /* holder for the value of this tag */
  double tmp_double;

  non_fatal_err = nonfatal_parse_err;

  while (((s = p3_read_line(file_input)) != NULL) && (strcmp(s,"="))) {
    /* If we are reading from a settings file, then skip every 
       line except those begining "PRIMER_" or "P3_FILE_ID".
       Hint: strncomp returns 0 if both strings are equal */
     if (file_type == settings 
	 && strncmp(s, "PRIMER_", 7) /* "s does not begin with 'PRIMER_'" */
	 && strncmp(s, "P3_FILE_ID", 10) /* "s does not begin with
					    'P3_FILE_ID'" */
	 ) {
      continue;
    }
    /* Silently ignore all primer3plus tags */
    /* Removed 10/20/10 because P3P_ tags
       are already ignored in settings files. */
    /* if (!(strncmp(s, "P3P_", 4))) {
      continue;
      } */

    data_found = 1;
    /* Print out the input */
    if (echo_output) printf("%s\n", s);
    line_len = strlen(s);
    /* If the line has an "=" read the tag in the right place */
    if ((n=strchr(s,'=')) == NULL) {
      /* The input line is illegal because it has no
       * "=" in it, but we still will read to the end
       * of the record. */
      pr_append_new_chunk(glob_err, "Input line with no '=': ");
      pr_append(glob_err, s);
      continue;
    } 
    /* Read in the new tags used from primer3 version 2.0 on */    
    else {
      /* Get the tag and the value pointers */
      tag_len = n - s;
      datum = n + 1;
      datum_len = line_len - tag_len - 1;
            
      /* Process "Sequence" (i.e. Per-Record) Arguments". */
      parse_err = non_fatal_err;
              
      /* COMPARE_AND_MALLOC("SEQUENCE", sa->sequence); */
      if (COMPARE("SEQUENCE_TEMPLATE")) {   /* NEW WAY */
        if (/* p3_get_seq_arg_sequence(sa) */ sa->sequence) {
          pr_append_new_chunk(parse_err, "Duplicate tag: ");
          pr_append(parse_err, "SEQUENCE_TEMPLATE"); 
        } else {
          if (p3_set_sa_sequence(sa, datum)) exit(-2);
        }
        continue;
      }
      if (COMPARE("SEQUENCE_QUALITY")) {
        if ((sa->n_quality = parse_seq_quality(datum, sa)) == 0) {
          pr_append_new_chunk(parse_err,
                              "Error in sequence quality data");
        }
        continue;
      }
      COMPARE_AND_MALLOC("SEQUENCE_ID", sa->sequence_name);
      COMPARE_AND_MALLOC("SEQUENCE_PRIMER", sa->left_input);
      COMPARE_AND_MALLOC("SEQUENCE_PRIMER_REVCOMP", sa->right_input);
      COMPARE_AND_MALLOC("SEQUENCE_INTERNAL_OLIGO", sa->internal_input);
      COMPARE_2_INTERVAL_LIST("SEQUENCE_PRIMER_PAIR_OK_REGION_LIST", &sa->ok_regions);
      COMPARE_INTERVAL_LIST("SEQUENCE_TARGET", &sa->tar2);
      COMPARE_INTERVAL_LIST("SEQUENCE_EXCLUDED_REGION", &sa->excl2);
      COMPARE_INTERVAL_LIST("SEQUENCE_INTERNAL_EXCLUDED_REGION",
                              &sa->excl_internal2);
      if (COMPARE("SEQUENCE_OVERLAP_JUNCTION_LIST")) {
	if (parse_intron_list(datum, sa->primer_overlap_junctions, 
			      &sa->primer_overlap_junctions_count) == 0) {
          pr_append_new_chunk(parse_err,
			      "Error in SEQUENCE_PRIMER_OVERLAP_JUNCTION_LIST");
        }
        continue;
      }
      if (COMPARE("SEQUENCE_INCLUDED_REGION")) {
        p = parse_int_pair("SEQUENCE_INCLUDED_REGION", datum, ',',
                           &sa->incl_s, &sa->incl_l, parse_err);
        if (NULL == p) /* An error; the message is already
                        * in parse_err.  */
          continue;
        while (' ' == *p || '\t' == *p) p++;
        if (*p != '\n' && *p != '\0')
            tag_syntax_error("SEQUENCE_INCLUDED_REGION", datum,
                             parse_err);
          continue;
      }
      COMPARE_INT("SEQUENCE_START_CODON_POSITION", sa->start_codon_pos);
      COMPARE_INT("SEQUENCE_FORCE_LEFT_START", sa->force_left_start);
      COMPARE_INT("SEQUENCE_FORCE_LEFT_END", sa->force_left_end);
      COMPARE_INT("SEQUENCE_FORCE_RIGHT_START", sa->force_right_start);
      COMPARE_INT("SEQUENCE_FORCE_RIGHT_END", sa->force_right_end);
      /* Process "Global" Arguments (those that persist between boulder
       * records). */
      parse_err = glob_err;  /* These errors are considered fatal. */
      if (COMPARE("PRIMER_PRODUCT_SIZE_RANGE")) {
        parse_product_size("PRIMER_PRODUCT_SIZE_RANGE", datum, pa,
                           parse_err);
        continue;
      }
      COMPARE_INT("PRIMER_OPT_SIZE", pa->p_args.opt_size);
      COMPARE_INT("PRIMER_MIN_SIZE", pa->p_args.min_size);
      COMPARE_INT("PRIMER_MAX_SIZE", pa->p_args.max_size);
      COMPARE_INT("PRIMER_MAX_POLY_X", pa->p_args.max_poly_x);
      COMPARE_FLOAT("PRIMER_OPT_TM", pa->p_args.opt_tm);
      COMPARE_FLOAT("PRIMER_OPT_GC_PERCENT", pa->p_args.opt_gc_content);
      COMPARE_FLOAT("PRIMER_MIN_TM", pa->p_args.min_tm);
      COMPARE_FLOAT("PRIMER_MAX_TM", pa->p_args.max_tm);
      COMPARE_FLOAT("PRIMER_PAIR_MAX_DIFF_TM", pa->max_diff_tm);
      if (COMPARE("PRIMER_TM_FORMULA")) {
          parse_int("PRIMER_TM_FORMULA", datum, &tmp_int, parse_err);
          pa->tm_santalucia = (tm_method_type) tmp_int;    /* added by T.Koressaar */
          continue;
      }
      if (COMPARE("PRIMER_SALT_CORRECTIONS")) {
        parse_int("PRIMER_SALT_CORRECTIONS", datum, &tmp_int, parse_err);
        pa->salt_corrections = (salt_correction_type) tmp_int; /* added by T.Koressaar */
        continue;
      }
      COMPARE_FLOAT("PRIMER_MIN_GC", pa->p_args.min_gc);
      COMPARE_FLOAT("PRIMER_MAX_GC", pa->p_args.max_gc);
      COMPARE_FLOAT("PRIMER_SALT_MONOVALENT", pa->p_args.salt_conc);
      COMPARE_FLOAT("PRIMER_SALT_DIVALENT", pa->p_args.divalent_conc);
      COMPARE_FLOAT("PRIMER_DNTP_CONC", pa->p_args.dntp_conc);
      COMPARE_FLOAT("PRIMER_DNA_CONC", pa->p_args.dna_conc);
      COMPARE_INT("PRIMER_MAX_NS_ACCEPTED", pa->p_args.num_ns_accepted);
      COMPARE_INT("PRIMER_PRODUCT_OPT_SIZE", pa->product_opt_size);
      COMPARE_FLOAT("PRIMER_MAX_SELF_ANY", pa->p_args.max_self_any);

      /* COMPARE_FLOAT("PRIMER_MAX_SELF_END", pa->p_args.max_self_end); */
      /* NEW */ COMPARE_FLOAT_USE_FN("PRIMER_MAX_SELF_END", p3_set_gs_primer_self_end)
	/* if (COMPARE("PRIMER_MAX_SELF_END")) {
	  parse_double("PRIMER_MAX_SELF_END", datum, &tmp_double, parse_err);
	  p3_set_gs_primer_self_end(pa, tmp_double);
	  continue;
	  } */

      COMPARE_FLOAT("PRIMER_MAX_SELF_ANY_TH", pa->p_args.max_self_any_th);
      COMPARE_FLOAT("PRIMER_MAX_SELF_END_TH", pa->p_args.max_self_end_th);
      COMPARE_FLOAT("PRIMER_MAX_HAIRPIN_TH", pa->p_args.max_hairpin_th);   
      COMPARE_FLOAT("PRIMER_PAIR_MAX_COMPL_ANY", pa->pair_compl_any);
      COMPARE_FLOAT("PRIMER_PAIR_MAX_COMPL_END", pa->pair_compl_end);
      COMPARE_FLOAT("PRIMER_PAIR_MAX_COMPL_ANY_TH", pa->pair_compl_any_th);
      COMPARE_FLOAT("PRIMER_PAIR_MAX_COMPL_END_TH", pa->pair_compl_end_th);
      COMPARE_INT("P3_FILE_FLAG", res->file_flag);
      COMPARE_INT("PRIMER_PICK_ANYWAY", pa->pick_anyway);
      COMPARE_INT("PRIMER_GC_CLAMP", pa->gc_clamp);
      COMPARE_INT("PRIMER_MAX_END_GC", pa->max_end_gc);
      COMPARE_INT("PRIMER_EXPLAIN_FLAG", res->explain_flag);
      COMPARE_INT("PRIMER_LIBERAL_BASE", pa->liberal_base);
      COMPARE_INT("PRIMER_FIRST_BASE_INDEX", pa->first_base_index);
      COMPARE_INT("PRIMER_NUM_RETURN", pa->num_return);
      COMPARE_INT("PRIMER_MIN_QUALITY", pa->p_args.min_quality);
      COMPARE_INT("PRIMER_MIN_END_QUALITY", pa->p_args.min_end_quality);
      if (COMPARE("PRIMER_MIN_THREE_PRIME_DISTANCE")) {
	parse_int("PRIMER_MIN_THREE_PRIME_DISTANCE", datum, &(min_three_prime_distance), parse_err);
	/* check if specific tag also specified - error in this case */
	if (min_3_prime_distance_specific == 1) {
	  pr_append_new_chunk(glob_err,
                              "Both PRIMER_MIN_THREE_PRIME_DISTANCE and PRIMER_{LEFT/RIGHT}_MIN_THREE_PRIME_DISTANCE specified");
	} else {
	  min_3_prime_distance_global = 1;
	  /* set up individual flags */
	  pa->min_left_three_prime_distance = min_three_prime_distance;
	  pa->min_right_three_prime_distance = min_three_prime_distance;
	}
	continue;
      }
      if (COMPARE("PRIMER_MIN_LEFT_THREE_PRIME_DISTANCE")) {
	parse_int("PRIMER_MIN_LEFT_THREE_PRIME_DISTANCE", datum, &(pa->min_left_three_prime_distance), parse_err);
	/* check if global tag also specified - error in this case */
	if (min_3_prime_distance_global == 1) {
	  pr_append_new_chunk(glob_err,
                              "Both PRIMER_MIN_THREE_PRIME_DISTANCE and PRIMER_{LEFT/RIGHT}_MIN_THREE_PRIME_DISTANCE specified");
	} else {
	  min_3_prime_distance_specific = 1;
	}
	continue;
      }
      if (COMPARE("PRIMER_MIN_RIGHT_THREE_PRIME_DISTANCE")) {
	parse_int("PRIMER_MIN_RIGHT_THREE_PRIME_DISTANCE", datum, &(pa->min_right_three_prime_distance), parse_err);
	/* check if global tag also specified - error in this case */
	if (min_3_prime_distance_global == 1) {
	  pr_append_new_chunk(glob_err,
                              "Both PRIMER_MIN_THREE_PRIME_DISTANCE and PRIMER_{LEFT/RIGHT}_MIN_THREE_PRIME_DISTANCE specified");
	} else {
	  min_3_prime_distance_specific = 1;
	}
	continue;
      }
      if (file_type == settings) {
        if (COMPARE("P3_FILE_ID")) continue;
      }
      COMPARE_INT("PRIMER_QUALITY_RANGE_MIN", pa->quality_range_min);
      COMPARE_INT("PRIMER_QUALITY_RANGE_MAX", pa->quality_range_max);
      COMPARE_FLOAT("PRIMER_PRODUCT_MAX_TM", pa->product_max_tm);
      COMPARE_FLOAT("PRIMER_PRODUCT_MIN_TM", pa->product_min_tm);
      COMPARE_FLOAT("PRIMER_PRODUCT_OPT_TM", pa->product_opt_tm);
      COMPARE_INT("PRIMER_SEQUENCING_LEAD", pa->sequencing.lead);
      COMPARE_INT("PRIMER_SEQUENCING_SPACING", pa->sequencing.spacing);
      COMPARE_INT("PRIMER_SEQUENCING_INTERVAL", pa->sequencing.interval);
      COMPARE_INT("PRIMER_SEQUENCING_ACCURACY", pa->sequencing.accuracy);
      if (COMPARE("PRIMER_MIN_5_PRIME_OVERLAP_OF_JUNCTION")) {
	parse_int("PRIMER_MIN_5_PRIME_OVERLAP_OF_JUNCTION", datum, &pa->min_5_prime_overlap_of_junction, parse_err);
	/* min_5_prime = 1; Removed 10/20/2010 */
	continue;
      }
      if (COMPARE("PRIMER_MIN_3_PRIME_OVERLAP_OF_JUNCTION")) {
	parse_int("PRIMER_MIN_3_PRIME_OVERLAP_OF_JUNCTION", datum, &pa->min_3_prime_overlap_of_junction, parse_err);
	/* min_3_prime = 1; Removed 10/20/2010 */
	continue;
      }
      COMPARE_AND_MALLOC("PRIMER_TASK", task_tmp);
      COMPARE_INT("PRIMER_PICK_RIGHT_PRIMER", pa->pick_right_primer);
      COMPARE_INT("PRIMER_PICK_INTERNAL_OLIGO", pa->pick_internal_oligo);
      COMPARE_INT("PRIMER_PICK_LEFT_PRIMER", pa->pick_left_primer);
      COMPARE_INT("PRIMER_INTERNAL_OPT_SIZE", pa->o_args.opt_size);
      COMPARE_INT("PRIMER_INTERNAL_MAX_SIZE", pa->o_args.max_size);
      COMPARE_INT("PRIMER_INTERNAL_MIN_SIZE", pa->o_args.min_size);
      COMPARE_INT("PRIMER_INTERNAL_MAX_POLY_X", pa->o_args.max_poly_x);
      COMPARE_FLOAT("PRIMER_INTERNAL_OPT_TM", pa->o_args.opt_tm);
      COMPARE_FLOAT("PRIMER_INTERNAL_OPT_GC_PERCENT",
                    pa->o_args.opt_gc_content);
      COMPARE_FLOAT("PRIMER_INTERNAL_MAX_TM", pa->o_args.max_tm);
      COMPARE_FLOAT("PRIMER_INTERNAL_MIN_TM", pa->o_args.min_tm);
      COMPARE_FLOAT("PRIMER_INTERNAL_MIN_GC", pa->o_args.min_gc);
      COMPARE_FLOAT("PRIMER_INTERNAL_MAX_GC", pa->o_args.max_gc);
      COMPARE_FLOAT("PRIMER_INTERNAL_SALT_MONOVALENT",
                        pa->o_args.salt_conc);
      COMPARE_FLOAT("PRIMER_INTERNAL_SALT_DIVALENT",
                    pa->o_args.divalent_conc);
      COMPARE_FLOAT("PRIMER_INTERNAL_DNTP_CONC",
                    pa->o_args.dntp_conc);
      COMPARE_FLOAT("PRIMER_INTERNAL_DNA_CONC", pa->o_args.dna_conc);
      COMPARE_INT("PRIMER_INTERNAL_MAX_NS_ACCEPTED", pa->o_args.num_ns_accepted);
      COMPARE_INT("PRIMER_INTERNAL_MIN_QUALITY", pa->o_args.min_quality);
      COMPARE_FLOAT("PRIMER_INTERNAL_MAX_SELF_ANY",
		    pa->o_args.max_self_any);

      /* COMPARE_FLOAT("PRIMER_INTERNAL_MAX_SELF_END", 
	 pa->o_args.max_self_end); */
      /* NEW  */ COMPARE_FLOAT_USE_FN("PRIMER_INTERNAL_MAX_SELF_END", 
				      p3_set_gs_primer_internal_oligo_self_end);
      /* if (COMPARE("PRIMER_INTERNAL_MAX_SELF_END")) { 
	 parse_double("PRIMER_INTERNAL_MAX_SELF_END", datum, &tmp_double, parse_err);
	 p3_set_gs_primer_internal_oligo_self_end(pa, tmp_double);
	 continue;
	 } */

      COMPARE_FLOAT("PRIMER_INTERNAL_MAX_SELF_ANY_TH",
			   pa->o_args.max_self_any_th);
      COMPARE_FLOAT("PRIMER_INTERNAL_MAX_SELF_END_TH",
				 pa->o_args.max_self_end_th);
      COMPARE_FLOAT("PRIMER_INTERNAL_MAX_HAIRPIN_TH",
			       pa->o_args.max_hairpin_th);
      COMPARE_FLOAT("PRIMER_MAX_LIBRARY_MISPRIMING",
                    pa->p_args.max_repeat_compl);
      COMPARE_FLOAT("PRIMER_INTERNAL_MAX_LIBRARY_MISHYB",
                    pa->o_args.max_repeat_compl);
      COMPARE_FLOAT("PRIMER_PAIR_MAX_LIBRARY_MISPRIMING",
                    pa->pair_repeat_compl);
      /* Mispriming / mishybing in the template. */
      COMPARE_FLOAT("PRIMER_MAX_TEMPLATE_MISPRIMING",
                    pa->p_args.max_template_mispriming);
      COMPARE_FLOAT("PRIMER_MAX_TEMPLATE_MISPRIMING_TH",
			  pa->p_args.max_template_mispriming_th);
      COMPARE_FLOAT("PRIMER_PAIR_MAX_TEMPLATE_MISPRIMING",
                    pa->pair_max_template_mispriming);
      COMPARE_FLOAT("PRIMER_PAIR_MAX_TEMPLATE_MISPRIMING_TH",
		    pa->pair_max_template_mispriming_th);
       /* Control interpretation of ambiguity codes in mispriming
          and mishyb libraries. */
      COMPARE_INT("PRIMER_LIB_AMBIGUITY_CODES_CONSENSUS",
                  pa->lib_ambiguity_codes_consensus);
      COMPARE_FLOAT("PRIMER_INSIDE_PENALTY", pa->inside_penalty);
      COMPARE_FLOAT("PRIMER_OUTSIDE_PENALTY", pa->outside_penalty);
      if (COMPARE("PRIMER_MISPRIMING_LIBRARY")) {
        if (repeat_file_path != NULL) {
          pr_append_new_chunk(glob_err,
                              "Duplicate PRIMER_MISPRIMING_LIBRARY tag");
          free(repeat_file_path);
          repeat_file_path = NULL;
        } else {
          repeat_file_path = (char*) _rb_safe_malloc(strlen(datum) + 1);
          strcpy(repeat_file_path, datum);
        }
        continue;
      }
      if (COMPARE("PRIMER_INTERNAL_MISHYB_LIBRARY")) {
        if (int_repeat_file_path != NULL) {
          pr_append_new_chunk(glob_err,
                              "Duplicate PRIMER_INTERNAL_MISHYB_LIBRARY tag");
          free(int_repeat_file_path);
          int_repeat_file_path = NULL;
        } else {
          int_repeat_file_path = (char*) _rb_safe_malloc(strlen(datum) + 1);
          strcpy(int_repeat_file_path, datum);
        }
        continue;
      }
      if (COMPARE("P3_COMMENT")) continue;
      COMPARE_FLOAT("PRIMER_MAX_END_STABILITY", pa->max_end_stability);

      COMPARE_INT("PRIMER_LOWERCASE_MASKING",
                  pa->lowercase_masking); 
      /* added by T. Koressaar */
      OVERWRITE_COMPARE_AND_MALLOC("PRIMER_MUST_MATCH_FIVE_PRIME", pa->p_args.must_match_five_prime);
      OVERWRITE_COMPARE_AND_MALLOC("PRIMER_MUST_MATCH_THREE_PRIME", pa->p_args.must_match_three_prime);
      OVERWRITE_COMPARE_AND_MALLOC("PRIMER_INTERNAL_MUST_MATCH_FIVE_PRIME", pa->o_args.must_match_five_prime);
      OVERWRITE_COMPARE_AND_MALLOC("PRIMER_INTERNAL_MUST_MATCH_THREE_PRIME", pa->o_args.must_match_three_prime);
      /* added by A. Untergasser */
      COMPARE_INT("PRIMER_THERMODYNAMIC_OLIGO_ALIGNMENT", pa->thermodynamic_oligo_alignment);
      COMPARE_INT("PRIMER_THERMODYNAMIC_TEMPLATE_ALIGNMENT", pa->thermodynamic_template_alignment);
      if (COMPARE("PRIMER_THERMODYNAMIC_PARAMETERS_PATH")) {
        if (thermodynamic_params_path == NULL) {
          thermodynamic_params_path = (char*) _rb_safe_malloc(datum_len + 1);
          strcpy(thermodynamic_params_path, datum);
          thermodynamic_path_changed = 1;
        }
        /* check if path changes */
	else if (strcmp(thermodynamic_params_path, datum)) {
	  free(thermodynamic_params_path);
	  thermodynamic_params_path = (char*) _rb_safe_malloc(datum_len + 1); 
	  strcpy(thermodynamic_params_path, datum);
	  thermodynamic_path_changed = 1;
        }
        continue;
      }
      /* weights for objective functions  */
      /* CHANGE TEMP/temp -> TM/tm */
      COMPARE_FLOAT("PRIMER_WT_TM_GT", pa->p_args.weights.temp_gt);
      COMPARE_FLOAT("PRIMER_WT_TM_LT", pa->p_args.weights.temp_lt);
      COMPARE_FLOAT("PRIMER_WT_GC_PERCENT_GT", pa->p_args.weights.gc_content_gt);
      COMPARE_FLOAT("PRIMER_WT_GC_PERCENT_LT", pa->p_args.weights.gc_content_lt);
      COMPARE_FLOAT("PRIMER_WT_SIZE_LT", pa->p_args.weights.length_lt);
      COMPARE_FLOAT("PRIMER_WT_SIZE_GT", pa->p_args.weights.length_gt);
      COMPARE_FLOAT("PRIMER_WT_SELF_ANY", pa->p_args.weights.compl_any);
      COMPARE_FLOAT("PRIMER_WT_SELF_END", pa->p_args.weights.compl_end);
      COMPARE_FLOAT("PRIMER_WT_SELF_ANY_TH", pa->p_args.weights.compl_any_th);
      COMPARE_FLOAT("PRIMER_WT_SELF_END_TH", pa->p_args.weights.compl_end_th);
      COMPARE_FLOAT("PRIMER_WT_HAIRPIN_TH", pa->p_args.weights.hairpin_th);
      COMPARE_FLOAT("PRIMER_WT_NUM_NS", pa->p_args.weights.num_ns);
      COMPARE_FLOAT("PRIMER_WT_LIBRARY_MISPRIMING", pa->p_args.weights.repeat_sim);
      COMPARE_FLOAT("PRIMER_WT_SEQ_QUAL", pa->p_args.weights.seq_quality);
      COMPARE_FLOAT("PRIMER_WT_END_QUAL", pa->p_args.weights.end_quality);
      COMPARE_FLOAT("PRIMER_WT_POS_PENALTY", pa->p_args.weights.pos_penalty);
      COMPARE_FLOAT("PRIMER_WT_END_STABILITY",
                    pa->p_args.weights.end_stability);
      COMPARE_FLOAT("PRIMER_WT_TEMPLATE_MISPRIMING",
                    pa->p_args.weights.template_mispriming);
      COMPARE_FLOAT("PRIMER_WT_TEMPLATE_MISPRIMING_TH",
		                        pa->p_args.weights.template_mispriming_th);
      COMPARE_FLOAT("PRIMER_INTERNAL_WT_TM_GT", pa->o_args.weights.temp_gt);
      COMPARE_FLOAT("PRIMER_INTERNAL_WT_TM_LT", pa->o_args.weights.temp_lt);
      COMPARE_FLOAT("PRIMER_INTERNAL_WT_GC_PERCENT_GT", pa->o_args.weights.gc_content_gt);
      COMPARE_FLOAT("PRIMER_INTERNAL_WT_GC_PERCENT_LT", pa->o_args.weights.gc_content_lt);
      COMPARE_FLOAT("PRIMER_INTERNAL_WT_SIZE_LT", pa->o_args.weights.length_lt);
      COMPARE_FLOAT("PRIMER_INTERNAL_WT_SIZE_GT", pa->o_args.weights.length_gt);
      COMPARE_FLOAT("PRIMER_INTERNAL_WT_SELF_ANY", pa->o_args.weights.compl_any);
      COMPARE_FLOAT("PRIMER_INTERNAL_WT_SELF_END", pa->o_args.weights.compl_end);
      COMPARE_FLOAT("PRIMER_INTERNAL_WT_SELF_ANY_TH", pa->o_args.weights.compl_any_th);
      COMPARE_FLOAT("PRIMER_INTERNAL_WT_SELF_END_TH", pa->o_args.weights.compl_end_th);
      COMPARE_FLOAT("PRIMER_INTERNAL_WT_HAIRPIN_TH", pa->o_args.weights.hairpin_th);
      COMPARE_FLOAT("PRIMER_INTERNAL_WT_NUM_NS", pa->o_args.weights.num_ns);
      COMPARE_FLOAT("PRIMER_INTERNAL_WT_LIBRARY_MISHYB", pa->o_args.weights.repeat_sim);
      COMPARE_FLOAT("PRIMER_INTERNAL_WT_SEQ_QUAL", pa->o_args.weights.seq_quality);
      COMPARE_FLOAT("PRIMER_INTERNAL_WT_END_QUAL", pa->o_args.weights.end_quality);
      COMPARE_FLOAT("PRIMER_WT_TEMPLATE_MISPRIMING_TH",
		    pa->o_args.weights.template_mispriming_th);
      COMPARE_FLOAT("PRIMER_PAIR_WT_PR_PENALTY", 
                    pa->pr_pair_weights.primer_quality);
      COMPARE_FLOAT("PRIMER_PAIR_WT_IO_PENALTY",
                    pa->pr_pair_weights.io_quality);
      COMPARE_FLOAT("PRIMER_PAIR_WT_DIFF_TM",
                    pa->pr_pair_weights.diff_tm);
      COMPARE_FLOAT("PRIMER_PAIR_WT_COMPL_ANY",
                    pa->pr_pair_weights.compl_any);
      COMPARE_FLOAT("PRIMER_PAIR_WT_COMPL_END",
                    pa->pr_pair_weights.compl_end);
      COMPARE_FLOAT("PRIMER_PAIR_WT_COMPL_ANY_TH",
		    pa->pr_pair_weights.compl_any_th);
      COMPARE_FLOAT("PRIMER_PAIR_WT_COMPL_END_TH",
		    pa->pr_pair_weights.compl_end_th);
      COMPARE_FLOAT("PRIMER_PAIR_WT_PRODUCT_TM_LT",
                    pa->pr_pair_weights.product_tm_lt);
      COMPARE_FLOAT("PRIMER_PAIR_WT_PRODUCT_TM_GT",
                    pa->pr_pair_weights.product_tm_gt);
      COMPARE_FLOAT("PRIMER_PAIR_WT_PRODUCT_SIZE_GT",
                    pa->pr_pair_weights.product_size_gt);
      COMPARE_FLOAT("PRIMER_PAIR_WT_PRODUCT_SIZE_LT",
                    pa->pr_pair_weights.product_size_lt);
      COMPARE_FLOAT("PRIMER_PAIR_WT_LIBRARY_MISPRIMING",
                    pa->pr_pair_weights.repeat_sim);
      COMPARE_FLOAT("PRIMER_PAIR_WT_TEMPLATE_MISPRIMING",
                    pa->pr_pair_weights.template_mispriming);
      COMPARE_FLOAT("PRIMER_PAIR_WT_TEMPLATE_MISPRIMING_TH",
		    pa->pr_pair_weights.template_mispriming_th);
    }
    /* End of reading the tags in the right place */
        
    /*  Complain about unrecognized tags */
     if (*strict_tags == 1) {
	pr_append_new_chunk(glob_err, "Unrecognized tag: ");
	pr_append(glob_err, s);
	fprintf(stderr, "Unrecognized tag: %s\n", s);
     }
  }  /* while ((s = p3_read_line(stdin)) != NULL && strcmp(s,"=")) { */

  /* Check if the record was terminated by "=" */
  if (NULL == s) { /* End of file. */
    if (data_found) {
       pr_append_new_chunk(glob_err, 
                          "Final record not terminated by '='");
      return 1;
    } else  return 0;
  }
    
  /* Figure out the right settings for the tasks*/
  if (task_tmp != NULL) {
    if (!strcmp_nocase(task_tmp, "pick_pcr_primers")) {
      pa->primer_task = generic;
      pa->pick_left_primer = 1;
      pa->pick_right_primer = 1;
      pa->pick_internal_oligo = 0;
    } else if (!strcmp_nocase(task_tmp, "pick_pcr_primers_and_hyb_probe")) {
      pa->primer_task = generic; 
      pa->pick_left_primer = 1;
      pa->pick_right_primer = 1;
      pa->pick_internal_oligo = 1;
    } else if (!strcmp_nocase(task_tmp, "pick_left_only")) {
      pa->primer_task = generic;
      pa->pick_left_primer = 1;
      pa->pick_right_primer = 0;
      pa->pick_internal_oligo = 0;
    } else if (!strcmp_nocase(task_tmp, "pick_right_only")) {
      pa->primer_task = generic;
      pa->pick_left_primer = 0;
      pa->pick_right_primer = 1;
      pa->pick_internal_oligo = 0;
    } else if (!strcmp_nocase(task_tmp, "pick_hyb_probe_only")) {
      pa->primer_task = generic;
      pa->pick_left_primer = 0;
      pa->pick_right_primer = 0;
      pa->pick_internal_oligo = 1;
    } else if (!strcmp_nocase(task_tmp, "generic")) {
      pa->primer_task = generic;
    } else if (!strcmp_nocase(task_tmp, "pick_detection_primers")) {
      pa->primer_task = generic; /* Deliberate duplication for
				    backward compatibility. */
    } else if (!strcmp_nocase(task_tmp, "pick_cloning_primers")) {
      pa->primer_task = pick_cloning_primers;
    } else if (!strcmp_nocase(task_tmp, "pick_discriminative_primers")) {
      pa->primer_task = pick_discriminative_primers;
    } else if (!strcmp_nocase(task_tmp, "pick_sequencing_primers")) {
      pa->primer_task = pick_sequencing_primers;
    } else if (!strcmp_nocase(task_tmp, "pick_primer_list")) {
      pa->primer_task = pick_primer_list;
    } else if (!strcmp_nocase(task_tmp, "check_primers")) {
      pa->primer_task = check_primers;
      /* check_primers sets the picking flags itself */
      pa->pick_left_primer = 0;
      pa->pick_right_primer = 0;
      pa->pick_internal_oligo = 0;
      if (sa->left_input){
        pa->pick_left_primer = 1;
      }
      if (sa->right_input){
        pa->pick_right_primer = 1;
      }
      if (sa->internal_input){
        pa->pick_internal_oligo = 1;
      }
    } else 
      pr_append_new_chunk(glob_err,
                          "Unrecognized PRIMER_TASK");
    free(task_tmp);
  }

  /* 
   * WARNING: read_and_create_seq_lib uses p3_read_line, so repeat
   * library files cannot be read inside the 
   * while ((s = p3_read_line(stdin))...) loop above.
   *
   * FIX ME, in fact the reading
   * of the library contents probably belongs inside
   * primer3_boulder_main.c or libprimer3.c.
   */

  /* Read in the repeat libraries */
  if (NULL != repeat_file_path) {
    destroy_seq_lib(pa->p_args.repeat_lib);
    if ('\0' == *repeat_file_path) {
      /* Input now specifies no repeat library. */
      pa->p_args.repeat_lib = NULL;
    }
    else {
      pa->p_args.repeat_lib
        = read_and_create_seq_lib(repeat_file_path, 
                                  "mispriming library");
      if(pa->p_args.repeat_lib->error.data != NULL) {
        pr_append_new_chunk(glob_err, pa->p_args.repeat_lib->error.data);
      }
    }
    free(repeat_file_path);
    repeat_file_path = NULL;
  }

  /* Read in the repeat libraries for internal oligo */
  if (NULL != int_repeat_file_path) {
    destroy_seq_lib(pa->o_args.repeat_lib);
    if ('\0' == *int_repeat_file_path) {
      /* Input now specifies no mishybridization library. */
      pa->o_args.repeat_lib = NULL;
    }
    else {
      pa->o_args.repeat_lib = 
        read_and_create_seq_lib(int_repeat_file_path,
                                "internal oligo mishyb library");
      if(pa->o_args.repeat_lib->error.data != NULL) {
        pr_append_new_chunk(glob_err, pa->o_args.repeat_lib->error.data);
      }
    }
    free(int_repeat_file_path);
    int_repeat_file_path = NULL;
  }

  if (pa->primer_task == pick_pcr_primers_and_hyb_probe) {
    PR_ASSERT(pa->pick_internal_oligo);
  }

  /* Removed 10/20/2010 as excessively compulsive, especially in the context
     of taking input from web pages.
     if ((min_3_prime || min_5_prime) && (sa->primer_overlap_junctions_count == 0)) {
     pr_append_new_chunk(warnings,
                         "SEQUENCE_OVERLAP_JUNCTION_LIST not given, but "
			 "PRIMER_MIN_3_PRIME_OVERLAP_OF_JUNCTION or "
			 "PRIMER_MIN_5_PRIME_OVERLAP_OF_JUNCTION specified");
			 } */

  return 1;
}