a5ee99816fca0ed5bc7813301e82982a928b4835
[com/asn1c.git] / libasn1common / asn1_ref.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <errno.h>
5 #include <assert.h>
6
7 #include "asn1_ref.h"
8
9 /*
10  * Construct a new empty reference.
11  */
12 asn1p_ref_t *
13 asn1p_ref_new(int _lineno, struct asn1p_module_s *mod) {
14         asn1p_ref_t *ref;
15
16     ref = calloc(1, sizeof *ref);
17     assert(ref);
18     asn1p_ref_set_source(ref, mod, _lineno);
19
20     return ref;
21 }
22
23 void
24 asn1p_ref_free(asn1p_ref_t *ref) {
25         if(ref) {
26                 if(ref->components) {
27                         size_t i = ref->comp_count;
28                         while(i--) {
29                                 free(ref->components[i].name);
30                                 ref->components[i].name = 0;
31                         }
32                         free(ref->components);
33                         ref->components = 0;
34                 }
35
36                 free(ref);
37         }
38 }
39
40 void
41 asn1p_ref_set_source(asn1p_ref_t *ref, struct asn1p_module_s *module,
42                      int lineno) {
43     if(ref) {
44         ref->module = module;
45         ref->_lineno = lineno;
46     }
47 }
48
49 static enum asn1p_ref_lex_type_e
50 asn1p_ref_name2lextype(const char *name) {
51         enum asn1p_ref_lex_type_e lex_type;
52         int has_lowercase = 0;
53
54         if(*name == '&') {
55                 if(name[1] >= 'A' && name[1] <= 'Z') {
56                         lex_type = RLT_AmpUppercase;
57                 } else {
58                         lex_type = RLT_Amplowercase;
59                 }
60         } else if(*name >= 'A' && *name <= 'Z') {
61                 const char *p;
62
63                 for(p = name; *p; p++) {
64                         if(*p >= 'a' && *p <= 'z') {
65                                 has_lowercase = 1;
66                                 break;
67                         }
68                 }
69
70                 if(has_lowercase) {
71                         lex_type = RLT_Uppercase;
72                 } else {
73                         lex_type = RLT_CAPITALS;
74                 }
75         } else if(*name == '@') {
76                 if(name[1] == '.')
77                         lex_type = RLT_AtDotlowercase;
78                 else
79                         lex_type = RLT_Atlowercase;
80         } else {
81                 lex_type = RLT_lowercase;
82         }
83
84         return lex_type;
85 }
86
87 int
88 asn1p_ref_add_component(asn1p_ref_t *ref, const char *name, enum asn1p_ref_lex_type_e lex_type) {
89
90         if(!ref || !name
91         || (int)lex_type < RLT_UNKNOWN || lex_type >= RLT_MAX) {
92                 errno = EINVAL;
93                 return -1;
94         }
95
96         if(ref->comp_count == ref->comp_size) {
97                 int newsize = ref->comp_size?(ref->comp_size<<2):4;
98                 void *p = realloc(ref->components,
99                         newsize * sizeof(ref->components[0]));
100                 if(p) {
101                         ref->components = p;
102                         ref->comp_size = newsize;
103                 } else {
104                         return -1;
105                 }
106
107         }
108
109         if(lex_type == RLT_UNKNOWN) {
110                 lex_type = asn1p_ref_name2lextype(name);
111         } else {
112                 assert(lex_type == asn1p_ref_name2lextype(name));
113         }
114
115         ref->components[ref->comp_count].name = strdup(name);
116         ref->components[ref->comp_count].lex_type = lex_type;
117         if(ref->components[ref->comp_count].name) {
118                 ref->comp_count++;
119                 return 0;
120         } else {
121                 return -1;
122         }
123 }
124
125 asn1p_ref_t *
126 asn1p_ref_clone(asn1p_ref_t *ref) {
127         asn1p_ref_t *newref;
128
129         newref = asn1p_ref_new(ref->_lineno, ref->module);
130         if(newref) {
131                 for(size_t i = 0; i < ref->comp_count; i++) {
132                         if(asn1p_ref_add_component(newref,
133                                 ref->components[i].name,
134                                 ref->components[i].lex_type
135                         )) {
136                                 asn1p_ref_free(newref);
137                                 newref = NULL;
138                                 break;
139                         }
140                 }
141         }
142
143         return newref;
144 }
145
146 int
147 asn1p_ref_compare(const asn1p_ref_t *a, const asn1p_ref_t *b) {
148     if(a->comp_count != b->comp_count)
149         return -1;
150     if(a->module != b->module)
151         return -1;
152
153     for(size_t i = 0; i < a->comp_count; i++) {
154         if(a->components[i].lex_type != b->components[i].lex_type
155            || strcmp(a->components[i].name, b->components[i].name) != 0) {
156             return -1;
157         }
158     }
159
160     return 0;
161 }
162
163 const char *
164 asn1p_ref_string(const asn1p_ref_t *ref) {
165     static char static_buf[32];
166     static char *buf = static_buf;
167     static size_t buf_size = sizeof(static_buf);
168     char *p = buf;
169
170     if(!ref) return "<no-ref>";
171
172     for(size_t i = 0; i < ref->comp_count; i++) {
173         size_t space = buf_size - (p - buf);
174         int ret =
175             snprintf(p, space, "%s%s", i ? "." : "", ref->components[i].name);
176         if(ret < 0 || (size_t)ret >= space) {
177             i--;
178             char *tmp = malloc(buf_size * 2 + 1);
179             assert(tmp);
180             size_t p_offset = p - buf;
181             memcpy(tmp, buf, (p - buf));
182             if(buf != static_buf) free(buf);
183             buf_size *= 2;
184             buf = tmp;
185             p = tmp + p_offset;
186         } else {
187             p += ret;
188         }
189     }
190
191     *p = '\0';
192     return buf;
193 }
194