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);
152 qlisttbl_t *tbl = (qlisttbl_t *)calloc(1,
sizeof(qlisttbl_t));
190 tbl->namematch = namematch;
191 tbl->namecmp = strcmp;
194 if (options & QLISTTBL_THREADSAFE) {
195 Q_MUTEX_NEW(tbl->qmutex,
true);
196 if (tbl->qmutex == NULL) {
202 if (options & QLISTTBL_UNIQUE) {
205 if (options & QLISTTBL_CASEINSENSITIVE) {
206 tbl->namematch = namecasematch;
207 tbl->namecmp = strcasecmp;
209 if (options & QLISTTBL_INSERTTOP) {
210 tbl->inserttop =
true;
212 if (options & QLISTTBL_LOOKUPFORWARD) {
213 tbl->lookupforward =
true;
249bool qlisttbl_put(qlisttbl_t *tbl,
const char *name,
const void *data,
size_t size)
252 qlisttbl_obj_t *obj = newobj(name, data, size);
268 if (tbl->inserttop ==
false) {
269 obj->prev = tbl->last;
273 obj->next = tbl->first;
298 size_t size = (str) ? (strlen(str) + 1) : 0;
299 return qlisttbl_put(tbl, name, (
const void *)str, size);
317 DYNAMIC_VSPRINTF(str, format);
348 snprintf(str,
sizeof(str),
"%"PRId64, num);
392void *
qlisttbl_get(qlisttbl_t *tbl,
const char *name,
size_t *size,
bool newmem)
401 qlisttbl_obj_t *obj = findobj(tbl, name, NULL);
404 if (newmem ==
true) {
405 data = malloc(obj->size);
411 memcpy(data, obj->data, obj->size);
417 if (size != NULL) *size = obj->size;
507 qlisttbl_data_t *objs = NULL;
508 size_t allocobjs = 0;
512 memset((
void *)&obj, 0,
sizeof(obj));
514 while (tbl->getnext(tbl, &obj, name, newmem) ==
true) {
518 if (numfound >= allocobjs) {
519 if (allocobjs == 0) allocobjs = 10;
521 objs = (qlisttbl_data_t *)realloc(objs,
sizeof(qlisttbl_data_t) * allocobjs);
523 DEBUG(
"qlisttbl->getmulti(): Memory reallocation failure.");
530 qlisttbl_data_t *newobj = &objs[numfound - 1];
531 newobj->data = obj.data;
532 newobj->size = obj.size;
533 newobj->type = (newmem ==
false) ? 1 : 2;
536 if (newmem ==
true) {
537 if (obj.name != NULL) free(obj.name);
541 newobj = &objs[numfound];
542 memset((
void *)newobj,
'\0',
sizeof(qlisttbl_data_t));
548 if (numobjs != NULL) {
575 if (objs == NULL)
return;
577 qlisttbl_data_t *obj;
578 for (obj = &objs[0]; obj->type == 2; obj++) {
579 if (obj->data != NULL) free(obj->data);
595 if (name == NULL)
return false;
597 size_t numremoved = 0;
600 memset((
void*)&obj, 0,
sizeof(obj));
638 if (obj == NULL)
return false;
643 qlisttbl_obj_t *prev = obj->prev;
644 qlisttbl_obj_t *next = obj->next;
647 qlisttbl_obj_t *
this = NULL;
648 if (prev != NULL)
this = prev->next;
649 else if (next != NULL)
this = next->prev;
650 else this = tbl->first;
655 DEBUG(
"qlisttbl->removeobj(): Can't veryfy object.");
661 if (prev == NULL) tbl->first = next;
662 else prev->next = next;
664 if (next == NULL) tbl->last = prev;
665 else next->prev = prev;
730 if (obj == NULL)
return NULL;
734 qlisttbl_obj_t *cont = NULL;
735 if (obj->size == 0) {
737 cont = (tbl->lookupforward) ? tbl->first : tbl->last;
739 cont = findobj(tbl, name, NULL);
742 cont = (tbl->lookupforward) ? obj->next : obj->prev;
751 uint32_t hash = (name != NULL) ?
qhashmurmur3_32(name, strlen(name)) : 0;
754 while (cont != NULL) {
755 if (name == NULL || tbl->namematch(cont, name, hash) ==
true) {
756 if (newmem ==
true) {
757 obj->name = strdup(cont->name);
758 obj->data = malloc(cont->size);
759 if (obj->name == NULL || obj->data == NULL) {
760 if (obj->name != NULL) free(obj->name);
761 if (obj->data != NULL) free(obj->data);
767 memcpy(obj->data, cont->data, cont->size);
769 obj->name = cont->name;
770 obj->data = cont->data;
772 obj->hash = cont->hash;
773 obj->size = cont->size;
774 obj->prev = cont->prev;
775 obj->next = cont->next;
781 cont = (tbl->lookupforward) ? cont->next : cont->prev;
830 qlisttbl_obj_t *obj1, *obj2;
831 qlisttbl_obj_t tmpobj;
833 for (n = tbl->num; n > 0;) {
835 for (i = 0, obj1 = tbl->first; i < (n - 1); i++, obj1 = obj1->next) {
837 if (tbl->namecmp(obj1->name, obj2->name) > 0) {
840 obj1->hash = obj2->hash;
841 obj1->name = obj2->name;
842 obj1->data = obj2->data;
843 obj1->size = obj2->size;
844 obj2->hash = tmpobj.hash;
845 obj2->name = tmpobj.name;
846 obj2->data = tmpobj.data;
847 obj2->size = tmpobj.size;
866 for (obj = tbl->first; obj != NULL;) {
867 qlisttbl_obj_t *next = obj->next;
898 if (filepath == NULL) {
904 if ((fd = open(filepath, O_CREAT|O_WRONLY|O_TRUNC, (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH))) < 0) {
905 DEBUG(
"qlisttbl->save(): Can't open file %s", filepath);
910 qio_printf(fd, -1,
"# %s %s\n", filepath, gmtstr);
915 for (obj = tbl->first; obj; obj = obj->next) {
917 if (encode ==
true) encval =
qurl_encode(obj->data, obj->size);
918 else encval = obj->data;
919 qio_printf(fd, -1,
"%s%c%s\n", obj->name, sepchar, encval);
920 if (encode ==
true) free(encval);
946 if (str == NULL)
return -1;
952 for (offset = str; *offset !=
'\0'; ) {
954 for (buf = offset; *offset !=
'\n' && *offset !=
'\0'; offset++);
955 if (*offset !=
'\0') {
962 if ((buf[0] ==
'#') || (buf[0] ==
'\0'))
continue;
965 char *data = strdup(buf);
966 char *name = _q_makeword(data, sepchar);
1001 qlisttbl_obj_t *obj;
1002 for (obj = tbl->first; obj; obj = obj->next) {
1003 fprintf(out,
"%s=" , obj->name);
1004 _q_textout(out, obj->data, obj->size, MAX_HUMANOUT);
1005 fprintf(out,
" (%zu, %08x)\n" , obj->size, obj->hash);
1023 Q_MUTEX_ENTER(tbl->qmutex);
1033 Q_MUTEX_LEAVE(tbl->qmutex);
1044 Q_MUTEX_DESTROY(tbl->qmutex);
1048#ifndef _DOXYGEN_SKIP
1051static qlisttbl_obj_t *newobj(
const char *name,
const void *data,
size_t size)
1053 if (name == NULL || data == NULL || size <= 0) {
1059 char *dup_name = strdup(name);
1060 void *dup_data = malloc(size);
1061 qlisttbl_obj_t *obj = (qlisttbl_obj_t *)malloc(
sizeof(qlisttbl_obj_t));
1062 if (dup_name == NULL || dup_data == NULL || obj == NULL) {
1063 if (dup_name != NULL) free(dup_name);
1064 if (dup_data != NULL) free(dup_data);
1065 if (obj != NULL) free(obj);
1069 memcpy(dup_data, data, size);
1070 memset((
void *)obj,
'\0',
sizeof(qlisttbl_obj_t));
1073 obj->name = dup_name;
1074 obj->data = dup_data;
1081static bool insertobj(qlisttbl_t *tbl, qlisttbl_obj_t *obj)
1086 qlisttbl_obj_t *prev = obj->prev;
1087 qlisttbl_obj_t *next = obj->next;
1089 if (prev == NULL) tbl->first = obj;
1090 else prev->next = obj;
1092 if (next == NULL) tbl->last = obj;
1093 else next->prev = obj;
1102static qlisttbl_obj_t *findobj(qlisttbl_t *tbl,
const char *name, qlisttbl_obj_t *retobj)
1104 if (retobj != NULL) {
1105 memset((
void *)retobj,
'\0',
sizeof(qlisttbl_obj_t));
1108 if (name == NULL || tbl->num == 0) {
1114 qlisttbl_obj_t *obj = (tbl->lookupforward) ? tbl->first : tbl->last;
1115 while (obj != NULL) {
1117 if (tbl->namematch(obj, name, hash) ==
true) {
1118 if (retobj != NULL) {
1123 obj = (tbl->lookupforward)? obj->next : obj->prev;
1127 if (retobj != NULL) {
1128 if (tbl->inserttop) {
1129 retobj->prev = NULL;
1130 retobj->next = tbl->first;
1132 retobj->prev = tbl->last;
1133 retobj->next = NULL;
1142static bool namematch(qlisttbl_obj_t *obj,
const char *name, uint32_t hash)
1144 if ((obj->hash == hash) && !strcmp(obj->name, name)) {
1150static bool namecasematch(qlisttbl_obj_t *obj,
const char *name, uint32_t hash)
1152 if (!strcasecmp(obj->name, name)) {
char * qurl_encode(const void *bin, size_t size)
Encode data using URL encoding(Percent encoding) algorithm.
size_t qurl_decode(char *str)
Decode URL encoded string.
void * qfile_load(const char *filepath, size_t *nbytes)
Load 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,...)
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 given name and return a 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 string type.
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(): Print out stored elements for debugging purpose.
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 white spaces(including CR, LF) from head and tail of the string.
char * qtime_gmt_str(time_t utctime)
Get GMT time string formatted like 'Wed, 11-Nov-2007 23:19:25 GMT'.