X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=libcitadel%2Flib%2Fhash.c;h=f6adc2a9b43b649e6740505f47e1d642b4559068;hb=d974a48b3dbf9f3bda27b73990087f88eca08dbe;hp=bd22f10a8f35df74d5c1a58e68c7a1e379f7ff38;hpb=3295005f3c652d3cbc384b6f4077a5799a0be4bc;p=citadel.git diff --git a/libcitadel/lib/hash.c b/libcitadel/lib/hash.c index bd22f10a8..f6adc2a9b 100644 --- a/libcitadel/lib/hash.c +++ b/libcitadel/lib/hash.c @@ -1,6 +1,7 @@ #include #include #include +#include //dbg #include #include "libcitadel.h" @@ -426,18 +427,31 @@ static long FindInHash(HashList *Hash, long HashBinKey) /** - * @brief another hashing algorithm; treat it as just a pointer to long. - * @param str Our pointer to the long value + * @brief another hashing algorithm; treat it as just a pointer to int. + * @param str Our pointer to the int value * @param len the length of the data pointed to; needs to be sizeof int, else we won't use it! * \returns the calculated hash value */ -int Flathash(const char *str, long len) +long Flathash(const char *str, long len) { if (len != sizeof (int)) return 0; else return *(int*)str; } +/** + * @brief another hashing algorithm; treat it as just a pointer to long. + * @param str Our pointer to the long value + * @param len the length of the data pointed to; needs to be sizeof long, else we won't use it! + * \returns the calculated hash value + */ +long lFlathash(const char *str, long len) +{ + if (len != sizeof (long)) + return 0; + else return *(long*)str; +} + /** * @brief private abstract wrapper around the hashing algorithm * @param HKey the hash string @@ -972,3 +986,116 @@ int HashLittle(const void *key, size_t length) { return (int)hashlittle(key, length, 1); } + +/** + * \brief parses an MSet string into a list for later use + * \param MSetList List to be read from MSetStr + * \param MSetStr String containing the list + */ +int ParseMSet(MSet **MSetList, StrBuf *MSetStr) +{ + const char *POS = NULL, *SetPOS = NULL; + StrBuf *OneSet; + HashList *ThisMSet; + long StartSet, EndSet; + long *pEndSet; + + *MSetList = NULL; + if ((MSetStr == NULL) || (StrLength(MSetStr) == 0)) + return 0; + + OneSet = NewStrBufPlain(NULL, StrLength(MSetStr)); + + ThisMSet = NewHash(0, lFlathash); + + *MSetList = (MSet*) ThisMSet; + + /* an MSet is a coma separated value list. */ + StrBufExtract_NextToken(OneSet, MSetStr, &POS, ','); + do { + SetPOS = NULL; + + /* One set may consist of two Numbers: Start + optional End */ + StartSet = StrBufExtractNext_long(OneSet, &SetPOS, ':'); + EndSet = 0; /* no range is our default. */ + /* do we have an end (aka range?) */ + if ((SetPOS != NULL) && (SetPOS != StrBufNOTNULL)) + { + if (*(SetPOS) == '*') + EndSet = LONG_MAX; /* ranges with '*' go until infinity */ + else + /* in other cases, get the EndPoint */ + EndSet = StrBufExtractNext_long(OneSet, &SetPOS, ':'); + } + + pEndSet = (long*) malloc (sizeof(long)); + *pEndSet = EndSet; + + Put(ThisMSet, LKEY(StartSet), pEndSet, NULL); + /* if we don't have another, we're done. */ + if (POS == StrBufNOTNULL) + break; + StrBufExtract_NextToken(OneSet, MSetStr, &POS, ','); + } while (1); + FreeStrBuf(&OneSet); + + return 1; +} + +/** + * \brief checks whether a message is inside a mset + * \param MSetList List to search for MsgNo + * \param MsgNo number to search in mset + */ +int IsInMSetList(MSet *MSetList, long MsgNo) +{ + /* basicaly we are a ... */ + long MemberPosition; + HashList *Hash = (HashList*) MSetList; + long HashAt; + long EndAt; + + if (Hash == NULL) + return 0; + if (Hash->MemberSize == 0) + return 0; + /** first, find out were we could fit in... */ + HashAt = FindInHash(Hash, MsgNo); + + /* we're below the first entry, so not found. */ + if (HashAt < 0) + return 0; + /* upper edge? move to last item */ + if (HashAt >= Hash->nMembersUsed) + HashAt = Hash->nMembersUsed - 1; + /* Match? then we got it. */ + else if (Hash->LookupTable[HashAt]->Key == MsgNo) + return 1; + /* One above possible range start? we need to move to the lower one. */ + else if ((HashAt > 0) && + (Hash->LookupTable[HashAt]->Key > MsgNo)) + HashAt -=1; + + /* Fetch the actual data */ + MemberPosition = Hash->LookupTable[HashAt]->Position; + EndAt = *(long*) Hash->Members[MemberPosition]->Data; + if (EndAt == LONG_MAX) + return 1; + /* no range? */ + if (EndAt == 0) + return 0; + /* inside of range? */ + if (EndAt >= MsgNo) + return 1; + return 0; +} + + +/** + * \brief frees a mset [redirects to @ref DeleteHash + * \param FreeMe to be free'd + */ +void DeleteMSet(MSet **FreeMe) +{ + DeleteHash((HashList**) FreeMe); +}