blob: a5ee99816fca0ed5bc7813301e82982a928b4835 [file] [log] [blame]
Lev Walkind9221842017-08-22 01:44:56 -07001#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 */
12asn1p_ref_t *
13asn1p_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
23void
24asn1p_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
40void
41asn1p_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
49static enum asn1p_ref_lex_type_e
50asn1p_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
87int
88asn1p_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
125asn1p_ref_t *
126asn1p_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
146int
147asn1p_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
163const char *
164asn1p_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