aboutsummaryrefslogtreecommitdiffstats
path: root/libasn1parser/asn1p_ref.c
diff options
context:
space:
mode:
Diffstat (limited to 'libasn1parser/asn1p_ref.c')
-rw-r--r--libasn1parser/asn1p_ref.c137
1 files changed, 137 insertions, 0 deletions
diff --git a/libasn1parser/asn1p_ref.c b/libasn1parser/asn1p_ref.c
new file mode 100644
index 00000000..4ac2b32d
--- /dev/null
+++ b/libasn1parser/asn1p_ref.c
@@ -0,0 +1,137 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "asn1parser.h"
+
+/*
+ * Construct a new empty reference.
+ */
+asn1p_ref_t *
+asn1p_ref_new(int _lineno) {
+ asn1p_ref_t *ref;
+
+ ref = calloc(1, sizeof *ref);
+ if(ref) {
+ ref->_lineno = _lineno;
+ }
+
+ return ref;
+}
+
+void
+asn1p_ref_free(asn1p_ref_t *ref) {
+ if(ref) {
+ if(ref->components) {
+ int i = ref->comp_count;
+ while(i--) {
+ if(ref->components[i].name)
+ free(ref->components[i].name);
+ ref->components[i].name = 0;
+ }
+ free(ref->components);
+ ref->components = 0;
+ }
+
+ free(ref);
+ }
+}
+
+static enum asn1p_ref_lex_type_e
+asn1p_ref_name2lextype(char *name) {
+ enum asn1p_ref_lex_type_e lex_type;
+ int has_lowercase = 0;
+
+ if(*name == '&') {
+ if(name[1] >= 'A' && name[1] <= 'Z') {
+ lex_type = RLT_AmpUppercase;
+ } else {
+ lex_type = RLT_Amplowercase;
+ }
+ } else if(*name >= 'A' && *name <= 'Z') {
+ char *p;
+
+ for(p = name; *p; p++) {
+ if(*p >= 'a' && *p <= 'z') {
+ has_lowercase = 1;
+ break;
+ }
+ }
+
+ if(has_lowercase) {
+ lex_type = RLT_Uppercase;
+ } else {
+ lex_type = RLT_CAPITALS;
+ }
+ } else if(*name == '@') {
+ if(name[1] == '.')
+ lex_type = RLT_AtDotlowercase;
+ else
+ lex_type = RLT_Atlowercase;
+ } else {
+ lex_type = RLT_lowercase;
+ }
+
+ return lex_type;
+}
+
+int
+asn1p_ref_add_component(asn1p_ref_t *ref, char *name, enum asn1p_ref_lex_type_e lex_type) {
+
+ if(!ref || !name || lex_type < RLT_UNKNOWN || lex_type >= RLT_MAX) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if(ref->comp_count == ref->comp_size) {
+ int newsize = ref->comp_size?(ref->comp_size<<2):4;
+ void *p = realloc(ref->components,
+ newsize * sizeof(ref->components[0]));
+ if(p) {
+ ref->components = p;
+ ref->comp_size = newsize;
+ } else {
+ return -1;
+ }
+
+ }
+
+ if(lex_type == RLT_UNKNOWN) {
+ lex_type = asn1p_ref_name2lextype(name);
+ } else {
+ assert(lex_type == asn1p_ref_name2lextype(name));
+ }
+
+ ref->components[ref->comp_count].name = strdup(name);
+ ref->components[ref->comp_count].lex_type = lex_type;
+ if(ref->components[ref->comp_count].name) {
+ ref->comp_count++;
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+asn1p_ref_t *
+asn1p_ref_clone(asn1p_ref_t *ref) {
+ asn1p_ref_t *newref;
+
+ newref = asn1p_ref_new(ref->_lineno);
+ if(newref) {
+ int i;
+ for(i = 0; i < ref->comp_count; i++) {
+ if(asn1p_ref_add_component(newref,
+ ref->components[i].name,
+ ref->components[i].lex_type
+ )) {
+ asn1p_ref_free(newref);
+ newref = NULL;
+ break;
+ }
+ }
+ }
+
+ return newref;
+}