diff options
Diffstat (limited to 'src/aliases.c')
-rw-r--r-- | src/aliases.c | 364 |
1 files changed, 364 insertions, 0 deletions
diff --git a/src/aliases.c b/src/aliases.c new file mode 100644 index 0000000..1292685 --- /dev/null +++ b/src/aliases.c @@ -0,0 +1,364 @@ +#include <ctype.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "internal.h" + +struct alias { + struct alias *next; + struct canon *canon; + unsigned short name_len; + char name[1]; +}; + +#define HASH_SIZE (43) +static struct canon *canon_tab[HASH_SIZE]; +static struct alias *alias_tab[HASH_SIZE]; + +static bool create_alias(const char *alias, struct canon *c); +static struct canon *create_canon(const char *canon, short mibenum); +static int hash_val(const char *alias); + +#ifdef TEST +static void dump_alias_data(void); + +int main (void) +{ + struct canon *c; + + create_alias_data("Unicode:Files.Aliases"); + + dump_alias_data(); + + c = alias_canonicalise("moose"); + if (c) + printf("!!!\n"); + + c = alias_canonicalise("csinvariant"); + if (c) + printf("%s %d\n", c->name, c->mib_enum); + + c = alias_canonicalise("nats-sefi-add"); + if (c) + printf("%s %d\n", c->name, c->mib_enum); + + printf("%d\n", mibenum_from_name(c->name)); + + printf("%s\n", mibenum_to_name(c->mib_enum)); + + free_alias_data(); + + return 0; +} +#endif + +/** + * Create an alias + * + * \param alias The alias name + * \param c The canonical form + * \return true on success, false otherwise + */ +bool create_alias(const char *alias, struct canon *c) +{ + struct alias *a; + int hash; + + if (!alias || !c) + return false; + + a = malloc(sizeof(struct alias) + strlen(alias) + 1); + if (!a) + return false; + + a->canon = c; + a->name_len = strlen(alias); + strcpy(a->name, alias); + a->name[a->name_len] = '\0'; + + hash = hash_val(alias); + + a->next = alias_tab[hash]; + alias_tab[hash] = a; + + return true; +} + +/** + * Create a canonical form + * + * \param canon The canonical name + * \param mibenum The MIB enum value + * \return Pointer to struct canon or NULL on error + */ +struct canon *create_canon(const char *canon, short mibenum) +{ + struct canon *c; + int hash, len; + + if (!canon) + return NULL; + + len = strlen(canon); + + c = malloc(sizeof(struct canon) + len + 1); + if (!c) + return NULL; + + c->mib_enum = mibenum; + c->name_len = len; + strcpy(c->name, canon); + c->name[len] = '\0'; + + hash = hash_val(canon); + + c->next = canon_tab[hash]; + canon_tab[hash] = c; + + return c; +} + +/** + * Hash function + * + * \param alias String to hash + * \return The hashed value + */ +int hash_val(const char *alias) +{ + const char *s = alias; + unsigned int h = 5381; + + if (!alias) + return 0; + + while (*s) + h = (h * 33) ^ (*s++ & ~0x20); /* case insensitive */ + + return h % HASH_SIZE; +} + +/** + * Free all alias data + */ +void free_alias_data(void) +{ + struct canon *c, *d; + struct alias *a, *b; + int i; + + for (i = 0; i != HASH_SIZE; i++) { + for (c = canon_tab[i]; c; c = d) { + d = c->next; + free(c); + } + canon_tab[i] = NULL; + + for (a = alias_tab[i]; a; a = b) { + b = a->next; + free(a); + } + alias_tab[i] = NULL; + } +} + +#ifdef TEST +/** + * Dump all alias data to stdout + */ +void dump_alias_data(void) +{ + struct canon *c; + struct alias *a; + int i; + size_t size = 0; + + for (i = 0; i != HASH_SIZE; i++) { + for (c = canon_tab[i]; c; c = c->next) { + printf("%d %s\n", i, c->name); + size += offsetof(struct canon, name) + c->name_len; + } + + for (a = alias_tab[i]; a; a = a->next) { + printf("%d %s\n", i, a->name); + size += offsetof(struct alias, name) + a->name_len; + } + } + + size += (sizeof(canon_tab) / sizeof(canon_tab[0])); + size += (sizeof(alias_tab) / sizeof(alias_tab[0])); + + printf("%d\n", size); +} +#endif + +/** + * Create alias data from Aliases file + * + * \param filename The path to the Aliases file + * \return 1 on success, 0 on failure. + */ +int create_alias_data(const char *filename) +{ + char buf[300]; + FILE *fp; + + if (!filename) + return 0; + + fp = fopen(filename, "r"); + if (!fp) + return 0; + + while (fgets(buf, sizeof buf, fp)) { + char *p, *aliases = 0, *mib, *end; + struct canon *cf; + + if (buf[0] == 0 || buf[0] == '#') + /* skip blank lines or comments */ + continue; + + buf[strlen(buf) - 1] = 0; /* lose terminating newline */ + end = buf + strlen(buf); + + /* find end of canonical form */ + for (p = buf; *p && !isspace(*p) && !iscntrl(*p); p++) + ; /* do nothing */ + if (p >= end) + continue; + *p++ = '\0'; /* terminate canonical form */ + + /* skip whitespace */ + for (; *p && isspace(*p); p++) + ; /* do nothing */ + if (p >= end) + continue; + mib = p; + + /* find end of mibenum */ + for (; *p && !isspace(*p) && !iscntrl(*p); p++) + ; /* do nothing */ + if (p < end) + *p++ = '\0'; /* terminate mibenum */ + + cf = create_canon(buf, atoi(mib)); + if (!cf) + continue; + + /* skip whitespace */ + for (; p < end && *p && isspace(*p); p++) + ; /* do nothing */ + if (p >= end) + continue; + aliases = p; + + while (p < end) { + /* find end of alias */ + for (; *p && !isspace(*p) && !iscntrl(*p); p++) + ; /* do nothing */ + if (p > end) + /* stop if we've gone past the end */ + break; + /* terminate current alias */ + *p++ = '\0'; + + if (!create_alias(aliases, cf)) + break; + + /* in terminating, we may have advanced + * past the end - check this here */ + if (p >= end) + break; + + /* skip whitespace */ + for (; *p && isspace(*p); p++) + ; /* do nothing */ + + if (p >= end) + /* gone past end => stop */ + break; + + /* update pointer to current alias */ + aliases = p; + } + } + + fclose(fp); + + return 1; +} + +/** + * Retrieve the canonical form of an alias name + * + * \param alias The alias name + * \return Pointer to struct canon or NULL if not found + */ +struct canon *alias_canonicalise(const char *alias) +{ + int hash, len; + struct canon *c; + struct alias *a; + + if (!alias) + return NULL; + + hash = hash_val(alias); + len = strlen(alias); + + for (c = canon_tab[hash]; c; c = c->next) + if (c->name_len == len && strcasecmp(c->name, alias) == 0) + break; + if (c) + return c; + + for (a = alias_tab[hash]; a; a = a->next) + if (a->name_len == len && strcasecmp(a->name, alias) == 0) + break; + if (a) + return a->canon; + + return NULL; +} + +/** + * Retrieve the MIB enum value assigned to an encoding name + * + * \param alias The alias to lookup + * \return The MIB enum value, or 0 if not found + */ +short mibenum_from_name(const char *alias) +{ + struct canon *c; + + if (!alias) + return 0; + + c = alias_canonicalise(alias); + if (!c) + return 0; + + return c->mib_enum; +} + +/** + * Retrieve the canonical name of an encoding from the MIB enum + * + * \param mibenum The MIB enum value + * \return Pointer to canonical name, or NULL if not found + */ +const char *mibenum_to_name(short mibenum) +{ + int i; + struct canon *c; + + for (i = 0; i != HASH_SIZE; i++) + for (c = canon_tab[i]; c; c = c->next) + if (c->mib_enum == mibenum) + return c->name; + + return NULL; +} |