Example #1
0
static void
pr_append(pr_append_str *x,
          const char *s)
{
  if (pr_append_external(x, s))
          out_of_memory_error();
}
Example #2
0
int 
main (int argc, const char *argv[]) 
{
	unsigned int idx;
	char *end;
	int debug = 0;
	
	/* sequence file name specified by the user, otherwise STDIN will be used */
	const char *sequence_file_name = NULL;
	const char *lists_file_name = NULL;
	
	/* data structure for all k-mer lists used for masking */
	unsigned int nlists = 0;
	unsigned int nlist_parameters = 0;
	unsigned int npos = 0;
	unsigned int list_pos[MAX_VARIABLES], list_components[MAX_VARIABLES];
	
	masker_parameters mp = {};
	parameters_builder pbuilder = {};
	input_sequence *input_seq = NULL;
	
	pr_append_str parse_err;
	pr_append_str warnings;
	
	init_pr_append_str (&parse_err);
	init_pr_append_str (&warnings);

	/* fill mp with default parameters */
	mp.mdir = DEFAULT_MASKING_DIRECTION;
	mp.failure_rate = DEFAULT_FAILURE_RATE;
	mp.abs_cutoff = DEFAULT_ABS_CUTOFF;
	mp.nucl_masked_in_5p_direction = DEFAULT_M5P;
	mp.nucl_masked_in_3p_direction = DEFAULT_M3P;
	mp.print_sequence = PRINT_SEQUENCE;
	mp.do_soft_masking = HARD_MASKING;
	mp.masking_char = DEFAULT_MASK_CHAR;
	mp.list_prefix = DEFAULT_LIST_FILE_PREFIX;
	
	
	/* parsing and checking the commandline arguments */
	for (idx = 1; (int)idx < argc; idx++) {
		
  		if (!strcmp (argv[idx], "-h") || !strcmp (argv[idx], "--help") || !strcmp (argv[idx], "-?")) {
			print_help (0);
		
		} else if ((int)idx == argc - 1 && argv[idx][0] != '-') {
			sequence_file_name = argv[idx];
			
		} else if (!strcmp (argv[idx], "-lf") || !strcmp (argv[idx], "--lists_file")) {
			/* lists specified from the file */
			if (!argv[idx + 1] || argv[idx + 1][0] == '-') {
				pr_append_new_chunk_external (&warnings, "No lists file specified.");
				idx += 1;
				continue;
			}
			lists_file_name = argv[idx + 1];
			idx += 1;
			
		} else if (!strcmp (argv[idx], "-l") || !strcmp (argv[idx], "--list")) {
			/* lists specified from the commandline */
			if (nlist_parameters == MAX_VARIABLES) {
				pr_append_new_chunk_external (&parse_err, "Maximum number of list variables reached.");
				break;
			}
			
			if (!argv[idx + 1]) {
				pr_append_new_chunk_external (&warnings, "No list name specified with -l parameter!.");
				continue;
			}
			
			/* get the positions of list files */
			list_pos[nlist_parameters] = idx;
			while (argv[idx + 1]) {
				if (argv[idx + 1][0] == '-') {
					if (!argv[idx + 1][1]) break;
					strtod (argv[idx + 1] + 1, &end);
					if (*end != 0) break;
				} else if (idx + 1 != list_pos[nlist_parameters] + 1 && idx + 1 != list_pos[nlist_parameters] + 4) {
					strtod (argv[idx + 1], &end);
					if (*end != 0) break;
				} else if (idx + 1 == list_pos[nlist_parameters] + 4 && strcmp (argv[idx + 1], "sq")) {
					break;
				}
				idx += 1;
			}
			list_components[nlist_parameters] = idx - list_pos[nlist_parameters];
			nlist_parameters += 1;
			npos += 1;
			
		} else if (!strcmp (argv[idx], "-lp") || !strcmp (argv[idx], "--list_prefix")) {
			/* lists specified by the prefix */
			if (!argv[idx + 1] || argv[idx + 1][0] == '-') {
				pr_append_new_chunk_external (&warnings, "No list prefix specified! Using the default value.");
				idx += 1;
				continue;
			}
			mp.list_prefix = (char *)argv[idx + 1];
			idx += 1;			
			
		} else if (!strcmp (argv[idx], "-p") || !strcmp (argv[idx], "--probability_cutoff")) {
			if (!argv[idx + 1]) {
				pr_append_new_chunk_external (&warnings, "No cutoff value specified! Using the default value.");
				idx += 1;
				continue;
			}
			mp.failure_rate = strtod (argv[idx + 1], &end);
			mp.abs_cutoff = 0;
			if (*end != 0 || mp.failure_rate < 0 || mp.failure_rate > 1) {
				pr_append_new_chunk_external (&parse_err, "Invalid cutoff value: ");
				pr_append_external (&parse_err, argv[idx + 1]);
				break;
			}
			idx += 1;
			
		} else if (!strcmp (argv[idx], "-a") || !strcmp (argv[idx], "--absolute_value_cutoff")) {
			if (!argv[idx + 1]) {
				pr_append_new_chunk_external (&warnings, "No absolute cutoff value specified! Using the default value.");
				idx += 1;
				continue;
			}
			mp.abs_cutoff = strtod (argv[idx + 1], &end);
			mp.failure_rate = 0.0;
			if (*end != 0 || mp.abs_cutoff < 0) {
				pr_append_new_chunk_external (&parse_err, "Invalid absolute cutoff value: ");
				pr_append_external (&parse_err, argv[idx + 1]);
				break;
			}
			idx += 1;
			
		} else if (!strcmp (argv[idx], "-m5") || !strcmp (argv[idx], "--mask_5p")) {
			if (!argv[idx + 1]) {
				pr_append_new_chunk_external (&warnings, "Number of nucleotides masked in 5' direction not specified! Using the default value.");
				idx += 1;
				continue;
			}
			mp.nucl_masked_in_5p_direction = strtod (argv[idx + 1], &end);
			if (*end != 0) {
				pr_append_new_chunk_external (&parse_err, "Invalid number of nucleotides masked in 5' direction: ");
				pr_append_external (&parse_err, argv[idx + 1]);
				break;
			}
			idx += 1;
			
		} else if (!strcmp (argv[idx], "-m3") || !strcmp (argv[idx], "--mask_3p")) {
			if (!argv[idx + 1]) {
				pr_append_new_chunk_external (&warnings, "Number of nucleotides masked in 3' direction not specified! Using the default value.");
				idx += 1;
				continue;
			}
			mp.nucl_masked_in_3p_direction = strtod (argv[idx + 1], &end);
			if (*end != 0) {
				pr_append_new_chunk_external (&parse_err, "Invalid number of nucleotides masked in 3' direction: ");
				pr_append_external (&parse_err, argv[idx + 1]);
				break;
			}
			idx += 1;
			
		} else if (!strcmp (argv[idx], "-c") || !strcmp (argv[idx], "--masking_char")) {
			if (!argv[idx + 1 || argv[idx + 1][0] == '-']) {
				pr_append_new_chunk_external (&warnings, "Character for masking not specified! Using the default value.");
				idx += 1;
				continue;
			}
			mp.masking_char = argv[idx + 1][0];
			if (strlen(argv[idx + 1]) > 1 || mp.masking_char < 33 || mp.masking_char > 126) {
				pr_append_new_chunk_external (&parse_err, "Invalid character for masking: ");
				pr_append_external (&parse_err, argv[idx + 1]);
				break;
			}
			idx += 1;
			
		} else if (!strcmp (argv[idx], "-d") || !strcmp (argv[idx], "--masking_direction")) {
			if (!argv[idx + 1] || argv[idx + 1][0] == '-') {
				pr_append_new_chunk_external (&warnings, "Masking direction not specified! Masking both strands by default.");
			} else if (!strcmp (argv[idx + 1], "both")) {
				mp.mdir = both_on_same;
			} else if (!strcmp (argv[idx + 1], "fwd")) {
				mp.mdir = fwd;
			} else if (!strcmp (argv[idx + 1], "rev")) {
				mp.mdir = rev;
			} else {
				pr_append_new_chunk_external (&warnings, "Unknown masking direction: ");
				pr_append_external (&warnings, argv[idx + 1]);
				pr_append_external (&warnings, ". Masking both strands by default.");
			}
			idx += 1;
			
		} else if (!strcmp (argv[idx], "-s") || !strcmp (argv[idx], "--soft_mask")) {
			mp.do_soft_masking = SOFT_MASKING;

		} else if (!strcmp (argv[idx], "-D")) {
			debug += 1;
			
		} else {
			pr_append_new_chunk_external (&parse_err, "Unknown parameter: ");
			pr_append_external (&parse_err, argv[idx]);
			break;
		}
	}

	input_seq = create_input_sequence_from_file_name (sequence_file_name, &parse_err);

	if (parse_err.data != NULL) {
		fprintf(stderr, "%s -> parsing commandline: ERROR: %s\n", pr_programme_name, parse_err.data);
		exit(-1);
	}
	if (warnings.data != NULL) {
		fprintf(stderr, "%s -> parsing commandline: WARNING: %s\n", pr_programme_name, warnings.data);
	}
	
	if (lists_file_name) {
		/* if lists are given in a text file */
		mp.fp = read_formula_parameters_from_file (lists_file_name, &nlist_parameters, &pbuilder, &mp.formula_intercept, &parse_err);
		nlists = pbuilder.nfp;
	} 
	
	if (npos != 0) {
		/* if lists are given by commandline arguments (can be added to the ones given in a file) */
		pbuilder.fp_array = mp.fp;

		for (idx = 0; idx < npos; idx++) {
			unsigned int pos = list_pos[idx] + 1;
			char *values[4];
			unsigned int nvalues = list_components[idx];
			char *end;
			memcpy (&values, &argv[pos], nvalues * sizeof(*argv));
			
			if (nvalues == 1) {
				double ic;
				double neg = 1.0;
				if (values[0][0] == '-') {
					values[0] += 1;
					neg = -1.0;
				}
				ic = strtod (values[0], &end);
				if (*end == 0) {
					mp.formula_intercept = ic * neg;
					continue;
				}
			}
			add_variable_to_formula_parameters (values, nvalues, &pbuilder, &parse_err);
		}		
		nlists = pbuilder.nfp;
		mp.fp = pbuilder.fp_array;

	} else if (nlists == 0 && !lists_file_name) {
		/* if there are no lists specified use the default formula */
		mp.fp = create_default_formula_parameters (mp.list_prefix, &parse_err);
		mp.formula_intercept = DEFAULT_INTERCEPT;
		nlists = DEFAULT_NLISTS;
		nlist_parameters = DEFAULT_NLIST_PARAMETERS;
	} 

	mp.nlists = nlists;
	
	if (mp.abs_cutoff > 0 && nlist_parameters != 1) {
		fprintf (stderr, "Error: Absolute value cutoff works with one list and one k-mer frequency parameter only. Currently you are using %u lists and %u parameters.\n", nlists, nlist_parameters);
		print_help(1);
	}

	if (parse_err.data != NULL) {
		fprintf(stderr, "%s -> building formula: ERROR: %s\n", pr_programme_name, parse_err.data);
		delete_input_sequence (input_seq);
		exit(-1);
	}
	
	if (debug > 0) print_parameters (&mp);
	
	read_and_mask_sequence (input_seq, NULL, &mp, &parse_err, debug);

	if (parse_err.data != NULL) {
		fprintf(stderr, "%s -> masking sequence: ERROR: %s\n", pr_programme_name, parse_err.data);
		delete_input_sequence (input_seq);
		delete_formula_parameters (mp.fp, nlists);
		exit(-1);
	}
	
	destroy_pr_append_str_data (&warnings);
	destroy_pr_append_str_data (&parse_err);
	delete_input_sequence (input_seq);
	delete_formula_parameters (mp.fp, nlists);
	
	if (debug > 0) fprintf (stderr, "Done!\n");
	return 0;
}
Example #3
0
static void
p3sl_append(pr_append_str *x, const char *s)
{
  int r = pr_append_external(x, s);
  if (r) longjmp(_jmp_buf, 1);
}
int
main(int argc, char *argv[])
{
  /* Setup the input data structures handlers */
  int format_output = 0;
  int strict_tags = 0;
  int echo_settings = 0;
  int io_version = 4;
  int default_version = 2;
  int dump_args = 0;

  p3_global_settings *global_pa;
  seq_args *sarg;
  read_boulder_record_results read_boulder_record_res = {0,0};

  pr_append_str p3_settings_path;
  pr_append_str output_path;
  pr_append_str error_path;
  pr_append_str fatal_parse_err;
  pr_append_str nonfatal_parse_err;
  pr_append_str warnings;

  /* Some variables needed by getopt */
  int opt, option_index = 0;
  struct option long_options[] = {
    {"about", no_argument, 0, 'a'},
    {"format_output", no_argument, &format_output, 1},
    {"strict_tags", no_argument, &strict_tags, 1},
    {"p3_settings_file", required_argument, 0, 'p'},
    {"echo_settings_file", no_argument, &echo_settings, 1},
    {"io_version", required_argument, 0, 'i'},
    {"default_version", required_argument, 0, 'd'},
    {"Dump_args", no_argument, 0, 'D'},
    {"2x_compat", no_argument, 0, '2'},
    {"output", required_argument, 0, 'o'},
    {"error", required_argument, 0, 'e'},
    {0, 0, 0, 0}
  };
  int about = 0, compat = 0, invalid_flag = 0;

  /* Retval will point to the return value from choose_primers(). */
  p3retval *retval = NULL;
  int input_found=0;

  init_pr_append_str(&fatal_parse_err);
  init_pr_append_str(&nonfatal_parse_err);
  init_pr_append_str(&warnings);
  init_pr_append_str(&p3_settings_path);
  init_pr_append_str(&output_path);
  init_pr_append_str(&error_path);

  /* Get the program name for correct error messages */
  pr_release = libprimer3_release();
  pr_program_name = argv[0];
  p3_set_program_name(pr_program_name);

  /* We set up some signal handlers in case someone starts up the program
   * from the command line, wonders why nothing is happening, and then kills
   * the program. */
  signal(SIGINT, sig_handler);
  signal(SIGTERM, sig_handler);

  /* Read in the flags provided with the program call */
  opterr = 0;
  while ((opt = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1) {
    switch (opt) {
    case 'a':
      about = 1;
      break;
    case 'p':
      if (pr_append_external(&p3_settings_path, optarg)) {
	exit(-2); /* Out of memory. */
      }
      break;
    case 'i':
      if (!strcmp(optarg, "4"))
        io_version = 4;
      else
        io_version = -1;
      break;

    case 'd': /* default_version */
      if (!strcmp(optarg, "1"))
        default_version = 1;
      else if (!strcmp(optarg, "2"))
        default_version = 2;
      else
        default_version = -1;
      break;

    case 'D':  /* Undocumented flag for testing; causes 
		  values of arguments to be echoed to
		  stdout. */
      dump_args = 1;
      break;
    case '2':
      compat = 1;
      break;
    case 'o':
      if (pr_append_external(&output_path, optarg)) {
	exit(-2); /* Out of memory. */
      }

      break;
    case 'e':
      if (pr_append_external(&error_path, optarg)) {
	exit(-2); /* Out of memory. */
      }

      break;
    case '?':
      invalid_flag = 1;
      break;
    }
  }
  /* Open the output and error files specified */

  if (!pr_is_empty(&error_path)) {
    /* reassign stderr */
    if (freopen(pr_append_str_chars(&error_path), "w", stderr)
	== NULL) {
      fprintf(stderr, "Error creating file %s\n",
	      pr_append_str_chars(&error_path));
      exit(-1);
    }
    destroy_pr_append_str_data(&error_path);
  }

  if (!pr_is_empty(&output_path)) {
    /* reassign stdout */
    if (freopen(pr_append_str_chars(&output_path), "w", stdout)
	== NULL) {
      fprintf(stderr, "Error creating file %s\n",
	      pr_append_str_chars(&output_path));
      exit(-1);
    }
    destroy_pr_append_str_data(&output_path);
  }
  /* We do any printing after redirecting stdout and stderr */
  if (about == 1) {
    printf("%s\n", pr_release);
    exit(0);
  }
  if ((io_version == -1) || (invalid_flag == 1) || (default_version == -1)) {
    print_usage();
    exit(-1);
  }
  if (compat == 1) {
    printf("PRIMER_ERROR=flag -2x_compat is no longer supported\n=\n");
    exit(-1);
  }

  /* Check if an input file has been specified on the command line. */
  if (optind < argc) {
    if (optind + 1 != argc) {
      print_usage();
      exit(-1);
    }
    if (freopen(argv[optind], "r", stdin) == NULL) {
      fprintf(stderr, "Error opening file %s\n", argv[optind]);
      exit(-1);
    }
  }

  /* Allocate the space for global settings and fill in default parameters */
  if (default_version == 1)
    global_pa = p3_create_global_settings_default_version_1();
  else if (default_version == 2) 
    global_pa = p3_create_global_settings();
  else {
    print_usage();
    exit(-1);
  }
    
  if (!global_pa) {
    exit(-2); /* Out of memory. */
  }
  global_pa->dump = dump_args ;

  /* Settings files have to be read in just below, and
     the functions need a temporary sarg */
  if (!(sarg = create_seq_arg())) {
    exit(-2);
  }

  /* Read data from the settings file until a "=" line occurs.  Assign
     parameter values for primer picking to pa and sa. */
  if (!pr_is_empty(&p3_settings_path)) {
    read_p3_file(pr_append_str_chars(&p3_settings_path),
		 settings,
		 echo_settings && !format_output,
		 strict_tags,
		 global_pa, sarg, &fatal_parse_err,
		 &nonfatal_parse_err, &warnings, &read_boulder_record_res);
    destroy_pr_append_str_data(&p3_settings_path);
    /* Check if any thermodynamical alignment flag was given */
    if ((global_pa->thermodynamic_oligo_alignment == 1) || 
	(global_pa->thermodynamic_template_alignment == 1))
      read_thermodynamic_parameters();
  }

  /* We also need to print out errors here because the loop erases all
     errors at start. If there are fatal errors, write the proper
     message and exit */
  if (fatal_parse_err.data != NULL) {
    if (format_output) {
        format_error(stdout, sarg->sequence_name, fatal_parse_err.data);
    } else {
        print_boulder_error(fatal_parse_err.data);
    }
    fprintf(stderr, "%s: %s\n",
              pr_program_name, fatal_parse_err.data);
    destroy_seq_args(sarg);
    exit(-4);
  }

  /* If there are nonfatal errors, write the proper message
   * and skip to the end of the loop */
  if (!pr_is_empty(&nonfatal_parse_err)) {
    if (format_output) {
        format_error(stdout, sarg->sequence_name,
                     nonfatal_parse_err.data);
    } else {
        print_boulder_error(nonfatal_parse_err.data);
    }
  }

  /* The temporary sarg is not needed any more */
  destroy_seq_args(sarg);
  sarg = NULL;

  /* Read the data from input stream record by record and process it if
   * there are no errors. This is where the work is done. */
  while (1) {
    /* Create and initialize a seq_args data structure. sa (seq_args *) is
     * initialized here because Values are _not_ retained across different
     * input records. */
    if (!(sarg = create_seq_arg())) {
      exit(-2);
    }

    /* Reset all errors handlers and the return structure */
    pr_set_empty(&fatal_parse_err);
    pr_set_empty(&nonfatal_parse_err);
    pr_set_empty(&warnings);
    retval = NULL;

    /* See read_boulder.h for documentation on read_boulder_record().*/
    if (!read_boulder_record(stdin,
			     &strict_tags,
			     &io_version,
			     !format_output,
			     all_parameters,
			     global_pa,
			     sarg,
			     &fatal_parse_err,
			     &nonfatal_parse_err,
			     &warnings,
			     &read_boulder_record_res)) {
      break; /* There were no more boulder records */
    }

    /* Check if any thermodynamical alignment flag was given and the
       path to the parameter files changed - we need to reread them */
    if (((global_pa->thermodynamic_oligo_alignment == 1) ||
	 (global_pa->thermodynamic_template_alignment == 1))
	&& (thermodynamic_path_changed == 1))
      read_thermodynamic_parameters();

    /* Check that we found the thermodynamic parameters in case any thermodynamic flag was set to 1. */
    if (((global_pa->thermodynamic_oligo_alignment == 1) ||
	 (global_pa->thermodynamic_template_alignment == 1))
	&& (thermodynamic_params_path == NULL)) {
      /* no parameter directory found, error */
      printf("PRIMER_ERROR=thermodynamic approach chosen, but path to thermodynamic parameters not specified\n=\n");
      exit(-1);
    }

    input_found = 1;
    if ((global_pa->primer_task == generic)
	&& (global_pa->pick_internal_oligo == 1)){
      PR_ASSERT(global_pa->pick_internal_oligo);
    }

    /* If there are fatal errors, write the proper message and exit */
    if (fatal_parse_err.data != NULL) {
      if (format_output) {
        format_error(stdout, sarg->sequence_name, fatal_parse_err.data);
      } else {
        print_boulder_error(fatal_parse_err.data);
      }
      fprintf(stderr, "%s: %s\n",
              pr_program_name, fatal_parse_err.data);
      destroy_p3retval(retval);
      destroy_seq_args(sarg);
      exit(-4);
    }

    /* If there are nonfatal errors, write the proper message
     * and skip to the end of the loop */
    if (!pr_is_empty(&nonfatal_parse_err)) {
      if (format_output) {
        format_error(stdout, sarg->sequence_name,
                     nonfatal_parse_err.data);
      } else {
        print_boulder_error(nonfatal_parse_err.data);
      }
      goto loop_wrap_up;
    }

    /* Print any warnings and continue processing */
    if (!pr_is_empty(&warnings)) {
      if (format_output) {
        format_warning(stdout, sarg->sequence_name,
		       warnings.data);
      } else {
        print_boulder_warning(warnings.data);
      }
    }

    if (read_boulder_record_res.file_flag && sarg->sequence_name == NULL) {
      /* We will not have a base name for the files */
      if (format_output) {
        format_error(stdout, NULL,
                     "Need PRIMER_SEQUENCE_ID if PRIMER_FILE_FLAG is not 0");
      } else {
        print_boulder_error("Need PRIMER_SEQUENCE_ID if PRIMER_FILE_FLAG is not 0");
      }
      goto loop_wrap_up;
    }

    /* Pick the primers - the central function */
    p3_set_gs_primer_file_flag(global_pa,
                               read_boulder_record_res.file_flag);
    retval = choose_primers(global_pa, sarg);
    if (NULL == retval) exit(-2); /* Out of memory. */

    /* If it was necessary to use a left_input, right_input,
       or internal_oligo_input primer that was
       unacceptable, then add warnings. */
    if (global_pa->pick_anyway && format_output) {
      if (sarg->left_input) {
        add_must_use_warnings(&retval->warnings,
                              "Left primer", &retval->fwd.expl);
      }
      if (sarg->right_input) {
        add_must_use_warnings(&retval->warnings,
                              "Right primer", &retval->rev.expl);
      }
      if (sarg->internal_input) {
        add_must_use_warnings(&retval->warnings,
                              "Hybridization probe", &retval->intl.expl);
      }
    }

    if (pr_is_empty(&retval->glob_err)
        && pr_is_empty(&retval->per_sequence_err)) {
      /* We need to test for errors before we call
         p3_print_oligo_lists. This function only works on retval as
         returned when there were no errors. */
      if (read_boulder_record_res.file_flag) {
        /* Create files with left, right, and internal oligos. */
        p3_print_oligo_lists(retval, sarg, global_pa,
                             &retval->per_sequence_err,
                             sarg->sequence_name);
      }
    }

    if (format_output) {
      print_format_output(stdout, &io_version, global_pa,
                          sarg, retval, pr_release,
                          read_boulder_record_res.explain_flag);
    } else {
      /* Use boulder output */
      print_boulder(io_version, global_pa, sarg, retval,
                    read_boulder_record_res.explain_flag);
    }

  loop_wrap_up: /* Here the failed loops join in again */
    if (NULL != retval) {
      /* Check for errors and print them */
      if (NULL != retval->glob_err.data) {
        fprintf(stderr, "%s: %s\n", pr_program_name, retval->glob_err.data);
        destroy_p3retval(retval);
        destroy_seq_args(sarg);
        exit(-4);
      }
    }
    destroy_p3retval(retval); /* This works even if retval is NULL */
    retval = NULL;
    destroy_seq_args(sarg);
    sarg = NULL;

  }   /* while (1) (processing boulder io records) ...
         End of the primary working loop */

  /* To avoid being distracted when looking for leaks: */
  if ((global_pa->thermodynamic_oligo_alignment == 1) ||
      (global_pa->thermodynamic_template_alignment == 1))
    destroy_thal_structures();
  p3_destroy_global_settings(global_pa);
  global_pa = NULL;
  destroy_seq_args(sarg);
  destroy_pr_append_str_data(&nonfatal_parse_err);
  destroy_pr_append_str_data(&fatal_parse_err);
  destroy_pr_append_str_data(&warnings);
  destroy_dpal_thal_arg_holder();
  free(thermodynamic_params_path);
  /* If it could not read input, then complain and die */
  if (0 == input_found) {
    print_usage();
    exit(-3);
  }
  return 0;
}