107#include "qinternal.h"
108#include "utilities/qencode.h"
109#include "utilities/qfile.h"
110#include "utilities/qhash.h"
111#include "utilities/qio.h"
112#include "utilities/qstring.h"
113#include "utilities/qtime.h"
114#include "containers/qlisttbl.h"
118static qlisttbl_obj_t *newobj(
const char *name,
const void *data,
size_t size);
119static bool insertobj(qlisttbl_t *tbl, qlisttbl_obj_t *obj);
120static qlisttbl_obj_t *findobj(qlisttbl_t *tbl,
const char *name, qlisttbl_obj_t *retobj);
122static bool namematch(qlisttbl_obj_t *obj,
const char *name, uint32_t hash);
123static bool namecasematch(qlisttbl_obj_t *obj,
const char *name, uint32_t hash);
150 qlisttbl_t *tbl = (qlisttbl_t *)calloc(1,
sizeof(qlisttbl_t));
188 tbl->namematch = namematch;
189 tbl->namecmp = strcmp;
192 if (options & QLISTTBL_THREADSAFE) {
193 Q_MUTEX_NEW(tbl->qmutex,
true);
194 if (tbl->qmutex == NULL) {
200 if (options & QLISTTBL_UNIQUE) {
203 if (options & QLISTTBL_CASEINSENSITIVE) {
204 tbl->namematch = namecasematch;
205 tbl->namecmp = strcasecmp;
207 if (options & QLISTTBL_INSERTTOP) {
208 tbl->inserttop =
true;
210 if (options & QLISTTBL_LOOKUPFORWARD) {
211 tbl->lookupforward =
true;
247bool qlisttbl_put(qlisttbl_t *tbl,
const char *name,
const void *data,
size_t size) {
249 qlisttbl_obj_t *obj = newobj(name, data, size);
265 if (tbl->inserttop ==
false) {
266 obj->prev = tbl->last;
270 obj->next = tbl->first;
294 size_t size = (str) ? (strlen(str) + 1) : 0;
295 return qlisttbl_put(tbl, name, (
const void *)str, size);
312 DYNAMIC_VSPRINTF(str, format);
342 snprintf(str,
sizeof(str),
"%"PRId64, num);
385void *
qlisttbl_get(qlisttbl_t *tbl,
const char *name,
size_t *size,
bool newmem) {
393 qlisttbl_obj_t *obj = findobj(tbl, name, NULL);
396 if (newmem ==
true) {
397 data = malloc(obj->size);
403 memcpy(data, obj->data, obj->size);
409 if (size != NULL) *size = obj->size;
498 qlisttbl_data_t *objs = NULL;
499 size_t allocobjs = 0;
503 memset((
void *)&obj, 0,
sizeof(obj));
505 while (tbl->getnext(tbl, &obj, name, newmem) ==
true) {
509 if (numfound >= allocobjs) {
510 if (allocobjs == 0) allocobjs = 10;
512 objs = (qlisttbl_data_t *)realloc(objs,
sizeof(qlisttbl_data_t) * allocobjs);
514 DEBUG(
"qlisttbl->getmulti(): Memory reallocation failure.");
521 qlisttbl_data_t *newobj = &objs[numfound - 1];
522 newobj->data = obj.data;
523 newobj->size = obj.size;
524 newobj->type = (newmem ==
false) ? 1 : 2;
527 if (newmem ==
true) {
528 if (obj.name != NULL) free(obj.name);
532 newobj = &objs[numfound];
533 memset((
void *)newobj,
'\0',
sizeof(qlisttbl_data_t));
539 if (numobjs != NULL) {
565 if (objs == NULL)
return;
567 qlisttbl_data_t *obj;
568 for (obj = &objs[0]; obj->type == 2; obj++) {
569 if (obj->data != NULL) free(obj->data);
584 if (name == NULL)
return false;
586 size_t numremoved = 0;
589 memset((
void*)&obj, 0,
sizeof(obj));
626 if (obj == NULL)
return false;
631 qlisttbl_obj_t *prev = obj->prev;
632 qlisttbl_obj_t *next = obj->next;
635 qlisttbl_obj_t *
this = NULL;
636 if (prev != NULL)
this = prev->next;
637 else if (next != NULL)
this = next->prev;
638 else this = tbl->first;
643 DEBUG(
"qlisttbl->removeobj(): Can't verify object.");
649 if (prev == NULL) tbl->first = next;
650 else prev->next = next;
652 if (next == NULL) tbl->last = prev;
653 else next->prev = prev;
717 if (obj == NULL)
return NULL;
721 qlisttbl_obj_t *cont = NULL;
722 if (obj->size == 0) {
724 cont = (tbl->lookupforward) ? tbl->first : tbl->last;
726 cont = findobj(tbl, name, NULL);
729 cont = (tbl->lookupforward) ? obj->next : obj->prev;
738 uint32_t hash = (name != NULL) ?
qhashmurmur3_32(name, strlen(name)) : 0;
741 while (cont != NULL) {
742 if (name == NULL || tbl->namematch(cont, name, hash) ==
true) {
743 if (newmem ==
true) {
744 obj->name = strdup(cont->name);
745 obj->data = malloc(cont->size);
746 if (obj->name == NULL || obj->data == NULL) {
747 if (obj->name != NULL) free(obj->name);
748 if (obj->data != NULL) free(obj->data);
754 memcpy(obj->data, cont->data, cont->size);
756 obj->name = cont->name;
757 obj->data = cont->data;
759 obj->hash = cont->hash;
760 obj->size = cont->size;
761 obj->prev = cont->prev;
762 obj->next = cont->next;
768 cont = (tbl->lookupforward) ? cont->next : cont->prev;
815 qlisttbl_obj_t *obj1, *obj2;
816 qlisttbl_obj_t tmpobj;
818 for (n = tbl->num; n > 0;) {
820 for (i = 0, obj1 = tbl->first; i < (n - 1); i++, obj1 = obj1->next) {
822 if (tbl->namecmp(obj1->name, obj2->name) > 0) {
825 obj1->hash = obj2->hash;
826 obj1->name = obj2->name;
827 obj1->data = obj2->data;
828 obj1->size = obj2->size;
829 obj2->hash = tmpobj.hash;
830 obj2->name = tmpobj.name;
831 obj2->data = tmpobj.data;
832 obj2->size = tmpobj.size;
850 for (obj = tbl->first; obj != NULL;) {
851 qlisttbl_obj_t *next = obj->next;
881 if (filepath == NULL) {
887 if ((fd = open(filepath, O_CREAT|O_WRONLY|O_TRUNC, (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH))) < 0) {
888 DEBUG(
"qlisttbl->save(): Can't open file %s", filepath);
893 qio_printf(fd, -1,
"# %s %s\n", filepath, gmtstr);
898 for (obj = tbl->first; obj; obj = obj->next) {
900 if (encode ==
true) encval =
qurl_encode(obj->data, obj->size);
901 else encval = obj->data;
902 qio_printf(fd, -1,
"%s%c%s\n", obj->name, sepchar, encval);
903 if (encode ==
true) free(encval);
928 if (str == NULL)
return -1;
934 for (offset = str; *offset !=
'\0'; ) {
936 for (buf = offset; *offset !=
'\n' && *offset !=
'\0'; offset++);
937 if (*offset !=
'\0') {
944 if ((buf[0] ==
'#') || (buf[0] ==
'\0'))
continue;
947 char *data = strdup(buf);
948 char *name = _q_makeword(data, sepchar);
983 for (obj = tbl->first; obj; obj = obj->next) {
984 fprintf(out,
"%s=" , obj->name);
985 _q_textout(out, obj->data, obj->size, MAX_HUMANOUT);
986 fprintf(out,
" (%zu, %08x)\n" , obj->size, obj->hash);
1003 Q_MUTEX_ENTER(tbl->qmutex);
1012 Q_MUTEX_LEAVE(tbl->qmutex);
1022 Q_MUTEX_DESTROY(tbl->qmutex);
1026#ifndef _DOXYGEN_SKIP
1029static qlisttbl_obj_t *newobj(
const char *name,
const void *data,
size_t size) {
1030 if (name == NULL || data == NULL || size <= 0) {
1036 char *dup_name = strdup(name);
1037 void *dup_data = malloc(size);
1038 qlisttbl_obj_t *obj = (qlisttbl_obj_t *)malloc(
sizeof(qlisttbl_obj_t));
1039 if (dup_name == NULL || dup_data == NULL || obj == NULL) {
1040 if (dup_name != NULL) free(dup_name);
1041 if (dup_data != NULL) free(dup_data);
1042 if (obj != NULL) free(obj);
1046 memcpy(dup_data, data, size);
1047 memset((
void *)obj,
'\0',
sizeof(qlisttbl_obj_t));
1050 obj->name = dup_name;
1051 obj->data = dup_data;
1058static bool insertobj(qlisttbl_t *tbl, qlisttbl_obj_t *obj) {
1062 qlisttbl_obj_t *prev = obj->prev;
1063 qlisttbl_obj_t *next = obj->next;
1065 if (prev == NULL) tbl->first = obj;
1066 else prev->next = obj;
1068 if (next == NULL) tbl->last = obj;
1069 else next->prev = obj;
1078static qlisttbl_obj_t *findobj(qlisttbl_t *tbl,
const char *name, qlisttbl_obj_t *retobj) {
1079 if (retobj != NULL) {
1080 memset((
void *)retobj,
'\0',
sizeof(qlisttbl_obj_t));
1083 if (name == NULL || tbl->num == 0) {
1089 qlisttbl_obj_t *obj = (tbl->lookupforward) ? tbl->first : tbl->last;
1090 while (obj != NULL) {
1092 if (tbl->namematch(obj, name, hash) ==
true) {
1093 if (retobj != NULL) {
1098 obj = (tbl->lookupforward)? obj->next : obj->prev;
1102 if (retobj != NULL) {
1103 if (tbl->inserttop) {
1104 retobj->prev = NULL;
1105 retobj->next = tbl->first;
1107 retobj->prev = tbl->last;
1108 retobj->next = NULL;
1117static bool namematch(qlisttbl_obj_t *obj,
const char *name, uint32_t hash) {
1118 if ((obj->hash == hash) && !strcmp(obj->name, name)) {
1124static bool namecasematch(qlisttbl_obj_t *obj,
const char *name, uint32_t hash) {
1125 if (!strcasecmp(obj->name, name)) {
char * qurl_encode(const void *bin, size_t size)
Encode data using URL encoding (percent encoding).
size_t qurl_decode(char *str)
Decode a URL-encoded string.
void * qfile_load(const char *filepath, size_t *nbytes)
Load a file into memory.
uint32_t qhashmurmur3_32(const void *data, size_t nbytes)
Get 32-bit Murmur3 hash.
ssize_t qio_printf(int fd, int timeoutms, const char *format,...)
Write formatted output to a file descriptor.
qlisttbl_data_t * qlisttbl_getmulti(qlisttbl_t *tbl, const char *name, bool newmem, size_t *numobjs)
qlisttbl->getmulti(): Finds all objects with the given name and returns an array of objects.
bool qlisttbl_put(qlisttbl_t *tbl, const char *name, const void *data, size_t size)
qlisttbl->put(): Put an element to this table.
qlisttbl_t * qlisttbl(int options)
Create a new Q_LIST linked-list container.
bool qlisttbl_putstrf(qlisttbl_t *tbl, const char *name, const char *format,...)
qlisttbl->putstrf(): Put a formatted string into this table.
void qlisttbl_sort(qlisttbl_t *tbl)
qlisttbl->sort(): Sort keys in this table.
bool qlisttbl_putint(qlisttbl_t *tbl, const char *name, int64_t num)
qlisttbl->putint(): Put an integer into this table as a string.
void qlisttbl_freemulti(qlisttbl_data_t *objs)
qlisttbl->freemulti(): Deallocate object array returned by getmulti().
bool qlisttbl_removeobj(qlisttbl_t *tbl, const qlisttbl_obj_t *obj)
qlisttbl->removeobj(): Remove objects with given object pointer.
size_t qlisttbl_size(qlisttbl_t *tbl)
qlisttbl->size(): Returns the number of elements in this table.
void qlisttbl_free(qlisttbl_t *tbl)
qlisttbl->free(): Free qlisttbl_t
void qlisttbl_lock(qlisttbl_t *tbl)
qlisttbl->lock(): Enter critical section.
void qlisttbl_unlock(qlisttbl_t *tbl)
qlisttbl->unlock(): Leave critical section.
char * qlisttbl_getstr(qlisttbl_t *tbl, const char *name, bool newmem)
qlisttbl->getstr(): Finds an object with given name and returns as string type.
bool qlisttbl_putstr(qlisttbl_t *tbl, const char *name, const char *str)
qlisttbl->putstr(): Put a string into this table.
void qlisttbl_clear(qlisttbl_t *tbl)
qlisttbl->clear(): Removes all of the elements from this table.
bool qlisttbl_save(qlisttbl_t *tbl, const char *filepath, char sepchar, bool encode)
qlisttbl->save(): Save qlisttbl as plain text format Dumping direction is always forward(from the top...
bool qlisttbl_debug(qlisttbl_t *tbl, FILE *out)
qlisttbl->debug(): Prints stored elements for debugging purposes.
bool qlisttbl_getnext(qlisttbl_t *tbl, qlisttbl_obj_t *obj, const char *name, bool newmem)
qlisttbl->getnext(): Get next element.
size_t qlisttbl_remove(qlisttbl_t *tbl, const char *name)
qlisttbl->remove(): Remove matched objects with given name.
void * qlisttbl_get(qlisttbl_t *tbl, const char *name, size_t *size, bool newmem)
qlisttbl->get(): Finds an object with given name.
ssize_t qlisttbl_load(qlisttbl_t *tbl, const char *filepath, char sepchar, bool decode)
qlisttbl->load(): Load and append entries from given filepath Loading direction is always appending a...
int64_t qlisttbl_getint(qlisttbl_t *tbl, const char *name)
qlisttbl->getint(): Finds an object with given name and returns as integer type.
char * qstrtrim(char *str)
Remove whitespace, including CR and LF, from both ends of a string.
char * qtime_gmt_str(time_t utctime)
Get GMT time string formatted like 'Wed, 11-Nov-2007 23:19:25 GMT'.