|  | /* | 
|  | ******************************************************************************* | 
|  | * | 
|  | *   Copyright (C) 1998-2000, International Business Machines | 
|  | *   Corporation and others.  All Rights Reserved. | 
|  | * | 
|  | ******************************************************************************* | 
|  | * | 
|  | * File list.c | 
|  | * | 
|  | * Modification History: | 
|  | * | 
|  | *   Date        Name        Description | 
|  | *   06/01/99    stephen     Creation. | 
|  | ******************************************************************************* | 
|  | */ | 
|  |  | 
|  | #include "list.h" | 
|  | #include "cmemory.h" | 
|  | #include "cstring.h" | 
|  | #include "unicode/ustring.h" | 
|  |  | 
|  | /* Protos */ | 
|  | static void strlist_grow(struct SList *list, UErrorCode *status); | 
|  | static void strlist2d_grow(struct SList *list, UErrorCode *status); | 
|  | static void strlist2d_growRows(struct SList *list, UErrorCode *status); | 
|  | static void taglist_grow(struct SList *list, UErrorCode *status); | 
|  |  | 
|  | /* String list */ | 
|  |  | 
|  | struct SList* | 
|  | strlist_open(UErrorCode *status) | 
|  | { | 
|  | struct SList *list; | 
|  |  | 
|  | if(U_FAILURE(*status)) return 0; | 
|  |  | 
|  | list = (struct SList*) uprv_malloc(sizeof(struct SList)); | 
|  | if(list == 0) { | 
|  | *status = U_MEMORY_ALLOCATION_ERROR; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | list->fType = eStringList; | 
|  |  | 
|  | list->u.fStringList.fData = 0; | 
|  | list->u.fStringList.fCount = 0; | 
|  | list->u.fStringList.fCapacity = 32; | 
|  |  | 
|  | strlist_grow(list, status); | 
|  |  | 
|  | return list; | 
|  | } | 
|  |  | 
|  | void | 
|  | strlist_close(struct SList *list, | 
|  | UErrorCode *status) | 
|  | { | 
|  | int32_t i; | 
|  |  | 
|  | if(U_FAILURE(*status)) return; | 
|  |  | 
|  | if(list->fType != eStringList) { | 
|  | *status = U_ILLEGAL_ARGUMENT_ERROR; | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* deallocate each string */ | 
|  | for(i = 0; i < list->u.fStringList.fCount; ++i) { | 
|  | uprv_free(list->u.fStringList.fData[i]); | 
|  | } | 
|  | uprv_free(list->u.fStringList.fData); | 
|  |  | 
|  | list->fType = eEmpty; | 
|  | uprv_free(list); | 
|  | } | 
|  |  | 
|  | void | 
|  | strlist_add(struct SList *list, | 
|  | const UChar *s, | 
|  | UErrorCode *status) | 
|  | { | 
|  | int32_t index; | 
|  |  | 
|  | if(U_FAILURE(*status)) return; | 
|  |  | 
|  | if(list->fType != eStringList) { | 
|  | *status = U_ILLEGAL_ARGUMENT_ERROR; | 
|  | return; | 
|  | } | 
|  |  | 
|  | index = list->u.fStringList.fCount; | 
|  |  | 
|  | if(list->u.fStringList.fCount == list->u.fStringList.fCapacity) | 
|  | strlist_grow(list, status); | 
|  |  | 
|  | list->u.fStringList.fData[index] = (UChar*) | 
|  | uprv_malloc(sizeof(UChar) * (u_strlen(s) + 1)); | 
|  | if(list->u.fStringList.fData[index] == 0) { | 
|  | *status = U_MEMORY_ALLOCATION_ERROR; | 
|  | return; | 
|  | } | 
|  |  | 
|  | u_strcpy(list->u.fStringList.fData[index], s); | 
|  | ++(list->u.fStringList.fCount); | 
|  | } | 
|  |  | 
|  | static void | 
|  | strlist_grow(struct SList *list, | 
|  | UErrorCode *status) | 
|  | { | 
|  | int32_t i, j; | 
|  | int32_t newCapacity; | 
|  | UChar **newData; | 
|  |  | 
|  | if(U_FAILURE(*status)) return; | 
|  |  | 
|  | if(list->fType != eStringList) { | 
|  | *status = U_ILLEGAL_ARGUMENT_ERROR; | 
|  | return; | 
|  | } | 
|  |  | 
|  | newCapacity = list->u.fStringList.fCapacity << 1; | 
|  |  | 
|  | /* allocate space for the array of strings */ | 
|  | newData = (UChar**) uprv_malloc(sizeof(UChar*) * newCapacity); | 
|  | if(newData == 0) { | 
|  | *status = U_MEMORY_ALLOCATION_ERROR; | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* allocate and copy each string */ | 
|  | for(i = 0; i < list->u.fStringList.fCount; ++i) { | 
|  | newData[i] = (UChar*) | 
|  | uprv_malloc(sizeof(UChar) * (u_strlen(list->u.fStringList.fData[i]) + 1)); | 
|  | if(newData[i] == 0) { | 
|  | *status = U_MEMORY_ALLOCATION_ERROR; | 
|  | for(j = 0; j < i; ++j) | 
|  | uprv_free(newData[j]); | 
|  | uprv_free(newData); | 
|  | return; | 
|  | } | 
|  | u_strcpy(newData[i], list->u.fStringList.fData[i]); | 
|  | } | 
|  |  | 
|  | uprv_free(list->u.fStringList.fData); | 
|  | list->u.fStringList.fData = newData; | 
|  | list->u.fStringList.fCapacity = newCapacity; | 
|  | } | 
|  |  | 
|  | /* 2-d String list*/ | 
|  |  | 
|  | struct SList* | 
|  | strlist2d_open(UErrorCode *status) | 
|  | { | 
|  | struct SList *list; | 
|  |  | 
|  | if(U_FAILURE(*status)) return 0; | 
|  |  | 
|  | list = (struct SList*) uprv_malloc(sizeof(struct SList)); | 
|  | if(list == 0) { | 
|  | *status = U_MEMORY_ALLOCATION_ERROR; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | list->fType = eStringList2d; | 
|  |  | 
|  | list->u.fStringList2d.fData = 0; | 
|  | list->u.fStringList2d.fCount = 0; | 
|  | list->u.fStringList2d.fCapacity = 32; | 
|  |  | 
|  | list->u.fStringList2d.fRows = 0; | 
|  | list->u.fStringList2d.fRowCount = 0; | 
|  | list->u.fStringList2d.fRowCapacity = 32; | 
|  |  | 
|  | strlist2d_grow(list, status); | 
|  | strlist2d_growRows(list, status); | 
|  |  | 
|  | if(U_SUCCESS(*status)) { | 
|  | list->u.fStringList2d.fRows[0] = 0; | 
|  | list->u.fStringList2d.fRowCount = 1; | 
|  | } | 
|  |  | 
|  | return list; | 
|  | } | 
|  |  | 
|  | void | 
|  | strlist2d_close(struct SList *list, | 
|  | UErrorCode *status) | 
|  | { | 
|  | int32_t i; | 
|  |  | 
|  | if(U_FAILURE(*status)) return; | 
|  |  | 
|  | if(list->fType != eStringList2d) { | 
|  | *status = U_ILLEGAL_ARGUMENT_ERROR; | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* deallocate each string */ | 
|  | for(i = 0; i < list->u.fStringList2d.fCount; ++i) { | 
|  | uprv_free(list->u.fStringList2d.fData[i]); | 
|  | } | 
|  | uprv_free(list->u.fStringList2d.fData); | 
|  |  | 
|  | uprv_free(list->u.fStringList2d.fRows); | 
|  |  | 
|  | list->fType = eEmpty; | 
|  | uprv_free(list); | 
|  | } | 
|  |  | 
|  | void | 
|  | strlist2d_newRow(struct SList *list, | 
|  | UErrorCode *status) | 
|  | { | 
|  | if(U_FAILURE(*status)) return; | 
|  |  | 
|  | if(list->fType != eStringList2d) { | 
|  | *status = U_ILLEGAL_ARGUMENT_ERROR; | 
|  | return; | 
|  | } | 
|  |  | 
|  | if(list->u.fStringList2d.fRowCount == list->u.fStringList2d.fRowCapacity) | 
|  | strlist2d_growRows(list, status); | 
|  | if(U_FAILURE(*status)) return; | 
|  | list->u.fStringList2d.fRows[(list->u.fStringList2d.fRowCount)++] = | 
|  | list->u.fStringList2d.fCount; | 
|  | } | 
|  |  | 
|  | void strlist2d_add(struct SList *list, | 
|  | const UChar *s, | 
|  | UErrorCode *status) | 
|  | { | 
|  | int32_t index; | 
|  |  | 
|  | if(U_FAILURE(*status)) return; | 
|  |  | 
|  | if(list->fType != eStringList2d) { | 
|  | *status = U_ILLEGAL_ARGUMENT_ERROR; | 
|  | return; | 
|  | } | 
|  |  | 
|  | index = list->u.fStringList2d.fCount; | 
|  |  | 
|  | if(list->u.fStringList2d.fCount == list->u.fStringList2d.fCapacity) | 
|  | strlist2d_grow(list, status); | 
|  |  | 
|  | list->u.fStringList2d.fData[index] = (UChar*) | 
|  | uprv_malloc(sizeof(UChar) * (u_strlen(s) + 1)); | 
|  | if(list->u.fStringList2d.fData[index] == 0) { | 
|  | *status = U_MEMORY_ALLOCATION_ERROR; | 
|  | return; | 
|  | } | 
|  |  | 
|  | u_strcpy(list->u.fStringList2d.fData[index], s); | 
|  | ++(list->u.fStringList2d.fCount); | 
|  | } | 
|  |  | 
|  | static void | 
|  | strlist2d_grow(struct SList *list, | 
|  | UErrorCode *status) | 
|  | { | 
|  | int32_t i, j; | 
|  | int32_t newCapacity; | 
|  | UChar **newData; | 
|  |  | 
|  | if(U_FAILURE(*status)) return; | 
|  |  | 
|  | if(list->fType != eStringList2d) { | 
|  | *status = U_ILLEGAL_ARGUMENT_ERROR; | 
|  | return; | 
|  | } | 
|  |  | 
|  | newCapacity = list->u.fStringList2d.fCapacity << 1; | 
|  |  | 
|  | /* allocate space for the array of strings */ | 
|  | newData = (UChar**) uprv_malloc(sizeof(UChar*) * newCapacity); | 
|  | if(newData == 0) { | 
|  | *status = U_MEMORY_ALLOCATION_ERROR; | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* allocate and copy each string */ | 
|  | for(i = 0; i < list->u.fStringList2d.fCount; ++i) { | 
|  | newData[i] = (UChar*) | 
|  | uprv_malloc(sizeof(UChar) * (u_strlen(list->u.fStringList2d.fData[i]) + 1)); | 
|  | if(newData[i] == 0) { | 
|  | *status = U_MEMORY_ALLOCATION_ERROR; | 
|  | for(j = 0; j < i; ++j) | 
|  | uprv_free(newData[j]); | 
|  | uprv_free(newData); | 
|  | return; | 
|  | } | 
|  | u_strcpy(newData[i], list->u.fStringList2d.fData[i]); | 
|  | } | 
|  |  | 
|  | uprv_free(list->u.fStringList2d.fData); | 
|  | list->u.fStringList2d.fData = newData; | 
|  | list->u.fStringList2d.fCapacity = newCapacity; | 
|  | } | 
|  |  | 
|  | static void | 
|  | strlist2d_growRows(struct SList *list, | 
|  | UErrorCode *status) | 
|  | { | 
|  | int32_t i; | 
|  | int32_t newCapacity; | 
|  | int32_t *newRows; | 
|  |  | 
|  | if(U_FAILURE(*status)) return; | 
|  |  | 
|  | if(list->fType != eStringList2d) { | 
|  | *status = U_ILLEGAL_ARGUMENT_ERROR; | 
|  | return; | 
|  | } | 
|  |  | 
|  | newCapacity = list->u.fStringList2d.fRowCapacity << 1; | 
|  |  | 
|  | /* allocate space for the array of ints */ | 
|  | newRows = (int32_t*) uprv_malloc(sizeof(int32_t) * newCapacity); | 
|  | if(newRows == 0) { | 
|  | *status = U_MEMORY_ALLOCATION_ERROR; | 
|  | } | 
|  |  | 
|  | /* copy each int */ | 
|  | for(i = 0; i < list->u.fStringList2d.fRowCount; ++i) | 
|  | newRows[i] = list->u.fStringList2d.fRows[i]; | 
|  |  | 
|  | /* clean up */ | 
|  | uprv_free(list->u.fStringList2d.fRows); | 
|  | list->u.fStringList2d.fRows = newRows; | 
|  | list->u.fStringList2d.fRowCapacity = newCapacity; | 
|  | } | 
|  |  | 
|  | /* Tagged list */ | 
|  |  | 
|  | struct SList* | 
|  | taglist_open(UErrorCode *status) | 
|  | { | 
|  | struct SList *list; | 
|  |  | 
|  | if(U_FAILURE(*status)) return 0; | 
|  |  | 
|  | list = (struct SList*) uprv_malloc(sizeof(struct SList)); | 
|  | if(list == 0) { | 
|  | *status = U_MEMORY_ALLOCATION_ERROR; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | list->fType = eTaggedList; | 
|  |  | 
|  | /*list->u.fTaggedList.fData = 0;*/ | 
|  | list->u.fTaggedList.fFirst = NULL; | 
|  | list->u.fTaggedList.fCount = 0; | 
|  | /*list->u.fTaggedList.fCapacity = 32;*/ | 
|  |  | 
|  | /*taglist_grow(list, status);*/ | 
|  |  | 
|  | return list; | 
|  | } | 
|  |  | 
|  | void | 
|  | taglist_close(struct SList *list, | 
|  | UErrorCode *status) | 
|  | { | 
|  | struct SStringPair *current; | 
|  | struct SStringPair *prev; | 
|  | if(U_FAILURE(*status)) return; | 
|  |  | 
|  | if(list->fType != eTaggedList) { | 
|  | *status = U_ILLEGAL_ARGUMENT_ERROR; | 
|  | return; | 
|  | } | 
|  |  | 
|  | current = list->u.fTaggedList.fFirst; | 
|  |  | 
|  | while(current != NULL) { | 
|  | prev = current; | 
|  | current = current->fNext; | 
|  | uprv_free(prev); | 
|  | } | 
|  |  | 
|  |  | 
|  | /*uprv_free(list->u.fTaggedList.fData);*/ | 
|  |  | 
|  | list->fType = eEmpty; | 
|  | uprv_free(list); | 
|  | } | 
|  |  | 
|  |  | 
|  | void | 
|  | taglist_add(struct SList *list, | 
|  | const UChar *tag, | 
|  | const UChar *data, | 
|  | UErrorCode *status) | 
|  | { | 
|  | /*int32_t index;*/ | 
|  | struct SStringPair *pair = NULL; | 
|  | struct SStringPair *current = NULL; | 
|  | struct SStringPair *prev = NULL; | 
|  |  | 
|  | if(U_FAILURE(*status)) return; | 
|  |  | 
|  | if(list->fType != eTaggedList) { | 
|  | *status = U_ILLEGAL_ARGUMENT_ERROR; | 
|  | return; | 
|  | } | 
|  |  | 
|  | pair = (struct SStringPair *) uprv_malloc(sizeof(struct SStringPair)); | 
|  | if(pair->fKey == 0) { | 
|  | *status = U_MEMORY_ALLOCATION_ERROR; | 
|  | return; | 
|  | } | 
|  |  | 
|  |  | 
|  | pair->fKey = (char*) uprv_malloc(sizeof(char) * (u_strlen(tag) + 1)); | 
|  | if(pair->fKey == 0) { | 
|  | *status = U_MEMORY_ALLOCATION_ERROR; | 
|  | uprv_free(pair); | 
|  | return; | 
|  | } | 
|  |  | 
|  | pair->fValue = (UChar*) uprv_malloc(sizeof(UChar) * (u_strlen(data) + 1)); | 
|  | if(pair->fValue == 0) { | 
|  | *status = U_MEMORY_ALLOCATION_ERROR; | 
|  | uprv_free(pair->fKey); | 
|  | uprv_free(pair); | 
|  | return; | 
|  | } | 
|  |  | 
|  | ++(list->u.fTaggedList.fCount); | 
|  |  | 
|  | /*u_strcpy(pair.fKey, tag);*/ | 
|  | u_UCharsToChars(tag, pair->fKey, u_strlen(tag)+1); | 
|  | u_strcpy(pair->fValue, data); | 
|  |  | 
|  | /* is list still empty? */ | 
|  | if(list->u.fTaggedList.fFirst == NULL) { | 
|  | list->u.fTaggedList.fFirst = pair; | 
|  | pair->fNext = NULL; | 
|  | return; | 
|  | } else { | 
|  | current = list->u.fTaggedList.fFirst; | 
|  | } | 
|  |  | 
|  | while(current != NULL) { | 
|  | if(uprv_strcmp(current->fKey, pair->fKey)<0) { | 
|  | prev = current; | 
|  | current = current->fNext; | 
|  | } else { /*we're either in front of list, or in middle*/ | 
|  | if(prev == NULL) { /*front of the list*/ | 
|  | list->u.fTaggedList.fFirst = pair; | 
|  | } else { /*middle of the list*/ | 
|  | prev->fNext = pair; | 
|  | } | 
|  | pair->fNext = current; | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* end of list */ | 
|  | prev->fNext = pair; | 
|  | pair->fNext = NULL; | 
|  |  | 
|  | /*index = list->u.fTaggedList.fCount;*/ | 
|  |  | 
|  | /*if(list->u.fTaggedList.fCount == list->u.fTaggedList.fCapacity)*/ | 
|  | /*taglist_grow(list, status);*/ | 
|  |  | 
|  | /*list->u.fTaggedList.fData[index] = pair;*/ | 
|  | } | 
|  |  | 
|  | const UChar* | 
|  | taglist_get(const struct SList *list, | 
|  | const char *tag, | 
|  | UErrorCode *status) | 
|  | { | 
|  | /*int32_t i;*/ | 
|  | struct SStringPair *current; | 
|  |  | 
|  | if(U_FAILURE(*status)) return 0; | 
|  |  | 
|  | if(list->fType != eTaggedList) { | 
|  | *status = U_ILLEGAL_ARGUMENT_ERROR; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* is list still empty? */ | 
|  | if(list->u.fTaggedList.fFirst == NULL) { | 
|  | return NULL; | 
|  | } else { | 
|  | current = list->u.fTaggedList.fFirst; | 
|  | } | 
|  |  | 
|  | while(current != NULL) { | 
|  | if(uprv_strcmp(current->fKey, tag)!=0) { | 
|  | current = current->fNext; | 
|  | } else { /*we're either in front of list, or in middle*/ | 
|  | return current->fValue; | 
|  | } | 
|  | } | 
|  |  | 
|  | return NULL; | 
|  | } |