1 /*
2 Copyright (c) 1996,1997,1998,1999,2000,2001,2004,2006,2007,2008,2009,
3               2010,2011,2012
4 Whitehead Institute for Biomedical Research, Steve Rozen
5 (http://purl.com/STEVEROZEN/), Andreas Untergasser and Helen Skaletsky.
6 All rights reserved.
7 
8     This file is part of the primer3 suite and libraries.
9 
10     The primer3 suite and libraries are free software;
11     you can redistribute them and/or modify them under the terms
12     of the GNU General Public License as published by the Free
13     Software Foundation; either version 2 of the License, or (at
14     your option) any later version.
15 
16     This software is distributed in the hope that it will be useful,
17     but WITHOUT ANY WARRANTY; without even the implied warranty of
18     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19     GNU General Public License for more details.
20 
21     You should have received a copy of the GNU General Public License
22     along with this software (file gpl-2.0.txt in the source
23     distribution); if not, write to the Free Software
24     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 
26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30 OWNERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 */
38 
39 #include <errno.h>
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <math.h>
43 #include <limits.h>
44 #include <signal.h>
45 #include <float.h>
46 #include <string.h>
47 #include <ctype.h> /* toupper */
48 
49 #ifdef __GNUC__
50 #include <ext/hash_map>
51 #else
52 #include <hash_map>
53 #endif
54 
55 namespace std
56 {
57   using namespace __gnu_cxx;
58 }
59 
60 #include "dpal.h"
61 #include "thal.h"
62 #include "oligotm.h"
63 #include "libprimer3.h"
64 
65 /* #define's */
66 
67 /*
68  * OPTIMIZE_OK_REGIONS 1 allows _optimize_ok_regions_list() to use the
69  * max/min product size info and the max/min oligo length to reduce
70  * the sizes of the ok regions (while still generating the same primer
71  * pairs in the same order).  Set OPTIMIZE_OK_REGIONS to 0 confirm
72  * that the results do not change.  (The output tags
73  * PRIMER_{LEFT,RIGHT,PAIR}_EXPLAIN _will_ likely change.)
74  */
75 #define OPTIMIZE_OK_REGIONS 1
76 
77 #ifndef MAX_PRIMER_LENGTH
78 #define MAX_PRIMER_LENGTH 36
79 #endif
80 #if (MAX_PRIMER_LENGTH > DPAL_MAX_ALIGN)
81 #error "MAX_PRIMER_LENGTH must be <= DPAL_MAX_ALIGN"
82 #endif
83 #if (MAX_PRIMER_LENGTH > THAL_MAX_ALIGN)
84 # error "MAX_PRIMER_LENGTH must be <= THAL_MAX_ALIGN"
85 #endif
86 #define MAX_NN_TM_LENGTH 36 /* The maxium length for which to use the
87                                nearest neighbor model when calculating
88                                oligo Tms. */
89 
90 #define MACRO_CAT_2(A,B) A##B
91 #define MACRO_VALUE_AS_STRING(A) MACRO_STRING(A)
92 
93 #define PR_POSITION_PENALTY_IS_NULL(PA) \
94 (PR_DEFAULT_INSIDE_PENALTY == (PA)->inside_penalty \
95  && PR_DEFAULT_OUTSIDE_PENALTY == (PA)->outside_penalty)
96 
97 #define INITIAL_LIST_LEN     2000 /* Initial size of oligo lists. */
98 #define INITIAL_NUM_RETURN   5    /* Initial space to allocate for pairs to
99                                      return. */
100 
101 #define PAIR_OK 1
102 #define PAIR_FAILED 0
103 
104 #define OK_OR_MUST_USE(H) (!p3_ol_has_any_problem(H) || (H)->must_use)
105 
106 #define PR_UNDEFINED_INT_OPT          INT_MIN
107 #define PR_UNDEFINED_DBL_OPT          DBL_MIN
108 
109 /* Undefined value for alignment score (meaning do not check) used for
110    maximum template mispriming or mishyb. */
111 #define PR_UNDEFINED_ALIGN_OPT        -100.0
112 
113 #define TRIMMED_SEQ_LEN(X) ((X)->incl_l)
114 
115 typedef struct dpal_arg_holder {
116   dpal_args *local;
117   dpal_args *end;
118   dpal_args *local_end;
119   dpal_args *local_ambig;
120   dpal_args *local_end_ambig;
121 } dpal_arg_holder;
122 typedef struct thal_arg_holder {
123   thal_args *any;
124   thal_args *end1;
125   thal_args *end2;
126   thal_args *hairpin_th;
127 } thal_arg_holder;
128 
129 static jmp_buf _jmp_buf;
130 
131 static int thermodynamic_alignment_length_error = 0;
132 static char *thermodynamic_alignment_length_error_msg = NULL;
133 
134 /* Variables needed in choose_pair_or_triple, need to be global
135    for memory de-allocation reasons. Full description given in the function. */
136 static int *max_j_seen;
137 static std::hash_map<int, primer_pair*> **pairs;
138 
139 /* Function declarations. */
140 
141 static void  pr_set_default_global_args_1(p3_global_settings *);
142 static void  pr_set_default_global_args_2(p3_global_settings *);
143 static void _adjust_seq_args(const p3_global_settings *pa,
144                              seq_args *sa,
145                              pr_append_str *nonfatal_err,
146                              pr_append_str *warning);
147 
148 static void _optimize_ok_regions_list(const p3_global_settings *pa,
149 				      seq_args *sa);
150 
151 static int any_5_prime_ol_extension_has_problem(const primer_rec *);
152 
153 static int p3_ol_is_uninitialized(const primer_rec *);
154 
155 static int fake_a_sequence(seq_args *sa, const p3_global_settings *pa);
156 
157 static int    _pr_data_control(const p3_global_settings *,
158                                const seq_args *,
159                                pr_append_str *glob_err,
160                                pr_append_str *nonfatal_err,
161                                pr_append_str *warning);
162 
163 static int    _pr_need_pair_template_mispriming(const p3_global_settings *pa);
164 static int    _pr_need_pair_template_mispriming_thermod(const p3_global_settings *pa);
165 
166 static int    _pr_need_template_mispriming(const p3_global_settings *);
167 static int    _pr_need_template_mispriming_thermod(const p3_global_settings *);
168 
169 static void   _pr_substr(const char *, int, int, char *);
170 
171 
172 static int    _check_and_adjust_intervals(seq_args *sa,
173                                           int seq_len,
174                                           int first_index,
175                                           pr_append_str * nonfatal_err,
176                                           pr_append_str *warning);
177 
178 static int    _check_and_adjust_overlap_pos(seq_args *sa,
179                                             int *list,
180                                             int *count,
181                                             const char *tag,
182                                             int seq_len,
183                                             int first_index,
184                                             pr_append_str * nonfatal_err,
185                                             pr_append_str *warning);
186 
187 static int    _check_and_adjust_1_interval(const char *,
188                                            int num,
189                                            interval_array_t,
190                                            int,
191                                            int first_index,
192                                            pr_append_str *err,
193                                            seq_args *,
194                                            pr_append_str
195                                            *warning, int);
196 
197 static void   sort_primer_array(oligo_array *);
198 
199 static void   add_pair(const primer_pair *, pair_array_t *);
200 
201 static double align(const char *, const char*, const dpal_args *a);
202 
203 static double align_thermod(const char *, const char *, const thal_args *a);
204 
205 static int    characterize_pair(p3retval *p,
206                                 const p3_global_settings *,
207                                 const seq_args *,
208                                 int, int, int,
209                                 primer_pair *,
210                                 const dpal_arg_holder*,
211                                 const thal_arg_holder*,
212                                 int update_stats);
213 
214 static void    choose_pair_or_triple(p3retval *,
215                                     const p3_global_settings *,
216                                     const seq_args *,
217                                     const dpal_arg_holder *,
218                                     const thal_arg_holder *,
219 				    const thal_arg_holder *,
220                                     pair_array_t *);
221 
222 static int    sequence_quality_is_ok(const p3_global_settings *, primer_rec *,
223                                      oligo_type,
224                                      const seq_args *, int, int,
225                                      oligo_stats *global_oligo_stats,
226                                      const args_for_one_oligo_or_primer *);
227 
228 static int    choose_internal_oligo(p3retval *,
229                                     const primer_rec *, const primer_rec *,
230                                     int *,
231                                     const seq_args *,
232                                     const p3_global_settings *,
233                                     const dpal_arg_holder *,
234                                     const thal_arg_holder *);
235 
236 void          compute_position_penalty(const p3_global_settings *,
237                                        const seq_args *,
238                                        primer_rec *, oligo_type);
239 
240 static p3retval *create_p3retval(void);
241 
242 static char   dna_to_upper(char *, int);
243 
244 static int    find_stop_codon(const char *, int, int);
245 
246 static void   gc_and_n_content(int, int, const char *, primer_rec *);
247 
248 static int    make_detection_primer_lists(p3retval *,
249                                 const p3_global_settings *,
250                                 const seq_args *,
251                                 const dpal_arg_holder *,
252                                 const thal_arg_holder *);
253 
254 static int    make_complete_primer_lists(p3retval *retval,
255                                 const p3_global_settings *pa,
256                                 const seq_args *sa,
257                                 const dpal_arg_holder *dpal_arg_to_use,
258                                 const thal_arg_holder *thal_arg_to_use,
259 				const thal_arg_holder *thal_oligo_arg_to_use);
260 
261 static int    add_primers_to_check(p3retval *retval,
262                                 const p3_global_settings *pa,
263                                 const seq_args *sa,
264                                 const dpal_arg_holder *dpal_arg_to_use,
265                                 const thal_arg_holder *thal_arg_to_use,
266 				const thal_arg_holder *thal_oligo_arg_to_use);
267 
268 static int    pick_sequencing_primer_list(p3retval *retval,
269                                 const p3_global_settings *pa,
270                                 const seq_args *sa,
271                                 const dpal_arg_holder *dpal_arg_to_use,
272                                 const thal_arg_holder *thal_arg_to_use);
273 
274 static int    make_internal_oligo_list(p3retval *,
275                                        const p3_global_settings *,
276                                        const seq_args *,
277                                        const dpal_arg_holder *,
278                                        const thal_arg_holder *);
279 
280 static int    pick_only_best_primer(const int, const int,
281                                     oligo_array *,
282                                     const p3_global_settings *,
283                                     const seq_args *,
284                                     const dpal_arg_holder *,
285                                     const thal_arg_holder *,
286                                     p3retval *);
287 
288 static int    pick_primer_range(const int, const int, int *,
289                                 oligo_array *,
290                                 const p3_global_settings *,
291                                 const seq_args *,
292                                 const dpal_arg_holder *,
293                                 const thal_arg_holder *,
294                                 p3retval *retval);
295 
296 static int    add_one_primer(const char *, int *, oligo_array *,
297                              const p3_global_settings *,
298                              const seq_args *,
299                              const dpal_arg_holder *,
300                              const thal_arg_holder *,
301                              p3retval *);
302 
303 static int   add_one_primer_by_position(int, int, int *,
304                                         oligo_array *,
305                                         const p3_global_settings *,
306                                         const seq_args *,
307                                         const dpal_arg_holder *,
308                                         const thal_arg_holder *,
309                                         p3retval *);
310 
311 static int   pick_primers_by_position(const int, const int,
312                                       int *,
313                                       oligo_array *,
314                                       const p3_global_settings *,
315                                       const seq_args *,
316                                       const dpal_arg_holder *,
317                                       const thal_arg_holder *,
318                                       p3retval *);
319 
320 static double obj_fn(const p3_global_settings *, primer_pair *);
321 
322 static int    left_oligo_in_pair_overlaps_used_oligo(const primer_rec *left,
323                                                      const primer_pair *best_pair,
324                                                      int min_dist);
325 
326 static int    right_oligo_in_pair_overlaps_used_oligo(const primer_rec *right,
327                                                       const primer_pair *best_pair,
328                                                       int min_dist);
329 
330 static int    oligo_overlaps_interval(int, int,
331                                       const interval_array_t, int);
332 
333 static void   calc_and_check_oligo_features(const p3_global_settings *pa,
334                                        primer_rec *,
335                                        oligo_type,
336                                        const dpal_arg_holder*,
337                                        const thal_arg_holder*,
338                                        const seq_args *, oligo_stats *,
339                                        p3retval *,
340                                        const char *);
341 
342 static void   pr_append(pr_append_str *, const char *);
343 
344 static void   pr_append_new_chunk(pr_append_str *x, const char *s);
345 
346 static int    pair_spans_target(const primer_pair *, const seq_args *);
347 static void   pr_append_w_sep(pr_append_str *, const char *, const char *);
348 static void*  pr_safe_malloc(size_t x);
349 static void*  pr_safe_realloc(void *p, size_t x);
350 
351 static int    compare_primer_pair(const void *, const void*);
352 
353 static int    primer_rec_comp(const void *, const void *);
354 static int    print_list_header(FILE *, oligo_type, int, int, int);
355 static int    print_oligo(FILE *, const seq_args *, int, const primer_rec *,
356                           oligo_type, int, int,int);
357 static char   *strstr_nocase(char *, char *);
358 
359 static double p_obj_fn(const p3_global_settings *, primer_rec *, int );
360 
361 static void   oligo_compl(primer_rec *,
362                           const args_for_one_oligo_or_primer *po_args,
363                           oligo_stats *,
364                           const dpal_arg_holder *,
365                           const char *oligo_seq,
366                           const char *revc_oligo_seq
367                           );
368 static void   oligo_compl_thermod(primer_rec *, /* TO DO 2012-06-01 -- update by removing last argument. */
369                           const args_for_one_oligo_or_primer *po_args,
370                           oligo_stats *,
371                           const thal_arg_holder *,
372                           const char *oligo_seq,
373                           const char *revc_oligo_seq
374                           );
375 static void   oligo_hairpin(primer_rec *,
376                             const args_for_one_oligo_or_primer *po_args,
377                             oligo_stats *,
378                             const thal_arg_holder *,
379                             const char *oligo_seq
380                             );
381 
382 static void   oligo_compute_sequence_and_reverse(primer_rec *,
383                                                  const seq_args *,
384                                                  oligo_type,
385                                                  int*, int*,
386                                                  char*, char*);
387 
388 static void   oligo_repeat_library_mispriming(primer_rec *,
389                                               const p3_global_settings *,
390                                               const seq_args *,
391                                               oligo_type,
392                                               oligo_stats *,
393                                               const dpal_arg_holder *);
394 
395 static void   oligo_template_mispriming(primer_rec *,
396                                         const p3_global_settings *,
397                                         const seq_args *,
398                                         oligo_type,
399                                         oligo_stats *,
400                                         const dpal_args *,
401                                         const thal_args *);
402 
403 static int    pair_repeat_sim(primer_pair *, const p3_global_settings *);
404 
405 static void   free_repeat_sim_score(p3retval *);
406 static void   free_primer_repeat_sim_score(primer_rec *);
407 
408 /* edited by T. Koressaar for lowercase masking:  */
409 static int    is_lowercase_masked(int position,
410                                    const char *sequence,
411                                    primer_rec *h,
412                                    oligo_stats *);
413 
414 static int    primer_must_match(const p3_global_settings *pa,
415 				primer_rec *h,
416 				oligo_stats *stats,
417 				const char *input_oligo_seq,
418                                 char *match_three_prime,
419                                 char *match_five_prime);
420 static int    compare_nucleotides(const char a, const char b);
421 static int    test_must_match_parameters(char *test);
422 
423 static void set_retval_both_stop_codons(const seq_args *sa, p3retval *retval);
424 
425 /* Functions to set bitfield parameters for oligos (or primers) */
426 static void bf_set_overlaps_target(primer_rec *, int);
427 static int bf_get_overlaps_target(const primer_rec *);
428 static void bf_set_overlaps_excl_region(primer_rec *, int);
429 static int bf_get_overlaps_excl_region(const primer_rec *);
430 static void bf_set_infinite_pos_penalty(primer_rec *, int);
431 static int bf_get_infinite_pos_penalty(const primer_rec *);
432 
433 /* Functions to record problems with oligos (or primers) */
434 static void initialize_op(primer_rec *);
435 static void op_set_completely_written(primer_rec *);
436 static void op_set_must_match_err(primer_rec *);
437 static void op_set_too_many_ns(primer_rec *);
438 static void op_set_overlaps_target(primer_rec *);
439 static void op_set_high_gc_content(primer_rec *);
440 static void op_set_low_gc_content(primer_rec *);
441 static void op_set_high_tm(primer_rec *);
442 static void op_set_low_tm(primer_rec *);
443 static void op_set_overlaps_excluded_region(primer_rec *);
444 static void op_set_not_in_any_ok_region(primer_rec *);
445 static void op_set_high_self_any(primer_rec *oligo);
446 static void op_set_high_self_end(primer_rec *oligo);
447 static void op_set_high_hairpin_th(primer_rec *oligo);
448 static void op_set_no_gc_glamp(primer_rec *);
449 static void op_set_too_many_gc_at_end(primer_rec *);
450 static void op_set_high_end_stability(primer_rec *);
451 static void op_set_high_poly_x(primer_rec *);
452 static void op_set_low_sequence_quality(primer_rec *);
453 static void op_set_low_end_sequence_quality(primer_rec *oligo);
454 static void op_set_high_similarity_to_non_template_seq(primer_rec *);
455 static void op_set_high_similarity_to_multiple_template_sites(primer_rec *);
456 static void op_set_overlaps_masked_sequence(primer_rec *);
457 static void op_set_too_long(primer_rec *);
458 static void op_set_too_short(primer_rec *);
459 static void op_set_does_not_amplify_orf(primer_rec *);
460 /* End functions to set problems in oligos */
461 
462 /* Global static variables. */
463 static const char *primer3_copyright_char_star = "\n"
464 "Copyright (c) 1996,1997,1998,1999,2000,2001,2004,2006,2007,2008\n"
465 "  2009,2010,2011,2012\n"
466 "Whitehead Institute for Biomedical Research, Steve Rozen\n"
467 "(http://purl.com/STEVEROZEN/), Andreas Untergasser and Helen Skaletsky\n"
468 "All rights reserved.\n"
469 "\n"
470 "    This file is part of the primer3 suite and libraries.\n"
471 "\n"
472 "    The primer3 suite and libraries are free software;\n"
473 "    you can redistribute them and/or modify them under the terms\n"
474 "    of the GNU General Public License as published by the Free\n"
475 "    Software Foundation; either version 2 of the License, or (at\n"
476 "    your option) any later version.\n"
477 "\n"
478 "    This software is distributed in the hope that it will be useful,\n"
479 "    but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
480 "    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
481 "    GNU General Public License for more details.\n"
482 "\n"
483 "    You should have received a copy of the GNU General Public License\n"
484 "    along with this software (file gpl-2.0.txt in the source\n"
485 "    distribution); if not, write to the Free Software\n"
486 "    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n"
487 "\n"
488 "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
489 "\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
490 "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
491 "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
492 "OWNERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
493 "SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
494 "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
495 "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
496 "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
497 "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
498 "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
499 "\n";
500 
501 static const char *pr_program_name = "probably primer3_core";
502 
503 static const int use_end_for_th_template_mispriming = 1;
504 
505 #define DEFAULT_OPT_GC_PERCENT PR_UNDEFINED_INT_OPT
506 
507 /* Set the program name */
508 void
p3_set_program_name(const char * pname)509 p3_set_program_name(const char *pname)
510 {
511   pr_program_name = pname;
512 }
513 
514 /* ============================================================ */
515 /* BEGIN functions for global settings                          */
516 /* ============================================================ */
517 
518 /* Allocate space for global settings and fill in defaults */
519 p3_global_settings *
p3_create_global_settings()520 p3_create_global_settings()
521 {
522   p3_global_settings *r;
523 
524   if (!(r = (p3_global_settings *) malloc(sizeof(*r)))) {
525     return NULL;
526   }
527 
528   pr_set_default_global_args_2(r);
529 
530   return r;
531 }
532 
533 /* Allocate space for global settings and fill in defaults */
534 p3_global_settings *
p3_create_global_settings_default_version_1()535 p3_create_global_settings_default_version_1()
536 {
537   p3_global_settings *r;
538 
539   if (!(r = (p3_global_settings *) malloc(sizeof(*r)))) {
540     return NULL;
541   }
542 
543   pr_set_default_global_args_1(r);
544 
545   return r;
546 }
547 
548 /* Free the space of global settings */
549 void
p3_destroy_global_settings(p3_global_settings * a)550 p3_destroy_global_settings(p3_global_settings *a)
551 {
552   if (NULL != a) {
553     if (NULL != a->p_args.must_match_five_prime) {
554     	free(a->p_args.must_match_five_prime);
555     }
556     if (NULL != a->p_args.must_match_three_prime) {
557     	free(a->p_args.must_match_three_prime);
558     }
559     if (NULL != a->o_args.must_match_five_prime) {
560     	free(a->o_args.must_match_five_prime);
561     }
562     if (NULL != a->o_args.must_match_three_prime) {
563     	free(a->o_args.must_match_three_prime);
564     }
565     destroy_seq_lib(a->p_args.repeat_lib);
566     destroy_seq_lib(a->o_args.repeat_lib);
567     free(a);
568   }
569 }
570 
571 static void
pr_set_default_global_args_2(p3_global_settings * a)572 pr_set_default_global_args_2(p3_global_settings *a)
573 /* Write the default values for default_values=2 into
574    the p3_global_settings struct */
575 {
576   pr_set_default_global_args_1(a);
577   a->tm_santalucia                    = santalucia_auto;
578   a->salt_corrections                 = santalucia;
579   a->thermodynamic_oligo_alignment    = 1;
580   a->thermodynamic_template_alignment = 0;
581   a->p_args.divalent_conc             = 1.5;
582   a->p_args.dntp_conc                 = 0.6;
583   a->lib_ambiguity_codes_consensus    = 0;
584 }
585 
586 /* Write the default values for default_values=1 into
587    the p3_global_settings struct */
588 static void
pr_set_default_global_args_1(p3_global_settings * a)589 pr_set_default_global_args_1(p3_global_settings *a)
590 {
591   memset(a, 0, sizeof(*a));
592 
593   /* Arguments for primers ================================= */
594   a->p_args.opt_size          = 20;
595   a->p_args.min_size          = 18;
596   a->p_args.max_size          = 27;
597 
598   a->p_args.opt_tm            = 60;
599   a->p_args.min_tm            = 57;
600   a->p_args.max_tm            = 63;
601 
602   a->p_args.min_gc            = 20.0;
603   a->p_args.opt_gc_content    = DEFAULT_OPT_GC_PERCENT;
604   a->p_args.max_gc            = 80.0;
605   a->p_args.salt_conc         = 50.0;
606   a->p_args.divalent_conc     = 0.0;
607   a->p_args.dntp_conc         = 0.0;
608 
609   a->p_args.dna_conc          = 50.0;
610   a->p_args.num_ns_accepted   = 0;
611   a->p_args.max_self_any      = 8.0;
612   a->p_args.max_self_end      = 3.0;
613   a->p_args.max_self_any_th   = 47.0;
614   a->p_args.max_self_end_th   = 47.0;
615   a->p_args.max_hairpin_th    = 47.0;
616   a->p_args.max_poly_x        = 5;
617   a->p_args.max_repeat_compl  = 12.0;
618   a->p_args.min_quality       = 0;
619   a->p_args.min_end_quality   = 0;
620   a->p_args.max_template_mispriming = PR_UNDEFINED_ALIGN_OPT;
621   a->p_args.max_template_mispriming_th = PR_UNDEFINED_ALIGN_OPT;
622   /* The following apply only to primers (and not to internal
623      oligos). */
624   a->gc_clamp                 = 0;
625   a->max_end_gc               = 5;
626 
627 /* Weights for objective functions for oligos and pairs. */
628   a->p_args.weights.compl_any     = 0;
629   a->p_args.weights.compl_any_th  = 0;
630   a->p_args.weights.compl_end     = 0;
631   a->p_args.weights.compl_end_th  = 0;
632   a->p_args.weights.end_quality   = 0;
633   a->p_args.weights.end_stability = 0;
634   a->p_args.weights.gc_content_gt = 0;
635   a->p_args.weights.gc_content_lt = 0;
636   a->p_args.weights.hairpin_th    = 0;
637   a->p_args.weights.length_gt     = 1;
638   a->p_args.weights.length_lt     = 1;
639   a->p_args.weights.num_ns        = 0;
640   a->p_args.weights.pos_penalty   = 1;
641   a->p_args.weights.repeat_sim    = 0;
642   a->p_args.weights.seq_quality   = 0;
643   a->p_args.weights.temp_cutoff   = 5;
644   a->p_args.weights.temp_gt       = 1;
645   a->p_args.weights.temp_lt       = 1;
646   a->p_args.weights.template_mispriming = 0.0;
647   a->p_args.weights.template_mispriming_th = 0.0;
648   a->p_args.must_match_five_prime  = NULL;
649   a->p_args.must_match_three_prime = NULL;
650   /* End of weights for objective functions for oligos and pairs. */
651 
652   /* End of arguments for primers =========================== */
653 
654   a->max_diff_tm         = 100.0;
655   a->tm_santalucia       = breslauer_auto;
656   a->salt_corrections    = schildkraut;
657   a->pair_compl_any      = 8.0;
658   a->pair_compl_end      = 3.0;
659   a->pair_compl_any_th   = 47.0;
660   a->pair_compl_end_th   = 47.0;
661   a->thermodynamic_oligo_alignment = 0;
662   a->thermodynamic_template_alignment = 0;
663   a->liberal_base        = 0;
664   a->primer_task         = generic;
665   a->pick_left_primer    = 1;
666   a->pick_right_primer   = 1;
667   a->pick_internal_oligo = 0;
668   a->first_base_index    = 0;
669   a->num_return          = 5;
670   a->pr_min[0]           = 100;
671   a->pr_max[0]           = 300;
672   a->num_intervals       = 1;
673   a->pair_repeat_compl   = 24.0;
674   a->quality_range_min   = 0;
675   a->quality_range_max   = 100;
676   a->outside_penalty     = PR_DEFAULT_OUTSIDE_PENALTY;
677   a->inside_penalty      = PR_DEFAULT_INSIDE_PENALTY;
678   a->max_end_stability   = 100.0;
679   a->lowercase_masking   = 0;
680   a->product_max_tm      = PR_DEFAULT_PRODUCT_MAX_TM;
681   a->product_min_tm      = PR_DEFAULT_PRODUCT_MIN_TM;
682   a->product_opt_tm      = PR_UNDEFINED_DBL_OPT;
683   a->product_opt_size    = PR_UNDEFINED_INT_OPT;
684   a->pair_max_template_mispriming = PR_UNDEFINED_ALIGN_OPT;
685   a->pair_max_template_mispriming_th = PR_UNDEFINED_ALIGN_OPT;
686   a->o_args.opt_size        = 20;
687   a->o_args.min_size        = 18;
688   a->o_args.max_size        = 27;
689   a->o_args.opt_tm          = 60.0;
690   a->o_args.min_tm          = 57.0;
691   a->o_args.max_tm          = 63.0;
692   a->o_args.min_gc          = 20.0;
693   a->o_args.max_gc          = 80.0;
694   a->o_args.opt_gc_content  = DEFAULT_OPT_GC_PERCENT;
695   a->o_args.max_poly_x      = 5;
696   a->o_args.salt_conc       = 50.0;
697   a->o_args.divalent_conc   = 0.0;
698   a->o_args.dntp_conc       = 0.0;
699   a->o_args.dna_conc        = 50.0;
700   a->o_args.num_ns_accepted = 0;
701   a->o_args.max_self_any    = 12.0;
702   a->o_args.max_self_end    = 12.0;
703   a->o_args.max_self_any_th = 47.0;
704   a->o_args.max_self_end_th = 47.0;
705   a->o_args.max_hairpin_th  = 47.0;
706   a->o_args.max_repeat_compl= 12.0;
707 
708   a->o_args.min_quality           = 0;
709   a->o_args.min_end_quality       = 0;
710   a->o_args.max_template_mispriming = PR_UNDEFINED_ALIGN_OPT;
711   a->o_args.max_template_mispriming_th = PR_UNDEFINED_ALIGN_OPT;
712   a->o_args.weights.temp_gt       = 1;
713   a->o_args.weights.temp_lt       = 1;
714   a->o_args.weights.length_gt     = 1;
715   a->o_args.weights.length_lt     = 1;
716   a->o_args.weights.gc_content_gt = 0;
717   a->o_args.weights.gc_content_lt = 0;
718   a->o_args.weights.compl_any     = 0;
719   a->o_args.weights.compl_end     = 0;
720   a->o_args.weights.compl_any_th  = 0;
721   a->o_args.weights.compl_end_th  = 0;
722   a->o_args.weights.hairpin_th    = 0;
723   a->o_args.weights.num_ns        = 0;
724   a->o_args.weights.repeat_sim    = 0;
725   a->o_args.weights.seq_quality   = 0;
726   a->o_args.weights.end_quality   = 0;
727   a->o_args.must_match_five_prime  = NULL;
728   a->o_args.must_match_three_prime = NULL;
729 
730   a->pr_pair_weights.primer_quality  = 1;
731   a->pr_pair_weights.io_quality      = 0;
732   a->pr_pair_weights.diff_tm         = 0;
733   a->pr_pair_weights.compl_any       = 0;
734   a->pr_pair_weights.compl_end       = 0;
735   a->pr_pair_weights.compl_any_th    = 0;
736   a->pr_pair_weights.compl_end_th    = 0;
737   a->pr_pair_weights.temp_cutoff     = 5;
738   a->pr_pair_weights.repeat_sim      = 0;
739 
740   a->pr_pair_weights.product_tm_lt   = 0;
741   a->pr_pair_weights.product_tm_gt   = 0;
742   a->pr_pair_weights.product_size_lt = 0;
743   a->pr_pair_weights.product_size_gt = 0;
744 
745   a->lib_ambiguity_codes_consensus   = 1;
746   /*  Set to 1 for backward compatibility. This _NOT_ what
747       one normally wants, since many libraries contain
748       strings of N, which then match every oligo (very bad).
749   */
750 
751   a->min_left_three_prime_distance   = -1;
752   a->min_right_three_prime_distance  = -1;
753 
754   a->sequencing.lead                 = 50;
755   a->sequencing.spacing              = 500;
756   a->sequencing.interval             = 250;
757   a->sequencing.accuracy             = 20;
758 
759   a->min_5_prime_overlap_of_junction = 7;
760   a->min_3_prime_overlap_of_junction = 4;
761 
762 }
763 
764 /* Add a pair of integers to an  array of intervals */
765 int
p3_add_to_interval_array(interval_array_t2 * interval_arr,int i1,int i2)766 p3_add_to_interval_array(interval_array_t2 *interval_arr, int i1, int i2)
767 {
768   int c = interval_arr->count;
769   if (c >= PR_MAX_INTERVAL_ARRAY) return 1;
770   interval_arr->pairs[c][0] = i1;
771   interval_arr->pairs[c][1] = i2;
772   interval_arr->count++;
773   return  0;
774 }
775 
776 /* Add 2 pairs of integers to an array of 2 intervals */
777 int
p3_add_to_2_interval_array(interval_array_t4 * interval_arr,int i1,int i2,int i3,int i4)778 p3_add_to_2_interval_array(interval_array_t4 *interval_arr, int i1, int i2, int i3, int i4)
779 {
780   int c = interval_arr->count;
781   if (c >= PR_MAX_INTERVAL_ARRAY) return 1;
782   /* for a region either both values are given, or none is given */
783   if (((i1 == -1) && (i2 != -1)) || ((i1 != -1) && (i2 == -1)))
784     return 2;
785   if (((i3 == -1) && (i4 != -1)) || ((i3 != -1) && (i4 == -1)))
786     return 2;
787   interval_arr->left_pairs[c][0] = i1;
788   interval_arr->left_pairs[c][1] = i2;
789   interval_arr->right_pairs[c][0] = i3;
790   interval_arr->right_pairs[c][1] = i4;
791   if ((i1 == -1) && (i2 == -1))
792     interval_arr->any_left = 1;
793   if ((i3 == -1) && (i4 == -1))
794     interval_arr->any_right = 1;
795   if ((i1 == -1) && (i2 == -1) && (i3 == -1) && (i4 == -1))
796     interval_arr->any_pair = 1;
797   interval_arr->count++;
798   return  0;
799 }
800 
801 /* ============================================================ */
802 /* END functions for global settings                            */
803 /* ============================================================ */
804 
805 int
interval_array_t2_count(const interval_array_t2 * array)806 interval_array_t2_count(const interval_array_t2 *array)
807 {
808   return array->count;
809 }
810 
811 const int *
interval_array_t2_get_pair(const interval_array_t2 * array,int i)812 interval_array_t2_get_pair(const interval_array_t2 *array, int i)
813 {
814   if (i > array->count) abort();
815   if (i < 0) abort();
816   return array->pairs[i];
817 }
818 
819 /* ============================================================ */
820 /* BEGIN functions for p3retval                                 */
821 /* ============================================================ */
822 
823 /* Allocate a new primer3 state. Return NULL if out of memory. Assuming
824    malloc sets errno to ENOMEM according to Unix98, set errno to ENOMEM
825    on out-of-memory error. */
826 static p3retval *
create_p3retval(void)827 create_p3retval(void)
828 {
829   p3retval *state = (p3retval *)malloc(sizeof(*state));
830   if (!state)
831     return NULL;
832 
833   state->fwd.oligo
834     = (primer_rec *) malloc(sizeof(*state->fwd.oligo)  * INITIAL_LIST_LEN);
835 
836   state->rev.oligo
837     = (primer_rec *) malloc(sizeof(*state->rev.oligo)  * INITIAL_LIST_LEN);
838 
839   state->intl.oligo
840     = (primer_rec *) malloc(sizeof(*state->intl.oligo) * INITIAL_LIST_LEN);
841 
842   if (state->fwd.oligo == NULL
843       || state->rev.oligo == NULL
844       || state->intl.oligo == NULL) {
845     free(state);
846     return NULL;
847   }
848 
849   state->fwd.storage_size  = INITIAL_LIST_LEN;
850   state->rev.storage_size  = INITIAL_LIST_LEN;
851   state->intl.storage_size = INITIAL_LIST_LEN;
852 
853   state->fwd.num_elem  = 0;
854   state->rev.num_elem  = 0;
855   state->intl.num_elem = 0;
856 
857   state->fwd.type  = OT_LEFT;
858   state->intl.type = OT_INTL;
859   state->rev.type  = OT_RIGHT;
860 
861   state->best_pairs.storage_size = 0;
862   state->best_pairs.pairs = NULL;
863   state->best_pairs.num_pairs = 0;
864 
865   init_pr_append_str(&state->glob_err);
866   init_pr_append_str(&state->per_sequence_err);
867   init_pr_append_str(&state->warnings);
868 
869   memset(&state->fwd.expl,  0, sizeof(state->fwd.expl));
870   memset(&state->rev.expl,  0, sizeof(state->rev.expl));
871   memset(&state->intl.expl, 0, sizeof(state->intl.expl));
872 
873   memset(&state->best_pairs.expl, 0, sizeof(state->best_pairs.expl));
874 
875   return state;
876 }
877 /* ============================================================ */
878 /* BEGIN functions for dpal_arg_holder                          */
879 /* ============================================================ */
880 
881 /* Create the dpal arg holder */
882 dpal_arg_holder *
create_dpal_arg_holder()883 create_dpal_arg_holder ()
884 {
885 
886   dpal_arg_holder *h
887     = (dpal_arg_holder *) pr_safe_malloc(sizeof(dpal_arg_holder));
888 
889   h->local = (dpal_args *) pr_safe_malloc(sizeof(*h->local));
890   set_dpal_args(h->local);
891   h->local->flag = DPAL_LOCAL;
892 
893   h->end = (dpal_args *) pr_safe_malloc(sizeof(*h->end));
894   set_dpal_args(h->end);
895   h->end->flag = DPAL_GLOBAL_END;
896 
897   h->local_end = (dpal_args *) pr_safe_malloc(sizeof(*h->local_end));
898   set_dpal_args(h->local_end);
899   h->local_end->flag = DPAL_LOCAL_END;
900 
901   h->local_ambig  = (dpal_args *) pr_safe_malloc(sizeof(*h->local_ambig));
902   *h->local_ambig = *h->local;
903   PR_ASSERT(dpal_set_ambiguity_code_matrix(h->local_ambig));
904 
905   h->local_end_ambig = (dpal_args *) pr_safe_malloc(sizeof(*h->local_end_ambig));
906   *h->local_end_ambig = *h->local_end;
907   PR_ASSERT(dpal_set_ambiguity_code_matrix(h->local_end_ambig));
908 
909   return h;
910 }
911 
912 /* Free the dpal arg holder */
913 void
destroy_dpal_arg_holder(dpal_arg_holder * h)914 destroy_dpal_arg_holder(dpal_arg_holder *h)
915 {
916   if (NULL != h) {
917     free(h->local);
918     free(h->end);
919     free(h->local_end);
920     free(h->local_ambig);
921     free(h->local_end_ambig);
922     free(h);
923   }
924 }
925 
926 /* This is a static variable that is initialized once
927    in choose_primers().  We make this variable have
928    'file' scope, we do not have to remember to free the associated
929    storage after each call to choose_primers(). */
930 static dpal_arg_holder *dpal_arg_to_use = NULL;
931 
932 /* ============================================================ */
933 /* END functions for dpal_arg_holder                            */
934 /* ============================================================ */
935 
936 /* ============================================================ */
937 /* BEGIN functions for thal_arg_holder                           */
938 /* ============================================================ */
939 /* Create the thal arg holder */
940 thal_arg_holder *
create_thal_arg_holder(const args_for_one_oligo_or_primer * po_args)941 create_thal_arg_holder (const args_for_one_oligo_or_primer *po_args)
942 {
943 
944    thal_arg_holder *h
945      = (thal_arg_holder *) pr_safe_malloc(sizeof(thal_arg_holder));
946 
947    h->any = (thal_args *) pr_safe_malloc(sizeof(*h->any));
948    set_thal_default_args(h->any);
949    h->any->type = thal_any;
950    h->any->mv = po_args->salt_conc;
951    h->any->dv = po_args->divalent_conc;
952    h->any->dntp = po_args->dntp_conc;
953    h->any->dna_conc = po_args->dna_conc;
954 
955    h->end1 = (thal_args *) pr_safe_malloc(sizeof(*h->end1));
956    set_thal_default_args(h->end1);
957    h->end1->type = thal_end1;
958    h->end1->mv = po_args->salt_conc;
959    h->end1->dv = po_args->divalent_conc;
960    h->end1->dntp = po_args->dntp_conc;
961    h->end1->dna_conc = po_args->dna_conc;
962 
963    h->end2 = (thal_args *) pr_safe_malloc(sizeof(*h->end2));
964    set_thal_default_args(h->end2);
965    h->end2->type = thal_end2;
966    h->end2->mv = po_args->salt_conc;
967    h->end2->dv = po_args->divalent_conc;
968    h->end2->dntp = po_args->dntp_conc;
969    h->end2->dna_conc = po_args->dna_conc;
970 
971    h->hairpin_th  = (thal_args *) pr_safe_malloc(sizeof(*h->hairpin_th));
972    set_thal_default_args(h->hairpin_th);
973    h->hairpin_th->type = thal_hairpin;
974    h->hairpin_th->mv = po_args->salt_conc;
975    h->hairpin_th->dv = po_args->divalent_conc;
976    h->hairpin_th->dntp = po_args->dntp_conc;
977    h->hairpin_th->dna_conc = po_args->dna_conc;
978    h->hairpin_th->dimer = 0;
979 
980    return h;
981 }
982 
983 /* Free the thal arg holder */
984 void
destroy_thal_arg_holder(thal_arg_holder * h)985 destroy_thal_arg_holder(thal_arg_holder *h)
986 {
987   if (NULL != h) {
988     free(h->any);
989     free(h->end1);
990     free(h->end2);
991     free(h->hairpin_th);
992     free(h);
993   }
994 }
995 
996 static thal_arg_holder *thal_arg_to_use = NULL;
997 static thal_arg_holder *thal_oligo_arg_to_use = NULL;
998 /* ============================================================ */
999 /* END functions for thal_arg_holder                            */
1000 /* ============================================================ */
1001 
1002 /* Deallocate a primer3 state */
1003 void
destroy_p3retval(p3retval * state)1004 destroy_p3retval(p3retval *state)
1005 {
1006   if (!state)
1007     return;
1008 
1009   free_repeat_sim_score(state);
1010   free(state->fwd.oligo);
1011   free(state->rev.oligo);
1012   free(state->intl.oligo);
1013   if (state->best_pairs.storage_size != 0 && state->best_pairs.pairs)
1014     free(state->best_pairs.pairs);
1015 
1016   destroy_pr_append_str_data(&state->glob_err);
1017   destroy_pr_append_str_data(&state->per_sequence_err);
1018   destroy_pr_append_str_data(&state->warnings);
1019 
1020   free(state);
1021 }
1022 
1023 void
destroy_dpal_thal_arg_holder()1024 destroy_dpal_thal_arg_holder() {
1025    if(dpal_arg_to_use)
1026      destroy_dpal_arg_holder(dpal_arg_to_use);
1027    if(thal_arg_to_use)
1028      destroy_thal_arg_holder(thal_arg_to_use);
1029    if(thal_oligo_arg_to_use)
1030      destroy_thal_arg_holder(thal_oligo_arg_to_use);
1031 }
1032 
1033 const oligo_array *
p3_get_rv_fwd(const p3retval * r)1034 p3_get_rv_fwd(const p3retval *r) {
1035   return &r->fwd;
1036 }
1037 
1038 const oligo_array *
p3_get_rv_intl(const p3retval * r)1039 p3_get_rv_intl(const p3retval *r) {
1040   return &r->intl;
1041 }
1042 
1043 const oligo_array *
p3_get_rv_rev(const p3retval * r)1044 p3_get_rv_rev(const p3retval *r) {
1045   return &r->rev;
1046 }
1047 
1048 const pair_array_t *
p3_get_rv_best_pairs(const p3retval * r)1049 p3_get_rv_best_pairs(const p3retval *r) {
1050   return &r->best_pairs;
1051 }
1052 
1053 /* ============================================================ */
1054 /* END functions for p3retval                                   */
1055 /* ============================================================ */
1056 
1057 /* ============================================================ */
1058 /* BEGIN functions for seq_arg_holder                           */
1059 /* ============================================================ */
1060 
1061 /* Create and initialize a seq_args data structure */
1062 seq_args *
create_seq_arg()1063 create_seq_arg()
1064 {
1065   seq_args *r = (seq_args *) malloc(sizeof(*r));
1066   if (NULL == r) return NULL; /* Out of memory */
1067   memset(r, 0, sizeof(*r));
1068   r->start_codon_pos = PR_DEFAULT_START_CODON_POS;
1069   r->incl_l = -1; /* Indicates logical NULL. */
1070 
1071   r->force_left_start = PR_NULL_FORCE_POSITION; /* Indicates logical NULL. */
1072   r->force_left_end = PR_NULL_FORCE_POSITION; /* Indicates logical NULL. */
1073   r->force_right_start = PR_NULL_FORCE_POSITION; /* Indicates logical NULL. */
1074   r->force_right_end = PR_NULL_FORCE_POSITION; /* Indicates logical NULL. */
1075   r->primer_overlap_junctions_count = 0;
1076 
1077   r->n_quality = 0;
1078   r->quality = NULL;
1079 
1080   return r;
1081 }
1082 
1083 /* Free a seq_arg data structure */
1084 void
destroy_seq_args(seq_args * sa)1085 destroy_seq_args(seq_args *sa)
1086 {
1087   if (NULL == sa) return;
1088   free(sa->internal_input);
1089   free(sa->left_input);
1090   free(sa->right_input);
1091   free(sa->sequence);
1092   free(sa->quality);
1093   free(sa->trimmed_seq);
1094 
1095   /* edited by T. Koressaar for lowercase masking */
1096   free(sa->trimmed_orig_seq);
1097 
1098   free(sa->upcased_seq);
1099   free(sa->upcased_seq_r);
1100   free(sa->sequence_name);
1101   free(sa);
1102 }
1103 
1104 /* ============================================================ */
1105 /* END functions for seq_arg_holder                             */
1106 /* ============================================================ */
1107 
1108 
1109 /* Function used to de-allocate the memory used by the hash maps
1110    allocated in choose_pair_or_triple. */
free_pair_memory(int rev_num_elem)1111 static void free_pair_memory(int rev_num_elem)
1112 {
1113   std::hash_map<int, primer_pair*> *hmap;
1114   std::hash_map<int, primer_pair*>::iterator it;
1115   primer_pair *pp;
1116   int i;
1117 
1118   free(max_j_seen);
1119   for (i=0; i<rev_num_elem; i++) {
1120     hmap = pairs[i];
1121     if (hmap) {
1122       for (it=hmap->begin(); it!=hmap->end(); it++) {
1123         pp = it->second;
1124         if (pp != NULL)
1125 	  delete pp;
1126       }
1127       delete hmap;
1128     }
1129   }
1130   free(pairs);
1131 }
1132 
1133 
1134 /* ============================================================ */
1135 /* BEGIN choose_primers()                                       */
1136 /* The main primer3 interface                                   */
1137 /* See libprimer3.h for documentation.                          */
1138 /* ============================================================ */
1139 p3retval *
choose_primers(const p3_global_settings * pa,seq_args * sa)1140 choose_primers(const p3_global_settings *pa,
1141                seq_args *sa)
1142 {
1143   /* Create retval and set were to find the results */
1144   p3retval *retval = create_p3retval();
1145   if (retval == NULL)  return NULL;
1146 
1147   PR_ASSERT(NULL != pa);
1148   PR_ASSERT(NULL != sa);
1149 
1150   if (pa->dump) {
1151     printf("Start of choose_primers:\n");
1152     p3_print_args(pa, sa) ;
1153   }
1154 
1155   /* Set the general output type */
1156   if (pa->pick_left_primer && pa->pick_right_primer) {
1157     retval->output_type = primer_pairs;
1158   } else {
1159     retval->output_type = primer_list;
1160   }
1161   if (pa->primer_task == pick_primer_list ||
1162       pa->primer_task == pick_sequencing_primers) {
1163     retval->output_type = primer_list;
1164   }
1165 
1166   /*
1167    * For catching ENOMEM.  WARNING: We can only use longjmp to escape
1168    * from errors that have been called through choose_primers().
1169    * Therefore, if we subsequently update other static functions in
1170    * this file to have external linkage then we need to check whether
1171    * they call (or use functions that in turn call) longjmp to handle
1172    * ENOMEM.
1173    */
1174   if (setjmp(_jmp_buf) != 0) {
1175     /* Check if this was a thermodynamic alignment length error. */
1176     if (thermodynamic_alignment_length_error == 1) {
1177       thermodynamic_alignment_length_error = 0;
1178       /* Set per sequence error */
1179       pr_append_new_chunk(&retval->per_sequence_err,
1180 			  thermodynamic_alignment_length_error_msg);
1181       free(thermodynamic_alignment_length_error_msg);
1182       thermodynamic_alignment_length_error_msg = NULL;
1183       /* Other necessary cleanup. */
1184       free_pair_memory(retval->rev.num_elem);
1185       return retval;
1186     }
1187     /* This was a memory error. */
1188     destroy_p3retval(retval);
1189     return NULL;  /* If we get here, that means errno should be ENOMEM. */
1190   }
1191 
1192   /* Change some parameters to fit the task */
1193   _adjust_seq_args(pa, sa, &retval->per_sequence_err,&retval->warnings);
1194 
1195   if (pa->dump) {
1196     printf("After _adjust_seq_args\n");
1197     p3_print_args(pa, sa) ;
1198   }
1199 
1200   if (!pr_is_empty(&retval->per_sequence_err)) return retval;
1201 
1202   /* TO DO -- move the check below to pr_data_control and issue a
1203      warning if it fails. */
1204   /* if (pa->p_args.min_quality != 0
1205      && pa->p_args.min_end_quality < pa->p_args.min_quality)
1206        ... issue warning ...
1207      pa->p_args.min_end_quality = pa->p_args.min_quality; */
1208 
1209   /* Check if the input in sa and pa makes sense */
1210   if (_pr_data_control(pa, sa,
1211                        &retval->glob_err,  /* Fatal errors */
1212                        &retval->per_sequence_err, /* Non-fatal errors */
1213                        &retval->warnings
1214                        ) !=0 ) {
1215     return retval;
1216   }
1217 
1218 
1219   set_retval_both_stop_codons(sa, retval);
1220 
1221   /* Set the parameters for alignment functions
1222      if dpal_arg_to_use, a static variable that has 'file'
1223      scope, has not yet been initialized. */
1224   if (dpal_arg_to_use == NULL)
1225     dpal_arg_to_use = create_dpal_arg_holder();
1226    if(thal_arg_to_use == NULL) {
1227       thal_arg_to_use = create_thal_arg_holder(&pa->p_args);
1228    } else {
1229       destroy_thal_arg_holder(thal_arg_to_use);
1230       thal_arg_to_use = create_thal_arg_holder(&pa->p_args);
1231    }
1232    if(thal_oligo_arg_to_use == NULL) {
1233       thal_oligo_arg_to_use = create_thal_arg_holder(&pa->o_args);
1234    } else {
1235       destroy_thal_arg_holder(thal_oligo_arg_to_use);
1236       thal_oligo_arg_to_use = create_thal_arg_holder(&pa->o_args);
1237    }
1238   if (pa->primer_task == pick_primer_list) {
1239     make_complete_primer_lists(retval, pa, sa,
1240                                dpal_arg_to_use,thal_arg_to_use,thal_oligo_arg_to_use);
1241   } else if (pa->primer_task == pick_sequencing_primers) {
1242     pick_sequencing_primer_list(retval, pa, sa,
1243                                 dpal_arg_to_use,thal_arg_to_use);
1244   } else if (pa->primer_task == check_primers) {
1245     add_primers_to_check(retval, pa, sa,
1246                          dpal_arg_to_use, thal_arg_to_use, thal_oligo_arg_to_use);
1247   } else { /* The general way to pick primers */
1248     /* Populate the forward and reverse primer lists */
1249     if (make_detection_primer_lists(retval, pa, sa,
1250                                     dpal_arg_to_use,thal_arg_to_use) != 0) {
1251       /* There was an error */
1252       return retval;
1253     }
1254     /* Populate the internal oligo lists */
1255     if ( pa->pick_internal_oligo) {
1256       if (make_internal_oligo_list(retval, pa, sa,
1257                                    dpal_arg_to_use,thal_oligo_arg_to_use) != 0) {
1258         /* There was an error*/
1259         return retval;
1260       }
1261     }
1262   }
1263 
1264   if (pa->pick_right_primer &&
1265       (pa->primer_task != pick_sequencing_primers))
1266     sort_primer_array(&retval->rev);
1267 
1268   if (pa->pick_left_primer &&
1269       (pa->primer_task != pick_sequencing_primers))
1270     sort_primer_array(&retval->fwd);
1271 
1272   /* If we are returning a list of internal oligos, sort them by their
1273      'goodness'. We do not care if these are sorted if we end up in
1274      choose_pair_or_triple(), since this calls
1275      choose_internal_oligo(), which selects the best internal oligo
1276      for a given primer pair. */
1277   if (retval->output_type == primer_list && pa->pick_internal_oligo == 1)
1278     sort_primer_array(&retval->intl);
1279 
1280   /* Select primer pairs if needed */
1281   if (retval->output_type == primer_pairs) {
1282     choose_pair_or_triple(retval, pa, sa, dpal_arg_to_use, thal_arg_to_use,
1283        thal_oligo_arg_to_use, &retval->best_pairs);
1284   }
1285 
1286   if (pa->dump) {
1287     printf("End of choose_primers:\n");
1288     p3_print_args(pa, sa) ;
1289   }
1290 
1291   return retval;
1292 }
1293 /* ============================================================ */
1294 /* END choose_primers()                                         */
1295 /* ============================================================ */
1296 
1297 /* ============================================================ */
1298 /* BEGIN choose_pair_or_triple
1299 
1300    This function uses retval->fwd and retval->rev and
1301    updates the oligos in these array.
1302 
1303    This function posibly uses retval->intl and updates its
1304    elements via choose_internal_oligo().
1305 
1306    This function examines primer pairs or triples to find
1307    pa->num_return pairs or triples to return.
1308 
1309    Results are returned in best_pairs and in
1310    retval->best_pairs.expl */
1311 /* ============================================================ */
1312 static void
choose_pair_or_triple(p3retval * retval,const p3_global_settings * pa,const seq_args * sa,const dpal_arg_holder * dpal_arg_to_use,const thal_arg_holder * thal_arg_to_use,const thal_arg_holder * thal_oligo_arg_to_use,pair_array_t * best_pairs)1313 choose_pair_or_triple(p3retval *retval,
1314                       const p3_global_settings *pa,
1315                       const seq_args *sa,
1316                       const dpal_arg_holder *dpal_arg_to_use,
1317                       const thal_arg_holder *thal_arg_to_use,
1318 		      const thal_arg_holder *thal_oligo_arg_to_use,
1319                       pair_array_t *best_pairs) {
1320   int i,j;   /* Loop index. */
1321   int n_int; /* Index of the internal oligo */
1322   /*int *max_j_seen; */  /* The maximum value of j (loop index for forward primers)
1323                             that has been examined for every reverse primer
1324                             index (i) -- global variable now */
1325   int update_stats = 1;  /* Flag to indicate whether pair_stats
1326                             should be updated. */
1327   primer_pair h;             /* The current pair which is being evaluated. */
1328   primer_pair the_best_pair; /* The best pair is being "remembered". */
1329   pair_stats *pair_expl = &retval->best_pairs.expl; /* For statistics */
1330 
1331   int product_size_range_index = 0;
1332   int trace_me = 0;
1333   int the_best_i, the_best_j;
1334 
1335   /* Hash maps used to store pairs that were computed */
1336 
1337   /* std::hash_map<int, primer_pair*> **pairs; */
1338   /* pairs is an array of pointers to hash maps.  It will be indexed
1339      by the indices of the reverse primers in retval->rev. -- global var now */
1340 
1341   std::hash_map<int, primer_pair*> *hmap, *best_hmap = NULL;
1342   /* hmap and best_hmap will be pointers to hash maps also pointed to
1343      by elements of pairs. */
1344 
1345   std::hash_map<int, primer_pair*>::iterator it;
1346   primer_pair *pp, *best_pp = NULL;
1347   int pair_found = 0;
1348 
1349   pairs =
1350     (std::hash_map<int, primer_pair*>**)
1351     calloc (retval->rev.num_elem,
1352 	    sizeof(std::hash_map<int, primer_pair*>*));
1353   if (!pairs) longjmp(_jmp_buf, 1);
1354 
1355   memset(&the_best_pair, 0, sizeof(the_best_pair));
1356   max_j_seen = (int *) malloc(sizeof(int) * retval->rev.num_elem);
1357   for (i = 0; i < retval->rev.num_elem; i++) max_j_seen[i] = -1;
1358 
1359   /* Pick pairs till we have enough. */
1360   while(1) {
1361 
1362     /* FIX ME, is this memset really needed?  Apparently slow */
1363     memset(&the_best_pair, 0, sizeof(the_best_pair));
1364 
1365     the_best_i = -1;
1366     the_best_j = -1;
1367     /* To start put penalty to the maximum */
1368     the_best_pair.pair_quality = DBL_MAX;
1369 
1370     /* Iterate over the reverse primers. */
1371     for (i = 0; i < retval->rev.num_elem; i++) {
1372 
1373       hmap = pairs[i];
1374       /* Pairs[i] is NULL if there has never been an assignment to
1375 	 pairs[i] because pairs was allocated by calloc, which
1376 	 sets the allocated memory to 0. */
1377 
1378       /* Only use a primer that *might be* legal or that the caller
1379          has provided and specified as "must use".  Primers are *NOT*
1380          FULLY ASSESSED until the call to characterize_pair(), in
1381          order to avoid expensive computations (mostly alignments)
1382          unless necessary. */
1383       if (!OK_OR_MUST_USE(&retval->rev.oligo[i])) {
1384         /* Can free the memory used by the hmap associated to this
1385 	   reverse primer */
1386         if (hmap) {
1387           for (it=hmap->begin(); it!=hmap->end(); it++) {
1388 	    /* it->second is the second element (i.e. the 'value', as
1389 	       opposed to the 'key'). */
1390             pp = it->second;
1391             delete pp;
1392           }
1393 	  if (hmap == best_hmap) best_hmap = NULL;
1394           delete hmap;
1395 	  hmap = NULL;
1396           pairs[i] = NULL;
1397         }
1398         continue;
1399       }
1400 
1401       /* If the pair cannot be better than the one already
1402        * selected, then we can skip remaining reverse primers */
1403       if (pa->pr_pair_weights.primer_quality *
1404            (retval->rev.oligo[i].quality + retval->fwd.oligo[0].quality)
1405               > the_best_pair.pair_quality) {
1406         break;
1407       }
1408 
1409       if (retval->rev.oligo[i].overlaps) {
1410         /* The stats will not keep track of the pair correctly
1411            after the first pass, because an oligo might
1412            have been legal on one pass but become illegal on
1413            a subsequent pass. */
1414         if (update_stats) {
1415           if (trace_me)
1416             fprintf(stderr,
1417                     "i=%d, j=%d, overlaps_oligo_in_better_pair++\n",
1418                     i, j);
1419           pair_expl->overlaps_oligo_in_better_pair++;
1420         }
1421         /* Can free the memory used by the hmap associated to this reverse primer */
1422         if (hmap) {
1423           for (it=hmap->begin(); it!=hmap->end(); it++) {
1424 	    /* it->second is the second element (i.e. the 'value', as
1425 	       opposed to the 'key'). */
1426             pp = it->second;
1427             delete pp;
1428           }
1429 	  if (hmap == best_hmap) best_hmap = NULL;
1430           delete hmap;
1431 	  hmap = NULL;
1432           pairs[i] = NULL;
1433         }
1434         continue;
1435       }
1436 
1437       /* Loop over forward primers */
1438       for (j=0; j<retval->fwd.num_elem; j++) {
1439 
1440         /* We check the reverse oligo again, because we may
1441            have determined that it is "not ok", even though
1442            (as a far as we knew), it was ok above. */
1443         if (!OK_OR_MUST_USE(&retval->rev.oligo[i])) {
1444           /* Can free the memory used by the hmap associated to this reverse primer */
1445           if (hmap) {
1446             for (it=hmap->begin(); it!=hmap->end(); it++) {
1447 	      /* it->second is the second element (i.e. the 'value', as
1448 		 opposed to the 'key'). */
1449               pp = it->second;
1450               delete pp;
1451             }
1452 	    if (hmap == best_hmap) best_hmap = NULL;
1453 	    delete hmap;
1454 	    hmap = NULL;
1455             pairs[i] = NULL;
1456           }
1457           break;
1458         }
1459 
1460         /* Only use a primer that is legal, or that the caller
1461            has provided and specified as "must use". */
1462         if (!OK_OR_MUST_USE(&retval->fwd.oligo[j])) continue;
1463 
1464         /* If the pair cannot be better than the one already
1465          * selected, then we can skip remaining forward primers
1466          * for this reverse primer */
1467         if (pa->pr_pair_weights.primer_quality *
1468             (retval->fwd.oligo[j].quality + retval->rev.oligo[i].quality)
1469             > the_best_pair.pair_quality) {
1470           break;
1471         }
1472 
1473         /* Need to have this here because if we break just above, then,
1474            at a later iteration, we may need to examine the oligo
1475            pair with reverse oligo at i and forward oligo at j. */
1476         update_stats = 0;
1477         if (j > max_j_seen[i]) {
1478           if (trace_me)
1479             fprintf(stderr,
1480 		    "updates ON: i=%d, j=%d, max_j_seen[%d]=%d\n",
1481 		    i, j, i, max_j_seen[i]);
1482           max_j_seen[i] = j;
1483           if (trace_me)
1484             fprintf(stderr, "max_j_seen[%d] --> %d\n", i, max_j_seen[i]);
1485           if (trace_me) fprintf(stderr, "updates on\n");
1486           update_stats = 1;
1487         }
1488 
1489         if (retval->fwd.oligo[j].overlaps) {
1490           /* The stats will not keep track of the pair correctly
1491              after the first pass, because an oligo might
1492              have been legal on one pass but become illegal on
1493              a subsequent pass. */
1494           if (update_stats) {
1495             if (trace_me)
1496               fprintf(stderr,
1497                       "i=%d, j=%d, overlaps_oligo_in_better_pair++\n",
1498                       i, j);
1499             pair_expl->overlaps_oligo_in_better_pair++;
1500           }
1501           continue;
1502         }
1503 
1504 	/* Some simple checks first, before searching the hashmap */
1505 	int must_use = 0;
1506 	if ((pa->primer_task == check_primers) ||
1507 	    ((retval->fwd.oligo[j].must_use != 0) &&
1508 	     (retval->rev.oligo[i].must_use != 0))) {
1509 	  must_use = 1;
1510 	}
1511 
1512 	/* Determine if overlap with an overlap point is required, and
1513 	   if so, whether one of the primers in the pairs overlaps
1514 	   that point. */
1515 	if ((sa->primer_overlap_junctions_count > 0)
1516 	    && !(retval->rev.oligo[i].overlaps_overlap_position
1517 		 || retval->fwd.oligo[j].overlaps_overlap_position)
1518 	    ) {
1519 	  if (update_stats) {
1520 	    pair_expl->considered++;
1521 	    pair_expl->does_not_overlap_a_required_point++;
1522 	  }
1523 	  if (!must_use) continue;
1524 	}
1525 
1526 	/* Check product size now */
1527 	double product_size
1528 	  = retval->rev.oligo[i].start - retval->fwd.oligo[j].start+1;
1529 
1530 	if (product_size < pa->pr_min[product_size_range_index] ||
1531 	    product_size > pa->pr_max[product_size_range_index]) {
1532 	  if (update_stats) {
1533 	    /* This line NEW */ if (!must_use)
1534 	                           pair_expl->considered++;
1535 	    pair_expl->product++;
1536 	  }
1537 	  if (!must_use) continue;
1538 	}
1539 
1540         /* Check if pair was already computed */
1541         pair_found = 0;
1542         if (hmap) {
1543           it = hmap->find(j);
1544           if (it != hmap->end()) {
1545             pair_found = 1;
1546 
1547 	    /* it->second is the second element (i.e. the 'value', as
1548 	       opposed to the 'key'). */
1549             pp = it->second;
1550             if (pp) {
1551 	      /* The pair was computed, it isn't illegal and it wasn't
1552 		 selected yet */
1553 	      if (update_stats) {
1554 		pair_expl->considered++;
1555 		if (trace_me)
1556 		  fprintf(stderr, "ok++\n");
1557 		pair_expl->ok++;
1558 	      }
1559 	      /* Check if this is a better pair */
1560 	      if (compare_primer_pair(pp, &the_best_pair) < 0) {
1561 		the_best_pair = *pp;
1562 		the_best_i = i;
1563 		the_best_j = j;
1564 		best_hmap = hmap;
1565 		best_pp = pp;
1566 	      }
1567 
1568 	      /* There cannot be a better pair */
1569 	      if (the_best_pair.pair_quality == 0) {
1570 		break;
1571 	      }
1572             } /* else - pp is NULL - it's illegal or already selected */
1573           }
1574         } else {
1575           /* Create this hashmap */
1576           hmap = new std::hash_map<int, primer_pair*>;
1577           if (!hmap)
1578             longjmp(_jmp_buf, 1);
1579           pairs[i] = hmap;
1580         }
1581 
1582         if (!pair_found) {
1583           /* Characterize the pair. h is initialized by this
1584              call. */
1585           int tmp =
1586 	    characterize_pair(retval, pa, sa, j, i,
1587 			      product_size_range_index,
1588 			      &h, dpal_arg_to_use,
1589 			      thal_arg_to_use,
1590 			      update_stats);
1591           if (tmp == PAIR_OK) {
1592 
1593             /* Choose internal oligo if needed */
1594             if (pa->pick_right_primer && pa->pick_left_primer
1595                 && pa->pick_internal_oligo) {
1596               if (choose_internal_oligo(retval, h.left, h.right,
1597                                         &n_int, sa, pa,
1598                                         dpal_arg_to_use, thal_oligo_arg_to_use)!=0) {
1599 
1600                 /* We were UNable to choose an internal oligo. */
1601                 if (update_stats) {
1602                   pair_expl->internal++;
1603                 }
1604 
1605                 /* Mark the pair as not good - the entry in the hash
1606 		   map will be a NULL */
1607                 (*hmap)[j] = NULL;
1608                 continue;
1609               } else {
1610                 /* We DID choose an internal oligo, and we
1611                    set h.intl to point to it. */
1612                 h.intl = &retval->intl.oligo[n_int];
1613               }
1614             }
1615 
1616             if (update_stats) {
1617               if (trace_me)
1618                 fprintf(stderr, "ok++\n");
1619               pair_expl->ok++;
1620             }
1621 
1622             /* Calculate the pair penalty */
1623             h.pair_quality = obj_fn(pa, &h);
1624             PR_ASSERT(h.pair_quality >= 0.0);
1625 
1626             /* Save the pair */
1627             pp = new primer_pair;
1628             if (!pp)
1629               longjmp(_jmp_buf, 1);
1630             *pp = h;
1631             (*hmap)[j] = pp;
1632 
1633             /* The current pair (h) is the new best pair if it is
1634 	       better than the best pair so far. */
1635             if (compare_primer_pair(&h, &the_best_pair) < 0) {
1636               the_best_pair = h;
1637               the_best_i = i;
1638               the_best_j = j;
1639               best_hmap = hmap;
1640               best_pp = pp;
1641             }
1642 
1643             /* There cannot be a better pair */
1644             if (the_best_pair.pair_quality == 0) {
1645               break;
1646             }
1647           } else if (tmp == PAIR_FAILED) {
1648             /* Illegal pair */
1649             (*hmap)[j] = NULL;
1650           }
1651         }
1652       }  /* for (j=0; j<retval->fwd.num_elem; j++) -- inner loop */
1653 
1654       /* Check if there cannot be a better pair than best found */
1655       if (the_best_pair.pair_quality == 0) {
1656         break;
1657       }
1658 
1659     } /* for (i = 0; i < retval->rev.num_elem; i++) --- outer loop */
1660 
1661     if (the_best_pair.pair_quality == DBL_MAX){
1662       /* No pair was found. Try another product-size-range,
1663        if one exists. */
1664 
1665       product_size_range_index++;
1666       /* Re-set the high-water marks for the indices
1667          for reverse and forward primers:  */
1668       for (i = 0; i < retval->rev.num_elem; i++) max_j_seen[i] = -1;
1669 
1670       if (!(product_size_range_index < pa->num_intervals)) {
1671         /* We ran out of product-size-ranges. Exit the while loop. */
1672         break;
1673 
1674         /* Our bookkeeping was incorrect unless the assertion below is
1675 	   true. If num_intervals > 1 or min_three_*_prime_distance >
1676 	   -1 the assertion below might not be true. */
1677         PR_ASSERT(!((pa->num_intervals == 1) &&
1678 		    ((pa->min_left_three_prime_distance == -1) ||
1679 		     (pa->min_right_three_prime_distance == -1)))
1680                   || (best_pairs->num_pairs == pair_expl->ok));
1681       }
1682 
1683     } else {
1684       /* Store the best primer for output */
1685 
1686       if (trace_me)
1687         fprintf(stderr, "ADD pair i=%d, j=%d\n", the_best_i, the_best_j);
1688 
1689       add_pair(&the_best_pair, best_pairs);
1690 
1691       /* Mark the pair as already selected */
1692       delete best_pp;
1693       (*best_hmap)[the_best_j] = NULL;
1694 
1695       /* Update the overlaps flags */
1696       for (i = 0; i < retval->rev.num_elem; i++) {
1697 	if (right_oligo_in_pair_overlaps_used_oligo(&retval->rev.oligo[i],
1698 						    &the_best_pair,
1699 						    pa->min_right_three_prime_distance)) {
1700 	  retval->rev.oligo[i].overlaps = 1;
1701 	}
1702       }
1703       for (j = 0; j < retval->fwd.num_elem; j++) {
1704 	if (left_oligo_in_pair_overlaps_used_oligo(&retval->fwd.oligo[j],
1705 						   &the_best_pair,
1706 						   pa->min_left_three_prime_distance)) {
1707 	  retval->fwd.oligo[j].overlaps = 1;
1708 	}
1709       }
1710 
1711       /* If we have enough then stop the while loop */
1712       if (pa->num_return == best_pairs->num_pairs) {
1713         break;
1714       }
1715     }
1716   } /* end of while(continue_trying == 1) */
1717 
1718   /* Final cleanup of dynamically allocated storage for this
1719      function. */
1720   free_pair_memory(retval->rev.num_elem);
1721 }
1722 /* ============================================================ */
1723 /* END choose_pair_or_triple                                    */
1724 /* ============================================================ */
1725 
1726 /* ============================================================ */
1727 /* BEGIN choose_internal_oligo */
1728 /* Choose best internal oligo for given pair of left and right
1729    primers. */
1730 /* ============================================================ */
1731 static int
choose_internal_oligo(p3retval * retval,const primer_rec * left,const primer_rec * right,int * nm,const seq_args * sa,const p3_global_settings * pa,const dpal_arg_holder * dpal_arg_to_use,const thal_arg_holder * thal_arg_to_use)1732 choose_internal_oligo(p3retval *retval,
1733                       const primer_rec *left,
1734                       const primer_rec *right,
1735                       int *nm,
1736                       const seq_args *sa,
1737                       const p3_global_settings *pa,
1738                       const dpal_arg_holder *dpal_arg_to_use,
1739                       const thal_arg_holder *thal_arg_to_use
1740                       )
1741 {
1742   int i,k;
1743   double min;
1744   char oligo_seq[MAX_PRIMER_LENGTH+1], revc_oligo_seq[MAX_PRIMER_LENGTH+1];
1745   primer_rec *h;
1746   min = 1000000.;
1747   i = -1;
1748 
1749   for (k=0; k < retval->intl.num_elem; k++) {
1750     h = &retval->intl.oligo[k];  /* h is the record for the oligo currently
1751                                     under consideration */
1752 
1753     if ((h->start > (left->start + (left->length-1)))
1754         && ((h->start + (h->length-1))
1755             < (right->start-right->length+1))
1756         && (h->quality < min)
1757         && (OK_OR_MUST_USE(h))) {
1758 
1759       if (h->self_any == ALIGN_SCORE_UNDEF && pa->thermodynamic_oligo_alignment==0) {
1760 
1761         _pr_substr(sa->trimmed_seq, h->start, h->length, oligo_seq);
1762         p3_reverse_complement(oligo_seq, revc_oligo_seq);
1763 
1764         oligo_compl(h, &pa->o_args, &retval->intl.expl,
1765                     dpal_arg_to_use, oligo_seq, revc_oligo_seq);
1766         if (!OK_OR_MUST_USE(h)) continue;
1767       }
1768 
1769       if (h->self_any == ALIGN_SCORE_UNDEF && pa->thermodynamic_oligo_alignment==1) {
1770         _pr_substr(sa->trimmed_seq, h->start, h->length, oligo_seq);
1771 	p3_reverse_complement(oligo_seq, revc_oligo_seq);
1772 
1773         oligo_compl_thermod(h, &pa->o_args, &retval->intl.expl,
1774                             thal_oligo_arg_to_use, oligo_seq, oligo_seq);
1775         if (!OK_OR_MUST_USE(h)) continue;
1776       }
1777       if(h->hairpin_th == ALIGN_SCORE_UNDEF && pa->thermodynamic_oligo_alignment==1) {
1778 	_pr_substr(sa->trimmed_seq, h->start, h->length, oligo_seq);
1779 	oligo_hairpin(h, &pa->o_args,
1780                       &retval->intl.expl, thal_oligo_arg_to_use,
1781                       oligo_seq);
1782         if (!OK_OR_MUST_USE(h)) continue;
1783       }
1784 
1785       if (h->repeat_sim.score == NULL) {
1786         oligo_repeat_library_mispriming(h, pa, sa, OT_INTL, &retval->intl.expl,
1787                                         dpal_arg_to_use);
1788         if (!OK_OR_MUST_USE(h)) continue;
1789       }
1790 
1791       min = h->quality;
1792       i=k;
1793 
1794     } /* if ((h->start.... */
1795 
1796   }  /* for (k=0;..... */
1797 
1798   *nm = i;
1799   if(*nm < 0) return 1;
1800   return 0;
1801 }
1802 /* ============================================================ */
1803 /* END choose_internal_oligo */
1804 /* ============================================================ */
1805 
1806 
1807 
1808 /*
1809    Translate the values in the stats struct into an warning string.
1810    Call this function only if the 'stat's contains the _errors_
1811    associated with a given primer i.e. that primer was supplied by the
1812    caller and pick_anyway is set.
1813 */
1814 void
add_must_use_warnings(pr_append_str * warning,const char * text,const oligo_stats * stats)1815 add_must_use_warnings(pr_append_str *warning,
1816                       const char* text,
1817                       const oligo_stats *stats)
1818 {
1819   const char *sep = "/";
1820   pr_append_str s;
1821 
1822   s.data = NULL;
1823   s.storage_size = 0;
1824 
1825   if (stats->size_min) pr_append_w_sep(&s, sep, "Too short");
1826   if (stats->size_max) pr_append_w_sep(&s, sep, "Too long");
1827   if (stats->ns) pr_append_w_sep(&s, sep, "Too many Ns");
1828   if (stats->target) pr_append_w_sep(&s, sep, "Overlaps Target");
1829   if (stats->excluded) pr_append_w_sep(&s, sep, "Overlaps Excluded Region");
1830   if (stats->gc) pr_append_w_sep(&s, sep, "Unacceptable GC content");
1831   if (stats->gc_clamp) pr_append_w_sep(&s, sep, "No GC clamp");
1832   if (stats->temp_min) pr_append_w_sep(&s, sep, "Tm too low");
1833   if (stats->temp_max) pr_append_w_sep(&s, sep, "Tm too high");
1834   if (stats->compl_any) pr_append_w_sep(&s, sep, "High self complementarity");
1835   if (stats->compl_end)
1836     pr_append_w_sep(&s, sep, "High end self complementarity");
1837   if (stats->hairpin_th) pr_append_w_sep(&s, sep, "High hairpin stability (thermod. approach)");
1838   if (stats->repeat_score)
1839     pr_append_w_sep(&s, sep, "High similarity to mispriming or mishyb library");
1840   if (stats->poly_x) pr_append_w_sep(&s, sep, "Long poly-X");
1841   if (stats->seq_quality) pr_append_w_sep(&s, sep, "Low sequence quality");
1842   if (stats->stability) pr_append_w_sep(&s, sep, "High 3' stability");
1843   if (stats->no_orf) pr_append_w_sep(&s, sep, "Would not amplify any ORF");
1844   if (stats->not_in_any_left_ok_region) pr_append_w_sep(&s, sep, "Not in any ok left region");
1845   if (stats->not_in_any_right_ok_region) pr_append_w_sep(&s, sep, "Not in any ok right region");
1846 
1847   /* edited by T. Koressaar for lowercase masking: */
1848   if (stats->gmasked)
1849     pr_append_w_sep(&s, sep, "Masked with lowercase letter");
1850 
1851   if (stats->must_match_fail)
1852     pr_append_w_sep(&s, sep, "Failed must_match requirements");
1853 
1854   if (s.data) {
1855     pr_append_new_chunk(warning, text);
1856     pr_append(warning, " is unacceptable: ");
1857     pr_append(warning, s.data);
1858     free(s.data);
1859   }
1860 }
1861 
1862 /*
1863    Also see the documentation in librimer3.h,
1864    p3_global_settings.min_{left/right_}three_prime_distance.
1865 
1866    If min_dist == -1, return 0
1867 
1868    If min_dist ==  0:
1869      Return 1 if the left or the right
1870      primer is identical to the left or right
1871      primer (respectively) in best_pair.
1872 
1873      Otherwise return 0.
1874 
1875    If min_dist > 0:
1876      Return 1 if EITHER:
1877      (1) The 3' end of the left primer in pair is
1878          < min_dist from the 3' end of the left primer
1879          in best_pair
1880      OR
1881      (2) The 3' end of the right primer in pair is
1882          < min_dist from the 3' end of the right primer
1883          in best_pair
1884 
1885 */
1886 
1887 static int
right_oligo_in_pair_overlaps_used_oligo(const primer_rec * right,const primer_pair * best_pair,int min_dist)1888 right_oligo_in_pair_overlaps_used_oligo(const primer_rec *right,
1889                                         const primer_pair *best_pair,
1890                                         int min_dist)
1891 {
1892   int best_pos, pair_pos;
1893 
1894   if (min_dist == -1)
1895     return 0;
1896 
1897   best_pos = best_pair->right->start - best_pair->right->length + 1;
1898 
1899   pair_pos = right->start - right->length + 1;
1900 
1901   if ((abs(best_pos - pair_pos) < min_dist)
1902       && (min_dist != 0)) { return 1; }
1903 
1904   if ((best_pair->right->length == right->length)
1905       && (best_pair->right->start == right->start)
1906       && (min_dist == 0)) {
1907     return 1;
1908   }
1909 
1910   return 0;
1911 }
1912 
1913 static int
left_oligo_in_pair_overlaps_used_oligo(const primer_rec * left,const primer_pair * best_pair,int min_dist)1914 left_oligo_in_pair_overlaps_used_oligo(const primer_rec *left,
1915                                        const primer_pair *best_pair,
1916                                        int min_dist)
1917 {
1918   int best_pos, pair_pos;
1919 
1920   if (min_dist == -1)
1921     return 0;
1922 
1923   best_pos =  best_pair->left->start + best_pair->left->length - 1;
1924 
1925   pair_pos = left->start + left->length -  1;
1926 
1927   if ((abs(best_pos - pair_pos) < min_dist)
1928       && (min_dist != 0)) { return 1; }
1929 
1930   if ((best_pair->left->length == left->length)
1931       && (best_pair->left->start == left->start)
1932       && (min_dist == 0)) {
1933     return 1;
1934   }
1935 
1936   return 0;
1937 }
1938 
1939 /* Add 'pair' to 'retpair'; always appends. */
1940 static void
add_pair(const primer_pair * pair,pair_array_t * retpair)1941 add_pair(const primer_pair *pair,
1942          pair_array_t *retpair)
1943 {
1944   /* If array is not initialised, initialise it with the size of pairs
1945      to return */
1946   if (0 == retpair->storage_size) {
1947     retpair->storage_size = INITIAL_NUM_RETURN;
1948     retpair->pairs
1949       = (primer_pair *)
1950       pr_safe_malloc(retpair->storage_size * sizeof(*retpair->pairs));
1951   } else {
1952     if (retpair->storage_size == retpair->num_pairs) {
1953       /* We need more space, so realloc double the space*/
1954       retpair->storage_size *= 2;
1955       retpair->pairs
1956         = (primer_pair *)
1957         pr_safe_realloc(retpair->pairs,
1958                         retpair->storage_size * sizeof(*retpair->pairs));
1959     }
1960   }
1961   /* Copy the pair into the storage place */
1962   retpair->pairs[retpair->num_pairs] = *pair;
1963   retpair->num_pairs++;
1964 }
1965 
1966 /*
1967  * Make lists of acceptable left and right primers.  After return, the
1968  * lists are stored in retval->fwd.oligo and retval->rev.oligo and the
1969  * coresponding list sizes are stored in retval->fwd.num_elem and
1970  * retval->rev.num_elem.  Return 1 if one of lists is empty or if
1971  * leftmost left primer and rightmost right primer do not provide
1972  * sufficient product size.
1973  */
1974 static int
make_detection_primer_lists(p3retval * retval,const p3_global_settings * pa,const seq_args * sa,const dpal_arg_holder * dpal_arg_to_use,const thal_arg_holder * thal_arg_to_use)1975 make_detection_primer_lists(p3retval *retval,
1976                             const p3_global_settings *pa,
1977                             const seq_args *sa,
1978                             const dpal_arg_holder *dpal_arg_to_use,
1979                             const thal_arg_holder *thal_arg_to_use)
1980 {
1981   int left, right;
1982   int length, start;
1983   int i,n,/*k,*/ pr_min;
1984   int tar_l, tar_r, f_b, r_b;
1985   pair_stats *pair_expl = &retval->best_pairs.expl; /* To store the statistics for pairs */
1986 
1987   /* Var to save the very left and very right primer */
1988   left = right = 0;
1989 
1990   /* Set pr_min to the very smallest
1991      allowable product size. */
1992   pr_min = INT_MAX;
1993   for (i=0; i < pa->num_intervals; i++)
1994     if(pa->pr_min[i] < pr_min)
1995       pr_min = pa->pr_min[i];
1996 
1997   /* Get the length of the sequence */
1998   PR_ASSERT(INT_MAX > (n=strlen(sa->trimmed_seq)));
1999 
2000   tar_r = 0; /* Target start position */
2001   tar_l = n; /* Target length */
2002 
2003   /* Iterate over target array */
2004   for (i=0; i < sa->tar2.count; i++) {
2005 
2006     /* Select the rightmost target start */
2007     if (sa->tar2.pairs[i][0] > tar_r)
2008       tar_r = sa->tar2.pairs[i][0];
2009 
2010     /* Select the rightmost target end */
2011     if (sa->tar2.pairs[i][0] + sa->tar2.pairs[i][1] - 1 < tar_l)
2012       tar_l = sa->tar2.pairs[i][0] + sa->tar2.pairs[i][1] - 1;
2013   }
2014 
2015   if (_PR_DEFAULT_POSITION_PENALTIES(pa)) {
2016     if (0 == tar_r) tar_r = n;
2017     if (tar_l == n) tar_l = 0;
2018   } else {
2019     tar_r = n;
2020     tar_l = 0;
2021   }
2022 
2023   /* We use some global information to restrict the region
2024      of the input sequence in which we generate candidate
2025      oligos. */
2026   if (retval->output_type == primer_list && pa->pick_left_primer == 1)
2027     f_b = n - 1;
2028   else if (tar_r - 1 < n - pr_min + pa->p_args.max_size - 1
2029            && !(pa->pick_anyway && sa->left_input))
2030     f_b=tar_r - 1;
2031   else
2032     f_b = n - pr_min + pa->p_args.max_size-1;
2033 
2034   if (pa->pick_left_primer) {
2035     /* We will need a left primer. */
2036     left=n; right=0;
2037     length = f_b - pa->p_args.min_size + 1;
2038     start = pa->p_args.min_size - 1;
2039 
2040     /* Use the primer provided */
2041      if (sa->left_input) {
2042       add_one_primer(sa->left_input, &left, &retval->fwd,
2043                      pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
2044 
2045     }
2046     /* Pick primers at one position */
2047     else if(sa->force_left_start > -1 ||
2048                 sa->force_left_end > -1) {
2049       pick_primers_by_position(sa->force_left_start, sa->force_left_end,
2050                                &left, &retval->fwd, pa, sa,
2051                                dpal_arg_to_use, thal_arg_to_use, retval);
2052     }
2053     /* Or pick all good in the given range */
2054     else {
2055        pick_primer_range(start, length, &left, &retval->fwd,
2056                         pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
2057     }
2058 
2059   }  /* if (pa->pick_left_primer) */
2060    if (retval->output_type == primer_list && pa->pick_right_primer == 1)
2061     r_b = 0;
2062   else if (tar_l+1>pr_min - pa->p_args.max_size
2063            && !(pa->pick_anyway && sa->right_input))
2064     r_b = tar_l+1;
2065   else
2066     r_b = pr_min - pa->p_args.max_size;
2067 
2068   if ( pa->pick_right_primer ) {
2069 
2070     /* We will need a right primer */
2071     length = n-pa->p_args.min_size - r_b + 1;
2072     start = r_b;
2073 
2074     /* Use the primer provided */
2075     if (sa->right_input) {
2076       add_one_primer(sa->right_input, &right, &retval->rev,
2077                      pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
2078       /*  pick_right_primers(start, length, &right, &retval->rev,
2079           pa, sa, dpal_arg_to_use, retval);*/
2080 
2081     }
2082     /* Pick primers at one position */
2083     else if(sa->force_right_start > -1 ||
2084                 sa->force_right_end > -1) {
2085       pick_primers_by_position(sa->force_right_start, sa->force_right_end,
2086                                &right, &retval->rev, pa, sa,
2087                                dpal_arg_to_use, thal_arg_to_use, retval);
2088     }
2089     /* Or pick all good in the given range */
2090     else {
2091       pick_primer_range(start, length, &right, &retval->rev,
2092                         pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
2093     }
2094   }
2095 
2096   /*
2097    * Return 1 if either the left primer list or the right primer
2098    * list is empty or if leftmost left primer and
2099    * rightmost right primer do not provide sufficient product size.
2100    */
2101 
2102   if ((pa->pick_left_primer && 0 == retval->fwd.num_elem)
2103       || ((pa->pick_right_primer)  && 0 == retval->rev.num_elem)) {
2104     return 1;
2105   } else if (!((sa->right_input)
2106                 && (sa->left_input))
2107              && pa->pick_left_primer
2108              && pa->pick_right_primer
2109              && (right - left) < (pr_min - 1)) {
2110     pair_expl->product    = 1;
2111     pair_expl->considered = 1;
2112     return 1;
2113   } else return 0;
2114 } /* make_detection_primer_lists */
2115 
2116 /*
2117  * Make complete list of acceptable internal oligos in retval->intl.oligo.
2118  * and place the number of valid elements in mid in retval->intl.num_elem.  Return 1 if
2119  * there are no acceptable internal oligos; otherwise return 0.
2120  */
2121 static int
make_internal_oligo_list(p3retval * retval,const p3_global_settings * pa,const seq_args * sa,const dpal_arg_holder * dpal_arg_to_use,const thal_arg_holder * thal_arg_to_use)2122 make_internal_oligo_list(p3retval *retval,
2123                          const p3_global_settings *pa,
2124                          const seq_args *sa,
2125                          const dpal_arg_holder *dpal_arg_to_use,
2126                          const thal_arg_holder *thal_arg_to_use)
2127 {
2128   int ret;
2129   int left = 0;
2130 
2131   /* Use the primer provided */
2132   if ((sa->internal_input) || (pa->primer_task == check_primers)){
2133           ret = add_one_primer(sa->internal_input, &left, &retval->intl,
2134                                pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
2135   }
2136   else {
2137     /* Pick all good in the given range */
2138 
2139     /* Use the settings to select a proper range */
2140     int length = strlen(sa->trimmed_seq) - pa->o_args.min_size;
2141     int start = pa->o_args.min_size - 1;
2142     int left = 0;
2143 
2144     ret = pick_primer_range(start, length, &left, &retval->intl,
2145                             pa, sa, dpal_arg_to_use, thal_arg_to_use,
2146                             retval);
2147   }
2148   return ret;
2149 } /* make_internal_oligo_list */
2150 
2151 /*
2152  * Make lists of acceptable left and right primers.  After return, the
2153  * lists are stored in retval->fwd.oligo and retval->rev.oligo and the
2154  * coresponding list sizes are stored in retval->fwd.num_elem and
2155  * retval->rev.num_elem.  Return 1 if one of lists is empty or if
2156  * leftmost left primer and rightmost right primer do not provide
2157  * sufficient product size.
2158  */
2159 static int
make_complete_primer_lists(p3retval * retval,const p3_global_settings * pa,const seq_args * sa,const dpal_arg_holder * dpal_arg_to_use,const thal_arg_holder * thal_arg_to_use,const thal_arg_holder * thal_oligo_arg_to_use)2160 make_complete_primer_lists(p3retval *retval,
2161                   const p3_global_settings *pa,
2162                   const seq_args *sa,
2163                   const dpal_arg_holder *dpal_arg_to_use,
2164                   const thal_arg_holder *thal_arg_to_use,
2165 		  const thal_arg_holder *thal_oligo_arg_to_use)
2166 {
2167   int extreme;
2168   int length, start;
2169   int n;
2170 
2171   /* Get the length of the sequence */
2172    PR_ASSERT(INT_MAX > (n=strlen(sa->trimmed_seq)));
2173    if (pa->pick_left_primer) {
2174     /* We will need a left primer. */
2175     extreme = 0;
2176     length = n - pa->p_args.min_size;
2177     start = pa->p_args.min_size - 1;
2178 
2179     /* Pick all good in the given range */
2180     pick_primer_range(start, length, &extreme, &retval->fwd,
2181                       pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
2182 
2183   }  /* if (pa->pick_left_primer) */
2184   if ( pa->pick_right_primer ) {
2185     /* We will need a right primer */
2186     extreme = n;
2187     length = n - pa->p_args.min_size + 1;
2188     start = 0;
2189 
2190     /* Pick all good in the given range */
2191     pick_primer_range(start, length, &extreme, &retval->rev,
2192                       pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
2193   }
2194 
2195   if ( pa->pick_internal_oligo ) {
2196     /* We will need a internal oligo */
2197     length = n - pa->o_args.min_size;
2198     start = pa->o_args.min_size - 1;
2199     extreme = 0;
2200 
2201     /* Pick all good in the given range */
2202     pick_primer_range(start, length, &extreme, &retval->intl,
2203                       pa, sa, dpal_arg_to_use, thal_oligo_arg_to_use, retval);
2204   }
2205 
2206   return 0;
2207 } /* make_complete_primer_lists */
2208 
2209 /*
2210  * Add caller-specified primers to retval->fwd, retval->rev, and/or
2211  * retval->intl.  The primers do not have to be "legal". It is possible
2212  * to add more than one primer to retval->fwd, etc, if the input
2213  * primer is found in multiple locations in the template. Similar to
2214  * make_complete_primer_lists.
2215  */
2216 static int
add_primers_to_check(p3retval * retval,const p3_global_settings * pa,const seq_args * sa,const dpal_arg_holder * dpal_arg_to_use,const thal_arg_holder * thal_arg_to_use,const thal_arg_holder * thal_oligo_arg_to_use)2217 add_primers_to_check(p3retval *retval,
2218 		     const p3_global_settings *pa,
2219 		     const seq_args *sa,
2220 		     const dpal_arg_holder *dpal_arg_to_use,
2221 		     const thal_arg_holder *thal_arg_to_use,
2222 		     const thal_arg_holder *thal_oligo_arg_to_use)
2223 {
2224   int extreme = 0; /* Required when calling add_one_primer
2225 		      but not used in the current function. */
2226 
2227   if (sa->left_input) {
2228     add_one_primer(sa->left_input, &extreme, &retval->fwd,
2229                    pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
2230   }
2231 
2232   if (sa->right_input) {
2233     add_one_primer(sa->right_input, &extreme, &retval->rev,
2234                    pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
2235   }
2236 
2237   if (sa->internal_input) {
2238     add_one_primer(sa->internal_input, &extreme, &retval->intl,
2239                    pa, sa, dpal_arg_to_use, thal_oligo_arg_to_use, retval);
2240   }
2241 
2242   return 0;
2243 } /* add_primers_to_check */
2244 
2245 /*
2246  * Make lists of acceptable left and right primers.  After return, the
2247  * lists are stored in retval->fwd.oligo and retval->rev.oligo and the
2248  * coresponding list sizes are stored in retval->fwd.num_elem and
2249  * retval->rev.num_elem.  Return 1 if one of lists is empty or if
2250  * leftmost left primer and rightmost right primer do not provide
2251  * sufficient product size.
2252  */
2253 static int
pick_sequencing_primer_list(p3retval * retval,const p3_global_settings * pa,const seq_args * sa,const dpal_arg_holder * dpal_arg_to_use,const thal_arg_holder * thal_arg_to_use)2254 pick_sequencing_primer_list(p3retval *retval,
2255                             const p3_global_settings *pa,
2256                             const seq_args *sa,
2257                             const dpal_arg_holder *dpal_arg_to_use,
2258                             const thal_arg_holder *thal_arg_to_use)
2259 {
2260   int length, start;
2261   int n, rest_accuracy;
2262   int primer_nr; /* number of primers we need to pick */
2263   int tar_n; /* counter for the targets */
2264   int step_nr; /* counter to step through the targets */
2265   int sequenced_len; /* bp sequenced in good quality */
2266   int extra_seq; /* bp sequenced additionally on both sides */
2267 
2268   /* best location for the 3' end of the fwd primer: */
2269   int pr_position_f;
2270 
2271   /* best location for the 3' end of the rev primer: */
2272   int pr_position_r;
2273 
2274   /* Get the length of the sequence */
2275   PR_ASSERT(INT_MAX > (n=strlen(sa->trimmed_seq)));
2276 
2277   /* For each target needed loop*/
2278   for (tar_n=0; tar_n < sa->tar2.count; tar_n++) {
2279 
2280     /* Calculate the amount of primers needed */
2281     primer_nr = 1;
2282     if ((pa->pick_left_primer) && (pa->pick_right_primer)){
2283       sequenced_len = pa->sequencing.interval;
2284       while(sequenced_len < sa->tar2.pairs[tar_n][1]) {
2285         primer_nr++;
2286         sequenced_len = pa->sequencing.spacing * (primer_nr - 1)
2287           + pa->sequencing.interval;
2288       }
2289     } else {
2290       sequenced_len = pa->sequencing.spacing;
2291       while(sequenced_len < sa->tar2.pairs[tar_n][1]) {
2292         primer_nr++;
2293         sequenced_len = pa->sequencing.spacing * primer_nr;
2294       }
2295     }
2296     /* Calculate the overlap on the sides */
2297     extra_seq = (sequenced_len - sa->tar2.pairs[tar_n][1]) / 2;
2298 
2299     /* Pick primers for each position */
2300     for ( step_nr = 0 ; step_nr < primer_nr ; step_nr++ ) {
2301       pr_position_f = sa->tar2.pairs[tar_n][0] - extra_seq
2302         + ( pa->sequencing.spacing * step_nr )
2303         - pa->sequencing.lead;
2304       if ((pa->pick_left_primer) && (pa->pick_right_primer)) {
2305         pr_position_r = sa->tar2.pairs[tar_n][0] - extra_seq
2306           + ( pa->sequencing.spacing * step_nr )
2307           + pa->sequencing.interval
2308           + pa->sequencing.lead;
2309       } else {
2310           pr_position_r = sa->tar2.pairs[tar_n][0] - extra_seq
2311             + ( pa->sequencing.spacing * (step_nr+1))
2312             + pa->sequencing.lead;
2313       }
2314       /* Check if calculated positions make sense */
2315       /* position_f cannot be outside included region */
2316       if (pr_position_f < (pa->p_args.min_size -1)) {
2317         pr_position_f = pa->p_args.min_size - 1;
2318       }
2319       if (pr_position_f > (n - pa->p_args.min_size - 1)) {
2320         pr_position_f = n - pa->p_args.min_size - 1;
2321         /* Actually this should never happen */
2322         pr_append_new_chunk(&retval->warnings,
2323                             "Calculation error in forward "
2324                             "sequencing position calculation");
2325       }
2326       /* position_r cannot be outside included region */
2327       if (pr_position_r < (pa->p_args.min_size - 1)) {
2328         pr_position_r = pa->p_args.min_size - 1;
2329         /* Actually this should never happen */
2330         pr_append_new_chunk(&retval->warnings,
2331                             "Calculation error in reverse "
2332                             "sequencing position calculation");
2333       }
2334       if (pr_position_r > (n - pa->p_args.min_size - 1)) {
2335         pr_position_r = n - pa->p_args.min_size - 1;
2336       }
2337       /* Now all pr_positions are within the sequence */
2338       if (pa->pick_left_primer) {
2339         /* Set the start and length for the regions */
2340         start = pr_position_f - pa->sequencing.accuracy;
2341         if (start < 0) {
2342           rest_accuracy = pr_position_f + 1;
2343           start = 0;
2344         } else {
2345           rest_accuracy = pa->sequencing.accuracy;
2346         }
2347         length = rest_accuracy + pa->sequencing.accuracy ;
2348         if ((start + length) > n) {
2349           length = n - start;
2350         }
2351         /* Pick all good in the given range */
2352         pick_only_best_primer(start, length, &retval->fwd,
2353                               pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
2354       }
2355       if (pa->pick_right_primer) {
2356         start = pr_position_r - pa->sequencing.accuracy;
2357         if (start < 0) {
2358           rest_accuracy = pr_position_r + 1;
2359           start = 0;
2360         } else {
2361           rest_accuracy = pa->sequencing.accuracy;
2362         }
2363         length = rest_accuracy + pa->sequencing.accuracy ;
2364         if ((start + length) > n) {
2365           length = n - start;
2366         }
2367         /* Pick all good in the given range */
2368         pick_only_best_primer(start, length, &retval->rev,
2369                               pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
2370       }
2371     }
2372 
2373   } /* End of Target Loop */
2374 
2375   /* Print an error if not all primers will be printed */
2376   if (retval->fwd.num_elem > pa->num_return
2377                   || retval->rev.num_elem > pa->num_return) {
2378     pr_append_new_chunk( &retval->warnings,
2379      "Increase PRIMER_NUM_RETURN to obtain all sequencing primers");
2380   }
2381 
2382   return 0;
2383 } /* pick_sequencing_primer_list */
2384 
2385 static void
add_oligo_to_oligo_array(oligo_array * oarray,primer_rec orec)2386 add_oligo_to_oligo_array(oligo_array *oarray, primer_rec orec) {
2387   /* Allocate some space for primers if needed */
2388   if (NULL == oarray->oligo) {
2389     oarray->storage_size = INITIAL_LIST_LEN;
2390     oarray->oligo
2391       = (primer_rec *)
2392       pr_safe_malloc(sizeof(*oarray->oligo) * oarray->storage_size);
2393   }
2394   /* If there is no space on the array, allocate new space */
2395   if ((oarray->num_elem + 1) >= oarray->storage_size) { /* TO DO, is +1 really needed? */
2396     oarray->storage_size += (oarray->storage_size >> 1);
2397     oarray->oligo
2398       = (primer_rec *)
2399       pr_safe_realloc(oarray->oligo,
2400                       oarray->storage_size * sizeof(*oarray->oligo));
2401   }
2402   oarray->oligo[oarray->num_elem] = orec;
2403   oarray->num_elem++;
2404 }
2405 
2406 /* pick_primer_range picks all primers which have their 3' end in the range
2407  * from start to start+length and store only the best *oligo  */
2408 static int
pick_only_best_primer(const int start,const int length,oligo_array * oligo,const p3_global_settings * pa,const seq_args * sa,const dpal_arg_holder * dpal_arg_to_use,const thal_arg_holder * thal_arg_to_use,p3retval * retval)2409 pick_only_best_primer(const int start,
2410                       const int length,
2411                       oligo_array *oligo,
2412                       const p3_global_settings *pa,
2413                       const seq_args *sa,
2414                       const dpal_arg_holder *dpal_arg_to_use,
2415                       const thal_arg_holder *thal_arg_to_use,
2416                       p3retval *retval)
2417 {
2418   /* Variables for the loop */
2419   int i, j, primer_size_small, primer_size_large;
2420   int n, found_primer;
2421   char number[20];
2422   char *p_number = &number[0];
2423   int temp_value;
2424 
2425   /* Array to store one primer sequences in */
2426   char oligo_seq[MAX_PRIMER_LENGTH+1];
2427 
2428   /* Struct to store the primer parameters in */
2429   primer_rec h;
2430   primer_rec best;
2431   memset(&h, 0, sizeof(primer_rec));
2432   memset(&best, 0, sizeof(primer_rec));
2433   best.quality = 1000.00;
2434   found_primer = 0;
2435 
2436   /* Set n to the length of included region */
2437   PR_ASSERT(INT_MAX > (n=strlen(sa->trimmed_seq)));
2438 
2439   /* Conditions for primer length */
2440   if (oligo->type == OT_INTL) {
2441     primer_size_small=pa->o_args.min_size;
2442     primer_size_large=pa->o_args.max_size;
2443   }
2444   else {
2445     primer_size_small=pa->p_args.min_size;
2446     primer_size_large=pa->p_args.max_size;
2447   }
2448 
2449   /* Loop over locations in the sequence */
2450   for(i = start + length - 1; i >= start; i--) {
2451     oligo_seq[0] = '\0';
2452 
2453     /* Loop over possible primer lengths, from min to max */
2454     for (j = primer_size_small; j <= primer_size_large; j++) {
2455       /* Set the length of the primer */
2456       h.length = j;
2457 
2458       /* Set repeat_sim to NULL as indicator that the repeat_sim
2459          struct is not initialized. */
2460       h.repeat_sim.score = NULL;
2461 
2462       /* Figure out positions for left primers and internal oligos */
2463       if (oligo->type != OT_RIGHT) {
2464         /* Break if the primer is bigger than the sequence left */
2465         if(i-j < -1) continue;
2466 
2467         /* Set the start of the primer */
2468         h.start = i - j + 1;
2469 
2470         /* Put the real primer sequence in oligo_seq */
2471         _pr_substr(sa->trimmed_seq, h.start, j, oligo_seq);
2472       } else {
2473         /* Figure out positions for reverse primers */
2474         /* Break if the primer is bigger than the sequence left*/
2475         if(i+j > n) continue;
2476 
2477         /* Set the start of the primer */
2478         h.start = i+j-1;
2479 
2480         /* Put the real primer sequence in s */
2481         _pr_substr(sa->trimmed_seq,  i, j, oligo_seq);
2482 
2483       }
2484 
2485       /* Do not force primer3 to use this oligo */
2486       h.must_use = 0;
2487 
2488       h.overlaps = 0;
2489 
2490       /* Add it to the considered statistics */
2491       oligo->expl.considered++;
2492       /* Calculate all the primer parameters */
2493       calc_and_check_oligo_features(pa, &h, oligo->type, dpal_arg_to_use, thal_arg_to_use,
2494                                     sa, &oligo->expl, retval, oligo_seq);
2495 
2496       /* If primer has to be used or is OK */
2497       if (OK_OR_MUST_USE(&h)) {
2498         /* Calculate the penalty */
2499         h.quality = p_obj_fn(pa, &h, oligo->type);
2500         /* Save the primer in the array */
2501         if (h.quality < best.quality) {
2502 	  /* Free memory used by previous best primer. */
2503 	  free_primer_repeat_sim_score(&best);
2504           best = h;
2505           found_primer = 1;
2506         } else {
2507 	  /* Free memory used by this primer. */
2508 	  free_primer_repeat_sim_score(&h);
2509 	}
2510       }
2511       else {
2512 	/* Free memory used by this primer. */
2513 	free_primer_repeat_sim_score(&h);
2514 	if (any_5_prime_ol_extension_has_problem(&h)) {
2515 	  /* Break from the inner for loop, because there is no
2516 	     legal longer oligo with the same 3' sequence. */
2517 	  break;
2518 	}
2519       }
2520     } /* j: Loop over possible primer length from min to max */
2521   } /* i: Loop over the sequence */
2522 
2523   if (found_primer == 1) {
2524     /* Add the best to the array */
2525     add_oligo_to_oligo_array(oligo, best);
2526     /* Update statistics with how many primers are good */
2527     oligo->expl.ok = oligo->expl.ok + 1;
2528   } else {
2529     if (oligo->type == OT_RIGHT) {
2530       pr_append_new_chunk(&retval->warnings, "No right primer found in range ");
2531     } else {
2532       pr_append_new_chunk(&retval->warnings, "No left primer found in range ");
2533     }
2534     temp_value = start + pa->first_base_index;
2535     sprintf(p_number, "%d", temp_value);
2536     pr_append(&retval->warnings, p_number);
2537     pr_append(&retval->warnings, " - ");
2538     temp_value = start + length + pa->first_base_index;
2539     sprintf(p_number, "%d", temp_value);
2540     pr_append(&retval->warnings, p_number);
2541   }
2542   if (oligo->num_elem == 0) return 1;
2543   else return 0;
2544 } /* pick_only_best_primer */
2545 
2546 /* pick_primer_range picks all legal primers in the range from start
2547    to start+length and stores them in *oligo  */
2548 static int
pick_primer_range(const int start,const int length,int * extreme,oligo_array * oligo,const p3_global_settings * pa,const seq_args * sa,const dpal_arg_holder * dpal_arg_to_use,const thal_arg_holder * thal_arg_to_use,p3retval * retval)2549 pick_primer_range(const int start, const int length, int *extreme,
2550                   oligo_array *oligo, const p3_global_settings *pa,
2551                   const seq_args *sa,
2552                   const dpal_arg_holder *dpal_arg_to_use,
2553                   const thal_arg_holder *thal_arg_to_use,
2554                   p3retval *retval)
2555 {
2556   /* Variables for the loop */
2557   int i, j;
2558   int primer_size_small, primer_size_large;
2559   int pr_min, n;
2560 
2561   /* Array to store one primer sequences in */
2562   char oligo_seq[MAX_PRIMER_LENGTH+1];
2563 
2564   /* Struct to store the primer parameters in */
2565   primer_rec h;
2566   memset(&h, 0, sizeof(primer_rec));
2567 
2568   /* Set pr_min to the very smallest
2569      allowable product size. */
2570   pr_min = INT_MAX;
2571   for (i=0; i < pa->num_intervals; i++)
2572     if(pa->pr_min[i] < pr_min)
2573       pr_min = pa->pr_min[i];
2574 
2575   /* Set n to the length of included region */
2576   PR_ASSERT(INT_MAX > (n=strlen(sa->trimmed_seq)));
2577 
2578   if (oligo->type == OT_INTL) {
2579     primer_size_small=pa->o_args.min_size;
2580     primer_size_large=pa->o_args.max_size;
2581   }
2582   else {
2583     primer_size_small=pa->p_args.min_size;
2584     primer_size_large=pa->p_args.max_size;
2585   }
2586 
2587   /* Loop over locations in the sequence */
2588   for(i = start + length; i >= start; i--) {
2589     oligo_seq[0] = '\0';
2590 
2591     /* Loop over possible primer lengths, from min to max */
2592     for (j = primer_size_small; j <= primer_size_large; j++) {
2593 
2594       /* Set the length of the primer */
2595       h.length = j;
2596 
2597       /* Figure out positions for left primers and internal oligos */
2598       if (oligo->type != OT_RIGHT) {
2599         /* Check if the product is of sufficient size */
2600         if (i-j > n-pr_min-1 && retval->output_type == primer_pairs
2601             && oligo->type == OT_LEFT) continue;
2602 
2603         /* Break if the primer is bigger than the sequence left */
2604         if (i-j < -1) break;
2605 
2606         /* Set the start of the primer */
2607         h.start = i - j + 1;
2608 
2609         /* Put the real primer sequence in oligo_seq */
2610         _pr_substr(sa->trimmed_seq, h.start, j, oligo_seq);
2611       } else {
2612         /* Figure out positions for reverse primers */
2613         /* Check if the product is of sufficient size */
2614         if (i+j < pr_min && retval->output_type == primer_pairs) continue;
2615 
2616         /* Break if the primer is bigger than the sequence left*/
2617         if (i+j > n) break;
2618 
2619         /* Set the start of the primer */
2620         h.start = i+j-1;
2621 
2622         /* Put the real primer sequence in s */
2623         _pr_substr(sa->trimmed_seq,  i, j, oligo_seq);
2624 
2625       }
2626 
2627       /* Do not force primer3 to use this oligo */
2628       h.must_use = 0;
2629 
2630       h.overlaps = 0;
2631 
2632       /* Add it to the considered statistics */
2633       oligo->expl.considered++;
2634       /* Calculate all the primer parameters */
2635       calc_and_check_oligo_features(pa, &h, oligo->type, dpal_arg_to_use, thal_arg_to_use,
2636                                     sa, &oligo->expl, retval, oligo_seq);
2637        /* If primer has to be used or is OK */
2638       if (OK_OR_MUST_USE(&h)) {
2639         /* Calculate the penalty */
2640         h.quality = p_obj_fn(pa, &h, oligo->type);
2641         /* Save the primer in the array */
2642         add_oligo_to_oligo_array(oligo, h);
2643         /* Update the most extreme primer variable */
2644         if (( h.start < *extreme) && (oligo->type != OT_RIGHT))
2645           *extreme = h.start;
2646         /* Update the most extreme primer variable */
2647         if ((h.start > *extreme) && (oligo->type == OT_RIGHT))
2648           *extreme = h.start;
2649       } else {
2650 	/* Free memory used by this primer. */
2651 	free_primer_repeat_sim_score(&h);
2652 	if (any_5_prime_ol_extension_has_problem(&h)) {
2653 	  /* Break from the inner for loop, because there is no
2654 	     legal longer oligo with the same 3' sequence. */
2655 	  break;
2656 	}
2657       }
2658     } /* j: Loop over possible primer length from min to max */
2659   } /* i: Loop over the sequence */
2660 
2661   /* Update statistics with how many primers are good */
2662   oligo->expl.ok = oligo->num_elem;
2663 
2664   if (oligo->num_elem == 0) return 1;
2665   else return 0;
2666 } /* pick_primer_range */
2667 
2668 /* add_one_primer finds one primer in the trimmed sequence and stores
2669  * it in *oligo The main difference to the general fuction is that it
2670  * calculates its length and it will add a primer of any length to the
2671  * list */
2672 static int
add_one_primer(const char * primer,int * extreme,oligo_array * oligo,const p3_global_settings * pa,const seq_args * sa,const dpal_arg_holder * dpal_arg_to_use,const thal_arg_holder * thal_arg_to_use,p3retval * retval)2673 add_one_primer(const char *primer, int *extreme, oligo_array *oligo,
2674                const p3_global_settings *pa,
2675                const seq_args *sa,
2676                const dpal_arg_holder *dpal_arg_to_use,
2677                const thal_arg_holder *thal_arg_to_use,
2678                p3retval *retval) {
2679   /* Variables for the loop */
2680   int i, j;
2681   int n;
2682 
2683   /* Array to store one primer sequences in */
2684   char oligo_seq[MAX_PRIMER_LENGTH+1] , test_oligo[MAX_PRIMER_LENGTH+1];
2685 
2686   /* Struct to store the primer parameters in */
2687   primer_rec h;
2688   memset(&h, 0, sizeof(primer_rec));
2689 
2690   /* Copy *primer into test_oligo */
2691   test_oligo[0] = '\0';
2692   if (oligo->type != OT_RIGHT) {
2693     strncat(test_oligo, primer, MAX_PRIMER_LENGTH);
2694   } else {
2695     p3_reverse_complement(primer, test_oligo);
2696   }
2697 
2698   PR_ASSERT(INT_MAX > (n=strlen(sa->trimmed_seq)));
2699 
2700   /* This time we already know the size of the primer */
2701   j = strlen(primer);
2702 
2703   /* Loop over the whole sequence */
2704   for(i = strlen(sa->trimmed_seq); i >= 0; i--) {
2705     oligo_seq[0] = '\0';
2706 
2707     /* Set the length of the primer */
2708     h.length = j;
2709 
2710     /* Figure out positions for forward primers */
2711     if (oligo->type != OT_RIGHT) {
2712       /* Break if the primer is bigger than the sequence left*/
2713       if(i-j < -1) continue;
2714 
2715       /* Set the start of the primer */
2716       h.start = i - j +1;
2717 
2718       /* Put the real primer sequence in s */
2719       _pr_substr(sa->trimmed_seq, h.start, j, oligo_seq);
2720     }
2721     /* Figure out positions for reverse primers */
2722     else {
2723       /* Break if the primer is bigger than the sequence left*/
2724       if(i+j>n) continue;
2725 
2726       /* Set the start of the primer */
2727       h.start=i+j-1;
2728 
2729       /* Put the real primer sequence in s */
2730       _pr_substr(sa->trimmed_seq,  i, j, oligo_seq);
2731     }
2732 
2733     /* Compare the primer with the sequence */
2734     if (strcmp_nocase(test_oligo, oligo_seq))
2735       continue;
2736 
2737     /* Force primer3 to use this oligo */
2738     h.must_use = (1 && pa->pick_anyway);
2739 
2740     h.overlaps = 0;
2741 
2742     /* Add it to the considered statistics */
2743     oligo->expl.considered++;
2744 
2745     /* Calculate all the primer parameters */
2746     calc_and_check_oligo_features(pa, &h, oligo->type, dpal_arg_to_use, thal_arg_to_use,
2747                                   sa, &oligo->expl, retval, oligo_seq);
2748 
2749     /* If primer has to be used or is OK */
2750     if (OK_OR_MUST_USE(&h)) {
2751       /* Calculate the penalty */
2752       h.quality = p_obj_fn(pa, &h, oligo->type);
2753       /* Save the primer in the array */
2754       add_oligo_to_oligo_array(oligo,  h);
2755       /* Update the most extreme primer variable */
2756       if ((h.start < *extreme) && (oligo->type != OT_RIGHT))
2757         *extreme = h.start;
2758       /* Update the most extreme primer variable */
2759       if ((h.start > *extreme) && (oligo->type == OT_RIGHT))
2760         *extreme = h.start;
2761     } else {
2762       /* Free memory used by this primer. */
2763       free_primer_repeat_sim_score(&h);
2764     }
2765   } /* i: Loop over the sequence */
2766     /* Update array with how many primers are good */
2767   /* Update statistics with how many primers are good */
2768   oligo->expl.ok = oligo->num_elem;
2769 
2770   if (oligo->num_elem == 0) return 1;
2771   else {
2772     if (oligo->num_elem > 1) {
2773       pr_append_new_chunk(&retval->warnings,
2774 			  "More than one position in template for input oligo ");
2775       pr_append(&retval->warnings, primer);
2776     }
2777     return 0; /* Success */
2778   }
2779 }
2780 
2781 /* add_one_primer finds one primer in the trimmed sequence and stores
2782  * it in *oligo The main difference to the general fuction is that it
2783  * calculates its length and it will add a primer of any length to the
2784  * list */
2785 static int
add_one_primer_by_position(int start,int length,int * extreme,oligo_array * oligo,const p3_global_settings * pa,const seq_args * sa,const dpal_arg_holder * dpal_arg_to_use,const thal_arg_holder * thal_arg_to_use,p3retval * retval)2786 add_one_primer_by_position(int start, int length, int *extreme, oligo_array *oligo,
2787                            const p3_global_settings *pa,
2788                            const seq_args *sa,
2789                            const dpal_arg_holder *dpal_arg_to_use,
2790                            const thal_arg_holder *thal_arg_to_use,
2791                            p3retval *retval) {
2792   /* Variables for the loop */
2793   int i;
2794   int n, found_primer;
2795 
2796   /* Array to store one primer sequences in */
2797   char oligo_seq[MAX_PRIMER_LENGTH+1];
2798 
2799   /* Struct to store the primer parameters in */
2800   primer_rec h;
2801   memset(&h, 0, sizeof(primer_rec));
2802 
2803   /* Retun 1 for no primer found */
2804   found_primer = 1;
2805 
2806   PR_ASSERT(INT_MAX > (n=strlen(sa->trimmed_seq)));
2807 
2808   /* Just to be sure */
2809   if (start < 0) {
2810     return 1;
2811   }
2812   if (start >= n) {
2813     return 1;
2814   }
2815   if (oligo->type != OT_RIGHT) {
2816     if ((start + length) > n) {
2817       return 1;
2818     }
2819   } else {
2820     if ((start - length + 1) < 0) {
2821       return 1;
2822     }
2823   }
2824 
2825   oligo_seq[0] = '\0';
2826 
2827   /* Set the length of the primer */
2828   h.length = length;
2829 
2830   /* Figure out positions for forward primers */
2831   if (oligo->type != OT_RIGHT) {
2832     /* Set the start of the primer */
2833     h.start = start;
2834 
2835     /* Put the real primer sequence in s */
2836     _pr_substr(sa->trimmed_seq, h.start, length, oligo_seq);
2837   }
2838   /* Figure out positions for reverse primers */
2839   else {
2840     i = start - length + 1;
2841     /* Set the start of the primer */
2842     h.start = start;
2843 
2844     /* Put the real primer sequence in s */
2845     _pr_substr(sa->trimmed_seq, i, length, oligo_seq);
2846   }
2847 
2848   /* Force primer3 to use this oligo */
2849   h.must_use = (1 && pa->pick_anyway);
2850 
2851   h.overlaps = 0;
2852 
2853   /* Add it to the considered statistics */
2854   oligo->expl.considered++;
2855 
2856   /* Calculate all the primer parameters */
2857   calc_and_check_oligo_features(pa, &h, oligo->type, dpal_arg_to_use, thal_arg_to_use,
2858                                 sa, &oligo->expl, retval, oligo_seq);
2859 
2860   /* If primer has to be used or is OK */
2861   if (OK_OR_MUST_USE(&h)) {
2862     /* Calculate the penalty */
2863       h.quality = p_obj_fn(pa, &h, oligo->type);
2864       /* Save the primer in the array */
2865       add_oligo_to_oligo_array(oligo, h);
2866       found_primer = 0;
2867       /* Update the most extreme primer variable */
2868       if (( h.start < *extreme) &&
2869           (oligo->type != OT_RIGHT))
2870         *extreme =  h.start;
2871       /* Update the most extreme primer variable */
2872       if (( h.start > *extreme) &&
2873           (oligo->type == OT_RIGHT))
2874         *extreme =  h.start;
2875       /* Update the number of primers */
2876   } else {
2877     /* Free memory used by this primer. */
2878     free_primer_repeat_sim_score(&h);
2879   }
2880   /* Update array with how many primers are good */
2881   /* Update statistics with how many primers are good */
2882   oligo->expl.ok = oligo->num_elem;
2883 
2884   /* return 0 for success */
2885   return found_primer;
2886 }
2887 
2888 static int
pick_primers_by_position(const int start,const int end,int * extreme,oligo_array * oligo,const p3_global_settings * pa,const seq_args * sa,const dpal_arg_holder * dpal_arg_to_use,const thal_arg_holder * thal_arg_to_use,p3retval * retval)2889 pick_primers_by_position(const int start, const int end, int *extreme,
2890                          oligo_array *oligo, const p3_global_settings *pa,
2891                          const seq_args *sa,
2892                          const dpal_arg_holder *dpal_arg_to_use,
2893                          const thal_arg_holder *thal_arg_to_use,
2894                          p3retval *retval)
2895 {
2896   int found_primer, length, j, ret, new_start;
2897   found_primer = 1;
2898   ret = 1;
2899 
2900   if(start > -1 && end > -1) {
2901     if (oligo->type != OT_RIGHT) {
2902       length = end - start + 1;
2903     } else {
2904       length = start - end + 1;
2905     }
2906 
2907     found_primer = add_one_primer_by_position(start, length, extreme, oligo,
2908                                               pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
2909     return found_primer;
2910   } else if (start > -1) {
2911     /* Loop over possible primer lengths, from min to max */
2912     ret = 0;
2913     for (j = pa->p_args.min_size; j <= pa->p_args.max_size; j++) {
2914       ret += add_one_primer_by_position(start, j, extreme, oligo,
2915                                         pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
2916       if (ret == 0) {
2917         found_primer = 0;
2918       }
2919     }
2920     return found_primer;
2921   } else if (end > -1) {
2922     /* Loop over possible primer lengths, from min to max */
2923     ret = 0;
2924     for (j = pa->p_args.min_size; j <= pa->p_args.max_size; j++) {
2925       if (oligo->type != OT_RIGHT) {
2926         new_start = end - j + 1;
2927       } else {
2928         new_start = end + j - 1;
2929       }
2930       ret += add_one_primer_by_position(new_start, j, extreme, oligo,
2931                                         pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
2932       if (ret == 0) {
2933         found_primer = 0;
2934       }
2935     }
2936     return found_primer;
2937   } else {
2938     /* Actually this should never happen */
2939     pr_append_new_chunk(&retval->warnings,
2940            "Calculation error in forced primer position calculation");
2941     return 1;
2942   }
2943 }
2944 
2945 /*
2946  * Compute various characteristics of the oligo, and determine
2947  * if it is acceptable.
2948  */
2949 #define OUTSIDE_START_WT  30.0
2950 #define INSIDE_START_WT   20.0
2951 #define INSIDE_STOP_WT   100.0
2952 #define OUTSIDE_STOP_WT    0.5
2953 static void
calc_and_check_oligo_features(const p3_global_settings * pa,primer_rec * h,oligo_type otype,const dpal_arg_holder * dpal_arg_to_use,const thal_arg_holder * thal_arg_to_use,const seq_args * sa,oligo_stats * stats,p3retval * retval,const char * input_oligo_seq)2954 calc_and_check_oligo_features(const p3_global_settings *pa,
2955                               primer_rec *h,
2956                               oligo_type otype,
2957                               const dpal_arg_holder *dpal_arg_to_use,
2958                               const thal_arg_holder *thal_arg_to_use,
2959                               const seq_args *sa,
2960                               oligo_stats *stats,
2961                               p3retval *retval,
2962 
2963                               /* This is 5'->3' on the template sequence: */
2964                               const char *input_oligo_seq
2965                               )
2966 {
2967   int i, j, k, for_i, gc_count;
2968   int three_prime_pos; /* position of 3' base of oligo */
2969   oligo_type l = otype;
2970   int poly_x, max_poly_x;
2971   int must_use = h->must_use;
2972   int three_conditions
2973     = (must_use || pa->file_flag || retval->output_type == primer_list);
2974   const char *seq = sa->trimmed_seq;
2975   const thal_args *thal_args_for_template_mispriming
2976     = use_end_for_th_template_mispriming
2977     ? thal_arg_to_use->end1
2978     : thal_arg_to_use->any;
2979 
2980   char s1_rev[MAX_PRIMER_LENGTH+1];
2981   const char *oligo_seq;
2982   const char *revc_oligo_seq;
2983 
2984   const args_for_one_oligo_or_primer *po_args;
2985 
2986   /* Initialize slots in h */
2987   initialize_op(h);
2988   h->overlaps = 0;
2989 
2990   /* Set repeat_sim to NULL as indicator that the repeat_sim
2991      struct is not initialized. */
2992   h->repeat_sim.score = NULL;
2993 
2994   h->gc_content = h->num_ns = 0;
2995   h->overlaps_overlap_position = 0;
2996   h->template_mispriming = h->template_mispriming_r = ALIGN_SCORE_UNDEF;
2997   h->template_mispriming_ok = 0;
2998 
2999   PR_ASSERT(OT_LEFT == l || OT_RIGHT == l || OT_INTL == l);
3000 
3001   p3_reverse_complement(input_oligo_seq, s1_rev);
3002   if (OT_RIGHT == l) {
3003     oligo_seq = s1_rev;
3004     revc_oligo_seq = input_oligo_seq;
3005  } else {
3006     oligo_seq = input_oligo_seq;
3007     revc_oligo_seq = s1_rev;
3008   }
3009 
3010   if (OT_INTL == l) {
3011     po_args = &pa->o_args;
3012   } else {
3013     po_args = &pa->p_args;
3014   }
3015 
3016   /* Set j and k, and sanity check */
3017   if (OT_LEFT == otype || OT_INTL == otype) {
3018     j = h->start;
3019     three_prime_pos = k = j+h->length-1;
3020   }  else {
3021     three_prime_pos = j = h->start-h->length+1;
3022     k = h->start;
3023   }
3024   PR_ASSERT(k >= 0);
3025   PR_ASSERT(k < TRIMMED_SEQ_LEN(sa));
3026 
3027   if ((otype == OT_LEFT) && !PR_START_CODON_POS_IS_NULL(sa)
3028       /* Make sure the primer would amplify at least part of
3029          the ORF. */
3030       && (0 != (h->start - sa->start_codon_pos) % 3
3031           || h->start <= retval->upstream_stop_codon
3032           || (retval->stop_codon_pos != -1
3033               && h->start >= retval->stop_codon_pos))) {
3034     stats->no_orf++;
3035     op_set_does_not_amplify_orf(h);
3036     if (!pa->pick_anyway) return;
3037   }
3038 
3039   /* edited by T. Koressaar for lowercase masking */
3040   if(pa->lowercase_masking == 1) {
3041     if (is_lowercase_masked(three_prime_pos,
3042                             sa->trimmed_orig_seq,
3043                             h, stats)) {
3044       if (!must_use) return;
3045     }
3046   }
3047   /* end T. Koressar's changes */
3048 
3049   /* edited by A. Untergasser for forcing sequence use */
3050   if ((po_args->must_match_five_prime != NULL) or
3051       (po_args->must_match_three_prime != NULL)) {
3052     if (primer_must_match(pa, h, stats, oligo_seq,
3053                           po_args->must_match_three_prime,
3054                           po_args->must_match_five_prime)) {
3055       if (!must_use) {
3056 	op_set_must_match_err(h);
3057 	return;
3058       }
3059     }
3060   }
3061   /* end A. Untergasser's changes */
3062 
3063   gc_and_n_content(j, k-j+1, sa->trimmed_seq, h);
3064 
3065   if (h->num_ns > po_args->num_ns_accepted) {
3066     op_set_too_many_ns(h);
3067     stats->ns++;
3068     if (!must_use) return;
3069   }
3070 
3071   /* Upstream error checking has ensured that we use non-default position
3072      penalties only when there is 0 or 1 target. */
3073   PR_ASSERT(sa->tar2.count <= 1 || _PR_DEFAULT_POSITION_PENALTIES(pa));
3074 
3075   if (pa->primer_task == pick_sequencing_primers) {
3076     h->position_penalty = 0.0;
3077   } else if (l != OT_INTL
3078              && _PR_DEFAULT_POSITION_PENALTIES(pa)
3079              && oligo_overlaps_interval(j, k-j+1, sa->tar2.pairs, sa->tar2.count)) {
3080     h->position_penalty = 0.0;
3081     bf_set_infinite_pos_penalty(h,1);
3082     bf_set_overlaps_target(h,1);
3083   } else if (l != OT_INTL && !_PR_DEFAULT_POSITION_PENALTIES(pa)
3084              && 1 == sa->tar2.count) {
3085     compute_position_penalty(pa, sa, h, l);
3086     if (bf_get_infinite_pos_penalty(h)) {
3087         bf_set_overlaps_target(h,1);
3088     }
3089   } else {
3090     h->position_penalty = 0.0;
3091     bf_set_infinite_pos_penalty(h,0);
3092   }
3093 
3094   if (!PR_START_CODON_POS_IS_NULL(sa)) {
3095     if (OT_LEFT == l) {
3096       if (sa->start_codon_pos > h->start)
3097         h->position_penalty
3098           = (sa->start_codon_pos - h->start) * OUTSIDE_START_WT;
3099       else
3100         h->position_penalty
3101           = (h->start - sa->start_codon_pos) * INSIDE_START_WT;
3102     } else if (OT_RIGHT == l) {
3103 
3104       if (-1 == retval->stop_codon_pos) {
3105         h->position_penalty = (TRIMMED_SEQ_LEN(sa) - h->start - 1) * INSIDE_STOP_WT;
3106       } else if (retval->stop_codon_pos < h->start) {
3107         h->position_penalty
3108           = (h->start - retval->stop_codon_pos) * OUTSIDE_STOP_WT;
3109       } else {
3110         h->position_penalty
3111           = (retval->stop_codon_pos - h->start) * INSIDE_STOP_WT;
3112       }
3113     }
3114   }
3115 
3116   /* TO DO Simplify logic here */
3117   if (l != OT_INTL
3118       && oligo_overlaps_interval(j, k-j+1, sa->excl2.pairs, sa->excl2.count))
3119     bf_set_overlaps_excl_region(h,1);
3120 
3121   if (l == OT_INTL
3122       && oligo_overlaps_interval(j, k-j+1, sa->excl_internal2.pairs,
3123                                               sa->excl_internal2.count))
3124     bf_set_overlaps_excl_region(h,1);
3125 
3126   if(l != OT_INTL && bf_get_overlaps_target(h)) {
3127     op_set_overlaps_target(h);
3128     stats->target++;
3129     if (!must_use) return;
3130   }
3131 
3132   if(bf_get_overlaps_excl_region(h)){
3133     op_set_overlaps_excluded_region(h);
3134     stats->excluded++;
3135     if (!must_use) return;
3136   }
3137 
3138   /* Check if the oligo is included in any ok region */
3139   if ((l == OT_LEFT) && (sa->ok_regions.count > 0) && (!sa->ok_regions.any_left)) {
3140     int included = 0;
3141     for (i=0; i<sa->ok_regions.count; i++) {
3142       if ((j >= sa->ok_regions.left_pairs[i][0]) &&
3143           (k <= sa->ok_regions.left_pairs[i][0] + sa->ok_regions.left_pairs[i][1] - 1)) {
3144         included = 1;
3145         break;
3146       }
3147     }
3148     if (!included) {
3149       op_set_not_in_any_ok_region(h);
3150       stats->not_in_any_left_ok_region++;
3151       if (!must_use) return;
3152     }
3153   }
3154   if ((l == OT_RIGHT) && (sa->ok_regions.count > 0) && (!sa->ok_regions.any_right)) {
3155     int included = 0;
3156     for (i=0; i<sa->ok_regions.count; i++) {
3157       if ((j >= sa->ok_regions.right_pairs[i][0]) &&
3158           (k <= sa->ok_regions.right_pairs[i][0] + sa->ok_regions.right_pairs[i][1] - 1)) {
3159         included = 1;
3160         break;
3161       }
3162     }
3163     if (!included) {
3164       op_set_not_in_any_ok_region(h);
3165       stats->not_in_any_right_ok_region++;
3166       if (!must_use) return;
3167     }
3168   }
3169 
3170   if (h->gc_content < po_args->min_gc) {
3171     op_set_low_gc_content(h);
3172     stats->gc++;
3173     if (!must_use) return;
3174   } else if (h->gc_content > po_args->max_gc) {
3175     op_set_high_gc_content(h);
3176     stats->gc++;
3177     if (!must_use) return;
3178   }
3179 
3180   if (OT_LEFT == l || OT_RIGHT == l) {
3181     /* gc_clamp is applicable only to primers (as opposed
3182        to primers and hybridzations oligos. */
3183     for (i = 0; i < pa->gc_clamp; i++) {
3184       /* We want to look at the 3' end of the oligo being
3185          assessed, so we look in the 5' end of its reverse-complement */
3186       if (revc_oligo_seq[i] != 'G' && revc_oligo_seq[i] != 'C') {
3187         op_set_no_gc_glamp(h);
3188         stats->gc_clamp++;
3189         if (!must_use) return; else break;
3190       }
3191     }
3192   }
3193 
3194 #if 0
3195   /* Old code, works */
3196   if(pa->gc_clamp != 0){
3197     if(OT_LEFT == l) {
3198       for(i=k-pa->gc_clamp+1; i<= k; i++)if(seq[i] !='G'&&seq[i] !='C'){
3199         op_set_no_gc_glamp(h);
3200         stats->gc_clamp++;
3201         if (!must_use) return; else break;
3202       }
3203     }
3204     if(OT_RIGHT == l){
3205       for(i=j; i<j+pa->gc_clamp; i++)if(seq[i] != 'G' && seq[i] != 'C'){
3206         op_set_no_gc_glamp(h);
3207         stats->gc_clamp++;
3208         if (!must_use) return; else break;
3209       }
3210     }
3211   }
3212 #endif
3213 
3214   if (pa->max_end_gc < 5
3215       && (OT_LEFT == l || OT_RIGHT == l)) {
3216     /* The CGs are only counted in the END of primers (as opposed
3217        to primers and hybridzations oligos. */
3218     gc_count=0;
3219     for (i = 0; i < 5; i++) {
3220       /* We want to look at the 3' end of the oligo being
3221          assessed, so we look in the 5' end of its reverse-complement */
3222       if (revc_oligo_seq[i] == 'G' || revc_oligo_seq[i] == 'C') {
3223         gc_count++;
3224       }
3225     }
3226     if (gc_count > pa->max_end_gc) {
3227       op_set_too_many_gc_at_end(h);
3228       stats->gc_end_high++;
3229       if (!must_use) return;
3230     }
3231   }
3232 
3233   /* Tentative interface for generic oligo  testing
3234      function */
3235   if (!sequence_quality_is_ok(pa, h, l, sa, j, k,
3236                               stats, po_args)
3237       && !must_use) return;
3238 
3239   max_poly_x = po_args->max_poly_x;
3240   if (max_poly_x > 0) {
3241     poly_x = 1;
3242     for(i=j+1;i<=k;i++){
3243       if(seq[i] == seq[i-1]||seq[i] == 'N'){
3244         poly_x++;
3245         if(poly_x > max_poly_x){
3246           op_set_high_poly_x(h);
3247           stats->poly_x++;
3248           if (!must_use) return; else break;
3249         }
3250       }
3251       else poly_x = 1;
3252     }
3253   }
3254 
3255   h->temp  /* Oligo/primer melting temperature */
3256     = seqtm(oligo_seq, po_args->dna_conc,
3257             po_args->salt_conc,
3258             po_args->divalent_conc,
3259             po_args->dntp_conc,
3260             MAX_NN_TM_LENGTH,
3261             pa->tm_santalucia,
3262             pa->salt_corrections);
3263 
3264   if (h->temp < po_args->min_tm) {
3265     op_set_low_tm(h);
3266     stats->temp_min++;
3267     if (!must_use) return;
3268   }
3269 
3270   if (h->temp > po_args->max_tm) {
3271     op_set_high_tm(h);
3272     stats->temp_max++;
3273     if (!must_use) return;
3274   }
3275 
3276   /* End stability is applicable only to primers
3277      (not to oligos) */
3278   if (OT_LEFT == l || OT_RIGHT == l) {
3279     if ((h->end_stability = end_oligodg(oligo_seq, 5,
3280                                         pa->tm_santalucia))
3281         > pa->max_end_stability) {
3282       /* Must not be called on a hybridization probe / internal oligo: */
3283       op_set_high_end_stability(h);
3284       stats->stability++;
3285       if (!must_use) return;
3286     }
3287   }
3288 
3289   if ((must_use
3290       || pa->file_flag
3291       || retval->output_type == primer_list
3292       || po_args->weights.compl_any
3293       || po_args->weights.compl_end)
3294       && pa->thermodynamic_oligo_alignment==0) {
3295 
3296     oligo_compl(h, po_args,
3297                 stats, dpal_arg_to_use,
3298                 oligo_seq, revc_oligo_seq);
3299 
3300     if ((!(p3_ol_is_uninitialized(h))) && !must_use) {
3301       PR_ASSERT(!p3_ol_is_ok(h));
3302       return;
3303     }
3304   } else {
3305     /* Thermodynamical approach: for primers only  */
3306     if ((must_use
3307        || pa->file_flag
3308        || retval->output_type == primer_list
3309        || po_args->weights.compl_any_th
3310        || po_args->weights.compl_end_th)
3311        && pa->thermodynamic_oligo_alignment==1
3312        )
3313      {
3314         oligo_compl_thermod(h, po_args,
3315                             stats, thal_arg_to_use,
3316                             oligo_seq, oligo_seq);
3317                             /* input_oligo_seq, input_oligo_seq);*/
3318                             /* oligo_seq, revc_oligo_seq); */
3319         if ((!(p3_ol_is_uninitialized(h))) && !must_use) {
3320            PR_ASSERT(!p3_ol_is_ok(h));
3321            return;
3322         }
3323      } else  {
3324         h->self_any = h->self_end  = ALIGN_SCORE_UNDEF;
3325      }
3326   }
3327 
3328   if ((three_conditions
3329        || po_args->weights.hairpin_th
3330 #if 0
3331         || po_args->weights.compl_any_th /* Triinu, is this needed? */
3332         || po_args->weights.compl_end_th /* Triinu, is this needed? */
3333 #endif
3334        )
3335        && pa->thermodynamic_oligo_alignment==1
3336        ) {
3337       oligo_hairpin(h, po_args,
3338                     stats, thal_arg_to_use,
3339                     /* input_oligo_seq);*/
3340                     oligo_seq);
3341       if ((!(p3_ol_is_uninitialized(h))) && !must_use) {
3342          PR_ASSERT(!p3_ol_is_ok(h));
3343          return;
3344       }
3345    } else   {
3346     /* This will get calculated later if necessary, in characterize_pair. */
3347     h->hairpin_th = ALIGN_SCORE_UNDEF;
3348    }
3349    /* end of thermod. approach */
3350 
3351 
3352 #if 0
3353   /* FIX ME FIXME */
3354   if (((must_use
3355         || pa->file_flag
3356         || retval->output_type == primer_list
3357         || po_args->weights.repeat_sim
3358         || ((OT_RIGHT == l || OT_LEFT == l)
3359             && pa->p_args.weights.template_mispriming))
3360 
3361        && pa->thermodynamic_oligo_alignment==0)
3362       || (pa->thermodynamic_oligo_alignment==1 && po_args->weights.repeat_sim)) {
3363 
3364     oligo_repeat_library_mispriming(h, pa, sa, l, stats,
3365                                     dpal_arg_to_use);
3366     if (pa->thermodynamic_template_alignment==0 && OK_OR_MUST_USE(h)) {
3367       oligo_template_mispriming(h, pa, sa, l, stats,
3368 				dpal_arg_to_use->local_end,
3369 				thal_args_for_template_mispriming);
3370     }
3371   }
3372 
3373   if ((must_use
3374        || pa->file_flag
3375        || retval->output_type == primer_list
3376        || ((OT_RIGHT == l || OT_LEFT == l)
3377 	   && pa->p_args.weights.template_mispriming_th))
3378 
3379       && pa->thermodynamic_template_alignment==1)
3380  {
3381 
3382     oligo_template_mispriming(h, pa, sa, l, stats,
3383                               dpal_arg_to_use->local_end,
3384                               thal_args_for_template_mispriming);
3385   }
3386   /* END FIX ME FIXME */
3387 #else
3388 
3389   if (three_conditions || po_args->weights.repeat_sim) {
3390     oligo_repeat_library_mispriming(h, pa, sa, l, stats,
3391                                     dpal_arg_to_use);
3392   }
3393 
3394 
3395   if (!OK_OR_MUST_USE(h)) return;
3396 
3397   if (three_conditions
3398       ||
3399       ( /* Do we need template mispriming for the penalty function? */
3400        (OT_RIGHT == l || OT_LEFT == l)
3401        &&
3402        (
3403 	(pa->p_args.weights.template_mispriming && !pa->thermodynamic_template_alignment)
3404 	||
3405 	(pa->p_args.weights.template_mispriming_th && pa->thermodynamic_template_alignment)
3406 	)
3407        )
3408       ) {
3409     if (OK_OR_MUST_USE(h)) {
3410       oligo_template_mispriming(h, pa, sa, l, stats,
3411 				dpal_arg_to_use->local_end,
3412 				thal_args_for_template_mispriming);
3413     }
3414   }
3415 
3416 #endif
3417 
3418   if (h->length > po_args->max_size ) {
3419     op_set_too_long(h);
3420     stats->size_max ++;
3421     if (!must_use) return;
3422   }
3423 
3424   if (h->length < po_args->min_size ) {
3425     op_set_too_short(h);
3426     stats->size_min ++;
3427     if (!must_use) return;
3428   }
3429 
3430   for (for_i=0; for_i < sa->primer_overlap_junctions_count; for_i++) {
3431     if (OT_LEFT == l
3432         && ((h->start + pa->min_5_prime_overlap_of_junction - 1)
3433             <= sa->primer_overlap_junctions[for_i])
3434         && ((h->start + h->length - pa->min_3_prime_overlap_of_junction))
3435         > sa->primer_overlap_junctions[for_i]) {
3436       h->overlaps_overlap_position = 1;
3437       /* no need to continue checking */
3438       break;
3439     }
3440     if (OT_RIGHT == l
3441         && ((h->start - h->length + pa->min_3_prime_overlap_of_junction)
3442             <= sa->primer_overlap_junctions[for_i])
3443         && ((h->start - pa->min_5_prime_overlap_of_junction + 1))
3444         > sa->primer_overlap_junctions[for_i]) {
3445       h->overlaps_overlap_position = 1;
3446       /* no need to continue checking */
3447       break;
3448     }
3449   }
3450 
3451   /* FIX ME FIXME Steve, is this really needed? */
3452   op_set_completely_written(h);
3453 
3454 } /* calc_and_check_oligo_features */
3455 #undef OUTSIDE_START_WT
3456 #undef INSIDE_START_WT
3457 #undef INSIDE_STOP_WT
3458 #undef OUTSIDE_STOP_WT
3459 
3460 /* Calculate the minimum sequence quality and the minimum sequence
3461    quality of the 3' end of a primer or oligo.  Set h->seq_quality
3462    and h->seq_end_quality with these values.  Return 1 (== ok)
3463    if sa->quality is undefined.  Otherwise, return 1 (ok)
3464    if h->seq_quality and h->seq_end_quality are within
3465    range, or else return 0.
3466 */
3467 static int
sequence_quality_is_ok(const p3_global_settings * pa,primer_rec * h,oligo_type l,const seq_args * sa,int j,int k,oligo_stats * global_oligo_stats,const args_for_one_oligo_or_primer * po_args)3468 sequence_quality_is_ok(const p3_global_settings *pa,
3469                        primer_rec *h,
3470                        oligo_type l,
3471                        const seq_args *sa,
3472                        int j, int k,
3473                        oligo_stats *global_oligo_stats,
3474                        const args_for_one_oligo_or_primer *po_args) {
3475   int i, min_q, min_q_end, m, q;
3476   int  retval = 1;
3477 
3478   if (NULL == sa->quality) {
3479     h->seq_end_quality = h->seq_quality = pa->quality_range_max;
3480     return 1;
3481   }
3482 
3483   q = pa->quality_range_max;
3484 
3485   min_q = po_args->min_quality;
3486   if (OT_LEFT == l || OT_RIGHT == l) {
3487     min_q_end = po_args->min_end_quality;
3488   }  else {
3489     min_q_end = min_q;
3490   }
3491 
3492   if (OT_LEFT == l || OT_INTL == l) {
3493 
3494     for(i = k-4; i <= k; i++) {
3495       if(i < j) continue;
3496       m = sa->quality[i + sa->incl_s];
3497       if (m < q) q = m;
3498     }
3499     min_q_end = q;
3500 
3501     for(i = j; i<=k-5; i++) {
3502       m = sa->quality[i + sa->incl_s];
3503       if (m < q) q = m;
3504     }
3505     min_q = q;
3506 
3507   } else if (OT_RIGHT == l) {
3508     for(i = j; i < j+5; i++) {
3509       if(i > k) break;
3510       m = sa->quality[i + sa->incl_s];
3511       if (m < q) q = m;
3512     }
3513     min_q_end = q;
3514 
3515     for(i = j+5; i <= k; i++) {
3516       m = sa->quality[i + sa->incl_s];
3517       if (m < q) q = m;
3518     }
3519     min_q = q;
3520   } else {
3521     PR_ASSERT(0); /* Programming error. */
3522   }
3523 
3524   h->seq_quality = min_q;
3525   h->seq_end_quality = min_q_end;
3526 
3527   if (h->seq_quality < po_args->min_quality) {
3528     op_set_low_sequence_quality(h);
3529     global_oligo_stats->seq_quality++;
3530     retval = 0;
3531     return retval;
3532   }
3533 
3534   if (OT_LEFT == l || OT_RIGHT == l) {
3535     if (h->seq_end_quality < po_args->min_end_quality) {
3536       op_set_low_end_sequence_quality(h);
3537       global_oligo_stats->seq_quality++;
3538       retval = 0;
3539     }
3540   }
3541   return retval;
3542 }
3543 
3544 /*
3545  * Set h->gc_content to the GC % of the 'len' bases starting at 'start' in
3546  * 'sequence' (excluding 'N's).  Set h->num_ns to the number of 'N's in that
3547  * subsequence.
3548  */
3549 static void
gc_and_n_content(int start,int len,const char * sequence,primer_rec * h)3550 gc_and_n_content(int start, int len,
3551                  const char *sequence,
3552                  primer_rec *h)
3553 {
3554   const char* p = &sequence[start];
3555   const char* stop = p + len;
3556   int num_gc = 0, num_gcat = 0, num_n = 0;
3557   while (p < stop) {
3558     if ('N' == *p)
3559       num_n++;
3560     else {
3561       num_gcat++;
3562       if ('C' == *p || 'G' == *p) num_gc++;
3563     }
3564     p++;
3565   }
3566   h->num_ns = num_n;
3567   if (0 == num_gcat) h->gc_content= 0.0;
3568   else h->gc_content = 100.0 * ((double)num_gc)/num_gcat;
3569 }
3570 
3571 static int
oligo_overlaps_interval(int start,int len,const interval_array_t intervals,int num_intervals)3572 oligo_overlaps_interval(int start,
3573                         int len,
3574                         const interval_array_t intervals,
3575                         int num_intervals)
3576 {
3577     int i;
3578     int last = start + len - 1;
3579     for (i = 0; i < num_intervals; i++)
3580         if (!(last < intervals[i][0]
3581               || start > (intervals[i][0] + intervals[i][1] - 1)))
3582             return 1;
3583     return 0;
3584 }
3585 
3586 /* Calculate the part of the objective function due to one primer. */
3587 static double
p_obj_fn(const p3_global_settings * pa,primer_rec * h,int j)3588 p_obj_fn(const p3_global_settings *pa,
3589          primer_rec *h,
3590          int  j) {
3591   double sum;
3592 
3593   sum = 0;
3594   if (j == OT_LEFT || j == OT_RIGHT) {
3595       if(pa->p_args.weights.temp_gt && h->temp > pa->p_args.opt_tm)
3596            sum += pa->p_args.weights.temp_gt * (h->temp - pa->p_args.opt_tm);
3597       if (pa->p_args.weights.temp_lt && h->temp < pa->p_args.opt_tm)
3598            sum += pa->p_args.weights.temp_lt * (pa->p_args.opt_tm - h->temp);
3599 
3600       if (pa->p_args.weights.gc_content_gt && h->gc_content > pa->p_args.opt_gc_content)
3601            sum += pa->p_args.weights.gc_content_gt
3602              * (h->gc_content - pa->p_args.opt_gc_content);
3603       if (pa->p_args.weights.gc_content_lt && h->gc_content < pa->p_args.opt_gc_content)
3604            sum += pa->p_args.weights.gc_content_lt
3605              * (pa->p_args.opt_gc_content - h->gc_content);
3606 
3607       if (pa->p_args.weights.length_lt && h->length < pa->p_args.opt_size)
3608            sum += pa->p_args.weights.length_lt * (pa->p_args.opt_size - h->length);
3609       if (pa->p_args.weights.length_gt && h->length > pa->p_args.opt_size)
3610            sum += pa->p_args.weights.length_gt * (h->length - pa->p_args.opt_size);
3611 
3612       /* BEGIN: secondary structures */
3613       if (pa->thermodynamic_oligo_alignment==0) {
3614 
3615 	if (pa->p_args.weights.compl_any)
3616            sum += pa->p_args.weights.compl_any * h->self_any;
3617 	if (pa->p_args.weights.compl_end)
3618            sum += pa->p_args.weights.compl_end * h->self_end;
3619 
3620       } else if (pa->thermodynamic_oligo_alignment==1) {
3621 
3622 	if (pa->p_args.weights.compl_any_th) {
3623 	  if ((h->temp - pa->p_args.weights.temp_cutoff) <= h->self_any)
3624 	    sum += pa->p_args.weights.compl_any_th
3625 	      * (h->self_any - (h->temp - pa->p_args.weights.temp_cutoff - 1.0)); /* -1.0 is added for the case where == */
3626 	  else
3627 	    sum += pa->p_args.weights.compl_any_th
3628 	      * (1/(h->temp - pa->p_args.weights.temp_cutoff + 1.0 - h->self_any));
3629 	}
3630 
3631 	if (pa->p_args.weights.compl_end_th) {
3632 	  if ((h->temp - pa->p_args.weights.temp_cutoff) <= h->self_end)
3633 	    sum += pa->p_args.weights.compl_end_th
3634 	      * (h->self_end - (h->temp - pa->p_args.weights.temp_cutoff - 1.0));
3635 	  else
3636 	    sum += pa->p_args.weights.compl_end_th
3637 	      * (1/(h->temp - pa->p_args.weights.temp_cutoff + 1.0 - h->self_end));
3638 	}
3639 
3640 	if (pa->p_args.weights.hairpin_th) {
3641 	  if ((h->temp - pa->p_args.weights.temp_cutoff) <= h->hairpin_th)
3642 	    sum += pa->p_args.weights.hairpin_th
3643 	      * (h->hairpin_th - (h->temp - pa->p_args.weights.temp_cutoff - 1.0));
3644 	  else
3645 	    sum += pa->p_args.weights.hairpin_th
3646 	      * (1/(h->temp - pa->p_args.weights.temp_cutoff + 1.0 - h->hairpin_th));
3647 	}
3648 
3649       } else {
3650 	PR_ASSERT(0)
3651 	  /* Programming error,
3652 	     illegal value for pa->thermodynamic_oligo_alignment */
3653       }
3654        /* END: secondary structures */
3655 
3656       if (pa->p_args.weights.num_ns)
3657            sum += pa->p_args.weights.num_ns * h->num_ns;
3658       if(pa->p_args.weights.repeat_sim)
3659            sum += pa->p_args.weights.repeat_sim
3660              * h->repeat_sim.score[h->repeat_sim.max];
3661       if (!bf_get_overlaps_target(h)) {
3662         /* We might be evaluating p_obj_fn with h->target if
3663            the client supplied 'pick_anyway' and specified
3664            a primer or oligo. */
3665         PR_ASSERT(!(bf_get_infinite_pos_penalty(h)));
3666         if(pa->p_args.weights.pos_penalty)
3667           sum += pa->p_args.weights.pos_penalty * h->position_penalty;
3668       }
3669       if(pa->p_args.weights.end_stability)
3670            sum += pa->p_args.weights.end_stability * h->end_stability;
3671 
3672       /* FIX ME QUALITY WT Change here */
3673       if(pa->p_args.weights.seq_quality)
3674            sum += pa->p_args.weights.seq_quality *
3675 	     (pa->quality_range_max - h->seq_quality);  /* Look for end seq quality */
3676 
3677       if (pa->p_args.weights.template_mispriming && pa->thermodynamic_template_alignment==0) {
3678         PR_ASSERT(oligo_max_template_mispriming(h) != ALIGN_SCORE_UNDEF);
3679         sum += pa->p_args.weights.template_mispriming *
3680           oligo_max_template_mispriming(h);
3681       }
3682 
3683       if (pa->p_args.weights.template_mispriming_th && pa->thermodynamic_template_alignment==1) {
3684 
3685 	PR_ASSERT(oligo_max_template_mispriming_thermod(h) != ALIGN_SCORE_UNDEF);
3686 
3687 	if((h->temp - pa->p_args.weights.temp_cutoff) <= oligo_max_template_mispriming_thermod(h))
3688 	  sum += pa->p_args.weights.template_mispriming_th *
3689 	    (oligo_max_template_mispriming_thermod(h) - (h->temp - pa->p_args.weights.temp_cutoff - 1.0));
3690 	if((h->temp - pa->p_args.weights.temp_cutoff) > oligo_max_template_mispriming_thermod(h))
3691 	  sum += pa->p_args.weights.template_mispriming_th *
3692 	    (1/(h->temp - pa->p_args.weights.temp_cutoff + 1.0 - oligo_max_template_mispriming_thermod(h)));
3693       }
3694       return sum;
3695   } else if (j == OT_INTL) {
3696       if(pa->o_args.weights.temp_gt && h->temp > pa->o_args.opt_tm)
3697          sum += pa->o_args.weights.temp_gt * (h->temp - pa->o_args.opt_tm);
3698       if(pa->o_args.weights.temp_lt && h->temp < pa->o_args.opt_tm)
3699          sum += pa->o_args.weights.temp_lt * (pa->o_args.opt_tm - h->temp);
3700 
3701       if(pa->o_args.weights.gc_content_gt && h->gc_content > pa->o_args.opt_gc_content)
3702            sum += pa->o_args.weights.gc_content_gt
3703              * (h->gc_content - pa->o_args.opt_gc_content);
3704       if(pa->o_args.weights.gc_content_lt && h->gc_content < pa->o_args.opt_gc_content)
3705            sum += pa->o_args.weights.gc_content_lt
3706              * (pa->o_args.opt_gc_content - h->gc_content);
3707 
3708       if(pa->o_args.weights.length_lt && h->length < pa->o_args.opt_size)
3709          sum += pa->o_args.weights.length_lt * (pa->o_args.opt_size - h->length);
3710       if(pa->o_args.weights.length_gt && h->length  > pa->o_args.opt_size)
3711          sum += pa->o_args.weights.length_gt * (h->length - pa->o_args.opt_size);
3712       if(pa->o_args.weights.compl_any && pa->thermodynamic_oligo_alignment==0)
3713          sum += pa->o_args.weights.compl_any * h->self_any;
3714       if(pa->o_args.weights.compl_end && pa->thermodynamic_oligo_alignment==0)
3715          sum += pa->o_args.weights.compl_end * h->self_end;
3716 
3717       /* begin thermodynamical approach */
3718       if (pa->thermodynamic_oligo_alignment==1) {
3719 
3720 	if (pa->o_args.weights.compl_any_th) {
3721 	  if ((h->temp - pa->o_args.weights.temp_cutoff) <= h->self_any)
3722 	    sum +=
3723 	      pa->o_args.weights.compl_any_th
3724 	      * (h->self_any - (h->temp - pa->o_args.weights.temp_cutoff - 1.0)); /* -1.0 is added for the case where == */
3725 	  else
3726 	    sum +=
3727 	      pa->o_args.weights.compl_any_th
3728 	      * (1/(h->temp - pa->o_args.weights.temp_cutoff + 1.0 - h->self_any));
3729 	}
3730 
3731 	if (pa->o_args.weights.compl_end_th) {
3732 	  if ((h->temp - pa->o_args.weights.temp_cutoff) <= h->self_end)
3733 	    sum +=
3734 	      pa->o_args.weights.compl_end_th
3735 	      * (h->self_end - (h->temp - pa->o_args.weights.temp_cutoff - 1.0));
3736 	  else
3737 	    sum +=
3738 	      pa->o_args.weights.compl_end_th
3739 	      * (1/(h->temp - pa->o_args.weights.temp_cutoff + 1.0 - h->self_end));
3740 	}
3741 
3742 	if (pa->o_args.weights.hairpin_th) {
3743 	  if ((h->temp - pa->o_args.weights.temp_cutoff) <= h->hairpin_th)
3744 	    sum += pa->o_args.weights.hairpin_th * (h->hairpin_th - (h->temp - pa->o_args.weights.temp_cutoff - 1.0));
3745 	  else
3746 	    sum += pa->o_args.weights.hairpin_th * (1/(h->temp - pa->o_args.weights.temp_cutoff + 1.0 - h->hairpin_th));
3747 	}
3748       }
3749       /* end thermodynamical approach */
3750 
3751       if(pa->o_args.weights.num_ns)
3752          sum += pa->o_args.weights.num_ns * h->num_ns;
3753       if(pa->o_args.weights.repeat_sim)
3754          sum += pa->o_args.weights.repeat_sim
3755            * h->repeat_sim.score[h->repeat_sim.max];
3756 
3757       /* FIX ME QUALITY WT */
3758       if(pa->o_args.weights.seq_quality)
3759          sum += pa->o_args.weights.seq_quality *
3760                      (pa->quality_range_max - h->seq_quality);
3761 
3762       return sum;
3763   } else {
3764     PR_ASSERT(0); /* Programmig error. */
3765   }
3766 }
3767 
3768 /* Return max of h->template_mispriming and h->template_mispriming_r (max
3769    template mispriming on either strand). */
3770 double
oligo_max_template_mispriming(const primer_rec * h)3771 oligo_max_template_mispriming(const primer_rec *h) {
3772    return h->template_mispriming > h->template_mispriming_r ?
3773      h->template_mispriming : h->template_mispriming_r;
3774 }
3775 
3776 double
oligo_max_template_mispriming_thermod(const primer_rec * h)3777 oligo_max_template_mispriming_thermod(const primer_rec *h) {
3778    return h->template_mispriming > h->template_mispriming_r ?
3779      h->template_mispriming : h->template_mispriming_r;
3780 }
3781 
3782 /* Sort a given primer array by penalty */
3783 static void
sort_primer_array(oligo_array * oligo)3784 sort_primer_array(oligo_array *oligo)
3785 {
3786   qsort(&oligo->oligo[0], oligo->num_elem, sizeof(*oligo->oligo),
3787         primer_rec_comp);
3788 }
3789 
3790 /* Compare function for sorting primer records. */
3791 static int
primer_rec_comp(const void * x1,const void * x2)3792 primer_rec_comp(const void *x1, const void *x2)
3793 {
3794   const primer_rec *a1 = (const primer_rec *) x1;
3795   const primer_rec *a2 = (const primer_rec *) x2;
3796 
3797   if(a1->quality < a2->quality) return -1;
3798   if (a1->quality > a2->quality) return 1;
3799 
3800   /*
3801    * We want primer_rec_comp to always return a non-0 result, because
3802    * different implementations of qsort differ in how they treat "equal"
3803    * elements, making it difficult to compare test output on different
3804    * systems.
3805    */
3806   if(a1->start > a2->start) return -1;
3807   if(a1->start < a2->start) return 1;
3808   if(a1->length < a2->length) return -1;
3809   return 1;
3810 }
3811 
3812 /* Compare function for sorting primer records. */
3813 static int
compare_primer_pair(const void * x1,const void * x2)3814 compare_primer_pair(const void *x1, const void *x2)
3815 {
3816   const primer_pair *a1 = (const primer_pair *) x1;
3817   const primer_pair *a2 = (const primer_pair *) x2;
3818   const double epsilon = 1e-6;
3819   int y1, y2;
3820 
3821   if ((a1->pair_quality + epsilon) < a2->pair_quality) return -1;
3822   if (a1->pair_quality > (a2->pair_quality + epsilon)) return 1;
3823 
3824   /*
3825    * The following statements ensure that we get a stable order that
3826    * is the same on all systems.
3827    */
3828 
3829   y1 = a1->left->start;
3830   y2 = a2->left->start;
3831   if (y1 > y2) return -1; /* prefer left primers to the right. */
3832   if (y1 < y2) return 1;
3833 
3834   y1 = a1->right->start;
3835   y2 = a2->right->start;
3836   if (y1 < y2) return -1; /* prefer right primers to the left. */
3837   if (y1 > y2) return 1;
3838 
3839   y1 = a1->left->length;
3840   y2 = a2->left->length;
3841   if (y1 < y2) return -1; /* prefer shorter primers. */
3842   if (y1 > y2) return 1;
3843 
3844   y1 = a1->right->length;
3845   y2 = a2->right->length;
3846   if (y1 < y2) return -1; /* prefer shorter primers. */
3847   if (y1 > y2) return 1;
3848 
3849   return 0;
3850 }
3851 
3852 /*
3853  * Defines parameter values for given primer pair. Returns PAIR_OK if the pair is
3854  * acceptable; PAIR_FAILED otherwise.  This function sets the
3855  * various elements of *ppair, and also calculates some key EXPENSIVE
3856  * parameters for individual primers if they have not been set yet.
3857  */
3858 static int
characterize_pair(p3retval * retval,const p3_global_settings * pa,const seq_args * sa,int m,int n,int int_num,primer_pair * ppair,const dpal_arg_holder * dpal_arg_to_use,const thal_arg_holder * thal_arg_to_use,int update_stats)3859 characterize_pair(p3retval *retval,
3860                   const p3_global_settings *pa,
3861                   const seq_args *sa,
3862                   int m, int n, int int_num,
3863                   primer_pair *ppair,
3864                   const dpal_arg_holder *dpal_arg_to_use,
3865                   const thal_arg_holder *thal_arg_to_use,
3866                   int update_stats) {
3867   char s1[MAX_PRIMER_LENGTH+1], s2[MAX_PRIMER_LENGTH+1],
3868     s1_rev[MAX_PRIMER_LENGTH+1], s2_rev[MAX_PRIMER_LENGTH+1];
3869   double compl_end;
3870   pair_stats *pair_expl = &retval->best_pairs.expl;
3871   int must_use = 0;
3872   double min_oligo_tm;
3873   int i;
3874   const thal_args *thal_args_for_template_mispriming
3875     = use_end_for_th_template_mispriming
3876     ? thal_arg_to_use->end1
3877     : thal_arg_to_use->any;
3878 
3879   memset(ppair, 0, sizeof(*ppair));
3880 
3881   ppair->left = &retval->fwd.oligo[m];
3882   ppair->right = &retval->rev.oligo[n];
3883   ppair->product_size = retval->rev.oligo[n].start - retval->fwd.oligo[m].start+1;
3884 
3885   ppair->target = 0;
3886   ppair->compl_any = ppair->compl_end = 0;
3887   if (update_stats) {
3888     pair_expl->considered++;
3889   }
3890 
3891   if (pa->primer_task == check_primers) {
3892     must_use = 1;
3893   }
3894 
3895   /* We must use the pair if the caller specifed
3896      both the left and the right primer. */
3897   if (ppair->left->must_use != 0 &&
3898       ppair->right->must_use != 0) {
3899 
3900     /* But if caller specified primers are in
3901        reversed order we cannot analyze them
3902        as a pair. */
3903     if (ppair->product_size < 1) {
3904       pair_expl->reversed++;
3905       return PAIR_FAILED;
3906     }
3907 
3908     must_use = 1;
3909   }
3910 
3911   ppair->must_use = must_use;
3912 
3913   if (sa->tar2.count > 0) {
3914     if (pair_spans_target(ppair, sa)) {
3915       ppair->target = 1;
3916     } else {
3917       ppair->target = -1;
3918       if (update_stats) { pair_expl->target++; }
3919       if (!must_use) return PAIR_FAILED;
3920     }
3921   }
3922 
3923   /* ============================================================= */
3924 
3925   /* Check that the pair is included in one of the specified ok regions */
3926   if ((sa->ok_regions.count > 0) && (!sa->ok_regions.any_pair)) {
3927     int included = 0;
3928     int l_start = ppair->left->start, l_end = ppair->left->start + ppair->left->length - 1;
3929     int r_start = ppair->right->start - ppair->right->length + 1, r_end = ppair->right->start;
3930     for (i=0; i<sa->ok_regions.count; i++) {
3931       if (sa->ok_regions.left_pairs[i][0] == -1) {
3932         /* any left primer, check right primer */
3933         if ((r_start >= sa->ok_regions.right_pairs[i][0]) &&
3934             (r_end <= sa->ok_regions.right_pairs[i][0] + sa->ok_regions.right_pairs[i][1] - 1)) {
3935           included = 1;
3936           break;
3937         }
3938       } else if (sa->ok_regions.right_pairs[i][0] == -1) {
3939         /* any right primer, check the left primer */
3940         if ((l_start >= sa->ok_regions.left_pairs[i][0]) &&
3941             (l_end <= sa->ok_regions.left_pairs[i][0] + sa->ok_regions.left_pairs[i][1] - 1)) {
3942           included = 1;
3943           break;
3944         }
3945       } else {
3946         /* check both primers */
3947         if ((l_start >= sa->ok_regions.left_pairs[i][0]) &&
3948             (l_end <= sa->ok_regions.left_pairs[i][0] + sa->ok_regions.left_pairs[i][1] - 1) &&
3949             (r_start >= sa->ok_regions.right_pairs[i][0]) &&
3950             (r_end <= sa->ok_regions.right_pairs[i][0] + sa->ok_regions.right_pairs[i][1] - 1)) {
3951           included = 1;
3952           break;
3953         }
3954       }
3955     }
3956     if (!included) {
3957       if (update_stats) { pair_expl->not_in_any_ok_region++; }
3958       if (!must_use) return PAIR_FAILED;
3959     }
3960   }
3961 
3962   /* ============================================================= */
3963   /* Compute product Tm and related parameters; check constraints. */
3964 
3965   if (ppair->right->start - ppair->left->start + 1 <= 0) {
3966     fprintf(stderr, "temporary");
3967   }
3968   PR_ASSERT(ppair->right->start - ppair->left->start + 1 > 0)
3969   ppair->product_tm
3970     = long_seq_tm(sa->trimmed_seq, ppair->left->start,
3971                   ppair->right->start - ppair->left->start + 1,
3972                   /* TO DO -- skewed, it would be better to not use p_args elements here */
3973                   pa->p_args.salt_conc,
3974                   pa->p_args.divalent_conc,
3975                   pa->p_args.dntp_conc);
3976 
3977   PR_ASSERT(ppair->product_tm != OLIGOTM_ERROR);
3978 
3979   min_oligo_tm
3980     = ppair->left->temp > ppair->right->temp ? ppair->right->temp : ppair->left->temp;
3981   ppair->product_tm_oligo_tm_diff = ppair->product_tm - min_oligo_tm;
3982   ppair->t_opt_a  = 0.3 * min_oligo_tm + 0.7 * ppair->product_tm - 14.9;
3983 
3984   if (pa->product_min_tm != PR_DEFAULT_PRODUCT_MIN_TM
3985       && ppair->product_tm < pa->product_min_tm) {
3986     if (update_stats) { pair_expl->low_tm++; }
3987     if (!must_use) return PAIR_FAILED;
3988   }
3989 
3990   if (pa->product_max_tm != PR_DEFAULT_PRODUCT_MAX_TM
3991       && ppair->product_tm > pa->product_max_tm) {
3992     if (update_stats) { pair_expl->high_tm++; }
3993     if (!must_use) return PAIR_FAILED;
3994   }
3995 
3996   ppair->diff_tm = fabs(retval->fwd.oligo[m].temp - retval->rev.oligo[n].temp);
3997   if (ppair->diff_tm > pa->max_diff_tm) {
3998     if (update_stats) { pair_expl->temp_diff++; }
3999     if (!must_use) return PAIR_FAILED;
4000   }
4001 
4002   /* End of product-temperature related computations. */
4003   /* ============================================================= */
4004 
4005 
4006   /* ============================================================= */
4007   /* BEGIN "EXPENSIVE" computations on _individual_ primers
4008      in the pair.  These have been postponed until
4009      this point in the interests of efficiency.
4010   */
4011 
4012   /* ============================================================= */
4013   /* Estimate secondary structure and primer-dimer of _individual_
4014      primers if not already calculated. */
4015 
4016   /* s1 is the forward oligo. */
4017   _pr_substr(sa->trimmed_seq,
4018              retval->fwd.oligo[m].start,
4019              retval->fwd.oligo[m].length,
4020              s1);
4021 
4022   /* s2 is the reverse oligo. */
4023   _pr_substr(sa->trimmed_seq,
4024              retval->rev.oligo[n].start - retval->rev.oligo[n].length + 1,
4025              retval->rev.oligo[n].length,
4026              s2);
4027 
4028   p3_reverse_complement(s1, s1_rev);
4029   p3_reverse_complement(s2, s2_rev);
4030 
4031 
4032   if (retval->fwd.oligo[m].self_any == ALIGN_SCORE_UNDEF
4033       && pa->thermodynamic_oligo_alignment==0) {
4034     /* We have not yet computed the 'self_any' paramter,
4035        which is an estimate of self primer-dimer and secondary
4036        structure propensity. */
4037     oligo_compl(&retval->fwd.oligo[m], &pa->p_args,
4038                 &retval->fwd.expl, dpal_arg_to_use, s1, s1_rev);
4039 
4040     if (!OK_OR_MUST_USE(&retval->fwd.oligo[m])) {
4041       pair_expl->considered--;
4042       if (!must_use) return PAIR_FAILED;
4043     }
4044   }
4045    /* Thermodynamic approach, fwd-primer */
4046    if (retval->fwd.oligo[m].self_any == ALIGN_SCORE_UNDEF
4047        && pa->thermodynamic_oligo_alignment==1) {
4048       oligo_compl_thermod(&retval->fwd.oligo[m], &pa->p_args,
4049                           &retval->fwd.expl, thal_arg_to_use, s1, s1); /* ! s1, s1_rev */
4050 
4051       if (!OK_OR_MUST_USE(&retval->fwd.oligo[m])) {
4052          pair_expl->considered--;
4053          if (!must_use) return PAIR_FAILED;
4054       }
4055    }
4056    if (retval->fwd.oligo[m].hairpin_th == ALIGN_SCORE_UNDEF
4057        && pa->thermodynamic_oligo_alignment==1) {
4058       oligo_hairpin(&retval->fwd.oligo[m], &pa->p_args,
4059                           &retval->fwd.expl, thal_arg_to_use, s1);
4060       if (!OK_OR_MUST_USE(&retval->fwd.oligo[m])) {
4061          pair_expl->considered--;
4062          if (!must_use) return PAIR_FAILED;
4063       }
4064    }
4065 
4066    /* End of thermodynamic approach */
4067 
4068   if (retval->rev.oligo[n].self_any == ALIGN_SCORE_UNDEF && pa->thermodynamic_oligo_alignment==0) {
4069     oligo_compl(&retval->rev.oligo[n], &pa->p_args,
4070                 &retval->rev.expl, dpal_arg_to_use, s2_rev, s2);
4071 
4072     if (!OK_OR_MUST_USE(&retval->rev.oligo[n])) {
4073       pair_expl->considered--;
4074       if (!must_use) return PAIR_FAILED;
4075     }
4076   }
4077    /* Thermodynamic approach */
4078    if (retval->rev.oligo[n].self_any == ALIGN_SCORE_UNDEF && pa->thermodynamic_oligo_alignment==1) {
4079       oligo_compl_thermod(&retval->rev.oligo[n], &pa->p_args,
4080                           &retval->rev.expl, thal_arg_to_use, s2_rev, s2_rev); /* s2_rev, s2 */
4081 
4082       if (!OK_OR_MUST_USE(&retval->rev.oligo[n])) {
4083          pair_expl->considered--;
4084          if (!must_use) return PAIR_FAILED;
4085       }
4086    }
4087    if (retval->rev.oligo[n].hairpin_th == ALIGN_SCORE_UNDEF && pa->thermodynamic_oligo_alignment==1) {
4088       oligo_hairpin(&retval->rev.oligo[n], &pa->p_args,
4089                     &retval->rev.expl, thal_arg_to_use, s2_rev);
4090       if (!OK_OR_MUST_USE(&retval->rev.oligo[n])) {
4091          pair_expl->considered--;
4092          if (!must_use) return PAIR_FAILED;
4093       }
4094    }
4095 
4096    /* End of thermodynamic approach */
4097   /* End of secondary structure and primer-dimer of _individual_
4098      primers. */
4099   /* ============================================================= */
4100 
4101 
4102   /* ============================================================= */
4103   /* Mispriming of _individual_ primers to template and
4104      to repeat libraries. */
4105 
4106   if (retval->fwd.oligo[m].repeat_sim.score == NULL) {
4107     /* We have not yet checked the oligo against the repeat library. */
4108     oligo_repeat_library_mispriming(&retval->fwd.oligo[m], pa, sa, OT_LEFT,
4109                                     &retval->fwd.expl,dpal_arg_to_use);
4110     if (OK_OR_MUST_USE(&retval->fwd.oligo[m])) {
4111       oligo_template_mispriming(&retval->fwd.oligo[m], pa, sa, OT_LEFT,
4112 				&retval->fwd.expl,
4113 				dpal_arg_to_use->local_end,
4114 				thal_args_for_template_mispriming);
4115     }
4116     if (!OK_OR_MUST_USE(&retval->fwd.oligo[m])) {
4117       pair_expl->considered--;
4118       if (!must_use) return PAIR_FAILED;
4119     }
4120   }
4121 
4122   if (retval->rev.oligo[n].repeat_sim.score == NULL) {
4123     oligo_repeat_library_mispriming(&retval->rev.oligo[n], pa, sa, OT_RIGHT,
4124                                     &retval->rev.expl, dpal_arg_to_use);
4125     if (OK_OR_MUST_USE(&retval->rev.oligo[n])) {
4126       oligo_template_mispriming(&retval->rev.oligo[n], pa, sa, OT_RIGHT,
4127 				&retval->rev.expl,
4128 				dpal_arg_to_use->local_end,
4129 				thal_args_for_template_mispriming);
4130     }
4131     if (!OK_OR_MUST_USE(&retval->rev.oligo[n])) {
4132       pair_expl->considered--;
4133       if (!must_use) return PAIR_FAILED;
4134     }
4135   }
4136 
4137   /* End of mispriming of _individual_ primers to template and
4138      to repeat libraries. */
4139   /* ============================================================= */
4140 
4141 
4142   /* ============================================================= */
4143   /*
4144    * Similarity between s1 and s2 is equivalent to complementarity between
4145    * s2's complement and s1.  (Both s1 and s2 are taken from the same strand.)
4146    */
4147    if(pa->thermodynamic_oligo_alignment==0) {
4148       ppair->compl_any = align(s1, s2, dpal_arg_to_use->local);
4149       if (ppair->compl_any > pa->pair_compl_any) {
4150          if (update_stats) { pair_expl->compl_any++; }
4151          if (!must_use) return PAIR_FAILED;
4152       }
4153 
4154       ppair->compl_end = align(s1, s2, dpal_arg_to_use->end);
4155       if (ppair->compl_end > pa->pair_compl_end) {
4156          if (update_stats) { pair_expl->compl_end++; }
4157          if (!must_use) return PAIR_FAILED;
4158       }
4159    } else {
4160       /* thermodynamical approach */
4161       ppair->compl_any = align_thermod(s1, s2_rev, thal_arg_to_use->any);
4162       if (ppair->compl_any > pa->pair_compl_any_th) {
4163          if (update_stats) {
4164             pair_expl->compl_any++;
4165          }
4166          if (!must_use) return PAIR_FAILED;
4167       }
4168       ppair->compl_end = align_thermod(s1, s2_rev, thal_arg_to_use->end1);
4169       compl_end        = align_thermod(s1, s2_rev, thal_arg_to_use->end2); /* Triinu Please check */
4170       if (ppair->compl_end < compl_end) {
4171          ppair->compl_end = compl_end;
4172       }
4173       if (ppair->compl_end > pa->pair_compl_end_th) {
4174          if (update_stats) {
4175             pair_expl->compl_end++;
4176          }
4177          if (!must_use) return PAIR_FAILED;
4178       }
4179    }
4180 
4181   /*
4182    * It is conceivable (though unlikely) that
4183    * align(s2_rev, s1_rev, end_args) > align(s1,s2,end_args).
4184    */
4185   if (pa->thermodynamic_oligo_alignment==0 && (compl_end = align(s2_rev, s1_rev, dpal_arg_to_use->end))
4186       > ppair->compl_end) {
4187     if (compl_end > pa->p_args.max_self_end) {
4188       if (update_stats) { pair_expl->compl_end++; }
4189       if (!must_use) return PAIR_FAILED;
4190     }
4191     ppair->compl_end = compl_end;
4192   }
4193 
4194   if ((ppair->repeat_sim = pair_repeat_sim(ppair, pa))
4195       > pa->pair_repeat_compl) {
4196     if (update_stats) { pair_expl->repeat_sim++; }
4197     if (!must_use) return PAIR_FAILED;
4198   }
4199    /* thermodynamic approach */
4200    if (pa->thermodynamic_oligo_alignment==1 &&
4201        ((compl_end = align_thermod(s2, s1_rev, thal_arg_to_use->end1)) > ppair->compl_end ||
4202 	(compl_end = align_thermod(s2, s1_rev, thal_arg_to_use->end2)) > ppair->compl_end)) {
4203       if (compl_end > pa->p_args.max_self_end_th) {
4204          if (update_stats) {
4205             pair_expl->compl_end++;
4206          }
4207          if (!must_use) return PAIR_FAILED;
4208       }
4209       ppair->compl_end = compl_end;
4210    }
4211 
4212   /* ============================================================= */
4213 
4214 
4215   /* ============================================================= */
4216   /* Calculate _pair_ mispriming, if necessary. */
4217 
4218    if (pa->thermodynamic_template_alignment == 0) {
4219      if (!_pr_need_pair_template_mispriming(pa))
4220         ppair->template_mispriming = ALIGN_SCORE_UNDEF;
4221      else {
4222         PR_ASSERT(ppair->left->template_mispriming != ALIGN_SCORE_UNDEF);
4223         PR_ASSERT(ppair->left->template_mispriming_r != ALIGN_SCORE_UNDEF);
4224         PR_ASSERT(ppair->right->template_mispriming != ALIGN_SCORE_UNDEF);
4225         PR_ASSERT(ppair->right->template_mispriming_r != ALIGN_SCORE_UNDEF);
4226         ppair->template_mispriming =
4227            ppair->left->template_mispriming + ppair->right->template_mispriming_r;
4228         if ((ppair->left->template_mispriming_r + ppair->right->template_mispriming)
4229              > ppair->template_mispriming)
4230            ppair->template_mispriming
4231            = ppair->left->template_mispriming_r + ppair->right->template_mispriming;
4232 
4233         if (pa->pair_max_template_mispriming >= 0.0
4234              && ppair->template_mispriming > pa->pair_max_template_mispriming) {
4235             if (update_stats) { pair_expl->template_mispriming++; }
4236             if (!must_use) return PAIR_FAILED;
4237         }
4238      }
4239    } else { /* thermodynamic approach */
4240      if (!_pr_need_pair_template_mispriming_thermod(pa))
4241        ppair->template_mispriming = ALIGN_SCORE_UNDEF;
4242      else {
4243        PR_ASSERT(ppair->left->template_mispriming != ALIGN_SCORE_UNDEF);
4244        PR_ASSERT(ppair->left->template_mispriming_r != ALIGN_SCORE_UNDEF);
4245        PR_ASSERT(ppair->right->template_mispriming != ALIGN_SCORE_UNDEF);
4246        PR_ASSERT(ppair->right->template_mispriming_r != ALIGN_SCORE_UNDEF);
4247        ppair->template_mispriming =
4248            ppair->left->template_mispriming + ppair->right->template_mispriming_r;
4249        if ((ppair->left->template_mispriming_r + ppair->right->template_mispriming)
4250              > ppair->template_mispriming)
4251            ppair->template_mispriming
4252            = ppair->left->template_mispriming_r + ppair->right->template_mispriming;
4253 
4254        if (pa->pair_max_template_mispriming_th
4255            && ppair->template_mispriming > pa->pair_max_template_mispriming_th) {
4256             if (update_stats) {
4257                pair_expl->template_mispriming++;
4258             }
4259             if (!must_use) return PAIR_FAILED;
4260        }
4261      }
4262    }
4263 
4264    /* End of calculating _pair_ mispriming if necessary. */
4265    /* ============================================================= */
4266 
4267   return PAIR_OK;
4268 } /* characterize_pair */
4269 
4270 
4271 /*
4272  */
4273 void
compute_position_penalty(const p3_global_settings * pa,const seq_args * sa,primer_rec * h,oligo_type o_type)4274 compute_position_penalty(const p3_global_settings *pa,
4275                          const seq_args *sa,
4276                          primer_rec *h,
4277                          oligo_type o_type)
4278 {
4279   int three_prime_base;
4280   int inside_flag = 0;
4281   int target_begin, target_end;
4282 
4283   PR_ASSERT(OT_LEFT == o_type || OT_RIGHT == o_type);
4284   PR_ASSERT(1 == sa->tar2.count);
4285   target_begin = sa->tar2.pairs[0][0];
4286   target_end = target_begin + sa->tar2.pairs[0][1] - 1;
4287 
4288   three_prime_base = OT_LEFT == o_type
4289     ? h->start + h->length - 1 : h->start - h->length + 1;
4290   bf_set_infinite_pos_penalty(h,1);
4291   h->position_penalty = 0.0;
4292 
4293   if (OT_LEFT == o_type) {
4294     if (three_prime_base <= target_end) {
4295       bf_set_infinite_pos_penalty(h,0);
4296       if (three_prime_base < target_begin)
4297         h->position_penalty = target_begin - three_prime_base - 1;
4298       else {
4299         h->position_penalty = three_prime_base - target_begin + 1;
4300         inside_flag = 1;
4301       }
4302     }
4303   } else { /* OT_RIGHT == o_type */
4304     if (three_prime_base >= target_begin) {
4305       bf_set_infinite_pos_penalty(h,0);
4306       if (three_prime_base > target_end) {
4307         h->position_penalty = three_prime_base - target_end - 1;
4308       } else {
4309         h->position_penalty = target_end - three_prime_base + 1;
4310         inside_flag = 1;
4311       }
4312     }
4313   }
4314   if (!inside_flag)
4315     h->position_penalty *= pa->outside_penalty;
4316   else {
4317     h->position_penalty *= pa->inside_penalty;
4318   }
4319 }
4320 
4321 /*
4322  * Return 1 if 'pair' spans any target (in sa->tar); otherwise return 0; An
4323  * oligo pair spans a target, t, if the last base of the left primer is to
4324  * left of the last base of t and the first base of the right primer is to
4325  * the right of the first base of t.  Of course the primers must
4326  * still be in a legal position with respect to each other.
4327  */
4328 static int
pair_spans_target(const primer_pair * pair,const seq_args * sa)4329 pair_spans_target(const primer_pair *pair, const seq_args *sa)
4330 {
4331   int i;
4332   int last_of_left = pair->left->start + pair->left->length - 1;
4333   int first_of_right = pair->right->start - pair->right->length + 1;
4334   int target_first, target_last;
4335   for (i = 0; i < sa->tar2.count; i++) {
4336     target_first = sa->tar2.pairs[i][0];
4337     target_last = target_first + sa->tar2.pairs[i][1] - 1;
4338     if (last_of_left <= target_last
4339         && first_of_right >= target_first
4340         && last_of_left < first_of_right)
4341       return 1;
4342   }
4343   return 0;
4344 }
4345 
4346 /*
4347  * Return the value of the objective function value for given primer pair.
4348  * We must know that the pair is acceptable before calling obj_fn.
4349  */
4350 static double
obj_fn(const p3_global_settings * pa,primer_pair * h)4351 obj_fn(const p3_global_settings *pa, primer_pair *h)
4352 {
4353   double sum;
4354   double lower_tm;
4355 
4356   sum = 0.0;
4357   lower_tm = h->right->temp;
4358   if(h->left->temp < h->right->temp) lower_tm = h->left->temp;
4359 
4360   if(pa->pr_pair_weights.primer_quality)   /*  HERE 1 */
4361     sum += pa->pr_pair_weights.primer_quality * (h->left->quality + h->right->quality);
4362 
4363   if(pa->pr_pair_weights.io_quality && pa->pick_right_primer
4364      && pa->pick_left_primer && pa->pick_internal_oligo)
4365     sum += pa->pr_pair_weights.io_quality * h->intl->quality;
4366 
4367   if(pa->pr_pair_weights.diff_tm)
4368     sum += pa->pr_pair_weights.diff_tm * h->diff_tm;
4369 
4370   if (pa->thermodynamic_oligo_alignment==0) {
4371     if (pa->pr_pair_weights.compl_any)
4372       sum += pa->pr_pair_weights.compl_any * h->compl_any;
4373     if (pa->pr_pair_weights.compl_end)
4374       sum += pa->pr_pair_weights.compl_end * h->compl_end;
4375   } else if (pa->thermodynamic_oligo_alignment==1) {
4376 
4377     if (pa->pr_pair_weights.compl_any_th && ((lower_tm - pa->pr_pair_weights.temp_cutoff) <= h->compl_any))
4378       sum += pa->pr_pair_weights.compl_any_th * (h->compl_any - (lower_tm - pa->pr_pair_weights.temp_cutoff - 1.0));
4379     if (pa->pr_pair_weights.compl_any_th && ((lower_tm - pa->pr_pair_weights.temp_cutoff) > h->compl_any))
4380       sum += pa->pr_pair_weights.compl_any_th * (1/(lower_tm - pa->pr_pair_weights.temp_cutoff + 1.0 - h->compl_any));
4381 
4382     if (pa->pr_pair_weights.compl_end_th && ((lower_tm - pa->pr_pair_weights.temp_cutoff) <= h->compl_end))
4383       sum += pa->pr_pair_weights.compl_end_th * (h->compl_end - (lower_tm - pa->pr_pair_weights.temp_cutoff - 1.0));
4384     if (pa->pr_pair_weights.compl_end_th && ((lower_tm - pa->pr_pair_weights.temp_cutoff) > h->compl_end))
4385       sum += pa->pr_pair_weights.compl_end_th * (1/(lower_tm - pa->pr_pair_weights.temp_cutoff + 1.0 - h->compl_end));
4386   } else {
4387     PR_ASSERT(0);
4388     /* Programming error */
4389   }
4390 
4391   if(pa->pr_pair_weights.product_tm_lt && h->product_tm < pa->product_opt_tm)
4392     sum += pa->pr_pair_weights.product_tm_lt *
4393       (pa->product_opt_tm - h->product_tm);
4394 
4395   if(pa->pr_pair_weights.product_tm_gt && h->product_tm > pa->product_opt_tm)
4396     sum += pa->pr_pair_weights.product_tm_gt *
4397       (h->product_tm - pa->product_opt_tm);
4398 
4399   if(pa->pr_pair_weights.product_size_lt &&
4400      h->product_size < pa->product_opt_size)
4401     sum += pa->pr_pair_weights.product_size_lt *
4402       (pa->product_opt_size - h->product_size);
4403 
4404   if(pa->pr_pair_weights.product_size_gt &&
4405      h->product_size > pa->product_opt_size)
4406     sum += pa->pr_pair_weights.product_size_gt *
4407       (h->product_size - pa->product_opt_size);
4408 
4409   if(pa->pr_pair_weights.repeat_sim)
4410     sum += pa->pr_pair_weights.repeat_sim * h->repeat_sim;
4411 
4412   if (pa->pr_pair_weights.template_mispriming && pa->thermodynamic_template_alignment==0) {
4413     PR_ASSERT(pa->pr_pair_weights.template_mispriming >= 0.0);
4414     PR_ASSERT(h->template_mispriming >= 0.0);
4415     sum += pa->pr_pair_weights.template_mispriming * h->template_mispriming;
4416   }
4417   if (pa->pr_pair_weights.template_mispriming_th && pa->thermodynamic_template_alignment==1) {
4418       PR_ASSERT(pa->pr_pair_weights.template_mispriming_th >= 0.0);
4419       PR_ASSERT(h->template_mispriming >= 0.0);
4420       if((lower_tm - pa->pr_pair_weights.temp_cutoff) <= h->template_mispriming)
4421         sum += pa->pr_pair_weights.template_mispriming_th *
4422         (h->template_mispriming - (lower_tm - pa->pr_pair_weights.temp_cutoff - 1.0));
4423       if((lower_tm - pa->pr_pair_weights.temp_cutoff) > h->template_mispriming)
4424         sum += pa->pr_pair_weights.template_mispriming_th *
4425         (1/(lower_tm - pa->pr_pair_weights.temp_cutoff + 1.0 - h->template_mispriming));
4426    }
4427    PR_ASSERT(sum >= 0.0);
4428    return sum;
4429 }
4430 
4431 static double
align(const char * s1,const char * s2,const dpal_args * a)4432 align(const char *s1,
4433       const char *s2,
4434       const dpal_args *a) {
4435    dpal_results r;
4436    if(a->flag == DPAL_LOCAL || a->flag == DPAL_LOCAL_END) {
4437     if (strlen(s2) < 3) {
4438       /* For extremely short alignments we simply
4439          max out the score, because the dpal subroutines
4440          for these cannot handle this case.
4441          TO DO: this can probably be corrected in dpal. */
4442       return strlen(s2);
4443     }
4444   }
4445   dpal((const unsigned char *) s1, (const unsigned char *) s2, a, &r);
4446   PR_ASSERT(r.score <= SHRT_MAX);
4447   if (r.score == DPAL_ERROR_SCORE) {
4448     /* There was an error. */
4449     if (errno == ENOMEM) {
4450       longjmp(_jmp_buf, 1);
4451     } else {
4452       /* This branch is taken only if there is a programming error, in
4453          that s1 or s2 were NULL or contained an illegal character. We
4454          try to print some debugging information before aborting. */
4455       fprintf(stderr, "%s", r.msg);
4456       /* Always false, causes an abort: */
4457       PR_ASSERT(r.score != DPAL_ERROR_SCORE);
4458     }
4459   }
4460   return ((r.score < 0.0) ? 0.0 : r.score / PR_ALIGN_SCORE_PRECISION);
4461 }
4462 
4463 /* Helper function */
4464 static int
_set_string(char ** loc,const char * new_string)4465 _set_string(char **loc, const char *new_string) {
4466   if (*loc) {
4467     free(*loc);
4468   }
4469   if (!(*loc = (char *) malloc(strlen(new_string) + 1)))
4470     return 1; /* ENOMEM */
4471   strcpy(*loc, new_string);
4472   return 0;
4473 }
4474 
4475 static double
align_thermod(const char * s1,const char * s2,const thal_args * a)4476 align_thermod(const char *s1,
4477               const char *s2,
4478               const thal_args *a)
4479 {
4480    int thal_trace=0;
4481    thal_results r;
4482    thal((const unsigned char *) s1, (const unsigned char *) s2, a, &r);
4483    if (thal_trace) {
4484      fprintf(stdout,
4485 	     "thal, thal_args, type=%d maxLoop=%d mv=%f dv=%f "
4486 	     "dntp=%f dna_conc=%f, temp=%f, temponly=%d dimer=%d\n",
4487 	     a->type, a->maxLoop, a->mv, a->dv, a->dntp, a->dna_conc,
4488 	     a->temp, a->temponly, a->dimer);
4489      fprintf(stdout,
4490 	     "thal: s1=%s s2=%s temp=%f msg=%s end1=%d end2=%d\n",
4491 	     s1, s2, r.temp, r.msg, r.align_end_1, r.align_end_2);
4492    }
4493    PR_ASSERT(r.temp <= DBL_MAX);
4494    if (r.temp == THAL_ERROR_SCORE)
4495      {
4496         /* There was an error. */
4497         if (errno == ENOMEM) {
4498 	  longjmp(_jmp_buf, 1);
4499 	} else {
4500 	  /* This branch is taken if there is an error other than
4501 	     ENOMEM, in which case we treat it as a per sequence error.
4502 	  */
4503 	  /* Save the error string */
4504 	  if (!_set_string(&thermodynamic_alignment_length_error_msg, r.msg)) {
4505 	    thermodynamic_alignment_length_error = 1;
4506 	  }
4507 	  longjmp(_jmp_buf, 1);
4508 	}
4509      }
4510    return ((r.temp < 0.0) ? 0.0 : (double) (r.temp));
4511 }
4512 
4513 /* Return the sequence of oligo in
4514    a ****static***** buffer.  The
4515    sequence returned is changed at the
4516    next call to pr_oligo_sequence. */
4517 char *
pr_oligo_sequence(const seq_args * sa,const primer_rec * oligo)4518 pr_oligo_sequence(const seq_args *sa,
4519     const primer_rec *oligo)
4520 {
4521   static char s[MAX_PRIMER_LENGTH+1];
4522   int seq_len;
4523   PR_ASSERT(NULL != sa);
4524   PR_ASSERT(NULL != oligo);
4525   seq_len = strlen(sa->sequence);
4526   PR_ASSERT(oligo->start + sa->incl_s >= 0);
4527   PR_ASSERT(oligo->start + sa->incl_s + oligo->length <= seq_len);
4528   _pr_substr(sa->sequence, sa->incl_s + oligo->start, oligo->length, s);
4529   return &s[0];
4530 }
4531 
4532 char *
pr_oligo_rev_c_sequence(const seq_args * sa,const primer_rec * o)4533 pr_oligo_rev_c_sequence(const seq_args *sa,
4534     const primer_rec *o)
4535 {
4536   static char s[MAX_PRIMER_LENGTH+1], s1[MAX_PRIMER_LENGTH+1];
4537   int seq_len, start;
4538   PR_ASSERT(NULL != sa);
4539   PR_ASSERT(NULL != o);
4540   seq_len = strlen(sa->sequence);
4541   start = sa->incl_s + o->start - o->length + 1;
4542   PR_ASSERT(start >= 0);
4543   PR_ASSERT(start + o->length <= seq_len);
4544   _pr_substr(sa->sequence, start, o->length, s);
4545   p3_reverse_complement(s,s1);
4546   return &s1[0];
4547 }
4548 
4549 /* Calculate self complementarity (both h->self_any and h->self_end)
4550    which we use as an approximation for both secondary structure and
4551    self primer-dimer. */
4552 static void
oligo_compl(primer_rec * h,const args_for_one_oligo_or_primer * po_args,oligo_stats * ostats,const dpal_arg_holder * dpal_arg_to_use,const char * oligo_seq,const char * revc_oligo_seq)4553 oligo_compl(primer_rec *h,
4554               const args_for_one_oligo_or_primer *po_args,
4555               oligo_stats *ostats,
4556               const dpal_arg_holder *dpal_arg_to_use,
4557               const char *oligo_seq,
4558               const char *revc_oligo_seq)
4559 {
4560    PR_ASSERT(h != NULL);
4561 
4562    h->self_any = align(oligo_seq, revc_oligo_seq, dpal_arg_to_use->local);
4563    if (h->self_any > po_args->max_self_any) {
4564       op_set_high_self_any(h);
4565       ostats->compl_any++;
4566       ostats->ok--;
4567       if (!h->must_use) return;
4568    }
4569 
4570    h->self_end = align(oligo_seq, revc_oligo_seq, dpal_arg_to_use->end);
4571    if (h->self_end > po_args->max_self_end) {
4572       op_set_high_self_end(h);
4573       ostats->compl_end++;
4574       ostats->ok--;
4575       if (!h->must_use) return;
4576    }
4577 }
4578 
4579 static void
oligo_compl_thermod(primer_rec * h,const args_for_one_oligo_or_primer * po_args,oligo_stats * ostats,const thal_arg_holder * thal_arg_to_use,const char * oligo_seq,const char * revc_oligo_seq)4580 oligo_compl_thermod(primer_rec *h,
4581                     const args_for_one_oligo_or_primer *po_args,
4582                     oligo_stats *ostats,
4583                     const thal_arg_holder *thal_arg_to_use,
4584                     const char *oligo_seq,
4585                     const char *revc_oligo_seq)
4586 {
4587 
4588    PR_ASSERT(h != NULL);
4589    h->self_any = align_thermod(oligo_seq, revc_oligo_seq, thal_arg_to_use->any);
4590    if(h->self_any > po_args->max_self_any_th) {
4591       op_set_high_self_any(h);
4592       ostats->compl_any++;
4593       ostats->ok--;
4594       if (!h->must_use) return;
4595    }
4596    h->self_end = align_thermod(oligo_seq, revc_oligo_seq, thal_arg_to_use->end1);
4597    if(h->self_end > po_args->max_self_end_th){
4598       op_set_high_self_end(h);
4599       ostats->compl_end++;
4600       ostats->ok--;
4601       if (!h->must_use) return;
4602    }
4603 }
4604 
4605 static void
oligo_hairpin(primer_rec * h,const args_for_one_oligo_or_primer * po_args,oligo_stats * ostats,const thal_arg_holder * thal_arg_to_use,const char * oligo_seq)4606 oligo_hairpin(primer_rec *h,
4607               const args_for_one_oligo_or_primer *po_args,
4608               oligo_stats *ostats,
4609               const thal_arg_holder *thal_arg_to_use,
4610               const char *oligo_seq)
4611 {
4612    PR_ASSERT(h != NULL);
4613    h->hairpin_th = align_thermod(oligo_seq, oligo_seq, thal_arg_to_use->hairpin_th);
4614    if(h->hairpin_th > po_args->max_hairpin_th) {
4615       op_set_high_hairpin_th(h);
4616       ostats->hairpin_th++;
4617       ostats->ok--;
4618       return;
4619    }
4620 }
4621 
4622 static void
primer_mispriming_to_template(primer_rec * h,const p3_global_settings * pa,const seq_args * sa,oligo_type l,oligo_stats * ostats,int first,int last,const char * s,const char * s_r,const dpal_args * align_args)4623 primer_mispriming_to_template(primer_rec *h,
4624                               const p3_global_settings *pa,
4625                               const seq_args *sa,
4626                               oligo_type l,
4627                               oligo_stats *ostats,
4628                               int first,
4629                               int last,
4630                               /* The oligo sequence: */
4631                               const char *s,
4632                               /* s reverse complemented: */
4633                               const char *s_r,
4634                               const dpal_args *align_args
4635                               )
4636 {
4637   const char *oseq;
4638   char *target, *target_r;
4639   int tmp, seqlen;
4640   int debug = 0;
4641   int first_untrimmed, last_untrimmed;
4642                   /* Indexes of first and last bases of the oligo in sa->seq,
4643                      that is, WITHIN THE TOTAL SEQUENCE INPUT. */
4644 
4645   /* first, last are indexes of first and last bases of the oligo in
4646      sa->trimmed_seq, that is, WITHIN THE INCLUDED REGION. */
4647 
4648   char   tmp_char;
4649   double tmp_score;
4650 
4651   seqlen = strlen(sa->upcased_seq);
4652   first_untrimmed = sa->incl_s + first;
4653   last_untrimmed = sa->incl_s + last;
4654 
4655   if (l == OT_LEFT) {
4656     oseq = &s[0];
4657     target = &sa->upcased_seq[0];
4658     target_r = &sa->upcased_seq_r[0];
4659   } else {  /* l == OT_RIGHT */
4660     if (debug)
4661       fprintf(stderr, "first_untrimmed = %d, last_untrimmed = %d\n",
4662               first_untrimmed, last_untrimmed);
4663     oseq = &s_r[0];
4664     target = &sa->upcased_seq_r[0];
4665     target_r = &sa->upcased_seq[0];
4666     /* We need to adjust first_untrimmed and last_untrimmed so that
4667        they are correct in the reverse-complemented
4668        sequence.
4669     */
4670     tmp = (seqlen - last_untrimmed) - 1;
4671     last_untrimmed  = (seqlen - first_untrimmed) - 1;
4672     first_untrimmed = tmp;
4673   }
4674 
4675   /* 1. Align to the template 5' of the oligo. */
4676   tmp_char = target[first_untrimmed];
4677   target[first_untrimmed] = '\0';
4678 
4679   tmp_score = align(oseq, target, align_args);
4680 
4681   if (debug) {
4682     if (l == OT_LEFT) fprintf(stderr, "\n************ OLIGO = LEFT\n");
4683     else fprintf(stderr,              "\n************ OLIGO = RIGHT\n");
4684     fprintf(stderr, "first_untrimmed = %d, last_untrimmed = %d,first = %d, last = %d\n",
4685             first_untrimmed, last_untrimmed, first, last);
4686 
4687     fprintf(stderr, "5' of oligo: Score %f aligning %s against %s\n\n", tmp_score,
4688             oseq, target);
4689   }
4690 
4691   target[first_untrimmed] = tmp_char;
4692 
4693   /* 2. Align to the template 3' of the oligo. */
4694   h->template_mispriming
4695     = align(oseq, &target[0] + last_untrimmed + 1, align_args);
4696 
4697   if (debug)
4698     fprintf(stderr, "3' of oligo Score %f aligning %s against %s\n\n",
4699             h->template_mispriming, oseq, &target[0] + last_untrimmed + 1);
4700 
4701   /* 3. Take the max of 1. and 2. */
4702   if (tmp_score > h->template_mispriming)
4703     h->template_mispriming = tmp_score;
4704 
4705   /* 4. Align to the reverse strand of the template. */
4706   h->template_mispriming_r
4707     = align(oseq, target_r, align_args);
4708 
4709   if (debug)
4710     fprintf(stderr, "other strand Score %f aligning %s against %s\n\n",
4711             h->template_mispriming_r, oseq, target_r);
4712 
4713   if (pa->p_args.max_template_mispriming >= 0) {
4714     if (oligo_max_template_mispriming(h)
4715 	> pa->p_args.max_template_mispriming) {
4716       op_set_high_similarity_to_multiple_template_sites(h);
4717       if (OT_LEFT == l || OT_RIGHT == l ) {
4718         ostats->template_mispriming++;
4719         ostats->ok--;
4720       } else PR_ASSERT(0); /* Should not get here. */
4721     } else {
4722       /* This oligo is ok, mark it so we do not do this check again. */
4723       h->template_mispriming_ok = 1;
4724     }
4725   }
4726 }
4727 
4728 static void
primer_mispriming_to_template_thermod(primer_rec * h,const p3_global_settings * pa,const seq_args * sa,oligo_type l,oligo_stats * ostats,int first,int last,const char * s,const char * s_r,const thal_args * align_args)4729 primer_mispriming_to_template_thermod(primer_rec *h,
4730                                       const p3_global_settings *pa,
4731                                       const seq_args *sa,
4732                                       oligo_type l,
4733                                       oligo_stats *ostats,
4734                                       int first,
4735                                       int last,
4736                                       /* The oligo sequence: */
4737                                       const char *s,
4738                                       /* s reverse complemented: */
4739                                       const char *s_r,
4740                                       const thal_args *align_args)
4741 {
4742    const char *oseq;
4743    char *target, *target_r;
4744    int tmp, seqlen;
4745    int debug = 0;
4746    int first_untrimmed, last_untrimmed;
4747    /* Indexes of first and last bases of the oligo in sa->seq,
4748     *                      that is, WITHIN THE TOTAL SEQUENCE INPUT. */
4749 
4750    /* first, last are indexes of first and last bases of the oligo in
4751     *      sa->trimmed_seq, that is, WITHIN THE INCLUDED REGION. */
4752 
4753    char   tmp_char;
4754    double  tmp_score;
4755 
4756    seqlen = strlen(sa->upcased_seq);
4757    first_untrimmed = sa->incl_s + first;
4758    last_untrimmed = sa->incl_s + last;
4759 
4760    if (l == OT_RIGHT) {
4761       oseq = &s_r[0];
4762       target = &sa->upcased_seq[0];
4763       target_r = &sa->upcased_seq_r[0];
4764    } else { /* l == OT_RIGHT */
4765       if (debug)
4766         fprintf(stdout, "first_untrimmed = %d, last_untrimmed = %d\n",
4767                 first_untrimmed, last_untrimmed);
4768       oseq = &s[0];
4769       target = &sa->upcased_seq_r[0];
4770       target_r = &sa->upcased_seq[0];
4771       /* We need to adjust first_untrimmed and last_untrimmed so that
4772        * they are correct in the reverse-complemented
4773        * sequence.
4774              *     */
4775             tmp = (seqlen - last_untrimmed) - 1;
4776             last_untrimmed  = (seqlen - first_untrimmed) - 1;
4777             first_untrimmed = tmp;
4778    }
4779 
4780    /* 1. Align to the template 5' of the oligo. */
4781    /* tmp_char = target_r[first_untrimmed]; Corrected 2012-05-30 */
4782    tmp_char = target[first_untrimmed];
4783    target[first_untrimmed] = '\0';
4784 
4785    tmp_score = align_thermod(oseq, target, align_args);
4786 
4787    if (debug) {
4788         if (l == OT_LEFT) fprintf(stdout, "\n************ OLIGO = LEFT\n");
4789         else fprintf(stdout,              "\n************ OLIGO = RIGHT\n");
4790         fprintf(stdout, "first_untrimmed = %d, last_untrimmed = %d, first = %d, last = %d\n",
4791                 first_untrimmed, last_untrimmed, first, last);
4792 
4793         fprintf(stdout, "5' of oligo: Score %f aligning %s against %s\n\n", tmp_score,
4794                 oseq, target);
4795    }
4796    target[first_untrimmed] = tmp_char;
4797 
4798    /* 2. Align to the template 3' of the oligo. */
4799    h->template_mispriming
4800      = align_thermod(oseq, &target[0] + last_untrimmed + 1, align_args);
4801 
4802    if (debug)
4803      fprintf(stdout, "3' of oligo Score %f aligning %s against %s\n\n",
4804 	     h->template_mispriming, oseq, &target[0] + last_untrimmed + 1);
4805 
4806    /* 3. Take the max of 1. and 2. */
4807    if (tmp_score > h->template_mispriming)
4808      h->template_mispriming = tmp_score;
4809 
4810    /* 4. Align to the reverse strand of the template. */
4811    h->template_mispriming_r
4812      = align_thermod(oseq, target_r, align_args);
4813 
4814    if (debug)
4815      fprintf(stdout,
4816 	     "In primer_mispriming_to_template_thermod\n"
4817 	     " other strand Score %f aligning %s against %s\n\n",
4818 	     h->template_mispriming_r, oseq, target_r);
4819 
4820    if (pa->p_args.max_template_mispriming_th >= 0) {
4821      if (oligo_max_template_mispriming_thermod(h)
4822 	 > pa->p_args.max_template_mispriming_th) {
4823        op_set_high_similarity_to_multiple_template_sites(h);
4824        if (OT_LEFT == l || OT_RIGHT == l ) {
4825 	 ostats->template_mispriming++;
4826 	 ostats->ok--;
4827        }
4828        else PR_ASSERT(0); /* Should not get here. */
4829      } else {
4830        /* This oligo is ok, mark it so we do not do this check again. */
4831        h->template_mispriming_ok = 1;
4832      }
4833    }
4834 }
4835 
4836 static void
oligo_compute_sequence_and_reverse(primer_rec * h,const seq_args * sa,oligo_type l,int * first,int * last,char * s,char * s_r)4837 oligo_compute_sequence_and_reverse(primer_rec *h,
4838                                    const seq_args *sa,
4839                                    oligo_type l,
4840                                    int *first, int *last,
4841                                    char *s, char *s_r)
4842 {
4843   *first =  (OT_LEFT == l || OT_INTL == l)
4844     ? h->start
4845     : h->start - h->length + 1;
4846   *last  =  (OT_LEFT == l || OT_INTL == l)
4847     ? h->start + h->length - 1
4848     : h->start;
4849 
4850   _pr_substr(sa->trimmed_seq, *first, h->length, s);
4851   p3_reverse_complement(s, s_r);
4852 }
4853 
4854 /* Possible improvement -- pass in the oligo sequences */
4855 static void
oligo_repeat_library_mispriming(primer_rec * h,const p3_global_settings * pa,const seq_args * sa,oligo_type l,oligo_stats * ostats,const dpal_arg_holder * dpal_arg_to_use)4856 oligo_repeat_library_mispriming(primer_rec *h,
4857                                 const p3_global_settings *pa,
4858                                 const seq_args *sa,
4859                                 oligo_type l,
4860                                 oligo_stats *ostats,
4861                                 const dpal_arg_holder *dpal_arg_to_use)
4862 {
4863   char
4864     s[MAX_PRIMER_LENGTH+1],     /* Will contain the oligo sequence. */
4865     s_r[MAX_PRIMER_LENGTH+1];   /* Will contain s reverse complemented. */
4866 
4867   double w;
4868   const seq_lib *lib;
4869   int i;
4870   int first, last; /* Indexes of first and last bases of the oligo in
4871                      sa->trimmed_seq, that is, WITHIN THE INCLUDED
4872                      REGION. */
4873   int   min, max;
4874   short max_lib_compl;
4875 
4876   /* First, check the oligo against the repeat library. */
4877   if (OT_INTL == l) {
4878     lib = pa->o_args.repeat_lib;
4879     max_lib_compl = (short) pa->o_args.max_repeat_compl;
4880   } else {
4881     lib = pa->p_args.repeat_lib;
4882     max_lib_compl = (short) pa->p_args.max_repeat_compl;
4883   }
4884 
4885   oligo_compute_sequence_and_reverse(h, sa, l, &first, &last, s, s_r);
4886 
4887   /*
4888    * Calculate maximum similarity to sequences from user defined repeat
4889    * library. Compare it with maximum allowed repeat similarity.
4890    */
4891 
4892   if (seq_lib_num_seq(lib) > 0) {
4893     /* Library exists and is non-empty. */
4894 
4895     h->repeat_sim.score =
4896       (double *) pr_safe_malloc(lib->seq_num * sizeof(double));
4897     h->repeat_sim.max = h->repeat_sim.min = 0;
4898     max = min = 0;
4899     h->repeat_sim.name = lib->names[0];
4900 
4901     for (i = 0; i < lib->seq_num; i++) {
4902       if (OT_LEFT == l)
4903         w = lib->weight[i] *
4904           align(s, lib->seqs[i],
4905                 (pa->lib_ambiguity_codes_consensus
4906                  ? dpal_arg_to_use->local_end_ambig
4907                  : dpal_arg_to_use->local_end));
4908 
4909       else if (OT_INTL == l)
4910         w = lib->weight[i] *
4911           align(s, lib->seqs[i],
4912                 (pa->lib_ambiguity_codes_consensus
4913                  ? dpal_arg_to_use->local_ambig
4914                  : dpal_arg_to_use->local));
4915 
4916       else
4917         w = lib->weight[i] *
4918           align(s_r, lib->rev_compl_seqs[i],
4919                 (pa->lib_ambiguity_codes_consensus
4920                  ? dpal_arg_to_use->local_end_ambig
4921                  : dpal_arg_to_use->local));
4922 
4923 
4924       if (w > SHRT_MAX || w < SHRT_MIN) {
4925         abort(); /* TO DO, propagate error */
4926         /* This check is necessary for the next 9 lines */
4927       }
4928       h->repeat_sim.score[i] = w;
4929       if(w > max){
4930         max = (int) w;
4931         h->repeat_sim.max = i;
4932         h->repeat_sim.name = lib->names[i];
4933       }
4934       if(w < min){
4935         min = (int) w;
4936         h->repeat_sim.min = i;
4937       }
4938 
4939       if (w > max_lib_compl) {
4940         op_set_high_similarity_to_non_template_seq(h);
4941         ostats->repeat_score++;
4942         ostats->ok--;
4943         if (!h->must_use) return;
4944       } /* if w > max_lib_compl */
4945     } /* for */
4946   } /* if library exists and is non-empty */
4947   /* End of checking against the repeat library */
4948 }
4949 
4950 /* This function carries out either the old "dpal" alignment or the
4951    thermodynamic alignment, depending on the value of
4952    pa->thermodynamic_template_alignment. */
4953 static void
oligo_template_mispriming(primer_rec * h,const p3_global_settings * pa,const seq_args * sa,oligo_type l,oligo_stats * ostats,const dpal_args * d_align_args,const thal_args * t_align_args)4954 oligo_template_mispriming(primer_rec *h,
4955                           const p3_global_settings *pa,
4956                           const seq_args *sa,
4957                           oligo_type l,
4958                           oligo_stats *ostats,
4959                           const dpal_args *d_align_args,
4960                           const thal_args *t_align_args)
4961 {
4962   char
4963     s[MAX_PRIMER_LENGTH+1],     /* Will contain the oligo sequence. */
4964     s_r[MAX_PRIMER_LENGTH+1];   /* Will contain s reverse complemented. */
4965 
4966   int first, last; /* Indexes of first and last bases of the oligo in
4967                      sa->trimmed_seq, that is, WITHIN THE INCLUDED
4968                      REGION. */
4969 
4970   /* Check if we already did this and the oligo was ok. */
4971   if (h->template_mispriming_ok) {
4972     return;
4973   }
4974 
4975   oligo_compute_sequence_and_reverse(h, sa, l, &first, &last, s, s_r);
4976 
4977   /* Calculate maximum similarity to ectopic sites in the template. */
4978   if (l == OT_RIGHT || l == OT_LEFT) {
4979     if (pa->thermodynamic_template_alignment == 0 && _pr_need_template_mispriming(pa))
4980       primer_mispriming_to_template(h, pa, sa, l,
4981                                     ostats, first,
4982                                     last, s, s_r, d_align_args);
4983     if (pa->thermodynamic_template_alignment == 1 && _pr_need_template_mispriming_thermod(pa))
4984       primer_mispriming_to_template_thermod(h, pa, sa, l,
4985                                             ostats, first,
4986                                             last, s, s_r, t_align_args);
4987   }
4988 }
4989 
4990 static int
pair_repeat_sim(primer_pair * h,const p3_global_settings * pa)4991 pair_repeat_sim(primer_pair *h,
4992                 const p3_global_settings *pa) {
4993   int i, n, max, w;
4994   primer_rec *fw, *rev;
4995 
4996   fw = h->left;
4997   rev = h->right;
4998 
4999   max = 0;
5000   n = seq_lib_num_seq(pa->p_args.repeat_lib);
5001   if(n == 0) return 0;
5002   h->rep_name =  pa->p_args.repeat_lib->names[0] ;
5003   for (i = 0; i < n; i++) {
5004     if ((w = (int) (fw->repeat_sim.score[i] +
5005                     rev->repeat_sim.score[i])) > max) {
5006       max = w;
5007       h->rep_name =  pa->p_args.repeat_lib->names[i] ;
5008     }
5009   }
5010   return max;
5011 }
5012 
5013 static void
set_retval_both_stop_codons(const seq_args * sa,p3retval * retval)5014 set_retval_both_stop_codons(const seq_args *sa, p3retval *retval) {
5015   /* The position of the intial base of the rightmost stop codon that
5016    * is to the left of sa->start_codon_pos; valid only if
5017    * sa->start_codon_pos is "not null".  We will not want to include
5018    * a stop codon to the right of the the start codon in the
5019    * amplicon. */
5020   retval->upstream_stop_codon = find_stop_codon(sa->trimmed_seq,
5021                                                 sa->start_codon_pos, -1);
5022   retval->upstream_stop_codon += sa->incl_s;
5023   retval->stop_codon_pos = find_stop_codon(sa->trimmed_seq,
5024                                              sa->start_codon_pos,  1);
5025   retval->stop_codon_pos += sa->incl_s;
5026 }
5027 
5028 /*
5029  * 's' is the sequence in which to find the stop codon.
5030  * 'start' is the position of a start codon.
5031  *
5032  * There are two modes depending on 'direction'.
5033  *
5034  * If direction is 1:
5035  *
5036  * Return the index of the first stop codon to the right of
5037  * 'start' in 's' (in same frame).
5038  * If there is no such stop codon return -1.
5039  *
5040  * If direction is -1:
5041  *
5042  * If 'start' is negative then return -1.
5043  * Otherwise return the index the first stop codon to left of 'start'.
5044  * If there is no such stop codon return -1.
5045  *
5046  * Note: we don't insist that the start codon be ATG, since in some
5047  * cases the caller will not have the full sequence in 's', nor even
5048  * know the postion of the start codon relative to s.
5049  */
5050 static int
find_stop_codon(const char * s,int start,int direction)5051 find_stop_codon(const char* s,
5052                 int start,
5053                 int direction) {
5054   const char *p, *q;
5055   int increment = 3 * direction;
5056   int len = strlen(s);
5057 
5058   PR_ASSERT(s != NULL);
5059   PR_ASSERT(direction == 1 || direction == -1);
5060   PR_ASSERT(len >= 3);
5061   PR_ASSERT(start <= (len - 3));
5062 
5063   if (start < 0) {
5064     if (direction == 1)
5065       while (start < 0) start += increment;
5066     else
5067       return -1;
5068   }
5069 
5070   for (p = &s[start];
5071        p >= &s[0]
5072          && *p
5073          && *(p + 1)
5074          && *(p + 2);
5075        p += increment) {
5076     if ('T' != *p && 't' != *p) continue;
5077     q = p + 1;
5078     if ('A' == *q || 'a' == *q) {
5079       q++;
5080       if  ('G' == *q || 'g' == *q || 'A' == *q || 'a' == *q)
5081         return p - &s[0];
5082     } else if ('G' == *q || 'g' == *q) {
5083       q++;
5084       if ('A' == *q || 'a' == *q)
5085         return p - &s[0];
5086     }
5087   }
5088   return -1;
5089 }
5090 
5091 int
strcmp_nocase(const char * s1,const char * s2)5092 strcmp_nocase(const char *s1, const char *s2)
5093 {
5094   static char M[UCHAR_MAX];
5095   static int f = 0;
5096   int i;
5097   const char *p, *q;
5098 
5099   if(f != 1){
5100     for(i = 0; i < UCHAR_MAX; i++) M[i] = i;
5101     i = 'a'; M[i] = 'A'; i = 'b'; M[i] = 'B'; i = 'c'; M[i] = 'C';
5102     i = 'A'; M[i] = 'a'; i = 'B'; M[i] = 'b'; i = 'C'; M[i] = 'c';
5103     i = 'd'; M[i] = 'D'; i = 'e'; M[i] = 'E'; i = 'f'; M[i] = 'F';
5104     i = 'D'; M[i] = 'd'; i = 'E'; M[i] = 'e'; i = 'F'; M[i] = 'f';
5105     i = 'g'; M[i] = 'G'; i = 'h'; M[i] = 'H'; i = 'i'; M[i] = 'I';
5106     i = 'G'; M[i] = 'g'; i = 'H'; M[i] = 'h'; i = 'I'; M[i] = 'i';
5107     i = 'k'; M[i] = 'K'; i = 'l'; M[i] = 'L'; i = 'm'; M[i] = 'M';
5108     i = 'K'; M[i] = 'k'; i = 'L'; M[i] = 'l'; i = 'M'; M[i] = 'm';
5109     i = 'n'; M[i] = 'N'; i = 'o'; M[i] = 'O'; i = 'p'; M[i] = 'P';
5110     i = 'N'; M[i] = 'n'; i = 'O'; M[i] = 'o'; i = 'P'; M[i] = 'p';
5111     i = 'q'; M[i] = 'Q'; i = 'r'; M[i] = 'R'; i = 's'; M[i] = 'S';
5112     i = 'Q'; M[i] = 'q'; i = 'R'; M[i] = 'r'; i = 'S'; M[i] = 's';
5113     i = 't'; M[i] = 'T'; i = 'u'; M[i] = 'U'; i = 'v'; M[i] = 'V';
5114     i = 'T'; M[i] = 't'; i = 'U'; M[i] = 'u'; i = 'V'; M[i] = 'v';
5115     i = 'w'; M[i] = 'W'; i = 'x'; M[i] = 'X'; i = 'y'; M[i] = 'Y';
5116     i = 'W'; M[i] = 'w'; i = 'X'; M[i] = 'x'; i = 'Y'; M[i] = 'y';
5117     i = 'z'; M[i] = 'Z'; i = 'Z'; M[i] = 'z'; i = 'j'; M[i] = 'J';
5118     i = 'J'; M[i] = 'j';
5119     f = 1;
5120   }
5121 
5122   if(s1 == NULL || s2 == NULL) return 1;
5123   if(strlen(s1) != strlen(s2)) return 1;
5124   p = s1; q = s2;
5125   while(*p != '\0' && *p != '\n' && *q != '\0' && *q != '\n'){
5126     i = *p;
5127     if(*p == *q || M[i] == *q ) {p++; q++; continue;}
5128 
5129     return 1;
5130   }
5131   return 0;
5132 }
5133 
5134 static void
free_repeat_sim_score(p3retval * state)5135 free_repeat_sim_score(p3retval *state)
5136 {
5137   int i;
5138 
5139   for (i = 0; i < state->fwd.num_elem; i++) {
5140     if (state->fwd.oligo[i].repeat_sim.score != NULL) {
5141       free(state->fwd.oligo[i].repeat_sim.score);
5142       state->fwd.oligo[i].repeat_sim.score = NULL;
5143     }
5144   }
5145 
5146   for (i = 0; i < state->rev.num_elem; i++) {
5147     if (state->rev.oligo[i].repeat_sim.score != NULL) {
5148       free(state->rev.oligo[i].repeat_sim.score);
5149       state->rev.oligo[i].repeat_sim.score = NULL;
5150     }
5151   }
5152 
5153   for (i = 0; i < state->intl.num_elem; i++) {
5154     if (state->intl.oligo[i].repeat_sim.score != NULL) {
5155       free(state->intl.oligo[i].repeat_sim.score);
5156       state->intl.oligo[i].repeat_sim.score = NULL;
5157     }
5158   }
5159 }
5160 
5161 static void
free_primer_repeat_sim_score(primer_rec * h)5162 free_primer_repeat_sim_score(primer_rec *h)
5163 {
5164   if (h->repeat_sim.score != NULL) {
5165     free(h->repeat_sim.score);
5166     h->repeat_sim.score = NULL;
5167   }
5168 }
5169 
5170 /*
5171  Edited by T. Koressaar for lowercase masking. This function checks
5172  if the 3' end of the primer has been masked by lowercase letter.
5173  Function created/Added by Eric Reppo, July 9, 2002
5174  */
5175 static int
is_lowercase_masked(int position,const char * sequence,primer_rec * h,oligo_stats * global_oligo_stats)5176 is_lowercase_masked(int position,
5177                     const char *sequence,
5178                     primer_rec *h,
5179                     oligo_stats *global_oligo_stats)
5180 {
5181   const char* p = &sequence[position];
5182   if ('a' == *p || 'c' == *p ||'g' == *p || 't' == *p) {
5183     op_set_overlaps_masked_sequence(h);
5184     global_oligo_stats->gmasked++;
5185     return 1;
5186   }
5187   return 0;
5188 }
5189 
5190 /*
5191  Edited by A. Untergasser
5192  */
5193 static int
primer_must_match(const p3_global_settings * pa,primer_rec * h,oligo_stats * global_oligo_stats,const char * input_oligo_seq,char * match_three_prime,char * match_five_prime)5194 primer_must_match(const p3_global_settings *pa, primer_rec *h, oligo_stats *global_oligo_stats,
5195 		  /* This is 5'->3' on the template sequence: */
5196 		  const char *input_oligo_seq, char *match_three_prime, char *match_five_prime)
5197 {
5198   const char *seq;
5199   char *test;
5200   int length = h->length - 5;
5201   if (match_five_prime != NULL) {
5202     seq = input_oligo_seq;
5203     test = match_five_prime;
5204     for (int i = 0; i < 5; i++) {
5205       if (!compare_nucleotides(*seq, *test)) {
5206 	global_oligo_stats->must_match_fail++;
5207 	return 1;
5208       }
5209       seq++;
5210       test++;
5211     }
5212   }
5213   if (match_three_prime != NULL) {
5214     seq = input_oligo_seq;
5215     test = match_three_prime;
5216     seq = seq + length;
5217     for (int i = 0; i < 5; i++) {
5218       if (!compare_nucleotides(*seq, *test)) {
5219 	global_oligo_stats->must_match_fail++;
5220 	return 1;
5221       }
5222       seq++;
5223       test++;
5224 		}
5225   }
5226   return 0;
5227 }
5228 
5229 /* For a [NACTG] is allowed, for b [NACTGRYWSMKBHDV].*/
compare_nucleotides(const char a,const char b)5230 static int compare_nucleotides(const char a, const char b)
5231 {
5232   char x = a;
5233   char y = b;
5234   /* Convert to uppercase */
5235   if(a >= 'a' && a <= 'z'){
5236     x = ('A' + a - 'a');
5237   }
5238   if(b >= 'b' && b <= 'z'){
5239     y = ('A' + b - 'a');
5240   }
5241 
5242   if ( x == y ) {
5243     return 1;
5244   }
5245   if (( x == 'N') or (y == 'N')) {
5246     return 1;
5247   }
5248   if (x == 'A') {
5249     if ((y == 'R') or (y == 'W') or (y == 'M') or
5250 	(y == 'H') or (y == 'D') or (y == 'V')){
5251       return 1;
5252     }
5253   }
5254   if (x == 'G') {
5255     if ((y == 'R') or (y == 'S') or (y == 'K') or
5256 	(y == 'B') or (y == 'D') or (y == 'V')){
5257       return 1;
5258     }
5259   }
5260   if (x == 'C') {
5261     if ((y == 'Y') or (y == 'S') or (y == 'M') or
5262 	(y == 'B') or (y == 'H') or (y == 'V')){
5263       return 1;
5264     }
5265   }
5266   if (x == 'T') {
5267     if ((y == 'Y') or (y == 'W') or (y == 'K') or
5268 	(y == 'B') or (y == 'H') or (y == 'D')){
5269       return 1;
5270     }
5271   }
5272   return 0;
5273 }
5274 
test_must_match_parameters(char * test)5275 static int test_must_match_parameters(char *test)
5276 {
5277   int i = 0;
5278   char x;
5279   while (*test != '\0') {
5280     /* First to UPPER letters */
5281     if ((*test >= 'a') && (*test <= 'z')){
5282       x = ('A' + (*test) - 'a');
5283     } else {
5284       x = *test;
5285     }
5286     /* Second check that it is in Range A-Z */
5287     if ((x < 'A') || (x > 'Z')){
5288       return 1;
5289     }
5290     /* Check it is NACTGRYWSMKBHDV */
5291     if ((x == 'N') ||
5292 	(x == 'A') || (x == 'C') ||
5293 	(x == 'T') || (x == 'G') ||
5294 	(x == 'R') || (x == 'Y') ||
5295 	(x == 'W') || (x == 'S') ||
5296 	(x == 'M') || (x == 'K') ||
5297 	(x == 'B') || (x == 'H') ||
5298 	(x == 'D') || (x == 'V')){
5299       test++;
5300       i++;
5301     } else {
5302       return 1;
5303     }
5304   }
5305   /* Check it is 5 letters */
5306   if (i != 5) {
5307     return 1;
5308   }
5309   return 0;
5310 }
5311 
5312 /* Put substring of seq starting at n with length m into s. */
5313 void
_pr_substr(const char * seq,int n,int m,char * s)5314 _pr_substr(const char *seq, int n, int m, char *s)
5315 {
5316   int i;
5317   for(i=n;i<n+m;i++)s[i-n]=seq[i];
5318   s[m]='\0';
5319 }
5320 
5321 /* Reverse and complement the sequence seq and put the result in s.
5322    WARNING: It is up the caller to ensure that s points to enough
5323    space. */
5324 void
p3_reverse_complement(const char * seq,char * s)5325 p3_reverse_complement(const char *seq, char *s)
5326 {
5327   const char *p = seq;
5328   char *q = s;
5329 
5330   while (*p != '\0') p++;
5331   p--;
5332   while (p >= seq) {
5333     switch (*p)
5334       {
5335       case 'A': *q='T'; break;
5336       case 'C': *q='G'; break;
5337       case 'G': *q='C'; break;
5338       case 'T': *q='A'; break;
5339       case 'U': *q='A'; break;
5340 
5341       case 'B': *q='V'; break;
5342       case 'D': *q='H'; break;
5343       case 'H': *q='D'; break;
5344       case 'V': *q='B'; break;
5345       case 'R': *q='Y'; break;
5346       case 'Y': *q='R'; break;
5347       case 'K': *q='M'; break;
5348       case 'M': *q='K'; break;
5349       case 'S': *q='S'; break;
5350       case 'W': *q='W'; break;
5351 
5352       case 'N': *q='N'; break;
5353 
5354       case 'a': *q='t'; break;
5355       case 'c': *q='g'; break;
5356       case 'g': *q='c'; break;
5357       case 't': *q='a'; break;
5358       case 'u': *q='a'; break;
5359 
5360       case 'b': *q='v'; break;
5361       case 'd': *q='h'; break;
5362       case 'h': *q='d'; break;
5363       case 'v': *q='b'; break;
5364       case 'r': *q='y'; break;
5365       case 'y': *q='r'; break;
5366       case 'k': *q='m'; break;
5367       case 'm': *q='k'; break;
5368       case 's': *q='s'; break;
5369       case 'w': *q='w'; break;
5370 
5371       case 'n': *q='n'; break;
5372       }
5373     p--; q++;
5374   }
5375   *q = '\0';
5376 }
5377 
5378 int
_pr_need_template_mispriming(const p3_global_settings * pa)5379 _pr_need_template_mispriming(const p3_global_settings *pa) {
5380   return
5381     pa->p_args.max_template_mispriming >= 0
5382     || pa->p_args.weights.template_mispriming > 0.0
5383     || _pr_need_pair_template_mispriming(pa);
5384 }
5385 int
_pr_need_template_mispriming_thermod(const p3_global_settings * pa)5386 _pr_need_template_mispriming_thermod(const p3_global_settings *pa) {
5387      return
5388        pa->p_args.max_template_mispriming_th >= 0
5389        || pa->p_args.weights.template_mispriming_th > 0.0
5390        || _pr_need_pair_template_mispriming_thermod(pa);
5391   }
5392 
5393 int
_pr_need_pair_template_mispriming(const p3_global_settings * pa)5394 _pr_need_pair_template_mispriming(const p3_global_settings *pa)
5395 {
5396   return
5397     pa->pair_max_template_mispriming >= 0
5398     || pa->pr_pair_weights.template_mispriming > 0.0;
5399 }
5400 
5401 int
_pr_need_pair_template_mispriming_thermod(const p3_global_settings * pa)5402 _pr_need_pair_template_mispriming_thermod(const p3_global_settings *pa)
5403 {
5404    return
5405      pa->pair_max_template_mispriming_th >= 0
5406      || pa->pr_pair_weights.template_mispriming_th > 0.0;
5407 }
5408 
5409 /* Upcase a DNA string, s, in place.  If amibiguity_code_ok is false,
5410    then the characters acgtnACGTN are 'recognized' and upcased.  If
5411    ambiguity_code_ok is true, then the IUB/IUPAC ambiguity codes are
5412    also 'recognized' and upcased.
5413 
5414    Change any unrecognized letters in *s to 'N"
5415 
5416    Return the first unrecognized letter, if
5417    any, that is seen. Otherwise return '\0'. */
5418 static char
dna_to_upper(char * s,int ambiguity_code_ok)5419 dna_to_upper(char * s, int ambiguity_code_ok)
5420 {
5421   char *p = s;
5422   int unrecognized_base = '\0';
5423   while (*p) {
5424     switch (*p) {
5425       case 'a': case 'A': *p='A'; break;
5426       case 'c': case 'C': *p='C'; break;
5427       case 'g': case 'G': *p='G'; break;
5428       case 't': case 'T': *p='T'; break;
5429       case 'n': case 'N': *p='N'; break;
5430       default:
5431         if (ambiguity_code_ok) {
5432           switch (*p) {
5433           case 'r': case 'R': *p = 'R'; break;
5434           case 'y': case 'Y': *p = 'Y'; break;
5435           case 'm': case 'M': *p = 'M'; break;
5436           case 'w': case 'W': *p = 'W'; break;
5437           case 's': case 'S': *p = 'S'; break;
5438           case 'k': case 'K': *p = 'K'; break;
5439           case 'd': case 'D': *p = 'D'; break;
5440           case 'h': case 'H': *p = 'H'; break;
5441           case 'v': case 'V': *p = 'V'; break;
5442           case 'b': case 'B': *p = 'B'; break;
5443           }
5444         } else {
5445           if (!unrecognized_base) unrecognized_base = *p;
5446           *p = 'N';
5447         }
5448         break;
5449       }
5450     p++;
5451   }
5452   return unrecognized_base;
5453 }
5454 
5455 static char *
strstr_nocase(char * s1,char * s2)5456 strstr_nocase(char *s1, char *s2) {
5457   int  n1, n2;
5458   char *p, q, *tmp;
5459 
5460   if(s1 == NULL || s2 == NULL) return NULL;
5461   n1 = strlen(s1); n2 = strlen(s2);
5462   if(n1 < n2) return NULL;
5463 
5464   tmp = (char *) pr_safe_malloc(n1 + 1);
5465   strcpy(tmp, s1);
5466 
5467   q = *tmp; p = tmp;
5468   while(q != '\0' && q != '\n'){
5469     q = *(p + n2);
5470     *(p + n2) = '\0';
5471     if(strcmp_nocase(p, s2)){
5472       *(p + n2) = q; p++; continue;
5473     }
5474     else {free(tmp); return p;}
5475   }
5476   free(tmp); return NULL;
5477 }
5478 
5479 #define CHECK  if (r > bsize || r < 0) return "Internal error, not enough space for \"explain\" string";  bufp += r; bsize -= r
5480 #define SP_AND_CHECK(FMT, VAL) { r = sprintf(bufp, FMT, VAL); CHECK; }
5481 #define IF_SP_AND_CHECK(FMT, VAL) { if (VAL) { SP_AND_CHECK(FMT, VAL) } }
5482 const char *
p3_pair_explain_string(const pair_stats * pair_expl)5483 p3_pair_explain_string(const pair_stats *pair_expl)
5484 {
5485   /* WARNING WARNING WARNING
5486 
5487   Static, fixed-size buffer.  If you add more calls to SP_AND_CHECK or
5488   IF_SP_AND_CHECK, you need to make sure the buffer cannot overflow.
5489   */
5490 
5491   static char buf[10000];
5492   char *bufp = buf;
5493   size_t bsize = 10000;
5494   size_t r;
5495 
5496   SP_AND_CHECK("considered %d", pair_expl->considered)
5497   IF_SP_AND_CHECK(", no target %d", pair_expl->target)
5498   IF_SP_AND_CHECK(", unacceptable product size %d", pair_expl->product)
5499   IF_SP_AND_CHECK(", low product Tm %d", pair_expl->low_tm)
5500   IF_SP_AND_CHECK(", high product Tm %d", pair_expl->high_tm)
5501   IF_SP_AND_CHECK(", tm diff too large %d",pair_expl->temp_diff)
5502   IF_SP_AND_CHECK(", high any compl %d", pair_expl->compl_any)
5503   IF_SP_AND_CHECK(", high end compl %d", pair_expl->compl_end)
5504   IF_SP_AND_CHECK(", no internal oligo %d", pair_expl->internal)
5505   IF_SP_AND_CHECK(", high mispriming library similarity %d",
5506                   pair_expl->repeat_sim)
5507   IF_SP_AND_CHECK(", no overlap of required point %d",
5508                   pair_expl->does_not_overlap_a_required_point)
5509   IF_SP_AND_CHECK(", primer in pair overlaps a primer in a better pair %d",
5510                   pair_expl->overlaps_oligo_in_better_pair)
5511   IF_SP_AND_CHECK(", high template mispriming score %d",
5512                   pair_expl->template_mispriming)
5513   IF_SP_AND_CHECK(", not in any ok region %d",
5514                   pair_expl->not_in_any_ok_region);
5515   IF_SP_AND_CHECK(", left primer to right of right primer %d",
5516 		  pair_expl->reversed);
5517 
5518   SP_AND_CHECK(", ok %d", pair_expl->ok)
5519 
5520   return buf;
5521 }
5522 
5523 const char *
p3_oligo_explain_string(const oligo_stats * stat)5524 p3_oligo_explain_string(const oligo_stats *stat)
5525 {
5526   /* WARNING WARNING WARNING
5527 
5528   Static, fixed-size buffer.  If you add more calls to SP_AND_CHECK or
5529   IF_SP_AND_CHECK, you need to make sure the buffer cannot overflow.
5530   */
5531 
5532   static char buf[10000];
5533   char *bufp = buf;
5534   size_t bsize = 10000;
5535   size_t r;
5536 
5537   SP_AND_CHECK("considered %d", stat->considered)
5538   IF_SP_AND_CHECK(", would not amplify any of the ORF %d", stat->no_orf)
5539   IF_SP_AND_CHECK(", too many Ns %d", stat->ns)
5540   IF_SP_AND_CHECK(", overlap target %d", stat->target)
5541   IF_SP_AND_CHECK(", overlap excluded region %d", stat->excluded)
5542   IF_SP_AND_CHECK(", GC content failed %d", stat->gc)
5543   IF_SP_AND_CHECK(", GC clamp failed %d", stat->gc_clamp)
5544   IF_SP_AND_CHECK(", low tm %d", stat->temp_min)
5545   IF_SP_AND_CHECK(", high tm %d", stat->temp_max)
5546   IF_SP_AND_CHECK(", high any compl %d", stat->compl_any)
5547   IF_SP_AND_CHECK(", high end compl %d", stat->compl_end)
5548   IF_SP_AND_CHECK(", high hairpin stability %d", stat->hairpin_th)
5549   IF_SP_AND_CHECK(", high repeat similarity %d", stat->repeat_score)
5550   IF_SP_AND_CHECK(", long poly-x seq %d", stat->poly_x)
5551   IF_SP_AND_CHECK(", low sequence quality %d", stat->seq_quality)
5552   IF_SP_AND_CHECK(", high 3' stability %d", stat->stability)
5553   IF_SP_AND_CHECK(", high template mispriming score %d",
5554                   stat->template_mispriming)
5555   IF_SP_AND_CHECK(", lowercase masking of 3' end %d",stat->gmasked)
5556   IF_SP_AND_CHECK(", failed must_match requirements %d",stat->must_match_fail)
5557   IF_SP_AND_CHECK(", not in any ok left region %d",
5558                   stat->not_in_any_left_ok_region)
5559   IF_SP_AND_CHECK(", not in any ok right region %d",
5560                   stat->not_in_any_right_ok_region)
5561   SP_AND_CHECK(", ok %d", stat->ok)
5562   return buf;
5563 }
5564 #undef CHECK
5565 #undef SP_AND_CHECK
5566 #undef IF_SP_AND_CHEC
5567 
5568 const char *
p3_get_oligo_array_explain_string(const oligo_array * oligo_array)5569 p3_get_oligo_array_explain_string(const oligo_array *oligo_array)
5570 {
5571   return p3_oligo_explain_string(&oligo_array->expl);
5572 }
5573 
5574 const char *
p3_get_pair_array_explain_string(const pair_array_t * pair_array)5575 p3_get_pair_array_explain_string(const pair_array_t *pair_array)
5576 {
5577   return p3_pair_explain_string(&pair_array->expl);
5578 }
5579 
5580 const char *
libprimer3_release(void)5581 libprimer3_release(void)
5582 {
5583   return "libprimer3 release 2.3.6";
5584 }
5585 
5586 const char *
primer3_copyright(void)5587 primer3_copyright(void)
5588 {
5589   return primer3_copyright_char_star;
5590 }
5591 
5592 /* ============================================================ */
5593 /* BEGIN Internal and external functions for pr_append_str      */
5594 /* ============================================================ */
5595 
5596 void
init_pr_append_str(pr_append_str * s)5597 init_pr_append_str(pr_append_str *s)
5598 {
5599   s->data = NULL;
5600   s->storage_size = 0;
5601 }
5602 
5603 const char *
pr_append_str_chars(const pr_append_str * x)5604 pr_append_str_chars(const pr_append_str *x)
5605 {
5606   return x->data;
5607 }
5608 
5609 pr_append_str *
create_pr_append_str()5610 create_pr_append_str()
5611 {
5612   /* We cannot use pr_safe_malloc here
5613      because this function will be called outside
5614      of the setjmp(....) */
5615   pr_append_str *ret;
5616 
5617   ret = (pr_append_str *) malloc(sizeof(pr_append_str));
5618   if (NULL == ret) return NULL;
5619   init_pr_append_str(ret);
5620   return ret;
5621 }
5622 
5623 void
destroy_pr_append_str_data(pr_append_str * str)5624 destroy_pr_append_str_data(pr_append_str *str)
5625 {
5626   if (NULL == str) return;
5627   free(str->data);
5628   str->data = NULL;
5629 }
5630 
5631 void
destroy_pr_append_str(pr_append_str * str)5632 destroy_pr_append_str(pr_append_str *str)
5633 {
5634   if (str == NULL) return;
5635   destroy_pr_append_str_data(str);
5636   free(str);
5637 }
5638 
5639 int
pr_append_external(pr_append_str * x,const char * s)5640 pr_append_external(pr_append_str *x,  const char *s)
5641 {
5642   int xlen, slen;
5643 
5644   PR_ASSERT(NULL != s);
5645   PR_ASSERT(NULL != x);
5646 
5647   if (NULL == x->data) {
5648     x->storage_size = 24;
5649     x->data = (char *) malloc(x->storage_size);
5650     if (NULL == x->data) return 1; /* out of memory */
5651     *x->data = '\0';
5652   }
5653   xlen = strlen(x->data);
5654   slen = strlen(s);
5655   if (xlen + slen + 1 > x->storage_size) {
5656     x->storage_size += 2 * (slen + 1);
5657     x->data = (char *) realloc(x->data, x->storage_size);
5658     if (NULL == x->data) return 1; /* out of memory */
5659   }
5660   strcpy(x->data + xlen, s);
5661   return 0;
5662 }
5663 
5664 static void
pr_append_new_chunk(pr_append_str * x,const char * s)5665 pr_append_new_chunk(pr_append_str *x, const char *s)
5666 {
5667   PR_ASSERT(NULL != x)
5668   if (NULL == s) return;
5669   pr_append_w_sep(x, "; ", s);
5670 }
5671 
5672 int
pr_append_new_chunk_external(pr_append_str * x,const char * s)5673 pr_append_new_chunk_external(pr_append_str *x, const char *s)
5674 {
5675   PR_ASSERT(NULL != x)
5676     if (NULL == s) return 0;
5677   return(pr_append_w_sep_external(x, "; ", s));
5678 }
5679 
5680 int
pr_append_w_sep_external(pr_append_str * x,const char * sep,const char * s)5681 pr_append_w_sep_external(pr_append_str *x,
5682                          const char *sep,
5683                          const char *s)
5684 {
5685   PR_ASSERT(NULL != x)
5686   PR_ASSERT(NULL != s)
5687   PR_ASSERT(NULL != sep)
5688     if (pr_is_empty(x)) {
5689       return(pr_append_external(x, s));
5690     } else {
5691         return(pr_append_external(x, sep)
5692                || pr_append_external(x, s));
5693     }
5694 }
5695 
5696 void
pr_set_empty(pr_append_str * x)5697 pr_set_empty(pr_append_str *x)
5698 {
5699   PR_ASSERT(NULL != x);
5700   if (NULL != x->data) *x->data = '\0';
5701 }
5702 
5703 int
pr_is_empty(const pr_append_str * x)5704 pr_is_empty( const pr_append_str *x)
5705 {
5706   PR_ASSERT(NULL != x);
5707   return  NULL == x->data || '\0' == *x->data;
5708 }
5709 
5710 static void
pr_append_w_sep(pr_append_str * x,const char * sep,const char * s)5711 pr_append_w_sep(pr_append_str *x,
5712                 const char *sep,
5713                 const char *s)
5714 {
5715   if (pr_append_w_sep_external(x, sep, s)) longjmp(_jmp_buf, 1);
5716 }
5717 
5718 static void
pr_append(pr_append_str * x,const char * s)5719 pr_append(pr_append_str *x,
5720                  const char *s)
5721 {
5722   if (pr_append_external(x, s)) longjmp(_jmp_buf, 1);
5723 }
5724 
5725 /* ============================================================ */
5726 /* END internal and external functions for pr_append_str        */
5727 /* ============================================================ */
5728 
5729 
5730 /* =========================================================== */
5731 /* Malloc and realloc wrappers that longjmp() on failure       */
5732 /* =========================================================== */
5733 static void *
pr_safe_malloc(size_t x)5734 pr_safe_malloc(size_t x)
5735 {
5736   void *r = malloc(x);
5737   if (NULL == r) longjmp(_jmp_buf, 1);
5738   return r;
5739 }
5740 
5741 static void *
pr_safe_realloc(void * p,size_t x)5742 pr_safe_realloc(void *p, size_t x)
5743 {
5744   void *r = realloc(p, x);
5745   if (NULL == r) longjmp(_jmp_buf, 1);
5746   return r;
5747 }
5748 
5749 /* =========================================================== */
5750 /* End of malloc/realloc wrappers.                             */
5751 /* =========================================================== */
5752 
5753 
5754 /* ============================================================ */
5755 /* START functions which check and modify the input             */
5756 /* ============================================================ */
5757 
5758 /* Fuction to set the included region and fix the start positions */
5759 static void
_adjust_seq_args(const p3_global_settings * pa,seq_args * sa,pr_append_str * nonfatal_err,pr_append_str * warning)5760 _adjust_seq_args(const p3_global_settings *pa,
5761                  seq_args *sa,
5762                  pr_append_str *nonfatal_err,
5763                  pr_append_str *warning)
5764 {
5765   int seq_len, inc_len;
5766 
5767   /* Create a seq for check primers if needed */
5768   if (pa->primer_task == check_primers) {
5769     if (NULL == sa->sequence) {
5770       fake_a_sequence(sa, pa);
5771     }
5772   }
5773   if (pa->primer_task == pick_sequencing_primers && sa->incl_l != -1) {
5774     pr_append_new_chunk(nonfatal_err,
5775 			"Task pick_sequencing_primers cannot be combined with included region");
5776     return;
5777   }
5778 
5779   /*
5780      Complain if there is no sequence; We need to check this
5781      error here, because this function cannot do its work if
5782      sa->sequence == NULL
5783   */
5784   if (NULL == sa->sequence) {
5785     if (pa->primer_task == check_primers) {
5786       pr_append_new_chunk(nonfatal_err, "No primers provided");
5787     } else {
5788       pr_append_new_chunk(nonfatal_err, "Missing SEQUENCE tag");
5789     }
5790     return;
5791   }
5792 
5793   seq_len = strlen(sa->sequence);
5794 
5795   /* For pick_cloning_primers set the forced positions */
5796   if (pa->primer_task == pick_cloning_primers) {
5797     if(sa->incl_l == -1) {
5798       sa->force_left_start = pa->first_base_index;
5799       sa->force_right_start = seq_len + pa->first_base_index - 1;
5800     } else {
5801       sa->force_left_start = sa->incl_s;
5802       sa->force_right_start = sa->incl_s + sa->incl_l - 1;
5803     }
5804   }
5805 
5806   /* For pick_discriminative_primers set the forced positions */
5807   if (pa->primer_task == pick_discriminative_primers) {
5808     /* Changed here from incl_s and incl_l to sa->tar2->pairs[0][0/1] */
5809     if (sa->tar2.count != 1) {
5810       pr_append_new_chunk(nonfatal_err,
5811 			  "Task pick_discriminative_primers requires exactly one SEQUENCE_TARGET");
5812     }
5813     sa->force_left_end = sa->tar2.pairs[0][0];
5814     sa->force_right_end = sa->tar2.pairs[0][0] + sa->tar2.pairs[0][1] - 1;
5815   }
5816 
5817   /* If no included region is specified,
5818    * use the whole sequence as included region */
5819   if (sa->incl_l == -1) {
5820     sa->incl_l = seq_len;
5821     sa->incl_s = pa->first_base_index;
5822   }
5823 
5824   /* Generate at least one target */
5825   if (pa->primer_task == pick_sequencing_primers && sa->tar2.count == 0) {
5826     sa->tar2.pairs[0][0] = pa->first_base_index;
5827     sa->tar2.pairs[0][1] = seq_len;
5828     sa->tar2.count = 1;
5829   }
5830 
5831   /* Fix the start of the included region and start codon */
5832   sa->incl_s -= pa->first_base_index;
5833   sa->start_codon_pos -= pa->first_base_index;
5834 
5835   /* Fix the start */
5836   sa->force_left_start -= pa->first_base_index;
5837   sa->force_left_end -= pa->first_base_index;
5838   sa->force_right_start -= pa->first_base_index;
5839   sa->force_right_end -= pa->first_base_index;
5840 
5841   /* Make it relative to included region */
5842   sa->force_left_start -= sa->incl_s;
5843   sa->force_left_end -= sa->incl_s;
5844   sa->force_right_start -= sa->incl_s;
5845   sa->force_right_end -= sa->incl_s;
5846 
5847   inc_len = sa->incl_s + sa->incl_l - 1;
5848 
5849   if ((sa->incl_l < INT_MAX) && (sa->incl_s > -1)
5850       && (sa->incl_l > -1) && (inc_len < seq_len) ) {
5851     /* Copies inluded region into trimmed_seq */
5852     sa->trimmed_seq = (char *) pr_safe_malloc(sa->incl_l + 1);
5853     _pr_substr(sa->sequence, sa->incl_s, sa->incl_l, sa->trimmed_seq);
5854 
5855     /* Copies inluded region into trimmed_orig_seq */
5856     /* edited by T. Koressaar for lowercase masking */
5857     sa->trimmed_orig_seq = (char *) pr_safe_malloc(sa->incl_l + 1);
5858     _pr_substr(sa->sequence, sa->incl_s, sa->incl_l, sa->trimmed_orig_seq);
5859 
5860     /* Copies the whole sequence into upcased_seq */
5861     sa->upcased_seq = (char *) pr_safe_malloc(strlen(sa->sequence) + 1);
5862     strcpy(sa->upcased_seq, sa->sequence);
5863     dna_to_upper(sa->upcased_seq, 1);
5864     /* We do not need to check for illegal characters in the return
5865        from dna_to_upper(), because errors are checked in
5866        _pr_data_control sa->trimmed_seq. */
5867 
5868     /* Copies the reverse complement of the whole sequence into upcased_seq_r */
5869     sa->upcased_seq_r = (char *) pr_safe_malloc(strlen(sa->sequence) + 1);
5870     p3_reverse_complement(sa->upcased_seq, sa->upcased_seq_r);
5871   }
5872 
5873   if (_check_and_adjust_intervals(sa,
5874                                   seq_len,
5875                                   pa->first_base_index,
5876                                   nonfatal_err, warning)) {
5877     return;
5878   }
5879 
5880   if (_check_and_adjust_overlap_pos(sa,
5881                                     sa->primer_overlap_junctions,
5882                                     &sa->primer_overlap_junctions_count,
5883                                     "SEQUENCE_OVERLAP_JUNCTION_LIST",
5884                                     seq_len,
5885                                     pa->first_base_index,
5886                                     nonfatal_err, warning)) {
5887     return;
5888   }
5889 
5890   /* Update ok regions, if non empty */
5891   if (sa->ok_regions.count > 0) {
5892     _optimize_ok_regions_list(pa, sa);
5893   }
5894 
5895 }
5896 
5897 /*
5898  * This function uses the max/min product size info and the max/min
5899  * oligo length in order to reduce the ranges of the ok regions. On
5900  * some imputs this improves speed dramatically.
5901  */
5902 static void
_optimize_ok_regions_list(const p3_global_settings * pa,seq_args * sa)5903 _optimize_ok_regions_list(const p3_global_settings *pa,
5904 			  seq_args *sa)
5905 {
5906   /* We do this only if we enabled the optimization and
5907    * the primers were NOT specified. */
5908   if (!OPTIMIZE_OK_REGIONS || (sa->left_input) || (sa->right_input)) {
5909     return;
5910   }
5911 
5912   /* If any pair is allowed, no point in doing this */
5913   if (sa->ok_regions.any_pair) {
5914     return;
5915   }
5916 
5917   int pmin = INT_MAX;
5918   int pmax = 0;
5919   int omin = pa->p_args.min_size;
5920   int omax = pa->p_args.max_size;
5921 
5922   /* Determine min/max product size */
5923   for (int i=0; i<pa->num_intervals; i++) {
5924     if (pa->pr_min[i] < pmin) { pmin = pa->pr_min[i]; }
5925     if (pa->pr_max[i] > pmax) { pmax = pa->pr_max[i]; }
5926   }
5927 
5928   /* Update each region */
5929   for (int i=0; i<sa->ok_regions.count; i++) {
5930     int ls = -1, le = -1, rs = -1, re = -1;
5931     int new_ls = -1, new_le = -1, new_rs = -1, new_re = -1;
5932     if (sa->ok_regions.left_pairs[i][0] != -1) {
5933       ls = sa->ok_regions.left_pairs[i][0];
5934       le = sa->ok_regions.left_pairs[i][0]
5935 	+ sa->ok_regions.left_pairs[i][1] - 1;
5936     }
5937     if (sa->ok_regions.right_pairs[i][0] != -1) {
5938       rs = sa->ok_regions.right_pairs[i][0];
5939       re = sa->ok_regions.right_pairs[i][0]
5940 	+ sa->ok_regions.right_pairs[i][1] - 1;
5941     }
5942     /* Compute new right region based on left range and min/max values
5943        of product size and oligo length */
5944     if (ls != -1) {
5945       new_rs = ls + pmin - omax - 1; /* -1 just to be safe */
5946       new_re = le - omin + pmax + 1; /* +1 just to be safe */
5947       /* Adjust the ranges */
5948       if ((rs == -1) || (new_rs > rs)) { rs = new_rs; }
5949       if ((re == -1) || (new_re < re)) { re = new_re; }
5950       if (rs < 0) { rs = 0; }
5951       if (re > (signed) strlen(sa->sequence)) { re = strlen(sa->sequence); }
5952     }
5953     /* Compute new left region based on right range and min/max values
5954        of product size and oligo length */
5955     if (rs != -1) {
5956       new_ls = rs + omin - pmax - 1; /* -1 just to be safe */
5957       new_le = re - pmin + omax + 1; /* +1 just to be safe */
5958       /* Adjust the ranges */
5959       if ((ls == -1) || (new_ls > ls)) { ls = new_ls; }
5960       if ((le == -1) || (new_le < le)) { le = new_le; }
5961       if (ls < 0) { ls = 0; }
5962       if (le > (signed) strlen(sa->sequence)) { le = strlen(sa->sequence); }
5963     }
5964     /* Temporary testing fprintf: */
5965     /* fprintf(stderr, "Adjusted range [%d,%d,%d,%d] to [%d,%d,%d,%d],
5966 	    pmin is %d, pmax is %d, omin is %d, omax is %d\n",
5967 	    sa->ok_regions.left_pairs[i][0],
5968 	    sa->ok_regions.left_pairs[i][0] +
5969 	    sa->ok_regions.left_pairs[i][1] - 1,
5970 	    sa->ok_regions.right_pairs[i][0],
5971 	    sa->ok_regions.right_pairs[i][0] +
5972 	    sa->ok_regions.right_pairs[i][1] - 1, ls, le, rs, re,
5973 	    pmin, pmax, omin, omax);
5974     */
5975     sa->ok_regions.left_pairs[i][0] = ls;
5976     sa->ok_regions.left_pairs[i][1] = le - ls + 1;
5977     sa->ok_regions.right_pairs[i][0] = rs;
5978     sa->ok_regions.right_pairs[i][1] = re - rs + 1;
5979   }
5980   /* any_left and any_right not true anymore */
5981   sa->ok_regions.any_left = 0;
5982   sa->ok_regions.any_right = 0;
5983 }
5984 
5985 /*
5986  * Return 1 on error, 0 on success.  fake_a_sequence creates a sequence
5987  * out of the provided primers and puts them in sa.
5988  */
5989 
5990 static int
fake_a_sequence(seq_args * sa,const p3_global_settings * pa)5991 fake_a_sequence(seq_args *sa, const p3_global_settings *pa)
5992 {
5993   int i, product_size, space, ns_to_fill;
5994   char *rev = NULL;
5995   int ns_to_fill_first, ns_to_fill_second;
5996 
5997   /* Determine the product size */
5998   if ( pa->product_opt_size == PR_UNDEFINED_INT_OPT){
5999     product_size = pa->pr_max[0] - pa->pr_min[0];
6000   } else {
6001     product_size = pa->product_opt_size;
6002   }
6003 
6004   space = product_size + 1;
6005   ns_to_fill = product_size;
6006 
6007 
6008   /* Calculate how many Ns have to be added */
6009   if (sa->left_input){
6010     ns_to_fill = ns_to_fill - strlen(sa->left_input);
6011   }
6012   if (sa->right_input){
6013     ns_to_fill = ns_to_fill - strlen(sa->right_input);
6014     rev = (char *) pr_safe_malloc(strlen(sa->right_input) + 1);
6015     p3_reverse_complement(sa->right_input, rev);
6016   }
6017   if (sa->internal_input){
6018           ns_to_fill = ns_to_fill - strlen(sa->internal_input);
6019   }
6020   /* Return if there are no primers provided */
6021   if (ns_to_fill == product_size + 1){
6022     return 0;
6023   }
6024   ns_to_fill_first = ns_to_fill / 2;
6025   ns_to_fill_second = ns_to_fill - ns_to_fill_first;
6026   /* Allocate the space for the sequence */
6027   sa->sequence = (char *) pr_safe_malloc(space);
6028   *sa->sequence = '\0';
6029   /* Copy over the primers */
6030   if (sa->left_input){
6031     strcat(sa->sequence, sa->left_input);
6032   }
6033 
6034   /* Add the Ns*/
6035   for (i = 0; i < ns_to_fill_first; i++ ) {
6036     strcat(sa->sequence, "N\0");
6037   }
6038   if (sa->internal_input){
6039     strcat(sa->sequence, sa->internal_input);
6040   }
6041   for (i = 0; i < ns_to_fill_second; i++ ) {
6042     strcat(sa->sequence, "N\0");
6043   }
6044   if (sa->right_input){
6045     strcat(sa->sequence, rev);
6046   }
6047   free(rev);
6048   return 0;
6049 }
6050 
6051 /*
6052  * Return 1 on error, 0 on success.  Set sa->trimmed_seq and possibly modify
6053  * sa->tar.  Upcase and check all bases in sa->trimmed_seq.
6054  * TO DO -- this would probably be cleaner if it only
6055  * checked, rather than updated, sa.
6056  */
6057 /* Check if the input in sa and pa makes sense */
6058 int
_pr_data_control(const p3_global_settings * pa,const seq_args * sa,pr_append_str * glob_err,pr_append_str * nonfatal_err,pr_append_str * warning)6059 _pr_data_control(const p3_global_settings *pa,
6060                  const seq_args *sa,
6061                  pr_append_str *glob_err,
6062                  pr_append_str *nonfatal_err,
6063                  pr_append_str *warning)
6064 {
6065   static char s1[MAX_PRIMER_LENGTH+1];
6066   int i, pr_min, seq_len;
6067   char offending_char = '\0';
6068 
6069   seq_len = strlen(sa->sequence);
6070 
6071   /* If sequence quality is provided, is it as long as the sequence? */
6072   if (sa->n_quality !=0 && sa->n_quality != seq_len)
6073     pr_append_new_chunk(nonfatal_err,
6074                         "Error in sequence quality data");
6075 
6076   if ((pa->min_left_three_prime_distance < -1) ||
6077       (pa->min_right_three_prime_distance < -1))
6078     pr_append_new_chunk(nonfatal_err,
6079                         "Minimum 3' distance must be >= -1 "
6080                         "(min_*_three_prime_distance)");
6081 
6082   if ((pa->p_args.min_quality != 0 || pa->o_args.min_quality != 0)
6083       && sa->n_quality == 0)
6084     pr_append_new_chunk(nonfatal_err, "Sequence quality data missing");
6085 
6086   if (pa->first_base_index < PR_NULL_FORCE_POSITION) {
6087     pr_append_new_chunk(glob_err, "Value too small at tag PRIMER_FIRST_BASE_INDEX");
6088     return 1;
6089   }
6090 
6091   if (pa->p_args.max_template_mispriming > SHRT_MAX && pa->thermodynamic_template_alignment == 0) {
6092     pr_append_new_chunk(glob_err, "Value too large at tag PRIMER_MAX_TEMPLATE_MISPRIMING");
6093     return 1;
6094   }
6095 
6096   if (pa->pair_max_template_mispriming > SHRT_MAX && pa->thermodynamic_template_alignment == 0) {
6097     pr_append_new_chunk(glob_err, "Value too large at tag PRIMER_PAIR_MAX_TEMPLATE_MISPRIMING");
6098     return 1;
6099   }
6100 
6101   if (pa->p_args.max_repeat_compl > SHRT_MAX && pa->thermodynamic_oligo_alignment == 0) {
6102     pr_append_new_chunk(glob_err, "Value too large at tag PRIMER_MAX_LIBRARY_MISPRIMING");
6103     return 1;
6104   }
6105 
6106   if (pa->o_args.max_repeat_compl > SHRT_MAX && pa->thermodynamic_oligo_alignment == 0) {
6107     pr_append_new_chunk(glob_err, "Value too large at tag PRIMER_INTERNAL_MAX_LIBRARY_MISHYB");
6108     return 1;
6109   }
6110 
6111   if (pa->pair_repeat_compl > SHRT_MAX && pa->thermodynamic_oligo_alignment == 0) {
6112     pr_append_new_chunk(glob_err, "Value too large at tag PRIMER_PAIR_MAX_LIBRARY_MISPRIMING");
6113     return 1;
6114   }
6115 
6116   if (pa->o_args.max_template_mispriming >= 0 && pa->thermodynamic_template_alignment==0)
6117     pr_append_new_chunk(glob_err,
6118                         "PRIMER_INTERNAL_MAX_TEMPLATE_MISHYB is not supported");
6119   if (pa->o_args.max_template_mispriming_th >= 0 && pa->thermodynamic_template_alignment==1)
6120     pr_append_new_chunk(glob_err,
6121                         "PRIMER_INTERNAL_MAX_TEMPLATE_MISHYB_TH is not supported");
6122   if (pa->p_args.min_size < 1)
6123     pr_append_new_chunk(glob_err, "PRIMER_MIN_SIZE must be >= 1");
6124 
6125   if (pa->p_args.max_size > MAX_PRIMER_LENGTH) {
6126     pr_append_new_chunk(glob_err,
6127                         "PRIMER_MAX_SIZE exceeds built-in maximum of ");
6128     pr_append(glob_err, MACRO_VALUE_AS_STRING(MAX_PRIMER_LENGTH));
6129     return 1;
6130   }
6131 
6132   if (pa->p_args.opt_size > pa->p_args.max_size) {
6133     pr_append_new_chunk(glob_err,
6134                         "PRIMER_{OPT,DEFAULT}_SIZE > PRIMER_MAX_SIZE");
6135     return 1;
6136   }
6137 
6138   if (pa->p_args.opt_size < pa->p_args.min_size) {
6139     pr_append_new_chunk(glob_err,
6140                         "PRIMER_{OPT,DEFAULT}_SIZE < PRIMER_MIN_SIZE");
6141     return 1;
6142   }
6143 
6144   if (pa->o_args.max_size > MAX_PRIMER_LENGTH) {
6145     pr_append_new_chunk(glob_err,
6146                         "PRIMER_INTERNAL_MAX_SIZE exceeds built-in maximum");
6147     return 1;
6148   }
6149 
6150   if (pa->o_args.opt_size > pa->o_args.max_size) {
6151     pr_append_new_chunk(glob_err,
6152                         "PRIMER_INTERNAL_{OPT,DEFAULT}_SIZE > MAX_SIZE");
6153     return 1;
6154   }
6155 
6156   if (pa->o_args.opt_size < pa->o_args.min_size) {
6157     pr_append_new_chunk(glob_err,
6158                         "PRIMER_INTERNAL_{OPT,DEFAULT}_SIZE < MIN_SIZE");
6159     return 1;
6160   }
6161 
6162   /* A GC clamp can not be bigger then the primer */
6163   if (pa->gc_clamp > pa->p_args.min_size) {
6164     pr_append_new_chunk(glob_err,
6165                         "PRIMER_GC_CLAMP > PRIMER_MIN_SIZE");
6166     return 1;
6167   }
6168 
6169   /* Must be >= 0 and <= 5 */
6170   if ((pa->max_end_gc < 0)
6171       || (pa->max_end_gc > 5)) {
6172     pr_append_new_chunk(glob_err,
6173                         "PRIMER_MAX_END_GC must be between 0 to 5");
6174     return 1;
6175   }
6176 
6177   /* Product size must be provided */
6178   if (0 == pa->num_intervals) {
6179     pr_append_new_chunk( glob_err,
6180                          "Empty value for PRIMER_PRODUCT_SIZE_RANGE");
6181     return 1;
6182   }
6183   for (i = 0; i < pa->num_intervals; i++) {
6184     if (pa->pr_min[i] > pa->pr_max[i] || pa->pr_min[i] < 0) {
6185       pr_append_new_chunk(glob_err,
6186                           "Illegal element in PRIMER_PRODUCT_SIZE_RANGE");
6187       return 1;
6188     }
6189   }
6190 
6191   pr_min = INT_MAX;
6192   /* Check if the primer is bigger then the product */
6193   for(i=0;i<pa->num_intervals;i++)
6194     if(pa->pr_min[i]<pr_min) pr_min=pa->pr_min[i];
6195 
6196   if (pa->p_args.max_size > pr_min) {
6197     pr_append_new_chunk(glob_err,
6198                         "PRIMER_MAX_SIZE > min PRIMER_PRODUCT_SIZE_RANGE");
6199     return 1;
6200   }
6201 
6202   if ((pa->pick_internal_oligo == 1 )
6203       && pa->o_args.max_size > pr_min) {
6204     pr_append_new_chunk(glob_err,
6205                         "PRIMER_INTERNAL_MAX_SIZE > min PRIMER_PRODUCT_SIZE_RANGE");
6206     return 1;
6207   }
6208 
6209   /* There must be at least one primer returned */
6210   if (pa->num_return < 1) {
6211     pr_append_new_chunk(glob_err,
6212                         "PRIMER_NUM_RETURN < 1");
6213     return 1;
6214   }
6215 
6216   if ((pa->p_args.must_match_five_prime != NULL) && (strlen(pa->p_args.must_match_five_prime) != 5)) {
6217     pr_append_new_chunk(glob_err,
6218                         "PRIMER_MUST_MATCH_FIVE_PRIME must have 5 characters");
6219     return 1;
6220   }
6221   if ((pa->p_args.must_match_three_prime != NULL) && (strlen(pa->p_args.must_match_three_prime) != 5)) {
6222     pr_append_new_chunk(glob_err,
6223                         "PRIMER_MUST_MATCH_THREE_PRIME must have 5 characters");
6224     return 1;
6225   }
6226   if ((pa->o_args.must_match_five_prime != NULL) && (strlen(pa->o_args.must_match_five_prime) != 5)) {
6227     pr_append_new_chunk(glob_err,
6228                         "PRIMER_INTERNAL_MUST_MATCH_FIVE_PRIME must have 5 characters");
6229     return 1;
6230   }
6231   if ((pa->o_args.must_match_three_prime != NULL) && (strlen(pa->o_args.must_match_three_prime) != 5)) {
6232     pr_append_new_chunk(glob_err,
6233                         "PRIMER_INTERNAL_MUST_MATCH_THREE_PRIME must have 5 characters");
6234     return 1;
6235   }
6236 
6237   if (sa->incl_l >= INT_MAX) {
6238     pr_append_new_chunk(nonfatal_err, "Value for SEQUENCE_INCLUDED_REGION too large");
6239     return 1;
6240   }
6241 
6242   if (sa->incl_s < 0 || sa->incl_l < 0
6243       || sa->incl_s + sa->incl_l > seq_len) {
6244     pr_append_new_chunk(nonfatal_err, "Illegal value for SEQUENCE_INCLUDED_REGION");
6245     return 1;
6246   }
6247 
6248   /* The product must fit in the included region */
6249   if (sa->incl_l < pr_min && pa->pick_left_primer == 1
6250       && pa->pick_right_primer == 1) {
6251     if (pa->primer_task == check_primers) {
6252       pr_append_new_chunk(warning,
6253                           "SEQUENCE_INCLUDED_REGION length < min PRIMER_PRODUCT_SIZE_RANGE");
6254     } else if (pa->primer_task != pick_primer_list) {
6255       pr_append_new_chunk(nonfatal_err,
6256                           "SEQUENCE_INCLUDED_REGION length < min PRIMER_PRODUCT_SIZE_RANGE");
6257     }
6258 
6259     if (pa->primer_task == generic) {
6260       return 1;
6261     }
6262   }
6263 
6264   if (pa->max_end_stability < 0) {
6265     pr_append_new_chunk(nonfatal_err,
6266                         "PRIMER_MAX_END_STABILITY must be non-negative");
6267     return 1;
6268   }
6269 
6270   /* Is the startodon ATG and in the incl. region */
6271   if (!PR_START_CODON_POS_IS_NULL(sa)) {
6272     if (!PR_POSITION_PENALTY_IS_NULL(pa)) {
6273       pr_append_new_chunk(nonfatal_err,
6274                           "Cannot accept both SEQUENCE_START_CODON_POSITION and non-default ");
6275       pr_append(nonfatal_err,
6276                 "arguments for PRIMER_INSIDE_PENALTY or PRIMER_OUTSIDE_PENALTY");
6277     }
6278     if (sa->start_codon_pos  > (sa->incl_s + sa->incl_l - 3)) {
6279       pr_append_new_chunk(nonfatal_err,
6280                           "Start codon position not contained in SEQUENCE_INCLUDED_REGION");
6281       return 1;
6282     } else {
6283       if (sa->start_codon_pos >= 0
6284           && ((sa->sequence[sa->start_codon_pos] != 'A'
6285                && sa->sequence[sa->start_codon_pos] != 'a')
6286               || (sa->sequence[sa->start_codon_pos + 1] != 'T'
6287                   && sa->sequence[sa->start_codon_pos + 1] != 't')
6288               || (sa->sequence[sa->start_codon_pos + 2] != 'G'
6289                   && sa->sequence[sa->start_codon_pos + 2] != 'g'))) {
6290         pr_append_new_chunk(nonfatal_err,
6291                             "No start codon at SEQUENCE_START_CODON_POSITION");
6292         return 1;
6293       }
6294     }
6295   }
6296 
6297   if (NULL != sa->quality) {
6298     if(pa->p_args.min_quality != 0 && pa->p_args.min_quality < pa->quality_range_min) {
6299       pr_append_new_chunk(glob_err,
6300                           "PRIMER_MIN_QUALITY < PRIMER_QUALITY_RANGE_MIN");
6301       return 1;
6302     }
6303     if (pa->p_args.min_quality != 0 && pa->p_args.min_quality > pa->quality_range_max) {
6304       pr_append_new_chunk(glob_err,
6305                           "PRIMER_MIN_QUALITY > PRIMER_QUALITY_RANGE_MAX");
6306       return 1;
6307     }
6308     if (pa->o_args.min_quality != 0 && pa->o_args.min_quality <pa->quality_range_min) {
6309       pr_append_new_chunk(glob_err,
6310                           "PRIMER_INTERNAL_MIN_QUALITY < PRIMER_QUALITY_RANGE_MIN");
6311       return 1;
6312     }
6313     if (pa->o_args.min_quality != 0 && pa->o_args.min_quality > pa->quality_range_max) {
6314       pr_append_new_chunk(glob_err,
6315                           "PRIMER_INTERNAL_MIN_QUALITY > PRIMER_QUALITY_RANGE_MAX");
6316       return 1;
6317     }
6318     for(i=0; i < sa->n_quality; i++) {
6319       if(sa->quality[i] < pa->quality_range_min ||
6320          sa->quality[i] > pa->quality_range_max) {
6321         pr_append_new_chunk(nonfatal_err,
6322                             "Sequence quality score out of range");
6323         return 1;
6324       }
6325     }
6326   }
6327   else if (pa->p_args.weights.seq_quality || pa->o_args.weights.seq_quality) {
6328     pr_append_new_chunk(nonfatal_err,
6329                         "Sequence quality is part of objective function but sequence quality is not defined");
6330     return 1;
6331   }
6332 
6333   if ((offending_char = dna_to_upper(sa->trimmed_seq, 0))) {
6334     if (pa->liberal_base) {
6335       pr_append_new_chunk(warning,
6336                           "Unrecognized base in input sequence");
6337     }
6338     else {
6339       pr_append_new_chunk(nonfatal_err,
6340                           "Unrecognized base in input sequence");
6341       return 1;
6342     }
6343   }
6344 
6345   if (pa->p_args.opt_tm < pa->p_args.min_tm
6346       || pa->p_args.opt_tm > pa->p_args.max_tm) {
6347     pr_append_new_chunk(glob_err,
6348                         "Optimum primer Tm lower than minimum or higher than maximum");
6349     return 1;
6350   }
6351 
6352   if (pa->o_args.opt_tm < pa->o_args.min_tm
6353       || pa->o_args.opt_tm > pa->o_args.max_tm) {
6354     pr_append_new_chunk(glob_err,
6355                         "Optimum internal oligo Tm lower than minimum or higher than maximum");
6356     return 1;
6357   }
6358 
6359   if (pa->p_args.min_gc > pa->p_args.max_gc
6360       || pa->p_args.min_gc > 100
6361       || pa->p_args.max_gc < 0){
6362     pr_append_new_chunk(glob_err,
6363                         "Illegal value for PRIMER_MAX_GC and PRIMER_MIN_GC");
6364     return 1;
6365   }
6366 
6367   if (pa->o_args.min_gc > pa->o_args.max_gc
6368       || pa->o_args.min_gc > 100
6369       || pa->o_args.max_gc < 0) {
6370     pr_append_new_chunk(glob_err,
6371                         "Illegal value for PRIMER_INTERNAL_OLIGO_GC");
6372     return 1;
6373   }
6374   if (pa->p_args.num_ns_accepted < 0) {
6375     pr_append_new_chunk(glob_err,
6376                         "Illegal value for PRIMER_MAX_NS_ACCEPTED");
6377     return 1;
6378   }
6379   if (pa->o_args.num_ns_accepted < 0){
6380     pr_append_new_chunk(glob_err,
6381                         "Illegal value for PRIMER_INTERNAL_MAX_NS_ACCEPTED");
6382     return 1;
6383   }
6384   if (pa->p_args.max_self_any < 0 || pa->p_args.max_self_any > SHRT_MAX
6385       || pa->p_args.max_self_end < 0 || pa->p_args.max_self_end > SHRT_MAX
6386       || pa->pair_compl_any < 0 || pa->pair_compl_any > SHRT_MAX
6387       || pa->pair_compl_end < 0 || pa->pair_compl_end > SHRT_MAX) {
6388     pr_append_new_chunk(glob_err,
6389                         "Illegal value for primer complementarity restrictions");
6390     return 1;
6391   }
6392 
6393   if (pa->p_args.max_self_any_th < 0
6394       || pa->p_args.max_self_end_th < 0 || pa->p_args.max_hairpin_th < 0
6395       || pa->pair_compl_any_th < 0 || pa->pair_compl_end_th < 0) {
6396      pr_append_new_chunk(glob_err,
6397                          "Illegal value for primer complementarity restrictions (thermod. approach)");
6398      return 1;
6399   }
6400 
6401   if( pa->o_args.max_self_any < 0 || pa->o_args.max_self_any > SHRT_MAX
6402       || pa->o_args.max_self_end < 0 || pa->o_args.max_self_end > SHRT_MAX) {
6403     pr_append_new_chunk(glob_err,
6404                         "Illegal value for internal oligo complementarity restrictions");
6405     return 1;
6406   }
6407 
6408   if( pa->o_args.max_self_any_th < 0
6409       || pa->o_args.max_self_end_th < 0 || pa->o_args.max_hairpin_th < 0) {
6410      pr_append_new_chunk(glob_err,
6411                          "Illegal value for internal oligo complementarity restrictions");
6412      return 1;
6413   }
6414 
6415   if (pa->p_args.salt_conc <= 0 || pa->p_args.dna_conc<=0){
6416     pr_append_new_chunk(glob_err,
6417                         "Illegal value for primer salt or dna concentration");
6418     return 1;
6419   }
6420 
6421   if((pa->p_args.dntp_conc < 0 && pa->p_args.divalent_conc !=0 )
6422      || pa->p_args.divalent_conc<0){ /* added by T.Koressaar */
6423     pr_append_new_chunk(glob_err, "Illegal value for primer divalent salt or dNTP concentration");
6424     return 1;
6425   }
6426 
6427   if(pa->o_args.salt_conc<=0||pa->o_args.dna_conc<=0){
6428     pr_append_new_chunk(glob_err,
6429                         "Illegal value for internal oligo salt or dna concentration");
6430     return 1;
6431   }
6432 
6433   if((pa->o_args.dntp_conc<0 && pa->o_args.divalent_conc!=0)
6434      || pa->o_args.divalent_conc < 0) { /* added by T.Koressaar */
6435     pr_append_new_chunk(glob_err,
6436                         "Illegal value for internal oligo divalent salt or dNTP concentration");
6437     return 1;
6438   }
6439 
6440   if (!_PR_DEFAULT_POSITION_PENALTIES(pa) && sa->tar2.count > 1) {
6441     pr_append_new_chunk(nonfatal_err,
6442                         "Non-default inside penalty or outside penalty ");
6443     pr_append(nonfatal_err,
6444               "is valid only when number of targets <= 1");
6445   }
6446   if (!_PR_DEFAULT_POSITION_PENALTIES(pa) && 0 == sa->tar2.count) {
6447     pr_append_new_chunk(warning,
6448                         "Non-default inside penalty or outside penalty ");
6449     pr_append(warning,
6450               "has no effect when number of targets is 0");
6451   }
6452   if (pa->pick_internal_oligo != 1 && sa->internal_input) {
6453     pr_append_new_chunk(nonfatal_err,
6454                         "Not specified to pick internal oligos");
6455     pr_append(nonfatal_err,
6456               " but a specific internal oligo is provided");
6457   }
6458   if (sa->internal_input) {
6459     if (strlen(sa->internal_input) > MAX_PRIMER_LENGTH) {
6460       pr_append_new_chunk(glob_err,
6461                           "Specified internal oligo exceeds built-in maximum of ");
6462       pr_append(glob_err, MACRO_VALUE_AS_STRING(MAX_PRIMER_LENGTH));
6463       return 1;
6464     }
6465     if (strlen(sa->internal_input) > (unsigned) pa->o_args.max_size)
6466       pr_append_new_chunk(warning,
6467                           "Specified internal oligo > PRIMER_INTERNAL_MAX_SIZE");
6468 
6469     if (strlen(sa->internal_input) < (unsigned) pa->o_args.min_size)
6470       pr_append_new_chunk(warning,
6471                           "Specified internal oligo < PRIMER_INTERNAL_MIN_SIZE");
6472 
6473     if (!strstr_nocase(sa->sequence, sa->internal_input))
6474       pr_append_new_chunk(nonfatal_err,
6475                           "Specified internal oligo not in sequence");
6476     else if (!strstr_nocase(sa->trimmed_seq, sa->internal_input))
6477       pr_append_new_chunk(nonfatal_err,
6478                           "Specified internal oligo not in Included Region");
6479   }
6480   if (sa->left_input) {
6481     if (strlen(sa->left_input) > MAX_PRIMER_LENGTH) {
6482       pr_append_new_chunk(glob_err,
6483                           "Specified left primer exceeds built-in maximum of ");
6484       pr_append(glob_err, MACRO_VALUE_AS_STRING(MAX_PRIMER_LENGTH));
6485       return 1;
6486     }
6487     if (strlen(sa->left_input) > (unsigned) pa->p_args.max_size)
6488       pr_append_new_chunk(warning,
6489                           "Specified left primer > PRIMER_MAX_SIZE");
6490     if (strlen(sa->left_input) < (unsigned) pa->p_args.min_size)
6491       pr_append_new_chunk(warning,
6492                           "Specified left primer < PRIMER_MIN_SIZE");
6493     if (!strstr_nocase(sa->sequence, sa->left_input))
6494       pr_append_new_chunk(nonfatal_err,
6495                           "Specified left primer not in sequence");
6496     else if (!strstr_nocase(sa->trimmed_seq, sa->left_input))
6497       pr_append_new_chunk(nonfatal_err,
6498                           "Specified left primer not in Included Region");
6499   }
6500   if (sa->right_input) {
6501     if (strlen(sa->right_input) > MAX_PRIMER_LENGTH) {
6502       pr_append_new_chunk(glob_err,
6503                           "Specified right primer exceeds built-in maximum of ");
6504       pr_append(glob_err, MACRO_VALUE_AS_STRING(MAX_PRIMER_LENGTH));
6505       return 1;
6506     }
6507     if (strlen(sa->right_input) < (unsigned) pa->p_args.min_size)
6508       pr_append_new_chunk(warning,
6509                           "Specified right primer < PRIMER_MIN_SIZE");
6510     if (strlen(sa->right_input) > (unsigned) pa->p_args.max_size) {
6511       pr_append_new_chunk(warning,
6512                           "Specified right primer > PRIMER_MAX_SIZE");
6513     } else { /* We do not want to overflow s1. */
6514       p3_reverse_complement(sa->right_input,s1);
6515       if (!strstr_nocase(sa->sequence, s1))
6516         pr_append_new_chunk(nonfatal_err,
6517                             "Specified right primer not in sequence");
6518       else if (!strstr_nocase(sa->trimmed_seq, s1))
6519         pr_append_new_chunk(nonfatal_err,
6520                             "Specified right primer not in Included Region");
6521     }
6522   }
6523 
6524   if ((pa->pr_pair_weights.product_tm_lt ||
6525        pa->pr_pair_weights.product_tm_gt)
6526       && pa->product_opt_tm == PR_UNDEFINED_DBL_OPT) {
6527     pr_append_new_chunk(glob_err,
6528                         "Product temperature is part of objective function while optimum temperature is not defined");
6529     return 1;
6530   }
6531 
6532   if((pa->pr_pair_weights.product_size_lt ||
6533       pa->pr_pair_weights.product_size_gt)
6534      && pa->product_opt_size == PR_UNDEFINED_INT_OPT){
6535     pr_append_new_chunk(glob_err,
6536                         "Product size is part of objective function while optimum size is not defined");
6537     return 1;
6538   }
6539 
6540   if ((pa->p_args.weights.gc_content_lt ||
6541        pa->p_args.weights.gc_content_gt)
6542       && pa->p_args.opt_gc_content == DEFAULT_OPT_GC_PERCENT) {
6543     pr_append_new_chunk(glob_err,
6544                         "Primer GC content is part of objective function while optimum gc_content is not defined");
6545     return 1;
6546   }
6547 
6548   if ((pa->o_args.weights.gc_content_lt ||
6549        pa->o_args.weights.gc_content_gt)
6550       && pa->o_args.opt_gc_content == DEFAULT_OPT_GC_PERCENT) {
6551     pr_append_new_chunk(glob_err,
6552                         "Hyb probe GC content is part of objective function "
6553                         "while optimum gc_content is not defined");
6554     return 1;
6555   }
6556 
6557   if ((pa->pick_internal_oligo != 1) &&
6558       (pa->pr_pair_weights.io_quality)) {
6559     pr_append_new_chunk(glob_err,
6560                         "Internal oligo quality is part of objective function "
6561                         "while internal oligo choice is not required");
6562     return 1;
6563   }
6564 
6565   if (pa->p_args.weights.repeat_sim && (!seq_lib_num_seq(pa->p_args.repeat_lib))) {
6566     pr_append_new_chunk(glob_err,
6567                         "Mispriming score is part of objective function, but mispriming library is not defined");
6568     return 1;
6569   }
6570 
6571   if (pa->o_args.weights.repeat_sim && (!seq_lib_num_seq(pa->o_args.repeat_lib))) {
6572     pr_append_new_chunk(glob_err,
6573                         "Internal oligo mispriming score is part of objective function while mishyb library is not defined");
6574     return 1;
6575   }
6576 
6577   if (pa->pr_pair_weights.repeat_sim && (!(seq_lib_num_seq(pa->p_args.repeat_lib)))) {
6578     pr_append_new_chunk(glob_err,
6579                         "Mispriming score is part of objective function, "
6580                         "but mispriming library is not defined");
6581     return 1;
6582   }
6583 
6584   if(pa->pr_pair_weights.io_quality
6585      && pa->pick_internal_oligo == 0 ) {
6586     pr_append_new_chunk(glob_err,
6587                         "Internal oligo quality is part of objective function"
6588                         " while internal oligo choice is not required");
6589     return 1;
6590   }
6591 
6592   if (pa->sequencing.lead < 0) {
6593     pr_append_new_chunk(glob_err,
6594                         "Illegal value for PRIMER_SEQUENCING_LEAD");
6595     return 1;
6596   }
6597 
6598   if (pa->sequencing.interval < 0) {
6599     pr_append_new_chunk(glob_err,
6600                         "Illegal value for PRIMER_SEQUENCING_INTERVAL");
6601     return 1;
6602   }
6603 
6604   if (pa->sequencing.accuracy < 0) {
6605     pr_append_new_chunk(glob_err,
6606                         "Illegal value for PRIMER_SEQUENCING_ACCURACY");
6607     return 1;
6608   }
6609 
6610   if (pa->sequencing.spacing < 0) {
6611     pr_append_new_chunk(glob_err,
6612                         "Illegal value for PRIMER_SEQUENCING_SPACING");
6613     return 1;
6614   }
6615 
6616   if(pa->sequencing.interval > pa->sequencing.spacing) {
6617     pr_append_new_chunk(glob_err,
6618                         "PRIMER_SEQUENCING_INTERVAL > PRIMER_SEQUENCING_SPACING");
6619     return 1;
6620   }
6621 
6622   if(pa->sequencing.accuracy > pa->sequencing.spacing) {
6623     pr_append_new_chunk(glob_err,
6624                         "PRIMER_SEQUENCING_ACCURACY > PRIMER_SEQUENCING_SPACING");
6625     return 1;
6626   }
6627 
6628   if(pa->sequencing.lead > pa->sequencing.spacing) {
6629     pr_append_new_chunk(glob_err,
6630                         "PRIMER_SEQUENCING_LEAD > PRIMER_SEQUENCING_SPACING");
6631     return 1;
6632   }
6633 
6634   if((sa->force_left_start > -1) && (sa->force_left_end > -1)
6635      && (sa->force_left_start > sa->force_left_end)) {
6636     pr_append_new_chunk(glob_err,
6637                         "SEQUENCE_FORCE_LEFT_START > SEQUENCE_FORCE_LEFT_END");
6638     return 1;
6639   }
6640 
6641   if((sa->force_right_end > -1) && (sa->force_right_start > -1)
6642      && (sa->force_right_end > sa->force_right_start)) {
6643     pr_append_new_chunk(glob_err,
6644                         "SEQUENCE_FORCE_RIGHT_END > SEQUENCE_FORCE_RIGHT_START");
6645     return 1;
6646   }
6647 
6648   if (pa->min_5_prime_overlap_of_junction < 1) {
6649     pr_append_new_chunk(glob_err,
6650                         "Illegal value for PRIMER_MIN_5_PRIME_OVERLAP_OF_JUNCTION");
6651     return 1;
6652   }
6653 
6654   if (pa->min_3_prime_overlap_of_junction < 1) {
6655     pr_append_new_chunk(glob_err,
6656                         "Illegal value for PRIMER_MIN_3_PRIME_OVERLAP_OF_JUNCTION");
6657     return 1;
6658   }
6659 
6660   if ((sa->primer_overlap_junctions_count > 0) &&
6661       (pa->min_5_prime_overlap_of_junction > (pa->p_args.max_size / 2))) {
6662     pr_append_new_chunk(glob_err,
6663                         "PRIMER_MIN_5_PRIME_OVERLAP_OF_JUNCTION > PRIMER_MAX_SIZE / 2");
6664     return 1;
6665   }
6666 
6667   if ((sa->primer_overlap_junctions_count > 0) &&
6668       (pa->min_3_prime_overlap_of_junction > (pa->p_args.max_size / 2))) {
6669     pr_append_new_chunk(glob_err,
6670                         "PRIMER_MIN_3_PRIME_OVERLAP_OF_JUNCTION > PRIMER_MAX_SIZE / 2");
6671     return 1;
6672   }
6673 
6674   if (pa->p_args.divalent_conc > 0.0 && pa->p_args.dntp_conc <= 0.0) {
6675     pr_append_new_chunk(warning,
6676 			"PRIMER_SALT_DIVALENT > 0.0 "
6677 			"but PRIMER_DNTP_CONC <= 0.0; "
6678 			"use reasonable value for PRIMER_DNTP_CONC");
6679   }
6680 
6681   if ((pa->p_args.must_match_five_prime != NULL) &&
6682       (test_must_match_parameters(pa->p_args.must_match_five_prime))) {
6683     pr_append_new_chunk(glob_err,
6684                         "Illegal values for PRIMER_MUST_MATCH_FIVE_PRIME");
6685     return 1;
6686   }
6687 
6688   if ((pa->p_args.must_match_three_prime != NULL) &&
6689       (test_must_match_parameters(pa->p_args.must_match_three_prime))) {
6690     pr_append_new_chunk(glob_err,
6691                         "Illegal values for PRIMER_MUST_MATCH_THREE_PRIME");
6692     return 1;
6693   }
6694 
6695   if ((pa->o_args.must_match_five_prime != NULL) &&
6696       (test_must_match_parameters(pa->o_args.must_match_five_prime))) {
6697     pr_append_new_chunk(glob_err,
6698                         "Illegal values for PRIMER_INTERNAL_MUST_MATCH_FIVE_PRIME");
6699     return 1;
6700   }
6701 
6702   if ((pa->o_args.must_match_three_prime != NULL) &&
6703       (test_must_match_parameters(pa->o_args.must_match_three_prime))) {
6704     pr_append_new_chunk(glob_err,
6705                         "Illegal values for PRIMER_INTERNAL_MUST_MATCH_THREE_PRIME");
6706     return 1;
6707   }
6708 
6709   return (NULL == nonfatal_err->data && NULL == glob_err->data) ? 0 : 1;
6710 } /* _pr_data_control */
6711 
6712 static int
_check_and_adjust_overlap_pos(seq_args * sa,int * list,int * count,const char * tag,int seq_len,int first_index,pr_append_str * nonfatal_err,pr_append_str * warning)6713 _check_and_adjust_overlap_pos(seq_args *sa,
6714                               int *list,
6715                               int *count,
6716                               const char *tag,
6717                               int seq_len,
6718                               int first_index,
6719                               pr_append_str *nonfatal_err,
6720                               pr_append_str *warning) {
6721   int i;
6722   int outside_warning_issued = 0;
6723   char buffer[255];
6724 
6725   if (*count == 0) {
6726     return 0;
6727   }
6728 
6729   for (i = 0; i < *count; i++) {
6730     /* Subtract first_index from the "must overlap" positions */
6731     list[i] -= first_index;
6732 
6733     if (list[i] >= seq_len) {
6734       sprintf(buffer, "%s beyond end of sequence", tag);
6735       pr_append_new_chunk(nonfatal_err, buffer);
6736       return 1;
6737     }
6738 
6739     if (list[i] < 0) {
6740       sprintf(buffer, "Negative %s length", tag);
6741       pr_append_new_chunk(nonfatal_err, buffer);
6742       return 1;
6743     }
6744 
6745     /* Cause the intron positions to be relative to the included region. */
6746     list[i] -= sa->incl_s;
6747 
6748     /* Check that intron positions are within the included region. */
6749     if (list[i] < 0
6750         || list[i] > sa->incl_l) {
6751       if (!outside_warning_issued) {
6752         sprintf(buffer, "%s outside of INCLUDED_REGION", tag);
6753         pr_append_new_chunk(warning, buffer);
6754         outside_warning_issued = 1;
6755       }
6756     }
6757   }
6758 
6759   return 0;
6760 }
6761 
6762 static int
_check_and_adjust_intervals(seq_args * sa,int seq_len,int first_index,pr_append_str * nonfatal_err,pr_append_str * warning)6763 _check_and_adjust_intervals(seq_args *sa,
6764                             int seq_len,
6765                             int first_index,
6766                             pr_append_str * nonfatal_err,
6767                             pr_append_str *warning) {
6768 
6769   if (_check_and_adjust_1_interval("TARGET",
6770                                    sa->tar2.count,
6771                                    sa->tar2.pairs,
6772                                    seq_len,
6773                                    first_index,
6774                                    nonfatal_err, sa, warning, 0)
6775       == 1) return 1;
6776   sa->start_codon_pos -= sa->incl_s;
6777 
6778   if (_check_and_adjust_1_interval("EXCLUDED_REGION",
6779                                    sa->excl2.count, sa->excl2.pairs,
6780                                    seq_len, first_index,
6781                                    nonfatal_err, sa, warning, 0)
6782       == 1) return 1;
6783 
6784   if (_check_and_adjust_1_interval("PRIMER_INTERNAL_OLIGO_EXCLUDED_REGION",
6785                                    sa->excl_internal2.count,
6786                                    sa->excl_internal2.pairs,
6787                                    seq_len,
6788                                    first_index,
6789                                    nonfatal_err, sa, warning, 0)
6790       == 1) return 1;
6791   if (_check_and_adjust_1_interval("PRIMER_PAIR_OK_REGION_LIST",
6792                                    sa->ok_regions.count,
6793                                    sa->ok_regions.left_pairs,
6794                                    seq_len,
6795                                    first_index,
6796                                    nonfatal_err, sa, warning, 1)
6797       == 1) return 1;
6798   if (_check_and_adjust_1_interval("PRIMER_PAIR_OK_REGION_LIST",
6799                                    sa->ok_regions.count,
6800                                    sa->ok_regions.right_pairs,
6801                                    seq_len,
6802                                    first_index,
6803                                    nonfatal_err, sa, warning, 1)
6804       == 1) return 1;
6805   return 0;
6806 }
6807 
6808 /*
6809  * Check intervals, and add any errors to err.
6810  * Update the start of each interval to
6811  * be relative to the start of the included region.
6812  */
6813 static int
_check_and_adjust_1_interval(const char * tag_name,int num_intervals,interval_array_t intervals,int seq_len,int first_index,pr_append_str * err,seq_args * sa,pr_append_str * warning,int empty_allowed)6814 _check_and_adjust_1_interval(const char *tag_name,
6815                              int num_intervals,
6816                              interval_array_t intervals,
6817                              int seq_len,
6818                              int first_index,
6819                              pr_append_str *err,
6820                              seq_args *sa,
6821                              pr_append_str *warning,
6822                              int empty_allowed)
6823 {
6824   int i;
6825   int outside_warning_issued = 0;
6826 
6827   /* Subtract the first_index from the start positions in the interval
6828      array */
6829   for (i = 0; i < num_intervals; i++) {
6830     if (empty_allowed && (intervals[i][0] == -1) && (intervals[i][1] == -1))
6831       continue;
6832     if (empty_allowed && (((intervals[i][0] == -1) && (intervals[i][1] != -1))
6833                           || ((intervals[i][0] != -1) && (intervals[i][1] == -1)))) {
6834       pr_append_new_chunk(err, tag_name);
6835       pr_append(err, " illegal interval");
6836       return 1;
6837     }
6838     intervals[i][0] -= first_index;
6839   }
6840 
6841   for (i=0; i < num_intervals; i++) {
6842     if (empty_allowed && (intervals[i][0] == -1) && (intervals[i][1] == -1))
6843       continue;
6844     if (intervals[i][0] + intervals[i][1] > seq_len) {
6845       pr_append_new_chunk(err, tag_name);
6846       pr_append(err, " beyond end of sequence");
6847       return 1;
6848     }
6849     /* Cause the interval start to be relative to the included region. */
6850     intervals[i][0] -= sa->incl_s;
6851     /* Check that intervals are within the included region. */
6852     if (intervals[i][0] < 0
6853         || intervals[i][0] + intervals[i][1] > sa->incl_l) {
6854       if (!outside_warning_issued) {
6855         pr_append_new_chunk(warning, tag_name);
6856         pr_append(warning,
6857                   " outside of INCLUDED_REGION");
6858         outside_warning_issued = 1;
6859       }
6860     }
6861     if (intervals[i][1] < 0) {
6862       pr_append_new_chunk(err, "Negative ");
6863       pr_append(err, tag_name);
6864       pr_append(err, " length");
6865       return 1;
6866     }
6867   }
6868   return 0;
6869 } /* _check_and_adjust_intervals  */
6870 
6871 /* ============================================================ */
6872 /* END functions that check and modify the input                */
6873 /* ============================================================ */
6874 
6875 /* ============================================================ */
6876 /* BEGIN create primer files functions                          */
6877 /* ============================================================ */
6878 
6879 /* START OF WHAT SHOULD GO TO IO_PRIMER_FILES.C */
6880 
6881 /*
6882    Creates up to three files, the names of which are based on the
6883    argument 'file_name'.  One file is a table of forward primers, one
6884    a table of reverse primers, and one a table of internal
6885    hybridization oligos, depending on what the caller to
6886    choose_primers() requested (in the 'pa' argument).  Returns 0 on
6887    success, 1 on error.  On error, check errno for ENOMEM. Used to
6888    implement P3_FILE_FLAG=1.
6889  */
6890 int
p3_print_oligo_lists(const p3retval * retval,const seq_args * sa,const p3_global_settings * pa,pr_append_str * err,const char * file_name)6891 p3_print_oligo_lists(const p3retval *retval,
6892                      const seq_args *sa,
6893                      const p3_global_settings *pa,
6894                      pr_append_str *err,
6895                      const char *file_name)
6896 {
6897   /* Figure out if the sequence starts at position 1 or 0 */
6898   int   first_base_index = pa->first_base_index;
6899   int   ret;
6900   /* Start building up a filename */
6901   char *file;
6902   FILE *fh;
6903 
6904   if (setjmp(_jmp_buf) != 0) {
6905     return 1;  /* If we get here, that means we returned via a longjmp.
6906                   In this case errno should be ENOMEM. */
6907 
6908   }
6909 
6910   file = (char *) malloc(strlen(sa->sequence_name) + 5);
6911   if (NULL == file) return 1; /* ENOMEM */
6912 
6913   /* Check if the left primers have to be printed */
6914   if( pa->pick_left_primer ) {
6915     /* Create the file name and open file*/
6916     strcpy(file, sa->sequence_name);
6917     strcat(file, ".for");
6918     if (!(fh = fopen(file,"w"))) {
6919       if (pr_append_new_chunk_external(err, "Unable to open file "))
6920         return 1;
6921       if (pr_append_external(err, file)) return 1;
6922       if (pr_append_external(err, " for writing")) return 1;
6923       free(file);
6924       return 1;
6925     }
6926 
6927     /* Print the content to the file */
6928     ret =
6929       p3_print_one_oligo_list(sa, retval->fwd.num_elem,
6930 			      retval->fwd.oligo, OT_LEFT,
6931 			      first_base_index, NULL != pa->p_args.repeat_lib,
6932 			      fh,pa->thermodynamic_oligo_alignment);
6933     fclose(fh);
6934     if (ret) return 1;
6935   }
6936 
6937   /* Check if the right primers have to be printed */
6938   if (pa->pick_right_primer) {
6939     strcpy(file, sa->sequence_name);
6940     strcat(file, ".rev");
6941     if (!(fh = fopen(file,"w"))) {
6942       pr_append_new_chunk(err, "Unable to open file ");
6943       pr_append(err, file);
6944       pr_append(err, " for writing");
6945       free(file);
6946       return 1;
6947     }
6948     /* Print the content to the file */
6949     ret = p3_print_one_oligo_list(sa, retval->rev.num_elem,
6950 				  retval->rev.oligo, OT_RIGHT,
6951 				  first_base_index, NULL != pa->p_args.repeat_lib,
6952 				  fh, pa->thermodynamic_oligo_alignment);
6953 
6954     fclose(fh);
6955     if (ret) return 1;
6956   }
6957 
6958   /* Check if the internal oligos have to be printed */
6959   if (pa->pick_internal_oligo) {
6960     /* Create the file name and open file*/
6961     strcpy(file, sa->sequence_name);
6962     strcat(file, ".int");
6963     if (!(fh = fopen(file,"w"))) {
6964       if (pr_append_new_chunk_external(err, "Unable to open file "))
6965         return 1;
6966       if (pr_append_external(err, file)) return 1;
6967       if (pr_append_external(err, " for writing")) return 1;
6968       free(file);
6969       return 1;
6970     }
6971     /* Print the content to the file */
6972     ret = p3_print_one_oligo_list(sa, retval->intl.num_elem,
6973                                   retval->intl.oligo, OT_INTL,
6974                                   first_base_index,
6975                                   NULL != pa->o_args.repeat_lib,
6976 				  fh, pa->thermodynamic_oligo_alignment);
6977     fclose(fh);
6978     if (ret) return 1;
6979   }
6980   free(file);
6981   return 0;
6982 }
6983 
6984 /* Print out the content of one primer array */
6985 /* Return 1 on error, otherwise 0. */
6986 int
p3_print_one_oligo_list(const seq_args * sa,int n,const primer_rec * oligo_arr,const oligo_type o_type,const int first_base_index,const int print_lib_sim,FILE * fh,const int thermodynamic_oligo_alignment)6987 p3_print_one_oligo_list(const seq_args *sa,
6988                         int n,
6989                         const primer_rec *oligo_arr,
6990                         const oligo_type o_type,
6991                         const int first_base_index,
6992                         const int print_lib_sim,
6993                         FILE  *fh,
6994                         const int thermodynamic_oligo_alignment)
6995 {
6996   int i;
6997 
6998   /* Print out the header for the table */
6999   if (print_list_header(fh, o_type, first_base_index, print_lib_sim, thermodynamic_oligo_alignment))
7000     return 1; /* error */
7001   /* Iterate over the array */
7002   for (i = 0; i < n; i++) {
7003     /* Print each single oligo */
7004     if (print_oligo(fh, sa, i, &oligo_arr[i], o_type,
7005                     first_base_index, print_lib_sim, thermodynamic_oligo_alignment))
7006       return 1; /* error */
7007   }
7008   return 0; /* success */
7009 }
7010 
7011 static int
print_list_header(FILE * fh,oligo_type type,int first_base_index,int print_lib_sim,int thermodynamic_oligo_alignment)7012 print_list_header(FILE *fh,
7013                   oligo_type type,
7014                   int first_base_index,
7015                   int print_lib_sim,
7016                   int thermodynamic_oligo_alignment)
7017 {
7018   int ret;
7019   ret = fprintf(fh, "ACCEPTABLE %s\n",
7020                 OT_LEFT == type ? "LEFT PRIMERS"
7021                 : OT_RIGHT == type ? "RIGHT PRIMERS" : "INTERNAL OLIGOS");
7022   if (ret < 0) return 1;
7023 
7024   ret = fprintf(fh, "                               %4d-based     ",
7025                 first_base_index);
7026   if (ret < 0) return 1;
7027 
7028    if(thermodynamic_oligo_alignment)
7029      ret = fprintf(fh, "#                self   self hair-");
7030    else
7031      ret = fprintf(fh, "#               self  self");
7032    if (ret < 0) return 1;
7033    if (print_lib_sim)
7034      /* ret = fprintf(fh, "#               self  self   lib  qual-\n"); */
7035      ret = fprintf(fh, "   lib");
7036    if (ret < 0) return 1;
7037    ret = fprintf(fh, "  qual-\n");
7038    if (ret < 0) return 1;
7039 
7040    ret = fprintf(fh, "   # sequence                       start ln  ");
7041    if (ret < 0) return 1;
7042 
7043    ret = fprintf(fh, "N   GC%%     Tm");
7044    if (ret < 0) return 1;
7045    if(thermodynamic_oligo_alignment)
7046      ret = fprintf(fh, " any_th end_th   pin");
7047    else
7048      ret = fprintf(fh, "   any   end");
7049    if (ret < 0) return 1;
7050    if (print_lib_sim)
7051      ret = fprintf(fh, "   sim   lity\n");
7052    else
7053      ret = fprintf(fh, "   lity\n");
7054 
7055   if (ret < 0) return 1;
7056   return 0;
7057 }
7058 
7059 static int
print_oligo(FILE * fh,const seq_args * sa,int index,const primer_rec * h,oligo_type type,int first_base_index,int print_lib_sim,int thermodynamical_approach)7060 print_oligo(FILE *fh,
7061             const seq_args *sa,
7062             int index,
7063             const primer_rec *h,
7064             oligo_type type,
7065             int first_base_index,
7066             int print_lib_sim,
7067             int thermodynamical_approach)
7068 {
7069   int ret;
7070 
7071   /* WARNING, *p points to static storage that is overwritten on next
7072      call to pr_oligo_sequence or pr_oligo_rev_c_sequence. */
7073   char *p =
7074     (OT_RIGHT != type)
7075     ? pr_oligo_sequence(sa, h)
7076     : pr_oligo_rev_c_sequence(sa, h);
7077 
7078   ret = fprintf(fh,
7079 		"%4d %-30s %5d %2d %2d %5.2f %5.3f %5.2f %5.2f",
7080 		index, p, h->start+sa->incl_s + first_base_index,
7081 		h->length,
7082 		h->num_ns, h->gc_content, h->temp,
7083 		h->self_any,
7084 		h->self_end);
7085   if (ret < 0) return 1;
7086 
7087   if (1==thermodynamical_approach) {
7088     ret = fprintf(fh, " %5.2f", h->hairpin_th);
7089     if (ret < 0) return 1;
7090   }
7091 
7092   if (ret < 0) return 1;
7093   if (print_lib_sim) {
7094     PR_ASSERT(h->repeat_sim.score != NULL);
7095     ret = fprintf(fh, " %5.2f",
7096 		  h->repeat_sim.score[h->repeat_sim.max]);
7097     if (ret < 0) return 1;
7098   }
7099   ret = fprintf(fh, " %6.3f\n", h->quality);
7100   if (ret < 0) return 1;
7101   else return 0;
7102 }
7103 
7104 /* END OF WHAT SHOULD GO TO IO_PRIMER_FILES.C */
7105 
7106 /* ============================================================ */
7107 /* END create primer files functions                            */
7108 /* ============================================================ */
7109 
7110 /* ============================================================
7111   * BEGIN p3_read_line, a utility used
7112   * both for reading boulder input and for reading sequence
7113   * libraries.
7114   * ============================================================ */
7115 
7116 /* Read a line of any length from file.  Return NULL on end of file,
7117  * otherwise return a pointer to static storage containing the line.  Any
7118  * trailing newline is stripped off.  Be careful -- there is only
7119  * one static buffer, so subsequent calls will replace the string
7120  * pointed to by the return value.
7121  * Used in seq_lib functions and also exported
7122  * used in p3_read_line and seq_lib functions
7123  * */
7124 #define INIT_BUF_SIZE 1024
7125 
7126 char*
p3_read_line(FILE * file)7127 p3_read_line(FILE *file)
7128 {
7129   static size_t ssz;
7130   static char *s = NULL;
7131 
7132   size_t remaining_size;
7133   char *p, *n;
7134 
7135   if (NULL == s) {
7136     ssz = INIT_BUF_SIZE;
7137     s = (char *) pr_safe_malloc(ssz);
7138   }
7139   p = s;
7140   remaining_size = ssz;
7141   while (1) {
7142     if (fgets(p, remaining_size, file) == NULL) /* End of file. */
7143       return p == s ? NULL : s;
7144 
7145     if ((n = strchr(p, '\n')) != NULL) {
7146       *n = '\0';
7147       return s;
7148     }
7149 
7150     /* We did not get the whole line. */
7151 
7152     /*
7153      * The following assertion is a bit of hack, a at least for 32-bit
7154      * machines, because we will usually run out of address space first.
7155      * Really we should treat an over-long line as an input error, but
7156      * since an over-long line is unlikely and we do want to provide some
7157      * protection....
7158      */
7159     PR_ASSERT(ssz <= INT_MAX);
7160     if (ssz >= INT_MAX / 2)
7161       ssz = INT_MAX;
7162     else {
7163       ssz *= 2;
7164     }
7165     s = (char *) pr_safe_realloc(s, ssz);
7166     p = strchr(s, '\0');
7167     remaining_size = ssz - (p - s);
7168   }
7169 }
7170 
7171 /* ============================================================ */
7172 /* END p3_read_line                                             */
7173 /* ============================================================ */
7174 
7175 /* ============================================================ */
7176 /* BEGIN 'get' functions for seq_args                           */
7177 /* ============================================================ */
7178 
7179 const interval_array_t2 *
p3_get_sa_tar2(const seq_args * sargs)7180 p3_get_sa_tar2(const seq_args *sargs) {
7181   return &sargs->tar2 ;
7182 }
7183 
7184 const interval_array_t2 *
p3_get_sa_excl2(const seq_args * sargs)7185 p3_get_sa_excl2(const seq_args *sargs) {
7186   return &sargs->excl2 ;
7187 }
7188 
7189 const interval_array_t2 *
p3_get_sa_excl_internal2(const seq_args * sargs)7190 p3_get_sa_excl_internal2(const seq_args *sargs) {
7191   return &sargs->excl_internal2 ;
7192 }
7193 
7194 const interval_array_t4 *
p3_get_sa_ok_regions(const seq_args * sargs)7195 p3_get_sa_ok_regions(const seq_args *sargs)
7196 {
7197   return &sargs->ok_regions;
7198 }
7199 
7200 const int*
p3_get_sa_overlap_junctions(const seq_args * sargs)7201 p3_get_sa_overlap_junctions(const seq_args *sargs)
7202 {
7203   return sargs->primer_overlap_junctions;
7204 }
7205 
7206 /* ============================================================ */
7207 /* END 'get' functions for seq_args                             */
7208 /* ============================================================ */
7209 
7210 int
p3_get_sa_n_quality(seq_args * sargs)7211 p3_get_sa_n_quality(seq_args *sargs) {
7212   return sargs->n_quality ;
7213 }
7214 
7215 /* ============================================================ */
7216 /* BEGIN 'set' functions for seq_args                           */
7217 /* ============================================================ */
7218 
7219 int
p3_set_sa_sequence(seq_args * sargs,const char * sequence)7220 p3_set_sa_sequence(seq_args *sargs, const char *sequence) {
7221   return _set_string(&sargs->sequence, sequence) ;
7222 }
7223 
7224 void
p3_set_sa_primer_sequence_quality(seq_args * sargs,int quality)7225 p3_set_sa_primer_sequence_quality(seq_args *sargs, int quality) {
7226   sargs->quality[sargs->n_quality++] = quality ;
7227 }
7228 
7229 int
p3_set_sa_sequence_name(seq_args * sargs,const char * sequence_name)7230 p3_set_sa_sequence_name(seq_args *sargs, const char* sequence_name) {
7231  return _set_string(&sargs->sequence_name, sequence_name);
7232 }
7233 
7234 int
p3_set_sa_left_input(seq_args * sargs,const char * s)7235 p3_set_sa_left_input(seq_args *sargs, const char *s) {
7236  return _set_string(&sargs->left_input, s);
7237 }
7238 
7239 int
p3_set_sa_right_input(seq_args * sargs,const char * s)7240 p3_set_sa_right_input(seq_args *sargs, const char *s) {
7241  return _set_string(&sargs->right_input, s);
7242 }
7243 
7244 int
p3_set_sa_internal_input(seq_args * sargs,const char * s)7245 p3_set_sa_internal_input(seq_args *sargs, const char *s) {
7246  return _set_string(&sargs->internal_input, s);
7247 }
7248 
7249 void
p3_set_sa_incl_s(seq_args * sargs,int incl_s)7250 p3_set_sa_incl_s(seq_args *sargs, int incl_s) {
7251   sargs->incl_s = incl_s;
7252 }
7253 
7254 void
p3_set_sa_incl_l(seq_args * sargs,int incl_l)7255 p3_set_sa_incl_l(seq_args *sargs, int incl_l) {
7256   sargs->incl_l = incl_l;
7257 }
7258 
7259 void
p3_set_sa_empty_quality(seq_args * sargs)7260 p3_set_sa_empty_quality(seq_args *sargs) {
7261   sargs->n_quality = 0;
7262 }
7263 
7264 void
p3_sa_add_to_quality_array(seq_args * sargs,int quality)7265 p3_sa_add_to_quality_array(seq_args *sargs, int quality) {
7266   int n = sargs->n_quality;
7267   if (sargs->quality_storage_size == 0) {
7268     sargs->quality_storage_size = 3000;
7269     sargs->quality
7270       = (int *)
7271       pr_safe_malloc(sizeof(*sargs->quality)
7272                      * sargs->quality_storage_size);
7273   }
7274   if (n > sargs->quality_storage_size) {
7275     sargs->quality_storage_size *= 2;
7276     sargs->quality
7277       = (int *)
7278       pr_safe_realloc(sargs->quality,
7279                       sizeof(*sargs->quality)
7280                       * sargs->quality_storage_size);
7281   }
7282   sargs->quality[n] = quality;
7283   sargs->n_quality++;
7284 }
7285 
7286 int
p3_sa_add_to_overlap_junctions_array(seq_args * sargs,int overlap)7287 p3_sa_add_to_overlap_junctions_array(seq_args *sargs, int overlap)
7288 {
7289   int c = sargs->primer_overlap_junctions_count;
7290   if (c >= PR_MAX_INTERVAL_ARRAY) return 1;
7291   sargs->primer_overlap_junctions[sargs->primer_overlap_junctions_count++] = overlap;
7292   return 0;
7293 }
7294 
7295 void
p3_set_sa_start_codon_pos(seq_args * sargs,int start_codon_pos)7296 p3_set_sa_start_codon_pos(seq_args *sargs, int start_codon_pos) {
7297   sargs->start_codon_pos = start_codon_pos;
7298 }
7299 
7300 int
p3_add_to_sa_tar2(seq_args * sargs,int n1,int n2)7301 p3_add_to_sa_tar2(seq_args *sargs, int n1, int n2) {
7302   return p3_add_to_interval_array(&sargs->tar2, n1, n2);
7303 }
7304 
7305 int
p3_add_to_sa_excl2(seq_args * sargs,int n1,int n2)7306 p3_add_to_sa_excl2(seq_args *sargs, int n1, int n2) {
7307   return p3_add_to_interval_array(&sargs->excl2, n1, n2);
7308 }
7309 
7310 int
p3_add_to_sa_excl_internal2(seq_args * sargs,int n1,int n2)7311 p3_add_to_sa_excl_internal2(seq_args *sargs, int n1, int n2) {
7312   return p3_add_to_interval_array(&sargs->excl_internal2, n1, n2);
7313 }
7314 
7315 int
p3_add_to_sa_ok_regions(seq_args * sargs,int l1,int l2,int r1,int r2)7316 p3_add_to_sa_ok_regions(seq_args *sargs, int l1, int l2, int r1, int r2)
7317 {
7318   return p3_add_to_2_interval_array(&sargs->ok_regions, l1, l2, r1, r2);
7319 }
7320 
7321 /* ============================================================ */
7322 /* END 'set' functions for seq_args                             */
7323 /* ============================================================ */
7324 
7325 /* ============================================================ */
7326 /* BEGIN 'get' functions for p3_global_settings                 */
7327 /* ============================================================ */
7328 
7329 args_for_one_oligo_or_primer *
p3_get_gs_p_args(p3_global_settings * p)7330 p3_get_gs_p_args(p3_global_settings * p) {
7331   return &p->p_args;
7332 }
7333 
7334 args_for_one_oligo_or_primer *
p3_get_gs_o_args(p3_global_settings * p)7335 p3_get_gs_o_args(p3_global_settings * p) {
7336   return &p->o_args;
7337 }
7338 
7339 /* ============================================================ */
7340 /* END 'get' functions for p3_global_settings                   */
7341 /* ============================================================ */
7342 
7343 
7344 /* ============================================================ */
7345 /* BEGIN 'set' functions for p3_global_settings                 */
7346 /* ============================================================ */
7347 
7348 void
p3_set_gs_prmin(p3_global_settings * p,int val,int i)7349 p3_set_gs_prmin (p3_global_settings * p , int val, int i) {
7350   p->pr_min[i] = val ;
7351 }
7352 
7353 void
p3_set_gs_prmax(p3_global_settings * p,int val,int i)7354 p3_set_gs_prmax (p3_global_settings * p , int val, int i) {
7355   p->pr_max[i] = val ;
7356 }
7357 
7358 void
p3_set_gs_primer_opt_size(p3_global_settings * p,int val)7359 p3_set_gs_primer_opt_size(p3_global_settings * p , int val) {
7360   p->p_args.opt_size = val ;
7361 }
7362 
7363 void
p3_set_gs_primer_min_size(p3_global_settings * p,int val)7364 p3_set_gs_primer_min_size(p3_global_settings * p , int val) {
7365   p->p_args.min_size = val ;
7366 }
7367 
7368 void
p3_set_gs_primer_max_size(p3_global_settings * p,int val)7369 p3_set_gs_primer_max_size(p3_global_settings * p , int val) {
7370   p->p_args.max_size = val ;
7371 }
7372 
7373 void
p3_set_gs_primer_max_poly_x(p3_global_settings * p,int val)7374 p3_set_gs_primer_max_poly_x(p3_global_settings * p , int val) {
7375   p->p_args.max_poly_x = val;
7376 
7377 }
7378 
7379 void
p3_set_gs_primer_opt_tm(p3_global_settings * p,double d)7380 p3_set_gs_primer_opt_tm(p3_global_settings * p , double d) {
7381   p->p_args.opt_tm = d ;
7382 }
7383 
7384 void
p3_set_gs_primer_opt_gc_percent(p3_global_settings * p,double d)7385 p3_set_gs_primer_opt_gc_percent(p3_global_settings * p , double d) {
7386   p->p_args.opt_gc_content = d ;
7387 }
7388 
7389 void
p3_set_gs_primer_min_tm(p3_global_settings * p,double d)7390 p3_set_gs_primer_min_tm(p3_global_settings * p , double d) {
7391   p->p_args.min_tm = d ;
7392 }
7393 void
p3_set_gs_primer_max_tm(p3_global_settings * p,double d)7394 p3_set_gs_primer_max_tm(p3_global_settings * p , double d) {
7395   p->p_args.max_tm = d;
7396 }
7397 
7398 void
p3_set_gs_primer_max_diff_tm(p3_global_settings * p,double val)7399 p3_set_gs_primer_max_diff_tm(p3_global_settings * p , double val) {
7400   p->max_diff_tm = val;
7401 }
7402 
7403 void
p3_set_gs_primer_tm_santalucia(p3_global_settings * p,tm_method_type val)7404 p3_set_gs_primer_tm_santalucia(p3_global_settings * p,
7405                                tm_method_type val) {
7406   p->tm_santalucia = val ;
7407 }
7408 
7409 void
p3_set_gs_primer_salt_corrections(p3_global_settings * p,salt_correction_type val)7410 p3_set_gs_primer_salt_corrections(p3_global_settings * p,
7411                                   salt_correction_type val) {
7412   p->salt_corrections = val;
7413 }
7414 
7415 void
p3_set_gs_primer_min_gc(p3_global_settings * p,double val)7416 p3_set_gs_primer_min_gc(p3_global_settings * p , double val) {
7417   p->p_args.min_gc = val ;
7418 }
7419 
7420 void
p3_set_gs_primer_max_gc(p3_global_settings * p,double val)7421 p3_set_gs_primer_max_gc(p3_global_settings * p , double val) {
7422    p->p_args.max_gc = val ;
7423 }
7424 
7425 void
p3_set_gs_primer_salt_conc(p3_global_settings * p,double val)7426 p3_set_gs_primer_salt_conc(p3_global_settings * p , double val) {
7427   p->p_args.salt_conc = val ;
7428 }
7429 
7430 void
p3_set_gs_primer_divalent_conc(p3_global_settings * p,double val)7431 p3_set_gs_primer_divalent_conc(p3_global_settings * p , double val)
7432 {
7433  p->p_args.divalent_conc = val;
7434 }
7435 
7436 void
p3_set_gs_primer_dntp_conc(p3_global_settings * p,double val)7437 p3_set_gs_primer_dntp_conc(p3_global_settings * p , double val)
7438 {
7439   p->p_args.dntp_conc = val ;
7440 }
7441 
7442 void
p3_set_gs_primer_dna_conc(p3_global_settings * p,double val)7443 p3_set_gs_primer_dna_conc(p3_global_settings * p , double val)
7444 {
7445   p->p_args.dna_conc = val ;
7446 }
7447 
7448 void
p3_set_gs_primer_num_ns_accepted(p3_global_settings * p,int val)7449 p3_set_gs_primer_num_ns_accepted(p3_global_settings * p , int val)
7450 {
7451   p->p_args.num_ns_accepted = val ;
7452 }
7453 
7454 void
p3_set_gs_primer_product_opt_size(p3_global_settings * p,int val)7455 p3_set_gs_primer_product_opt_size(p3_global_settings * p , int val)
7456 {
7457   p->product_opt_size = val ;
7458 }
7459 
7460 void
p3_set_gs_primer_self_any(p3_global_settings * p,double val)7461 p3_set_gs_primer_self_any(p3_global_settings * p , double val)
7462 {
7463   p->p_args.max_self_any = val;
7464 }
7465 
7466 void
p3_set_gs_primer_self_any_th(p3_global_settings * p,double val)7467 p3_set_gs_primer_self_any_th(p3_global_settings * p , double val)
7468 {
7469   p->p_args.max_self_any_th = val;
7470 }
7471 
7472 void
p3_set_gs_primer_self_end(p3_global_settings * p,double val)7473 p3_set_gs_primer_self_end(p3_global_settings * p , double val)
7474 {
7475   p->p_args.max_self_end = val; /* (short) (val * 100); */
7476 }
7477 
7478 void
p3_set_gs_primer_self_end_th(p3_global_settings * p,double val)7479 p3_set_gs_primer_self_end_th(p3_global_settings * p , double val)
7480 {
7481    p->p_args.max_self_end_th = val;
7482 }
7483 
7484 void
p3_set_gs_primer_hairpin_th(p3_global_settings * p,double val)7485 p3_set_gs_primer_hairpin_th(p3_global_settings * p , double val) {
7486    p->p_args.max_hairpin_th = val;
7487 }
7488 
7489 void   /* Called in primer3_boulder_main.c. */
p3_set_gs_primer_file_flag(p3_global_settings * p,int file_flag)7490 p3_set_gs_primer_file_flag(p3_global_settings * p , int file_flag)
7491 {
7492   p->file_flag = file_flag;
7493 }
7494 
7495 void
p3_set_gs_pick_anyway(p3_global_settings * p,int pick_anyway)7496 p3_set_gs_pick_anyway(p3_global_settings * p , int pick_anyway)
7497 {
7498   p->pick_anyway = pick_anyway ;
7499 }
7500 
7501 void
p3_set_gs_gc_clamp(p3_global_settings * p,int gc_clamp)7502 p3_set_gs_gc_clamp(p3_global_settings * p , int gc_clamp)
7503 {
7504   p->gc_clamp = gc_clamp;
7505 }
7506 
7507 void
p3_set_gs_primer_liberal_base(p3_global_settings * p,int val)7508 p3_set_gs_primer_liberal_base(p3_global_settings * p , int val) {
7509   p->liberal_base = val;
7510 }
7511 
7512 void
p3_set_gs_primer_first_base_index(p3_global_settings * p,int first_base_index)7513 p3_set_gs_primer_first_base_index(p3_global_settings * p , int first_base_index){
7514   p->first_base_index = first_base_index;
7515 }
7516 
7517 void
p3_set_gs_primer_num_return(p3_global_settings * p,int val)7518 p3_set_gs_primer_num_return(p3_global_settings * p , int val) {
7519   p->num_return = val ;
7520 }
7521 
7522 void
p3_set_gs_primer_min_quality(p3_global_settings * p,int val)7523 p3_set_gs_primer_min_quality(p3_global_settings * p , int val) {
7524   p->p_args.min_quality = val ;
7525 }
7526 
7527 void
p3_set_gs_primer_min_end_quality(p3_global_settings * p,int val)7528 p3_set_gs_primer_min_end_quality(p3_global_settings * p , int val) {
7529   p->p_args.min_end_quality = val ;
7530 }
7531 
7532 void
p3_set_gs_primer_quality_range_min(p3_global_settings * p,int val)7533 p3_set_gs_primer_quality_range_min(p3_global_settings * p , int val) {
7534   p->quality_range_min = val ;
7535 }
7536 
7537 void
p3_set_gs_primer_quality_range_max(p3_global_settings * p,int val)7538 p3_set_gs_primer_quality_range_max(p3_global_settings * p , int val) {
7539   p->quality_range_max = val ;
7540 }
7541 
7542 void
p3_set_gs_primer_product_max_tm(p3_global_settings * p,double val)7543 p3_set_gs_primer_product_max_tm(p3_global_settings * p , double val) {
7544   p->product_max_tm = val ;
7545 }
7546 
7547 void
p3_set_gs_primer_product_min_tm(p3_global_settings * p,double val)7548 p3_set_gs_primer_product_min_tm(p3_global_settings * p , double val) {
7549   p->product_min_tm = val ;
7550 }
7551 
7552 void
p3_set_gs_primer_product_opt_tm(p3_global_settings * p,double val)7553 p3_set_gs_primer_product_opt_tm(p3_global_settings * p , double val) {
7554   p->product_opt_tm = val ;
7555 }
7556 
7557 void
p3_set_gs_primer_task(p3_global_settings * pa,char * task_tmp)7558 p3_set_gs_primer_task(p3_global_settings * pa , char * task_tmp)
7559 {
7560   if (!strcmp_nocase(task_tmp, "pick_pcr_primers")) {
7561     pa->primer_task = generic;
7562     pa->pick_left_primer = 1;
7563     pa->pick_right_primer = 1;
7564     pa->pick_internal_oligo = 0;
7565   } else if (!strcmp_nocase(task_tmp, "pick_pcr_primers_and_hyb_probe")) {
7566     pa->primer_task = generic;
7567     pa->pick_left_primer = 1;
7568     pa->pick_right_primer = 1;
7569     pa->pick_internal_oligo = 1;
7570   } else if (!strcmp_nocase(task_tmp, "pick_left_only")) {
7571     pa->primer_task = generic;
7572     pa->pick_left_primer = 1;
7573     pa->pick_right_primer = 0;
7574     pa->pick_internal_oligo = 0;
7575   } else if (!strcmp_nocase(task_tmp, "pick_right_only")) {
7576     pa->primer_task = generic;
7577     pa->pick_left_primer = 0;
7578     pa->pick_right_primer = 1;
7579     pa->pick_internal_oligo = 0;
7580   } else if (!strcmp_nocase(task_tmp, "pick_hyb_probe_only")) {
7581     pa->primer_task = generic;
7582     pa->pick_left_primer = 0;
7583     pa->pick_right_primer = 0;
7584     pa->pick_internal_oligo = 1;
7585   } else if (!strcmp_nocase(task_tmp, "generic")) {
7586     pa->primer_task = generic;
7587   } else if (!strcmp_nocase(task_tmp, "pick_detection_primers")) {
7588     pa->primer_task = generic; /* Deliberate duplication for
7589 				    backward compatibility. */
7590   } else if (!strcmp_nocase(task_tmp, "pick_cloning_primers")) {
7591     pa->primer_task = pick_cloning_primers;
7592   } else if (!strcmp_nocase(task_tmp, "pick_discriminative_primers")) {
7593     pa->primer_task = pick_discriminative_primers;
7594   } else if (!strcmp_nocase(task_tmp, "pick_sequencing_primers")) {
7595     pa->primer_task = pick_sequencing_primers;
7596   } else if (!strcmp_nocase(task_tmp, "pick_primer_list")) {
7597     pa->primer_task = pick_primer_list;
7598   } else if (!strcmp_nocase(task_tmp, "check_primers")) {
7599     pa->primer_task = check_primers;
7600   }
7601 }
7602 
7603 void
p3_set_gs_primer_pick_right_primer(p3_global_settings * p,int pick_right_primer)7604 p3_set_gs_primer_pick_right_primer(p3_global_settings * p , int pick_right_primer)
7605 {
7606   p->pick_right_primer = pick_right_primer;
7607 }
7608 
7609 void
p3_set_gs_primer_pick_internal_oligo(p3_global_settings * p,int pick_internal_oligo)7610 p3_set_gs_primer_pick_internal_oligo(p3_global_settings * p , int pick_internal_oligo)
7611 {
7612   p->pick_internal_oligo = pick_internal_oligo;
7613 }
7614 
7615 void
p3_set_gs_primer_pick_left_primer(p3_global_settings * p,int pick_left_primer)7616 p3_set_gs_primer_pick_left_primer(p3_global_settings * p , int pick_left_primer) {
7617   p->pick_left_primer = pick_left_primer;
7618 }
7619 
7620 void
p3_set_gs_primer_internal_oligo_opt_size(p3_global_settings * p,int val)7621 p3_set_gs_primer_internal_oligo_opt_size(p3_global_settings * p , int val) {
7622   p->o_args.opt_size = val ;
7623 }
7624 
7625 void
p3_set_gs_primer_internal_oligo_max_size(p3_global_settings * p,int val)7626 p3_set_gs_primer_internal_oligo_max_size(p3_global_settings * p , int val) {
7627   p->o_args.max_size = val ;
7628 }
7629 
7630 void
p3_set_gs_primer_internal_oligo_min_size(p3_global_settings * p,int val)7631 p3_set_gs_primer_internal_oligo_min_size(p3_global_settings * p , int val) {
7632   p->o_args.min_size = val ;
7633 }
7634 
7635 void
p3_set_gs_primer_internal_oligo_max_poly_x(p3_global_settings * p,int val)7636 p3_set_gs_primer_internal_oligo_max_poly_x(p3_global_settings * p , int val) {
7637   p->o_args.max_poly_x = val ;
7638 }
7639 
7640 void
p3_set_gs_primer_internal_oligo_opt_tm(p3_global_settings * p,double val)7641 p3_set_gs_primer_internal_oligo_opt_tm(p3_global_settings * p , double val) {
7642   p->o_args.opt_tm = val ;
7643 }
7644 
7645 void
p3_set_gs_primer_internal_oligo_opt_gc_percent(p3_global_settings * p,double val)7646 p3_set_gs_primer_internal_oligo_opt_gc_percent(p3_global_settings * p , double val) {
7647   p->o_args.opt_gc_content = val ;
7648 }
7649 
7650 void
p3_set_gs_primer_internal_oligo_max_tm(p3_global_settings * p,double val)7651 p3_set_gs_primer_internal_oligo_max_tm(p3_global_settings * p , double val) {
7652   p->o_args.max_tm = val ;
7653 }
7654 
7655 void
p3_set_gs_primer_internal_oligo_min_tm(p3_global_settings * p,double val)7656 p3_set_gs_primer_internal_oligo_min_tm(p3_global_settings * p , double val) {
7657   p->o_args.min_tm = val ;
7658 }
7659 
7660 void
p3_set_gs_primer_internal_oligo_min_gc(p3_global_settings * p,double val)7661 p3_set_gs_primer_internal_oligo_min_gc(p3_global_settings * p , double val) {
7662   p->o_args.min_gc = val ;
7663 }
7664 
7665 void
p3_set_gs_primer_internal_oligo_max_gc(p3_global_settings * p,double val)7666 p3_set_gs_primer_internal_oligo_max_gc(p3_global_settings * p , double val) {
7667   p->o_args.max_gc = val ;
7668 }
7669 
7670 void
p3_set_gs_primer_internal_oligo_salt_conc(p3_global_settings * p,double val)7671 p3_set_gs_primer_internal_oligo_salt_conc(p3_global_settings * p , double val) {
7672   p->o_args.salt_conc = val ;
7673 }
7674 
7675 void
p3_set_gs_primer_internal_oligo_divalent_conc(p3_global_settings * p,double val)7676 p3_set_gs_primer_internal_oligo_divalent_conc(p3_global_settings * p , double val) {
7677   p->o_args.divalent_conc = val ;
7678 }
7679 
7680 void
p3_set_gs_primer_internal_oligo_dntp_conc(p3_global_settings * p,double val)7681 p3_set_gs_primer_internal_oligo_dntp_conc(p3_global_settings * p , double val) {
7682   p->o_args.dntp_conc = val ;
7683 }
7684 
7685 void
p3_set_gs_primer_internal_oligo_dna_conc(p3_global_settings * p,double val)7686 p3_set_gs_primer_internal_oligo_dna_conc(p3_global_settings * p , double val) {
7687   p->o_args.dna_conc = val ;
7688 }
7689 
7690 void
p3_set_gs_primer_internal_oligo_num_ns(p3_global_settings * p,int val)7691 p3_set_gs_primer_internal_oligo_num_ns(p3_global_settings * p , int val) {
7692   p->o_args.num_ns_accepted = val ;
7693 }
7694 
7695 void
p3_set_gs_primer_internal_oligo_min_quality(p3_global_settings * p,int val)7696 p3_set_gs_primer_internal_oligo_min_quality(p3_global_settings * p , int val) {
7697   p->o_args.min_quality = val ;
7698 }
7699 
7700 void
p3_set_gs_primer_internal_oligo_self_any(p3_global_settings * p,double val)7701 p3_set_gs_primer_internal_oligo_self_any(p3_global_settings * p , double val) {
7702   p->o_args.max_self_any = val;
7703 }
7704 
7705 void
p3_set_gs_primer_internal_oligo_self_any_th(p3_global_settings * p,double val)7706 p3_set_gs_primer_internal_oligo_self_any_th(p3_global_settings * p , double val) {
7707   p->o_args.max_self_any_th = val;
7708 }
7709 
7710 void
p3_set_gs_primer_internal_oligo_self_end(p3_global_settings * p,double val)7711 p3_set_gs_primer_internal_oligo_self_end(p3_global_settings * p , double val) {
7712   p->o_args.max_self_end = val; /* (short) (val * 100); */
7713 }
7714 
7715 void
p3_set_gs_primer_internal_oligo_self_end_th(p3_global_settings * p,double val)7716 p3_set_gs_primer_internal_oligo_self_end_th(p3_global_settings * p , double val) {
7717    p->o_args.max_self_end_th = val;
7718 }
7719 
7720 void
p3_set_gs_primer_internal_oligo_hairpin_th(p3_global_settings * p,double val)7721 p3_set_gs_primer_internal_oligo_hairpin_th(p3_global_settings * p , double val) {
7722       p->o_args.max_hairpin_th = val;
7723 }
7724 
7725 
7726 void
p3_set_gs_primer_max_mispriming(p3_global_settings * p,double val)7727 p3_set_gs_primer_max_mispriming(p3_global_settings * p , double val) {
7728   p->p_args.max_repeat_compl = val;
7729 }
7730 
7731 void
p3_set_gs_primer_internal_oligo_max_mishyb(p3_global_settings * p,double val)7732 p3_set_gs_primer_internal_oligo_max_mishyb(p3_global_settings * p , double val) {
7733   p->o_args.max_repeat_compl = val;
7734 }
7735 
7736 void
p3_set_gs_primer_pair_max_mispriming(p3_global_settings * p,double val)7737 p3_set_gs_primer_pair_max_mispriming(p3_global_settings * p , double val) {
7738   p->pair_repeat_compl = val;
7739 }
7740 
7741 void
p3_set_gs_primer_max_template_mispriming(p3_global_settings * p,double val)7742 p3_set_gs_primer_max_template_mispriming(p3_global_settings * p , double val) {
7743   p->p_args.max_template_mispriming = val;
7744 }
7745 
7746 void
p3_set_gs_primer_max_template_mispriming_th(p3_global_settings * p,double val)7747 p3_set_gs_primer_max_template_mispriming_th(p3_global_settings * p , double val) {
7748   p->p_args.max_template_mispriming_th = val;
7749 }
7750 
7751 void
p3_set_gs_primer_lib_ambiguity_codes_consensus(p3_global_settings * p,int val)7752 p3_set_gs_primer_lib_ambiguity_codes_consensus(p3_global_settings * p , int val) {
7753   p->lib_ambiguity_codes_consensus = val ;
7754 }
7755 
7756 void
p3_set_gs_primer_inside_penalty(p3_global_settings * p,double val)7757 p3_set_gs_primer_inside_penalty(p3_global_settings * p , double val) {
7758   p->inside_penalty = val ;
7759 }
7760 
7761 void
p3_set_gs_primer_outside_penalty(p3_global_settings * p,double val)7762 p3_set_gs_primer_outside_penalty(p3_global_settings * p , double val) {
7763   p->outside_penalty = val ;
7764 }
7765 
7766 void
p3_set_gs_primer_mispriming_library(p3_global_settings * p,char * path)7767 p3_set_gs_primer_mispriming_library(p3_global_settings * p , char * path) {
7768   /* TO DO: Re-factor this? TO DO: Check for errors */
7769   p->p_args.repeat_lib = read_and_create_seq_lib(path, "mispriming library") ;
7770 }
7771 
7772 void
p3_set_gs_primer_internal_oligo_mishyb_library(p3_global_settings * p,char * path)7773 p3_set_gs_primer_internal_oligo_mishyb_library(p3_global_settings * p , char * path) {
7774   /* TO DO: Re-factor this? TO DO: Check for errors */
7775   p->o_args.repeat_lib = read_and_create_seq_lib(path, "internal oligio mishyb library") ;
7776 }
7777 
7778 void
p3_set_gs_primer_max_end_stability(p3_global_settings * p,double val)7779 p3_set_gs_primer_max_end_stability(p3_global_settings * p , double val) {
7780   p->max_end_stability = val ;
7781 }
7782 
7783 void
p3_set_gs_primer_lowercase_masking(p3_global_settings * p,int val)7784 p3_set_gs_primer_lowercase_masking(p3_global_settings * p , int val) {
7785   p->lowercase_masking = val ;
7786 }
7787 
7788 void
p3_set_gs_primer_thermodynamic_oligo_alignment(p3_global_settings * p,int val)7789 p3_set_gs_primer_thermodynamic_oligo_alignment(p3_global_settings * p , int val) {
7790    p->thermodynamic_oligo_alignment = val ;
7791 }
7792 
7793 void
p3_set_gs_primer_thermodynamic_template_alignment(p3_global_settings * p,int val)7794 p3_set_gs_primer_thermodynamic_template_alignment(p3_global_settings * p , int val) {
7795    p->thermodynamic_template_alignment = val ;
7796 }
7797 
7798 void
p3_set_gs_primer_wt_tm_gt(p3_global_settings * p,double val)7799 p3_set_gs_primer_wt_tm_gt(p3_global_settings * p , double val) {
7800   p->p_args.weights.temp_gt = val ;
7801 }
7802 
7803 void
p3_set_gs_primer_wt_tm_lt(p3_global_settings * p,double val)7804 p3_set_gs_primer_wt_tm_lt(p3_global_settings * p , double val) {
7805   p->p_args.weights.temp_lt = val ;
7806 }
7807 
7808 void
p3_set_gs_primer_wt_gc_percent_gt(p3_global_settings * p,double val)7809 p3_set_gs_primer_wt_gc_percent_gt(p3_global_settings * p , double val) {
7810   p->p_args.weights.gc_content_gt = val ;
7811 }
7812 
7813 void
p3_set_gs_primer_wt_gc_percent_lt(p3_global_settings * p,double val)7814 p3_set_gs_primer_wt_gc_percent_lt(p3_global_settings * p , double val) {
7815   p->p_args.weights.gc_content_lt = val ;
7816 }
7817 
7818 void
p3_set_gs_primer_wt_size_lt(p3_global_settings * p,double val)7819 p3_set_gs_primer_wt_size_lt(p3_global_settings * p , double val) {
7820   p->p_args.weights.length_lt = val ;
7821 }
7822 
7823 void
p3_set_gs_primer_wt_size_gt(p3_global_settings * p,double val)7824 p3_set_gs_primer_wt_size_gt(p3_global_settings * p , double val) {
7825   p->p_args.weights.length_gt = val ;
7826 }
7827 
7828 void
p3_set_gs_primer_wt_compl_any(p3_global_settings * p,double val)7829 p3_set_gs_primer_wt_compl_any(p3_global_settings * p , double val) {
7830   p->p_args.weights.compl_any = val ;
7831 }
7832 
7833 void
p3_set_gs_primer_wt_compl_any_th(p3_global_settings * p,double val)7834 p3_set_gs_primer_wt_compl_any_th(p3_global_settings * p , double val) {
7835    p->p_args.weights.compl_any_th = val ;
7836 }
7837 
7838 void
p3_set_gs_primer_wt_compl_end(p3_global_settings * p,double val)7839 p3_set_gs_primer_wt_compl_end(p3_global_settings * p , double val) {
7840   p->p_args.weights.compl_end = val ;
7841 }
7842 
7843 void
p3_set_gs_primer_wt_compl_end_th(p3_global_settings * p,double val)7844 p3_set_gs_primer_wt_compl_end_th(p3_global_settings * p , double val) {
7845      p->p_args.weights.compl_end_th = val ;
7846 }
7847 
7848 void
p3_set_gs_primer_wt_hairpin_th(p3_global_settings * p,double val)7849 p3_set_gs_primer_wt_hairpin_th(p3_global_settings * p , double val) {
7850    p->p_args.weights.hairpin_th = val ;
7851 }
7852 
7853 void
p3_set_gs_primer_wt_num_ns(p3_global_settings * p,double val)7854 p3_set_gs_primer_wt_num_ns(p3_global_settings * p , double val) {
7855   p->p_args.weights.num_ns = val ;
7856 }
7857 
7858 void
p3_set_gs_primer_wt_rep_sim(p3_global_settings * p,double val)7859 p3_set_gs_primer_wt_rep_sim(p3_global_settings * p , double val) {
7860   p->p_args.weights.repeat_sim = val ;
7861 }
7862 
7863 void
p3_set_gs_primer_wt_seq_qual(p3_global_settings * p,double val)7864 p3_set_gs_primer_wt_seq_qual(p3_global_settings * p , double val) {
7865   p->p_args.weights.seq_quality = val ;
7866 }
7867 
7868 void
p3_set_gs_primer_wt_end_qual(p3_global_settings * p,double val)7869 p3_set_gs_primer_wt_end_qual(p3_global_settings * p , double val) {
7870   p->p_args.weights.end_quality = val ;
7871 }
7872 
7873 void
p3_set_gs_primer_wt_pos_penalty(p3_global_settings * p,double val)7874 p3_set_gs_primer_wt_pos_penalty(p3_global_settings * p , double val){
7875   p->p_args.weights.pos_penalty = val ;
7876 }
7877 
7878 void
p3_set_gs_primer_wt_end_stability(p3_global_settings * p,double val)7879 p3_set_gs_primer_wt_end_stability(p3_global_settings * p , double val) {
7880   p->p_args.weights.end_stability = val ;
7881 }
7882 
7883 void
p3_set_gs_primer_wt_template_mispriming(p3_global_settings * p,double val)7884 p3_set_gs_primer_wt_template_mispriming(p3_global_settings * p , double val) {
7885   p->p_args.weights.template_mispriming = val ;
7886 }
7887 
7888 void
p3_set_gs_primer_wt_template_mispriming_th(p3_global_settings * p,double val)7889 p3_set_gs_primer_wt_template_mispriming_th(p3_global_settings * p , double val) {
7890      p->p_args.weights.template_mispriming_th = val ;
7891 }
7892 
7893 void
p3_set_gs_primer_io_wt_tm_gt(p3_global_settings * p,double val)7894 p3_set_gs_primer_io_wt_tm_gt(p3_global_settings * p , double val) {
7895   p->o_args.weights.temp_gt = val ;
7896 }
7897 
7898 void
p3_set_gs_primer_io_wt_tm_lt(p3_global_settings * p,double val)7899 p3_set_gs_primer_io_wt_tm_lt(p3_global_settings * p , double val){
7900   p->o_args.weights.temp_lt = val ;
7901 }
7902 
7903 void
p3_set_gs_primer_io_wt_gc_percent_gt(p3_global_settings * p,double val)7904 p3_set_gs_primer_io_wt_gc_percent_gt(p3_global_settings * p , double val) {
7905   p->o_args.weights.gc_content_gt = val ;
7906 }
7907 
7908 void
p3_set_gs_primer_io_wt_gc_percent_lt(p3_global_settings * p,double val)7909 p3_set_gs_primer_io_wt_gc_percent_lt(p3_global_settings * p , double val) {
7910   p->o_args.weights.gc_content_lt = val ;
7911 
7912 }
7913 
7914 void
p3_set_gs_primer_io_wt_size_lt(p3_global_settings * p,double val)7915 p3_set_gs_primer_io_wt_size_lt(p3_global_settings * p , double val) {
7916   p->o_args.weights.length_lt = val ;
7917 }
7918 
7919 void
p3_set_gs_primer_io_wt_size_gt(p3_global_settings * p,double val)7920 p3_set_gs_primer_io_wt_size_gt(p3_global_settings * p , double val) {
7921   p->o_args.weights.length_gt = val ;
7922 }
7923 
7924 void
p3_set_gs_primer_io_wt_wt_compl_any(p3_global_settings * p,double val)7925 p3_set_gs_primer_io_wt_wt_compl_any(p3_global_settings * p , double val) {
7926   p->o_args.weights.compl_any = val ;
7927 }
7928 
7929 void
p3_set_gs_primer_io_wt_wt_compl_any_th(p3_global_settings * p,double val)7930 p3_set_gs_primer_io_wt_wt_compl_any_th(p3_global_settings * p , double val) {
7931      p->o_args.weights.compl_any_th = val ;
7932 }
7933 
7934 void
p3_set_gs_primer_io_wt_compl_end(p3_global_settings * p,double val)7935 p3_set_gs_primer_io_wt_compl_end(p3_global_settings * p , double val) {
7936   p->o_args.weights.compl_end = val ;
7937 }
7938 
7939 void
p3_set_gs_primer_io_wt_compl_end_th(p3_global_settings * p,double val)7940 p3_set_gs_primer_io_wt_compl_end_th(p3_global_settings * p , double val) {
7941      p->o_args.weights.compl_end_th = val ;
7942 }
7943 
7944 void
p3_set_gs_primer_io_wt_hairpin_th(p3_global_settings * p,double val)7945 p3_set_gs_primer_io_wt_hairpin_th(p3_global_settings * p , double val) {
7946    p->o_args.weights.hairpin_th = val ;
7947 }
7948 
7949 void
p3_set_gs_primer_io_wt_num_ns(p3_global_settings * p,double val)7950 p3_set_gs_primer_io_wt_num_ns(p3_global_settings * p , double val) {
7951   p->o_args.weights.num_ns = val ;
7952 }
7953 
7954 void
p3_set_gs_primer_io_wt_rep_sim(p3_global_settings * p,double val)7955 p3_set_gs_primer_io_wt_rep_sim(p3_global_settings * p , double val) {
7956   p->o_args.weights.repeat_sim = val ;
7957 }
7958 
7959 void
p3_set_gs_primer_io_wt_seq_qual(p3_global_settings * p,double val)7960 p3_set_gs_primer_io_wt_seq_qual(p3_global_settings * p , double val) {
7961   p->o_args.weights.seq_quality = val ;
7962 }
7963 
7964 void
p3_set_gs_primer_io_wt_end_qual(p3_global_settings * p,double val)7965 p3_set_gs_primer_io_wt_end_qual(p3_global_settings * p , double val) {
7966   p->o_args.weights.end_quality = val ;
7967 }
7968 
7969 void
p3_set_gs_primer_pair_wt_pr_penalty(p3_global_settings * p,double val)7970 p3_set_gs_primer_pair_wt_pr_penalty(p3_global_settings * p , double val) {
7971   p->pr_pair_weights.primer_quality = val ;
7972 }
7973 
7974 void
p3_set_gs_primer_pair_wt_io_penalty(p3_global_settings * p,double val)7975 p3_set_gs_primer_pair_wt_io_penalty(p3_global_settings * p , double val) {
7976   p->pr_pair_weights.io_quality = val ;
7977 }
7978 
7979 void
p3_set_gs_primer_pair_wt_diff_tm(p3_global_settings * p,double val)7980 p3_set_gs_primer_pair_wt_diff_tm(p3_global_settings * p , double val) {
7981   p->pr_pair_weights.diff_tm = val ;
7982 }
7983 
7984 void
p3_set_gs_primer_pair_wt_compl_any(p3_global_settings * p,double val)7985 p3_set_gs_primer_pair_wt_compl_any(p3_global_settings * p , double val) {
7986   p->pr_pair_weights.compl_any = val ;
7987 }
7988 
7989 void
p3_set_gs_primer_pair_wt_compl_any_th(p3_global_settings * p,double val)7990 p3_set_gs_primer_pair_wt_compl_any_th(p3_global_settings * p , double val) {
7991    p->pr_pair_weights.compl_any_th = val ;
7992 }
7993 
7994 void
p3_set_gs_primer_pair_wt_compl_end(p3_global_settings * p,double val)7995 p3_set_gs_primer_pair_wt_compl_end(p3_global_settings * p , double val) {
7996   p->pr_pair_weights.compl_end = val ;
7997 }
7998 
7999 void
p3_set_gs_primer_pair_wt_compl_end_th(p3_global_settings * p,double val)8000 p3_set_gs_primer_pair_wt_compl_end_th(p3_global_settings * p , double val) {
8001    p->pr_pair_weights.compl_end_th = val ;
8002 }
8003 
8004 void
p3_set_gs_primer_pair_wt_product_tm_lt(p3_global_settings * p,double val)8005 p3_set_gs_primer_pair_wt_product_tm_lt(p3_global_settings * p , double val) {
8006   p->pr_pair_weights.product_tm_lt = val ;
8007 }
8008 
8009 void
p3_set_gs_primer_pair_wt_product_tm_gt(p3_global_settings * p,double val)8010 p3_set_gs_primer_pair_wt_product_tm_gt(p3_global_settings * p , double val) {
8011   p->pr_pair_weights.product_tm_gt = val ;
8012 }
8013 
8014 void
p3_set_gs_primer_pair_wt_product_size_gt(p3_global_settings * p,double val)8015 p3_set_gs_primer_pair_wt_product_size_gt(p3_global_settings * p , double val) {
8016   p->pr_pair_weights.product_size_gt = val ;
8017 }
8018 
8019 void
p3_set_gs_primer_pair_wt_product_size_lt(p3_global_settings * p,double val)8020 p3_set_gs_primer_pair_wt_product_size_lt(p3_global_settings * p , double val) {
8021   p->pr_pair_weights.product_size_lt = val ;
8022 }
8023 
8024 void
p3_set_gs_primer_pair_wt_rep_sim(p3_global_settings * p,double val)8025 p3_set_gs_primer_pair_wt_rep_sim(p3_global_settings * p , double val) {
8026   p->pr_pair_weights.repeat_sim = val ;
8027 }
8028 
8029 void
p3_set_gs_primer_pair_wt_template_mispriming(p3_global_settings * p,double val)8030 p3_set_gs_primer_pair_wt_template_mispriming(p3_global_settings * p , double val) {
8031   p->pr_pair_weights.template_mispriming = val ;
8032 }
8033 
8034 void
p3_set_gs_primer_pair_wt_template_mispriming_th(p3_global_settings * p,double val)8035 p3_set_gs_primer_pair_wt_template_mispriming_th(p3_global_settings * p , double val){
8036      p->pr_pair_weights.template_mispriming_th = val ;
8037 }
8038 
8039 void
p3_set_gs_lib_ambiguity_codes_consensus(p3_global_settings * p,int lib_ambiguity_codes_consensus)8040 p3_set_gs_lib_ambiguity_codes_consensus(p3_global_settings * p,
8041                                         int lib_ambiguity_codes_consensus)
8042 {
8043   p->lib_ambiguity_codes_consensus = lib_ambiguity_codes_consensus;
8044 }
8045 
8046 void
p3_set_gs_quality_range_min(p3_global_settings * p,int quality_range_min)8047 p3_set_gs_quality_range_min(p3_global_settings * p , int quality_range_min){
8048   p->quality_range_min = quality_range_min;
8049 }
8050 
8051 void
p3_set_gs_quality_range_max(p3_global_settings * p,int quality_range_max)8052 p3_set_gs_quality_range_max(p3_global_settings * p , int quality_range_max){
8053   p->quality_range_max = quality_range_max ;
8054 }
8055 
8056 void
p3_set_gs_max_end_gc(p3_global_settings * p,int max_end_gc)8057 p3_set_gs_max_end_gc(p3_global_settings *p, int max_end_gc) {
8058   p->max_end_gc = max_end_gc;
8059 }
8060 
8061 void
p3_set_gs_max_end_stability(p3_global_settings * p,int max_end_stability)8062 p3_set_gs_max_end_stability(p3_global_settings * p , int max_end_stability){
8063   p->max_end_stability = max_end_stability;
8064 }
8065 
8066 void
p3_set_gs_lowercase_masking(p3_global_settings * p,int lowercase_masking)8067 p3_set_gs_lowercase_masking(p3_global_settings * p , int lowercase_masking){
8068   p->lowercase_masking = lowercase_masking;
8069 }
8070 
8071 void
p3_set_gs_outside_penalty(p3_global_settings * p,double outside_penalty)8072 p3_set_gs_outside_penalty(p3_global_settings * p , double outside_penalty){
8073   p->outside_penalty = outside_penalty;
8074 }
8075 
8076 void
p3_set_gs_inside_penalty(p3_global_settings * p,double inside_penalty)8077 p3_set_gs_inside_penalty(p3_global_settings * p , double inside_penalty){
8078   p->inside_penalty = inside_penalty;
8079 }
8080 
8081 void
p3_set_gs_pair_max_template_mispriming(p3_global_settings * p,double pair_max_template_mispriming)8082 p3_set_gs_pair_max_template_mispriming(p3_global_settings * p,
8083                                        double  pair_max_template_mispriming)
8084 {
8085   p->pair_max_template_mispriming = pair_max_template_mispriming;
8086 }
8087 
8088 void
p3_set_gs_pair_max_template_mispriming_th(p3_global_settings * p,double pair_max_template_mispriming_th)8089 p3_set_gs_pair_max_template_mispriming_th(p3_global_settings * p,
8090                                           double  pair_max_template_mispriming_th)
8091 {
8092   p->pair_max_template_mispriming_th = pair_max_template_mispriming_th;
8093 }
8094 
8095 
8096 void
p3_set_gs_pair_repeat_compl(p3_global_settings * p,double pair_repeat_compl)8097 p3_set_gs_pair_repeat_compl(p3_global_settings * p, double pair_repeat_compl)
8098 {
8099   p->pair_repeat_compl = pair_repeat_compl;
8100 }
8101 
8102 void
p3_set_gs_pair_compl_any(p3_global_settings * p,double pair_compl_any)8103 p3_set_gs_pair_compl_any(p3_global_settings * p , double pair_compl_any)
8104 {
8105   p->pair_compl_any = pair_compl_any;
8106 }
8107 
8108 void
p3_set_gs_pair_compl_any_th(p3_global_settings * p,double pair_compl_any_th)8109 p3_set_gs_pair_compl_any_th(p3_global_settings * p , double pair_compl_any_th)
8110 {
8111   p->pair_compl_any_th = pair_compl_any_th;
8112 }
8113 
8114 void
p3_set_gs_pair_compl_end(p3_global_settings * p,double pair_compl_end)8115 p3_set_gs_pair_compl_end(p3_global_settings * p , double  pair_compl_end)
8116 {
8117   p->pair_compl_end = pair_compl_end;
8118 }
8119 
8120 void
p3_set_gs_pair_compl_end_th(p3_global_settings * p,double pair_compl_end_th)8121 p3_set_gs_pair_compl_end_th(p3_global_settings * p , double  pair_compl_end_th)
8122 {
8123   p->pair_compl_end = pair_compl_end_th;
8124 }
8125 
8126 void
p3_set_gs_min_left_three_prime_distance(p3_global_settings * p,int min_distance)8127 p3_set_gs_min_left_three_prime_distance(p3_global_settings *p, int min_distance)
8128 {
8129   p->min_left_three_prime_distance = min_distance;
8130 }
8131 
8132 void
p3_set_gs_min_right_three_prime_distance(p3_global_settings * p,int min_distance)8133 p3_set_gs_min_right_three_prime_distance(p3_global_settings *p, int min_distance)
8134 {
8135   p->min_right_three_prime_distance = min_distance;
8136 }
8137 
8138 void
p3_set_gs_min_5_prime_overlap_of_junction(p3_global_settings * p,int min_5_prime)8139 p3_set_gs_min_5_prime_overlap_of_junction(p3_global_settings *p, int min_5_prime)
8140 {
8141   p->min_5_prime_overlap_of_junction = min_5_prime;
8142 }
8143 
8144 void
p3_set_gs_min_3_prime_overlap_of_junction(p3_global_settings * p,int min_3_prime)8145 p3_set_gs_min_3_prime_overlap_of_junction(p3_global_settings *p, int min_3_prime)
8146 {
8147   p->min_3_prime_overlap_of_junction = min_3_prime;
8148 }
8149 
8150 void
p3_set_gs_max_diff_tm(p3_global_settings * p,double max_diff_tm)8151 p3_set_gs_max_diff_tm(p3_global_settings * p , double max_diff_tm) {
8152   p->max_diff_tm = max_diff_tm;
8153 }
8154 
8155 void
p3_set_gs_primer_pick_anyway(p3_global_settings * p,int val)8156 p3_set_gs_primer_pick_anyway(p3_global_settings * p , int val) {
8157   p->pick_anyway = val ;
8158 }
8159 
8160 void
p3_set_gs_primer_gc_clamp(p3_global_settings * p,int val)8161 p3_set_gs_primer_gc_clamp(p3_global_settings * p , int val) {
8162   p->gc_clamp = val;
8163 }
8164 
8165 void
p3_empty_gs_product_size_range(p3_global_settings * pgs)8166 p3_empty_gs_product_size_range(p3_global_settings *pgs) {
8167   pgs->num_intervals = 0;
8168 }
8169 
8170 int
p3_add_to_gs_product_size_range(p3_global_settings * pgs,int n1,int n2)8171 p3_add_to_gs_product_size_range(p3_global_settings *pgs,
8172                                 int n1, int n2) {
8173   if (pgs->num_intervals >= PR_MAX_INTERVAL_ARRAY)
8174     return 1;
8175   pgs->pr_min[pgs->num_intervals]  = n1;
8176   pgs->pr_max[pgs->num_intervals]  = n2;
8177   pgs->num_intervals++;
8178   return 0;
8179 }
8180 
8181 /* ============================================================ */
8182 /* END 'set' functions for p3_global_settings                   */
8183 /* ============================================================ */
8184 
8185 
8186 /* ============================================================ */
8187 /* START functions for setting and getting oligo problems       */
8188 /* ============================================================ */
8189 
8190 static void
initialize_op(primer_rec * oligo)8191 initialize_op(primer_rec *oligo) {
8192   oligo->problems.prob = 0UL;  /* 0UL is the unsigned long zero */
8193 }
8194 
8195 /* We use bitfields to store all primer data. The idea is that
8196  * a primer is uninitialized if all bits are 0. It was evaluated
8197  * if OP_PARTIALLY_WRITTEN is true. If OP_COMPLETELY_WRITTEN is
8198  * also true the primer was evaluated till the end - meaning if
8199  * all OP_... are false, the primer is OK, if some are true
8200  * primer3 was forced to use it (must_use). */
8201 
8202 
8203 #define OP_PARTIALLY_WRITTEN                   (1UL <<  0)
8204 #define OP_COMPLETELY_WRITTEN                  (1UL <<  1)
8205 #define BF_OVERLAPS_TARGET                     (1UL <<  2)
8206 #define BF_OVERLAPS_EXCL_REGION                (1UL <<  3)
8207 #define BF_INFINITE_POSITION_PENALTY           (1UL <<  4)
8208 /* Space for more bitfields */
8209 
8210 #define OP_NOT_IN_ANY_OK_REGION                (1UL <<  7)
8211 #define OP_TOO_MANY_NS                         (1UL <<  8) /* 3prime problem*/
8212 #define OP_OVERLAPS_TARGET                     (1UL <<  9) /* 3prime problem*/
8213 #define OP_HIGH_GC_CONTENT                     (1UL << 10)
8214 #define OP_LOW_GC_CONTENT                      (1UL << 11)
8215 #define OP_HIGH_TM                             (1UL << 12)
8216 #define OP_LOW_TM                              (1UL << 13)
8217 #define OP_OVERLAPS_EXCL_REGION                (1UL << 14) /* 3prime problem*/
8218 #define OP_HIGH_SELF_ANY                       (1UL << 15) /* 3prime problem*/
8219 #define OP_HIGH_SELF_END                       (1UL << 16)
8220 #define OP_NO_GC_CLAMP                         (1UL << 17) /* 3prime problem*/
8221 #define OP_HIGH_END_STABILITY                  (1UL << 18) /* 3prime problem*/
8222 #define OP_HIGH_POLY_X                         (1UL << 19) /* 3prime problem*/
8223 #define OP_LOW_SEQUENCE_QUALITY                (1UL << 20) /* 3prime problem*/
8224 #define OP_LOW_END_SEQUENCE_QUALITY            (1UL << 21) /* 3prime problem*/
8225 #define OP_HIGH_SIM_TO_NON_TEMPLATE_SEQ        (1UL << 22) /* 3prime problem*/
8226 #define OP_HIGH_SIM_TO_MULTI_TEMPLATE_SITES    (1UL << 23)
8227 #define OP_OVERLAPS_MASKED_SEQ                 (1UL << 24)
8228 #define OP_TOO_LONG                            (1UL << 25) /* 3prime problem*/
8229 #define OP_TOO_SHORT                           (1UL << 26)
8230 #define OP_DOES_NOT_AMPLIFY_ORF                (1UL << 27)
8231 #define OP_TOO_MANY_GC_AT_END                  (1UL << 28) /* 3prime problem*/
8232 #define OP_HIGH_HAIRPIN                        (1UL << 29) /* 3prime problem*/
8233 #define OP_MUST_MATCH_ERR                      (1UL << 30)
8234 
8235 /* Space for more Errors */
8236 
8237 /* Tip: the calculator of windows (in scientific mode) can easily convert
8238    between decimal and binary numbers */
8239 
8240 /* all bits 1 except bits 0 to 6 */
8241 /* (~0UL) ^ 127UL = 1111 1111  1111 1111  1111 1111  1000 0000 */
8242 static unsigned long int any_problem = (~0UL) ^ 127UL;
8243 /* 310297344UL = 0001 0010  0111 1110  1100 0011  0000 0000 */
8244 static unsigned long int five_prime_problem = 310297344UL;
8245 
8246 int
p3_ol_is_uninitialized(const primer_rec * oligo)8247 p3_ol_is_uninitialized(const primer_rec *oligo) {
8248   return (oligo->problems.prob == 0UL);
8249 }
8250 
8251 int
p3_ol_is_ok(const primer_rec * oligo)8252 p3_ol_is_ok(const primer_rec *oligo) {
8253   return (oligo->problems.prob & OP_COMPLETELY_WRITTEN) != 0;
8254 }
8255 
8256 /*
8257    Return 1 iff the argument 'oligo' has any problems -- i.e.
8258    violations of design constraints.
8259  */
8260 int
p3_ol_has_any_problem(const primer_rec * oligo)8261 p3_ol_has_any_problem(const primer_rec *oligo) {
8262   return (oligo->problems.prob & any_problem) != 0;
8263 }
8264 
8265 static int
any_5_prime_ol_extension_has_problem(const primer_rec * oligo)8266 any_5_prime_ol_extension_has_problem(const primer_rec *oligo) {
8267   return (oligo->problems.prob & five_prime_problem) != 0;
8268 }
8269 
8270 /*
8271     Return a string details the the problems in 'oligo', i.e. the
8272     constraints that 'oligo' violates.  WARNING: Returns a pointer to
8273     static storage, which is over-written on next call.
8274  */
8275 #define ADD_OP_STR(COND, STR) if (prob & COND) { tmp = STR; strcpy(next, tmp); next += strlen(tmp); }
8276 const char *
p3_get_ol_problem_string(const primer_rec * oligo)8277 p3_get_ol_problem_string(const primer_rec *oligo) {
8278   static char output[4096*2];  /* WARNING, make sure all error strings
8279                                   concatenated will not overflow this
8280                                   buffer. */
8281   char *next = output;
8282   const char *tmp;
8283   unsigned long int prob = oligo->problems.prob;
8284   output[0] = '\0';
8285 
8286   if (
8287       (prob & OP_PARTIALLY_WRITTEN)
8288       &&
8289       !(prob & OP_COMPLETELY_WRITTEN)
8290       ) {
8291     tmp = " Not completely checked;";
8292     strcpy(next, tmp);
8293     next += strlen(tmp);
8294   }
8295 
8296   {
8297     ADD_OP_STR(OP_TOO_MANY_NS,
8298                " Too many Ns;")
8299     ADD_OP_STR(OP_OVERLAPS_TARGET,
8300                " Overlaps target;")
8301     ADD_OP_STR(OP_HIGH_GC_CONTENT,
8302                " GC content too high;")
8303     ADD_OP_STR(OP_LOW_GC_CONTENT,
8304                " GC content too low;")
8305     ADD_OP_STR(OP_HIGH_TM,
8306                " Temperature too high;")
8307     ADD_OP_STR(OP_LOW_TM,
8308                " Temperature too low;")
8309     ADD_OP_STR(OP_OVERLAPS_EXCL_REGION,
8310                " Overlaps an excluded region;")
8311     ADD_OP_STR(OP_NOT_IN_ANY_OK_REGION,
8312                " Not in any ok region;")
8313     ADD_OP_STR(OP_HIGH_SELF_ANY,
8314                " Similarity to self too high;")
8315     ADD_OP_STR(OP_HIGH_SELF_END,
8316                " Similary to 3' end of self too high;")
8317     ADD_OP_STR(OP_HIGH_HAIRPIN,
8318                " Hairpin stability too high;")
8319     ADD_OP_STR(OP_NO_GC_CLAMP,
8320                " No 3' GC clamp;")
8321     ADD_OP_STR(OP_TOO_MANY_GC_AT_END,
8322                " Too many GCs at 3' end;")
8323     ADD_OP_STR(OP_HIGH_END_STABILITY,
8324                " 3' end too stable (delta-G too high);")
8325     ADD_OP_STR(OP_HIGH_POLY_X,
8326                " Contains too-long poly nucleotide tract;")
8327     ADD_OP_STR(OP_LOW_SEQUENCE_QUALITY,
8328                " Template sequence quality too low;")
8329     ADD_OP_STR(OP_LOW_END_SEQUENCE_QUALITY,
8330                " Template sequence quality at 3' end too low;")
8331     ADD_OP_STR(OP_HIGH_SIM_TO_NON_TEMPLATE_SEQ,
8332                " Similarity to non-template sequence too high;")
8333     ADD_OP_STR(OP_HIGH_SIM_TO_MULTI_TEMPLATE_SITES,
8334                " Similarity to multiple sites in template;")
8335     ADD_OP_STR(OP_OVERLAPS_MASKED_SEQ,
8336                " 3' base overlaps masked sequence;")
8337     ADD_OP_STR(OP_TOO_LONG,
8338                " Too long;")
8339     ADD_OP_STR(OP_TOO_SHORT,
8340                " Too short;")
8341     ADD_OP_STR(OP_DOES_NOT_AMPLIFY_ORF,
8342                " Would not amplify an open reading frame;")
8343     ADD_OP_STR(OP_MUST_MATCH_ERR,
8344                " Failed must_match requirements;")
8345   }
8346   return output;
8347 }
8348 #undef ADD_OP_STR
8349 
8350 static void
bf_set_overlaps_target(primer_rec * oligo,int val)8351 bf_set_overlaps_target(primer_rec *oligo, int val){
8352   if (val == 0) {
8353     oligo->problems.prob |= BF_OVERLAPS_TARGET;
8354     oligo->problems.prob ^= BF_OVERLAPS_TARGET;
8355   } else {
8356     oligo->problems.prob |= BF_OVERLAPS_TARGET;
8357   }
8358 }
8359 
8360 static int
bf_get_overlaps_target(const primer_rec * oligo)8361 bf_get_overlaps_target(const primer_rec *oligo) {
8362   return (oligo->problems.prob & BF_OVERLAPS_TARGET) != 0;
8363 }
8364 
8365 static void
bf_set_overlaps_excl_region(primer_rec * oligo,int val)8366 bf_set_overlaps_excl_region(primer_rec *oligo, int val){
8367   if (val == 0) {
8368     oligo->problems.prob |= BF_OVERLAPS_EXCL_REGION;
8369     oligo->problems.prob ^= BF_OVERLAPS_EXCL_REGION;
8370   } else {
8371     oligo->problems.prob |= BF_OVERLAPS_EXCL_REGION;
8372   }
8373 }
8374 
8375 static int
bf_get_overlaps_excl_region(const primer_rec * oligo)8376 bf_get_overlaps_excl_region(const primer_rec *oligo) {
8377   return (oligo->problems.prob & BF_OVERLAPS_EXCL_REGION) != 0;
8378 }
8379 
8380 static void
bf_set_infinite_pos_penalty(primer_rec * oligo,int val)8381 bf_set_infinite_pos_penalty(primer_rec *oligo, int val){
8382   if (val == 0) {
8383     oligo->problems.prob |= BF_INFINITE_POSITION_PENALTY;
8384     oligo->problems.prob ^= BF_INFINITE_POSITION_PENALTY;
8385   } else {
8386     oligo->problems.prob |= BF_INFINITE_POSITION_PENALTY;
8387   }
8388 }
8389 
8390 static int
bf_get_infinite_pos_penalty(const primer_rec * oligo)8391 bf_get_infinite_pos_penalty(const primer_rec *oligo) {
8392   return (oligo->problems.prob & BF_INFINITE_POSITION_PENALTY) != 0;
8393 }
8394 
8395 static void
op_set_does_not_amplify_orf(primer_rec * oligo)8396 op_set_does_not_amplify_orf(primer_rec *oligo) {
8397   oligo->problems.prob |= OP_DOES_NOT_AMPLIFY_ORF;
8398   oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8399 }
8400 
8401 static void
op_set_completely_written(primer_rec * oligo)8402 op_set_completely_written(primer_rec *oligo) {
8403   oligo->problems.prob |= OP_COMPLETELY_WRITTEN;
8404 }
8405 
8406 static void
op_set_must_match_err(primer_rec * oligo)8407 op_set_must_match_err(primer_rec *oligo) {
8408   oligo->problems.prob |= OP_MUST_MATCH_ERR;
8409   oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8410 }
8411 
8412 static void
op_set_too_many_ns(primer_rec * oligo)8413 op_set_too_many_ns(primer_rec *oligo) {
8414   oligo->problems.prob |= OP_TOO_MANY_NS;
8415   oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8416 }
8417 
8418 static void
op_set_overlaps_target(primer_rec * oligo)8419 op_set_overlaps_target(primer_rec *oligo) {
8420   oligo->problems.prob |= OP_OVERLAPS_TARGET;
8421   oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8422 }
8423 
8424 static void
op_set_high_gc_content(primer_rec * oligo)8425 op_set_high_gc_content(primer_rec *oligo) {
8426   oligo->problems.prob |= OP_HIGH_GC_CONTENT;
8427   oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8428 }
8429 
8430 static void
op_set_low_gc_content(primer_rec * oligo)8431 op_set_low_gc_content(primer_rec *oligo) {
8432   oligo->problems.prob |= OP_LOW_GC_CONTENT;
8433   oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8434 }
8435 
8436 static void
op_set_high_tm(primer_rec * oligo)8437 op_set_high_tm(primer_rec *oligo) {
8438   oligo->problems.prob |= OP_HIGH_TM;
8439   oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8440 }
8441 
8442 static void
op_set_low_tm(primer_rec * oligo)8443 op_set_low_tm(primer_rec *oligo) {
8444   oligo->problems.prob |= OP_LOW_TM;
8445   oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8446 }
8447 
8448 static void
op_set_overlaps_excluded_region(primer_rec * oligo)8449 op_set_overlaps_excluded_region(primer_rec *oligo) {
8450   oligo->problems.prob |= OP_OVERLAPS_EXCL_REGION;
8451   oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8452 }
8453 
8454 static void
op_set_not_in_any_ok_region(primer_rec * oligo)8455 op_set_not_in_any_ok_region(primer_rec *oligo) {
8456   oligo->problems.prob |= OP_NOT_IN_ANY_OK_REGION;
8457   oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8458 }
8459 
8460 static void
op_set_high_self_any(primer_rec * oligo)8461 op_set_high_self_any(primer_rec *oligo) {
8462   oligo->problems.prob |= OP_HIGH_SELF_ANY;
8463   oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8464 }
8465 
8466 static void
op_set_high_self_end(primer_rec * oligo)8467 op_set_high_self_end(primer_rec *oligo) {
8468   oligo->problems.prob |= OP_HIGH_SELF_END;
8469   oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8470 }
8471 
8472 static void
op_set_high_hairpin_th(primer_rec * oligo)8473 op_set_high_hairpin_th(primer_rec *oligo) {
8474    oligo->problems.prob |= OP_HIGH_HAIRPIN;
8475    oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8476 }
8477 
8478 static void
op_set_no_gc_glamp(primer_rec * oligo)8479 op_set_no_gc_glamp(primer_rec *oligo) {
8480   oligo->problems.prob |= OP_NO_GC_CLAMP;
8481   oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8482 }
8483 
8484 static void
op_set_too_many_gc_at_end(primer_rec * oligo)8485 op_set_too_many_gc_at_end(primer_rec *oligo) {
8486   oligo->problems.prob |= OP_TOO_MANY_GC_AT_END;
8487   oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8488 }
8489 
8490 /* Must not be called on a hybridization probe / internal oligo */
8491 static void
op_set_high_end_stability(primer_rec * oligo)8492 op_set_high_end_stability(primer_rec *oligo) {
8493   oligo->problems.prob |= OP_HIGH_END_STABILITY;
8494   oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8495 }
8496 
8497 static void
op_set_high_poly_x(primer_rec * oligo)8498 op_set_high_poly_x(primer_rec *oligo) {
8499   oligo->problems.prob |= OP_HIGH_POLY_X;
8500   oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8501 }
8502 
8503 static void
op_set_low_sequence_quality(primer_rec * oligo)8504 op_set_low_sequence_quality(primer_rec *oligo) {
8505   oligo->problems.prob |= OP_LOW_SEQUENCE_QUALITY;
8506   oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8507 }
8508 
8509 static void
op_set_low_end_sequence_quality(primer_rec * oligo)8510 op_set_low_end_sequence_quality(primer_rec *oligo) {
8511   oligo->problems.prob |= OP_LOW_END_SEQUENCE_QUALITY;
8512   oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8513 }
8514 
8515 static void
op_set_high_similarity_to_non_template_seq(primer_rec * oligo)8516 op_set_high_similarity_to_non_template_seq(primer_rec *oligo) {
8517   oligo->problems.prob |= OP_HIGH_SIM_TO_NON_TEMPLATE_SEQ;
8518   oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8519 }
8520 
8521 static void
op_set_high_similarity_to_multiple_template_sites(primer_rec * oligo)8522 op_set_high_similarity_to_multiple_template_sites(primer_rec *oligo) {
8523   oligo->problems.prob |= OP_HIGH_SIM_TO_MULTI_TEMPLATE_SITES;
8524   oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8525 }
8526 
8527 static void
op_set_overlaps_masked_sequence(primer_rec * oligo)8528 op_set_overlaps_masked_sequence(primer_rec *oligo) {
8529   oligo->problems.prob |= OP_OVERLAPS_MASKED_SEQ;
8530   oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8531 }
8532 
8533 static void
op_set_too_long(primer_rec * oligo)8534 op_set_too_long(primer_rec *oligo) {
8535   oligo->problems.prob |= OP_TOO_LONG;
8536   oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8537 }
8538 
8539 static void
op_set_too_short(primer_rec * oligo)8540 op_set_too_short(primer_rec *oligo) {
8541   oligo->problems.prob |= OP_TOO_SHORT;
8542   oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8543 }
8544 
8545 /* ============================================================ */
8546 /* END functions for setting and getting oligo problems         */
8547 /* ============================================================ */
8548 
8549 
8550 /* ============================================================ */
8551 /* START functions for getting values from p3retvals            */
8552 /* ============================================================ */
8553 
8554 char *
p3_get_rv_and_gs_warnings(const p3retval * retval,const p3_global_settings * pa)8555 p3_get_rv_and_gs_warnings(const p3retval *retval,
8556                           const p3_global_settings *pa) {
8557 
8558   pr_append_str warning;
8559 
8560   PR_ASSERT(NULL != pa);
8561 
8562   init_pr_append_str(&warning);
8563 
8564   if (seq_lib_warning_data(pa->p_args.repeat_lib))
8565     pr_append_new_chunk(&warning, seq_lib_warning_data(pa->p_args.repeat_lib));
8566 
8567   if(seq_lib_warning_data(pa->o_args.repeat_lib)) {
8568     pr_append_new_chunk(&warning, seq_lib_warning_data(pa->o_args.repeat_lib));
8569     pr_append(&warning, " (for internal oligo)");
8570   }
8571 
8572   if (!pr_is_empty(&retval->warnings))
8573     pr_append_new_chunk(&warning,  retval->warnings.data);
8574 
8575   return pr_is_empty(&warning) ? NULL : warning.data;
8576 }
8577 
8578 const char *
p3_get_rv_global_errors(const p3retval * retval)8579 p3_get_rv_global_errors(const p3retval *retval) {
8580   return retval->glob_err.data;
8581 }
8582 
8583 const char *
p3_get_rv_per_sequence_errors(const p3retval * retval)8584 p3_get_rv_per_sequence_errors(const p3retval *retval) {
8585   return retval->per_sequence_err.data;
8586 }
8587 
8588 p3_output_type
p3_get_rv_output_type(const p3retval * r)8589 p3_get_rv_output_type(const p3retval *r) {
8590   return r->output_type;
8591 }
8592 
8593 const char *
p3_get_rv_warnings(const p3retval * r)8594 p3_get_rv_warnings(const p3retval *r) {
8595   return pr_append_str_chars(&r->warnings);
8596 }
8597 
8598 int
p3_get_rv_stop_codon_pos(p3retval * r)8599 p3_get_rv_stop_codon_pos(p3retval *r) {
8600   return r->stop_codon_pos;
8601 }
8602 
8603 /* ============================================================ */
8604 /* END functions for getting values from p3retvals            */
8605 /* ============================================================ */
8606 
8607 void
p3_print_args(const p3_global_settings * p,seq_args * s)8608 p3_print_args(const p3_global_settings *p, seq_args *s)
8609 {
8610   int i;
8611 
8612   if (p != NULL) {
8613     printf("=============\n");
8614     printf("BEGIN GLOBAL ARGS\n") ;
8615     printf("  primer_task %i\n", p->primer_task);
8616     printf("  pick_left_primer %i\n", p->pick_left_primer);
8617     printf("  pick_right_primer %i\n", p->pick_right_primer);
8618     printf("  pick_internal_oligo %i\n", p->pick_internal_oligo);
8619     printf("  file_flag %i\n", p->file_flag) ;
8620     printf("  first_base_index %i\n", p->first_base_index);
8621     printf("  liberal_base %i\n", p->liberal_base );
8622     printf("  num_return %i\n", p->num_return) ;
8623     printf("  pick_anyway %i\n", p->pick_anyway);
8624     printf("  lib_ambiguity_codes_consensus %i\n",
8625            p->lib_ambiguity_codes_consensus) ;
8626     printf("  quality_range_min %i\n", p->quality_range_min) ;
8627     printf("  quality_range_max %i\n", p->quality_range_max) ;
8628 
8629     printf("  tm_santalucia %i\n", p->tm_santalucia) ;
8630     printf("  salt_corrections %i\n", p->salt_corrections) ;
8631     printf("  max_end_stability %f\n", p->max_end_stability) ;
8632     printf("  gc_clamp %i\n", p->gc_clamp) ;
8633     printf("  max_end_gc %i\n", p->max_end_gc);
8634     printf("  lowercase_masking %i\n", p->lowercase_masking) ;
8635     printf("  thermodynamic_oligo_alignment %i\n", p->thermodynamic_oligo_alignment);
8636     printf("  thermodynamic_template_alignment %i\n", p->thermodynamic_template_alignment);
8637     printf("  outside_penalty %f\n", p->outside_penalty) ;
8638     printf("  inside_penalty %f\n", p->inside_penalty) ;
8639     printf("  number of product size ranges: %d\n", p->num_intervals);
8640     printf("  product size ranges:\n");
8641     for (i = 0; i < p->num_intervals; i++) {
8642       printf("  %d - %d \n", p->pr_min[i], p->pr_max[i]);
8643     }
8644     printf("  product_opt_size %i\n", p->product_opt_size) ;
8645     printf("  product_max_tm %f\n", p->product_max_tm) ;
8646     printf("  product_min_tm %f\n", p->product_min_tm) ;
8647     printf("  product_opt_tm %f\n", p->product_opt_tm) ;
8648     printf("  pair_max_template_mispriming %f\n", p->pair_max_template_mispriming) ;
8649     printf("  pair_max_template_mispriming_th %f\n", p->pair_max_template_mispriming_th) ;
8650     printf("  pair_repeat_compl %f\n", p->pair_repeat_compl) ;
8651     printf("  pair_compl_any %f\n", p->pair_compl_any) ;
8652     printf("  pair_compl_end %f\n", p->pair_compl_end) ;
8653     printf("  pair_compl_any_th %f\n", p->pair_compl_any_th) ;
8654     printf("  pair_compl_end_th %f\n", p->pair_compl_end_th) ;
8655 
8656     printf("  min_left_three_prime_distance %i\n", p->min_left_three_prime_distance) ;
8657     printf("  min_right_three_prime_distance %i\n", p->min_right_three_prime_distance) ;
8658     printf("  min_5_prime_overlap_of_junction %i\n", p->min_5_prime_overlap_of_junction);
8659     printf("  min_3_prime_overlap_of_junction %i\n", p->min_3_prime_overlap_of_junction);
8660     printf("  dump %i\n", p->dump);
8661 
8662     printf("  begin pr_pair_weights\n") ;
8663     printf("    primer_quality %f\n", p->pr_pair_weights.primer_quality) ;
8664     printf("    io_quality %f\n", p->pr_pair_weights.io_quality) ;
8665     printf("    diff_tm %f\n", p->pr_pair_weights.diff_tm) ;
8666     printf("    compl_any %f\n", p->pr_pair_weights.compl_any) ;
8667     printf("    compl_end %f\n", p->pr_pair_weights.compl_end) ;
8668     printf("    compl_any_th %f\n", p->pr_pair_weights.compl_any_th) ;
8669     printf("    compl_end_th %f\n", p->pr_pair_weights.compl_end_th) ;
8670     printf("    product_tm_lt %f\n", p->pr_pair_weights.product_tm_lt) ;
8671     printf("    product_tm_gt %f\n", p->pr_pair_weights.product_tm_gt) ;
8672     printf("    product_size_lt %f\n", p->pr_pair_weights.product_size_lt) ;
8673     printf("    product_size_gt %f\n", p->pr_pair_weights.product_size_gt) ;
8674     printf("    repeat_sim %f\n", p->pr_pair_weights.repeat_sim) ;
8675     printf("    template_mispriming %f\n", p->pr_pair_weights.template_mispriming) ;
8676     printf("    template_mispriming_th %f\n", p->pr_pair_weights.template_mispriming_th) ;
8677     printf("  end pair_weights\n") ;
8678 
8679 
8680     printf("\n\n");
8681     printf("=============\n");
8682     printf("BEGIN primer_args\n");
8683     printf("begin oligo_weights\n");
8684     printf("temp_gt %f\n", p->p_args.weights.temp_gt ) ;
8685     printf("temp_gt %f\n", p->p_args.weights.temp_gt) ;
8686     printf("temp_lt %f\n", p->p_args.weights.temp_lt) ;
8687     printf("gc_content_gt %f\n", p->p_args.weights.gc_content_gt) ;
8688     printf("gc_content_lt %f\n", p->p_args.weights.gc_content_lt) ;
8689     printf("compl_any %f\n", p->p_args.weights.compl_any) ;
8690     printf("compl_end %f\n", p->p_args.weights.compl_end) ;
8691     printf("compl_any_th %f\n", p->p_args.weights.compl_any_th) ;
8692     printf("compl_end_th %f\n", p->p_args.weights.compl_end_th) ;
8693     printf("hairpin %f\n", p->p_args.weights.hairpin_th) ;
8694     printf("repeat_sim %f\n", p->p_args.weights.repeat_sim) ;
8695     printf("length_lt %f\n", p->p_args.weights.length_lt) ;
8696     printf("length_gt %f\n", p->p_args.weights.length_gt) ;
8697     printf("seq_quality %f\n", p->p_args.weights.seq_quality) ;
8698     printf("end_quality %f\n", p->p_args.weights.end_quality) ;
8699     printf("pos_penalty %f\n", p->p_args.weights.pos_penalty) ;
8700     printf("end_stability %f\n", p->p_args.weights.end_stability) ;
8701     printf("num_ns %f\n", p->p_args.weights.num_ns) ;
8702     printf("template_mispriming %f\n", p->p_args.weights.template_mispriming) ;
8703     printf("template_mispriming_th %f\n", p->p_args.weights.template_mispriming_th) ;
8704     printf("end oligo_weights\n") ;
8705 
8706     printf("opt_tm %f\n", p->p_args.opt_tm) ;
8707     printf("min_tm %f\n", p->p_args.min_tm) ;
8708     printf("max_tm %f\n", p->p_args.max_tm) ;
8709     printf("opt_gc_content %f\n", p->p_args.opt_gc_content) ;
8710     printf("max_gc %f\n", p->p_args.max_gc) ;
8711     printf("min_gc %f\n", p->p_args.min_gc) ;
8712     printf("divalent_conc %f\n", p->p_args.divalent_conc) ;
8713     printf("dntp_conc %f\n", p->p_args.dntp_conc) ;
8714     printf("dna_conc %f\n", p->p_args.dna_conc) ;
8715     printf("num_ns_accepted %i\n", p->p_args.num_ns_accepted) ;
8716     printf("opt_size %i\n", p->p_args.opt_size) ;
8717     printf("min_size %i\n", p->p_args.min_size) ;
8718     printf("max_size %i\n", p->p_args.max_size) ;
8719     printf("max_poly_x %i\n", p->p_args.max_poly_x) ;
8720     printf("min_end_quality %i\n", p->p_args.min_end_quality) ;
8721     printf("min_quality %i\n", p->p_args.min_quality) ;
8722     printf("max_self_any %f\n", p->p_args.max_self_any) ;
8723     printf("max_self_end %f\n", p->p_args.max_self_end) ;
8724     printf("max_self_any_th %f\n", p->p_args.max_self_any_th) ;
8725     printf("max_self_end_th %f\n", p->p_args.max_self_end_th) ;
8726     printf("max_hairpin %f\n", p->p_args.max_hairpin_th) ;
8727     printf("max_repeat_compl %f\n", p->p_args.max_repeat_compl) ;
8728     printf("max_template_mispriming %f\n", p->p_args.max_template_mispriming) ;
8729     printf("max_template_mispriming_th %f\n", p->p_args.max_template_mispriming_th) ;
8730     printf("end primer args\n") ;
8731 
8732     printf("begin internal oligo args (p->o_args.)\n") ;
8733 
8734     printf("  begin internal oligo_weights (p->o_args.weights.)\n") ;
8735     printf("    temp_gt %f\n", p->o_args.weights.temp_gt) ;
8736     printf("    temp_lt %f\n", p->o_args.weights.temp_lt) ;
8737     printf("    gc_content_gt %f\n", p->o_args.weights.gc_content_gt) ;
8738     printf("    gc_content_lt %f\n", p->o_args.weights.gc_content_lt) ;
8739     printf("    compl_any %f\n", p->o_args.weights.compl_any) ;
8740     printf("    compl_end %f\n", p->o_args.weights.compl_end) ;
8741     printf("    compl_any_th %f\n", p->o_args.weights.compl_any_th) ;
8742     printf("    compl_end_th %f\n", p->o_args.weights.compl_end_th) ;
8743     printf("    hairpin %f\n", p->o_args.weights.hairpin_th) ;
8744     printf("    repeat_sim %f\n", p->o_args.weights.repeat_sim) ;
8745     printf("    length_lt %f\n", p->o_args.weights.length_lt) ;
8746     printf("    length_gt %f\n", p->o_args.weights.length_gt) ;
8747     printf("    seq_quality %f\n", p->o_args.weights.seq_quality) ;
8748     printf("    end_quality %f\n", p->o_args.weights.end_quality) ;
8749     printf("    pos_penalty %f\n", p->o_args.weights.pos_penalty) ;
8750     printf("    end_stability %f\n", p->o_args.weights.end_stability) ;
8751     printf("    num_ns %f\n", p->o_args.weights.num_ns) ;
8752     printf("  end internal oligo_weights\n") ;
8753 
8754     printf("  opt_tm %f\n", p->o_args.opt_tm) ;
8755     printf("  min_tm %f\n", p->o_args.min_tm) ;
8756     printf("  max_tm %f\n", p->o_args.max_tm) ;
8757     printf("  opt_gc_content %f\n", p->o_args.opt_gc_content) ;
8758     printf("  max_gc %f\n", p->o_args.max_gc) ;
8759     printf("  min_gc %f\n", p->o_args.min_gc) ;
8760     printf("  divalent_conc %f\n", p->o_args.divalent_conc) ;
8761     printf("  dntp_conc %f\n", p->o_args.dntp_conc) ;
8762     printf("  dna_conc %f\n", p->o_args.dna_conc) ;
8763     printf("  num_ns_accepted %i\n", p->o_args.num_ns_accepted) ;
8764     printf("  opt_size %i\n", p->o_args.opt_size) ;
8765     printf("  min_size %i\n", p->o_args.min_size) ;
8766     printf("  max_size %i\n", p->o_args.max_size) ;
8767     printf("  max_poly_x %i\n", p->o_args.max_poly_x) ;
8768     printf("  min_end_quality %i\n", p->o_args.min_end_quality) ;
8769     printf("  min_quality %i\n", p->o_args.min_quality) ;
8770     printf("  max_self_any %f\n", p->o_args.max_self_any) ;
8771     printf("  max_self_end %f\n", p->o_args.max_self_end) ;
8772     printf("  max_repeat_compl %f\n", p->o_args.max_repeat_compl) ;
8773     printf("  end internal oligo args\n");
8774     printf("\n");
8775     printf("END GLOBAL ARGS\n");
8776     printf("=============\n");
8777     printf("\n");
8778   }
8779 
8780   if (s != NULL) {
8781     printf("=============\n");
8782     printf("BEGIN SEQUENCE ARGS\n") ;
8783     /* TO DO: complete the statments for dumping this data
8784        printf("interval_array_t2 tar2 %i\n",
8785        int pairs[PR_MAX_INTERVAL_ARRAY][2]) ;
8786        int count) ;
8787        printf("interval_array_t2 excl2 %i\n",
8788        int pairs[PR_MAX_INTERVAL_ARRAY][2]) ;
8789        int count) ;
8790        printf("interval_array_t2 excl_internal2 %i\n",
8791        int pairs[PR_MAX_INTERVAL_ARRAY][2]) ;
8792        int count) ;
8793        printf("ok_regions \n");
8794     */
8795 
8796     if (s->primer_overlap_junctions_count > 0) {
8797       printf("primer_overlap_junctions_count %i\n",
8798              s->primer_overlap_junctions_count);
8799       printf("primer_overlap_junctions_list [\n");
8800       for (i = 0; i < s->primer_overlap_junctions_count; i++) {
8801         printf("   %i\n", s->primer_overlap_junctions[i]);
8802       }
8803       printf("]\n");
8804     }
8805 
8806     printf("incl_s %i\n", s->incl_s) ;
8807     printf("incl_l %i\n", s->incl_l) ;
8808     printf("start_codon_pos %i\n", s->start_codon_pos) ;
8809     printf("n_quality %i\n", s->n_quality) ;
8810     /* TO DO printf("quality%i\", s->quality) ; */
8811     printf("quality_storage_size %i\n", s->quality_storage_size) ;
8812     printf("*sequence %s\n", s->sequence) ;
8813     printf("*sequence_name %s\n", s->sequence_name) ;
8814     printf("*sequence_file %s\n", s->sequence_file) ;
8815     printf("*trimmed_seq %s\n", s->trimmed_seq) ;
8816     printf("*trimmed_orig_seq %s\n", s->trimmed_orig_seq) ;
8817     printf("*upcased_seq %s\n", s->upcased_seq) ;
8818     printf("*upcased_seq_r %s\n", s->upcased_seq_r) ;
8819     printf("*left_input %s\n", s->left_input) ;
8820     printf("*right_input %s\n", s->right_input) ;
8821     printf("*internal_input %s\n", s->internal_input) ;
8822     printf("force_left_start %i\n", s->force_left_start) ;
8823     printf("force_left_end %i\n", s->force_left_end) ;
8824     printf("force_right_start %i\n", s->force_right_start) ;
8825     printf("force_right_end %i\n", s->force_right_end) ;
8826     printf("END SEQUENCE ARGS\n") ;
8827     printf("=============\n");
8828     printf("\n");
8829   }
8830 }
8831