/* * property list management code. * * G. Robert Malan (rmalan@eecs.umich.edu) * 2/20/97 * * $Id: propertyList.c,v 1.9 1997/05/08 20:39:42 rmalan Exp $ */ #include #include #include "propertyList.h" /***************************************************************************** * * Property List library routines: * *****************************************************************************/ plist_t createPropertyList(void) { plist_t plist; plist = (plist_t)malloc(sizeof(struct plist)); if (plist) plist->head = 0; return plist; } void destroyPropertyList(plist_t plist) { plist_entry_t entry, next; if (!plist) return; entry = plist->head; while(entry) { if (entry->key) free(entry->key); if (entry->value) free(entry->value); next = entry->next; free(entry); entry = next; } free(plist); } /* Returns 1 if success, 0 if fails */ int updateProperty(plist_t plist, char * key, char * value) { plist_entry_t found; plist_entry_t new_entry; if (!key || !value) return 1; for (found = plist->head; found != NULL; found = found->next) if ((strcmp(found->key, key) == 0)) break; if (found != NULL) { /* * Already have a key, so replace it's value. */ if (found->value) free(found->value); if (!(found->value = (char *)malloc(strlen(value) + 1))) return 0; strcpy(found->value, value); } else { /* * Not there, so just append it to beginning of the * header's linked list. */ /* Allocate it... */ if (!(new_entry = (plist_entry_t) malloc(sizeof(struct plist_entry)))) return 0; /* Fill it in... */ if (!(new_entry->key = (char *)malloc(strlen(key) + 1))) { free(new_entry); return 0; } strcpy(new_entry->key, key); if (!(new_entry->value = (char *)malloc(strlen(value) + 1))) { free(new_entry->key); free(new_entry); return 0; } strcpy(new_entry->value, value); /* Link it up... */ new_entry->next = plist->head; if (new_entry->next) new_entry->next->previous = new_entry; new_entry->previous = NULL; plist->head = new_entry; } return 1; } plist_t copyPropertyList(plist_t from) { plist_t retplist; plist_entry_t entry; if (!from) return (NULL); if (!(retplist = createPropertyList())) return (NULL); for (entry = from->head; entry; entry = entry->next) { if (!updateProperty(retplist, entry->key, entry->value)) { destroyPropertyList(retplist); return 0; } } return (retplist); } void deleteProperty(plist_t plist, char * key) { plist_entry_t entry; if (!key) return; for (entry = plist->head; entry; entry = entry->next) if (!strcmp(entry->key, key)) break; if (!entry) return; free(entry->key); if (entry->value) free(entry->value); if (entry->previous == NULL) { plist->head = entry->next; if (entry->next) entry->next->previous = NULL; }else{ entry->previous->next = entry->next; } if (entry->next != NULL) { entry->next->previous = entry->previous; } free(entry); } char * getProperty(plist_t plist, char * key) { plist_entry_t entry; for (entry = plist->head; entry; entry = entry->next) { if (strcmp(entry->key, key) == 0) return (strdup(entry->value)); } return (NULL); } /* * iterateProperty: * * cookie = 0 --> starting at beginning. * ret 1 if key value are valid. * ret 0 if end of list. * */ int iteratePropertyList(plist_t plist, plist_entry_t * cookie, char ** key, char ** value) { if (!plist) return 0; if (!*cookie) { *cookie = plist->head; }else{ *cookie = (*cookie)->next; } if (!*cookie) return 0; *key = strdup((*cookie)->key); *value = strdup((*cookie)->value); return 1; } /** * plistEqual: * * returns 1 if equal, 0 if not. */ int plistEqual(plist_t one, plist_t two) { plist_entry_t one_ptr; plist_entry_t two_ptr; /* * If they're both NULL then true. * XXX. This is a hack. We should really use NULL plist_t with * null head and tail instead of a null pointer for a null property * list. */ if (!one && !two) return 1; if ((!one && two) || (one && !two)) return 0; for (one_ptr = one->head; one_ptr; one_ptr = one_ptr->next) { for (two_ptr = two->head; two_ptr; two_ptr = two_ptr->next) { if (!strcmp(one_ptr->key, two_ptr->key)) { if (!strcmp(one_ptr->value, two_ptr->value)) { break; } else { return 0; } } } if (!two_ptr) return 0; } return 1; } /** * For debugging.... */ void dumpPropertyList(plist_t plist) { int ret; char * curkey; char * curval; plist_entry_t cookie; fprintf(stderr, "plist dump:\n"); if (!plist) { fprintf(stderr, "plist empty.\n"); return; } cookie = 0; ret = iteratePropertyList(plist, &cookie, &curkey, &curval); while(ret) { fprintf(stderr, "key '%s' val '%s'\n", curkey, curval); free(curkey); free(curval); ret = iteratePropertyList(plist, &cookie, &curkey, &curval); } fprintf(stderr, "\n"); } /* * Interface version 2.0 routines: */ static unsigned long getPlistSize(plist_t plist) { unsigned long curSize; plist_entry_t entry; for (entry = plist->head, curSize = 0; entry; entry = entry->next) { if (!entry->key) continue; curSize += strlen(entry->key) + 1; curSize += strlen(entry->value) + 1; } return (curSize); } char * marshallPlist(plist_t plist, unsigned long * length) { unsigned long plen; char * ptr; char * packagedPlist; plist_entry_t entry; *length = plen = getPlistSize(plist) + 1; ptr = packagedPlist = (char *)malloc(plen); for (entry = plist->head; entry; entry = entry->next) { if (!entry->key) continue; strcpy(ptr, entry->key); ptr += strlen(ptr) + 1; strcpy(ptr, entry->value); ptr += strlen(ptr) + 1; } *ptr = '\0'; return (packagedPlist); } plist_t unmarshallPlist(char * marshalledPlist, unsigned long plist_length) { char *key; char *value; unsigned long outOfBounds; plist_t plist; if (!marshalledPlist || !plist_length) return 0; if (!(plist = createPropertyList())) return 0; outOfBounds = ((unsigned long)marshalledPlist + plist_length); for (key = marshalledPlist; *key && (unsigned long)key < outOfBounds;) { /* XXX need strnlen to make sure we don't go out on string * length calcs. */ value = key + strlen(key) + 1; /* Invalid plist: */ if ((unsigned long)value >= outOfBounds) { destroyPropertyList(plist); return 0; } if (!updateProperty(plist, key, value)) { destroyPropertyList(plist); return 0; } key = (char *)((unsigned long)value + strlen(value) + 1); } return (plist); }