static VAttrList ReadAttrList (FILE *f) { VAttrList sublist, list = VCreateAttrList (); VAttrRec *a; int ch = 0; size_t name_size; VBundle b; char buf[2], *str, name_buf[VMaxAttrNameLength + 1]; /* Swallow a { marking the start of the attribute list: */ if (fscanf (f, " %1s", buf) != 1 || buf[0] != '{') { VWarning ("VReadFile: Missing {"); goto Fail; } /* For each attribute up to the next "}": */ while (fscanf (f, " %[^}: \t\n]", name_buf) == 1) { name_size = strlen (name_buf); /* Read a : and the first character of the attribute's value: */ if (fscanf (f, " %1s", buf) != 1 || buf[0] != ':' || fscanf (f, " %1s", buf) != 1) { VWarning ("VReadFile: Invalid %s attribute", name_buf); goto Fail; } /* The first character of the value tells us whether its an attribute list, quoted string, or unquoted string: */ if (buf[0] == '{') { /* The attribute value is another list of attributes: */ ungetc ('{', f); if (! (sublist = ReadAttrList (f))) goto Fail; a = VMalloc (sizeof (VAttrRec) + name_size); a->value = sublist; a->repn = VAttrListRepn; } else { /* The value doesn't start with '{' -- parse a word or string: */ if (! (str = ReadString (f, buf[0], name_buf))) goto Fail; while ((ch = fgetc (f)) && (ch == ' ' || ch == '\t')) ; ungetc (ch, f); /* If the word is followed by an '{'... */ if (ch == '{') { /* ...then it's a typed value -- the word is it's type name and the { is the start of it's attribute list value. */ b = VCreateBundle (str, NULL, 0, NULL); if (! (sublist = ReadAttrList (f))) { VFree (b); goto Fail; } b->list = sublist; a = VMalloc (sizeof (VAttrRec) + name_size); a->repn = VBundleRepn; a->value = b; } else { /* ...otherwise store it as a simple string value: */ a = VMalloc (sizeof (VAttrRec) + name_size + strlen (str) + 1); a->repn = VStringRepn; a->value = a->name + name_size + 1; strcpy (a->value, str); } VFree(str); } /* Copy the attribute's name into the newly allocated node: */ strcpy (a->name, name_buf); /* Place the new node on the end of the growing attribute list: */ a->next = NULL; a->prev = list->prev; if (a->prev) a->prev->next = a; else list->next = a; list->prev = a; } /* Swallow the terminating "}": */ if (fscanf (f, " %1s", buf) != 1 || buf[0] != '}') { VWarning ("VReadFile: Missing }"); Fail: VDestroyAttrList (list); return NULL; } return list; }
VAttrList VCopyAttrList (VAttrList list) { VAttrList new_list = VCreateAttrList (); size_t name_size, value_size; VAttrRec *old_a, *new_a; VBundle old_b, new_b; VTypeMethods *methods; /* For each node of the old list: */ for (old_a = list->next; old_a; old_a = old_a->next) { /* Compute the amount of storage needed for a copy of the node: */ name_size = strlen (old_a->name); value_size = (old_a->repn == VStringRepn) ? strlen ((VStringConst) old_a->value) + 1 : 0; /* Allocate that size and fill in the node's value: */ new_a = VMalloc (sizeof (VAttrRec) + name_size + value_size); strcpy (new_a->name, old_a->name); switch (new_a->repn = old_a->repn) { case VAttrListRepn: new_a->value = VCopyAttrList (old_a->value); break; case VBundleRepn: old_b = old_a->value; new_b = VCreateBundle (old_b->type_name, VCopyAttrList (old_b->list), old_b->length, NULL); if (old_b->length > 0) { new_b->data = VMalloc (old_b->length); memcpy (new_b->data, old_b->data, old_b->length); } new_a->value = new_b; break; case VPointerRepn: new_a->value = old_a->value; break; case VStringRepn: new_a->value = (VPointer) (new_a->name + name_size + 1); strcpy (new_a->value, old_a->value); break; default: if (methods = VRepnMethods (new_a->repn)) new_a->value = (methods->copy) (old_a->value); else VError ("VCopyAttrList: %s attribute has invalid repn %d", old_a->name, old_a->repn); } /* Append it to the new list: */ new_a->next = NULL; if (new_a->prev = new_list->prev) new_a->prev->next = new_a; if (! new_list->next) new_list->next = new_a; new_list->prev = new_a; } return new_list; }