+Tue Mar 2 18:55:50 1999 Theodore Y. Ts'o <tytso@mit.edu>
+
+ * prof_tree.c: Add new functions profile_get_node_name,
+ profile_get_node_value, profile_find_node,
+ profile_remove_node, profile_set_relation_value,
+ profile_rename_node. Rewrite profile_find_node_relation
+ and profile_find_node_subsection in terms of
+ profile_find_node.
+
+ * prof_set.c, Makefile.in: Add a new file which exports the public
+ interfaces for setting profile entries.
+
+ * prof_get.c, prof_init.c, prof_int.h: Add the KRB5_DLLIMP and
+ KRB5_CALLCONV to all of the various profile routines so
+ they can be properly exported via a Windows DLL.
+
+ * prof_int.h: Add definition for the flags in the profile
+ structure.
+
+ * prof_err.et: Add new error codes PROF_SET_SECTION_VALUE,
+ PROF_EINVAL, PROF_READ_ONLY, and PROF_EXISTS.
+
Fri Feb 19 00:49:10 1999 Theodore Y. Ts'o <tytso@mit.edu>
* test_parse.c (main): Add a call to profile_verify_node so we can
prof_file.o \
prof_parse.o \
prof_get.o \
+ prof_set.o \
prof_err.o \
prof_init.o
prof_file.$(OBJEXT) \
prof_parse.$(OBJEXT) \
prof_get.$(OBJEXT) \
+ prof_set.$(OBJEXT) \
prof_err.$(OBJEXT) \
prof_init.$(OBJEXT)
$(srcdir)/prof_file.c \
$(srcdir)/prof_parse.c \
$(srcdir)/prof_get.c \
+ $(srcdir)/prof_set.c \
prof_err.c \
$(srcdir)/prof_init.c
error_code PROF_BAD_PARENT_PTR,
"Bad parent pointer in profile strctures"
error_code PROF_MAGIC_ITERATOR, "Bad magic value in profile iterator"
+error_code PROF_SET_SECTION_VALUE, "Can't set value on section node"
+error_code PROF_EINVAL, "Invalid argument passed to profile library"
+error_code PROF_READ_ONLY, "Attempt to modify read-only profile"
#
# generated by prof_parse.c
#
error_code PROF_MAGIC_FILE, "Bad magic value in profile_file_t"
+#
+# generated by prof_set.c
+#
+error_code PROF_EXISTS, "Section already exists"
+
end
return retval;
}
-errcode_t profile_get_string(profile, name, subname, subsubname,
+KRB5_DLLIMP errcode_t KRB5_CALLCONV
+profile_get_string(profile, name, subname, subsubname,
def_val, ret_string)
profile_t profile;
const char *name, *subname, *subsubname;
return 0;
}
-errcode_t profile_get_integer(profile, name, subname, subsubname,
+KRB5_DLLIMP errcode_t KRB5_CALLCONV
+profile_get_integer(profile, name, subname, subsubname,
def_val, ret_int)
profile_t profile;
const char *name, *subname, *subsubname;
* This function will return the list of the names of subections in the
* under the specified section name.
*/
-errcode_t profile_get_subsection_names(profile, names, ret_names)
+KRB5_DLLIMP errcode_t KRB5_CALLCONV
+profile_get_subsection_names(profile, names, ret_names)
profile_t profile;
const char **names;
char ***ret_names;
* This function will return the list of the names of relations in the
* under the specified section name.
*/
-errcode_t profile_get_relation_names(profile, names, ret_names)
+KRB5_DLLIMP errcode_t KRB5_CALLCONV
+profile_get_relation_names(profile, names, ret_names)
profile_t profile;
const char **names;
char ***ret_names;
return retval;
}
-errcode_t profile_iterator_create(profile, names, flags, ret_iter)
+KRB5_DLLIMP errcode_t KRB5_CALLCONV
+profile_iterator_create(profile, names, flags, ret_iter)
profile_t profile;
const char **names;
int flags;
return profile_node_iterator_create(profile, names, flags, ret_iter);
}
-void profile_iterator_free(iter_p)
+KRB5_DLLIMP void KRB5_CALLCONV
+profile_iterator_free(iter_p)
void **iter_p;
{
profile_node_iterator_free(iter_p);
}
-errcode_t profile_iterator(iter_p, ret_name, ret_value)
+KRB5_DLLIMP errcode_t KRB5_CALLCONV
+profile_iterator(iter_p, ret_name, ret_value)
void **iter_p;
char **ret_name, **ret_value;
{
return 0;
}
-void profile_release_string(str)
+KRB5_DLLIMP void KRB5_CALLCONV
+profile_release_string(str)
char *str;
{
free(str);
error(do not have a 4-byte integer type)
#endif /* SIZEOF_LONG == 4 */
-errcode_t profile_init(filenames, ret_profile)
+KRB5_DLLIMP errcode_t KRB5_CALLCONV
+profile_init(filenames, ret_profile)
const char **filenames;
profile_t *ret_profile;
{
return 0;
}
-errcode_t profile_init_path(filepath, ret_profile)
+KRB5_DLLIMP errcode_t KRB5_CALLCONV
+profile_init_path(filepath, ret_profile)
const char *filepath;
profile_t *ret_profile;
{
}
-void profile_release(profile)
+KRB5_DLLIMP void KRB5_CALLCONV
+profile_release(profile)
profile_t profile;
{
prf_file_t p, next;
typedef struct _prf_file_t *prf_file_t;
+/*
+ * The profile flags
+ */
+#define PROFILE_FILE_RW 0x0001
+#define PROFILE_FILE_DIRTY 0x0002
+
/*
* This structure defines the high-level, user visible profile_t
* object, which is used as a handle by users who need to query some
int profile_is_node_final
PROTOTYPE((struct profile_node *node));
-
+
+const char *profile_get_node_name
+ PROTOTYPE((struct profile_node *node));
+
+const char *profile_get_node_value
+ PROTOTYPE((struct profile_node *node));
+
+errcode_t profile_find_node
+ PROTOTYPE ((struct profile_node *section,
+ const char *name, const char *value,
+ int section_flag, void **state,
+ struct profile_node **node));
+
errcode_t profile_find_node_relation
PROTOTYPE ((struct profile_node *section,
const char *name, void **state,
PROTOTYPE((void **iter_p, struct profile_node **ret_node,
char **ret_name, char **ret_value));
+errcode_t profile_remove_node
+ PROTOTYPE((struct profile_node *node));
+
+errcode_t profile_set_relation_value
+ PROTOTYPE((struct profile_node *node, const char *new_value));
+
+errcode_t profile_rename_node
+ PROTOTYPE((struct profile_node *node, const char *new_name));
+
/* prof_file.c */
errcode_t profile_open_file
/* prof_init.c */
-errcode_t profile_init
+KRB5_DLLIMP errcode_t KRB5_CALLCONV profile_init
PROTOTYPE ((const char **filenames, profile_t *ret_profile));
-errcode_t profile_init_path
+KRB5_DLLIMP errcode_t KRB5_CALLCONV profile_init_path
PROTOTYPE ((const char *filepath, profile_t *ret_profile));
-void profile_release
+KRB5_DLLIMP void KRB5_CALLCONV profile_release
PROTOTYPE ((profile_t profile));
/* prof_get.c */
PROTOTYPE ((profile_t profile, const char **names,
const char **ret_value));
-errcode_t profile_get_string
+KRB5_DLLIMP errcode_t KRB5_CALLCONV profile_get_string
PROTOTYPE((profile_t profile, const char *name, const char *subname,
const char *subsubname, const char *def_val,
char **ret_string));
-errcode_t profile_get_integer
+KRB5_DLLIMP errcode_t KRB5_CALLCONV profile_get_integer
PROTOTYPE((profile_t profile, const char *name, const char *subname,
const char *subsubname, int def_val,
int *ret_default));
-errcode_t profile_get_relation_names
+KRB5_DLLIMP errcode_t KRB5_CALLCONV profile_get_relation_names
PROTOTYPE((profile_t profile, const char **names, char ***ret_names));
-errcode_t profile_get_subsection_names
+KRB5_DLLIMP errcode_t KRB5_CALLCONV profile_get_subsection_names
PROTOTYPE((profile_t profile, const char **names, char ***ret_names));
-errcode_t profile_iterator_create
+KRB5_DLLIMP errcode_t KRB5_CALLCONV profile_iterator_create
PROTOTYPE((profile_t profile, const char **names,
int flags, void **ret_iter));
-void profile_iterator_free PROTOTYPE((void **iter_p));
+KRB5_DLLIMP void KRB5_CALLCONV profile_iterator_free
+ PROTOTYPE((void **iter_p));
-errcode_t profile_iterator
+KRB5_DLLIMP errcode_t KRB5_CALLCONV profile_iterator
PROTOTYPE((void **iter_p, char **ret_name, char **ret_value));
-void profile_release_string PROTOTYPE((char *str));
+KRB5_DLLIMP void KRB5_CALLCONV profile_release_string PROTOTYPE((char *str));
+
+
+/* prof_set.c */
+KRB5_DLLIMP errcode_t KRB5_CALLCONV profile_update_relation
+ PROTOTYPE((profile_t profile, const char **names,
+ const char *old_value, const char *new_value));
+
+KRB5_DLLIMP errcode_t KRB5_CALLCONV profile_clear_relation
+ PROTOTYPE((profile_t profile, const char **names));
+
+KRB5_DLLIMP errcode_t KRB5_CALLCONV profile_rename_section
+ PROTOTYPE((profile_t profile, const char **names,
+ const char *new_name));
+
+KRB5_DLLIMP errcode_t KRB5_CALLCONV profile_add_relation
+ PROTOTYPE((profile_t profile, const char **names,
+ const char *new_value));
+
+
--- /dev/null
+/*
+ * prof_set.c --- routines that expose the public interfaces for
+ * inserting, updating and deleting items from the profile.
+ *
+ * WARNING: These routines only look at the first file opened in the
+ * profile. It's not clear how to handle multiple files, actually.
+ * In the future it may be necessary to modify this public interface,
+ * or possibly add higher level functions to support this correctly.
+ *
+ * WARNING: We're not yet doing locking yet, either.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <errno.h>
+
+#include "prof_int.h"
+
+static errcode_t rw_setup(profile)
+ profile_t profile;
+{
+ prf_file_t file;
+ errcode_t retval;
+
+ if (!profile)
+ return PROF_NO_PROFILE;
+
+ if (profile->magic != PROF_MAGIC_PROFILE)
+ return PROF_MAGIC_PROFILE;
+
+ file = profile->first_file;
+ if (!(file->flags & PROFILE_FILE_RW))
+ return PROF_READ_ONLY;
+
+ /* Don't update the file if we've already made modifications */
+ if (file->flags & PROFILE_FILE_DIRTY)
+ return 0;
+
+ retval = profile_update_file(file);
+
+ return retval;
+}
+
+
+/*
+ * Delete or update a particular child node
+ *
+ * ADL - 2/23/99, rewritten TYT 2/25/99
+ */
+KRB5_DLLIMP errcode_t KRB5_CALLCONV
+profile_update_relation(profile, names, old_value, new_value)
+ profile_t profile;
+ const char **names;
+ const char *old_value;
+ const char *new_value;
+{
+ errcode_t retval;
+ struct profile_node *section, *node;
+ void *state;
+ const char **cpp;
+
+ retval = rw_setup(profile);
+ if (retval)
+ return retval;
+
+ if (names == 0 || names[0] == 0 || names[1] == 0)
+ return PROF_BAD_NAMESET;
+
+ if (!old_value || !*old_value)
+ return PROF_EINVAL;
+
+ section = profile->first_file->root;
+ for (cpp = names; cpp[1]; cpp++) {
+ state = 0;
+ retval = profile_find_node(section, *cpp, 0, 1,
+ &state, §ion);
+ if (retval)
+ return retval;
+ }
+
+ state = 0;
+ retval = profile_find_node(section, *cpp, old_value, 0, &state, &node);
+ if (retval)
+ return retval;
+
+ if (new_value)
+ retval = profile_set_relation_value(node, new_value);
+ else
+ retval = profile_remove_node(node);
+ if (retval)
+ return retval;
+
+ profile->first_file->flags |= PROFILE_FILE_DIRTY;
+
+ return 0;
+}
+
+/*
+ * Clear a particular all of the relations with a specific name.
+ *
+ * TYT - 2/25/99
+ */
+KRB5_DLLIMP errcode_t KRB5_CALLCONV
+profile_clear_relation(profile, names)
+ profile_t profile;
+ const char **names;
+{
+ errcode_t retval;
+ struct profile_node *section, *node;
+ void *state;
+ const char **cpp;
+
+ retval = rw_setup(profile);
+ if (retval)
+ return retval;
+
+ if (names == 0 || names[0] == 0 || names[1] == 0)
+ return PROF_BAD_NAMESET;
+
+ section = profile->first_file->root;
+ for (cpp = names; cpp[1]; cpp++) {
+ state = 0;
+ retval = profile_find_node(section, *cpp, 0, 1,
+ &state, §ion);
+ if (retval)
+ return retval;
+ }
+
+ state = 0;
+ do {
+ retval = profile_find_node(section, *cpp, 0, 0, &state, &node);
+ if (retval)
+ return retval;
+ retval = profile_remove_node(node);
+ if (retval)
+ return retval;
+ } while (state);
+
+ profile->first_file->flags |= PROFILE_FILE_DIRTY;
+
+ return 0;
+}
+
+/*
+ * Rename a particular section; if the new_section name is NULL,
+ * delete it.
+ *
+ * ADL - 2/23/99, rewritten TYT 2/25/99
+ */
+KRB5_DLLIMP errcode_t KRB5_CALLCONV
+profile_rename_section(profile, names, new_name)
+ profile_t profile;
+ const char **names;
+ const char *new_name;
+{
+ errcode_t retval;
+ struct profile_node *section, *node;
+ void *state;
+ const char **cpp;
+
+ retval = rw_setup(profile);
+ if (retval)
+ return retval;
+
+ if (names == 0 || names[0] == 0 || names[1] == 0)
+ return PROF_BAD_NAMESET;
+
+ section = profile->first_file->root;
+ for (cpp = names; cpp[1]; cpp++) {
+ state = 0;
+ retval = profile_find_node(section, *cpp, 0, 1,
+ &state, §ion);
+ if (retval)
+ return retval;
+ }
+
+ state = 0;
+ retval = profile_find_node(section, *cpp, 0, 1, &state, &node);
+ if (retval)
+ return retval;
+
+ if (new_name)
+ retval = profile_rename_node(node, new_name);
+ else
+ retval = profile_remove_node(node);
+ if (retval)
+ return retval;
+
+ profile->first_file->flags |= PROFILE_FILE_DIRTY;
+
+ return 0;
+}
+
+/*
+ * Insert a new relation. If the new_value argument is NULL, then
+ * create a new section instead.
+ *
+ * Note: if the intermediate sections do not exist, this function will
+ * automatically create them.
+ *
+ * ADL - 2/23/99, rewritten TYT 2/25/99
+ */
+KRB5_DLLIMP errcode_t KRB5_CALLCONV
+profile_add_relation(profile, names, new_value)
+ profile_t profile;
+ const char **names;
+ const char *new_value;
+{
+ errcode_t retval;
+ struct profile_node *section;
+ const char **cpp;
+ void *state;
+
+ retval = rw_setup(profile);
+ if (retval)
+ return retval;
+
+ if (names == 0 || names[0] == 0 || names[1] == 0)
+ return PROF_BAD_NAMESET;
+
+ section = profile->first_file->root;
+ for (cpp = names; cpp[1]; cpp++) {
+ state = 0;
+ retval = profile_find_node(section, *cpp, 0, 1,
+ &state, §ion);
+ if (retval == PROF_NO_SECTION)
+ retval = profile_add_node(section, *cpp, 0, §ion);
+ if (retval)
+ return retval;
+ }
+
+ if (new_value == 0) {
+ retval = profile_find_node(section, *cpp, 0, 1, &state, 0);
+ if (retval == 0)
+ return PROF_EXISTS;
+ else if (retval != PROF_NO_SECTION)
+ return retval;
+ }
+
+ retval = profile_add_node(section, *cpp, new_value, 0);
+ if (retval)
+ return retval;
+
+ profile->first_file->flags |= PROFILE_FILE_DIRTY;
+
+ return 0;
+}
+
}
/*
- * Iterate through the section, returning the relations which match
+ * Return the name of a node. (Note: this is for internal functions
+ * only; if the name needs to be returned from an exported function,
+ * strdup it first!)
+ */
+const char *profile_get_node_name(node)
+ struct profile_node *node;
+{
+ return node->name;
+}
+
+/*
+ * Return the value of a node. (Note: this is for internal functions
+ * only; if the name needs to be returned from an exported function,
+ * strdup it first!)
+ */
+const char *profile_get_node_value(node)
+ struct profile_node *node;
+{
+ return node->value;
+}
+
+/*
+ * Iterate through the section, returning the nodes 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_relation()
- * returns, if the state pointer is non-NULL, then this routine should
- * be called again.
+ * nodes in the section. If section_flag is non-zero, only return the
+ * section which matches the name; don't return relations. If value
+ * is non-NULL, then only return relations which match the requested
+ * value. (The value argument is ignored if section_flag is non-zero.)
+ *
+ * The first time this routine is called, the state pointer must be
+ * null. When this profile_find_node_relation() returns, if the state
+ * pointer is non-NULL, then this routine should be called again.
+ * (This won't happen if section_flag is non-zero, obviously.)
*
- * 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_relation is not an
- * exported interface), it should be strdup()'ed.
*/
-errcode_t profile_find_node_relation(section, name, state, ret_name, value)
+errcode_t profile_find_node(section, name, value, section_flag, state, node)
struct profile_node *section;
const char *name;
+ const char *value;
+ int section_flag;
void **state;
- char **ret_name, **value;
+ struct profile_node **node;
{
struct profile_node *p;
} else
p = section->first_child;
- while (p) {
- if (((name == 0) || (strcmp(p->name, name) == 0)) &&
- p->value) {
- if (value)
- *value = p->value;
- if (ret_name)
- *ret_name = p->name;
- break;
+ for (; p; p = p->next) {
+ if (name && (strcmp(p->name, name)))
+ continue;
+ if (section_flag) {
+ if (p->value)
+ continue;
+ } else {
+ if (!p->value)
+ continue;
+ if (value && (strcmp(p->value, value)))
+ continue;
}
- p = p->next;
+ /* A match! */
+ if (node)
+ *node = p;
+ break;
}
if (p == 0) {
*state = 0;
- return PROF_NO_RELATION;
+ return section_flag ? PROF_NO_SECTION : 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;
+ for (p = p->next; p; p = p->next) {
+ if (name && (strcmp(p->name, name)))
+ continue;
+ if (section_flag) {
+ if (p->value)
+ continue;
+ } else {
+ if (!p->value)
+ continue;
+ if (value && (strcmp(p->value, value)))
+ continue;
+ }
+ /* A match! */
+ break;
}
*state = p;
return 0;
}
+
/*
- * Iterate through the section, returning the subsections which match
+ * Iterate through the section, returning the relations 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()
+ * relations in the section. The first time this routine is called,
+ * the state pointer must be null. When this profile_find_node_relation()
* 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_relation is not an
+ * exported interface), it should be strdup()'ed.
*/
-errcode_t profile_find_node_subsection(section, name, state, ret_name,
- subsection)
+errcode_t profile_find_node_relation(section, name, state, ret_name, value)
struct profile_node *section;
const char *name;
void **state;
- char **ret_name;
- struct profile_node **subsection;
+ char **ret_name, **value;
{
struct profile_node *p;
+ errcode_t retval;
+
+ retval = profile_find_node(section, name, 0, 0, state, &p);
+ if (retval)
+ return retval;
- 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)) {
- if (subsection)
- *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;
+ if (value)
+ *value = p->value;
+ if (ret_name)
+ *ret_name = p->name;
}
- *state = p;
return 0;
}
/*
- * This function deletes a subsection or relation from a section,
- * depending whether on the section flag is non-zero or not.
+ * 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.
+ *
+ * This is (plus accessor functions for the name and value given a
+ * profile node) makes this function mostly syntactic sugar for
+ * profile_find_node.
*/
-errcode_t profile_remove_node(section, name, section_flag)
+errcode_t profile_find_node_subsection(section, name, state, ret_name,
+ subsection)
struct profile_node *section;
const char *name;
- int section_flag;
+ void **state;
+ char **ret_name;
+ struct profile_node **subsection;
{
- 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 or subsection.
- */
- while (p && (strcmp(p->name, name) == 0)) {
- /*
- * Skip if it is not the correct type.
- */
- if ((section_flag && p->value) ||
- (!section_flag && !p->value)) {
- 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->prev;
- profile_free_node(p);
- p = next;
+ struct profile_node *p;
+ errcode_t retval;
+
+ retval = profile_find_node(section, name, 0, 1, state, &p);
+ if (retval)
+ return retval;
+
+ if (p) {
+ if (subsection)
+ *subsection = p;
+ if (ret_name)
+ *ret_name = p->name;
}
return 0;
}
*ret_value = p->value;
return 0;
};
+
+/*
+ * Remove a particular node.
+ *
+ * TYT, 2/25/99
+ */
+errcode_t profile_remove_node(node)
+ struct profile_node *node;
+{
+ CHECK_MAGIC(node);
+
+ if (node->parent == 0)
+ return PROF_EINVAL; /* Can't remove the root! */
+
+ if (node->prev)
+ node->prev->next = node->next;
+ else
+ node->parent->first_child = node->next;
+
+ if (node->next)
+ node->next->prev = node->prev;
+
+ profile_free_node(node);
+
+ return 0;
+}
+
+/*
+ * Set the value of a specific node containing a relation.
+ *
+ * TYT, 2/25/99
+ */
+errcode_t profile_set_relation_value(node, new_value)
+ struct profile_node *node;
+ const char *new_value;
+{
+ char *cp;
+
+ CHECK_MAGIC(node);
+
+ if (node->value)
+ return PROF_SET_SECTION_VALUE;
+
+ cp = malloc(strlen(new_value)+1);
+ if (!cp)
+ return ENOMEM;
+
+ strcpy(cp, new_value);
+ free(node->value);
+ node->value = cp;
+
+ return 0;
+}
+
+/*
+ * Rename a specific node
+ *
+ * TYT 2/25/99
+ */
+errcode_t profile_rename_node(node, new_name)
+ struct profile_node *node;
+ const char *new_name;
+{
+ char *new_string;
+ struct profile_node *p, *last;
+
+ CHECK_MAGIC(node);
+
+ if (strcmp(new_name, node->name) == 0)
+ return 0; /* It's the same name, return */
+
+ /*
+ * Make sure we can allocate memory for the new name, first!
+ */
+ new_string = malloc(strlen(new_name)+1);
+ if (!new_string)
+ return ENOMEM;
+ strcpy(new_string, new_name);
+
+ /*
+ * Find the place to where the new node should go. We look
+ * for the place *after* the last match of the node name,
+ * since order matters.
+ */
+ for (p=node->parent->first_child, last = 0; p; last = p, p = p->next) {
+ if (strcmp(p->name, new_name) > 0)
+ break;
+ }
+
+ /*
+ * OK, let's detach the node
+ */
+ if (node->prev)
+ node->prev->next = node->next;
+ else
+ node->parent->first_child = node->next;
+
+ if (node->next)
+ node->next->prev = node->prev;
+
+ /*
+ * Now let's reattach it in the right place.
+ */
+ if (p)
+ p->prev = node;
+ if (last)
+ last->next = node;
+ else
+ node->parent->first_child = node;
+
+ free(node->name);
+ node->name = new_string;
+ return 0;
+}
#define PROFILE_ITER_SECTIONS_ONLY 0x0002
#define PROFILE_ITER_RELATIONS_ONLY 0x0004
-long profile_init
+KRB5_DLLIMP long KRB5_CALLCONV profile_init
PROTOTYPE ((const char **filenames, profile_t *ret_profile));
-long profile_init_path
+KRB5_DLLIMP long KRB5_CALLCONV profile_init_path
PROTOTYPE ((const char *filepath, profile_t *ret_profile));
-void profile_release
+KRB5_DLLIMP void KRB5_CALLCONV profile_release
PROTOTYPE ((profile_t profile));
KRB5_DLLIMP long KRB5_CALLCONV profile_get_values
KRB5_DLLIMP void KRB5_CALLCONV profile_free_list
PROTOTYPE ((char **list));
-long profile_get_string
+KRB5_DLLIMP long KRB5_CALLCONV profile_get_string
PROTOTYPE((profile_t profile, const char *name, const char *subname,
const char *subsubname, const char *def_val,
char **ret_string));
-long profile_get_integer
+KRB5_DLLIMP long KRB5_CALLCONV profile_get_integer
PROTOTYPE((profile_t profile, const char *name, const char *subname,
const char *subsubname, int def_val,
int *ret_default));
-long profile_get_relation_names
+KRB5_DLLIMP long KRB5_CALLCONV profile_get_relation_names
PROTOTYPE((profile_t profile, const char **names, char ***ret_names));
-long profile_get_subsection_names
+KRB5_DLLIMP long KRB5_CALLCONV profile_get_subsection_names
PROTOTYPE((profile_t profile, const char **names, char ***ret_names));
-long profile_iterator_create
+KRB5_DLLIMP long KRB5_CALLCONV profile_iterator_create
PROTOTYPE((profile_t profile, const char **names,
int flags, void **ret_iter));
-void profile_iterator_free PROTOTYPE((void **iter_p));
+KRB5_DLLIMP void KRB5_CALLCONV profile_iterator_free
+ PROTOTYPE((void **iter_p));
-long profile_iterator
+KRB5_DLLIMP long KRB5_CALLCONV profile_iterator
PROTOTYPE((void **iter_p, char **ret_name, char **ret_value));
-void profile_release_string PROTOTYPE((char *str));
+KRB5_DLLIMP void KRB5_CALLCONV profile_release_string PROTOTYPE((char *str));
+
+KRB5_DLLIMP long KRB5_CALLCONV profile_update_relation
+ PROTOTYPE((profile_t profile, const char **names,
+ const char *old_value, const char *new_value));
+
+KRB5_DLLIMP long KRB5_CALLCONV profile_clear_relation
+ PROTOTYPE((profile_t profile, const char **names));
+
+KRB5_DLLIMP long KRB5_CALLCONV profile_rename_section
+ PROTOTYPE((profile_t profile, const char **names,
+ const char *new_name));
+
+KRB5_DLLIMP long KRB5_CALLCONV profile_add_relation
+ PROTOTYPE((profile_t profile, const char **names,
+ const char *new_value));
#endif /* _KRB5_PROFILE_H */