diff options
author | Theodore Tso <tytso@mit.edu> | 1995-04-20 14:57:45 +0000 |
---|---|---|
committer | Theodore Tso <tytso@mit.edu> | 1995-04-20 14:57:45 +0000 |
commit | 3c2db26c6dbb4d19d137e07e6aec6306724cbb82 (patch) | |
tree | 1edc420f98d4bb06ecdd9437577086e5a74d68dc /src/util/profile/prof_tree.c | |
parent | 6441ad46e842e50e618843af0652fd5d6f24b565 (diff) | |
download | krb5-3c2db26c6dbb4d19d137e07e6aec6306724cbb82.tar.gz krb5-3c2db26c6dbb4d19d137e07e6aec6306724cbb82.tar.xz krb5-3c2db26c6dbb4d19d137e07e6aec6306724cbb82.zip |
Initial checkin of the profile library
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@5382 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/util/profile/prof_tree.c')
-rw-r--r-- | src/util/profile/prof_tree.c | 334 |
1 files changed, 334 insertions, 0 deletions
diff --git a/src/util/profile/prof_tree.c b/src/util/profile/prof_tree.c new file mode 100644 index 0000000000..1dc701373f --- /dev/null +++ b/src/util/profile/prof_tree.c @@ -0,0 +1,334 @@ +/* + * prof_tree.c --- these routines maintain the parse tree of the + * config file. + * + * All of the details of how the tree is stored is abstracted away in + * this file; all of the other profile routines build, access, and + * modify the tree via the accessor functions found in this file. + * + * Each node may represent either a relation or a section header. + * + * A section header must have its value field set to 0, and may a one + * or more child nodes, pointed to by first_child. + * + * A relation has as its value a pointer to allocated memory + * containing a string. Its first_child pointer must be null. + * + */ + + +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <errno.h> +#include <ctype.h> + +#include "prof_int.h" + +struct profile_node { + errcode_t magic; + char *name; + char *value; + int group_level; + struct profile_node *first_child; + struct profile_node *parent; + struct profile_node *next, *prev; +}; + +#define CHECK_MAGIC(node) \ + if ((node)->magic != PROF_MAGIC_NODE) \ + return PROF_MAGIC_NODE; + +/* + * Free a node, and any children + */ +void profile_free_node(node) + struct profile_node *node; +{ + struct profile_node *child; + + if (node->magic != PROF_MAGIC_NODE) + return; + + if (node->name) + free(node->name); + if (node->value) + free(node->value); + for (child=node->first_child; child; child = child->next) + profile_free_node(child); + node->magic = 0; + + free(node); +} + +/* + * Create a node + */ +errcode_t profile_create_node(name, value, ret_node) + const char *name, *value; + struct profile_node **ret_node; +{ + struct profile_node *new; + + new = malloc(sizeof(struct profile_node)); + if (!new) + return ENOMEM; + memset(new, 0, sizeof(struct profile_node)); + new->name = malloc(strlen(name)+1); + if (new->name == 0) { + profile_free_node(new); + return ENOMEM; + } + strcpy(new->name, name); + if (value) { + new->value = malloc(strlen(value)+1); + if (new->value == 0) { + profile_free_node(new); + return ENOMEM; + } + strcpy(new->value, value); + } + new->magic = PROF_MAGIC_NODE; + + *ret_node = new; + return 0; +} + +/* + * This function verifies that all of the representation invarients of + * the profile are true. If not, we have a programming bug somewhere, + * probably in this file. + */ +errcode_t profile_verify_node(node) + struct profile_node *node; +{ + struct profile_node *p, *last; + + CHECK_MAGIC(node); + + if (node->value && node->first_child) + return PROF_SECTION_WITH_VALUE; + + last = 0; + for (p = node->first_child; p; last = p, p = p->next) { + if (p->prev != last) + return PROF_BAD_LINK_LIST; + if (last && (last->next != p)) + return PROF_BAD_LINK_LIST; + if (node->group_level != p->group_level+1) + return PROF_BAD_GROUP_LVL; + if (p->parent != node) + return PROF_BAD_PARENT_PTR; + profile_verify_node(p); + } + return 0; +} + +/* + * Add a node to a particular section + */ +errcode_t profile_add_node(section, name, value, ret_node) + struct profile_node *section; + const char *name, *value; + struct profile_node **ret_node; +{ + errcode_t retval; + struct profile_node *p, *last, *new; + int cmp = -1; + + CHECK_MAGIC(section); + + if (section->value) + return PROF_ADD_NOT_SECTION; + + for (p=section->first_child, last = 0; p; last = p, p = p->next) { + cmp = strcmp(p->name, name); + if (cmp >= 0) + break; + } + retval = profile_create_node(name, value, &new); + if (retval) + return retval; + new->group_level = section->group_level+1; + new->parent = section; + if (cmp == 0) { + do { + last = p; + p = p->next; + } while (p && strcmp(p->name, name) == 0); + } + new->prev = last; + if (last) + last->next = new; + else + section->first_child = new; + if (p) + new->next = p; + if (ret_node) + *ret_node = new; + return 0; +} + +/* + * Iterate through the section, returning the relations which match + * the given name. If name is NULL, then interate through all the + * relations in the section. The first time this routine is called, + * the state pointer must be null. When this profile_find_node_relatioon() + * returns, if the state pointer is non-NULL, then this routine should + * be called again. + * + * The returned character string in value points to the stored + * character string in the parse string. Before this string value is + * returned to a calling application (profile_find_node_relatioon is not an + * exported interface), it should be strdup()'ed. + */ +errcode_t profile_find_node_relation(section, name, state, ret_name, value) + struct profile_node *section; + const char *name; + void **state; + char **ret_name, **value; +{ + struct profile_node *p; + + CHECK_MAGIC(section); + p = *state; + if (p) { + CHECK_MAGIC(p); + } else + p = section->first_child; + + while (p) { + if (((name == 0) || (strcmp(p->name, name) == 0)) && + p->value) { + *value = p->value; + if (ret_name) + *ret_name = p->name; + break; + } + p = p->next; + } + if (p == 0) { + *state = 0; + return PROF_NO_RELATION; + } + /* + * OK, we've found one match; now let's try to find another + * one. This way, if we return a non-zero state pointer, + * there's guaranteed to be another match that's returned. + */ + p = p->next; + while (p) { + if (((name == 0) || (strcmp(p->name, name) == 0)) && + p->value) + break; + p = p->next; + } + *state = p; + return 0; +} + +/* + * Iterate through the section, returning the subsections which match + * the given name. If name is NULL, then interate through all the + * subsections in the section. The first time this routine is called, + * the state pointer must be null. When this profile_find_node_subsection() + * returns, if the state pointer is non-NULL, then this routine should + * be called again. + */ +errcode_t profile_find_node_subsection(section, name, state, ret_name, + subsection) + struct profile_node *section; + const char *name; + void **state; + char **ret_name; + struct profile_node **subsection; +{ + struct profile_node *p; + + CHECK_MAGIC(section); + p = *state; + if (p) { + CHECK_MAGIC(p); + } else + p = section->first_child; + + while (p) { + if (((name == 0) || (strcmp(p->name, name) == 0)) && + (p->value == 0)) { + *subsection = p; + if (ret_name) + *ret_name = p->name; + break; + } + p = p->next; + } + if (p == 0) { + *state = 0; + return PROF_NO_SECTION; + } + /* + * OK, we've found one match; now let's try to find another + * one. This way, if we return a non-zero state pointer, + * there's guaranteed to be another match that's returned. + */ + p = p->next; + while (p) { + if (((name == 0) || (strcmp(p->name, name) == 0)) + && (p->value == 0)) + break; + p = p->next; + } + *state = p; + return 0; +} + +/* + * This function deletes a relation from a section. Subsections are + * not deleted; if those need to be deleted, they must be done so manually. + */ +errcode_t profile_delete_node_relation(section, name) + struct profile_node *section; + const char *name; +{ + struct profile_node *p, *next; + + for (p = section->first_child; p; p = p->next) { + if ((strcmp(p->name, name) == 0) && p->value) + break; + } + if (p == 0) + return PROF_NO_RELATION; + /* + * Now we start deleting the relations... if we find a + * subsection with the same name, delete it and keep going. + */ + while (p && (strcmp(p->name, name) == 0)) { + if (p->value == 0) { + p = p->next; + continue; + } + if (p->prev) + p->prev->next = p->next; + else + section->first_child = p->next; + next = p->next; + if (p->next) + p->next->prev = p; + profile_free_node(p); + p = next; + } + return 0; +} + +/* + * This function returns the parent of a particular node. + */ +errcode_t profile_get_node_parent(section, parent) + struct profile_node *section, **parent; +{ + *parent = section->parent; + return 0; +} + + |