diff options
Diffstat (limited to 'src/keys/listkey.cpp')
-rw-r--r-- | src/keys/listkey.cpp | 332 |
1 files changed, 332 insertions, 0 deletions
diff --git a/src/keys/listkey.cpp b/src/keys/listkey.cpp new file mode 100644 index 0000000..ffafdd4 --- /dev/null +++ b/src/keys/listkey.cpp @@ -0,0 +1,332 @@ +/****************************************************************************** + * listkey.cpp - code for base class 'ListKey'. ListKey is the basis for all + * types of keys that have lists of specified indexes + * (e.g. a list of verses, place, etc.) + */ + +#include <utilstr.h> +#include <stdlib.h> +#include <swkey.h> +#include <listkey.h> +#include <string.h> + +SWORD_NAMESPACE_START + +static const char *classes[] = {"ListKey", "SWKey", "SWObject", 0}; +SWClass ListKey::classdef(classes); + +/****************************************************************************** + * ListKey Constructor - initializes instance of ListKey + * + * ENT: ikey - text key + */ + +ListKey::ListKey(const char *ikey): SWKey(ikey) { + arraymax = 0; + ClearList(); + init(); +} + + +ListKey::ListKey(ListKey const &k) : SWKey(k.keytext) { + arraymax = k.arraymax; + arraypos = k.arraypos; + arraycnt = k.arraycnt; + array = (arraymax)?(SWKey **)malloc(k.arraymax * sizeof(SWKey *)):0; + for (int i = 0; i < arraycnt; i++) + array[i] = k.array[i]->clone(); + init(); +} + + +void ListKey::init() { + myclass = &classdef; +} + + +SWKey *ListKey::clone() const +{ + return new ListKey(*this); +} + +/****************************************************************************** + * ListKey Destructor - cleans up instance of ListKey + */ + +ListKey::~ListKey() +{ + ClearList(); +} + + +/****************************************************************************** + * ListKey::ClearList - Clears out elements of list + */ + +void ListKey::clear() +{ + int loop; + + if (arraymax) { + for (loop = 0; loop < arraycnt; loop++) + delete array[loop]; + + free(array); + arraymax = 0; + } + arraycnt = 0; + arraypos = 0; + array = 0; +} + + +/****************************************************************************** + * ListKey::copyFrom Equates this ListKey to another ListKey object + * + * ENT: ikey - other ListKey object + */ + +void ListKey::copyFrom(const ListKey &ikey) { + ClearList(); + + arraymax = ikey.arraymax; + arraypos = ikey.arraypos; + arraycnt = ikey.arraycnt; + array = (arraymax)?(SWKey **)malloc(ikey.arraymax * sizeof(SWKey *)):0; + for (int i = 0; i < arraycnt; i++) + array[i] = ikey.array[i]->clone(); + + SetToElement(0); +} + + +/****************************************************************************** + * ListKey::add - Adds an element to the list + */ + +void ListKey::add(const SWKey &ikey) { + if (++arraycnt > arraymax) { + array = (SWKey **) ((array) ? realloc(array, (arraycnt + 32) * sizeof(SWKey *)) : calloc(arraycnt + 32, sizeof(SWKey *))); + arraymax = arraycnt + 32; + } + array[arraycnt-1] = ikey.clone(); + SetToElement(arraycnt-1); +} + + + +/****************************************************************************** + * ListKey::setPosition(SW_POSITION) - Positions this key + * + * ENT: p - position + * + * RET: *this + */ + +void ListKey::setPosition(SW_POSITION p) { + switch (p) { + case 1: // GCC won't compile P_TOP + SetToElement(0, p); + break; + case 2: // GCC won't compile P_BOTTOM + SetToElement(arraycnt-1, p); + break; + } +} + + +/****************************************************************************** + * ListKey::increment - Increments a number of elements + */ + +void ListKey::increment(int step) { + if (step < 0) { + decrement(step*-1); + return; + } + Error(); // clear error + for(; step && !Error(); step--) { + if (arraypos < arraycnt) { + if (array[arraypos]->isBoundSet()) + (*(array[arraypos]))++; + if ((array[arraypos]->Error()) || (!array[arraypos]->isBoundSet())) { + SetToElement(arraypos+1); + } + else SWKey::setText((const char *)(*array[arraypos])); + } + else error = KEYERR_OUTOFBOUNDS; + } +} + + +/****************************************************************************** + * ListKey::decrement - Decrements a number of elements + */ + +void ListKey::decrement(int step) { + if (step < 0) { + increment(step*-1); + return; + } + Error(); // clear error + for(; step && !Error(); step--) { + if (arraypos > -1) { + if (array[arraypos]->isBoundSet()) + (*(array[arraypos]))--; + if ((array[arraypos]->Error()) || (!array[arraypos]->isBoundSet())) { + SetToElement(arraypos-1, BOTTOM); + } + else SWKey::setText((const char *)(*array[arraypos])); + } + else error = KEYERR_OUTOFBOUNDS; + } +} + + +/****************************************************************************** + * ListKey::Count - Returns number of elements in list + */ + +int ListKey::Count() { + return arraycnt; +} + + +/****************************************************************************** + * ListKey::SetToElement - Sets key to element number + * + * ENT: ielement - element number to set to + * + * RET: error status + */ + +char ListKey::SetToElement(int ielement, SW_POSITION pos) { + arraypos = ielement; + if (arraypos >= arraycnt) { + arraypos = (arraycnt>0)?arraycnt - 1:0; + error = KEYERR_OUTOFBOUNDS; + } + else { + if (arraypos < 0) { + arraypos = 0; + error = KEYERR_OUTOFBOUNDS; + } + else { + error = 0; + } + } + + if (arraycnt) { + if (array[arraypos]->isBoundSet()) + (*array[arraypos]) = pos; + SWKey::setText((const char *)(*array[arraypos])); + } + else SWKey::setText(""); + + return error; +} + + +/****************************************************************************** + * ListKey::GetElement - Gets a key element number + * + * ENT: pos - element number to get (or default current) + * + * RET: Key or null on error + */ + +SWKey *ListKey::getElement(int pos) { + if (pos < 0) + pos = arraypos; + + if (pos >=arraycnt) + error = KEYERR_OUTOFBOUNDS; + + return (error) ? 0:array[pos]; +} + + +/****************************************************************************** + * ListKey::Remove - Removes current element from list + */ + +void ListKey::Remove() { + if ((arraypos > -1) && (arraypos < arraycnt)) { + delete array[arraypos]; + if (arraypos < arraycnt - 1) + memmove(&array[arraypos], &array[arraypos+1], (arraycnt - arraypos - 1) * sizeof(SWKey *)); + arraycnt--; + + SetToElement((arraypos)?arraypos-1:0); + } +} + + +/****************************************************************************** + * ListKey::getRangeText - returns parsable range text for this key + */ + +const char *ListKey::getRangeText() const { + char *buf = new char[(arraycnt + 1) * 255]; + buf[0] = 0; + for (int i = 0; i < arraycnt; i++) { + strcat(buf, array[i]->getRangeText()); + if (i < arraycnt-1) + strcat(buf, "; "); + } + stdstr(&rangeText, buf); + delete [] buf; + return rangeText; +} + + +/****************************************************************************** + * ListKey::getText - returns text key if (const char *) cast is requested + */ + +const char *ListKey::getText() const { + int pos = arraypos; + SWKey *key = (pos >= arraycnt) ? 0:array[pos]; + return (key) ? key->getText() : keytext; +} + + +void ListKey::setText(const char *ikey) { + // at least try to set the current element to this text + for (arraypos = 0; arraypos < arraycnt; arraypos++) { + SWKey *key = array[arraypos]; + if (key) { + if (key->isTraversable() && key->isBoundSet()) { + key->setText(ikey); + if (!key->Error()) + break; + } + else { + if (!strcmp(key->getText(), ikey)) + break; + } + } + } + if (arraypos >= arraycnt) { + error = 1; + arraypos = arraycnt-1; + } + + SWKey::setText(ikey); +} + +// This sort impl sucks. Let's change it to a quicksort or some other efficient algol +void ListKey::sort() { + for (int i = 0; i < arraycnt; i++) { + for (int j = i; j < arraycnt; j++) { + if (*array[j] < *array[i]) { + SWKey *tmp = array[i]; + array[i] = array[j]; + array[j] = tmp; + } + } + } +} + +SWORD_NAMESPACE_END + |