aboutsummaryrefslogtreecommitdiffstats
path: root/libasn1compiler/asn1c_misc.c
diff options
context:
space:
mode:
Diffstat (limited to 'libasn1compiler/asn1c_misc.c')
-rw-r--r--libasn1compiler/asn1c_misc.c232
1 files changed, 232 insertions, 0 deletions
diff --git a/libasn1compiler/asn1c_misc.c b/libasn1compiler/asn1c_misc.c
new file mode 100644
index 00000000..b464b64c
--- /dev/null
+++ b/libasn1compiler/asn1c_misc.c
@@ -0,0 +1,232 @@
+#include "asn1c_internal.h"
+#include <asn1fix_export.h>
+
+#ifndef DEFFILEMODE /* Normally in <sys/stat.h> */
+#define DEFFILEMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
+#endif
+
+/*
+ * Construct identifier from multiple parts.
+ * Convert unsafe characters to underscores.
+ */
+char *
+asn1c_make_identifier(int unsafe_only_spaces, char *arg1, ...) {
+ static char *storage;
+ static int storage_size;
+ int nodelimiter = 0;
+ va_list ap;
+ char *str;
+ int size;
+ char *p;
+
+ if(arg1 == NULL)
+ return NULL;
+
+ /*
+ * Estimate the necessary storage size
+ */
+ size = strlen(arg1);
+ va_start(ap, arg1);
+ while((str = va_arg(ap, char *)))
+ size += 1 + strlen(str);
+ va_end(ap);
+
+ /*
+ * Make sure we have this amount of storage.
+ */
+ if(storage_size <= size) {
+ if(storage) free(storage);
+ storage = malloc(size + 1);
+ if(storage) {
+ storage_size = size;
+ } else {
+ storage_size = 0;
+ return NULL;
+ }
+ }
+
+ /*
+ * Fill-in the storage.
+ */
+ va_start(ap, arg1);
+ str = arg1;
+ p = storage;
+ for(str = arg1; str; str = va_arg(ap, char *)) {
+ int subst_made = 0;
+
+ if(str[0] == ' ' && str[1] == '\0') {
+ *p++ = ' ';
+ nodelimiter = 1; /* No delimiter */
+ continue;
+ }
+
+ if(str != arg1 && !nodelimiter)
+ *p++ = '_'; /* Delimiter between tokens */
+ nodelimiter = 0;
+
+ for(; *str; str++) {
+ if(isalnum(*str)) {
+ *p++ = *str;
+ subst_made = 0;
+ } else if(!subst_made++) {
+ if(unsafe_only_spaces && !isspace(*str)) {
+ *p ++ = *str;
+ } else {
+ *p++ = '_';
+ }
+ }
+ }
+ }
+ va_end(ap);
+ *p = '\0';
+
+ assert((p - storage) <= storage_size);
+
+ return storage;
+}
+
+FILE *
+asn1c_open_file(arg_t *arg, const char *name, const char *ext) {
+ int created = 1;
+ struct stat sb;
+ char *fname;
+ int len;
+ FILE *fp;
+ int fd;
+
+ /*
+ * Compute filenames.
+ */
+ len = strlen(name) + strlen(ext) + 1;
+ fname = alloca(len);
+ snprintf(fname, len, "%s%s", name, ext);
+
+ /*
+ * Create files.
+ */
+ fd = open(fname, O_CREAT | O_EXCL | O_WRONLY, DEFFILEMODE);
+ if(fd == -1 && errno == EEXIST) {
+ fd = open(fname, O_WRONLY, DEFFILEMODE);
+ created = 0;
+ }
+ if(fd == -1) {
+ perror(fname);
+ return NULL;
+ }
+
+ /*
+ * Check sanity.
+ */
+ if(fstat(fd, &sb) || !S_ISREG(sb.st_mode)) {
+ fprintf(stderr, "%s: Not a regular file\n", fname);
+ if(created) unlink(fname);
+ close(fd);
+ return NULL;
+ }
+
+ (void)ftruncate(fd, 0);
+
+ /*
+ * Convert file descriptor into file pointer.
+ */
+ fp = fdopen(fd, "w");
+ if(fp == NULL) {
+ if(created) unlink(fname);
+ close(fd);
+ }
+ return fp;
+}
+
+char *
+asn1c_type_name(arg_t *arg, asn1p_expr_t *expr, enum tnfmt _format) {
+ char *typename;
+
+ switch(expr->expr_type) {
+ case A1TC_REFERENCE:
+ typename = expr->reference->components[
+ expr->reference->comp_count-1].name;
+ if(typename[0] == '&') {
+ arg_t tmp = *arg;
+
+ /*
+ * This is a reference to a type defined in a class.
+ * Resolve it and use instead.
+ */
+ tmp.expr = asn1f_class_access_ex(arg->asn, arg->mod,
+ arg->expr, expr->reference, &tmp.mod);
+ if(tmp.expr) return NULL;
+
+ return asn1c_type_name(&tmp, tmp.expr, _format);
+ } else if(_format == TNF_RSAFE) {
+ /*
+ * The recursion-safe format is requested.
+ * The problem here is that only constructed types
+ * might be referenced with "struct".
+ * Change RSAFE to CTYPE if the terminal type
+ * is primitive.
+ */
+ asn1p_expr_t *terminal;
+ terminal = asn1f_find_terminal_type_ex(
+ arg->asn, arg->mod, arg->expr, NULL);
+ if(terminal
+ && (terminal->expr_type
+ & (ASN_BASIC_MASK | ASN_STRING_MASK)))
+ _format = TNF_CTYPE;
+ }
+ break;
+ case ASN_CONSTR_SEQUENCE_OF:
+ case ASN_CONSTR_SET_OF:
+ if(expr->Identifier) {
+ typename = expr->Identifier;
+ } else {
+ asn1p_expr_t *child;
+ child = TQ_FIRST(&(expr->members));
+ typename = asn1c_type_name(arg, child, _format);
+ if(typename)
+ return typename;
+ _format = TNF_SAFE;
+ typename = child->Identifier;
+ }
+ break;
+ case ASN_BASIC_INTEGER:
+ case ASN_BASIC_ENUMERATED:
+ if((arg->flags & A1C_USE_NATIVE_INTEGERS)) {
+ switch(_format) {
+ case TNF_CTYPE:
+ case TNF_RSAFE:
+ return "int";
+ default:
+ if(expr->expr_type == ASN_BASIC_INTEGER)
+ return "NativeInteger";
+ else
+ return "NativeEnumerated";
+ }
+ }
+ /* Fall through */
+ default:
+ if(expr->expr_type & (ASN_BASIC_MASK | ASN_STRING_MASK)) {
+ if(_format == TNF_RSAFE)
+ _format = TNF_CTYPE;
+ typename = ASN_EXPR_TYPE2STR(expr->expr_type);
+ } else {
+ _format = TNF_SAFE;
+ typename = expr->Identifier;
+ }
+ }
+
+ switch(_format) {
+ case TNF_UNMODIFIED:
+ case TNF_INCLUDE:
+ return asn1c_make_identifier(1, typename, 0);
+ case TNF_SAFE:
+ return asn1c_make_identifier(0, typename, 0);
+ case TNF_CTYPE:
+ return asn1c_make_identifier(0, typename, "t", 0);
+ case TNF_RSAFE:
+ return asn1c_make_identifier(0, "struct", " ", typename, 0);
+ }
+
+ assert("!unreachable");
+ return typename;
+}
+