diff --git a/demos/tabs.c b/demos/tabs.c new file mode 100644 index 0000000000000000000000000000000000000000..05af12fac30f99bbe729d119f6f362698c0e8a9c --- /dev/null +++ b/demos/tabs.c @@ -0,0 +1,33 @@ +#include + +#include "tabs.h" + +#define check_int_equal(x, y) do \ +{ \ + int x_ret = x; \ + int y_ret = y; \ + if(x_ret != y_ret) { \ + printf("error at %s:%d: %d != %d", __FILE__, __LINE__, x_ret, y_ret); \ + return 0; \ + } else { \ + printf("pass\n"); \ + } \ +} while (0); + +int main() { + tab_handler *handler = NULL; + + check_int_equal(common_tabs_init(&handler), COMMON_TABS_OK); + check_int_equal(common_tabs_add_header(handler, 4, "header1", "header2", "header3", "header4"), COMMON_TABS_OK); + check_int_equal(common_tabs_add_data(handler, 4, "1001", "1002", "1003", "1004"), COMMON_TABS_OK); + check_int_equal(common_tabs_add_data(handler, 4, "2001", "2002", "2003", "2004"), COMMON_TABS_OK); + check_int_equal(common_tabs_add_data(handler, 4, "3001", "3002", "3003", "3004"), COMMON_TABS_OK); + check_int_equal(common_tabs_add_data(handler, 4, "4001", "4002", "4003", "4004"), COMMON_TABS_OK); + check_int_equal(common_tabs_add_data(handler, 4, "5001", "5002", "5003", "5004"), COMMON_TABS_OK); + check_int_equal(common_tabs_add_data(handler, 4, "6001", "6002", "6003", "6004"), COMMON_TABS_OK); + check_int_equal(common_tabs_print_unicode_tabs(handler), COMMON_TABS_OK); + check_int_equal(common_tabs_print_ascii_tabs(handler), COMMON_TABS_OK); + check_int_equal(common_tabs_free(&handler), COMMON_TABS_OK); + + return 0; +} \ No newline at end of file diff --git a/include/tabs.h b/include/tabs.h new file mode 100644 index 0000000000000000000000000000000000000000..692ab5e262ccad4fefc246c4b9c4d0ee6db886c4 --- /dev/null +++ b/include/tabs.h @@ -0,0 +1,80 @@ +/** + * @file tabs.h + * @author yonglin_zhang + * @brief 制表符模块 + * @version 0.1 + * @date 2024-06-03 + * + * @copyright Copyright (c) 2024 + * + */ + +#define COMMON_TABS_OK 0x0000 /* < 执行成功 */ +#define COMMON_TABS_BAD_INPUT 0x0001 /* < 非法入参 */ +#define COMMON_TABS_MALLOC_FAILED 0x0002 /* < 申请内存失败 */ +#define COMMON_TABS_NEED_INIT 0x0003 /* < 需要初始化 */ +#define COMMON_TABS_ALREADY_INITED 0x0004 /* < 已经初始化 */ +#define COMMON_TABS_HEADERS_ARE_REQUIRED 0x0005 /* < 需要先添加表头 */ +#define COMMON_TABS_HEADER_AND_DATA_MISMATCH 0x0006 /* < 数据和表头的个数不匹配 */ + +typedef struct tab_handler tab_handler; + +/** + * @brief 表格句柄初始化 + * + * @warning *handler必须为NULL,否则视为初始化过 + * + * @param handler[in/out] 二级指针,传入后自动初始化 + * @return int 错误码 + */ +int common_tabs_init(tab_handler ** handler); + +/** + * @brief 表格句柄释放 + * + * @param handler[in/out] 二级指针,传入后自动释放并赋值为NULL + * @return int 错误码 + */ +int common_tabs_free(tab_handler ** handler); + +/** + * @brief 表格添加表头 + * + * @warning 可变参数必须为const char*类型,否则会导致严重的段错误 + * + * @param handler 句柄,一级指针即可 + * @param header_count 共计要传入的表头个数,最小为1 + * @param ... const char*类型,可传入多个 + * @return int 错误码 + */ +int common_tabs_add_header(tab_handler *handler, int header_count, ...); + +/** + * @brief 添加表格信息 + * + * @warning 可变参数必须为const char*类型,否则会导致严重的段错误 + * + * @param handler 句柄,一级指针即可 + * @param data_count 共计要传入的数据个数,最小为1 + * @param ... const char*类型,可传入多个 + * @return int 错误码 + */ +int common_tabs_add_data(tab_handler *handler, int data_count, ...); + +/** + * @brief 通过Unicode制表符打印表格信息 + * + * @warning Unicode有可能不通用所有平台,建议使用 \c commont_tabs_print_ascii_tabs + * + * @param handler[in] 句柄,一级指针 + * @return int + */ +int common_tabs_print_unicode_tabs(tab_handler *handler); + +/** + * @brief 通过ASCII编码打印表格信息 + * + * @param handler[in] 句柄,一级指针 + * @return int + */ +int common_tabs_print_ascii_tabs(tab_handler *handler); \ No newline at end of file diff --git a/src/tabs.c b/src/tabs.c new file mode 100644 index 0000000000000000000000000000000000000000..3fd5b3fd100ee2b4457ea68ad63625317d692aae --- /dev/null +++ b/src/tabs.c @@ -0,0 +1,444 @@ +/** + * @file tabs.c + * @author yonglin_zhang + * @brief 制表符模块实现 + * @version 0.1 + * @date 2024-06-03 + * + * @copyright Copyright (c) 2024 + * + */ + +#include "tabs.h" +#include +#include +#include +#include +#include +#include + +typedef struct node{ + char *value; + struct node *next; +}node; + +typedef struct tab_data { + node head; + struct tab_data * next; +}tab_data; + +struct tab_handler{ + node handler_header; // 表头 + tab_data handler_data; // 表数据 + tab_data *rear; // 表数据队尾 + int column_num; // 列数 + int *column_max; // 每列最大个数 +}; + +/** + * @brief 释放单链表,包含head + * + * @param head 链表头 + * @return int + */ +static void internal_link_list_free(node *head) { + node *free_ptr = NULL; + while(head != NULL) { + free_ptr = head; + head = head->next; + free(free_ptr->value); + free(free_ptr); + } +} + +/** + * @brief 通过变参参数添加数据 + * + * @param max[in] 每列最大计数器,其大小严格与param_count相等 + * @param head[in] 表头 + * @param args[in] 变参 + */ +static int internal_add_node_by_args(int max[], node *head, int param_count, va_list args) { + int counter = 0; + int length = 0; + const char *current_arg_ptr = NULL; + + // 拿到第一个数据 + current_arg_ptr = va_arg(args, const char *); + counter = 1; + while(counter <= param_count) { + // 添加节点,尾插法 + length = strlen(current_arg_ptr); + node *node_ptr = (node *)malloc(sizeof(node)); + node_ptr->value = (char *)malloc(sizeof(char) * length); + strcpy(node_ptr->value, current_arg_ptr); + node_ptr->next = NULL; + head->next = node_ptr; + head = node_ptr; + + // 更新每列最大长度 + // if(max[counter - 1] < length) { + // max[counter - 1] = length; + // } + max[counter - 1] = max[counter - 1] > length ? max[counter - 1] : length; + + // 指针后移 + current_arg_ptr = va_arg(args, const char *); + counter++; + } + return COMMON_TABS_OK; +} + +typedef enum { + LINE_TYPE1, + LINE_TYPE2, + LINE_TYPE3 +}LINE_TYPE; + +/** + * @brief 打印特殊行 + * + * @param handler + */ +static void internal_print_special_line_unicode(tab_handler *handler, LINE_TYPE line_type) { + int i = 0, j = 0; + switch (line_type) + { + case LINE_TYPE1: + printf("┌"); + break; + case LINE_TYPE2: + printf("├"); + break; + case LINE_TYPE3: + printf("└"); + break; + } + for(i = 0; i < handler->column_num; i++) { + for(j = 0; j < handler->column_max[i] + 2; j++) { + printf("─"); + } + if(i != handler->column_num - 1) { + switch (line_type) + { + case LINE_TYPE1: + printf("┬"); + break; + case LINE_TYPE2: + printf("┼"); + break; + case LINE_TYPE3: + printf("┴"); + break; + } + } + else { + switch (line_type) + { + case LINE_TYPE1: + printf("┐"); + break; + case LINE_TYPE2: + printf("┤"); + break; + case LINE_TYPE3: + printf("┘"); + break; + } + } + } + printf("\n"); +} + +static void internal_print_special_line_ascii(tab_handler *handler) { + int i = 0, j = 0; + printf("+"); + for(i = 0; i < handler->column_num; i++) { + for(j = 0; j < handler->column_max[i] + 2; j++) { + printf("-"); + } + printf("+"); + } + printf("\n"); +} + +typedef enum { + PRINTF_FORMAT_UNICODE, + PRINTF_FORMAT_ASCII, +}PRINTF_FORMAT; + +/** + * @brief 打印表头 + * + * @param handler + */ +static void internal_print_table_header(tab_handler *handler, PRINTF_FORMAT format) { + int counter = 0; + node *head = handler->handler_header.next; + if(format == PRINTF_FORMAT_UNICODE) { + printf("│"); + } + else { + printf("|"); + } + while(head != NULL) { + if(format == PRINTF_FORMAT_UNICODE) { + printf(" %-*s │", handler->column_max[counter], head->value); + } + else { + printf(" %-*s |", handler->column_max[counter], head->value); + } + head = head->next; + counter++; + } + printf("\n"); +} + +/** + * @brief 打印表内数据 + * + * @param handler + */ +static void internal_print_table_data(tab_handler *handler, PRINTF_FORMAT format) { + int counter = 0; + tab_data *data_head = NULL; + node *line_head = NULL; + + data_head = handler->handler_data.next; + while(data_head != NULL) { + if(format == PRINTF_FORMAT_UNICODE) { + printf("│"); + } + else { + printf("|"); + } + line_head = data_head->head.next; + counter = 0; + while(line_head != NULL) { + if(format == PRINTF_FORMAT_UNICODE) { + printf(" %-*s │", handler->column_max[counter], line_head->value); + } + else { + printf(" %-*s |", handler->column_max[counter], line_head->value); + } + + line_head = line_head->next; + counter++; + } + data_head = data_head->next; + printf("\n"); + } + +} + +int common_tabs_init(tab_handler ** handler) { + if(handler == NULL) { + return COMMON_TABS_BAD_INPUT; + } + if(*handler != NULL) { + return COMMON_TABS_ALREADY_INITED; + } + + *handler = (tab_handler *)malloc(sizeof(tab_handler)); + if(*handler == NULL) { + return COMMON_TABS_MALLOC_FAILED; + } + + (*handler)->handler_header.next = NULL; + (*handler)->handler_header.value = NULL; + + (*handler)->handler_data.head.next = NULL; + (*handler)->handler_data.head.value = NULL; + (*handler)->handler_data.next = NULL; + + (*handler)->rear = &(*handler)->handler_data; + + (*handler)->column_num = 0; + + return COMMON_TABS_OK; +} + +int common_tabs_free(tab_handler ** handler) { + /*================= + 1. 循环释放表头 + 2. 循环释放handler_data + 3. 如果column_num != 0,释放column_max + 4. 释放根节点 + 5. 根节点置为NULL + ==================*/ + + tab_data *free_ptr_data = NULL; + tab_data *free_ptr_temp = NULL; + + // step1 + internal_link_list_free((*handler)->handler_header.next); + + // step2 + free_ptr_data = (*handler)->handler_data.next; + while(free_ptr_data != NULL) { + free_ptr_temp = free_ptr_data; + free_ptr_data = free_ptr_data->next; + internal_link_list_free(free_ptr_temp->head.next); + free(free_ptr_temp); + } + + // step3 + if((*handler)->column_num != 0) { + free((*handler)->column_max); + } + + // step4 + free(*handler); + + // step5 + *handler = NULL; + + return COMMON_TABS_OK; +} + +int common_tabs_add_header(tab_handler *handler, int header_count, ...) { + va_list args; + int ret = 0; + + if(handler == NULL || header_count <= 0) { + return COMMON_TABS_BAD_INPUT; + } + + if(handler->handler_header.next != NULL) { + return COMMON_TABS_ALREADY_INITED; + } + + // 为每行最大计数器进行申请内存 + handler->column_max = NULL; + handler->column_max = (int*)malloc(sizeof(int) * header_count); + if(handler->column_max == NULL) { + return COMMON_TABS_MALLOC_FAILED; + } + + // 初始化数值 + memset(handler->column_max, 0, sizeof(int) * header_count); + + handler->column_num = header_count; + + // 添加节点的同时并获得每列的最大值,同时更新到column中 + va_start(args, header_count); + ret = internal_add_node_by_args(handler->column_max, &handler->handler_header, header_count, args); + va_end(args); + + return ret; +} + +int common_tabs_add_data(tab_handler *handler, int data_count, ...) { + va_list args; + int ret = 0; + tab_data *incoming_node = NULL; + + // 非法参数 + if(handler == NULL || data_count <= 0) { + return COMMON_TABS_BAD_INPUT; + } + + // 未添加表头 + if(handler->handler_header.next == NULL) { + return COMMON_TABS_HEADERS_ARE_REQUIRED; + } + + // 长度检查 + if(data_count != handler->column_num) { + return COMMON_TABS_HEADER_AND_DATA_MISMATCH; + } + + // 申请内存 + incoming_node = (tab_data *)malloc(sizeof(tab_data)); + if(incoming_node == NULL) { + return COMMON_TABS_MALLOC_FAILED; + } + + // 初始化数据 + incoming_node->head.next = NULL; + incoming_node->head.value = NULL; + incoming_node->next = NULL; + + // 添加数据 + va_start(args, data_count); + ret = internal_add_node_by_args(handler->column_max, &incoming_node->head, data_count, args); + va_end(args); + + // 添加失败的情况需要释放掉incoming_node及其内部数据 + if(ret != COMMON_TABS_OK) { + internal_link_list_free(incoming_node->head.next); + free(incoming_node); + return ret; + } + + handler->rear->next = incoming_node; + handler->rear = incoming_node; + + return ret; +} + + +/* +Unicode制表符: +┌┬┐ ┌─┐ +├┼┤ │┼│ +└┴┘ └─┘ +*/ +int common_tabs_print_unicode_tabs(tab_handler *handler) { + // step1 打印第一行 + // step2 打印表头 + // step3 打印第三行 + // step4 循环打印数据 + // step5 打印最后一行 + + // 设置本地化,以支持宽字符 + setlocale(LC_ALL, ""); + + // step1 + internal_print_special_line_unicode(handler, LINE_TYPE1); + + // step2 + internal_print_table_header(handler, PRINTF_FORMAT_UNICODE); + + // step3 + internal_print_special_line_unicode(handler, LINE_TYPE2); + + // step4 + internal_print_table_data(handler, PRINTF_FORMAT_UNICODE); + + // step5 + internal_print_special_line_unicode(handler, LINE_TYPE3); + + return COMMON_TABS_OK; +} + +/* +ASCII制表: ++--+ +| | ++--+ +*/ +int common_tabs_print_ascii_tabs(tab_handler *handler) { + // step1 打印第一行 + // step2 打印表头 + // step3 打印第三行 + // step4 循环打印数据 + // step5 打印最后一行 + + // step1 + internal_print_special_line_ascii(handler); + + // step2 + internal_print_table_header(handler, PRINTF_FORMAT_ASCII); + + // step3 + internal_print_special_line_ascii(handler); + + // step4 + internal_print_table_data(handler, PRINTF_FORMAT_ASCII); + + // step5 + internal_print_special_line_ascii(handler); + + return COMMON_TABS_OK; +} \ No newline at end of file diff --git a/test/check_big_number.c b/test/check_big_number.c index 111ae2b4080b57467a3354023a3a5afca095c609..5f92569351f1a42fdbee0796acd462d87565f924 100644 --- a/test/check_big_number.c +++ b/test/check_big_number.c @@ -7,7 +7,7 @@ static char left[] = "123456"; static char right[] = "123456789123456789"; static char correct_plus[] = "123456789123580245"; -static char correct_mult[] = "15241481358025481342784"; +// static char correct_mult[] = "15241481358025481342784"; START_TEST(test_plus_ok) { char operation_result[32] = { 0 }; @@ -38,11 +38,6 @@ START_TEST(test_plus_input) { } END_TEST -START_TEST(test_mult_ok) { - -} -END_TEST - Suite *check_big_number(void) { Suite *s;