Merge branch 'master' into sru_2_0
[yaz-moved-to-github.git] / src / odr_choice.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2013 Index Data
3  * See the file LICENSE for details.
4  */
5
6 /**
7  * \file odr_choice.c
8  * \brief Implements ODR CHOICE codec
9  */
10
11 #if HAVE_CONFIG_H
12 #include <config.h>
13 #endif
14
15 #include "odr-priv.h"
16
17 int odr_choice(ODR o, Odr_arm arm[], void *p, void *whichp,
18                const char *name)
19 {
20     int i, cl = -1, tg, cn, *which = (int *)whichp, bias = o->op->choice_bias;
21
22     if (o->error)
23         return 0;
24     if (o->direction != ODR_DECODE && !*(char**)p)
25         return 0;
26
27     if (o->direction == ODR_DECODE)
28     {
29         *which = -1;
30         *(char**)p = 0;
31     }
32     o->op->choice_bias = -1;
33
34     if (o->direction == ODR_PRINT)
35     {
36         if (name)
37         {
38             odr_prname(o, name);
39             odr_printf(o, "choice\n");
40         }
41     }
42     for (i = 0; arm[i].fun; i++)
43     {
44         if (o->direction == ODR_DECODE)
45         {
46             if (bias >= 0 && bias != arm[i].which)
47                 continue;
48             *which = arm[i].which;
49         }
50         else if (*which != arm[i].which)
51             continue;
52
53         if (arm[i].tagmode != ODR_NONE)
54         {
55             if (o->direction == ODR_DECODE && cl < 0)
56             {
57                 if (o->op->stack_top && !odr_constructed_more(o))
58                     return 0;
59                 if (ber_dectag(o->op->bp, &cl, &tg, &cn, odr_max(o)) <= 0)
60                     return 0;
61             }
62             else if (o->direction != ODR_DECODE)
63             {
64                 cl = arm[i].zclass;
65                 tg = arm[i].tag;
66             }
67             if (tg == arm[i].tag && cl == arm[i].zclass)
68             {
69                 if (arm[i].tagmode == ODR_IMPLICIT)
70                 {
71                     odr_implicit_settag(o, cl, tg);
72                     return (*arm[i].fun)(o, (char **)p, 0, arm[i].name);
73                 }
74                 /* explicit */
75                 if (!odr_constructed_begin(o, p, cl, tg, 0))
76                     return 0;
77                 return (*arm[i].fun)(o, (char **)p, 0, arm[i].name) &&
78                     odr_constructed_end(o);
79             }
80         }
81         else  /* no tagging. Have to poll type */
82         {
83             if ((*arm[i].fun)(o, (char **)p, 1, arm[i].name) && *(char**)p)
84                 return 1;
85         }
86     }
87     return 0;
88 }
89
90 void odr_choice_bias(ODR o, int what)
91 {
92     if (o->op->enable_bias)
93         o->op->choice_bias = what;
94 }
95
96 void odr_choice_enable_bias (ODR o, int mode)
97 {
98     o->op->enable_bias = mode;
99 }
100 /*
101  * Local variables:
102  * c-basic-offset: 4
103  * c-file-style: "Stroustrup"
104  * indent-tabs-mode: nil
105  * End:
106  * vim: shiftwidth=4 tabstop=8 expandtab
107  */
108