diff options
Diffstat (limited to 'libstore/kids.c')
-rw-r--r-- | libstore/kids.c | 311 |
1 files changed, 311 insertions, 0 deletions
diff --git a/libstore/kids.c b/libstore/kids.c new file mode 100644 index 00000000..ee00ace4 --- /dev/null +++ b/libstore/kids.c @@ -0,0 +1,311 @@ +/* Managing sub-stores + + Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc. + Written by Miles Bader <miles@gnu.ai.mit.edu> + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ + +#include <malloc.h> +#include <string.h> +#include <stdio.h> +#include <ctype.h> + +#include "store.h" + +/* Set STORE's current children list to (a copy of) CHILDREN and NUM_CHILDREN. */ +error_t +store_set_children (struct store *store, + struct store *const *children, unsigned num_children) +{ + unsigned size = num_children * sizeof (struct store_run); + struct store **copy = malloc (size); + + if (!copy) + return ENOMEM; + + if (store->children) + free (store->children); + + bcopy (children, copy, size); + store->children = copy; + store->num_children = num_children; + + return 0; +} + +/* Calls the allocate_encoding method in each child store of STORE, + propagating any errors. If any child does not hae such a method, + EOPNOTSUPP is returned. */ +error_t +store_allocate_child_encodings (const struct store *store, + struct store_enc *enc) +{ + int i; + error_t err = 0; + for (i = 0; i < store->num_children && !err; i++) + { + struct store *k = store->children[i]; + if (k->class->allocate_encoding) + (*k->class->allocate_encoding) (store, enc); + else + err = EOPNOTSUPP; + } + return err; +} + +/* Calls the encode method in each child store of STORE, propagating any + errors. If any child does not hae such a method, EOPNOTSUPP is returned. */ +error_t +store_encode_children (const struct store *store, struct store_enc *enc) +{ + int i; + error_t err = 0; + for (i = 0; i < store->num_children && !err; i++) + { + struct store *k = store->children[i]; + if (k->class->encode) + (*k->class->encode) (store, enc); + else + err = EOPNOTSUPP; + } + return err; +} + +/* Decodes NUM_CHILDREN from ENC, storing the results into successive + positions in CHILDREN. */ +error_t +store_decode_children (struct store_enc *enc, int num_children, + const struct store_class *const *classes, + struct store **children) +{ + int i; + error_t err = 0; + for (i = 0; i < num_children && !err; i++) + err = store_decode (enc, classes, &children[i]); + if (err) + /* Deallocate anything we've already created. */ + while (--i >= 0) + store_free (children[i]); + return err; +} + +/* Set FLAGS in all children of STORE, and if successfull, add FLAGS to + STORE's flags. */ +error_t +store_set_child_flags (struct store *store, int flags) +{ + int i; + error_t err = 0; + int old_child_flags[store->num_children]; + + for (i = 0; i < store->num_children && !err; i++) + { + old_child_flags[i] = store->children[i]->flags; + err = store_set_flags (store->children[i], flags); + } + + if (err) + while (i > 0) + store_clear_flags (store->children[--i], flags & ~old_child_flags[i]); + else + store->flags |= flags; + + return err; +} + +/* Clear FLAGS in all children of STORE, and if successfull, remove FLAGS from + STORE's flags. */ +error_t +store_clear_child_flags (struct store *store, int flags) +{ + int i; + error_t err = 0; + int old_child_flags[store->num_children]; + + for (i = 0; i < store->num_children && !err; i++) + { + old_child_flags[i] = store->children[i]->flags; + err = store_clear_flags (store->children[i], flags); + } + + if (err) + while (i > 0) + store_set_flags (store->children[--i], flags & ~old_child_flags[i]); + else + store->flags &= ~flags; + + return err; +} + +/* Parse multiple store names in NAME, and open each individually, returning + all in the vector STORES, and the number in NUM_STORES. The syntax of + NAME is a single non-alpha-numeric separator character, followed by each + child store name separated by the same separator; each child name is + TYPE:NAME notation as parsed by store_typed_open. If every child uses the + same TYPE: prefix, then it may be factored out and put before the child + list instead (the two types of notation are differentiated by whether the + first character of name is alpha-numeric or not). */ +error_t +store_open_children (const char *name, int flags, + const struct store_class *const *classes, + struct store ***stores, size_t *num_stores) +{ + char *pfx = 0; /* Prefix applied to each part name. */ + size_t pfx_len = 0; /* Space PFX + separator takes up. */ + char sep = *name; /* Character separating individual names. */ + + if (sep && isalnum (sep)) + /* If the first character is a `name' character, it's likely to be either + a type prefix (e.g, TYPE:@NAME1@NAME2@), so we distribute the type + prefix among the elements (@TYPE:NAME1@TYPE:NAME2@). */ + { + const char *pfx_end = name; + + while (isalnum (pfx_end)) + pfx_end++; + + if (*pfx_end++ != ':') + return EINVAL; + + /* Make a copy of the prefix. */ + pfx = strndupa (name, pfx_end - name); + pfx_len = pfx_end - name; + + sep = *pfx_end; + } + + if (sep) + /* Parse a list of store specs separated by SEP. */ + { + int k; + const char *p, *end; + error_t err = 0; + size_t count = 0; + + /* First, see how many there are. */ + for (p = name; p && p[1]; p = strchr (p + 1, sep)) + count++; + + /* Make a vector to hold them. */ + *stores = malloc (count * sizeof (struct store *)); + *num_stores = count; + if (! *stores) + return ENOMEM; + + bzero (*stores, count * sizeof (struct store *)); + + /* Open each child store. */ + for (p = name, k = 0; !err && p && p[1]; p = end, k++) + { + size_t kname_len; + + end = strchr (p + 1, sep); + kname_len = (end ? end - p - 1 : strlen (p + 1)); + + { + /* Allocate temporary child name on the stack. */ + char kname[pfx_len + kname_len + 1]; + + if (pfx) + /* Add type prefix to child name. */ + memcpy (kname, pfx, pfx_len); + + memcpy (kname + pfx_len, p + 1, kname_len); + kname[pfx_len + kname_len] = '\0'; + + err = store_typed_open (kname, flags, classes, &(*stores)[k]); + } + } + + if (err) + /* Failure opening some child, deallocate what we've done so far. */ + { + while (--k >= 0) + store_free ((*stores)[k]); + free (*stores); + } + + return err; + } + else + /* Empty list. */ + { + *stores = 0; + *num_stores = 0; + return 0; + } +} + +/* Try to come up with a name for the children in STORE, combining the names + of each child in a way that could be used to parse them with + store_open_children. This is done heuristically, and so may not succeed. + If a child doesn't have a name, EINVAL is returned. */ +error_t +store_children_name (const struct store *store, char **name) +{ + static char try_seps[] = "@+=,._%|;^!~'&"; + struct store **kids = store->children; + size_t num_kids = store->num_children; + + if (num_kids == 0) + { + *name = strdup (""); + return *name ? 0 : ENOMEM; + } + else + { + int k; + char *s; /* Current separator in search for one. */ + int fail; /* If we couldn't use *S as as sep. */ + size_t total_len = 0; /* Length of name we will return. */ + + /* Detect children without names, and calculate the total length of the + name we will return (which is the sum of the lengths of the child + names plus room for the types and separator characters. */ + for (k = 0; k < num_kids; k++) + if (!kids[k] || !kids[k]->name) + return EINVAL; + else + total_len += + /* separator + type name + type separator + child name */ + 1 + strlen (kids[k]->class->name) + 1 + strlen (kids[k]->name); + + /* Look for a separator character from those in TRY_SEPS that doesn't + occur in any of the the child names. */ + for (s = try_seps, fail = 1; *s && fail; s++) + for (k = 0, fail = 0; k < num_kids && !fail; k++) + if (strchr (kids[k]->name, *s)) + fail = 1; + + if (*s) + /* We found a usable separator! */ + { + char *p = malloc (total_len + 1); + + if (! p) + return ENOMEM; + *name = p; + + for (k = 0; k < num_kids; k++) + p += + sprintf (p, "%c%s:%s", *s, kids[k]->class->name, kids[k]->name); + + return 0; + } + else + return EGRATUITOUS; + } +} |