diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml new file mode 100644 index 0000000..51b04b2 --- /dev/null +++ b/.github/workflows/build-test.yml @@ -0,0 +1,167 @@ +name: build-and-package + +on: + #push: + #branches: test + # Sequence of patterns matched against refs/tags + #tags: + # - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 + create: + ref_type: tag +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) + BUILD_TYPE: Release + +jobs: + job1: + name: Build and Package on Linux + runs-on: ubuntu-16.04 + + steps: + - name: Checkout Repository + uses: actions/checkout@v2 + with: + ref: ${{github.ref}} + + - name: Create Build Environment + # Some projects don't allow in-source building, so create a separate build directory + # We'll use this as our working directory for all subsequent commands + run: cmake -E make_directory ${{runner.workspace}}/build + + - name: Configure CMake + # Use a bash shell so we can use the same syntax for environment variable + # access regardless of the host operating system + shell: bash + working-directory: ${{runner.workspace}}/build + # Note the current convention is to use the -S and -B options here to specify source + # and build directories, but this is only available with CMake 3.13 and higher. + # The CMake binaries on the Github Actions machines are (as of this writing) 3.12 + run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE + + - name: Build + working-directory: ${{runner.workspace}}/build + shell: bash + # Execute the build. You can specify a specific target with "--target " + run: cmake --build . --config $BUILD_TYPE + + - name: Package + if: ${{ success() }} + working-directory: ${{github.workspace}} + shell: bash + run: | + tar -Jcf linux-bin.tar.xz ./bin/ + + - name: Upload Artifact for Stage + if: ${{ success() }} + uses: actions/upload-artifact@v2 + with: + name: linux-bin-package + path: linux-bin.tar.xz + retention-days: 1 + + job2: + name: Build and Package on Windows + runs-on: windows-2019 + + steps: + - uses: actions/checkout@v2 + with: + ref: ${{github.ref}} + + - name: Create Build Environment + run: cmake -E make_directory ${{runner.workspace}}/build + + - name: Configure CMake + shell: bash + working-directory: ${{runner.workspace}}/build + run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE + + - name: Build + working-directory: ${{runner.workspace}}/build + shell: bash + run: cmake --build . --config $BUILD_TYPE + + - name: Package + if: ${{ success() }} + working-directory: ${{github.workspace}} + shell: bash + run: | + echo zip -r windows-bin.zip ./bin/ + tar -Jcf windows-bin.tar.xz ./bin/ + + - name: Upload Artifact for Stage + if: ${{ success() }} + uses: actions/upload-artifact@v2 + with: + name: windows-bin-package + path: windows-bin.tar.xz + retention-days: 1 + + job3: + name: Create Release and Upload Packages + needs: [job1, job2] + runs-on: ubuntu-latest + steps: + - name: Download Windows Artifacts + id: download-artifacts-win + uses: actions/download-artifact@v2 + with: + name: windows-bin-package + + - name: Download Linux Artifacts + id: download-artifacts-linux + uses: actions/download-artifact@v2 + with: + name: linux-bin-package + + - name: Truncate SHA + id: truncate-sha + uses: tangm421/truncate-sha-action@v1.0 + #with: + # sha: ${{github.sha}} + # field-width: 7 + + - name: Create Release + if: ${{ steps.download-artifacts-win.conclusion == 'success' && steps.download-artifacts-linux.conclusion == 'success' && steps.truncate-sha.conclusion=='success' }} + id: create_release + uses: actions/create-release@v1 + with: + tag_name: ${{ github.ref }}-${{steps.truncate-sha.outputs.sha-short}} + release_name: ${{ github.ref }}-${{steps.truncate-sha.outputs.sha-short}} + body: | + # Summary + This is a create release demo + # Changes in this Release + - First Change + - Second Change + draft: false + prerelease: false + + - name: Upload Windows Release Asset + id: upload-win-release-asset + if: ${{ steps.create_release.conclusion == 'success' }} + uses: actions/upload-release-asset@v1 + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./windows-bin.tar.xz + asset_name: windows-bin.tar.xz + asset_content_type: application/form + + - name: Upload Linux Release Asset + id: upload-linux-release-asset + if: ${{ steps.create_release.conclusion == 'success' }} + uses: actions/upload-release-asset@v1 + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./linux-bin.tar.xz + asset_name: linux-bin.tar.xz + asset_content_type: application/form + + - name: Clean Artifacts + uses: geekyeggo/delete-artifact@v1 + with: + name: | + windows-bin-package + linux-bin-package + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4c0b53d --- /dev/null +++ b/.gitignore @@ -0,0 +1,59 @@ +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf + +build/ +/m4/ +!/m4/.gitignore + +!/.github/workflows/*.yml + diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..cb30a34 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,24 @@ +sudo: required +language: c +os: linux + +branches: + only: + - master + +jobs: + include: + - name: cmake + script: + - echo ------------------------------------------- + - mkdir build + - cd build + - cmake ../ + - make + - name: automake + script: + - echo ------------------------------------------- + - autoreconf --install + - ./configure + - make + \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..6735fe8 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,58 @@ +cmake_minimum_required(VERSION 2.8.12.2) +project(clist) + +set(PROJECT_VERSION_MAJOR 1) +set(PROJECT_VERSION_MINOR 0) +set(PROJECT_VERSION_PATCH 1) +set(PROJECT_VERSION_TWEAK 1114) +set(PACKAGE_VERSION \"${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}.${PROJECT_VERSION_TWEAK}\") + +if(NOT MSVC) + set(CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}/clist/") +endif() + +set (_DEFAULT_LIBRARY_INSTALL_DIR lib) +if (EXISTS "${CMAKE_INSTALL_PREFIX}/lib32/" AND CMAKE_SIZEOF_VOID_P EQUAL 4) + set (_DEFAULT_LIBRARY_INSTALL_DIR lib32) +elseif (EXISTS "${CMAKE_INSTALL_PREFIX}/lib64/" AND CMAKE_SIZEOF_VOID_P EQUAL 8) + set (_DEFAULT_LIBRARY_INSTALL_DIR lib64) +endif () + +set(LIBRARY_INSTALL_DIR "${_DEFAULT_LIBRARY_INSTALL_DIR}" CACHE PATH "Library installation directory") +if(NOT IS_ABSOLUTE "${LIBRARY_INSTALL_DIR}") + set(LIBRARY_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${LIBRARY_INSTALL_DIR}") +endif() + +set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) +set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) +set(ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin) + +set(COMPILE_STATIC ON CACHE BOOL "Flag indicating if a static library should be built, or a dynamic one") +set(CLIST_DEBUG_ON OFF CACHE BOOL "Flag indicating if enable to print clist debug info") + +if(NOT MSVC OR COMPILE_STATIC) + set(PROJECT_IMPORT "") + set(PROJECT_EXPORT "") +else() + set(PROJECT_IMPORT "__declspec(dllimport)") + set(PROJECT_EXPORT "__declspec(dllexport)") +endif() + +if(NOT MSVC) + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0 -Wall -g -ggdb") + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3 -Wall") +endif() + +set(PROJECT_LIB optimized "${LIBRARY_INSTALL_DIR}/clist.lib" + debug "${LIBRARY_INSTALL_DIR}/clist_d.lib") + +configure_file( + "${PROJECT_SOURCE_DIR}/clist/config.h.in" + "${PROJECT_BINARY_DIR}/clist/config.h" +) +add_definitions(-DHAVE_CONFIG_H) + +set(CLIST_INTERNAL_INCLUDES "${PROJECT_SOURCE_DIR}/clist" "${PROJECT_BINARY_DIR}/clist") + +add_subdirectory(clist) +add_subdirectory(samples) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..bf75fab --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2017 tangm + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..62869c2 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,11 @@ + +AUTOMAKE_OPTIONS = foreign +ACLOCAL_AMFLAGS = -I m4 + +SUBDIRS = clist +SUBDIRS += samples + +cmakedatadir = $(datadir)/cmake +nobase_dist_cmakedata_DATA = ./CMakeLists.txt +nobase_dist_cmakedata_DATA += clist/CMakeLists.txt +nobase_dist_cmakedata_DATA += ./samples/CMakeLists.txt \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..2350ed9 --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +# 1. clist + +A simple test project for study + +- how to use cmake +- how to use automake +- how to use Travis-CI +- how to use jsDelivr +- how to use badges +- how to use Github Actions +- how to use git commit with signature verification + +--- + +[![Website](https://img.shields.io/website?down_message=offline&label=explore%20my%20blog&logo=Internet%20Explorer&style=for-the-badge&up_message=online&url=https%3A%2F%2Fblog.luanhui.cf "Welcome to my blog")](https://blog.luanhui.cf) diff --git a/clist/CMakeLists.txt b/clist/CMakeLists.txt new file mode 100644 index 0000000..6223d82 --- /dev/null +++ b/clist/CMakeLists.txt @@ -0,0 +1,31 @@ + +add_definitions(-DPROJECT_COMPILING) + +if(CLIST_DEBUG_ON) + add_definitions(-DCLIST_DEBUG) +endif() + +set(HEADERS + clist.h) + +set(SOURCES + clist.c) + +include_directories(${CLIST_INTERNAL_INCLUDES}) + +if(COMPILE_STATIC) + add_library(clist-static STATIC ${HEADERS} ${SOURCES}) + set_target_properties(clist-static PROPERTIES OUTPUT_NAME ${PROJECT_NAME}) + set_target_properties(clist-static PROPERTIES CLEAN_DIRECT_OUTPUT 1) + set(CLIST_INSTALLTARGETS clist-static) +else() + add_library(clist-shared SHARED ${SOURCES} ${HEADERS}) + set_target_properties(clist-shared PROPERTIES OUTPUT_NAME ${PROJECT_NAME}) + set_target_properties(clist-shared PROPERTIES CLEAN_DIRECT_OUTPUT 1) + set_target_properties(clist-shared PROPERTIES VERSION ${PACKAGE_VERSION}) + set(CLIST_INSTALLTARGETS clist-shared) +endif() + +install(FILES ${PROJECT_BINARY_DIR}/clist/config.h DESTINATION include) +install(FILES ${HEADERS} DESTINATION include) +install(TARGETS ${CLIST_INSTALLTARGETS} DESTINATION ${LIBRARY_INSTALL_DIR}) \ No newline at end of file diff --git a/clist/Makefile.am b/clist/Makefile.am new file mode 100644 index 0000000..3a2ffe7 --- /dev/null +++ b/clist/Makefile.am @@ -0,0 +1,11 @@ + +lib_LTLIBRARIES = libclist.la + +libclist_la_CPPFLAGS = @LIBCLIST_CPPFLAGS@ + +libclist_la_SOURCES = clist.c +nodist_libclist_la_SOURCES = $(top_buildidr)/config.h + +clistincludedir = $(includedir)/clist +nobase_clistinclude_HEADERS = clist.h +#include_HEADERS = clist.h diff --git a/clist/clist.c b/clist/clist.c new file mode 100644 index 0000000..c203ee1 --- /dev/null +++ b/clist/clist.c @@ -0,0 +1,272 @@ +/* + * + * + * Copyright (c) 2017 tangm + * + * This file is part of mansys + * + */ + +#include "clist.h" +#include +#include + +#ifdef CLIST_DEBUG +# define DEBUGOUT(s, fmt, ...) fprintf(s, fmt, __VA_ARGS__) +#else +# define DEBUGOUT(s, fmt, ...) +#endif + +#define SAFE_FREE(p) if(NULL != (p))\ + {\ + free((p));\ + (p) = NULL;\ + } + +#define SIZEOF_CLIST_NODE sizeof(clist_t) + + +const clist_iterator_t clist_iterator_end = (clist_iterator_t)0xdeadbeef; + +typedef struct clist_errdesc_t { + clist_errcode_t code; + const char *desc; +}clist_errdesc_t; + +static const clist_errdesc_t table_errors[] = { + { EOK, "" }, + { EOUTOFMEM, "Out of memory" }, + { ENOTCREATE, "Clist not create" }, + { EBADARGS, "Bad argument" }, + + { (clist_errcode_t)0x7fffffff, "Unknow error" } +}; + +const char* clist_get_error_string(clist_errcode_t code) +{ + int i = 0; + int tablesize = sizeof(table_errors) / sizeof(table_errors[0]); + + for (; i < tablesize; ++i) { + if (code == table_errors[i].code) + return table_errors[i].desc; + } + + return table_errors[tablesize - 1].desc; +} + +const char* clist_version() +{ +#ifdef HAVE_CONFIG_H + return (PACKAGE_VERSION); +#endif + return ""; +} + +clist_errcode_t clist_create(clist* pl) +{ + if (NULL == pl) { + return EBADARGS; + } + + pl->size = 0; + pl->head = NULL; + pl->tail = NULL; + + return EOK; +} + +void clist_destroy(clist* const pl) +{ + clist_t *p = NULL; + if (NULL == pl) { + return; + } + + while (pl->head && (pl->head != pl->tail)) { + DEBUGOUT(stdout, "[clist debug] destroy : prev[%p] --> head[%p] --> next[%p], size:%d\n", + pl->head->prev, pl->head, pl->head->next, pl->size); + + p = pl->head->next; + SAFE_FREE(pl->head->data); + pl->head->prev->next = p; + pl->head->next->prev = pl->head->prev; + SAFE_FREE(pl->head); + pl->head = p; + pl->size--; + } + + if (pl->head) + { + DEBUGOUT(stdout, "[clist debug] destroy : prev[%p] --> head[%p] --> next[%p], size:%d\n", + pl->head->prev, pl->head, pl->head->next, pl->size); + + SAFE_FREE(pl->head->data); + SAFE_FREE(pl->head); + pl->tail = NULL; + pl->size = 0; + } + + DEBUGOUT(stdout, "[clist debug] destroy done: head[%p] --> tail[%p], size:%d\n", + pl->head, pl->tail, pl->size); +} + +unsigned int clist_size(const clist * const pl) +{ + return pl->size; +} + +clist_errcode_t clist_add(clist * const pl, void * const data, flag_t push) +{ + clist_t* node = NULL; + + if (NULL == pl) { + return ENOTCREATE; + } + + node = (clist_t*)malloc(SIZEOF_CLIST_NODE); + if (NULL == node) { + return EOUTOFMEM; + } + + if (NULL == pl->head) { + pl->head = node; + pl->tail = node; + node->next = node; + node->prev = node; + } + else { + node->next = pl->head; + node->prev = pl->tail; + pl->tail->next = node; + pl->head->prev = node; + } + + if (push) { + pl->tail = node; + } else { + pl->head = node; + } + + node->data = data; + pl->size++; + + DEBUGOUT(stdout, "[clist debug] add : prev[%p] --> new node[%p] --> next[%p], size:%d\n", + node->prev, node, node->next, pl->size); + + return EOK; +} + +clist_iterator_t clist_begin(clist * const pl) +{ + return pl->head; +} + +clist_iterator_t clist_end(clist * const pl) +{ + return pl->tail; +} + +clist_iterator_t clist_step(clist_iterator_t it, clist_step_dir_t dir, clist* const pl) +{ + clist_iterator_t iter; + + if (dir == increase) { + iter = it->next; + if (iter == pl->head) { + iter = clist_iterator_end; + } + } else if (dir == decrease) { + iter = it->prev; + if (iter == pl->tail) { + iter = clist_iterator_end; + } + } + + return iter; +} + +flag_t clist_is_end(clist_iterator_t const it, clist * const pl) +{ + return (it->next == pl->head) ? true : false; +} + +clist_iterator_t clist_erase(clist_iterator_t it, clist* const pl) +{ + clist_iterator_t iter = it->next; + + DEBUGOUT(stdout, "[clist debug] delete before : prev[%p] --> delete node[%p] --> next[%p], size:%d\n", + it->prev, it, it->next, pl->size); + + if (it == pl->head) pl->head = it->next; + if (it == pl->tail) pl->tail = it->prev; + + it->next->prev = it->prev; + it->prev->next = it->next; + SAFE_FREE(it->data); + SAFE_FREE(it); + pl->size--; + + DEBUGOUT(stdout, "[clist debug] delete after : prev[%p] --> current node[%p] --> next[%p], size:%d\n", + iter->prev, iter, iter->next, pl->size); + + return iter; +} + +clist_iterator_t clist_find(clist_iterator_t const it, clist* const pl, comp_handler h, const void* const userdata) +{ + clist_iterator_t iter; + clist_t *p; + + if (NULL == it) { + p = pl->head; + } + else if (clist_iterator_end == it) { + return it; + } + else { + p = it; + } + while (p) { + if (true == h(p->data, userdata)) { + iter = p; + return iter; + } + p = p->next; + if (p == pl->head) { + return clist_iterator_end; + } + } + + return clist_iterator_end; +} + +void clist_sort(clist_iterator_t const it, clist* const pl, comp_handler h) +{ + clist_t *p, *q; + void *data; + + if (NULL == it) { + p = pl->head; + } else { + p = it; + } + + for (; p->next != pl->head; p = p->next) { + for (q = p->next; q != pl->head; q = q->next) { + if (true == h(p->data, q->data)) { + data = p->data; + p->data = q->data; + q->data = data; + } + } + } +} + +void * clist_get(clist_iterator_t it) +{ + if (it != clist_iterator_end) { + return it->data; + } + return NULL; +} diff --git a/clist/clist.h b/clist/clist.h new file mode 100644 index 0000000..1be5a5c --- /dev/null +++ b/clist/clist.h @@ -0,0 +1,224 @@ +/* + * + * + * Copyright (c) 2017 tangm + * + * This file is part of mansys + * + */ + +#ifndef __MANSYS_CLIST_HEADER__ +#define __MANSYS_CLIST_HEADER__ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef __cplusplus + extern "C" { +#endif +/* + * 操作链表时返回的错误码。 + */ +typedef int clist_errcode_t; +#define EOK ((clist_errcode_t)0) +#define EOUTOFMEM ((clist_errcode_t)-1) +#define ENOTCREATE ((clist_errcode_t)-10) +#define EBADARGS ((clist_errcode_t)-100) + +/* + * 获取错误码对应的错误描述字符串。 + */ +PROJECT_IMPORTEXPORT +const char* clist_get_error_string(clist_errcode_t code); + + +/* + * 自定义标志类型。 + */ +typedef char flag_t; +#define false ((flag_t)0) +#define true ((flag_t)1) + +/* + * 循环双向链表结构,无哨兵节点,并定义链表访问的迭代器。 + */ +typedef struct clist_t{ + void *data; + struct clist_t *next; + struct clist_t *prev; +}clist_t, *clist_iterator_t; + +/* + * 链表。 + */ +typedef struct clist { + unsigned int size; + clist_t *head; + clist_t *tail; +}clist; + +/* + * 链表结尾无效节点。 + */ +PROJECT_IMPORTEXPORT +extern const clist_iterator_t clist_iterator_end; + +/* + * 链表迭代器的后向或者前向步进。 + */ +typedef enum clist_step_dir_t { + increase, + decrease +}clist_step_dir_t; + + +/* + * 回调函数声明,供调用者作为条件比对使用。 + * 当用作查找回调时,data1参数为遍历的当前节点,data2为用户数据。 + * 当用作排序回调时,data1,data2参数分别为遍历链表时的前后节点。 + */ +typedef flag_t (*comp_handler)(const void* const data1, const void* const data2); + + + + +/* 链表操作函数全家福 */ + +/* + * 获取版本信息 + * +*/ +PROJECT_IMPORTEXPORT +const char* clist_version(); + +/* + * 创建链表 + * 输入参数: + * pl - 外部声明的链表变量指针,不能为空或者无效。 + * 返回值 : 错误码。 + * 说明 : 此函数不会增加内部节点。 + * + */ +PROJECT_IMPORTEXPORT +clist_errcode_t clist_create(clist* pl); + +/* + * 销毁链表 + * 输入参数 + * pl - 外部声明的链表变量指针,不能为空或者无效。 + * 返回值 : 错误码。 + * 说明 : 此函数会销毁调用者在外部申请的堆空间。 + */ +PROJECT_IMPORTEXPORT +void clist_destroy(clist* const pl); + +/* + * 获取链表节点个数 + * 输入参数 + * pl - 外部声明的链表变量指针,不能为空或者无效。 + * 返回值 : 链表节点个数。 + */ +PROJECT_IMPORTEXPORT +unsigned int clist_size(const clist* const pl); + +/* + * 增加节点 + * 输入参数 + * pl - 外部声明的链表变量指针,不能为空或者无效。 + * data - 调用者外部堆数据。 + * push - 尾部追加或者头部追加标志。 + * 返回值 : 错误码。 + */ +PROJECT_IMPORTEXPORT +clist_errcode_t clist_add(clist* const pl, void* const data, flag_t push); + +/* + * 获取链表头迭代器 + * 输入参数 + * pl - 外部声明的链表变量指针,不能为空或者无效。 + * 返回值 : 链表头迭代器。 + */ +PROJECT_IMPORTEXPORT +clist_iterator_t clist_begin(clist* const pl); + +/* + * 获取链表尾迭代器 + * 输入参数 + * pl - 外部声明的链表变量指针,不能为空或者无效。 + * 返回值 : 链表尾迭代器。 + */ +PROJECT_IMPORTEXPORT +clist_iterator_t clist_end(clist* const pl); + +/* + * 迭代器步进 + * 输入参数 + * it - 迭代器。 + * dir - 步进方向。 + * pl - 外部声明的链表变量指针,不能为空或者无效。 + * 返回值 : 迭代器步进后的新迭代器。 + */ +PROJECT_IMPORTEXPORT +clist_iterator_t clist_step(clist_iterator_t it, clist_step_dir_t dir, clist* const pl); + +/* + * 判断迭代器是否已到无效尾部 + * 输入参数 + * it - 迭代器。 + * pl - 外部声明的链表变量指针,不能为空或者无效。 + * 返回值 : 判断结果标志。 + */ +PROJECT_IMPORTEXPORT +flag_t clist_is_end(clist_iterator_t const it, clist* const pl); + +/* + * 从链表中删除迭代器指示的节点 + * 输入参数 + * it - 要删除节点位置的迭代器。 + * pl - 外部声明的链表变量指针,不能为空或者无效。 + * 返回值 : 迭代器指示位置的下一个节点位置的新迭代器。 + */ +PROJECT_IMPORTEXPORT +clist_iterator_t clist_erase(clist_iterator_t it, clist* const pl); + +/* + * 查找 + * 输入参数 + * it - 匹配起始位置的迭代器。 + * pl - 外部声明的链表变量指针,不能为空或者无效。 + * h - 回调函数。 + * userdata - 回调函数中传入的用户数据。 + * 返回值 : 满足条件的迭代器。 + * 说明 : 回调函数返回结果为true表示匹配,起始位置的迭代器传入NULL值,代表从头节点开始查找。 + */ +PROJECT_IMPORTEXPORT +clist_iterator_t clist_find(clist_iterator_t const it, clist* const pl, comp_handler h, const void* const userdata); + +/* + * 排序 + * 输入参数 + * it - 排序起始位置的迭代器。 + * pl - 外部声明的链表变量指针,不能为空或者无效。 + * h - 回调函数。 + * 返回值 : 无。 + * 说明 : 回调函数返回结果为true表示匹配。 + */ +PROJECT_IMPORTEXPORT +void clist_sort(clist_iterator_t const it, clist* const pl, comp_handler h); + +/* + * 返回迭代器指示位置的节点数据 + * 输入参数 + * it - 迭代器。 + * 返回值 : 调用者外部堆数据。 + */ +PROJECT_IMPORTEXPORT +void* clist_get(clist_iterator_t it); + + +#ifdef __cplusplus + } +#endif + +#endif//#ifndef __MANSYS_CLIST_HEADER__ diff --git a/clist/config.h.in b/clist/config.h.in new file mode 100644 index 0000000..a911db2 --- /dev/null +++ b/clist/config.h.in @@ -0,0 +1,10 @@ + +#define PROJECT_IMPORT ${PROJECT_IMPORT} +#define PROJECT_EXPORT ${PROJECT_EXPORT} +#ifdef PROJECT_COMPILING + #define PROJECT_IMPORTEXPORT PROJECT_EXPORT +#else + #define PROJECT_IMPORTEXPORT PROJECT_IMPORT +#endif // PROJECT_COMPILING + +#define PACKAGE_VERSION ${PACKAGE_VERSION} \ No newline at end of file diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..2500d1a --- /dev/null +++ b/configure.ac @@ -0,0 +1,85 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ([2.69]) + +AC_INIT([clist], [1.0.1.1114], [tangm421@outlook.com]) +AC_CONFIG_SRCDIR([clist/clist.c]) +AC_CONFIG_HEADER(config.h) +AC_CONFIG_AUX_DIR([build-aux]) +AC_CONFIG_MACRO_DIR([m4]) + +#m4_pattern_forbid([^PKG_]) + + +AM_INIT_AUTOMAKE +AM_PROG_AR([AC_MSG_ERROR([cannot find any available compression tool for \$AR])]) + + +AC_DISABLE_SHARED +LT_INIT() +# Checks for programs. +AC_PROG_CC +#AC_DISABLE_SHARED + +#AC_PROG_INSTALL +#AC_PROG_LIBTOOL +dnl AC_PROG_RANLIB + +AC_CANONICAL_HOST + +#AC_PROG_MAKE_SET + + +# Checks for libraries. + +# Checks for header files. +#AC_CHECK_HEADERS([malloc.h stdio.h stdlib.h string.h]) + +# Checks for typedefs, structures, and compiler characteristics. +#AC_CHECK_HEADER_STDBOOL +AC_CHECK_HEADERS_ONCE + +AC_CHECK_HEADERS([db_cxx.h], + [echo "db_cxx.h found"], + [AC_MSG_WARN([db_cxx.h not found])], + [#ifdef HAVE_FOO_H + # include + #endif + ]) + +AC_MSG_NOTICE([Using native OSTYPE value from \$host_os: $host_os, ARCH/LARCH value from \$host_cpu: $host_cpu]) + +#AC_DEFINE(PROJECT_IMPORTEXPORT, [], [Only usefull for windows]) +#AH_TEMPLATE(PROJECT_IMPORTEXPORT, [Only usefull for windows]) +AC_DEFINE_UNQUOTED(PROJECT_IMPORTEXPORT, ${PROJECT_IMPORTEXPORT:""}, [Only usefull for windows]) + +# AM_CONDITIONAL(ENABLE_CLIST_DEBUG, false) +# AC_ARG_WITH(clist-debug, +# [ --enable-clist-debug enable clist debug info], + # [AC_DEFINE_UNQUOTED(ENABLE_CLIST_DEBUG, , ENABLE_CLIST_DEBUG) + # AC_SUBST(LIBCLIST_CPPFLAGS, "-DCLIST_DEBUG") + # AM_CONDITIONAL(ENABLE_CLIST_DEBUG, true)], + # [ AC_SUBST(LIBCLIST_CPPFLAGS, "")]) + +# AM_CONDITIONAL(ENABLE_CLIST_DEBUG, false) +# AC_ARG_ENABLE(clist-debug, +# [ --enable-clist-debug Enable clist debug print], + # [AC_DEFINE_UNQUOTED(ENABLE_CLIST_DEBUG, , ENABLE_CLIST_DEBUG) + # AC_SUBST(LIBCLIST_CPPFLAGS, "-DCLIST_DEBUG") + # AM_CONDITIONAL(ENABLE_CLIST_DEBUG, true)], + # [ AC_SUBST(LIBCLIST_CPPFLAGS, "")]) + +AC_ARG_ENABLE(clist-debug, +[AS_HELP_STRING([--enable-clist-debug], [Enable clist debug print])], + AC_SUBST(LIBCLIST_CPPFLAGS, "-DCLIST_DEBUG"), + AC_SUBST(LIBCLIST_CPPFLAGS, "")) + + +# Checks for library functions. +#AC_FUNC_MALLOC + +AC_CONFIG_FILES([Makefile clist/Makefile samples/Makefile]) +AC_OUTPUT + +#AC_OUTPUT([Makefile clist/Makefile samples/Makefile]) diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt new file mode 100644 index 0000000..ae2db5d --- /dev/null +++ b/samples/CMakeLists.txt @@ -0,0 +1,26 @@ + +set(INS_BINDIR \"${EXECUTABLE_OUTPUT_PATH}\") +configure_file( + "${PROJECT_SOURCE_DIR}/samples/mydefines.h.in" + "${PROJECT_BINARY_DIR}/samples/mydefines.h" +) +add_definitions(-D_BINDIR=\"${EXECUTABLE_OUTPUT_PATH}\") + +set(CLIST_INTERNAL_INCLUDES "${CLIST_INTERNAL_INCLUDES}" "${PROJECT_SOURCE_DIR}/samples" "${PROJECT_BINARY_DIR}/samples") + +include_directories(${CLIST_INTERNAL_INCLUDES}) + +if(MSVC) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) +endif() + +set(SAMPLES_INSTALLTARGETS test-c) +add_executable(${SAMPLES_INSTALLTARGETS} test.c) +if(COMPILE_STATIC) + target_link_libraries(${SAMPLES_INSTALLTARGETS} clist-static) +else() + target_link_libraries(${SAMPLES_INSTALLTARGETS} clist-shared) +endif() + +install(TARGETS ${SAMPLES_INSTALLTARGETS} DESTINATION bin) + diff --git a/samples/Makefile.am b/samples/Makefile.am new file mode 100644 index 0000000..ec7a3ce --- /dev/null +++ b/samples/Makefile.am @@ -0,0 +1,22 @@ + +#AM_CFLAGS = -I$(top_srcdir)/clist + +bin_PROGRAMS = sample + +sample_CFLAGS = -I$(top_srcdir)/clist +sample_SOURCES = test.c +sample_LDADD = ../clist/libclist.la + +sample_CPPFLAGS = -D_BINDIR='"$(bindir)"' + +nodist_sample_SOURCES = mydefines.h +BUILT_SOURCES = mydefines.h +CLEANFILES = mydefines.h +mydefines.h: Makefile + echo '#define INSTALL_BINDIR "$(bindir)"' > $@ + + + + + + diff --git a/samples/memcheck.stp b/samples/memcheck.stp new file mode 100644 index 0000000..9ebfc58 --- /dev/null +++ b/samples/memcheck.stp @@ -0,0 +1,47 @@ + +probe begin { + printf("===============begin=============\n") +} + +//记录内存分配和释放的计数关联数组 +global g_mem_ref +//记录内存分配和释放的调用堆栈关联数组 +global g_mem_bt + +probe process("/lib64/libc.so.6").function("__libc_malloc").return { + if(target() == pid()) { + if(g_mem_ref[$return] == 0) { + g_mem_ref[$return]++ + g_mem_bt[$return] = sprint_ubacktrace() + } + } +} + +probe process("/lib64/libc.so.6").function("__libc_free").call { + if(target() == pid()) { + g_mem_ref[$mem]-- + if(g_mem_ref[$mem] == 0) { + if($mem != 0) { + //记录上次释放的调用堆栈 + g_mem_bt[$mem] = sprint_ubacktrace() + } + } else if(g_mem_ref[$mem] < 0 && $mem != 0) { + //如果调用free已经失衡,那就出现了重复释放内存的问题,这里输出当前调用堆栈,以及这个地址上次释放的调用堆栈 + printf("MMMMMMMMMMMMMMMMMMMMMMMMMMMM\n") + printf("g_mem_ref[%p]: %d\n", $mem, g_mem_ref[$mem]) + print_ubacktrace() + printf("last free backtrace:\n%s\n", g_mem_bt[$mem]) + printf("WWWWWWWWWWWWWWWWWWWWWWWWWWWW\n") + } + } +} + +probe end { + //最后输出产生泄漏的内存是在哪里分配的 + printf("===============end=============\n") + foreach(mem in g_mem_ref) { + if (g_mem_ref[mem] > 0) { + printf("%s\n", g_mem_bt[mem]) + } + } +} diff --git a/samples/mydefines.h.in b/samples/mydefines.h.in new file mode 100644 index 0000000..619b8fe --- /dev/null +++ b/samples/mydefines.h.in @@ -0,0 +1,2 @@ + +#define INSTALL_BINDIR ${INS_BINDIR} \ No newline at end of file diff --git a/samples/test.c b/samples/test.c new file mode 100644 index 0000000..4f452b6 --- /dev/null +++ b/samples/test.c @@ -0,0 +1,185 @@ + +#include "clist.h" +#include "mydefines.h" +#include +#include +#include + + +typedef struct member { + int no; + char str[20]; +}member; + +flag_t find_process_handler(const void* const data1, const void* const data2) { + member* p = (member*)data1; + if ((int)data2 == p->no) { + return true; + } else { + return false; + } +} + +flag_t sort_process_handler(const void* const data1, const void* const data2) { + member* p1 = (member*)data1; + member* p2 = (member*)data2; + if (p2->no > p1->no) { + return true; + } else { + return false; + } +} + +void showall(clist* pcl, flag_t dir) { + member* p; + clist_iterator_t it; + if (true == dir) { + printf("----------------- traverse from head to tail\n"); + it = clist_begin(pcl); + for (; it != clist_iterator_end; it = clist_step(it, increase, pcl)) { + p = clist_get(it); + printf("%d, %s\n", p->no, p->str); + } + } else { + printf("----------------- traverse from tail to head\n"); + it = clist_end(pcl); + for (; it != clist_iterator_end; it = clist_step(it, decrease, pcl)) { + p = clist_get(it); + printf("%d, %s\n", p->no, p->str); + } + } +} + +void test_data(clist *pcl) { + member* p; + + p = (member*)malloc(sizeof(member)); + p->no = 0; + strcpy(p->str, "name0"); + clist_add(pcl, p, true); + printf("insert tail: %d\n", p->no); + + p = (member*)malloc(sizeof(member)); + p->no = 10; + strcpy(p->str, "name10"); + clist_add(pcl, p, true); + printf("insert tail: %d\n", p->no); + + p = (member*)malloc(sizeof(member)); + p->no = 100; + strcpy(p->str, "name100"); + clist_add(pcl, p, true); + printf("insert tail: %d\n", p->no); + + p = (member*)malloc(sizeof(member)); + p->no = 1000; + strcpy(p->str, "name1000"); + clist_add(pcl, p, true); + printf("insert tail: %d\n", p->no); + + + p = (member*)malloc(sizeof(member)); + p->no = 0; + strcpy(p->str, "name-0"); + clist_add(pcl, p, false); + printf("insert front: %d\n", p->no); + + p = (member*)malloc(sizeof(member)); + p->no = -10; + strcpy(p->str, "name-10"); + clist_add(pcl, p, false); + printf("insert front: %d\n", p->no); + + p = (member*)malloc(sizeof(member)); + p->no = -100; + strcpy(p->str, "name-100"); + clist_add(pcl, p, false); + printf("insert front: %d\n", p->no); + + p = (member*)malloc(sizeof(member)); + p->no = -1000; + strcpy(p->str, "name-1000"); + clist_add(pcl, p, false); + printf("insert front: %d\n", p->no); +} + +int main(int argc, char* argv[]) +{ + // test to use defines in custom headers + printf("test to use defines in custom headers - INSTALL_BINDIR:%s\n", INSTALL_BINDIR); + // test to use preprocessor definitions + printf("test to use preprocessor definitions - _BINDIR:%s\n", _BINDIR); + + clist cl; + member* p; + clist_iterator_t it; + clist_errcode_t code; + + printf("press any key to begin..."); + getchar(); + + clist* test = NULL; + printf("----------------- invalid call -----------------\n"); + code = clist_create(test); + if (code != EOK) { + printf("%s\n", clist_get_error_string(code)); + } + + p = (member*)malloc(sizeof(member)); + p->no = 3546846; + strcpy(p->str, "xasxas"); + code = clist_add(test, p, true); + if (code != EOK) { + printf("%s\n", clist_get_error_string(code)); + free(p); + } + + clist_create(&cl); + + printf("----------------- input data -----------------\n"); + test_data(&cl); + + showall(&cl, true); + + showall(&cl, false); + + printf("----------------- find data -----------------\n"); + it = NULL; + while (1) { + it = clist_find(it, &cl, find_process_handler, 0); + if (it == clist_iterator_end) { + break; + } + p = clist_get(it); + printf("%d, %s\n", p->no, p->str); + it = clist_step(it, increase, &cl); + } + + printf("----------------- modify data -----------------\n"); + it = clist_find(NULL, &cl, find_process_handler, (void*)-1000); + if (it != clist_iterator_end) { + p = clist_get(it); + strcpy(p->str, "modified"); + } + showall(&cl, true); + + printf("----------------- delete data -----------------\n"); + it = NULL; + while (1) { + it = clist_find(it, &cl, find_process_handler, 0); + if (it == clist_iterator_end) { + break; + } else { + it = clist_erase(it, &cl); + } + } + showall(&cl, true); + + printf("----------------- sort -----------------\n"); + clist_sort(NULL, &cl, sort_process_handler); + showall(&cl, true); + + clist_destroy(&cl); + + return 0; +}