1 /*
2  *  commands.c
3  *
4  *  Various functions dealing with parsing and application of commands
5  *
6  *  (c) 2016 Ronny Lorenz
7  *
8  *  ViennaRNA package
9  */
10 
11 #ifdef HAVE_CONFIG_H
12 #include "config.h"
13 #endif
14 
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <math.h>
19 #include <ctype.h>
20 
21 #include "ViennaRNA/fold_vars.h"
22 #include "ViennaRNA/utils/basic.h"
23 #include "ViennaRNA/constraints/hard.h"
24 #include "ViennaRNA/constraints/soft.h"
25 #include "ViennaRNA/io/utils.h"
26 #include "ViennaRNA/commands.h"
27 
28 /**
29  *  @brief Types of commands within a list of #vrna_command_s structures
30  */
31 typedef enum {
32   VRNA_CMD_ERROR  = -1,
33   VRNA_CMD_LAST   = 0,
34   VRNA_CMD_HC,
35   VRNA_CMD_SC,
36   VRNA_CMD_MOTIF,
37   VRNA_CMD_UD,
38   VRNA_CMD_SD
39 } vrna_command_e;
40 
41 
42 /**
43  *  @brief List element for commands ready for application to a #vrna_fold_compound_t
44  *  @see vrna_file_commands_read(), vrna_commands_apply(), vrna_commands_free()
45  */
46 struct vrna_command_s {
47   vrna_command_e  type;
48   void            *data;
49 };
50 
51 typedef void *(command_parser_function)(const char *line);
52 
53 /*
54  #################################
55  # PRIVATE FUNCTION DECLARATIONS #
56  #################################
57  */
58 PRIVATE struct vrna_command_s parse_command(const char    *line,
59                                             int           line_number,
60                                             const char    *filename,
61                                             unsigned int  options);
62 
63 
64 PRIVATE void *parse_ud_command(const char *line);
65 
66 
67 PRIVATE void *parse_constraint_force(const char *line);
68 
69 
70 PRIVATE void *parse_constraint_prohibit(const char *line);
71 
72 
73 PRIVATE void *parse_constraint_con(const char *line);
74 
75 
76 PRIVATE void *parse_constraint_allow(const char *line);
77 
78 
79 PRIVATE void *parse_constraint_energy(const char *line);
80 
81 
82 PRIVATE void *parse_constraint(const char *line,
83                                char       command);
84 
85 
86 PRIVATE int parse_constraints_line(const char     *line,
87                                    char           command,
88                                    int            *i,
89                                    int            *j,
90                                    int            *k,
91                                    int            *l,
92                                    unsigned char  *loop,
93                                    char           *orientation,
94                                    float          *e);
95 
96 
97 PRIVATE int apply_hard_constraint(vrna_fold_compound_t  *vc,
98                                   void                  *constraint);
99 
100 
101 PRIVATE int apply_soft_constraint(vrna_fold_compound_t  *vc,
102                                   void                  *constraint);
103 
104 
105 PRIVATE int apply_ud(vrna_fold_compound_t *vc,
106                      void                 *data);
107 
108 
109 /*
110  #################################
111  # PRIVATE VARIABLES             #
112  #################################
113  */
114 
115 typedef struct {
116   char                    cmd[3];
117   vrna_command_e          type;
118   command_parser_function *parser;
119 } parsable;
120 
121 
122 /* number of commands we currently know and are able to interpret */
123 #define NUM_COMMANDS  7
124 
125 /* set of known parsable commands */
126 parsable known_commands[NUM_COMMANDS] = {
127   /* cmd , type , parser */
128   { "UD", VRNA_CMD_UD, parse_ud_command          },   /* unstructured domain */
129   { "SD", VRNA_CMD_SD, NULL                      },   /* structured domain */
130   { "P",  VRNA_CMD_HC, parse_constraint_prohibit },   /* prohibit base pairing */
131   { "F",  VRNA_CMD_HC, parse_constraint_force    },   /* force base pairing */
132   { "C",  VRNA_CMD_HC, parse_constraint_con      },   /* remove conflicting pairs/force nucleotide in loop context */
133   { "A",  VRNA_CMD_HC, parse_constraint_allow    },   /* allow (non-canonical) pairs */
134   { "E",  VRNA_CMD_SC, parse_constraint_energy   }  /* soft constraint */
135 };
136 
137 typedef struct {
138   int           i;
139   int           j;
140   int           k;
141   int           l;
142   int           size;
143   unsigned char loop;
144   char          orientation;
145   float         e;
146   char          command;
147 } constraint_struct;
148 
149 
150 typedef struct {
151   char          *motif_name;
152   char          *motif;
153   float         motif_en;
154   unsigned int  loop_type;
155 } ud_struct;
156 
157 /*
158  #################################
159  # BEGIN OF FUNCTION DEFINITIONS #
160  #################################
161  */
162 PUBLIC int
vrna_file_commands_apply(vrna_fold_compound_t * vc,const char * filename,unsigned int options)163 vrna_file_commands_apply(vrna_fold_compound_t *vc,
164                          const char           *filename,
165                          unsigned int         options)
166 {
167   /** [Applying commands from file] */
168   int                   r;
169   struct vrna_command_s *cmds;
170 
171   cmds  = vrna_file_commands_read(filename, options);
172   r     = vrna_commands_apply(vc, cmds, options);
173 
174   vrna_commands_free(cmds);
175 
176   return r;
177   /** [Applying commands from file] */
178 }
179 
180 
181 PUBLIC struct vrna_command_s *
vrna_file_commands_read(const char * filename,unsigned int options)182 vrna_file_commands_read(const char    *filename,
183                         unsigned int  options)
184 {
185   FILE                  *fp;
186   char                  *line;
187   int                   num_commands, max_commands, line_number, valid;
188   struct vrna_command_s cmd, *output;
189 
190   line_number   = 0;
191   num_commands  = 0;
192   max_commands  = 15;
193   line          = NULL;
194 
195   if (!(fp = fopen(filename, "r"))) {
196     vrna_message_warning("Command File could not be opened!");
197     return NULL;
198   }
199 
200   output = (struct vrna_command_s *)vrna_alloc(sizeof(struct vrna_command_s) * max_commands);
201 
202   /* let's go through the file line by line and parse the commands */
203   while ((line = vrna_read_line(fp))) {
204     line_number++;
205     switch (*line) {
206       /* skip comment lines */
207       case '#': /* fall through */
208       case '%': /* fall through */
209       case ';': /* fall through */
210       case '/': /* fall through */
211       case '*': /* fall through */
212       case ' ': /* fall through */
213       case '\0':
214         free(line);
215         continue;
216       default:
217         cmd = parse_command((const char *)line, line_number, filename, options);
218         break;
219     }
220 
221     if (cmd.type == VRNA_CMD_LAST) {
222       /* end of command list */
223       free(line);
224       break;
225     } else {
226       /* check whether command is valid in user-defined context */
227       valid = 0;
228       switch (cmd.type) {
229         case VRNA_CMD_HC:
230           valid = options & VRNA_CMD_PARSE_HC;
231           break;
232 
233         case VRNA_CMD_SC:
234           valid = options & VRNA_CMD_PARSE_SC;
235           break;
236 
237         case VRNA_CMD_UD:
238           valid = options & VRNA_CMD_PARSE_UD;
239           break;
240 
241         case VRNA_CMD_SD:
242           valid = options & VRNA_CMD_PARSE_SD;
243           break;
244 
245         default:
246           break;
247       }
248 
249       if (valid) {
250         /* add command to list */
251         output[num_commands++] = cmd;
252 
253         /* increase length of command list if necessary */
254         if (num_commands == max_commands) {
255           max_commands  *= 1.2;
256           output        = (struct vrna_command_s *)vrna_realloc(output,
257                                                                 sizeof(struct vrna_command_s) *
258                                                                 max_commands);
259         }
260       } else if ((!(options & VRNA_CMD_PARSE_SILENT)) && (!(cmd.type == VRNA_CMD_ERROR))) {
261         /* errors have been reported earlier */
262         vrna_message_warning("Ignoring forbidden command in file \"%s\":\nline %d: %s",
263                              filename,
264                              line_number,
265                              (const char *)line);
266       }
267     }
268 
269     free(line);
270   }
271 
272   /* mark end of command list */
273   output = (struct vrna_command_s *)vrna_realloc(output,
274                                                  sizeof(struct vrna_command_s) *
275                                                  (num_commands + 1));
276   output[num_commands].type = VRNA_CMD_LAST;
277   output[num_commands].data = NULL;
278 
279   /* cleanup */
280   free(line);
281 
282   return output;
283 }
284 
285 
286 PUBLIC int
vrna_commands_apply(vrna_fold_compound_t * vc,struct vrna_command_s * commands,unsigned int options)287 vrna_commands_apply(vrna_fold_compound_t  *vc,
288                     struct vrna_command_s *commands,
289                     unsigned int          options)
290 {
291   int                   r = 0;
292   struct vrna_command_s *ptr;
293 
294   if (vc && commands) {
295     for (ptr = commands; ptr->type != VRNA_CMD_LAST; ptr++) {
296       switch (ptr->type) {
297         case VRNA_CMD_HC:
298           if (options & VRNA_CMD_PARSE_HC)
299             r += apply_hard_constraint(vc, ptr->data);
300 
301           break;
302 
303         case VRNA_CMD_SC:
304           if (options & VRNA_CMD_PARSE_SC)
305             r += apply_soft_constraint(vc, ptr->data);
306 
307           break;
308 
309         case VRNA_CMD_UD:
310           if (options & VRNA_CMD_PARSE_UD)
311             r += apply_ud(vc, ptr->data);
312 
313           break;
314 
315         default:            /* do nothing */
316           break;
317       }
318     }
319   }
320 
321   return r;
322 }
323 
324 
325 PUBLIC void
vrna_commands_free(struct vrna_command_s * commands)326 vrna_commands_free(struct vrna_command_s *commands)
327 {
328   struct vrna_command_s *ptr;
329 
330   if (commands) {
331     for (ptr = commands; ptr->type != VRNA_CMD_LAST; ptr++) {
332       switch (ptr->type) {
333         case VRNA_CMD_UD:
334         {
335           ud_struct *d = (ud_struct *)ptr->data;
336           free(d->motif_name);
337           free(d->motif);
338           free(ptr->data);
339         }
340         break;
341 
342         default:
343           free(ptr->data);
344           break;
345       }
346     }
347     free(commands);
348   }
349 }
350 
351 
352 PRIVATE int
apply_ud(vrna_fold_compound_t * vc,void * data)353 apply_ud(vrna_fold_compound_t *vc,
354          void                 *data)
355 {
356   ud_struct *d = (ud_struct *)data;
357 
358   vrna_ud_add_motif(vc, d->motif, d->motif_en, d->motif_name, d->loop_type);
359 
360   return 1;
361 }
362 
363 
364 PRIVATE int
apply_hard_constraint(vrna_fold_compound_t * vc,void * data)365 apply_hard_constraint(vrna_fold_compound_t  *vc,
366                       void                  *data)
367 {
368   int               i, j, k, l, h, cnt1, cnt2, cnt3;
369   int               num_hc_up, max_hc_up;
370   vrna_hc_up_t      *hc_up;
371   unsigned char     t;
372   char              orientation;
373   constraint_struct *constraint = (constraint_struct *)data;
374 
375   i           = constraint->i;
376   j           = constraint->j;
377   k           = constraint->k;
378   l           = constraint->l;
379   t           = constraint->loop;
380   orientation = constraint->orientation;
381   h           = constraint->size;
382 
383   /* actually apply constraints */
384   if (h == 0) {
385     /* range mode (prohibit pairs only) */
386     for (cnt1 = i; cnt1 <= j; cnt1++)
387       for (cnt2 = MAX2(cnt1 + 1, k); cnt2 <= l; cnt2++)
388         vrna_hc_add_bp(vc, cnt1, cnt2, t);
389   } else {
390     /* we'll collect hard constraints for unpairedness */
391     num_hc_up = 0;
392     max_hc_up = 15;
393     hc_up     = vrna_alloc(sizeof(vrna_hc_up_t) * max_hc_up);
394 
395     for (cnt1 = i; cnt1 <= j; cnt1++)
396       for (cnt2 = k; cnt2 <= l; cnt2++)
397         for (cnt3 = h; cnt3 != 0; cnt3--) {
398           if (cnt2 == 0) {
399             /* enforce unpairedness of nucleotide */
400             /* just store this constraint, we'll apply it later */
401             hc_up[num_hc_up].position = cnt1 + (cnt3 - 1);
402             hc_up[num_hc_up].options  = t;
403             num_hc_up++;
404             if (num_hc_up == max_hc_up) {
405               /* increase size of hc_up if necessary */
406               max_hc_up = 1.2 * max_hc_up;
407               hc_up     = (vrna_hc_up_t *)vrna_realloc(hc_up, sizeof(vrna_hc_up_t) * max_hc_up);
408             }
409           } else if ((i == j) && (j == k) && (k == l)) {
410             /* enforce pairedness of nucleotide */
411             int d = 0;
412             if (orientation != '\0')
413               d = (orientation == 'U') ? -1 : 1;
414 
415             vrna_hc_add_bp_nonspecific(vc, cnt1 + (cnt3 - 1), d, t);
416           } else {
417             /* enforce / prohibit base pair */
418             vrna_hc_add_bp(vc, cnt1 + (cnt3 - 1), cnt2 - (cnt3 - 1), t);
419           }
420         }
421 
422     /* add hard constraints for unpairedness */
423     if (num_hc_up > 0) {
424       hc_up[num_hc_up].position = 0; /* mark end of list */
425       vrna_hc_add_up_batch(vc, hc_up);
426     }
427 
428     free(hc_up);
429   }
430 
431   return 1;
432 }
433 
434 
435 PRIVATE int
apply_soft_constraint(vrna_fold_compound_t * vc,void * data)436 apply_soft_constraint(vrna_fold_compound_t  *vc,
437                       void                  *data)
438 {
439   int               i, j, k, l, h, cnt1, cnt2, cnt3;
440   float             e;
441   constraint_struct *constraint = (constraint_struct *)data;
442 
443   i = constraint->i;
444   j = constraint->j;
445   k = constraint->k;
446   l = constraint->l;
447   h = constraint->size;
448   e = constraint->e;
449 
450   for (cnt1 = i; cnt1 <= j; cnt1++)
451     for (cnt2 = k; cnt2 <= l; cnt2++)
452       for (cnt3 = h; cnt3 != 0; cnt3--) {
453         if ((cnt2 == 0) || ((i == j) && (j == k) && (k == l)))  /* enforce nucleotide constraint */
454           vrna_sc_add_up(vc, cnt1 + (cnt3 - 1), e, VRNA_OPTION_DEFAULT);
455         else                                                    /* enforce base pair constraint */
456           vrna_sc_add_bp(vc, cnt1 + (cnt3 - 1), cnt2 - (cnt3 - 1), e, VRNA_OPTION_DEFAULT);
457       }
458 
459   return 1;
460 }
461 
462 
463 PRIVATE struct vrna_command_s
parse_command(const char * line,int line_number,const char * filename,unsigned int options)464 parse_command(const char    *line,
465               int           line_number,
466               const char    *filename,
467               unsigned int  options)
468 {
469   struct vrna_command_s cmd;
470   int                   i, r;
471   char                  command[3];
472 
473   command[0]  = '\0';
474   i           = NUM_COMMANDS;
475 
476   r = sscanf(line, "%2c", command);
477   if (r == 1) {
478     command[2] = '\0'; /* just a precaution */
479     for (i = 0; i < NUM_COMMANDS; i++)
480       if (!strncmp(known_commands[i].cmd, command, strlen(known_commands[i].cmd)))
481         break;
482   }
483 
484   if (i < NUM_COMMANDS) {
485     /* command is known, so lets try to process it */
486     cmd.data = (known_commands[i].parser) ? known_commands[i].parser(line) : NULL;
487     if (cmd.data) {
488       cmd.type = known_commands[i].type;
489     } else {
490       if (!(options & VRNA_CMD_PARSE_SILENT)) {
491         vrna_message_warning("Ignoring invalid command in file \"%s\":\nline %d: %s",
492                              filename,
493                              line_number,
494                              line);
495       }
496 
497       cmd.type = VRNA_CMD_ERROR;
498     }
499   } else {
500     if (!(options & VRNA_CMD_PARSE_SILENT)) {
501       vrna_message_warning("Ignoring unknown command in file \"%s\":\nline %d: %s",
502                            filename,
503                            line_number,
504                            line);
505     }
506 
507     cmd.type  = VRNA_CMD_ERROR;
508     cmd.data  = NULL;
509   }
510 
511   return cmd;
512 }
513 
514 
515 PRIVATE void *
parse_ud_command(const char * line)516 parse_ud_command(const char *line)
517 {
518   int           ret, entries_seen, max_entries, pos, pp;
519   char          *ptr, *buffer;
520   float         e;
521   unsigned int  loop_type;
522   ud_struct     *data;
523 
524   buffer            = (char *)vrna_alloc(sizeof(char) * (strlen(line) + 1));
525   data              = (ud_struct *)vrna_alloc(sizeof(ud_struct));
526   data->motif_name  = NULL;
527   data->motif       = NULL;
528   ret               = 0;  /* error indicator */
529   entries_seen      = 0;  /* entries seen so far */
530   max_entries       = 3;  /* expected number of entries */
531   pos               = 2;  /* position relative to start of line */
532   pp                = 0;
533 
534   while (!ret && (entries_seen < max_entries) && (sscanf(line + pos, "%s%n", buffer, &pp) == 1)) {
535     pos += pp;
536     switch (entries_seen) {
537       case 0:       /* motif in IUPAC format */
538         data->motif = strdup(buffer);
539         break;
540 
541       case 1:       /* motif energy in kcal/mol */
542         if (sscanf(buffer, "%g", &e) == 1)
543           data->motif_en = e;
544         else
545           ret = 1;
546 
547         break;
548 
549       case 2:       /* motif loop type */
550         loop_type = 0;
551         for (ptr = buffer; *ptr != '\0'; ptr++) {
552           switch (*ptr) {
553             case 'A':
554               loop_type |= VRNA_UNSTRUCTURED_DOMAIN_ALL_LOOPS;
555               break;
556             case 'E':
557               loop_type |= VRNA_UNSTRUCTURED_DOMAIN_EXT_LOOP;
558               break;
559             case 'H':
560               loop_type |= VRNA_UNSTRUCTURED_DOMAIN_HP_LOOP;
561               break;
562             case 'I':
563               loop_type |= VRNA_UNSTRUCTURED_DOMAIN_INT_LOOP;
564               break;
565             case 'M':
566               loop_type |= VRNA_UNSTRUCTURED_DOMAIN_MB_LOOP;
567               break;
568             default:
569               ret = 1;
570               break;
571           }
572           if (ret)
573             break;
574         }
575         data->loop_type = loop_type;
576         break;
577     }
578     entries_seen++;
579   }
580 
581   free(buffer);
582 
583   if (ret) {
584     free(data->motif_name);
585     free(data->motif);
586     free(data);
587     return NULL;
588   }
589 
590   if (data->loop_type == 0)
591     data->loop_type = VRNA_UNSTRUCTURED_DOMAIN_ALL_LOOPS;
592 
593   return (void *)data;
594 }
595 
596 
597 PRIVATE void *
parse_constraint_force(const char * line)598 parse_constraint_force(const char *line)
599 {
600   return parse_constraint(line, 'F');
601 }
602 
603 
604 PRIVATE void *
parse_constraint_prohibit(const char * line)605 parse_constraint_prohibit(const char *line)
606 {
607   return parse_constraint(line, 'P');
608 }
609 
610 
611 PRIVATE void *
parse_constraint_con(const char * line)612 parse_constraint_con(const char *line)
613 {
614   return parse_constraint(line, 'C');
615 }
616 
617 
618 PRIVATE void *
parse_constraint_allow(const char * line)619 parse_constraint_allow(const char *line)
620 {
621   return parse_constraint(line, 'A');
622 }
623 
624 
625 PRIVATE void *
parse_constraint_energy(const char * line)626 parse_constraint_energy(const char *line)
627 {
628   return parse_constraint(line, 'E');
629 }
630 
631 
632 PRIVATE void *
parse_constraint(const char * line,char command)633 parse_constraint(const char *line,
634                  char       command)
635 {
636   int               ret, i, j, k, l, h, valid;
637   unsigned char     loop;
638   char              orientation;
639   float             e;
640   constraint_struct *output;
641 
642   output = NULL;
643 
644   i           = j = k = l = -1;
645   orientation = '\0'; /* no orientation */
646   e           = 0.;
647 
648   ret = parse_constraints_line(line + 1, command, &i, &j, &k, &l, &loop, &orientation, &e);
649 
650   if (ret == 0) {
651     /* do something with the constraint we've just read */
652 
653     h = 1; /* helix length for pairs, or number of unpaired nucleotides */
654 
655     /* check indices */
656     valid = 0;
657     if (i > 0) {
658       if (j == -1) {
659         /* i and range [k:l] */
660         if ((k > 0) && (l > 0)) {
661           if ((k < l) && (i < k) && (orientation == '\0')) {
662             j     = i;
663             valid = 1;
664           }
665         }
666       } else if (k <= 0) {
667         /* range [i:j] and l */
668         if ((i < j) && (j < l) && (orientation == '\0')) {
669           k     = l;
670           valid = 1;
671         }
672       } else if (l <= 0) {
673         /* helix of size k starting with pair (i,j), or segment [i:i+k-1] */
674         if (i != j) {
675           if ((j == 0) || (((j - i + 1) > 2 * k) && (orientation == '\0'))) {
676             h     = k;
677             k     = l = j;
678             j     = i;
679             valid = 1;
680           }
681         }
682       } else if ((i < j) && (k < l) && (i <= k) && (j <= l) && (orientation == '\0')) {
683         /* range [i:j] and [k:l] */
684         if (command == 'P') {
685           /* we only allow this for 'prohibit pairing between two ranges' */
686           h     = 0;
687           valid = 1;
688         }
689       }
690     }
691 
692     if (valid) {
693       /* nucleotide constraint? */
694       if ((k == 0) && (l == 0) && (i == j) && (h > 0)) {
695         /* set correct loop type context */
696         switch (command) {
697           case 'P':
698             break;
699           case 'A':                                     /* this case allows particular nucleotides to form non-canonical pairs */
700             loop |= VRNA_CONSTRAINT_CONTEXT_NO_REMOVE;  /* do not remove possibility to stay unpaired */
701           /* fall through */
702           case 'F':                                     /* set i == j == k == l */
703             k = l = i;
704             break;
705           case 'E':
706             loop = VRNA_CONSTRAINT_CONTEXT_ALL_LOOPS;         /* soft constraints are always applied for all loops */
707             break;
708           case 'C':
709             loop |= VRNA_CONSTRAINT_CONTEXT_ENFORCE;          /* enforce context dependency */
710             break;
711           default:
712             break;
713         }
714       } else {
715         /* base pair constraint */
716         /* set correct loop type context */
717         switch (command) {
718           case 'P':
719             loop  = ~loop;                              /* prohibit */
720             loop  &= VRNA_CONSTRAINT_CONTEXT_ALL_LOOPS;
721             loop  |= VRNA_CONSTRAINT_CONTEXT_NO_REMOVE; /* since we prohibit pairs, we do not want to remove incompatible pairs */
722             break;
723           case 'F':
724             loop |= VRNA_CONSTRAINT_CONTEXT_ENFORCE;          /* enforce */
725             break;
726           case 'E':
727             loop = VRNA_CONSTRAINT_CONTEXT_ALL_LOOPS;          /* soft constraints are always applied for all loops */
728             break;
729           case 'C':
730             break;                                      /* remove conflicting pairs only */
731           case 'A':
732             loop |= VRNA_CONSTRAINT_CONTEXT_NO_REMOVE;  /* since we allow pairs, we do not want to remove incompatible pairs */
733             break;
734           default:
735             break;
736         }
737       }
738 
739       output              = (constraint_struct *)vrna_alloc(sizeof(constraint_struct));
740       output->command     = command;
741       output->i           = i;
742       output->j           = j;
743       output->k           = k;
744       output->l           = l;
745       output->size        = h;
746       output->loop        = loop;
747       output->orientation = orientation;
748       output->e           = e;
749     }
750   }
751 
752   return (void *)output;
753 }
754 
755 
756 PRIVATE int
parse_constraints_line(const char * line,char command,int * i,int * j,int * k,int * l,unsigned char * loop,char * orientation,float * e)757 parse_constraints_line(const char     *line,
758                        char           command,
759                        int            *i,
760                        int            *j,
761                        int            *k,
762                        int            *l,
763                        unsigned char  *loop,
764                        char           *orientation,
765                        float          *e)
766 {
767   int           v1, v2;
768   int           ret           = 0;
769   int           range_mode    = 0;
770   int           pos           = 0;
771   int           max_entries   = 5;
772   int           entries_seen  = 0;
773   int           pp;
774   float         energy;
775   char          buf[256], buf2[10], *c;
776   unsigned char tmp_loop;
777 
778   switch (command) {
779     case 'A':   /* fall through */
780     case 'F':   /* fall through */
781     case 'P':
782       max_entries = 5;
783       break;
784     case 'C':   /* fall through */
785     case 'E':
786       max_entries = 4;
787       break;
788     default:
789       ret = 1;            /* error */
790       break;
791   }
792 
793   /* default to all loop types */
794   *loop     = VRNA_CONSTRAINT_CONTEXT_ALL_LOOPS;
795   tmp_loop  = VRNA_CONSTRAINT_CONTEXT_NONE;
796 
797   /* now lets scan the entire line for content */
798   while (!ret && (entries_seen < max_entries) &&
799          (sscanf(line + pos, "%15s%n", &buf[0], &pp) == 1)) {
800     pos += pp;
801     switch (entries_seen) {
802       case 0: /* must be i, or range */
803         if (sscanf(buf, "%d-%d%n", &v1, &v2, &pp) == 2) {
804           if (pp == strlen(buf)) {
805             *i          = v1;
806             *j          = v2;
807             range_mode  = 1;
808             --max_entries;       /* no orientation allowed now */
809             break;
810           }
811         } else if (sscanf(buf, "%d%n", &v1, &pp) == 1) {
812           if (pp == strlen(buf)) {
813             *i = v1;
814             break;
815           }
816         }
817 
818         ret = 1;
819         break;
820       case 1: /* must be j, or range */
821         if (sscanf(buf, "%d-%d%n", &v1, &v2, &pp) == 2) {
822           if (pp == strlen(buf)) {
823             *k  = v1;
824             *l  = v2;
825             if (!range_mode)
826               --max_entries;       /* no orientation allowed now */
827 
828             range_mode = 1;
829             break;
830           }
831         } else if (range_mode) {
832           if (sscanf(buf, "%d%n", &v1, &pp) == 1) {
833             if (pp == strlen(buf)) {
834               *l = v1;
835               break;
836             }
837           }
838         } else if (sscanf(buf, "%d%n", &v1, &pp) == 1) {
839           if (pp == strlen(buf)) {
840             *j = v1;
841             break;
842           }
843         }
844 
845         ret = 1;
846         break;
847       case 2: /* skip if in range_mode */
848         if (!range_mode) {
849           /* must be k */
850           if (sscanf(buf, "%d%n", &v1, &pp) == 1) {
851             if (pp == strlen(buf)) {
852               *k = v1;
853               break;
854             }
855           }
856 
857           ret = 1;
858           break;
859         } else {
860           --max_entries;
861           /* fall through */
862         }
863 
864       case 3:
865         if (command == 'E') {
866           /* must be pseudo energy */
867           if (sscanf(buf, "%g%n", &energy, &pp) == 1) {
868             if (pp == strlen(buf)) {
869               *e = energy;
870               break;
871             }
872           }
873         } else {
874           /*  must be loop type, or orientation */
875           if (sscanf(buf, "%8s%n", &buf2[0], &pp) == 1) {
876             buf2[8] = '\0';
877             if (pp == strlen(buf)) {
878               for (c = &(buf2[0]); (*c != '\0') && (!ret); c++) {
879                 switch (*c) {
880                   case 'E':
881                     tmp_loop |= VRNA_CONSTRAINT_CONTEXT_EXT_LOOP;
882                     break;
883                   case 'H':
884                     tmp_loop |= VRNA_CONSTRAINT_CONTEXT_HP_LOOP;
885                     break;
886                   case 'I':
887                     tmp_loop |= VRNA_CONSTRAINT_CONTEXT_INT_LOOP;
888                     break;
889                   case 'i':
890                     tmp_loop |= VRNA_CONSTRAINT_CONTEXT_INT_LOOP_ENC;
891                     break;
892                   case 'M':
893                     tmp_loop |= VRNA_CONSTRAINT_CONTEXT_MB_LOOP;
894                     break;
895                   case 'm':
896                     tmp_loop |= VRNA_CONSTRAINT_CONTEXT_MB_LOOP_ENC;
897                     break;
898                   case 'A':
899                     tmp_loop |= VRNA_CONSTRAINT_CONTEXT_ALL_LOOPS;
900                     break;
901                   case 'U':
902                   case 'D':
903                     *orientation = *c;
904                     break;
905                   default:
906                     ret = 1;
907                 }
908               }
909               if (tmp_loop)
910                 *loop = tmp_loop;
911 
912               break;
913             }
914           }
915         }
916 
917         ret = 1;
918         break;
919       case 4: /* must be orientation */
920         if (!(sscanf(buf, "%c", orientation) == 1))
921           ret = 1;
922 
923         break;
924     }
925     ++entries_seen;
926   }
927 
928   return ret;
929 }
930