add new qloud-c-sdk component

This commit is contained in:
mculover666
2022-03-25 10:06:56 +08:00
parent 565cd29e94
commit a3ac2e56d8
166 changed files with 35027 additions and 0 deletions

View File

@@ -0,0 +1,142 @@
/**
* @copyright
*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright(C) 2018 - 2021 THL A29 Limited, a Tencent company.All rights reserved.
*
* Licensed under the MIT License(the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
* @file utils_downloader.c
* @brief
* @author fancyxu (fancyxu@tencent.com)
* @version 1.0
* @date 2021-10-18
*
* @par Change Log:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2021-10-18 <td>1.0 <td>fancyxu <td>first commit
* </table>
*/
#include "utils_downloader.h"
/**
* @brief Downloader.
*
*/
typedef struct {
UtilsDownloaderFunction func;
void* usr_data;
} UtilsDownloader;
/**
* @brief Init downloader.
*
* @param[in] func download function should implement
* @param[in] usr_data user data using in function
* @return pointer to downloader
*/
void* utils_downloader_init(UtilsDownloaderFunction func, void* usr_data)
{
if (!func.downloader_malloc) {
return NULL;
}
UtilsDownloader* handle = func.downloader_malloc(sizeof(UtilsDownloader));
if (!handle) {
return NULL;
}
handle->func = func;
handle->usr_data = usr_data;
return handle;
}
/**
* @brief Process download using function.
*
* @param[in,out] handle pointer to downloader
* @return -1 for fail, others see data_download_finish
*/
int utils_downloader_process(void* handle)
{
int rc = -1;
UtilsDownloader* downloader = handle;
UtilsDownloaderStatus status = UTILS_DOWNLOADER_STATUS_SUCCESS;
if (!handle) {
return -1;
}
rc = downloader->func.break_point_init(downloader->usr_data);
if (rc) {
status = UTILS_DOWNLOADER_STATUS_BREAK_POINT_FAILED;
goto exit;
}
// if check ok, restore from break point, otherwise set break point
rc = downloader->func.break_point_check(downloader->usr_data)
? downloader->func.break_point_set(downloader->usr_data)
: downloader->func.break_point_restore(downloader->usr_data);
if (rc) {
status = UTILS_DOWNLOADER_STATUS_BREAK_POINT_FAILED;
goto exit;
}
rc = downloader->func.data_download_init(downloader->usr_data);
if (rc) {
status = UTILS_DOWNLOADER_STATUS_DATA_DOWNLOAD_FAILED;
goto exit;
}
while (!downloader->func.data_download_is_over(downloader->usr_data)) {
rc = downloader->func.data_download_recv(downloader->usr_data);
if (rc < 0) {
status = UTILS_DOWNLOADER_STATUS_NETWORK_FAILED;
goto exit;
}
rc = downloader->func.data_download_save(downloader->usr_data);
if (rc) {
status = UTILS_DOWNLOADER_STATUS_DATA_DOWNLOAD_FAILED;
goto exit;
}
rc = downloader->func.break_point_save(downloader->usr_data);
if (rc) {
status = UTILS_DOWNLOADER_STATUS_BREAK_POINT_FAILED;
goto exit;
}
}
exit:
rc = downloader->func.data_download_finish(downloader->usr_data, status);
downloader->func.break_point_deinit(downloader->usr_data);
downloader->func.data_download_deinit(downloader->usr_data);
return rc;
}
/**
* @brief Deinit downloader.
*
* @param[in,out] handle pointer to downloader
*/
void utils_downloader_deinit(void* handle)
{
UtilsDownloader* downloader = handle;
if (!handle) {
return;
}
downloader->func.downloader_free(handle);
}

View File

@@ -0,0 +1,577 @@
/**
* @copyright
*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright(C) 2018 - 2021 THL A29 Limited, a Tencent company.All rights reserved.
*
* Licensed under the MIT License(the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
* @file utils_json.c
* @brief
* @author fancyxu (fancyxu@tencent.com)
* @version 1.0
* @date 2021-07-25
*
* @par Change Log:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2021-07-25 <td>1.0 <td>fancyxu <td>first commit
* <tr><td>2021-07-29 <td>1.1 <td>fancyxu <td>fix bug and add utils_json_value_data_get
* </table>
*/
#include "utils_json.h"
/**
* @brief Delimiter of json
*
*/
typedef enum {
JSON_DELIMITER_ARRAY_BEGIN = '[',
JSON_DELIMITER_ARRAY_END = ']',
JSON_DELIMITER_OBJECT_BEGIN = '{',
JSON_DELIMITER_OBJECT_END = '}',
JSON_DELIMITER_KEY = '"',
JSON_DELIMITER_VALUE = ':',
JSON_DELIMITER_ELEMENT_END = ',',
JSON_DELIMITER_TYPE_STRING = '"',
JSON_DELIMITER_TYPE_BOOLEAN_TRUE_UPPER = 'T',
JSON_DELIMITER_TYPE_BOOLEAN_TRUE_LOWER = 't',
JSON_DELIMITER_TYPE_BOOLEAN_FALSE_UPPER = 'F',
JSON_DELIMITER_TYPE_BOOLEAN_FALSE_LOWER = 'f',
JSON_DELIMITER_TYPE_NULL_UPPER = 'N',
JSON_DELIMITER_TYPE_NULL_LOWER = 'n',
JSON_DELIMITER_SPACE = ' ',
JSON_DELIMITER_NONE = 0,
} JsonDelimiter;
/**
* @brief Element type support
*
*/
typedef enum {
JSON_ELEMENT_ARRAY = 0,
JSON_ELEMENT_OBJECT,
JSON_ELEMENT_VALUE_STRING,
JSON_ELEMENT_VALUE_NUMBER,
JSON_ELEMENT_VALUE_BOOLEAN,
JSON_ELEMENT_VALUE_NULL,
JSON_ELEMENT_KEY,
} JsonElementType;
/**
* @brief Json Element
*
*/
typedef struct {
JsonElementType type;
char *pos_begin;
char *pos_end;
int element_len;
} JsonElement;
#define json_key JsonElement
#define json_value JsonElement
/**
* @brief Is delimiter begin or end matched
*
*/
typedef struct {
int (*is_begin_matched)(char *str);
int (*is_end_matched)(char *str, int *offset);
} IsDelimiterMatched;
/**
* @brief For array type, when meets '[', means depth++
*
* @param[in] str pointer to char
* @return true for matched
*/
static int _is_array_begin_matched(char *str)
{
return *str == JSON_DELIMITER_ARRAY_BEGIN;
}
/**
* @brief For array type, when meets ']', means depth--
*
* @param[in] str pointer to char
* @param[out] offset offset for pointer to move
* @return true for matched
*/
static int _is_array_end_matched(char *str, int *offset)
{
return *str == JSON_DELIMITER_ARRAY_END;
}
/**
* @brief For object type, when meets '{', means depth++
*
* @param[in] str pointer to char
* @return true for matched
*/
static int _is_object_begin_matched(char *str)
{
return *str == JSON_DELIMITER_OBJECT_BEGIN;
}
/**
* @brief For object type, when meets '}', means depth--
*
* @param[in] str pointer to char
* @param[out] offset offset for pointer to move
* @return true for matched
*/
static int _is_object_end_matched(char *str, int *offset)
{
return *str == JSON_DELIMITER_OBJECT_END;
}
/**
* @brief For string type, when meets '"', but not "\"", means the end
*
* @param[in] str pointer to char
* @param[out] offset offset for pointer to move
* @return true for matched
*/
static int _is_string_end_matched(char *str, int *offset)
{
return *str == '"' && *(str - 1) != '\\';
}
/**
* @brief For number type, when meets not '0~9', '.' or 'f' for float, means the end
*
* @param[in] str pointer to char
* @param[out] offset offset for pointer to move
* @return true for matched
*/
static int _is_number_end_matched(char *str, int *offset)
{
return (*str < '0' || *str > '9') && *str != '.' && *str != 'f' && *str != '-';
}
/**
* @brief For boolen type, when meets "true", "True", "false" or "False", means the end
*
* @param[in] str pointer to char
* @param[out] offset offset for pointer to move, -1 means error
* @return true for matched
*/
static int _is_boolean_end_matched(char *str, int *offset)
{
*offset = !strncmp(str, "true", 4) || !strncmp(str, "TRUE", 4) ? 4 : *offset;
*offset = !strncmp(str, "false", 5) || !strncmp(str, "FALSE", 5) ? 5 : *offset;
if (*offset == 0) {
*offset = -1; // -1 means error
}
return 1;
}
/**
* @brief For boolen type, when meets "null", "NULL", means the end
*
* @param[in] str pointer to char
* @param[out] offset offset for pointer to move, -1 means error
* @return true for matched
*/
static int _is_null_end_matched(char *str, int *offset)
{
*offset = !strncmp(str, "null", 4) || !strncmp(str, "NULL", 4) ? 4 : 0;
if (*offset == 0) {
*offset = -1; // -1 means error
}
return 1;
}
/**
* @brief Table of matched function of elements
*
*/
static IsDelimiterMatched sg_element_matched_func[] = {
{_is_array_begin_matched, _is_array_end_matched}, // JSON_ELEMENT_ARRAY
{_is_object_begin_matched, _is_object_end_matched}, // JSON_ELEMENT_OBJECT
{NULL, _is_string_end_matched}, // JSON_ELEMENT_VALUE_STRING
{NULL, _is_number_end_matched}, // JSON_ELEMENT_VALUE_NUMBER
{NULL, _is_boolean_end_matched}, // JSON_ELEMENT_VALUE_BOOLEAN
{NULL, _is_null_end_matched}, // JSON_ELEMENT_VALUE_NULL
{NULL, NULL}, // JSON_ELEMENT_KEY
};
/**
* @brief Increase pos and decrease remain len
*
* @param[in,out] pos current pos
* @param[in,out] len current len
*/
static void _increase_pos(char **pos, int *len)
{
(*pos)++;
(*len)--;
};
/**
* @brief Find delimiter and return pos
*
* @param[in] ch delimiter character
* @param[in] spilt_char if 0 then spilt nothing but delimiter
* @param[in] str input string
* @param[in,out] remain_len remaining length
* @return NULL for failed
*/
static char *_find_json_delimiter(JsonDelimiter ch, char spilt_char, char *str, int *remain_len)
{
char *pos = NULL;
while ((*remain_len) > 0 && str && *str) {
if ((!spilt_char && *str != ch) || (spilt_char && *str == spilt_char)) {
_increase_pos(&str, remain_len);
continue;
}
pos = (*str == ch) ? str : 0;
break;
}
return pos;
}
/**
* @brief Find element end
*
* @param[in] is_begin_matched using in nesting
* @param[in] is_end_matched match end
* @param[in] str input string
* @param[in,out] remain_len remaining length
* @return NULL for failed
*/
static char *_find_json_value_element_end(int (*is_begin_matched)(char *), int (*is_end_matched)(char *, int *),
char *str, int *remain_len)
{
int offset = 0;
int depth = 0;
char *pos = NULL;
while (str && *str) {
offset = 0;
if (*remain_len <= 0) {
return NULL;
}
if (is_begin_matched) {
if (is_begin_matched(str)) {
depth++;
}
}
if (is_end_matched(str, &offset)) {
if (!depth) {
if (offset < 0) {
break; // failed
}
pos = str + offset;
(*remain_len) -= offset;
break;
}
if (depth > 0) {
depth--;
}
}
str++;
(*remain_len)--;
}
return pos;
}
/**
* @brief Get json key from string
*
* @param[in] node_begin string begin
* @param[in,out] remain_len remaining length
* @param[out] key key node
* @return 0 for success
*/
static int _get_json_key(char *node_begin, int *remain_len, json_key *key)
{
char *key_begin = _find_json_delimiter(JSON_DELIMITER_KEY, JSON_DELIMITER_SPACE, node_begin, remain_len);
if (!key_begin) {
return -1;
}
_increase_pos(&key_begin, remain_len);
char *key_end = _find_json_delimiter(JSON_DELIMITER_KEY, JSON_DELIMITER_NONE, key_begin, remain_len);
if (!key_end) {
return -1;
}
key->type = JSON_ELEMENT_KEY;
key->pos_begin = key_begin;
key->pos_end = key_end;
key->element_len = key_end - key_begin;
return 0;
}
/**
* @brief Get json value from key end
*
* @param[in] key_end end of key
* @param[in,out] remain_len remaining length
* @param[out] value value node
* @return 0 for success
*/
static int _get_json_value(char *key_end, int *remain_len, json_value *value)
{
char *value_begin = _find_json_delimiter(JSON_DELIMITER_VALUE, JSON_DELIMITER_SPACE, key_end, remain_len);
if (!value_begin) {
return -1;
}
_increase_pos(&value_begin, remain_len);
// filter all the space
while (*value_begin == ' ') {
value_begin++;
(*remain_len)--;
if (*remain_len <= 0) {
return -1;
}
};
JsonElementType type;
char *value_end = NULL;
switch (*value_begin) {
case JSON_DELIMITER_ARRAY_BEGIN:
// should + 1 for escape first [
_increase_pos(&value_begin, remain_len);
type = JSON_ELEMENT_ARRAY;
break;
case JSON_DELIMITER_OBJECT_BEGIN:
// should + 1 for escape first {
_increase_pos(&value_begin, remain_len);
type = JSON_ELEMENT_OBJECT;
break;
case JSON_DELIMITER_TYPE_STRING:
// should + 1 for escape first "
_increase_pos(&value_begin, remain_len);
type = JSON_ELEMENT_VALUE_STRING;
break;
case JSON_DELIMITER_TYPE_BOOLEAN_TRUE_UPPER:
case JSON_DELIMITER_TYPE_BOOLEAN_TRUE_LOWER:
case JSON_DELIMITER_TYPE_BOOLEAN_FALSE_UPPER:
case JSON_DELIMITER_TYPE_BOOLEAN_FALSE_LOWER:
type = JSON_ELEMENT_VALUE_BOOLEAN;
break;
case JSON_DELIMITER_TYPE_NULL_UPPER:
case JSON_DELIMITER_TYPE_NULL_LOWER:
type = JSON_ELEMENT_VALUE_NULL;
break;
default:
type = JSON_ELEMENT_VALUE_NUMBER;
break;
}
value_end = _find_json_value_element_end(sg_element_matched_func[type].is_begin_matched,
sg_element_matched_func[type].is_end_matched, value_begin, remain_len);
if (!value_end) {
return -1;
}
int is_object_or_array = (type == JSON_ELEMENT_ARRAY || type == JSON_ELEMENT_OBJECT);
int is_object_or_array_or_string = (is_object_or_array || type == JSON_ELEMENT_VALUE_STRING);
value->type = type;
value->pos_begin = value_begin - is_object_or_array; // include '[' or '{'
value->element_len = value_end - value->pos_begin + is_object_or_array; // include ']' or '}'
value->pos_end = value_end + is_object_or_array_or_string; // filter '"' , ']' or '}'
return 0;
}
/**
* @brief Get value by key from json string
*
* @param[in] str json string
* @param[in] str_len strign length
* @param[in] key key
* @param[in] key_len key length
* @param[out] value value
* @return 0 for success
*/
int json_get_value_by_key(const char *str, int str_len, const char *key, int key_len, json_value *value)
{
int rc = 0;
char *object_begin = NULL;
json_key key_found = {JSON_ELEMENT_KEY, 0, 0, 0};
object_begin = _find_json_delimiter(JSON_DELIMITER_OBJECT_BEGIN, JSON_DELIMITER_SPACE, (char *)str, &str_len);
if (!object_begin) {
return -1;
}
_increase_pos(&object_begin, &str_len);
do {
rc = _get_json_key(object_begin, &str_len, &key_found);
if (rc) {
break;
}
_increase_pos(&key_found.pos_end, &str_len);
rc = _get_json_value(key_found.pos_end, &str_len, value);
if (rc) {
break;
}
// NULL of object begin can be ok for reach the end of str
object_begin = _find_json_delimiter(JSON_DELIMITER_ELEMENT_END, JSON_DELIMITER_SPACE, value->pos_end, &str_len);
if (object_begin) {
_increase_pos(&object_begin, &str_len);
}
} while (key_len != key_found.element_len || strncmp(key, key_found.pos_begin, key_found.element_len));
return rc;
}
/**
* @brief Get value from json string. Not strict, just for iot scene, we suppose all the string is valid json.
*
* @param[in] key key in json, support nesting with '.'
* @param[in] key_len key len
* @param[in] src json string
* @param[in] src_len src length
* @param[out] value value
* @return 0 for success
*/
int utils_json_value_get(const char *key, int key_len, const char *src, int src_len, UtilsJsonValue *value)
{
int rc = 0;
char *delim = NULL;
char *src_iter = (char *)src;
int src_iter_len = src_len;
char *key_iter = (char *)key;
char *key_next = NULL;
int key_next_len = 0;
json_value value_tmp;
// key can be separated by '.', such as: outer_key.(.......).inner_key
while ((delim = strchr(key_iter, '.'))) {
key_next = key_iter;
key_next_len = delim - key_iter;
rc = json_get_value_by_key(src_iter, src_iter_len, key_next, key_next_len, &value_tmp);
if (rc) {
return rc;
}
src_iter = value_tmp.pos_begin;
src_iter_len = value_tmp.element_len;
key_iter = delim + 1;
}
// found inner key and get value
rc = json_get_value_by_key(src_iter, src_iter_len, key_iter, key_len + key - key_iter, &value_tmp);
if (rc) {
return rc;
}
value->value = value_tmp.pos_begin;
value->value_len = value_tmp.element_len;
return 0;
}
/**
* @brief Get data of value with type.
*
* @param[in] value @see UtilsJsonValue
* @param[in] type value type, string can use value directly. @see UtilsJsonValueType
* @param[out] data data pointer, user should
* @return 0 for success
*/
int utils_json_value_data_get(UtilsJsonValue value, UtilsJsonValueType type, void *data)
{
char value_tmp[32] = {0};
if (value.value_len > sizeof(value_tmp)) {
return -1;
}
strncpy(value_tmp, value.value, value.value_len);
switch (type) {
case UTILS_JSON_VALUE_TYPE_INT32:
return !(sscanf(value_tmp, "%" SCNi32, (int32_t *)data) == 1);
case UTILS_JSON_VALUE_TYPE_INT64:
return !(sscanf(value_tmp, "%" SCNi64, (int64_t *)data) == 1);
case UTILS_JSON_VALUE_TYPE_UINT32:
return !(sscanf(value_tmp, "%" SCNu32, (uint32_t *)data) == 1);
case UTILS_JSON_VALUE_TYPE_UINT64:
return !(sscanf(value_tmp, "%" SCNu64, (uint64_t *)data) == 1);
case UTILS_JSON_VALUE_TYPE_FLOAT:
return !(sscanf(value_tmp, "%f", (float *)data) == 1);
case UTILS_JSON_VALUE_TYPE_DOUBLE:
return !(sscanf(value_tmp, "%lf", (double *)data) == 1);
case UTILS_JSON_VALUE_TYPE_BOOLEAN:
*(int *)data = strcmp(value_tmp, "false");
return 0;
default:
break;
}
return -1;
}
/**
* @brief Return unsigned int value of key in json.
*
* @return 0 for success
*/
int utils_json_get_uint32(const char *key, int key_len, const char *src, int src_len, uint32_t *data)
{
int rc;
UtilsJsonValue tmp;
rc = utils_json_value_get(key, key_len, src, src_len, &tmp);
if (rc) {
return -1;
}
rc = utils_json_value_data_get(tmp, UTILS_JSON_VALUE_TYPE_UINT32, data);
if (rc) {
return -1;
}
return 0;
}
/**
* @brief Remove '\\' in json string.
*
* @param[in,out] src string to transfer
* @param[in] src_len string len
* @return length after transfer
*/
int utils_json_strip_transfer(char *src, int src_len)
{
char *src_tmp = src;
char *end = src + src_len;
while (src_tmp < end) {
if (*src_tmp == '\\') {
memmove(src_tmp, src_tmp + 1, end - src_tmp);
end--;
}
src_tmp++;
}
return end - src;
}

View File

@@ -0,0 +1,326 @@
/**
* @copyright
*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright(C) 2018 - 2021 THL A29 Limited, a Tencent company.All rights reserved.
*
* Licensed under the MIT License(the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
* @file utils_list.c
* @brief utils list operation
* @author fancyxu (fancyxu@tencent.com)
* @version 1.0
* @date 2021-05-25
*
* @par Change Log:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2021-05-28 <td>1.0 <td>fancyxu <td>first commit
* </table>
*/
#include "utils_list.h"
/**
* @brief Define list node.
*
*/
typedef struct ListNode {
struct ListNode *prev;
struct ListNode *next;
void * val;
} ListNode;
/**
* @brief Double Linked List.
*
*/
typedef struct {
UtilsListFunc func;
ListNode * head;
ListNode * tail;
void * lock;
int len;
int max_len;
} List;
/**
* @brief List iterator.
*
*/
typedef struct {
List * list;
ListNode * next;
UtilsListDirection direction;
} ListIterator;
/**
* @brief Lock list.
*
* @param[in] list pointer to list
*/
static inline void _list_lock(List *list)
{
if (list->lock) {
list->func.list_lock(list->lock);
}
}
/**
* @brief Unlock list.
*
* @param[in] list pointer to list
*/
static inline void _list_unlock(List *list)
{
if (list->lock) {
list->func.list_unlock(list->lock);
}
}
/**
* @brief Delete the node in list and release the resource.
*
* @param[in] list pointer to list
* @param[in] node pointer to node needed remove
*/
static void _list_remove(void *list, void *node)
{
List * self = (List *)list;
ListNode *list_node = (ListNode *)node;
list_node->prev ? (list_node->prev->next = list_node->next) : (self->head = list_node->next);
list_node->next ? (list_node->next->prev = list_node->prev) : (self->tail = list_node->prev);
self->func.list_free(list_node->val);
self->func.list_free(list_node);
if (self->len) {
--self->len;
}
}
/**
* @brief Create list with max len, return NULL if fail.
*
* @param[in] func function needed by list
* @param[in] max_len max_len of list
* @return pointer to list, NULL for failed
*/
void *utils_list_create(UtilsListFunc func, int max_len)
{
List *self;
if (max_len <= 0) {
return NULL;
}
self = (List *)func.list_malloc(sizeof(List));
if (!self) {
return NULL;
}
memset(self, 0, sizeof(List));
if (func.list_lock_init) {
self->lock = func.list_lock_init();
if (!self->lock) {
func.list_free(self);
return NULL;
}
}
self->func = func;
self->max_len = max_len;
return self;
}
/**
* @brief Destroy list.
*
* @param[in] list pointer to list
*/
void utils_list_destroy(void *list)
{
if (!list) {
return;
}
List *self = (List *)list;
uint32_t len = self->len;
ListNode *next;
ListNode *curr = self->head;
while (len--) {
next = curr->next;
self->func.list_free(curr->val);
self->func.list_free(curr);
curr = next;
}
if (self->lock) {
self->func.list_lock_deinit(self->lock);
}
self->func.list_free(self);
}
/**
* @brief Get list len.
*
* @param[in] list pointer to list
* @return len of list
*/
int utils_list_len_get(void *list)
{
List *self = (List *)list;
return self->len;
}
/**
* @brief Push the node to list tail, return NULL if node invalid.
*
* @param[in] list pointer to list
* @param[in] val value needed to push to list
* @return pointer to node, NULL for failed
*/
void *utils_list_push(void *list, void *val)
{
List *self = (List *)list;
_list_lock(self);
if (!val || self->len >= self->max_len) {
_list_unlock(self);
return NULL;
}
ListNode *node;
node = self->func.list_malloc(sizeof(ListNode));
if (!node) {
_list_unlock(self);
return NULL;
}
node->prev = NULL;
node->next = NULL;
node->val = val;
if (self->len) {
node->prev = self->tail;
node->next = NULL;
self->tail->next = node;
self->tail = node;
} else {
self->head = self->tail = node;
node->prev = node->next = NULL;
}
++self->len;
_list_unlock(self);
return node;
}
/**
* @brief Pop the value from list head, return NULL if list empty.
*
* @param[in] list pointer to list
* @return value in the head node
*/
void *utils_list_pop(void *list)
{
List * self = (List *)list;
ListNode *node = NULL;
_list_lock(self);
if (!self->len) {
_list_unlock(self);
return NULL;
}
node = self->head;
if (--self->len) {
(self->head = node->next)->prev = NULL;
} else {
self->head = self->tail = NULL;
}
node->next = node->prev = NULL;
_list_unlock(self);
void *val = node->val;
self->func.list_free(node);
return val;
}
/**
* @brief Delete the node in list and release the resource.
*
* @param[in] list pointer to list
* @param[in] node pointer to node needed remove
*/
void utils_list_remove(void *list, void *node)
{
List *self = (List *)list;
_list_lock(self);
_list_remove(self, node);
_list_unlock(self);
}
/**
* @brief Process list using handle function.
*
* @param[in] list pointer to list
* @param[in] direction direction to traverse
* @param[in] handle process function @see OnNodeProcessHandle
* @param[in,out] usr_data usr data to pass to OnNodeProcessHandle
*/
void utils_list_process(void *list, uint8_t direction, OnNodeProcessHandle handle, void *usr_data)
{
int rc;
ListNode *node = NULL;
List * self = (List *)list;
_list_lock(self);
if (!utils_list_len_get(list)) {
_list_unlock(self);
return;
}
ListIterator iterator = {
.direction = direction,
.list = self,
.next = direction == LIST_HEAD ? self->head : self->tail,
};
// traverse list to process
while ((node = iterator.next)) {
iterator.next = iterator.direction == LIST_HEAD ? node->next : node->prev;
if (!node->val) {
_list_remove(list, node);
continue;
}
// process node and val
if (handle) {
rc = handle(list, node, node->val, usr_data);
if (rc) {
break;
}
}
}
_list_unlock(list);
}

View File

@@ -0,0 +1,178 @@
/**
* @copyright
*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright(C) 2018 - 2021 THL A29 Limited, a Tencent company.All rights reserved.
*
* Licensed under the MIT License(the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
* @file utils_log.c
* @brief different level log generator
* @author fancyxu (fancyxu@tencent.com)
* @version 1.0
* @date 2021-05-28
*
* @par Change Log:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2021-05-28 <td>1.0 <td>fancyxu <td>first commit
* </table>
*/
#include "utils_log.h"
static const char *LEVEL_STR[] = {"DIS", "ERR", "WRN", "INF", "DBG"};
static LogHandleFunc sg_log_handle_func;
static char *sg_log_buffer;
static int sg_log_max_size;
static void *sg_log_mutex;
static LogLevel sg_log_print_level = LOG_LEVEL_DEBUG;
extern LogLevel sg_log_upload_level;
/**
* @brief Get file name form path.
*
* @param[in] path file path
* @return file name
*/
static const char *_get_filename(const char *path)
{
#ifdef WIN32
char ch = '\\';
#else
char ch = '/';
#endif
const char *q = strrchr(path, ch);
if (!q) {
q = path;
} else {
q++;
}
return q;
}
/**
* @brief Init log with func, log level, max log size.
*
* @param[in] func function should be implement for utils log
* @param[in] log_level @see LogLevel
* @param[in] max_log_size max size of log to print
* @return 0 for success
*/
int utils_log_init(LogHandleFunc func, LogLevel log_level, int max_log_size)
{
sg_log_handle_func = func;
sg_log_print_level = log_level;
sg_log_max_size = max_log_size;
if (func.log_mutex_create) {
sg_log_mutex = func.log_mutex_create();
if (!sg_log_mutex) {
return -1;
}
}
if (func.log_malloc) {
sg_log_buffer = func.log_malloc(max_log_size);
if (!sg_log_buffer) {
if (sg_log_mutex) {
func.log_mutex_destroy(sg_log_mutex);
}
}
}
return !sg_log_buffer;
}
/**
* @brief Deinit log.
*
*/
void utils_log_deinit(void)
{
sg_log_handle_func.log_free(sg_log_buffer);
if (sg_log_mutex) {
sg_log_handle_func.log_mutex_destroy(sg_log_mutex);
}
sg_log_mutex = NULL;
sg_log_buffer = NULL;
}
/**
* @brief Set log level.
*
* @param log_level @see LogLevel
*/
void utils_log_set_level(LogLevel log_level)
{
sg_log_print_level = log_level;
}
/**
* @brief Get log level.
*
* @return @see LogLevel
*/
LogLevel utils_log_get_level(void)
{
return sg_log_print_level;
}
/**
* @brief Generate log if level higher than set.
*
* @param[in] file file path
* @param[in] func function where generate log
* @param[in] line line of source file where genertate log
* @param[in] level @see LogLevel
* @param[in] fmt format of log content
*/
void utils_log_gen(const char *file, const char *func, const int line, const int level, const char *fmt, ...)
{
if (level > sg_log_print_level) {
return;
}
if (sg_log_mutex) {
sg_log_handle_func.log_mutex_lock(sg_log_mutex);
}
/* format log content */
const char *file_name = _get_filename(file);
char *o = sg_log_buffer;
memset(sg_log_buffer, 0, sg_log_max_size);
o += snprintf(sg_log_buffer, sg_log_max_size, "%s|%s|%s|%s(%d): ", LEVEL_STR[level],
sg_log_handle_func.log_get_current_time_str(), file_name, func, line);
va_list ap;
va_start(ap, fmt);
vsnprintf(o, sg_log_max_size - 2 - strlen(sg_log_buffer), fmt, ap);
va_end(ap);
strncat(sg_log_buffer, "\r\n", sg_log_max_size - strlen(sg_log_buffer) - 1);
if (level <= sg_log_print_level) {
if (sg_log_handle_func.log_handle) {
sg_log_handle_func.log_handle(sg_log_buffer);
}
sg_log_handle_func.log_printf("%s", sg_log_buffer);
}
/* append to upload buffer */
if (sg_log_handle_func.log_upload) {
sg_log_handle_func.log_upload(level, sg_log_buffer);
}
if (sg_log_mutex) {
sg_log_handle_func.log_mutex_unlock(sg_log_mutex);
}
return;
}