├── .gitignore ├── 3rdparty └── zlib │ ├── README │ ├── adler32.c │ ├── deflate.c │ ├── deflate.h │ ├── inffast.c │ ├── inffast.h │ ├── inffixed.h │ ├── inflate.c │ ├── inflate.h │ ├── inftrees.c │ ├── inftrees.h │ ├── trees.c │ ├── trees.h │ ├── zconf.h │ ├── zlib.h │ ├── zutil.c │ └── zutil.h ├── CMakeLists.txt ├── Doxyfile.in ├── LICENSE ├── Makefile.am ├── README ├── autogen.sh ├── configure.ac ├── doc ├── compiling.dox ├── pageorder.dox ├── s0.png ├── s1.png ├── s2.png └── s3.png ├── m4 ├── ax_prog_doxygen.m4 └── ax_pthread.m4 ├── main ├── CMakeLists.txt ├── Makemodule.am ├── include │ ├── tl_allocator.h │ ├── tl_array.h │ ├── tl_blob.h │ ├── tl_hash.h │ ├── tl_hashmap.h │ ├── tl_iostream.h │ ├── tl_iterator.h │ ├── tl_list.h │ ├── tl_opt.h │ ├── tl_predef.h │ ├── tl_rbtree.h │ ├── tl_sort.h │ ├── tl_string.h │ ├── tl_transform.h │ ├── tl_unicode.h │ ├── tl_utf16.h │ └── tl_utf8.h └── src │ ├── allocator.c │ ├── array.c │ ├── blob.c │ ├── hash │ ├── crc32.c │ └── murmur3.c │ ├── hashmap.c │ ├── iostream │ ├── printf.c │ ├── read_blob.c │ └── read_line.c │ ├── iterator │ ├── array.c │ ├── hashmap.c │ └── list.c │ ├── list.c │ ├── list_node.c │ ├── opt.c │ ├── rbtree.c │ ├── search │ ├── array.c │ ├── array_insert_sorted.c │ ├── array_unsorted.c │ ├── list.c │ └── list_insert_sorted.c │ ├── sort │ ├── heap.c │ ├── insertion.c │ ├── merge.c │ ├── merge_array.c │ ├── merge_ip.c │ ├── merge_list.c │ └── quick.c │ ├── string.c │ ├── string │ ├── allocator.c │ ├── append_latin1.c │ ├── append_utf16.c │ ├── append_utf8.c │ ├── to_utf16.c │ ├── tokenize.c │ └── trim.c │ ├── transform.c │ ├── unicode │ ├── isspace.c │ ├── utf16.c │ └── utf8.c │ ├── xfrm │ ├── base64_dec.c │ ├── base64_enc.c │ ├── deflate.c │ ├── inflate.c │ ├── xfrm.c │ └── xfrm.h │ └── xfrm_blob.c ├── os ├── CMakeLists.txt ├── Makemodule.am ├── include │ ├── tl_dir.h │ ├── tl_file.h │ ├── tl_fs.h │ ├── tl_network.h │ ├── tl_packetserver.h │ ├── tl_process.h │ ├── tl_server.h │ ├── tl_splice.h │ ├── tl_thread.h │ ├── tl_threadpool.h │ └── tl_unix.h └── src │ ├── W32 │ ├── dir_it.c │ ├── dir_scan.c │ ├── file.c │ ├── fs.c │ ├── fstream.c │ ├── iostream.c │ ├── monitor.c │ ├── mutex.c │ ├── network.c │ ├── os.c │ ├── os.h │ ├── path.c │ ├── process.c │ ├── rwlock.c │ ├── sockstream.c │ ├── thread.c │ └── threadpool.c │ ├── bsdsock │ ├── addr_v6.c │ ├── bsdsock.h │ ├── network.c │ ├── resolve_addr.c │ ├── resolve_name.c │ ├── sock.c │ ├── tcpserver.c │ └── udpserver.c │ ├── network.c │ ├── platform.h │ ├── splice.c │ └── unix │ ├── dir_it.c │ ├── dir_scan.c │ ├── fdstream.c │ ├── file.c │ ├── fs.c │ ├── iostream.c │ ├── monitor.c │ ├── mutex.c │ ├── network.c │ ├── os.c │ ├── os.h │ ├── process.c │ ├── rwlock.c │ ├── thread.c │ └── threadpool.c ├── samples ├── CMakeLists.txt ├── Makemodule.am ├── cmdline.c ├── compress.c ├── dirlist.c ├── genpng.c ├── lookup.c └── stdio.c └── tests ├── Makemodule.am ├── childproc.c ├── test_array.c ├── test_base64.c ├── test_blob.c ├── test_fs.c ├── test_hash.c ├── test_hashmap.c ├── test_iterator.c ├── test_iterator_hashmap.c ├── test_list.c ├── test_namelookup.c ├── test_opt.c ├── test_packetserver.c ├── test_process.c ├── test_process_wrap.sh.in ├── test_rbtree.c ├── test_rwlock.c ├── test_sort.c ├── test_string.c ├── test_string2.c ├── test_tcp.c ├── test_thread.c ├── test_threadpool.c ├── test_udp.c └── test_udpbroadcast.c /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *# 3 | build/ 4 | *.o 5 | *.lo 6 | *.la 7 | .* 8 | *.log 9 | *.trs 10 | test_* 11 | test-driver 12 | childproc 13 | Makefile 14 | Makefile.in 15 | aclocal.m4 16 | autom4te.cache/ 17 | compile 18 | confdefs.h 19 | config.* 20 | configure 21 | depcomp 22 | install-sh 23 | libtool 24 | ltmain.sh 25 | m4/ 26 | missing 27 | compress 28 | dirlist 29 | genpng 30 | lookup 31 | stdio 32 | cmdline 33 | Doxyfile 34 | doxygen-doc 35 | -------------------------------------------------------------------------------- /3rdparty/zlib/inffast.h: -------------------------------------------------------------------------------- 1 | /* inffast.h -- header to use inffast.c 2 | * Copyright (C) 1995-2003, 2010 Mark Adler 3 | * For conditions of distribution and use, see copyright notice in zlib.h 4 | */ 5 | 6 | /* WARNING: this file should *not* be used by applications. It is 7 | part of the implementation of the compression library and is 8 | subject to change. Applications should only use zlib.h. 9 | */ 10 | 11 | void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start)); 12 | -------------------------------------------------------------------------------- /3rdparty/zlib/inftrees.h: -------------------------------------------------------------------------------- 1 | /* inftrees.h -- header to use inftrees.c 2 | * Copyright (C) 1995-2005, 2010 Mark Adler 3 | * For conditions of distribution and use, see copyright notice in zlib.h 4 | */ 5 | 6 | /* WARNING: this file should *not* be used by applications. It is 7 | part of the implementation of the compression library and is 8 | subject to change. Applications should only use zlib.h. 9 | */ 10 | 11 | /* Structure for decoding tables. Each entry provides either the 12 | information needed to do the operation requested by the code that 13 | indexed that table entry, or it provides a pointer to another 14 | table that indexes more bits of the code. op indicates whether 15 | the entry is a pointer to another table, a literal, a length or 16 | distance, an end-of-block, or an invalid code. For a table 17 | pointer, the low four bits of op is the number of index bits of 18 | that table. For a length or distance, the low four bits of op 19 | is the number of extra bits to get after the code. bits is 20 | the number of bits in this code or part of the code to drop off 21 | of the bit buffer. val is the actual byte to output in the case 22 | of a literal, the base length or distance, or the offset from 23 | the current table to the next table. Each entry is four bytes. */ 24 | typedef struct { 25 | unsigned char op; /* operation, extra bits, table bits */ 26 | unsigned char bits; /* bits in this part of the code */ 27 | unsigned short val; /* offset in table or code value */ 28 | } code; 29 | 30 | /* op values as set by inflate_table(): 31 | 00000000 - literal 32 | 0000tttt - table link, tttt != 0 is the number of table index bits 33 | 0001eeee - length or distance, eeee is the number of extra bits 34 | 01100000 - end of block 35 | 01000000 - invalid code 36 | */ 37 | 38 | /* Maximum size of the dynamic table. The maximum number of code structures is 39 | 1444, which is the sum of 852 for literal/length codes and 592 for distance 40 | codes. These values were found by exhaustive searches using the program 41 | examples/enough.c found in the zlib distribtution. The arguments to that 42 | program are the number of symbols, the initial root table size, and the 43 | maximum bit length of a code. "enough 286 9 15" for literal/length codes 44 | returns returns 852, and "enough 30 6 15" for distance codes returns 592. 45 | The initial root table size (9 or 6) is found in the fifth argument of the 46 | inflate_table() calls in inflate.c and infback.c. If the root table size is 47 | changed, then these maximum sizes would be need to be recalculated and 48 | updated. */ 49 | #define ENOUGH_LENS 852 50 | #define ENOUGH_DISTS 592 51 | #define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS) 52 | 53 | /* Type of code to build for inflate_table() */ 54 | typedef enum { 55 | CODES, 56 | LENS, 57 | DISTS 58 | } codetype; 59 | 60 | int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens, 61 | unsigned codes, code FAR * FAR *table, 62 | unsigned FAR *bits, unsigned short FAR *work)); 63 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project( ctools C ) 2 | 3 | cmake_minimum_required( VERSION 2.6 ) 4 | 5 | set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" ) 6 | set( CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" ) 7 | set( CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" ) 8 | 9 | set( PROJECT_BRIEF "A collection of tools and utillities for C programs" ) 10 | 11 | if( NOT WIN32 ) 12 | message( FATAL_ERROR "The CMake file only exists for compiling on Windows! Please use the Autotools build system" ) 13 | endif( ) 14 | 15 | #---------------------------------------------------------------------- 16 | # Feature configuration 17 | #---------------------------------------------------------------------- 18 | 19 | option( SHARED "Build a dynamic instead of a static library" OFF ) 20 | option( HAVE_DEFLATE "Support deflate compression" ON ) 21 | 22 | if( SHARED ) 23 | add_definitions( -DTL_SHARED ) 24 | endif( ) 25 | 26 | if( HAVE_DEFLATE ) 27 | add_definitions( -DTL_HAVE_DEFLATE ) 28 | endif( ) 29 | 30 | #---------------------------------------------------------------------- 31 | # Compiler detection and configuration 32 | #---------------------------------------------------------------------- 33 | if( CMAKE_COMPILER_IS_GNUCC OR MINGW ) 34 | message( STATUS "Compiling with gcc" ) 35 | set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ansi -pedantic" ) 36 | set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wshadow -Wwrite-strings" ) 37 | set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror" ) 38 | 39 | set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -ggdb" ) 40 | set( CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3 -Ofast" ) 41 | endif( ) 42 | 43 | if( MSVC ) 44 | message( STATUS "Compiling with MSVC" ) 45 | 46 | add_definitions( /D_CRT_SECURE_NO_WARNINGS ) 47 | add_definitions( /DUNICODE ) 48 | 49 | set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4005 /wd4996 /nologo /Oi" ) 50 | endif( ) 51 | 52 | #---------------------------------------------------------------------- 53 | # Configure targets 54 | #---------------------------------------------------------------------- 55 | set( CTOOLS_SYSLIBS userenv ws2_32 ) 56 | 57 | include_directories( ${CMAKE_SOURCE_DIR}/main/include/ 58 | ${CMAKE_SOURCE_DIR}/os/include/ ) 59 | 60 | if( SHARED ) 61 | set( TYPE SHARED ) 62 | else( ) 63 | set( TYPE STATIC ) 64 | endif( ) 65 | 66 | add_subdirectory( main ) 67 | add_subdirectory( os ) 68 | add_subdirectory( samples ) 69 | 70 | #---------------------------------------------------------------------- 71 | # Configure tests 72 | #---------------------------------------------------------------------- 73 | enable_testing( ) 74 | 75 | function( testcase name args ) 76 | add_executable( ${name} tests/${name}.c ) 77 | target_link_libraries( ${name} tlcore tlos ${CTOOLS_SYSLIBS} ) 78 | 79 | set( command 80 | "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${name}${CMAKE_EXECUTABLE_SUFFIX}" ) 81 | 82 | add_test( ${name} ${command} ${args} ) 83 | endfunction( ) 84 | 85 | add_executable( childproc tests/childproc.c ) 86 | target_link_libraries( childproc tlcore tlos ${CTOOLS_SYSLIBS} ) 87 | set( childexe 88 | "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/childproc${CMAKE_EXECUTABLE_SUFFIX}" ) 89 | 90 | testcase( test_array "" ) 91 | testcase( test_list "" ) 92 | testcase( test_rbtree "" ) 93 | testcase( test_sort "" ) 94 | testcase( test_string "" ) 95 | testcase( test_string2 "" ) 96 | testcase( test_fs "" ) 97 | testcase( test_hashmap "" ) 98 | testcase( test_iterator "" ) 99 | testcase( test_iterator_hashmap "" ) 100 | testcase( test_blob "" ) 101 | testcase( test_base64 "" ) 102 | testcase( test_namelookup "" ) 103 | testcase( test_tcp "" ) 104 | testcase( test_udp "" ) 105 | testcase( test_process "${childexe}" ) 106 | testcase( test_opt "" ) 107 | testcase( test_packetserver "" ) 108 | testcase( test_udpbroadcast "" ) 109 | testcase( test_thread "" ) 110 | testcase( test_rwlock "" ) 111 | testcase( test_threadpool "" ) 112 | testcase( test_hash "" ) 113 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Copyright (C) 2015 - David Oberhollenzer 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | 22 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | ACLOCAL_AMFLAGS = -I m4 2 | 3 | INC_FLAGS = -I$(top_srcdir)/main/include -I$(top_srcdir)/os/include 4 | 5 | AM_CPPFLAGS = -D_GNU_SOURCE $(INC_FLAGS) 6 | AM_CFLAGS = -ansi -pedantic -Wall -Wextra 7 | 8 | if HAVE_DEFLATE 9 | AM_CPPFLAGS += -DTL_HAVE_DEFLATE 10 | endif 11 | 12 | 13 | ZLIB_SRC = \ 14 | 3rdparty/zlib/adler32.c \ 15 | 3rdparty/zlib/deflate.c \ 16 | 3rdparty/zlib/deflate.h \ 17 | 3rdparty/zlib/inffast.c \ 18 | 3rdparty/zlib/inffast.h \ 19 | 3rdparty/zlib/inffixed.h \ 20 | 3rdparty/zlib/trees.c \ 21 | 3rdparty/zlib/trees.h \ 22 | 3rdparty/zlib/inflate.c \ 23 | 3rdparty/zlib/inflate.h \ 24 | 3rdparty/zlib/inftrees.c \ 25 | 3rdparty/zlib/inftrees.h \ 26 | 3rdparty/zlib/zutil.c \ 27 | 3rdparty/zlib/zutil.h \ 28 | 3rdparty/zlib/zconf.h \ 29 | 3rdparty/zlib/zlib.h 30 | 31 | ZLIB_EXTRA = \ 32 | 3rdparty/zlib/README 33 | 34 | 35 | include_HEADERS = 36 | lib_LTLIBRARIES = 37 | noinst_PROGRAMS = 38 | check_PROGRAMS = 39 | check_SCRIPTS = 40 | 41 | TESTS = 42 | EXTRA_DIST = LICENSE README doc $(ZLIB_SRC) $(ZLIB_EXTRA) 43 | 44 | EXTRA_DIST += CMakeLists.txt samples/CMakeLists.txt \ 45 | os/CMakeLists.txt main/CMakeLists.txt 46 | 47 | include main/Makemodule.am 48 | include os/Makemodule.am 49 | include samples/Makemodule.am 50 | include tests/Makemodule.am 51 | 52 | if HAVE_DOXYGEN 53 | @DX_RULES@ 54 | 55 | MOSTLYCLEANFILES = $(DX_CLEANFILES) 56 | endif 57 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | autoreconf --force --install --symlink 4 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_PREREQ([2.60]) 2 | 3 | AC_INIT([ctools], 0.1, [david.oberhollenzer@tele2.at], ctools) 4 | AC_CONFIG_MACRO_DIR([m4]) 5 | AM_INIT_AUTOMAKE([foreign subdir-objects dist-bzip2]) 6 | AM_SILENT_RULES([yes]) 7 | AC_PROG_CC 8 | AC_PROG_INSTALL 9 | AC_CANONICAL_HOST 10 | LT_INIT([win32-dll]) 11 | 12 | AC_SUBST(PROJECT_BRIEF, ["A collection of tools and utillities for C programs"]) 13 | 14 | ##### host OS detection ##### 15 | build_windows="no" 16 | need_pthread="no" 17 | 18 | case "${host_os}" in 19 | cygwin*|mingw*) 20 | AC_MSG_NOTICE(["Building for Windows"]) 21 | build_windows="yes" 22 | ;; 23 | *) 24 | AC_MSG_NOTICE(["Building for a generic UNIX-like OS"]) 25 | need_pthread="yes" 26 | ;; 27 | esac 28 | 29 | AM_CONDITIONAL([BUILD_WINDOWS], [test "x$build_windows" = "xyes"]) 30 | 31 | ###### handle configure switches, select dependencies ###### 32 | 33 | need_zlib="no" 34 | 35 | 36 | AC_ARG_ENABLE([deflate], 37 | [AS_HELP_STRING([--enable-deflate], [Support deflate compression])], 38 | [case "${enableval}" in 39 | yes) AM_CONDITIONAL([HAVE_DEFLATE], [true]) ;; 40 | no) AM_CONDITIONAL([HAVE_DEFLATE], [false]) ;; 41 | *) AC_MSG_ERROR([bad value ${enableval} for --disable-deflate]) ;; 42 | esac], 43 | [AM_CONDITIONAL([HAVE_DEFLATE], [true])]) 44 | 45 | AM_COND_IF([HAVE_DEFLATE], [ 46 | need_zlib="yes" 47 | ]) 48 | 49 | 50 | AC_ARG_WITH([builtin-zlib], 51 | [AS_HELP_STRING([--with-builtin-zlib], [Use built in zlib])], 52 | [case "${withval}" in 53 | yes) AM_CONDITIONAL([BUILTIN_ZLIB], [true]) ;; 54 | no) AM_CONDITIONAL([BUILTIN_ZLIB], [false]) ;; 55 | *) AC_MSG_ERROR([bad value ${withval} for --with-builtin-zlib]) ;; 56 | esac], 57 | [AM_CONDITIONAL([BUILTIN_ZLIB], [false])]) 58 | 59 | AM_COND_IF([BUILTIN_ZLIB], [ 60 | need_zlib="no" 61 | ]) 62 | 63 | ##### search for dependencies ##### 64 | 65 | zlib_missing="no" 66 | pthread_missing="no" 67 | 68 | if test "x$need_zlib" = "xyes"; then 69 | PKG_CHECK_MODULES(ZLIB, [zlib], [], [zlib_missing="yes"]) 70 | fi 71 | 72 | if test "x$need_pthread" = "xyes"; then 73 | AX_PTHREAD([], [pthread_missing="yes"]) 74 | fi 75 | 76 | ##### produce summary on dependencies ##### 77 | 78 | dep_missing="no" 79 | 80 | if test "x$zlib_missing" = "xyes"; then 81 | AC_MSG_WARN([cannot find ZLIB library]) 82 | AC_MSG_NOTICE([Deflate/inflate support can optionally be disabled]) 83 | AC_MSG_NOTICE([A builtin version of zlib can optionally be used]) 84 | dep_missing="yes" 85 | fi 86 | 87 | if test "x$pthread_missing" = "xyes"; then 88 | AC_MSG_WARN([cannot find pthread compiler flags/libraries]) 89 | dep_missing="yes" 90 | fi 91 | 92 | if test "x$dep_missing" = "xyes"; then 93 | AC_MSG_ERROR([missing one or more dependencies]) 94 | fi 95 | 96 | ##### Doxygen reference manual & documentation ##### 97 | 98 | AC_CHECK_PROGS([DOXYGEN], [doxygen]) 99 | AM_CONDITIONAL([HAVE_DOXYGEN], [test -n "$DOXYGEN"]) 100 | 101 | if test -z "$DOXYGEN"; then 102 | AC_MSG_WARN([Doxygen not found - continuing without Doxygen support]) 103 | else 104 | AC_CONFIG_FILES([Doxyfile]) 105 | 106 | DX_DOXYGEN_FEATURE(ON) 107 | DX_DOT_FEATURE(ON) 108 | DX_HTML_FEATURE(ON) 109 | DX_CHM_FEATURE(OFF) 110 | DX_CHI_FEATURE(OFF) 111 | DX_MAN_FEATURE(ON) 112 | DX_RTF_FEATURE(OFF) 113 | DX_XML_FEATURE(OFF) 114 | DX_PDF_FEATURE(ON) 115 | DX_PS_FEATURE(OFF) 116 | DX_INIT_DOXYGEN(ctools, Doxyfile) 117 | fi 118 | 119 | ##### generate output ##### 120 | 121 | AC_CONFIG_FILES([tests/test_process_wrap.sh], 122 | [chmod +x tests/test_process_wrap.sh]) 123 | AC_OUTPUT([Makefile]) 124 | -------------------------------------------------------------------------------- /doc/pageorder.dox: -------------------------------------------------------------------------------- 1 | /** 2 | \page compiling Compiling the library from source 3 | \page containers Containers 4 | \page kvcontainers Key-Value-Containers 5 | \page sorting Sorting Algorithms 6 | \page hash Hash and Check Sum Algorithms 7 | \page comp Data Compression and Transformation 8 | \page stringproc String processing functions 9 | \page filesystem Filesystem 10 | \page io Input/Output 11 | \page conc Concurrency 12 | \page interfaces Interfaces 13 | \page util Miscellaneous Utilities 14 | 15 | \example lookup.c 16 | \example dirlist.c 17 | \example cmdline.c 18 | */ 19 | -------------------------------------------------------------------------------- /doc/s0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AgentD/ctools/85281b6e50382f3106a5d7bac6bb541238e885d2/doc/s0.png -------------------------------------------------------------------------------- /doc/s1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AgentD/ctools/85281b6e50382f3106a5d7bac6bb541238e885d2/doc/s1.png -------------------------------------------------------------------------------- /doc/s2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AgentD/ctools/85281b6e50382f3106a5d7bac6bb541238e885d2/doc/s2.png -------------------------------------------------------------------------------- /doc/s3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AgentD/ctools/85281b6e50382f3106a5d7bac6bb541238e885d2/doc/s3.png -------------------------------------------------------------------------------- /main/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if( HAVE_DEFLATE ) 2 | set( ZLIB_DIR ${CMAKE_SOURCE_DIR}/3rdparty/zlib ) 3 | 4 | if( MSVC ) 5 | add_definitions( /D_CRT_NONSTDC_NO_DEPRECATE ) 6 | endif( ) 7 | 8 | add_definitions(-DZLIB_CONST=1) 9 | add_definitions(-DNO_GZCOMPRESS=1) 10 | add_definitions(-DNO_GZIP=1) 11 | add_definitions(-DHAVE_MEMCPY=1) 12 | 13 | include_directories( ${ZLIB_DIR}/${ZLIB_INCLUDE_DIRS} ) 14 | 15 | set( ZLIB_SRCS ${ZLIB_DIR}/adler32.c 16 | ${ZLIB_DIR}/deflate.c 17 | ${ZLIB_DIR}/inffast.c 18 | ${ZLIB_DIR}/trees.c 19 | ${ZLIB_DIR}/inflate.c 20 | ${ZLIB_DIR}/inftrees.c 21 | ${ZLIB_DIR}/zutil.c ) 22 | 23 | message( STATUS "Using our own zlib copy" ) 24 | 25 | set( XFRM_SRC src/xfrm/deflate.c 26 | src/xfrm/inflate.c ) 27 | endif( ) 28 | 29 | set( XFRM_SRC ${XFRM_SRC} 30 | src/xfrm/base64_enc.c 31 | src/xfrm/base64_dec.c ) 32 | 33 | set( SEARCH_SRC src/search/array.c 34 | src/search/array_insert_sorted.c 35 | src/search/array_unsorted.c 36 | src/search/list.c 37 | src/search/list_insert_sorted.c ) 38 | 39 | set( HASH_SRC src/hash/crc32.c 40 | src/hash/murmur3.c ) 41 | 42 | set( SORT_SRC src/sort/heap.c 43 | src/sort/insertion.c 44 | src/sort/merge.c 45 | src/sort/merge_ip.c 46 | src/sort/merge_list.c 47 | src/sort/merge_array.c 48 | src/sort/quick.c ) 49 | 50 | set( ITER_SRC src/iterator/array.c 51 | src/iterator/list.c 52 | src/iterator/hashmap.c ) 53 | 54 | set( STRING_SRC src/string.c 55 | src/string/trim.c 56 | src/string/append_utf8.c 57 | src/string/append_utf16.c 58 | src/string/append_latin1.c 59 | src/string/to_utf16.c 60 | src/string/tokenize.c 61 | src/string/allocator.c ) 62 | 63 | set( UNICODE_SRC src/unicode/isspace.c 64 | src/unicode/utf16.c 65 | src/unicode/utf8.c ) 66 | 67 | set( IOSTREAM_SRC src/iostream/printf.c 68 | src/iostream/read_blob.c 69 | src/iostream/read_line.c ) 70 | 71 | add_library( tlcore ${TYPE} src/array.c 72 | src/list.c 73 | src/list_node.c 74 | src/rbtree.c 75 | src/hashmap.c 76 | src/allocator.c 77 | src/blob.c 78 | src/transform.c 79 | src/xfrm_blob.c 80 | src/opt.c 81 | src/xfrm/xfrm.c 82 | ${IOSTREAM_SRC} 83 | ${UNICODE_SRC} 84 | ${STRING_SRC} 85 | ${SEARCH_SRC} 86 | ${SORT_SRC} 87 | ${HASH_SRC} 88 | ${XFRM_SRC} 89 | ${ITER_SRC} 90 | ${ZLIB_SRCS} ) 91 | 92 | if( SHARED ) 93 | set_target_properties( tlcore PROPERTIES PREFIX "" ) 94 | endif( ) 95 | -------------------------------------------------------------------------------- /main/Makemodule.am: -------------------------------------------------------------------------------- 1 | XFRM_SRC = \ 2 | main/src/xfrm/base64_dec.c \ 3 | main/src/xfrm/base64_enc.c \ 4 | main/src/xfrm/deflate.c \ 5 | main/src/xfrm/inflate.c \ 6 | main/src/xfrm/xfrm.c \ 7 | main/src/xfrm/xfrm.h 8 | 9 | UNICODE_SRC = \ 10 | main/src/unicode/isspace.c \ 11 | main/src/unicode/utf8.c \ 12 | main/src/unicode/utf16.c 13 | 14 | STRING_SRC = \ 15 | main/src/string/allocator.c \ 16 | main/src/string/append_latin1.c \ 17 | main/src/string/append_utf8.c \ 18 | main/src/string/append_utf16.c \ 19 | main/src/string/tokenize.c \ 20 | main/src/string/to_utf16.c \ 21 | main/src/string/trim.c 22 | 23 | SORT_SRC = \ 24 | main/src/sort/heap.c \ 25 | main/src/sort/insertion.c \ 26 | main/src/sort/merge.c \ 27 | main/src/sort/merge_array.c \ 28 | main/src/sort/merge_ip.c \ 29 | main/src/sort/merge_list.c \ 30 | main/src/sort/quick.c 31 | 32 | SEARCH_SRC = \ 33 | main/src/search/array.c \ 34 | main/src/search/array_insert_sorted.c \ 35 | main/src/search/array_unsorted.c \ 36 | main/src/search/list.c \ 37 | main/src/search/list_insert_sorted.c 38 | 39 | ITERATOR_SRC = \ 40 | main/src/iterator/array.c \ 41 | main/src/iterator/hashmap.c \ 42 | main/src/iterator/list.c 43 | 44 | IOSTREAM_SRC = \ 45 | main/src/iostream/printf.c \ 46 | main/src/iostream/read_blob.c \ 47 | main/src/iostream/read_line.c 48 | 49 | HASH_SRC = \ 50 | main/src/hash/crc32.c \ 51 | main/src/hash/murmur3.c 52 | 53 | CORE_SRC = \ 54 | main/src/allocator.c \ 55 | main/src/array.c \ 56 | main/src/blob.c \ 57 | main/src/hashmap.c \ 58 | main/src/list.c \ 59 | main/src/list_node.c \ 60 | main/src/opt.c \ 61 | main/src/rbtree.c \ 62 | main/src/string.c \ 63 | main/src/transform.c \ 64 | main/src/xfrm_blob.c 65 | 66 | CORE_HDR = \ 67 | main/include/tl_allocator.h \ 68 | main/include/tl_array.h \ 69 | main/include/tl_blob.h \ 70 | main/include/tl_hash.h \ 71 | main/include/tl_hashmap.h \ 72 | main/include/tl_iostream.h \ 73 | main/include/tl_iterator.h \ 74 | main/include/tl_list.h \ 75 | main/include/tl_opt.h \ 76 | main/include/tl_predef.h \ 77 | main/include/tl_rbtree.h \ 78 | main/include/tl_sort.h \ 79 | main/include/tl_string.h \ 80 | main/include/tl_transform.h \ 81 | main/include/tl_unicode.h \ 82 | main/include/tl_utf8.h \ 83 | main/include/tl_utf16.h 84 | 85 | libtlcore_la_SOURCES = \ 86 | $(XFRM_SRC) \ 87 | $(UNICODE_SRC) \ 88 | $(STRING_SRC) \ 89 | $(SORT_SRC) \ 90 | $(SEARCH_SRC) \ 91 | $(ITERATOR_SRC) \ 92 | $(IOSTREAM_SRC) \ 93 | $(HASH_SRC) \ 94 | $(CORE_SRC) \ 95 | $(CORE_HDR) 96 | 97 | libtlcore_la_CPPFLAGS = $(AM_CPPFLAGS) 98 | libtlcore_la_CFLAGS = $(AM_CFLAGS) $(ZLIB_CFLAGS) 99 | libtlcore_la_LDFLAGS = $(AM_LDFLAGS) 100 | libtlcore_la_LIBADD = $(ZLIB_LIBS) 101 | 102 | if BUILD_WINDOWS 103 | libtlcore_la_LDFLAGS += -no-undefined 104 | endif 105 | 106 | if BUILTIN_ZLIB 107 | libtlcore_la_CPPFLAGS += -D_LARGEFILE64_SOURCE=1 108 | libtlcore_la_CPPFLAGS += -DZLIB_CONST=1 109 | libtlcore_la_CPPFLAGS += -DNO_GZCOMPRESS=1 110 | libtlcore_la_CPPFLAGS += -DNO_GZIP=1 111 | libtlcore_la_CPPFLAGS += -DHAVE_MEMCPY=1 112 | libtlcore_la_CPPFLAGS += -I$(top_srcdir)/3rdparty/zlib 113 | libtlcore_la_SOURCES += $(ZLIB_SRC) 114 | endif 115 | 116 | include_HEADERS += $(CORE_HDR) 117 | lib_LTLIBRARIES += libtlcore.la 118 | -------------------------------------------------------------------------------- /main/include/tl_unicode.h: -------------------------------------------------------------------------------- 1 | /* 2 | * tl_unicode.h 3 | * This file is part of ctools 4 | * 5 | * Copyright (C) 2015 - David Oberhollenzer 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a 8 | * copy of this software and associated documentation files (the "Software"), 9 | * to deal in the Software without restriction, including without limitation 10 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | * and/or sell copies of the Software, and to permit persons to whom the 12 | * Software is furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | * DEALINGS IN THE SOFTWARE. 24 | */ 25 | 26 | /** 27 | * \file tl_unicode.h 28 | * 29 | * \brief Contains unicode helper functions 30 | */ 31 | 32 | #ifndef TOOLS_UNICODE_H 33 | #define TOOLS_UNICODE_H 34 | 35 | #include "tl_predef.h" 36 | 37 | /** 38 | * \page stringproc String processing functions 39 | * 40 | * \section unicode Unicode helper functions 41 | * 42 | * The following utility functions are provided for processing 43 | * unicode code points: 44 | * \li tl_isspace 45 | */ 46 | 47 | /** 48 | * \enum TL_CHAR_TYPE 49 | * 50 | * \brief Simple classification of Unicode characters 51 | */ 52 | typedef enum { 53 | /** \brief Character is a whitespace character */ 54 | TL_SPACE = 0x01, 55 | 56 | /** \brief Whitespace character is a non-breaking space */ 57 | TL_NB_SPACE = 0x02 58 | } TL_CHAR_TYPE; 59 | 60 | #ifdef __cplusplus 61 | extern "C" { 62 | #endif 63 | 64 | /** 65 | * \brief Determine if a unicode code point is a whitespace character 66 | * 67 | * A character is reported as whitespace character if it meets one of the 68 | * following criteria: 69 | * \li It is a Unicode space character (category Zs) 70 | * \li It is a Unicode line seperator (category Zl) 71 | * \li It is a Unicode paragraph seperator (category Zp) 72 | * \li It is U+0009 HORIZONTAL TABULATION. 73 | * \li It is U+000A LINE FEED. 74 | * \li It is U+000B VERTICAL TABULATION. 75 | * \li It is U+000C FORM FEED. 76 | * \li It is U+000D CARRIAGE RETURN. 77 | * \li It is U+001C FILE SEPARATOR. 78 | * \li It is U+001D GROUP SEPARATOR. 79 | * \li It is U+001E RECORD SEPARATOR. 80 | * \li It is U+001F UNIT SEPARATOR. 81 | * 82 | * \param cp The code point to test 83 | * 84 | * \return Zero if it is not a space, a combination of \ref TL_CHAR_TYPE 85 | * flags if it is 86 | */ 87 | TLAPI int tl_isspace(int cp); 88 | 89 | #ifdef __cplusplus 90 | } 91 | #endif 92 | 93 | #endif /* TOOLS_UNICODE_H */ 94 | 95 | -------------------------------------------------------------------------------- /main/src/allocator.c: -------------------------------------------------------------------------------- 1 | /* allocator.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_EXPORT 9 | #include "tl_allocator.h" 10 | 11 | #include 12 | 13 | void tl_allocator_copy(tl_allocator * this, void *dst, const void *src, 14 | size_t blocksize, size_t count) 15 | { 16 | const char *sptr = src; 17 | char *dptr = dst; 18 | size_t i; 19 | 20 | if (!dst || !src || !blocksize || !count) 21 | return; 22 | 23 | if (this && this->copy_inplace) { 24 | for (i = 0; i < count; 25 | ++i, dptr += blocksize, sptr += blocksize) { 26 | this->copy_inplace(this, dptr, sptr); 27 | } 28 | } else { 29 | memcpy(dst, src, blocksize * count); 30 | } 31 | } 32 | 33 | void tl_allocator_init(tl_allocator * this, void *block, 34 | size_t blocksize, size_t count) 35 | { 36 | char *ptr = block; 37 | size_t i; 38 | 39 | if (!block || !blocksize || !count) 40 | return; 41 | 42 | if (this && this->init) { 43 | for (i = 0; i < count; ++i, ptr += blocksize) { 44 | this->init(this, ptr); 45 | } 46 | } else { 47 | memset(block, 0, blocksize * count); 48 | } 49 | } 50 | 51 | void tl_allocator_cleanup(tl_allocator * this, void *block, 52 | size_t blocksize, size_t count) 53 | { 54 | char *ptr = block; 55 | size_t i; 56 | 57 | if (!block || !blocksize || !count || !this || !this->cleanup) 58 | return; 59 | 60 | for (i = 0; i < count; ++i, ptr += blocksize) { 61 | this->cleanup(this, ptr); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /main/src/hash/crc32.c: -------------------------------------------------------------------------------- 1 | /* crc32.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_EXPORT 9 | #include "tl_hash.h" 10 | #include 11 | 12 | /* 13 | Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C 14 | implementation that balances processor cache usage against speed" 15 | */ 16 | static const tl_u32 s_crc32[16] = { 17 | 0x00000000, 0x1DB71064, 0x3B6E20C8, 0x26D930AC, 18 | 0x76DC4190, 0x6B6B51F4, 0x4DB26158, 0x5005713C, 19 | 0xEDB88320, 0xF00F9344, 0xD6D6A3E8, 0xCB61B38C, 20 | 0x9B64C2B0, 0x86D3D2D4, 0xA00AE278, 0xBDBDF21C 21 | }; 22 | 23 | tl_u32 tl_hash_crc32(tl_u32 crc, const void *data, size_t len) 24 | { 25 | const tl_u8 *ptr = data; 26 | tl_u8 b; 27 | crc = ~crc; 28 | while (len--) { 29 | b = *ptr++; 30 | crc = (crc >> 4) ^ s_crc32[(crc & 0x0F) ^ (b & 0x0F)]; 31 | crc = (crc >> 4) ^ s_crc32[(crc & 0x0F) ^ (b >> 4)]; 32 | } 33 | return ~crc; 34 | } 35 | -------------------------------------------------------------------------------- /main/src/hash/murmur3.c: -------------------------------------------------------------------------------- 1 | /* murmur3.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_EXPORT 9 | #include "tl_hash.h" 10 | #include 11 | 12 | #define MM3_C1 0xCC9E2D51 13 | #define MM3_C2 0x1B873593 14 | #define MM3_R1 15 15 | #define MM3_R2 13 16 | #define MM3_M 5 17 | #define MM3_N 0xE6546B64 18 | 19 | tl_u32 tl_hash_murmur3_32(const void *data, size_t len, tl_u32 seed) 20 | { 21 | const tl_u32 *blocks = (const tl_u32 *)data; 22 | tl_u32 hash = seed, k1 = 0, k; 23 | size_t nblocks = len / 4, i; 24 | const unsigned char *tail; 25 | 26 | for (i = 0; i < nblocks; ++i) { 27 | if (((size_t)blocks) % sizeof(tl_u32)) { 28 | memcpy(&k, blocks + i, 4); 29 | } else { 30 | k = blocks[i]; 31 | } 32 | 33 | k *= MM3_C1; 34 | k = (k << MM3_R1) | (k >> (32 - MM3_R1)); 35 | k *= MM3_C2; 36 | 37 | hash ^= k; 38 | hash = ((hash << MM3_R2) | (hash >> (32 - MM3_R2))); 39 | hash = hash * MM3_M + MM3_N; 40 | } 41 | 42 | tail = (const unsigned char *)data + nblocks * 4; 43 | 44 | switch (len & 3) { 45 | case 3: 46 | k1 ^= tail[2] << 16; /* fall-through */ 47 | case 2: 48 | k1 ^= tail[1] << 8; /* fall-through */ 49 | case 1: 50 | k1 ^= tail[0]; /* fall-through */ 51 | k1 *= MM3_C1; 52 | k1 = (k1 << MM3_R1) | (k1 >> (32 - MM3_R1)); 53 | k1 *= MM3_C2; 54 | hash ^= k1; 55 | } 56 | 57 | hash ^= len; 58 | hash ^= (hash >> 16); 59 | hash *= 0x85EBCA6B; 60 | hash ^= (hash >> 13); 61 | hash *= 0xC2B2AE35; 62 | hash ^= (hash >> 16); 63 | return hash; 64 | } 65 | -------------------------------------------------------------------------------- /main/src/iostream/printf.c: -------------------------------------------------------------------------------- 1 | /* printf.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_EXPORT 9 | #include "tl_iostream.h" 10 | 11 | #include 12 | #include 13 | 14 | int tl_iostream_printf(tl_iostream *this, const char *format, ...) 15 | { 16 | char *buffer; 17 | va_list ap; 18 | int size, status; 19 | size_t actual; 20 | 21 | assert( this && format ); 22 | 23 | /* determine required buffer size and allocate */ 24 | va_start(ap, format); 25 | size = vsnprintf(NULL, 0, format, ap); 26 | va_end(ap); 27 | 28 | if (size < 0) 29 | return TL_ERR_INTERNAL; 30 | 31 | if (!(buffer = malloc(size + 1))) 32 | return TL_ERR_ALLOC; 33 | 34 | /* write to buffer */ 35 | va_start(ap, format); 36 | vsnprintf(buffer, size + 1, format, ap); 37 | va_end(ap); 38 | 39 | /* send buffer and cleanup */ 40 | status = this->write(this, buffer, size, &actual); 41 | 42 | if (actual != (size_t)size && status == 0) 43 | status = TL_ERR_INTERNAL; 44 | 45 | free(buffer); 46 | return status; 47 | } 48 | -------------------------------------------------------------------------------- /main/src/iostream/read_blob.c: -------------------------------------------------------------------------------- 1 | /* read_blob.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_EXPORT 9 | #include "tl_iostream.h" 10 | 11 | int tl_iostream_read_blob(tl_iostream *this, tl_blob *blob, size_t maximum) 12 | { 13 | int status; 14 | 15 | assert(this && blob); 16 | 17 | if (!tl_blob_init(blob, maximum, NULL)) 18 | return TL_ERR_ALLOC; 19 | 20 | status = this->read(this, blob->data, maximum, &blob->size); 21 | tl_blob_truncate(blob, blob->size); 22 | return status; 23 | } 24 | -------------------------------------------------------------------------------- /main/src/iterator/array.c: -------------------------------------------------------------------------------- 1 | /* array.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_EXPORT 9 | #include "tl_iterator.h" 10 | #include "tl_array.h" 11 | 12 | #include 13 | 14 | 15 | typedef struct { 16 | tl_iterator super; 17 | tl_array *array; 18 | size_t idx; 19 | int forward; 20 | } tl_array_iterator; 21 | 22 | 23 | static void tl_array_iterator_destroy(tl_iterator *this) 24 | { 25 | free(this); 26 | } 27 | 28 | static void tl_array_iterator_reset(tl_iterator *super) 29 | { 30 | tl_array_iterator *this = (tl_array_iterator *)super; 31 | 32 | if (!this->forward && this->array->used) { 33 | this->idx = this->array->used - 1; 34 | } else { 35 | this->idx = 0; 36 | } 37 | } 38 | 39 | static int tl_array_iterator_has_data(tl_iterator *super) 40 | { 41 | tl_array_iterator *this = (tl_array_iterator *)super; 42 | return this->idx < this->array->used; 43 | } 44 | 45 | static void tl_array_iterator_next(tl_iterator *super) 46 | { 47 | tl_array_iterator *this = (tl_array_iterator *)super; 48 | 49 | if (this->idx < this->array->used) { 50 | if (this->forward) { 51 | ++this->idx; 52 | } else { 53 | --this->idx; /* eventually underflows out of range */ 54 | } 55 | } 56 | } 57 | 58 | static void *tl_array_iterator_get_key(tl_iterator *this) 59 | { 60 | (void)this; 61 | return NULL; 62 | } 63 | 64 | static void *tl_array_iterator_get_value(tl_iterator *super) 65 | { 66 | tl_array_iterator *this = (tl_array_iterator *)super; 67 | 68 | if (this->idx >= this->array->used) 69 | return NULL; 70 | 71 | return (char *)this->array->data + this->idx * this->array->unitsize; 72 | } 73 | 74 | static void tl_array_iterator_remove(tl_iterator *super) 75 | { 76 | tl_array_iterator *this = (tl_array_iterator *)super; 77 | 78 | tl_array_remove(this->array, this->idx, 1); 79 | 80 | if (!this->forward) 81 | --this->idx; 82 | } 83 | 84 | static tl_iterator *tl_array_iterator_create(tl_array *array, int first) 85 | { 86 | tl_array_iterator* this = malloc(sizeof(*this)); 87 | tl_iterator *super = (tl_iterator *)this; 88 | 89 | this->array = array; 90 | this->idx = first ? 0 : array->used - 1; 91 | this->forward = first; 92 | 93 | super->destroy = tl_array_iterator_destroy; 94 | super->reset = tl_array_iterator_reset; 95 | super->has_data = tl_array_iterator_has_data; 96 | super->next = tl_array_iterator_next; 97 | super->get_key = tl_array_iterator_get_key; 98 | super->get_value = tl_array_iterator_get_value; 99 | super->remove = tl_array_iterator_remove; 100 | return super; 101 | } 102 | 103 | tl_iterator *tl_array_first(tl_array *this) 104 | { 105 | assert(this); 106 | return tl_array_iterator_create(this, 1); 107 | } 108 | 109 | tl_iterator *tl_array_last(tl_array *this) 110 | { 111 | assert(this); 112 | return tl_array_iterator_create(this, 0); 113 | } 114 | -------------------------------------------------------------------------------- /main/src/iterator/list.c: -------------------------------------------------------------------------------- 1 | /* list.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_EXPORT 9 | #include "tl_iterator.h" 10 | #include "tl_list.h" 11 | 12 | #include 13 | #include 14 | 15 | typedef struct { 16 | tl_iterator super; 17 | tl_list_node *node; 18 | tl_list *list; 19 | int forward; 20 | } tl_list_iterator; 21 | 22 | 23 | static void tl_list_iterator_destroy(tl_iterator *this) 24 | { 25 | free(this); 26 | } 27 | 28 | static void tl_list_iterator_reset(tl_iterator *super) 29 | { 30 | tl_list_iterator *this = (tl_list_iterator *)super; 31 | 32 | this->node = this->forward ? this->list->first : this->list->last; 33 | } 34 | 35 | static int tl_list_iterator_has_data(tl_iterator *super) 36 | { 37 | tl_list_iterator *this = (tl_list_iterator *)super; 38 | 39 | return this->node != NULL; 40 | } 41 | 42 | static void tl_list_iterator_next(tl_iterator *super) 43 | { 44 | tl_list_iterator *this = (tl_list_iterator *)super; 45 | 46 | if (!this->node) 47 | return; 48 | 49 | this->node = this->forward ? this->node->next : this->node->prev; 50 | } 51 | 52 | static void *tl_list_iterator_get_key(tl_iterator *this) 53 | { 54 | (void)this; 55 | return NULL; 56 | } 57 | 58 | static void* tl_list_iterator_get_value(tl_iterator *super) 59 | { 60 | tl_list_iterator *this = (tl_list_iterator *)super; 61 | return this->node ? tl_list_node_get_data(this->node) : NULL; 62 | } 63 | 64 | static void tl_list_iterator_remove(tl_iterator *super) 65 | { 66 | tl_list_iterator *this = (tl_list_iterator *)super; 67 | tl_list_node *old; 68 | 69 | if (!this->node) 70 | return; 71 | 72 | old = this->node; 73 | 74 | if (this->list->size) 75 | --this->list->size; 76 | 77 | if (this->node == this->list->first) { 78 | this->node = this->node->next; 79 | this->list->first = this->node; 80 | 81 | if (this->node) { 82 | this->node->prev = NULL; 83 | } else { 84 | this->list->last = NULL; 85 | } 86 | } else if (this->node == this->list->last) { 87 | this->node = this->node->prev; 88 | this->list->last = this->node; 89 | 90 | if (this->node) { 91 | this->node->next = NULL; 92 | } else { 93 | this->list->first = NULL; 94 | } 95 | } else { 96 | this->node->prev->next = this->node->next; 97 | this->node->next->prev = this->node->prev; 98 | this->node = this->forward ? this->node->next : 99 | this->node->prev; 100 | } 101 | 102 | tl_list_node_destroy(old, this->list); 103 | } 104 | 105 | static tl_iterator* tl_list_iterator_create(tl_list *list, int first) 106 | { 107 | tl_list_iterator* this = malloc(sizeof(*this)); 108 | tl_iterator *super = (tl_iterator *)this; 109 | 110 | this->list = list; 111 | this->node = first ? list->first : list->last; 112 | this->forward = first; 113 | 114 | super->destroy = tl_list_iterator_destroy; 115 | super->reset = tl_list_iterator_reset; 116 | super->has_data = tl_list_iterator_has_data; 117 | super->next = tl_list_iterator_next; 118 | super->get_key = tl_list_iterator_get_key; 119 | super->get_value = tl_list_iterator_get_value; 120 | super->remove = tl_list_iterator_remove; 121 | return super; 122 | } 123 | 124 | tl_iterator *tl_list_first(tl_list *this) 125 | { 126 | assert(this); 127 | return tl_list_iterator_create(this, 1); 128 | } 129 | 130 | tl_iterator *tl_list_last(tl_list *this) 131 | { 132 | assert(this); 133 | return tl_list_iterator_create(this, 0); 134 | } 135 | -------------------------------------------------------------------------------- /main/src/list_node.c: -------------------------------------------------------------------------------- 1 | /* list_node.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_EXPORT 9 | #include "tl_allocator.h" 10 | #include "tl_list.h" 11 | 12 | #include 13 | 14 | tl_list_node *tl_list_node_create(const tl_list * this, const void *data) 15 | { 16 | tl_list_node *node; 17 | void *ptr; 18 | 19 | assert(this && data); 20 | 21 | node = calloc(1, sizeof(*node) + this->unitsize); 22 | ptr = (char *)node + sizeof(*node); 23 | 24 | if (data) { 25 | tl_allocator_copy(this->alloc, ptr, data, this->unitsize, 1); 26 | } else { 27 | tl_allocator_init(this->alloc, ptr, this->unitsize, 1); 28 | } 29 | 30 | return node; 31 | } 32 | 33 | void tl_list_node_destroy(tl_list_node * node, tl_list * list) 34 | { 35 | assert(node && list); 36 | 37 | tl_allocator_cleanup(list->alloc, (char *)node + sizeof(*node), 38 | list->unitsize, 1); 39 | free(node); 40 | } 41 | -------------------------------------------------------------------------------- /main/src/opt.c: -------------------------------------------------------------------------------- 1 | /* opt.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_EXPORT 9 | #include "tl_opt.h" 10 | #include 11 | #include 12 | 13 | static int is_valid_flag(const char *str) 14 | { 15 | while (isalnum(*str)) 16 | ++str; 17 | return *str == '\0'; 18 | } 19 | 20 | static tl_option *find_long_opt(tl_option *opt, const char *str, 21 | const char **arg) 22 | { 23 | size_t len; 24 | 25 | for (; opt->longopt != NULL || opt->shortopt != '\0'; ++opt) { 26 | if (opt->longopt != NULL) { 27 | len = strlen(opt->longopt); 28 | 29 | if (strncmp(opt->longopt, str, len) != 0) 30 | continue; 31 | 32 | if (str[len] == '\0') { 33 | *arg = NULL; 34 | return opt; 35 | } 36 | 37 | if (str[len] == '=') { 38 | *arg = str + len + 1; 39 | return opt; 40 | } 41 | } 42 | } 43 | 44 | return NULL; 45 | } 46 | 47 | static tl_option *find_short_opt(tl_option *opt, char x) 48 | { 49 | for (; opt->longopt != NULL || opt->shortopt != '\0'; ++opt) { 50 | if (opt->shortopt == x) 51 | break; 52 | } 53 | 54 | return opt; 55 | } 56 | 57 | static void dispatch_opt(tl_option *opt, const char *arg) 58 | { 59 | if (opt->field != NULL) 60 | *(opt->field) |= opt->value; 61 | if (opt->handle_option != NULL) 62 | opt->handle_option(opt, arg); 63 | } 64 | 65 | int tl_process_args(tl_option *options, int argc, char **argv, int *optind) 66 | { 67 | int i = 1, ret = 0; 68 | const char *arg; 69 | tl_option *opt; 70 | 71 | assert(options != NULL); 72 | assert(argv != NULL); 73 | 74 | for (i = 1; i < argc && argv[i][0] == '-'; ++i) { 75 | if (argv[i][1] == '-') { 76 | if (argv[i][2] == '\0') { 77 | ++i; 78 | break; 79 | } 80 | 81 | opt = find_long_opt(options, argv[i] + 2, &arg); 82 | } else { 83 | if (argv[i][1] == '\0' || !is_valid_flag(argv[i] + 1)) 84 | goto fail_inv_charset; 85 | 86 | if (argv[i][2] != '\0') { 87 | for (arg = argv[i] + 1; *arg != '\0'; ++arg) { 88 | opt = find_short_opt(options, *arg); 89 | if (opt->arguments != TL_OPT_ARG_NONE) 90 | goto fail_unknown; 91 | 92 | dispatch_opt(opt, NULL); 93 | } 94 | continue; 95 | } 96 | 97 | opt = find_short_opt(options, argv[i][1]); 98 | arg = NULL; 99 | } 100 | 101 | if (opt == NULL) 102 | goto fail_unknown; 103 | 104 | switch (opt->arguments) { 105 | case TL_OPT_ARG_NONE: 106 | if (arg != NULL) 107 | goto fail_extra_arg; 108 | break; 109 | case TL_OPT_ARG_REQ: 110 | if (arg == NULL) { 111 | if ((i + 1) >= argc) 112 | goto fail_missing_arg; 113 | ++i; 114 | arg = argv[i]; 115 | } 116 | break; 117 | case TL_OPT_ARG_OPTIONAL: 118 | if (arg == NULL && (i + 1) < argc) { 119 | if (argv[i + 1][0] != '-') { 120 | ++i; 121 | arg = argv[i]; 122 | } 123 | } 124 | break; 125 | } 126 | 127 | dispatch_opt(opt, arg); 128 | } 129 | out: 130 | if (optind != NULL) 131 | *optind = i; 132 | 133 | return ret; 134 | fail_unknown: 135 | ret = TL_OPT_UNKNOWN; 136 | goto out; 137 | fail_inv_charset: 138 | ret = TL_OPT_CHARSET; 139 | goto out; 140 | fail_missing_arg: 141 | ret = TL_OPT_MISSING_ARGUMENT; 142 | goto out; 143 | fail_extra_arg: 144 | ret = TL_OPT_EXTRA_ARGUMENT; 145 | goto out; 146 | } 147 | -------------------------------------------------------------------------------- /main/src/search/array.c: -------------------------------------------------------------------------------- 1 | /* array.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_EXPORT 9 | #include "tl_array.h" 10 | 11 | void *tl_array_search(const tl_array *this, tl_compare cmp, const void *key) 12 | { 13 | size_t i, l, u; 14 | char *ptr; 15 | int cv; 16 | 17 | assert(this && cmp && key); 18 | 19 | if (!this->used) 20 | return NULL; 21 | 22 | l = 0; 23 | u = this->used; 24 | 25 | while (l < u) { 26 | i = (l + u) >> 1; 27 | ptr = (char *)this->data + i * this->unitsize; 28 | cv = cmp(key, ptr); 29 | 30 | if (cv < 0) { 31 | u = i; 32 | } else if (cv > 0) { 33 | l = i + 1; 34 | } else { 35 | return ptr; 36 | } 37 | } 38 | 39 | return NULL; 40 | } 41 | -------------------------------------------------------------------------------- /main/src/search/array_insert_sorted.c: -------------------------------------------------------------------------------- 1 | /* array_insert_sorted.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_EXPORT 9 | #include "tl_array.h" 10 | #include "tl_allocator.h" 11 | 12 | int tl_array_insert_sorted(tl_array *this, tl_compare cmp, const void *element) 13 | { 14 | size_t i = 0; 15 | char *ptr; 16 | 17 | assert(this && cmp && element); 18 | 19 | for (ptr = this->data; i < this->used; ++i, ptr += this->unitsize) { 20 | if (cmp(ptr, element) <= 0) 21 | continue; 22 | 23 | if (!tl_array_resize(this, this->used + 1, 0)) 24 | return 0; 25 | 26 | ptr = (char *)this->data + i * this->unitsize; 27 | 28 | memmove(ptr + this->unitsize, ptr, 29 | (this->used - 1 - i) * this->unitsize); 30 | 31 | tl_allocator_copy(this->alloc, ptr, element, 32 | this->unitsize, 1); 33 | return 1; 34 | } 35 | 36 | return tl_array_append(this, element); 37 | } 38 | -------------------------------------------------------------------------------- /main/src/search/array_unsorted.c: -------------------------------------------------------------------------------- 1 | /* array_unsorted.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_EXPORT 9 | #include "tl_array.h" 10 | 11 | void *tl_array_search_unsorted(const tl_array *this, tl_compare cmp, 12 | const void *key) 13 | { 14 | size_t i = 0; 15 | char *ptr; 16 | 17 | assert(this && cmp && key); 18 | 19 | for (ptr = this->data; i < this->used; ++i, ptr += this->unitsize) { 20 | if (cmp(ptr, key) == 0) 21 | return ptr; 22 | } 23 | 24 | return NULL; 25 | } 26 | -------------------------------------------------------------------------------- /main/src/search/list.c: -------------------------------------------------------------------------------- 1 | /* list.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_EXPORT 9 | #include "tl_list.h" 10 | 11 | tl_list_node *tl_list_search(const tl_list *this, tl_compare cmp, 12 | const void *key) 13 | { 14 | tl_list_node *n; 15 | 16 | assert(this && cmp && key); 17 | 18 | for (n = this->first; n != NULL; n = n->next) { 19 | if (cmp(tl_list_node_get_data(n), key) == 0) 20 | return n; 21 | } 22 | 23 | return NULL; 24 | } 25 | -------------------------------------------------------------------------------- /main/src/search/list_insert_sorted.c: -------------------------------------------------------------------------------- 1 | /* list_insert_sorted.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_EXPORT 9 | #include "tl_allocator.h" 10 | #include "tl_list.h" 11 | 12 | int tl_list_insert_sorted(tl_list *this, tl_compare cmp, const void *element) 13 | { 14 | tl_list_node *n, *t; 15 | 16 | assert(this && cmp && element); 17 | 18 | if (!(t = tl_list_node_create(this, element))) 19 | return 0; 20 | 21 | if (!this->size) { 22 | this->first = this->last = t; 23 | } else if (cmp(element, tl_list_node_get_data(this->first)) <= 0) { 24 | t->next = this->first; 25 | this->first->prev = t; 26 | this->first = t; 27 | } else { 28 | for (n = this->first; n != NULL; n = n->next) { 29 | if (cmp(tl_list_node_get_data(n), element) > 0) { 30 | t->next = n; 31 | t->prev = n->prev; 32 | 33 | t->next->prev = t; 34 | t->prev->next = t; 35 | goto done; 36 | } 37 | } 38 | 39 | t->prev = this->last; 40 | this->last->next = t; 41 | this->last = t; 42 | } 43 | done: 44 | this->size += 1; 45 | return 1; 46 | } 47 | 48 | -------------------------------------------------------------------------------- /main/src/sort/heap.c: -------------------------------------------------------------------------------- 1 | /* heap.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | 9 | /* 10 | Heapsort implementation is based on "Algorithms, 4th Edition" 11 | by ROBERT SEDGEWICK and KEVIN WAYNE. 12 | */ 13 | #define TL_EXPORT 14 | #include "tl_sort.h" 15 | 16 | #include 17 | #include 18 | 19 | static TL_INLINE void swap(char *a, char *b, size_t n) 20 | { 21 | size_t i; 22 | char t; 23 | 24 | for (i = 0; i < n; ++i) { 25 | t = *a; 26 | *(a++) = *b; 27 | *(b++) = t; 28 | } 29 | } 30 | 31 | static TL_INLINE void sink(char *pq, size_t k, size_t N, 32 | size_t size, tl_compare cmp) 33 | { 34 | size_t j; 35 | 36 | for (j = 2 * k; j <= N; j *= 2) { 37 | if (j < N && cmp(pq + size * (j - 1), pq + size * j) < 0) 38 | ++j; 39 | 40 | if (cmp(pq + size * (k - 1), pq + size * (j - 1)) >= 0) 41 | break; 42 | 43 | swap(pq + size * (k - 1), pq + size * (j - 1), size); 44 | k = j; 45 | } 46 | } 47 | 48 | void tl_heapsort(void *data, size_t n, size_t size, tl_compare cmp) 49 | { 50 | char *pq, *last; 51 | size_t k; 52 | 53 | pq = data; 54 | 55 | for (k = n / 2; k >= 1; --k) 56 | sink(pq, k, n, size, cmp); 57 | 58 | for (last = pq + size * (n - 1); n > 1; last -= size) { 59 | swap(pq, last, size); 60 | sink(pq, 1, --n, size, cmp); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /main/src/sort/insertion.c: -------------------------------------------------------------------------------- 1 | /* insertion.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_EXPORT 9 | #include "tl_sort.h" 10 | 11 | #include 12 | #include 13 | 14 | static TL_INLINE void swap(char *a, char *b, size_t n) 15 | { 16 | size_t i; 17 | char t; 18 | 19 | for (i = 0; i < n; ++i) { 20 | t = *a; 21 | *(a++) = *b; 22 | *(b++) = t; 23 | } 24 | } 25 | 26 | void tl_insertionsort(void *data, size_t n, size_t size, tl_compare cmp) 27 | { 28 | char *first = (char *)data + size; 29 | char *limit = (char *)data + n * size; 30 | char *ptr, *pl; 31 | 32 | for (ptr = first; ptr < limit; ptr += size) { 33 | for (pl = ptr; pl > (char *)data; pl -= size) { 34 | if (cmp(pl-size, pl) <= 0) 35 | break; 36 | 37 | swap(pl, pl - size, size); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /main/src/sort/merge.c: -------------------------------------------------------------------------------- 1 | /* merge.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | 9 | /* 10 | Merge sort implementation is based on "Algorithms, 4th Edition" 11 | by ROBERT SEDGEWICK and KEVIN WAYNE. 12 | */ 13 | #define TL_EXPORT 14 | #include "tl_sort.h" 15 | 16 | #include 17 | #include 18 | 19 | #ifndef MIN 20 | #define MIN(a, b) ((a) < (b) ? (a) : (b)) 21 | #endif 22 | 23 | static TL_INLINE void swap(char *a, char *b, size_t n) 24 | { 25 | size_t i; 26 | char t; 27 | 28 | for (i = 0; i < n; ++i) { 29 | t = *a; 30 | *(a++) = *b; 31 | *(b++) = t; 32 | } 33 | } 34 | 35 | static TL_INLINE void merge(char *dst, char *auxlo, char *auxmid, 36 | char *auxhi, char *auxlast, 37 | size_t size, tl_compare cmp) 38 | { 39 | memcpy(auxlo, dst, auxlast - auxlo + size); 40 | 41 | while (auxlo <= auxmid && auxhi <= auxlast) { 42 | if (cmp(auxhi, auxlo) < 0) { 43 | memcpy(dst, auxhi, size); 44 | auxhi += size; 45 | } else { 46 | memcpy(dst, auxlo, size); 47 | auxlo += size; 48 | } 49 | dst += size; 50 | } 51 | 52 | if (auxhi <= auxlast) { 53 | memcpy(dst, auxhi, auxlast - auxhi + size); 54 | } else if (auxlo <= auxmid) { 55 | memcpy(dst, auxlo, auxmid - auxlo + size); 56 | } 57 | } 58 | 59 | int tl_mergesort(void *data, size_t N, size_t size, tl_compare cmp) 60 | { 61 | char *dst, *auxlo, *auxmid, *auxhi, *auxlast, *aux; 62 | size_t n, i, hi, step; 63 | 64 | aux = malloc(N * size); 65 | 66 | if (!aux) 67 | return 0; 68 | 69 | for (step = 2 * size, n = 1; n < N; n *= 2, step *= 2) { 70 | dst = (char *)data; 71 | auxlo = aux; 72 | auxhi = aux + step / 2; 73 | auxmid = auxhi - size; 74 | 75 | for (i = 0; i < N - n; i += 2 * n) { 76 | hi = MIN(i + n + n - 1, N - 1); 77 | auxlast = aux + hi * size; 78 | 79 | merge(dst, auxlo, auxmid, auxhi, auxlast, size, cmp); 80 | dst += step; 81 | auxlo += step; 82 | auxmid += step; 83 | auxhi += step; 84 | } 85 | } 86 | 87 | free(aux); 88 | return 1; 89 | } 90 | -------------------------------------------------------------------------------- /main/src/sort/merge_array.c: -------------------------------------------------------------------------------- 1 | /* merge_array.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_EXPORT 9 | #include "tl_array.h" 10 | #include "tl_sort.h" 11 | 12 | void tl_array_stable_sort(tl_array *this, tl_compare cmp) 13 | { 14 | assert(this && cmp); 15 | 16 | if (!this->data || !this->used) 17 | return; 18 | if (tl_mergesort(this->data, this->used, this->unitsize, cmp)) 19 | return; 20 | tl_mergesort_inplace(this->data, this->used, this->unitsize, cmp); 21 | } 22 | -------------------------------------------------------------------------------- /main/src/sort/merge_ip.c: -------------------------------------------------------------------------------- 1 | /* merge_list.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_EXPORT 9 | #include "tl_sort.h" 10 | 11 | #include 12 | #include 13 | 14 | static TL_INLINE void swap(char *a, char *b, size_t n) 15 | { 16 | size_t i; 17 | char t; 18 | 19 | for (i = 0; i < n; ++i) { 20 | t = *a; 21 | *(a++) = *b; 22 | *(b++) = t; 23 | } 24 | } 25 | 26 | static size_t lower(char *data, size_t size, size_t N, 27 | size_t val, tl_compare cmp) 28 | { 29 | size_t half, mid, i = 0; 30 | 31 | while (N > 0) { 32 | half = N / 2; 33 | mid = i + half; 34 | 35 | if (cmp(data + mid * size, data + val * size) < 0) { 36 | i = mid + 1; 37 | N -= half + 1; 38 | } else { 39 | N = half; 40 | } 41 | } 42 | return i; 43 | } 44 | 45 | static size_t upper(char *data, size_t size, size_t N, 46 | size_t val, tl_compare cmp) 47 | { 48 | size_t half, mid, i = 0; 49 | 50 | while (N > 0) { 51 | half = N / 2; 52 | mid = i + half; 53 | 54 | if (cmp(data + val * size, data + mid * size) < 0) { 55 | N = half; 56 | } else { 57 | i = mid + 1; 58 | N -= half + 1; 59 | } 60 | } 61 | 62 | return i; 63 | } 64 | 65 | static void reverse(char *data, size_t size, size_t N) 66 | { 67 | char *dst = data + (N - 1) * size; 68 | 69 | for (; data < dst; data += size, dst -= size) 70 | swap(data, dst, size); 71 | } 72 | 73 | static void rotate(char *data, size_t size, size_t mid, size_t N) 74 | { 75 | reverse(data, size, mid); 76 | reverse(data + mid * size, size, N - mid); 77 | reverse(data, size, N); 78 | } 79 | 80 | static void ip_merge(char *data, size_t size, tl_compare cmp, 81 | size_t pivot, size_t N, size_t len1, size_t len2) 82 | { 83 | size_t first_cut, second_cut, len11, len22, new_mid; 84 | recursion: 85 | /* trivial cases */ 86 | if (!len1 || !len2) 87 | return; 88 | 89 | if (len1 + len2 == 2) { 90 | if (cmp(data + size, data) < 0) 91 | swap(data + size, data, size); 92 | return; 93 | } 94 | 95 | /* */ 96 | if (len1 > len2) { 97 | len11 = len1 / 2; 98 | first_cut = len11; 99 | second_cut = pivot + lower(data + pivot * size, size, 100 | N - pivot, first_cut - pivot, cmp); 101 | len22 = second_cut - pivot; 102 | } else { 103 | len22 = len2 / 2; 104 | second_cut = pivot + len22; 105 | first_cut = upper(data, size, pivot, second_cut, cmp); 106 | len11 = first_cut; 107 | } 108 | 109 | rotate(data + first_cut * size, size, pivot - first_cut, 110 | second_cut - first_cut); 111 | new_mid = first_cut + len22; 112 | 113 | /* recursion to the left */ 114 | ip_merge(data, size, cmp, first_cut, new_mid, len11, len22); 115 | 116 | /* recursion to the right */ 117 | data += new_mid * size; 118 | pivot = second_cut - new_mid; 119 | N -= new_mid; 120 | len1 -= len11; 121 | len2 -= len22; 122 | goto recursion; 123 | } 124 | 125 | void tl_mergesort_inplace(void *data, size_t N, size_t size, tl_compare cmp) 126 | { 127 | size_t middle; 128 | 129 | if (N < 12) { 130 | tl_insertionsort(data, N, size, cmp); 131 | } else { 132 | middle = N / 2; 133 | tl_mergesort_inplace(data, middle, size, cmp); 134 | tl_mergesort_inplace((char *)data + middle * size, 135 | N - middle, size, cmp); 136 | ip_merge(data, size, cmp, middle, N, middle, N-middle); 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /main/src/sort/merge_list.c: -------------------------------------------------------------------------------- 1 | /* merge_ip.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_EXPORT 9 | #include "tl_list.h" 10 | 11 | static tl_list_node *merge(tl_list_node *a, tl_list_node *b, tl_compare cmp) 12 | { 13 | tl_list_node *head, *tail; 14 | 15 | if (!a) 16 | return b; 17 | if (!b) 18 | return a; 19 | 20 | if (cmp(tl_list_node_get_data(a), tl_list_node_get_data(b)) <= 0) { 21 | head = a; 22 | a = a->next; 23 | } else { 24 | head = b; 25 | b = b->next; 26 | } 27 | 28 | head->prev = head->next = NULL; 29 | tail = head; 30 | 31 | while (a && b) { 32 | if (cmp(tl_list_node_get_data(a), 33 | tl_list_node_get_data(b)) <= 0) { 34 | a->prev = tail; 35 | tail->next = a; 36 | tail = a; 37 | a = a->next; 38 | } else { 39 | b->prev = tail; 40 | tail->next = b; 41 | tail = b; 42 | b = b->next; 43 | } 44 | } 45 | 46 | tail->next = a ? a : b; 47 | tail->next->prev = tail; 48 | return head; 49 | } 50 | 51 | tl_list_node *tl_mergesort_list(tl_list_node *list, size_t count, 52 | tl_compare cmp) 53 | { 54 | tl_list_node *lo, *hi; 55 | size_t i; 56 | 57 | if (!list || !list->next || count < 1) 58 | return list; 59 | 60 | hi = list; 61 | for (i = 0; i < count / 2; ++i) 62 | hi = hi->next; 63 | 64 | hi->prev->next = NULL; 65 | hi->prev = NULL; 66 | 67 | lo = tl_mergesort_list(list, count / 2, cmp); 68 | hi = tl_mergesort_list(hi, count - count / 2, cmp); 69 | 70 | return merge(lo, hi, cmp); 71 | } 72 | 73 | void tl_list_sort(tl_list *this, tl_compare cmp) 74 | { 75 | tl_list_node *n; 76 | 77 | assert(this && cmp); 78 | 79 | if (this->size > 1) { 80 | this->first = tl_mergesort_list(this->first, this->size, cmp); 81 | 82 | for (n = this->first; n->next != NULL; n = n->next) 83 | ; 84 | this->last = n; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /main/src/sort/quick.c: -------------------------------------------------------------------------------- 1 | /* quick.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | 9 | /* 10 | Quicksort implementation is based on "Engineering a Sort Function" 11 | by JON L. BENTLEY and M. DOUGLAS McILROY. 12 | */ 13 | #define TL_EXPORT 14 | #include "tl_sort.h" 15 | 16 | #include 17 | #include 18 | 19 | #ifndef MIN 20 | #define MIN(a, b) ((a) < (b) ? (a) : (b)) 21 | #endif 22 | 23 | static TL_INLINE void swap(char *a, char *b, size_t n) 24 | { 25 | size_t i; 26 | char t; 27 | 28 | for (i = 0; i < n; ++i) { 29 | t = *a; 30 | *(a++) = *b; 31 | *(b++) = t; 32 | } 33 | } 34 | 35 | static TL_INLINE void *median3(void *a, void *b, void *c, tl_compare cmp) 36 | { 37 | return cmp(a, b) < 0 ? 38 | (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a )) : 39 | (cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c )); 40 | } 41 | 42 | void tl_quicksort(void *data, size_t n, size_t size, tl_compare cmp) 43 | { 44 | char *pa, *pb, *pc, *pd, *pl, *pm, *pn; 45 | ptrdiff_t r; 46 | size_t d; 47 | 48 | recursion: 49 | /* for small arrays, use insertion sort */ 50 | if (n <= 7) { 51 | tl_insertionsort(data, n, size, cmp); 52 | return; 53 | } 54 | 55 | pl = data; 56 | pm = (char *)data + (n / 2) * size; 57 | pn = (char *)data + (n - 1) * size; 58 | 59 | /* for big arrays, pseudomedian of 9 */ 60 | if (n > 40) { 61 | d = (n / 8) * size; 62 | pl = median3(pl, pl + d, pl + 2 * d, cmp); 63 | pm = median3(pm - d, pm, pm + d, cmp); 64 | pn = median3(pn - 2 * d, pn - d, pn, cmp); 65 | } 66 | 67 | pm = median3(pl, pm, pn, cmp); 68 | 69 | /* split-end partitioning */ 70 | swap(data, pm, size); 71 | pa = pb = (char *)data + size; 72 | pc = pd = (char *)data + (n - 1) * size; 73 | 74 | while (1) { 75 | for (; pb <= pc && (r = cmp(pb, data)) <= 0; pb += size) { 76 | if (r == 0) { 77 | swap(pa, pb, size); 78 | pa += size; 79 | } 80 | } 81 | for (; pb <= pc && (r = cmp(pc, data)) >= 0; pc -= size) { 82 | if (r == 0) { 83 | swap(pc, pd, size); 84 | pd -= size; 85 | } 86 | } 87 | if (pb > pc) 88 | break; 89 | swap(pb, pc, size); 90 | pb += size; 91 | pc -= size; 92 | } 93 | 94 | pn = (char *)data + n * size; 95 | r = MIN(pa - (char *)data, pb - pa); 96 | if (r > 0) 97 | swap(data, pb - r, r); 98 | r = MIN(pd - pc, pn - pd - (long)size); 99 | if (r > 0) 100 | swap(pb, pn - r, r); 101 | 102 | /* recursion step to the left */ 103 | if ((size_t)(r = pb - pa) > size) 104 | tl_quicksort(data, r / size, size, cmp); 105 | 106 | /* recursion step to the right */ 107 | if ((size_t)(r = pd - pc) > size) { 108 | data = pn - r; 109 | n = r / size; 110 | goto recursion; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /main/src/string/allocator.c: -------------------------------------------------------------------------------- 1 | /* allocator.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_EXPORT 9 | #include "tl_allocator.h" 10 | #include "tl_string.h" 11 | 12 | static int stralloc_copy(tl_allocator *alc, void *dst, const void *src) 13 | { 14 | tl_string *d = (tl_string *)dst, *s = (tl_string *)src; 15 | (void)alc; 16 | 17 | memcpy(dst, src, sizeof(tl_string)); 18 | 19 | tl_array_init(&d->data, 1, NULL); 20 | if (!tl_array_copy(&d->data, &s->data)) { 21 | tl_array_cleanup(&d->data); 22 | return 0; 23 | } 24 | return 1; 25 | } 26 | 27 | static int stralloc_init(tl_allocator *alc, void *ptr) 28 | { 29 | (void)alc; 30 | return tl_string_init(ptr); 31 | } 32 | 33 | static void stralloc_cleanup(tl_allocator *alc, void *ptr) 34 | { 35 | (void)alc; 36 | tl_string_cleanup(ptr); 37 | } 38 | 39 | static tl_allocator stralloc = { 40 | stralloc_copy, 41 | stralloc_init, 42 | stralloc_cleanup 43 | }; 44 | 45 | tl_allocator *tl_string_get_allocator(void) 46 | { 47 | return &stralloc; 48 | } 49 | -------------------------------------------------------------------------------- /main/src/string/append_latin1.c: -------------------------------------------------------------------------------- 1 | /* append_latin1.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_EXPORT 9 | #include "tl_string.h" 10 | 11 | int tl_string_append_latin1_count(tl_string *this, const char *latin1, 12 | size_t count) 13 | { 14 | const unsigned char *src = (const unsigned char *)latin1; 15 | unsigned char *dst; 16 | size_t i, len; 17 | 18 | assert(this); 19 | assert(latin1); 20 | 21 | if (!count) 22 | return 1; 23 | 24 | for (i = 0, len = 0; i < count && src[i]; ++i) 25 | len += (src[i] & 0x80) ? 2 : 1; 26 | 27 | if (!tl_array_reserve(&this->data, this->data.used + len)) 28 | return 0; 29 | 30 | dst = (unsigned char *)this->data.data + this->data.used - 1; 31 | 32 | for (i = 0; i < count && *src; ++i, ++src, ++this->charcount) { 33 | if (*src & 0x80) { 34 | *(dst++) = 0xC0 | (((*src) >> 6) & 0x03); 35 | *(dst++) = 0x80 | (*src & 0x3F); 36 | } else { 37 | *(dst++) = *src; 38 | 39 | if (this->mbseq == this->charcount) 40 | ++this->mbseq; 41 | } 42 | } 43 | 44 | *dst = 0; 45 | this->data.used = dst - ((unsigned char *)this->data.data) + 1; 46 | return 1; 47 | } 48 | -------------------------------------------------------------------------------- /main/src/string/append_utf16.c: -------------------------------------------------------------------------------- 1 | /* append_utf16.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_EXPORT 9 | #include "tl_string.h" 10 | 11 | #define SURROGATE_OFFSET (0x10000 - (0xD800 << 10) - 0xDC00) 12 | 13 | #define BOM 0xFEFF 14 | 15 | #define IS_LEAD_SURROGATE(x) (((x) >= 0xD800) && ((x) <= 0xDBFF)) 16 | #define IS_TRAIL_SURROGATE(x) (((x) >= 0xDC00) && ((x) <= 0xDFFF)) 17 | 18 | int tl_string_append_utf16_count(tl_string *this, const tl_u16 *str, 19 | size_t count) 20 | { 21 | unsigned char *dst; 22 | size_t i, len; 23 | unsigned int cp; 24 | 25 | assert(this); 26 | assert(str); 27 | 28 | if (!count) 29 | return 1; 30 | 31 | len = tl_utf8_estimate_utf16_length(str, count); 32 | 33 | if (!tl_array_reserve(&this->data, this->data.used + len)) 34 | return 0; 35 | 36 | dst = (unsigned char *)this->data.data + this->data.used - 1; 37 | 38 | for (i = 0; i < count && *str; ++str, ++i) { 39 | if (IS_TRAIL_SURROGATE(*str) || *str == BOM || 40 | *str == 0xFFFE || *str == 0xFFFF) { 41 | continue; 42 | } 43 | 44 | if (IS_LEAD_SURROGATE(str[0])) { 45 | if ((i + 1) >= count) 46 | break; 47 | if (!IS_TRAIL_SURROGATE(str[1])) 48 | continue; 49 | 50 | cp = (str[0] << 10) + str[1] + SURROGATE_OFFSET; 51 | 52 | *(dst++) = 0xF0 | ((cp >> 18) & 0x07); 53 | *(dst++) = 0x80 | ((cp >> 12) & 0x3F); 54 | *(dst++) = 0x80 | ((cp >> 6) & 0x3F); 55 | *(dst++) = 0x80 | (cp & 0x3F); 56 | ++this->charcount; 57 | ++str; 58 | ++i; 59 | } else if (*str >= 0x0800) { 60 | *(dst++) = 0xE0 | ((*str >> 12) & 0x0F); 61 | *(dst++) = 0x80 | ((*str >> 6) & 0x3F); 62 | *(dst++) = 0x80 | (*str & 0x3F); 63 | ++this->charcount; 64 | } else if (*str >= 0x0080) { 65 | *(dst++) = 0xC0 | ((*str >> 6) & 0x1F); 66 | *(dst++) = 0x80 | (*str & 0x3F); 67 | ++this->charcount; 68 | } else { 69 | if (this->mbseq == this->charcount) 70 | ++this->mbseq; 71 | 72 | ++this->charcount; 73 | *(dst++) = *str; 74 | } 75 | } 76 | 77 | *dst = 0; 78 | this->data.used = dst - ((unsigned char*)this->data.data) + 1; 79 | return 1; 80 | } 81 | -------------------------------------------------------------------------------- /main/src/string/append_utf8.c: -------------------------------------------------------------------------------- 1 | /* append_utf8.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_EXPORT 9 | #include "tl_string.h" 10 | 11 | int tl_string_append_utf8_count(tl_string *this, const char *utf8, 12 | size_t count) 13 | { 14 | const unsigned char *src = (const unsigned char *)utf8; 15 | unsigned char *dst; 16 | size_t i = 0; 17 | 18 | assert(this); 19 | assert(utf8); 20 | 21 | if (!count) 22 | return 1; 23 | 24 | if (!tl_array_reserve(&this->data, this->data.used + count)) 25 | return 0; 26 | 27 | dst = (unsigned char *)this->data.data + this->data.used - 1; 28 | 29 | while (i < count && (*src)) { 30 | if ((*src & 0x80) == 0x00) { 31 | if (this->mbseq == this->charcount) 32 | ++this->mbseq; 33 | 34 | *(dst++) = *(src++); 35 | ++this->charcount; 36 | ++i; 37 | continue; 38 | } 39 | if ((*src & 0xE0) == 0xC0) { 40 | if ((i + 1) >= count) 41 | break; 42 | if ((src[1] & 0xC0) != 0x80) 43 | goto skip; 44 | if ((src[0] & 0xFE) == 0xC0) /* overlong */ 45 | goto skip; 46 | 47 | *(dst++) = *(src++); 48 | *(dst++) = *(src++); 49 | ++this->charcount; 50 | i += 2; 51 | continue; 52 | } 53 | if ((*src & 0xF0) == 0xE0) { 54 | if ((i + 2) >= count) 55 | break; 56 | if ((src[1] & 0xC0) != 0x80 || (src[2] & 0xC0) != 0x80) 57 | goto skip; 58 | 59 | /* overlong */ 60 | if (src[0] == 0xE0 && (src[1] & 0xE0) == 0x80) 61 | goto skip; 62 | 63 | /* surrogate */ 64 | if (src[0] == 0xED && (src[1] & 0xE0) == 0xA0) 65 | goto skip; 66 | /* 0xFFFF or 0xFFFE */ 67 | if (src[0] == 0xEF && src[1] == 0xBF && (src[2] & 0xFE) == 0xBE) 68 | goto skip; 69 | 70 | *(dst++) = *(src++); 71 | *(dst++) = *(src++); 72 | *(dst++) = *(src++); 73 | ++this->charcount; 74 | i += 3; 75 | continue; 76 | } 77 | if ((*src & 0xF8) == 0xF0) { 78 | if ((i + 3) >= count) 79 | break; 80 | if ((src[1] & 0xC0) != 0x80 || (src[2] & 0xC0) != 0x80 || (src[3] & 0xC0) != 0x80) 81 | goto skip; 82 | /* overlong */ 83 | if (src[0] == 0xF0 && (src[1] & 0xF0) == 0x80) 84 | goto skip; 85 | 86 | /* > 0x10FFFF */ 87 | if ((src[0] == 0xF4 && src[1] > 0x8F) || src[0] > 0xF4) 88 | goto skip; 89 | 90 | *(dst++) = *(src++); 91 | *(dst++) = *(src++); 92 | *(dst++) = *(src++); 93 | *(dst++) = *(src++); 94 | ++this->charcount; 95 | i += 4; 96 | continue; 97 | } 98 | skip: 99 | ++src; 100 | ++i; 101 | } 102 | 103 | *dst = 0; 104 | this->data.used = dst - ((unsigned char*)this->data.data) + 1; 105 | return 1; 106 | } 107 | -------------------------------------------------------------------------------- /main/src/string/to_utf16.c: -------------------------------------------------------------------------------- 1 | /* to_utf16.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_EXPORT 9 | #include "tl_string.h" 10 | #include "tl_utf16.h" 11 | 12 | size_t tl_string_to_utf16(const tl_string *this, tl_u16 *buffer, size_t size) 13 | { 14 | const unsigned char *src; 15 | unsigned int cp, len; 16 | tl_u16 temp[2]; 17 | size_t i, j; 18 | tl_u16 *dst; 19 | 20 | assert(this && buffer); 21 | 22 | if (!size) 23 | return 0; 24 | 25 | src = this->data.data; 26 | dst = buffer; 27 | 28 | for (j = 0, i = 0; i < this->charcount && (j + 1) < size; ++i) { 29 | cp = tl_utf8_decode((const char *)src, &len); 30 | src += len; 31 | 32 | len = tl_utf16_encode(temp, cp); 33 | if (!len || (j + len) >= size) 34 | break; 35 | 36 | memcpy(dst, temp, len * sizeof(tl_u16)); 37 | dst += len; 38 | j += len; 39 | } 40 | 41 | *dst = '\0'; 42 | return j; 43 | } 44 | -------------------------------------------------------------------------------- /main/src/string/tokenize.c: -------------------------------------------------------------------------------- 1 | /* tokenize.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_EXPORT 9 | #include "tl_iterator.h" 10 | #include "tl_string.h" 11 | 12 | typedef struct { 13 | tl_iterator super; 14 | tl_string *str; /* string to search throug */ 15 | tl_string current; /* the last extracted token */ 16 | tl_string seperators; /* string of seperator characters */ 17 | size_t offset; /* offset after the last substring */ 18 | } tl_token_iterator; 19 | 20 | #define STATE_NONE_FOUND 0 21 | #define STATE_LAST_WAS_START 1 22 | #define STATE_NONSEP_FOUND 2 23 | 24 | static void token_iterator_destroy(tl_iterator *super) 25 | { 26 | tl_token_iterator *this = (tl_token_iterator *)super; 27 | tl_string_cleanup(&this->current); 28 | tl_string_cleanup(&this->seperators); 29 | free(this); 30 | } 31 | 32 | static int token_iterator_has_data(tl_iterator *this) 33 | { 34 | return !tl_string_is_empty(&((tl_token_iterator *)this)->current); 35 | } 36 | 37 | static void token_iterator_next(tl_iterator *super) 38 | { 39 | tl_token_iterator *this = (tl_token_iterator *)super; 40 | size_t first; 41 | char *ptr; 42 | 43 | tl_string_clear(&this->current); 44 | 45 | if (this->offset >= (this->str->data.used - 1)) 46 | return; 47 | 48 | /* find first non-serperator character */ 49 | ptr = (char *)this->str->data.data + this->offset; 50 | 51 | for (; *ptr; ++ptr, ++this->offset) { 52 | if ((*ptr & 0xC0) == 0x80) 53 | continue; 54 | if (!tl_utf8_strchr(tl_string_cstr(&this->seperators), ptr)) 55 | break; 56 | } 57 | 58 | if (!(*ptr)) 59 | return; 60 | 61 | first = this->offset; 62 | 63 | /* find next seperator character */ 64 | for (; *ptr; ++ptr, ++this->offset) { 65 | if ((*ptr & 0xC0) == 0x80) 66 | continue; 67 | if (tl_utf8_strchr(tl_string_cstr(&this->seperators), ptr)) 68 | break; 69 | } 70 | 71 | /* isolate */ 72 | if (*ptr) { 73 | tl_string_append_utf8_count(&this->current, 74 | (char *)this->str->data.data + first, 75 | this->offset - first); 76 | } else { 77 | tl_string_append_utf8(&this->current, 78 | (char *)this->str->data.data + first); 79 | } 80 | } 81 | 82 | static void token_iterator_reset(tl_iterator *super) 83 | { 84 | tl_token_iterator *this = (tl_token_iterator *)super; 85 | this->offset = 0; 86 | token_iterator_next(super); 87 | } 88 | 89 | static void* token_iterator_get_value(tl_iterator *this) 90 | { 91 | return &((tl_token_iterator *)this)->current; 92 | } 93 | 94 | tl_iterator *tl_string_tokenize(tl_string *str, const char *seperators) 95 | { 96 | tl_token_iterator *it; 97 | 98 | assert(str && seperators); 99 | 100 | it = calloc(1, sizeof(*it)); 101 | if (!it) 102 | return NULL; 103 | 104 | if (!tl_string_init(&it->seperators)) 105 | goto fail; 106 | 107 | if (!tl_string_append_utf8(&it->seperators, seperators)) 108 | goto failsep; 109 | 110 | if (!tl_string_init(&it->current)) 111 | goto failsep; 112 | 113 | it->str = str; 114 | ((tl_iterator*)it)->destroy = token_iterator_destroy; 115 | ((tl_iterator*)it)->reset = token_iterator_reset; 116 | ((tl_iterator*)it)->has_data = token_iterator_has_data; 117 | ((tl_iterator*)it)->next = token_iterator_next; 118 | ((tl_iterator*)it)->get_value = token_iterator_get_value; 119 | 120 | token_iterator_reset((tl_iterator* )it); 121 | return (tl_iterator*)it; 122 | failsep: 123 | tl_string_cleanup(&it->seperators); 124 | fail: 125 | free(it); 126 | return NULL; 127 | } 128 | -------------------------------------------------------------------------------- /main/src/string/trim.c: -------------------------------------------------------------------------------- 1 | /* trim.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_EXPORT 9 | #include "tl_unicode.h" 10 | #include "tl_string.h" 11 | 12 | void tl_string_trim_end(tl_string *this) 13 | { 14 | unsigned char *ptr; 15 | int cp, i; 16 | 17 | assert(this); 18 | 19 | ptr = (unsigned char *)this->data.data + this->data.used - 2; 20 | 21 | while (this->charcount) { 22 | cp = 0; 23 | 24 | for (i = 0; (*ptr & 0xC0) == 0x80; i += 6) 25 | cp |= (*(ptr--) & 0x3F) << i; 26 | 27 | if ((*ptr & 0xF8) == 0xF0) { 28 | cp |= (*ptr & 0x07) << i; 29 | } else if ((*ptr & 0xF0) == 0xE0) { 30 | cp |= (*ptr & 0x0F) << i; 31 | } else if ((*ptr & 0xE0) == 0xC0) { 32 | cp |= (*ptr & 0x1F) << i; 33 | } else { 34 | cp |= *ptr; 35 | } 36 | 37 | if (!tl_isspace(cp)) 38 | break; 39 | 40 | --ptr; 41 | if (this->charcount == this->mbseq) 42 | --this->mbseq; 43 | --this->charcount; 44 | } 45 | 46 | ptr[1] = 0; 47 | this->data.used = ptr - (unsigned char*)this->data.data + 2; 48 | } 49 | 50 | void tl_string_trim_begin(tl_string *this) 51 | { 52 | unsigned char *ptr; 53 | size_t i = 0; 54 | int cp; 55 | 56 | assert(this); 57 | 58 | ptr = this->data.data; 59 | 60 | while (1) { 61 | cp = *(ptr++); 62 | if (!cp) 63 | break; 64 | 65 | if ((cp & 0xE0) == 0xC0) { 66 | cp &= 0x1F; 67 | } else if ((cp & 0xF0) == 0xE0) { 68 | cp &= 0x0F; 69 | } else if ((cp & 0xF8) == 0xF0) { 70 | cp &= 0x07; 71 | } 72 | 73 | while ((*ptr & 0xC0) == 0x80) { 74 | cp <<= 6; 75 | cp |= *(ptr++) & 0x3F; 76 | } 77 | 78 | if (!tl_isspace(cp)) 79 | break; 80 | 81 | ++i; 82 | } 83 | 84 | if (i) 85 | tl_string_remove(this, 0, i); 86 | } 87 | -------------------------------------------------------------------------------- /main/src/transform.c: -------------------------------------------------------------------------------- 1 | /* transform.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_EXPORT 9 | #include "tl_transform.h" 10 | 11 | #include 12 | #include 13 | 14 | tl_transform *tl_create_transform(int algo, int flags) 15 | { 16 | (void)flags; 17 | 18 | switch (algo) { 19 | #ifdef TL_HAVE_DEFLATE 20 | case TL_DEFLATE: 21 | return tl_deflate(flags); 22 | case TL_INFLATE: 23 | return tl_inflate(flags); 24 | #endif 25 | case TL_BASE64_ENCODE: 26 | return tl_base64_encode(flags); 27 | case TL_BASE64_DECODE: 28 | return tl_base64_decode(flags); 29 | default: 30 | break; 31 | } 32 | 33 | return NULL; 34 | } 35 | -------------------------------------------------------------------------------- /main/src/unicode/isspace.c: -------------------------------------------------------------------------------- 1 | /* isspace.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_EXPORT 9 | #include "tl_unicode.h" 10 | 11 | int tl_isspace(int cp) 12 | { 13 | if (cp >= 0x2000 && cp <= 0x200A) { 14 | if (cp == 0x2007) 15 | return TL_SPACE | TL_NB_SPACE; 16 | 17 | return TL_SPACE; 18 | } 19 | 20 | if (cp == 0x2028 || cp == 0x2029) 21 | return TL_SPACE | TL_SPACE; 22 | 23 | if (cp == 0x00A0 || cp == 0x202F) 24 | return TL_SPACE | TL_NB_SPACE; 25 | 26 | if (cp == 0x0020 || cp == 0x1680 || cp == 0x205F || cp == 0x3000) 27 | return TL_SPACE; 28 | 29 | if (cp >= 0x09 && cp <= 0x0D) 30 | return TL_SPACE; 31 | 32 | if (cp >= 0x1C && cp <= 0x1F) 33 | return TL_SPACE; 34 | 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /main/src/unicode/utf16.c: -------------------------------------------------------------------------------- 1 | /* utf16.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_EXPORT 9 | #include "tl_utf16.h" 10 | 11 | #define IS_SURROGATE( x ) (((x) >= 0xD800) && ((x) <= 0xDFFF)) 12 | 13 | #define LEAD_OFFSET (0xD800 - (0x10000 >> 10)) 14 | #define SURROGATE_OFFSET (0x10000 - (0xD800 << 10) - 0xDC00) 15 | 16 | #define IS_LEAD_SURROGATE( x ) (((x)>=0xD800) && ((x)<=0xDBFF)) 17 | #define IS_TRAIL_SURROGATE( x ) (((x)>=0xDC00) && ((x)<=0xDFFF)) 18 | 19 | size_t tl_utf16_charcount(const tl_u16 * str) 20 | { 21 | size_t count = 0; 22 | 23 | assert(str); 24 | 25 | while (*str) { 26 | if (IS_LEAD_SURROGATE(str[0])) { 27 | if (IS_TRAIL_SURROGATE(str[1])) { 28 | ++str; 29 | } 30 | } 31 | 32 | ++count; 33 | ++str; 34 | } 35 | 36 | return count; 37 | } 38 | 39 | size_t tl_utf16_strlen(const tl_u16 * str, size_t chars) 40 | { 41 | size_t i, count = 0; 42 | 43 | assert(str); 44 | 45 | for (i = 0; i < chars && *str; ++i) { 46 | if (IS_LEAD_SURROGATE(str[0])) { 47 | if (IS_TRAIL_SURROGATE(str[1])) { 48 | ++count; 49 | ++str; 50 | } 51 | } 52 | ++count; 53 | ++str; 54 | } 55 | 56 | return count; 57 | } 58 | 59 | unsigned int tl_utf16_decode(const tl_u16 * utf16, unsigned int *count) 60 | { 61 | if (count) 62 | *count = 0; 63 | 64 | assert(utf16); 65 | 66 | if (IS_SURROGATE(*utf16)) { 67 | if (count) 68 | *count = 2; 69 | 70 | return (utf16[0] << 10) + utf16[1] + SURROGATE_OFFSET; 71 | } 72 | 73 | if (count) 74 | *count = 1; 75 | 76 | return utf16[0]; 77 | } 78 | 79 | unsigned int tl_utf16_encode(tl_u16 * utf16, unsigned int cp) 80 | { 81 | assert(utf16); 82 | 83 | if (cp < 0x10000) { 84 | utf16[0] = cp; 85 | return 1; 86 | } 87 | 88 | utf16[0] = LEAD_OFFSET + (cp >> 10); 89 | utf16[1] = 0xDC00 + (cp & 0x3FF); 90 | return 2; 91 | } 92 | 93 | size_t tl_utf16_estimate_utf8_length(const char *str, size_t count) 94 | { 95 | const unsigned char *ptr = (const unsigned char *)str; 96 | size_t i, u16count = 0; 97 | 98 | assert(str); 99 | 100 | for (i = 0; i < count && *ptr; ++ptr) { 101 | if ((*ptr & 0xC0) == 0x80) 102 | continue; 103 | 104 | u16count += ((*ptr & 0xF8) == 0xF0) ? 2 : 1; 105 | ++i; 106 | } 107 | 108 | return u16count; 109 | } 110 | 111 | int tl_utf16_compare(const tl_u16 * a, const tl_u16 * b) 112 | { 113 | assert(a); 114 | assert(b); 115 | 116 | while ((*a) && (*b)) { 117 | if (IS_SURROGATE(*a) && !IS_SURROGATE(*b)) 118 | return 1; 119 | if (!IS_SURROGATE(*a) && IS_SURROGATE(*b)) 120 | return -1; 121 | 122 | if ((*a) < (*b)) 123 | return -1; 124 | if ((*a) > (*b)) 125 | return 1; 126 | 127 | ++a; 128 | ++b; 129 | } 130 | 131 | if ((*a) && !(*b)) 132 | return 1; /* b is prefix of a => a > b */ 133 | if (!(*a) && (*b)) 134 | return -1; /* a is prefix of b => a < b */ 135 | 136 | return 0; /* equal */ 137 | } 138 | -------------------------------------------------------------------------------- /main/src/xfrm/base64_dec.c: -------------------------------------------------------------------------------- 1 | /* base64_dec.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_EXPORT 9 | #include "xfrm.h" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | typedef struct { 16 | base_transform super; 17 | const char *charset; 18 | unsigned int ignore : 1; /* ignore unknown characters */ 19 | } tl_base64_decoder; 20 | 21 | 22 | static const char *base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 23 | "abcdefghijklmnopqrstuvwxyz" 24 | "0123456789+/="; 25 | 26 | static const char *base64_url = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 27 | "abcdefghijklmnopqrstuvwxyz" 28 | "0123456789-_="; 29 | 30 | 31 | static void base64_destroy(tl_iostream *stream) 32 | { 33 | tl_base64_decoder *this = (tl_base64_decoder *)stream; 34 | 35 | assert(this != NULL); 36 | assert(stream->type == TL_STREAM_TYPE_TRANSFORM); 37 | 38 | free(((base_transform *)this)->buffer); 39 | free(this); 40 | } 41 | 42 | static int base64_read(base_transform *this, void *buffer, 43 | size_t size, size_t *actual) 44 | { 45 | int ret = 0, total = 0, have, a, b, c, d; 46 | const unsigned char *ptr; 47 | 48 | have = this->used; 49 | ptr = this->buffer; 50 | 51 | while (have >= 4 && size >= 3) { 52 | a = *(ptr++); 53 | b = *(ptr++); 54 | c = *(ptr++); 55 | d = *(ptr++); 56 | have -= 4; 57 | 58 | if (a > 63 || b > 63 || (c > 63 && d < 63)) { 59 | ret = TL_ERR_INTERNAL; 60 | break; 61 | } 62 | 63 | if (c > 63 || d > 63) 64 | this->eof = 1; 65 | 66 | ((char *)buffer)[0] = ((a << 2) & 0xFC) | ((b >> 4) & 0x03); 67 | ++total; 68 | 69 | if (c > 63) 70 | break; 71 | 72 | ((char *)buffer)[1] = ((b << 4) & 0xF0) | ((c >> 2) & 0x0F); 73 | ++total; 74 | 75 | if (d > 63) 76 | break; 77 | 78 | ((char *)buffer)[2] = ((c << 6) & 0xC0) | (d & 0x3F); 79 | ++total; 80 | 81 | buffer = ((char *)buffer) + 3; 82 | size -= 3; 83 | } 84 | 85 | base_transform_remove(this, this->used - have); 86 | 87 | if (actual) 88 | *actual = total; 89 | 90 | return ret; 91 | } 92 | 93 | static int base64_write(tl_iostream *super, const void *buffer, 94 | size_t size, size_t *actual) 95 | { 96 | tl_base64_decoder *this = (tl_base64_decoder *)super; 97 | const char *ptr, *found; 98 | int j = 0, ret = 0; 99 | char temp[16]; 100 | size_t i; 101 | 102 | assert(this != NULL && buffer != NULL); 103 | assert(super->type == TL_STREAM_TYPE_TRANSFORM); 104 | 105 | for (i = 0, ptr = buffer; i < size; ++i, ++ptr) { 106 | if (isspace(*ptr)) 107 | continue; 108 | 109 | found = strchr(this->charset, *ptr); 110 | if (!found) { 111 | if (this->ignore) 112 | continue; 113 | ret = TL_ERR_ARG; 114 | break; 115 | } 116 | 117 | temp[j++] = found - this->charset; 118 | 119 | if (j == (int)sizeof(temp)) { 120 | ret = base_transform_write(super, temp, j, NULL); 121 | if (ret) 122 | break; 123 | j = 0; 124 | } 125 | } 126 | 127 | if (!ret && j) 128 | ret = base_transform_write(super, temp, j, NULL); 129 | 130 | if (actual) 131 | *actual = i; 132 | return ret; 133 | } 134 | 135 | tl_transform *tl_base64_decode(int flags) 136 | { 137 | tl_base64_decoder *this; 138 | 139 | if (flags & ~(TL_BASE64_URL_SAFE | TL_BASE64_IGNORE_GARBAGE)) 140 | return NULL; 141 | 142 | this = calloc(1, sizeof(*this)); 143 | if (!this) 144 | return NULL; 145 | 146 | base_transform_init((base_transform *)this); 147 | 148 | this->charset = (flags & TL_BASE64_URL_SAFE) ? base64_url : base64; 149 | 150 | if (flags & TL_BASE64_IGNORE_GARBAGE) 151 | this->ignore = 1; 152 | 153 | ((tl_iostream *)this)->destroy = base64_destroy; 154 | ((tl_iostream *)this)->write = base64_write; 155 | ((base_transform *)this)->read = base64_read; 156 | return (tl_transform *)this; 157 | } 158 | -------------------------------------------------------------------------------- /main/src/xfrm/base64_enc.c: -------------------------------------------------------------------------------- 1 | /* base64_enc.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_EXPORT 9 | #include "xfrm.h" 10 | 11 | #include 12 | #include 13 | 14 | typedef struct { 15 | base_transform super; 16 | const char *charset; 17 | unsigned int flush : 1; 18 | } tl_base64_encoder; 19 | 20 | 21 | static const char *base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 22 | "abcdefghijklmnopqrstuvwxyz" 23 | "0123456789+/="; 24 | 25 | static const char *base64_url = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 26 | "abcdefghijklmnopqrstuvwxyz" 27 | "0123456789-_="; 28 | 29 | 30 | static int base64_flush(tl_transform *super, int flags) 31 | { 32 | tl_base64_encoder *this = (tl_base64_encoder *)super; 33 | (void)flags; 34 | 35 | assert(this != NULL); 36 | assert(((tl_iostream *)super)->type == TL_STREAM_TYPE_TRANSFORM); 37 | 38 | this->flush = 1; 39 | return 0; 40 | } 41 | 42 | static void base64_destroy(tl_iostream *stream) 43 | { 44 | tl_base64_encoder *this = (tl_base64_encoder *)stream; 45 | 46 | assert(this != NULL); 47 | assert(stream->type == TL_STREAM_TYPE_TRANSFORM); 48 | 49 | free(((base_transform *)this)->buffer); 50 | free(this); 51 | } 52 | 53 | static TL_INLINE void encode(tl_base64_encoder *this, char *buffer, tl_u32 x) 54 | { 55 | buffer[0] = this->charset[ x & 0xFF]; 56 | buffer[1] = this->charset[(x >> 8) & 0xFF]; 57 | buffer[2] = this->charset[(x >> 16) & 0xFF]; 58 | buffer[3] = this->charset[(x >> 24) & 0xFF]; 59 | } 60 | 61 | static TL_INLINE tl_u32 split(const tl_u8 *ptr, int count) 62 | { 63 | tl_u32 x = ((ptr[0] & 0xFC) >> 2) | ((ptr[0] & 0x03) << 12); 64 | 65 | if (count <= 1) 66 | return x | (64 << 16) | (64 << 24); 67 | 68 | x |= ((ptr[1] & 0xF0) << 4) | ((ptr[1] & 0x0F) << 18); 69 | 70 | if (count <= 2) 71 | return x | (64 << 24); 72 | 73 | return x | ((ptr[2] & 0xC0) << 10) | ((ptr[2] & 0x3F) << 24); 74 | } 75 | 76 | static int base64_read(base_transform *super, void *buffer, 77 | size_t size, size_t *actual) 78 | { 79 | tl_base64_encoder *this = (tl_base64_encoder *)super; 80 | int ret = 0, total = 0, have; 81 | const tl_u8 *ptr; 82 | 83 | ptr = (const tl_u8 *)super->buffer; 84 | have = super->used; 85 | 86 | while (have >= 3 && size >= 4) { 87 | encode(this, buffer, split(ptr, 3)); 88 | ptr += 3; 89 | have -= 3; 90 | buffer = (char *)buffer + 4; 91 | size -= 4; 92 | total += 4; 93 | } 94 | 95 | if (this->flush && have < 3) { 96 | if (have <= 0) { 97 | super->eof = 1; 98 | } else if (size >= 4) { 99 | encode(this, buffer, split(ptr, have)); 100 | total += 4; 101 | super->eof = 1; 102 | have = 0; 103 | } 104 | } 105 | 106 | base_transform_remove(super, super->used - have); 107 | 108 | if (actual) 109 | *actual = total; 110 | 111 | return ret; 112 | } 113 | 114 | tl_transform *tl_base64_encode(int flags) 115 | { 116 | tl_base64_encoder *this; 117 | 118 | if (flags & ~TL_BASE64_URL_SAFE) 119 | return NULL; 120 | 121 | this = calloc(1, sizeof(*this)); 122 | if (!this) 123 | return NULL; 124 | 125 | base_transform_init((base_transform *)this); 126 | 127 | this->charset = (flags & TL_BASE64_URL_SAFE) ? base64_url : base64; 128 | 129 | ((tl_iostream *)this)->destroy = base64_destroy; 130 | ((tl_transform *)this)->flush = base64_flush; 131 | ((base_transform *)this)->read = base64_read; 132 | return (tl_transform *)this; 133 | } 134 | -------------------------------------------------------------------------------- /main/src/xfrm/deflate.c: -------------------------------------------------------------------------------- 1 | /* deflate.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_EXPORT 9 | #include "xfrm.h" 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | typedef struct { 17 | base_transform super; 18 | z_stream strm; 19 | int flush_mode; 20 | } tl_deflate_compressor; 21 | 22 | static int deflate_flush(tl_transform *super, int flags) 23 | { 24 | tl_deflate_compressor *this = (tl_deflate_compressor *)super; 25 | 26 | assert(this != NULL); 27 | assert(((tl_iostream *)super)->type == TL_STREAM_TYPE_TRANSFORM); 28 | 29 | this->flush_mode = Z_SYNC_FLUSH; 30 | 31 | if (flags & TL_TRANSFORM_FLUSH_EOF) 32 | this->flush_mode = Z_FINISH; 33 | 34 | return 0; 35 | } 36 | 37 | static void deflate_destroy(tl_iostream *stream) 38 | { 39 | tl_deflate_compressor *this = (tl_deflate_compressor *)stream; 40 | 41 | assert(this != NULL); 42 | assert(stream->type == TL_STREAM_TYPE_TRANSFORM); 43 | 44 | deflateEnd(&this->strm); 45 | free(((base_transform *)this)->buffer); 46 | free(this); 47 | } 48 | 49 | static int deflate_read(base_transform *super, void *buffer, 50 | size_t size, size_t *actual) 51 | { 52 | tl_deflate_compressor *this = (tl_deflate_compressor *)super; 53 | int ret = 0, have, total = 0; 54 | 55 | this->strm.next_in = (void *)super->buffer; 56 | this->strm.avail_in = super->used; 57 | 58 | do { 59 | this->strm.next_out = buffer; 60 | this->strm.avail_out = size; 61 | 62 | switch (deflate(&this->strm, this->flush_mode)) { 63 | case Z_STREAM_END: 64 | ret = TL_EOF; 65 | super->eof = 1; 66 | break; 67 | case Z_BUF_ERROR: 68 | ret = 0; 69 | total += (size - this->strm.avail_out); 70 | goto out_remove; 71 | case Z_OK: 72 | ret = 0; 73 | break; 74 | default: 75 | ret = TL_ERR_INTERNAL; 76 | goto out_remove; 77 | } 78 | 79 | have = size - this->strm.avail_out; 80 | 81 | buffer = (unsigned char *)buffer + have; 82 | size -= have; 83 | total += have; 84 | } while (size && this->strm.avail_out == 0); 85 | 86 | out_remove: 87 | base_transform_remove(super, super->used - this->strm.avail_in); 88 | 89 | if (actual) 90 | *actual = total; 91 | 92 | return ret; 93 | } 94 | 95 | tl_transform *tl_deflate(int flags) 96 | { 97 | int level = Z_DEFAULT_COMPRESSION; 98 | tl_deflate_compressor *this; 99 | 100 | if (flags & ~(TL_COMPRESS_GOOD | TL_COMPRESS_FAST)) 101 | return NULL; 102 | 103 | this = calloc(1, sizeof(*this)); 104 | if (!this) 105 | return NULL; 106 | 107 | base_transform_init((base_transform *)this); 108 | 109 | if (flags & TL_COMPRESS_GOOD) { 110 | level = Z_BEST_COMPRESSION; 111 | } else if (flags & TL_COMPRESS_FAST) { 112 | level = Z_BEST_SPEED; 113 | } 114 | 115 | if (deflateInit(&this->strm, level) != Z_OK) { 116 | free(this); 117 | return NULL; 118 | } 119 | 120 | ((tl_iostream *)this)->destroy = deflate_destroy; 121 | ((tl_transform *)this)->flush = deflate_flush; 122 | ((base_transform *)this)->read = deflate_read; 123 | this->flush_mode = Z_NO_FLUSH; 124 | return (tl_transform *)this; 125 | } 126 | -------------------------------------------------------------------------------- /main/src/xfrm/inflate.c: -------------------------------------------------------------------------------- 1 | /* inflate.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_EXPORT 9 | #include "xfrm.h" 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | typedef struct { 17 | base_transform super; 18 | z_stream strm; 19 | } tl_inflate_compressor; 20 | 21 | 22 | static void inflate_destroy(tl_iostream *stream) 23 | { 24 | tl_inflate_compressor *this = (tl_inflate_compressor *)stream; 25 | 26 | assert(this != NULL); 27 | assert(stream->type == TL_STREAM_TYPE_TRANSFORM); 28 | 29 | inflateEnd(&this->strm); 30 | free(((base_transform *)this)->buffer); 31 | free(this); 32 | } 33 | 34 | static int inflate_read(base_transform *super, void *buffer, 35 | size_t size, size_t *actual) 36 | { 37 | tl_inflate_compressor *this = (tl_inflate_compressor *)super; 38 | int ret = 0, have, total = 0; 39 | 40 | this->strm.next_in = super->buffer; 41 | this->strm.avail_in = super->used; 42 | 43 | do { 44 | this->strm.next_out = buffer; 45 | this->strm.avail_out = size; 46 | 47 | switch (inflate(&this->strm, Z_NO_FLUSH)) { 48 | case Z_STREAM_END: 49 | ret = TL_EOF; 50 | super->eof = 1; 51 | break; 52 | case Z_BUF_ERROR: 53 | ret = 0; 54 | total += (size - this->strm.avail_out); 55 | goto out_remove; 56 | case Z_OK: 57 | ret = 0; 58 | break; 59 | default: 60 | ret = TL_ERR_INTERNAL; 61 | goto out_remove; 62 | } 63 | 64 | have = size - this->strm.avail_out; 65 | 66 | buffer = (unsigned char*)buffer + have; 67 | size -= have; 68 | total += have; 69 | } while (size && this->strm.avail_out == 0); 70 | 71 | out_remove: 72 | base_transform_remove(super, super->used - this->strm.avail_in); 73 | 74 | if (actual) 75 | *actual = total; 76 | return ret; 77 | } 78 | 79 | tl_transform *tl_inflate(int flags) 80 | { 81 | tl_inflate_compressor *this; 82 | 83 | if (flags) 84 | return NULL; 85 | 86 | this = calloc(1, sizeof(*this)); 87 | if (!this) 88 | return NULL; 89 | 90 | base_transform_init((base_transform *)this); 91 | 92 | if (inflateInit(&this->strm) != Z_OK) { 93 | free(this); 94 | return NULL; 95 | } 96 | 97 | ((tl_iostream *)this)->destroy = inflate_destroy; 98 | ((base_transform *)this)->read = inflate_read; 99 | return (tl_transform *)this; 100 | } 101 | -------------------------------------------------------------------------------- /main/src/xfrm/xfrm.c: -------------------------------------------------------------------------------- 1 | /* xfrm.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_EXPORT 9 | #include "xfrm.h" 10 | 11 | 12 | static int dummy_flush(tl_transform *super, int flags) 13 | { 14 | assert(super != NULL); 15 | assert(((tl_iostream *)super)->type == TL_STREAM_TYPE_TRANSFORM); 16 | (void)super; (void)flags; 17 | return TL_ERR_NOT_SUPPORTED; 18 | } 19 | 20 | static int dummy_set_timeout(tl_iostream *stream, unsigned int timeout) 21 | { 22 | assert(stream != NULL); 23 | assert(stream->type == TL_STREAM_TYPE_TRANSFORM); 24 | (void)stream; (void)timeout; 25 | return TL_ERR_NOT_SUPPORTED; 26 | } 27 | 28 | static int base_transform_read(tl_iostream *stream, void *buffer, 29 | size_t size, size_t *actual) 30 | { 31 | base_transform *this = (base_transform *)stream; 32 | 33 | assert(this != NULL && buffer != NULL); 34 | assert(stream->type == TL_STREAM_TYPE_TRANSFORM); 35 | 36 | if (actual) 37 | *actual = 0; 38 | 39 | if (this->eof) 40 | return TL_EOF; 41 | 42 | if (!size) 43 | return 0; 44 | 45 | return this->read(this, buffer, size, actual); 46 | } 47 | 48 | int base_transform_write(tl_iostream *stream, const void *buffer, 49 | size_t size, size_t *actual) 50 | { 51 | base_transform *this = (base_transform *)stream; 52 | int ret = 0; 53 | void *new; 54 | 55 | assert(this != NULL && buffer != NULL); 56 | assert(stream->type == TL_STREAM_TYPE_TRANSFORM); 57 | 58 | if ((this->used + size) > this->total) { 59 | new = realloc(this->buffer, this->used + size); 60 | 61 | if (!new) { 62 | ret = TL_ERR_ALLOC; 63 | size = 0; 64 | goto out; 65 | } 66 | 67 | this->buffer = new; 68 | this->total = this->used + size; 69 | } 70 | 71 | memcpy(this->buffer + this->used, buffer, size); 72 | this->used += size; 73 | out: 74 | if (actual) 75 | *actual = size; 76 | return ret; 77 | } 78 | 79 | void base_transform_init(base_transform *cmp) 80 | { 81 | ((tl_transform *)cmp)->flush = dummy_flush; 82 | ((tl_iostream *)cmp)->set_timeout = dummy_set_timeout; 83 | ((tl_iostream *)cmp)->read = base_transform_read; 84 | ((tl_iostream *)cmp)->write = base_transform_write; 85 | ((tl_iostream *)cmp)->type = TL_STREAM_TYPE_TRANSFORM; 86 | } 87 | 88 | void base_transform_remove(base_transform *cmp, size_t count) 89 | { 90 | if (count < cmp->used) { 91 | memmove(cmp->buffer, cmp->buffer + count, cmp->used - count); 92 | cmp->used -= count; 93 | } else { 94 | cmp->used = 0; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /main/src/xfrm/xfrm.h: -------------------------------------------------------------------------------- 1 | /* xfrm.h -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #ifndef XFRM_H 9 | #define XFRM_H 10 | 11 | #include "tl_transform.h" 12 | 13 | typedef struct base_transform { 14 | tl_transform super; 15 | unsigned char *buffer; 16 | size_t total; 17 | size_t used; 18 | unsigned int eof : 1; 19 | 20 | int (*read)(struct base_transform *xfrm, void *buffer, 21 | size_t size, size_t *actual); 22 | } base_transform; 23 | 24 | void base_transform_init(base_transform *cmp); 25 | 26 | void base_transform_remove(base_transform *cmp, size_t count); 27 | 28 | int base_transform_write(tl_iostream *stream, const void *buffer, 29 | size_t size, size_t *actual); 30 | 31 | #endif /* COMPRESSOR_H */ 32 | 33 | -------------------------------------------------------------------------------- /main/src/xfrm_blob.c: -------------------------------------------------------------------------------- 1 | /* xfrm_blob.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_EXPORT 9 | #include "tl_transform.h" 10 | 11 | int tl_transform_blob(tl_blob *dst, const tl_blob *src, int algo, int flags) 12 | { 13 | tl_transform *comp = tl_create_transform(algo, flags); 14 | const unsigned char *ptr; 15 | size_t actual, total; 16 | char buffer[1024]; 17 | int ret; 18 | 19 | if (!comp) 20 | return TL_ERR_NOT_SUPPORTED; 21 | 22 | total = src->size; 23 | ptr = (const unsigned char *)src->data; 24 | 25 | tl_blob_init(dst, 0, NULL); 26 | 27 | while (total) { 28 | ret = tl_iostream_write(comp, ptr, total, &actual); 29 | if (ret) 30 | goto fail; 31 | 32 | ptr += actual; 33 | total -= actual; 34 | 35 | if (total == 0) { 36 | ret = comp->flush(comp, TL_TRANSFORM_FLUSH_EOF); 37 | if (ret && ret != TL_ERR_NOT_SUPPORTED) 38 | goto fail; 39 | } 40 | 41 | do { 42 | ret = tl_iostream_read(comp, buffer, sizeof(buffer), 43 | &actual); 44 | 45 | if (ret < 0 && ret != TL_EOF) 46 | goto fail; 47 | 48 | if (!tl_blob_append_raw(dst, buffer, actual)) { 49 | ret = TL_ERR_ALLOC; 50 | goto fail; 51 | } 52 | } while (ret != TL_EOF && actual > 0); 53 | } 54 | 55 | ret = 0; 56 | out: 57 | tl_iostream_destroy(comp); 58 | return ret; 59 | fail: 60 | tl_blob_cleanup(dst); 61 | goto out; 62 | } 63 | -------------------------------------------------------------------------------- /os/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library( tlos ${TYPE} src/network.c 2 | src/splice.c 3 | src/W32/os.c 4 | src/W32/fs.c 5 | src/W32/dir_it.c 6 | src/W32/dir_scan.c 7 | src/W32/network.c 8 | src/W32/process.c 9 | src/W32/thread.c 10 | src/W32/monitor.c 11 | src/W32/rwlock.c 12 | src/W32/mutex.c 13 | src/W32/threadpool.c 14 | src/W32/sockstream.c 15 | src/W32/fstream.c 16 | src/W32/iostream.c 17 | src/W32/file.c 18 | src/W32/path.c 19 | src/bsdsock/sock.c 20 | src/bsdsock/network.c 21 | src/bsdsock/addr_v6.c 22 | src/bsdsock/tcpserver.c 23 | src/bsdsock/resolve_name.c 24 | src/bsdsock/resolve_addr.c 25 | src/bsdsock/udpserver.c ) 26 | 27 | target_link_libraries( tlos tlcore ) 28 | 29 | if( SHARED ) 30 | target_link_libraries( tlos ${CTOOLS_SYSLIBS} ) 31 | set_target_properties( tlos PROPERTIES PREFIX "" ) 32 | endif( ) 33 | -------------------------------------------------------------------------------- /os/Makemodule.am: -------------------------------------------------------------------------------- 1 | OS_HDR = \ 2 | os/include/tl_dir.h \ 3 | os/include/tl_file.h \ 4 | os/include/tl_fs.h \ 5 | os/include/tl_network.h \ 6 | os/include/tl_packetserver.h \ 7 | os/include/tl_process.h \ 8 | os/include/tl_server.h \ 9 | os/include/tl_splice.h \ 10 | os/include/tl_thread.h \ 11 | os/include/tl_threadpool.h \ 12 | os/include/tl_unix.h 13 | 14 | OS_SRC= \ 15 | os/src/network.c \ 16 | os/src/platform.h \ 17 | os/src/splice.c 18 | 19 | W32_SRC = \ 20 | os/src/W32/dir_it.c \ 21 | os/src/W32/dir_scan.c \ 22 | os/src/W32/file.c \ 23 | os/src/W32/fs.c \ 24 | os/src/W32/fstream.c \ 25 | os/src/W32/iostream.c \ 26 | os/src/W32/monitor.c \ 27 | os/src/W32/mutex.c \ 28 | os/src/W32/network.c \ 29 | os/src/W32/os.c \ 30 | os/src/W32/os.h \ 31 | os/src/W32/path.c \ 32 | os/src/W32/process.c \ 33 | os/src/W32/rwlock.c \ 34 | os/src/W32/sockstream.c \ 35 | os/src/W32/thread.c \ 36 | os/src/W32/threadpool.c 37 | 38 | UNIX_SRC = \ 39 | os/src/unix/dir_it.c \ 40 | os/src/unix/dir_scan.c \ 41 | os/src/unix/fdstream.c \ 42 | os/src/unix/file.c \ 43 | os/src/unix/fs.c \ 44 | os/src/unix/iostream.c \ 45 | os/src/unix/monitor.c \ 46 | os/src/unix/mutex.c \ 47 | os/src/unix/network.c \ 48 | os/src/unix/os.c \ 49 | os/src/unix/os.h \ 50 | os/src/unix/process.c \ 51 | os/src/unix/rwlock.c \ 52 | os/src/unix/thread.c \ 53 | os/src/unix/threadpool.c 54 | 55 | BSDSOCK_SRC = \ 56 | os/src/bsdsock/addr_v6.c \ 57 | os/src/bsdsock/bsdsock.h \ 58 | os/src/bsdsock/network.c \ 59 | os/src/bsdsock/resolve_addr.c \ 60 | os/src/bsdsock/resolve_name.c \ 61 | os/src/bsdsock/sock.c \ 62 | os/src/bsdsock/tcpserver.c \ 63 | os/src/bsdsock/udpserver.c 64 | 65 | libtlos_la_SOURCES = \ 66 | $(OS_SRC) \ 67 | $(BSDSOCK_SRC) \ 68 | $(OS_HDR) 69 | 70 | libtlos_la_CPPFLAGS = $(AM_CPPFLAGS) 71 | libtlos_la_CFLAGS = $(AM_CFLAGS) $(PTHREAD_CFLAGS) 72 | libtlos_la_LDFLAGS = $(AM_LDFLAGS) $(PTHREAD_CFLAGS) 73 | libtlos_la_LIBADD = $(PTHREAD_LIBS) libtlcore.la 74 | 75 | if BUILD_WINDOWS 76 | libtlos_la_SOURCES += $(W32_SRC) 77 | libtlos_la_LDFLAGS += -no-undefined 78 | libtlos_la_LIBADD += -luserenv -lws2_32 79 | else 80 | libtlos_la_SOURCES += $(UNIX_SRC) 81 | endif 82 | 83 | include_HEADERS += $(OS_HDR) 84 | lib_LTLIBRARIES += libtlos.la 85 | 86 | EXTRA_DIST += $(W32_SRC) 87 | -------------------------------------------------------------------------------- /os/include/tl_dir.h: -------------------------------------------------------------------------------- 1 | /* 2 | * tl_dir.h 3 | * This file is part of ctools 4 | * 5 | * Copyright (C) 2015 - David Oberhollenzer 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a 8 | * copy of this software and associated documentation files (the "Software"), 9 | * to deal in the Software without restriction, including without limitation 10 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | * and/or sell copies of the Software, and to permit persons to whom the 12 | * Software is furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | * DEALINGS IN THE SOFTWARE. 24 | */ 25 | 26 | /** 27 | * \file tl_dir.h 28 | * 29 | * \brief Contains directroy enumeration functions 30 | */ 31 | #ifndef TOOLS_DIR 32 | #define TOOLS_DIR 33 | 34 | /** 35 | * \page filesystem Filesystem 36 | * 37 | * \section dir Directory scanning and iterating 38 | * 39 | * A platform dependend imeplementation of the tl_iterator interface is 40 | * provided for iterating directory contents on operating systems filesystem 41 | * hirarchy. 42 | * 43 | * The function tl_dir_scan can be used to load the contents of a directory 44 | * directly into a tl_array of tl_string instances (with the proper 45 | * tl_allocator set). 46 | * 47 | * \subsection dirlist Listing directory contents 48 | * 49 | * The function \ref tl_dir_scan can be used to load a directory listing into 50 | * a tl_array of tl_string instances. 51 | * 52 | * An iterator interface also exists in the form of \ref tl_dir_iterate. 53 | * 54 | * The file \ref dirlist.c contains a simple example for both methods. 55 | */ 56 | 57 | #include "tl_predef.h" 58 | 59 | #ifdef __cplusplus 60 | extern "C" { 61 | #endif 62 | 63 | /** 64 | * \brief Read all entries of a directory into an array of strings 65 | * 66 | * The content already in the target array remains unchanged. On success, the 67 | * function appends to the array, on failure it does not alter the array. 68 | * 69 | * \param path The path of the directory to scan 70 | * \param list A pointer to a tl_array of tl_string to append the entries to, 71 | * assumed to have a propper allocator set 72 | * 73 | * \return Zero on success, TL_ERR_ACCESS if the calling process does not have 74 | * the neccessarry permissions, TL_ERR_NOT_EXIST if the path does not 75 | * exist, TL_ERR_NOT_DIR if the path points to a file 76 | */ 77 | TLOSAPI int tl_dir_scan(const char *path, tl_array *list); 78 | 79 | /** 80 | * \brief Iterate over the contents of a directory 81 | * 82 | * \note The iterator has no keys and returns a pointer to a tl_string when 83 | * calling get_value. The remove method is not implemented. 84 | * 85 | * \param path The path of the directory to read from 86 | * 87 | * \return A pointer to an iterator object on success, NULL on failure 88 | */ 89 | TLOSAPI tl_iterator *tl_dir_iterate(const char *path); 90 | 91 | #ifdef __cplusplus 92 | } 93 | #endif 94 | 95 | #endif /* TOOLS_DIR */ 96 | 97 | -------------------------------------------------------------------------------- /os/include/tl_server.h: -------------------------------------------------------------------------------- 1 | /* 2 | * tl_server.h 3 | * This file is part of ctools 4 | * 5 | * Copyright (C) 2015 - David Oberhollenzer 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a 8 | * copy of this software and associated documentation files (the "Software"), 9 | * to deal in the Software without restriction, including without limitation 10 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | * and/or sell copies of the Software, and to permit persons to whom the 12 | * Software is furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | * DEALINGS IN THE SOFTWARE. 24 | */ 25 | 26 | /** 27 | * \file tl_server.h 28 | * 29 | * \brief Contains an abstract server interface (tl_server) 30 | */ 31 | #ifndef TOOLS_SERVER_H 32 | #define TOOLS_SERVER_H 33 | 34 | /** 35 | * \page interfaces Interfaces 36 | * 37 | * \section server The tl_server interface 38 | * 39 | * The tl_server interface abstracts stream based communication of a single 40 | * end-point with an arbitrary number of clients (e.g. a TCP server). The 41 | * client communications are abstracted in the form of tl_iostream instances 42 | * that the server creates when a new client connects. 43 | * 44 | * Usage example: 45 | * \code{.c} 46 | * tl_server* srv = function_that_creates_a_server( ); 47 | * int run = 1; 48 | * 49 | * while( run ) 50 | * { 51 | * tl_iostream* client = srv->wait_for_client( srv, 0 ); 52 | * 53 | * handle_client( client ); 54 | * } 55 | * 56 | * srv->destroy( destroy ); 57 | * \endcode 58 | * 59 | * For "raw" packet based, non-connection oriented communications (e.g. UDP), 60 | * the \ref tl_packetserver interface is used. 61 | */ 62 | 63 | #include "tl_predef.h" 64 | 65 | /** 66 | * \interface tl_server 67 | * 68 | * \brief An interface that abstracts byte stream based one-to-many 69 | * communication on the "one" end. 70 | * 71 | * \see \ref server 72 | */ 73 | struct tl_server { 74 | /** 75 | * \brief Destroy a server object shutting down all connections and, 76 | * freeing all its resources 77 | * 78 | * \param server A pointer to the server object 79 | */ 80 | void (*destroy)(tl_server *server); 81 | 82 | /** 83 | * \brief Wait until a new client connects 84 | * 85 | * \param server A pointer to a server object 86 | * \param timeout A timeout in milliseconds, or zero (or a negative 87 | * value) for infinite timeout. 88 | */ 89 | tl_iostream *(*wait_for_client)(tl_server *server, int timeout); 90 | }; 91 | 92 | #endif /* TOOLS_SERVER_H */ 93 | 94 | -------------------------------------------------------------------------------- /os/include/tl_splice.h: -------------------------------------------------------------------------------- 1 | #ifndef TOOLS_SPLICE_H 2 | #define TOOLS_SPLICE_H 3 | 4 | #include "tl_predef.h" 5 | #include "tl_iostream.h" 6 | 7 | /** 8 | * \enum TL_SPLICE_FLAG 9 | * 10 | * \brief Flags for tl_iostream_splice 11 | */ 12 | typedef enum { 13 | /** 14 | * \brief If the splice operation is not supported, 15 | * don't use the fallback 16 | * 17 | * By default, if the underlying OS implementation does no support 18 | * splice for the supplied streams, tl_iostream_splice will use a 19 | * fallback implementation that reads and writes data in a loop. 20 | * However, this fallback is no longer atomic. If a read succeeds 21 | * but a subsequent write fails, the fallback cannot put the data 22 | * back into the stream and the data is lost. So in some cases, 23 | * you might prefere tl_iostream_splice to fail immediately and 24 | * handle the case in a different way. 25 | */ 26 | TL_SPLICE_NO_FALLBACK = 0x01, 27 | 28 | TL_SPLICE_ALL_FLAGS = 0x01 29 | } TL_SPLICE_FLAG; 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | /** 36 | * \brief Read data from an input steam and write it to an output stream 37 | * 38 | * If the underlying streams wrap OS specific objects and the system supports 39 | * it, this function attempts to read transfer data from one stream and write 40 | * it to another using zero-copy functions. 41 | * 42 | * Should a direct transfer not be possible, a fallback read-write-loop 43 | * is used, unless \ref TL_SPLICE_NO_FALLBACK is specified. 44 | * 45 | * \param out The stream to write to 46 | * \param in The stream to read from 47 | * \param count The number of bytes to copy 48 | * \param actual If not NULL, returns the number of bytes actually copied 49 | * \param flags A combination of \ref TL_SPLICE_FLAG flags 50 | * 51 | * \return Zero on success, a negative value (\ref TL_ERROR_CODE) on failure 52 | */ 53 | TLOSAPI int tl_iostream_splice(tl_iostream *out, tl_iostream *in, 54 | size_t count, size_t *actual, int flags); 55 | 56 | #ifdef __cplusplus 57 | } 58 | #endif 59 | 60 | #endif /* TOOLS_SPLICE_H */ 61 | 62 | -------------------------------------------------------------------------------- /os/include/tl_unix.h: -------------------------------------------------------------------------------- 1 | /* 2 | * tl_unix.h 3 | * This file is part of ctools 4 | * 5 | * Copyright (C) 2015 - David Oberhollenzer 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a 8 | * copy of this software and associated documentation files (the "Software"), 9 | * to deal in the Software without restriction, including without limitation 10 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | * and/or sell copies of the Software, and to permit persons to whom the 12 | * Software is furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | * DEALINGS IN THE SOFTWARE. 24 | */ 25 | /** 26 | * \file tl_unix.h 27 | * 28 | * \brief Contains unix spefic functionality 29 | */ 30 | #ifndef TL_UNIX_H 31 | #define TL_UNIX_H 32 | 33 | #include "tl_predef.h" 34 | 35 | #ifdef __cplusplus 36 | extern "C" { 37 | #endif 38 | 39 | /** 40 | * \brief Get the file descriptor of a packetserver 41 | * 42 | * For packet servers created with the unix implementation of 43 | * tl_network_create_packet_server, this function returns the 44 | * underlying socket file descriptor. 45 | */ 46 | TLOSAPI int tl_unix_packetserver_fd(tl_packetserver *srv); 47 | 48 | /** 49 | * \brief Get the file descriptor of a tl_iostream 50 | * 51 | * For tl_iostream implementations created by the unix backend, 52 | * this function returns the underlying file descriptors. 53 | * 54 | * Similar to the pipe system call, this function returns two descriptor, 55 | * the first one for reading, the second one for writing. For some 56 | * implementations (e.g. sockets) they can both have the same value. 57 | * 58 | * \param fds An array that can hold up to two file descriptors, the first 59 | * one for reading, the second one for writing 60 | * 61 | * \return Returns the number of file descriptors written to fds 62 | */ 63 | TLOSAPI void tl_unix_iostream_fd(tl_iostream *str, int *fds); 64 | 65 | /** 66 | * \brief Get the file descriptor of a tl_server 67 | * 68 | * For servers created with the unix implementation of 69 | * tl_network_create_server, this function returns the 70 | * underlying socket file descriptor. 71 | */ 72 | TLOSAPI int tl_unix_server_fd(tl_server *srv); 73 | 74 | #ifdef __cplusplus 75 | } 76 | #endif 77 | 78 | #endif /* TL_UNIX_H */ 79 | 80 | -------------------------------------------------------------------------------- /os/src/W32/dir_scan.c: -------------------------------------------------------------------------------- 1 | /* dir_scan.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_OS_EXPORT 9 | #include "tl_array.h" 10 | #include "tl_dir.h" 11 | #include "os.h" 12 | 13 | int tl_dir_scan(const char *path, tl_array *list) 14 | { 15 | WIN32_FIND_DATAW ent; 16 | tl_string str; 17 | HANDLE hnd; 18 | WCHAR *ptr; 19 | int ret; 20 | 21 | assert(path && list); 22 | 23 | /* paste path string */ 24 | tl_string_init(&str); 25 | tl_string_append_utf8(&str, path); 26 | tl_string_append_utf8(&str, "\\*"); 27 | 28 | ret = get_absolute_path(&ptr, str.data.data); 29 | if (ret != 0) 30 | goto out; 31 | 32 | hnd = FindFirstFileW(ptr, &ent); 33 | free(ptr); 34 | 35 | ret = TL_ERR_NOT_EXIST; 36 | if (hnd == INVALID_HANDLE_VALUE) 37 | goto out; 38 | 39 | do { 40 | ptr = ent.cFileName; 41 | 42 | if (ptr[0] != '.' || (!ptr[1] && (ptr[1] != '.' || !ptr[2]))) { 43 | tl_string_clear(&str); 44 | tl_string_append_utf16(&str, ent.cFileName); 45 | tl_array_append(list, &str); 46 | } 47 | } while (FindNextFileW(hnd, &ent)); 48 | 49 | ret = 0; 50 | FindClose(hnd); 51 | out: 52 | tl_string_cleanup(&str); 53 | return ret; 54 | } 55 | -------------------------------------------------------------------------------- /os/src/W32/fstream.c: -------------------------------------------------------------------------------- 1 | /* fstream.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_OS_EXPORT 9 | #include "tl_iostream.h" 10 | #include "os.h" 11 | 12 | static void fstream_destroy(tl_iostream *super) 13 | { 14 | fstream *this = (fstream *)super; 15 | 16 | assert(this); 17 | if (this->rhnd) 18 | CloseHandle(this->rhnd); 19 | if (this->whnd && (this->rhnd != this->whnd)) 20 | CloseHandle(this->whnd); 21 | free(this); 22 | } 23 | 24 | static int fstream_set_timeout(tl_iostream *super, unsigned int timeout) 25 | { 26 | fstream *this = (fstream *)super; 27 | 28 | assert(this); 29 | 30 | if (this->rhnd) 31 | set_handle_timeout(this->rhnd, timeout); 32 | 33 | if (this->whnd && this->whnd != this->rhnd) 34 | set_handle_timeout(this->whnd, timeout); 35 | 36 | return 0; 37 | } 38 | 39 | static int fstream_write(tl_iostream *super, const void *buffer, 40 | size_t size, size_t *actual) 41 | { 42 | fstream *this = (fstream *)super; 43 | DWORD result; 44 | 45 | if (actual) 46 | *actual = 0; 47 | 48 | assert(this && buffer); 49 | 50 | if (!this->whnd) 51 | return TL_ERR_NOT_SUPPORTED; 52 | 53 | if (!WriteFile(this->whnd, buffer, size, &result, NULL)) 54 | return errno_to_fs(GetLastError()); 55 | 56 | if (actual) 57 | *actual = result; 58 | 59 | return 0; 60 | } 61 | 62 | static int fstream_read(tl_iostream *super, void *buffer, size_t size, 63 | size_t *actual) 64 | { 65 | fstream *this = (fstream *)super; 66 | DWORD result; 67 | 68 | if (actual) 69 | *actual = 0; 70 | 71 | assert(this && buffer); 72 | 73 | if (!this->rhnd) 74 | return TL_ERR_NOT_SUPPORTED; 75 | 76 | if (!ReadFile(this->rhnd, buffer, size, &result, NULL)) 77 | return errno_to_fs(GetLastError()); 78 | 79 | if (actual) 80 | *actual = result; 81 | 82 | return result ? 0 : TL_ERR_CLOSED; 83 | } 84 | 85 | /****************************************************************************/ 86 | 87 | fstream tl_stdio = { 88 | { 89 | TL_STREAM_TYPE_FILE, 90 | NULL, 91 | fstream_set_timeout, 92 | fstream_write, 93 | fstream_read}, 94 | NULL, 95 | NULL 96 | }; 97 | 98 | fstream tl_stderr = { 99 | { 100 | TL_STREAM_TYPE_FILE, 101 | NULL, 102 | fstream_set_timeout, 103 | fstream_write, 104 | fstream_read}, 105 | NULL, 106 | NULL 107 | }; 108 | 109 | /****************************************************************************/ 110 | 111 | tl_iostream *fstream_create(HANDLE readhnd, HANDLE writehnd, int type) 112 | { 113 | fstream *this = calloc(1, sizeof(*this)); 114 | tl_iostream *super = (tl_iostream *)this; 115 | 116 | if (this) { 117 | this->rhnd = readhnd; 118 | this->whnd = writehnd; 119 | super->type = type; 120 | super->read = fstream_read; 121 | super->write = fstream_write; 122 | super->destroy = fstream_destroy; 123 | super->set_timeout = fstream_set_timeout; 124 | } 125 | return super; 126 | } 127 | -------------------------------------------------------------------------------- /os/src/W32/iostream.c: -------------------------------------------------------------------------------- 1 | /* iostream.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_OS_EXPORT 9 | #include "tl_iostream.h" 10 | #include "os.h" 11 | 12 | int __tl_os_splice(tl_iostream *out, tl_iostream *in, 13 | size_t count, size_t *actual) 14 | { 15 | (void)out; 16 | (void)in; 17 | (void)count; 18 | (void)actual; 19 | return TL_ERR_NOT_SUPPORTED; 20 | } 21 | -------------------------------------------------------------------------------- /os/src/W32/monitor.c: -------------------------------------------------------------------------------- 1 | /* monitor.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_OS_EXPORT 9 | #include "tl_thread.h" 10 | #include "os.h" 11 | 12 | int tl_monitor_init(tl_monitor *this) 13 | { 14 | assert(this); 15 | this->notify_event = CreateEvent(NULL, FALSE, FALSE, NULL); 16 | 17 | if (!this->notify_event) 18 | return 0; 19 | 20 | this->notify_all_event = CreateEvent(NULL, TRUE, FALSE, NULL); 21 | 22 | if (!this->notify_all_event) { 23 | CloseHandle(this->notify_event); 24 | return 0; 25 | } 26 | 27 | InitializeCriticalSection(&this->mutex); 28 | InitializeCriticalSection(&this->waiter_mutex); 29 | this->wait_count = 0; 30 | return 1; 31 | } 32 | 33 | void tl_monitor_cleanup(tl_monitor *this) 34 | { 35 | assert(this); 36 | CloseHandle(this->notify_event); 37 | CloseHandle(this->notify_all_event); 38 | DeleteCriticalSection(&this->mutex); 39 | DeleteCriticalSection(&this->waiter_mutex); 40 | } 41 | 42 | tl_monitor *tl_monitor_create(void) 43 | { 44 | tl_monitor *this = calloc(1, sizeof(*this)); 45 | 46 | if (!tl_monitor_init(this)) { 47 | free(this); 48 | this = NULL; 49 | } 50 | 51 | return this; 52 | } 53 | 54 | void tl_monitor_destroy(tl_monitor *this) 55 | { 56 | assert(this); 57 | tl_monitor_cleanup(this); 58 | free(this); 59 | } 60 | 61 | int tl_monitor_lock(tl_monitor *this, unsigned long timeout) 62 | { 63 | assert(this); 64 | return tl_mutex_lock((tl_mutex *)&this->mutex, timeout); 65 | } 66 | 67 | void tl_monitor_unlock(tl_monitor *this) 68 | { 69 | assert(this); 70 | tl_mutex_unlock((tl_mutex *)&this->mutex); 71 | } 72 | 73 | int tl_monitor_wait(tl_monitor *this, unsigned long timeout) 74 | { 75 | DWORD status = WAIT_FAILED, waittime = timeout ? timeout : INFINITE; 76 | HANDLE events[2]; 77 | 78 | assert(this); 79 | 80 | /* increment wait count */ 81 | EnterCriticalSection(&this->waiter_mutex); 82 | ++(this->wait_count); 83 | LeaveCriticalSection(&this->waiter_mutex); 84 | 85 | /* wait for event */ 86 | LeaveCriticalSection(&this->mutex); 87 | events[0] = this->notify_event; 88 | events[1] = this->notify_all_event; 89 | 90 | status = WaitForMultipleObjects(2, events, FALSE, waittime); 91 | 92 | /* decrement wait count */ 93 | EnterCriticalSection(&this->waiter_mutex); 94 | --(this->wait_count); 95 | 96 | if (this->wait_count == 0 && status == (WAIT_OBJECT_0 + 1)) 97 | ResetEvent(this->notify_all_event); 98 | LeaveCriticalSection(&this->waiter_mutex); 99 | 100 | /* restore state */ 101 | EnterCriticalSection(&this->mutex); 102 | return status != WAIT_TIMEOUT && status != WAIT_FAILED; 103 | } 104 | 105 | void tl_monitor_notify(tl_monitor *this) 106 | { 107 | assert(this); 108 | 109 | EnterCriticalSection(&this->waiter_mutex); 110 | 111 | if (this->wait_count > 0) 112 | SetEvent(this->notify_event); 113 | 114 | LeaveCriticalSection(&this->waiter_mutex); 115 | } 116 | 117 | void tl_monitor_notify_all(tl_monitor *this) 118 | { 119 | assert(this); 120 | 121 | EnterCriticalSection(&this->waiter_mutex); 122 | 123 | if (this->wait_count > 0) 124 | SetEvent(this->notify_all_event); 125 | 126 | LeaveCriticalSection(&this->waiter_mutex); 127 | } 128 | -------------------------------------------------------------------------------- /os/src/W32/mutex.c: -------------------------------------------------------------------------------- 1 | /* mutex.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_OS_EXPORT 9 | #include "tl_thread.h" 10 | #include "os.h" 11 | 12 | tl_mutex *tl_mutex_create(int recursive) 13 | { 14 | CRITICAL_SECTION *this = calloc(1, sizeof(*this)); 15 | (void)recursive; 16 | 17 | assert(this); 18 | InitializeCriticalSection(this); 19 | return (tl_mutex *)this; 20 | } 21 | 22 | int tl_mutex_lock(tl_mutex *this, unsigned long timeout) 23 | { 24 | unsigned long dt; 25 | 26 | assert(this); 27 | 28 | if (timeout > 0) { 29 | retry: 30 | if (TryEnterCriticalSection((CRITICAL_SECTION *)this)) 31 | return 1; 32 | 33 | if (timeout) { 34 | dt = timeout < 10 ? timeout : 10; 35 | Sleep(dt); 36 | timeout -= dt; 37 | goto retry; 38 | } 39 | 40 | return 0; 41 | } 42 | 43 | EnterCriticalSection((CRITICAL_SECTION *)this); 44 | return 1; 45 | } 46 | 47 | void tl_mutex_unlock(tl_mutex *this) 48 | { 49 | assert(this); 50 | LeaveCriticalSection((CRITICAL_SECTION *)this); 51 | } 52 | 53 | void tl_mutex_destroy(tl_mutex *this) 54 | { 55 | assert(this); 56 | DeleteCriticalSection((CRITICAL_SECTION *)this); 57 | free(this); 58 | } 59 | -------------------------------------------------------------------------------- /os/src/W32/os.h: -------------------------------------------------------------------------------- 1 | /* os.h -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #ifndef OS_H 9 | #define OS_H 10 | 11 | #include "tl_iostream.h" 12 | #include "tl_thread.h" 13 | #include "tl_string.h" 14 | #include "tl_array.h" 15 | #include "tl_fs.h" 16 | 17 | #include "../platform.h" 18 | #include "../bsdsock/bsdsock.h" 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #define WIN32_LEAN_AND_MEAN 25 | #include 26 | 27 | typedef struct fstream fstream; 28 | typedef struct sockstream sockstream; 29 | 30 | struct tl_monitor { 31 | CRITICAL_SECTION mutex; 32 | CRITICAL_SECTION waiter_mutex; 33 | HANDLE notify_event; 34 | HANDLE notify_all_event; 35 | unsigned int wait_count; 36 | }; 37 | 38 | struct fstream { 39 | tl_iostream super; 40 | HANDLE rhnd; 41 | HANDLE whnd; 42 | }; 43 | 44 | struct sockstream { 45 | tl_iostream super; 46 | int proto; 47 | DWORD timeout; 48 | SOCKET socket; 49 | }; 50 | 51 | extern fstream tl_stdio; 52 | extern fstream tl_stderr; 53 | 54 | #ifdef __cplusplus 55 | extern "C" { 56 | #endif 57 | 58 | /** \brief Translate a GetLastError value to an TL_FS_* error code */ 59 | int errno_to_fs(int code); 60 | 61 | /** \brief Convert an UTF-8 string to UTF-16. Returned buffer must be freed */ 62 | WCHAR *utf8_to_utf16(const char *utf8); 63 | 64 | /** 65 | * \brief Acquire Winsock API 66 | * 67 | * Atomically increments an internal reference count. On the first call, 68 | * (i.e. refcount was 0), WSAStartup is called to initialize the winsock API. 69 | * 70 | * \return Non-zero on success, zero on failure 71 | */ 72 | int winsock_acquire(void); 73 | 74 | /** 75 | * \brief Release Winsock API 76 | * 77 | * Atomically decrements an internal reference count. If the reference count 78 | * reaches 0, WSACleanup is called to cleanup the winsock internal state. 79 | */ 80 | void winsock_release(void); 81 | 82 | /** \brief Create a stream operating on a winsock socket */ 83 | tl_iostream *sock_stream_create(SOCKET sockfd, int proto); 84 | 85 | int wait_for_fd(SOCKET socket, unsigned long timeout, int write); 86 | 87 | int WSAHandleFuckup(void); 88 | 89 | /** \brief Initialize a monitor object */ 90 | int tl_monitor_init(tl_monitor * monitor); 91 | 92 | /** \brief Destroy a monitor object */ 93 | void tl_monitor_cleanup(tl_monitor * monitor); 94 | 95 | /** \brief Create a stream object that uses pipe or file HANDLE objects */ 96 | tl_iostream *fstream_create(HANDLE readhnd, HANDLE writehnd, int type); 97 | 98 | /** \brief Set flags on socket */ 99 | int set_socket_flags(SOCKET fd, int netlayer, int *flags); 100 | 101 | int get_absolute_path(WCHAR **out, const char *path); 102 | 103 | void set_handle_timeout(HANDLE hnd, unsigned int timeout); 104 | 105 | #ifdef __cplusplus 106 | } 107 | #endif 108 | #endif /* OS_H */ 109 | -------------------------------------------------------------------------------- /os/src/W32/rwlock.c: -------------------------------------------------------------------------------- 1 | /* rwlock.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_OS_EXPORT 9 | #include "tl_thread.h" 10 | #include "os.h" 11 | 12 | /* 13 | based on implementation by Jordan Zimmerman from 14 | "Single-Writer Multi-Reader lock for Win98", 15 | comp.programming.threads 16 | */ 17 | struct tl_rwlock { 18 | CRITICAL_SECTION lock; 19 | CRITICAL_SECTION readlock; 20 | HANDLE writelock; 21 | int readers; 22 | }; 23 | 24 | tl_rwlock *tl_rwlock_create(void) 25 | { 26 | tl_rwlock *this = calloc(1, sizeof(*this)); 27 | 28 | if (!this) 29 | return NULL; 30 | 31 | InitializeCriticalSection(&this->lock); 32 | InitializeCriticalSection(&this->readlock); 33 | 34 | this->readers = 0; 35 | this->writelock = CreateEvent(NULL, TRUE, FALSE, NULL); 36 | return this; 37 | } 38 | 39 | int tl_rwlock_lock_read(tl_rwlock *this, unsigned long timeout) 40 | { 41 | assert(this); 42 | 43 | if (!tl_mutex_lock((tl_mutex *)&this->readlock, timeout)) 44 | return 0; 45 | if (!tl_mutex_lock((tl_mutex *)&this->lock, timeout)) { 46 | LeaveCriticalSection(&this->readlock); 47 | return 0; 48 | } 49 | 50 | ++(this->readers); 51 | ResetEvent(this->writelock); 52 | 53 | LeaveCriticalSection(&this->lock); 54 | LeaveCriticalSection(&this->readlock); 55 | return 1; 56 | } 57 | 58 | int tl_rwlock_lock_write(tl_rwlock *this, unsigned long timeout) 59 | { 60 | assert(this); 61 | 62 | if (!tl_mutex_lock((tl_mutex *)&this->readlock, timeout)) 63 | return 0; 64 | top: 65 | if (!tl_mutex_lock((tl_mutex *)&this->lock, timeout)) 66 | goto fail; 67 | 68 | if (this->readers) { 69 | LeaveCriticalSection(&(this->lock)); 70 | 71 | if (timeout > 0) { 72 | if (WaitForSingleObject(this->writelock, timeout) != 73 | WAIT_OBJECT_0) 74 | goto fail; 75 | } else { 76 | WaitForSingleObject(this->writelock, INFINITE); 77 | } 78 | goto top; 79 | } 80 | 81 | LeaveCriticalSection(&this->readlock); 82 | return 1; 83 | fail: 84 | LeaveCriticalSection(&this->readlock); 85 | return 0; 86 | } 87 | 88 | void tl_rwlock_unlock_read(tl_rwlock *this) 89 | { 90 | assert(this); 91 | EnterCriticalSection(&this->lock); 92 | if (--(this->readers) == 0) 93 | SetEvent(this->writelock); 94 | LeaveCriticalSection(&this->lock); 95 | } 96 | 97 | void tl_rwlock_unlock_write(tl_rwlock *this) 98 | { 99 | assert(this); 100 | LeaveCriticalSection(&this->lock); 101 | } 102 | 103 | void tl_rwlock_destroy(tl_rwlock *this) 104 | { 105 | assert(this); 106 | CloseHandle(this->writelock); 107 | DeleteCriticalSection(&this->lock); 108 | DeleteCriticalSection(&this->readlock); 109 | free(this); 110 | } 111 | -------------------------------------------------------------------------------- /os/src/W32/sockstream.c: -------------------------------------------------------------------------------- 1 | /* sockstream.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_OS_EXPORT 9 | #include "os.h" 10 | #include "tl_iostream.h" 11 | 12 | static void sockstream_destroy(tl_iostream *super) 13 | { 14 | sockstream *this = (sockstream *)super; 15 | 16 | assert(this); 17 | 18 | closesocket(this->socket); 19 | free(this); 20 | winsock_release(); 21 | } 22 | 23 | static int sockstream_set_timeout(tl_iostream *this, unsigned int timeout) 24 | { 25 | assert(this); 26 | 27 | ((sockstream *)this)->timeout = timeout; 28 | return 0; 29 | } 30 | 31 | static int sockstream_write_raw(tl_iostream *super, const void *buffer, 32 | size_t size, size_t *actual) 33 | { 34 | sockstream *this = (sockstream *)super; 35 | int status; 36 | 37 | assert(this && buffer); 38 | 39 | if (actual) 40 | *actual = 0; 41 | if (!size) 42 | return 0; 43 | 44 | if (!wait_for_fd(this->socket, this->timeout, 1)) 45 | return TL_ERR_TIMEOUT; 46 | 47 | status = send(((sockstream *)this)->socket, buffer, size, 0); 48 | 49 | if (status < 0) 50 | return WSAHandleFuckup(); 51 | if (actual) 52 | *actual = status; 53 | return 0; 54 | } 55 | 56 | static int sockstream_read_raw(tl_iostream *super, void *buffer, 57 | size_t size, size_t *actual) 58 | { 59 | sockstream *this = (sockstream *)super; 60 | int status; 61 | 62 | assert(this && buffer); 63 | 64 | if (actual) 65 | *actual = 0; 66 | if (!size) 67 | return 0; 68 | if (!wait_for_fd(this->socket, this->timeout, 0)) 69 | return TL_ERR_TIMEOUT; 70 | 71 | status = recv(this->socket, buffer, size, 0); 72 | 73 | if (status == 0) 74 | return TL_ERR_CLOSED; 75 | if (status < 0) 76 | return WSAHandleFuckup(); 77 | if (actual) 78 | *actual = status; 79 | return 0; 80 | } 81 | 82 | /****************************************************************************/ 83 | 84 | tl_iostream *sock_stream_create(SOCKET sockfd, int proto) 85 | { 86 | sockstream *this = calloc(1, sizeof(*this)); 87 | tl_iostream *super = (tl_iostream *)this; 88 | 89 | if (!this) 90 | return NULL; 91 | 92 | this->socket = sockfd; 93 | this->proto = proto; 94 | super->type = TL_STREAM_TYPE_SOCK; 95 | super->destroy = sockstream_destroy; 96 | super->set_timeout = sockstream_set_timeout; 97 | super->write = sockstream_write_raw; 98 | super->read = sockstream_read_raw; 99 | return super; 100 | } 101 | -------------------------------------------------------------------------------- /os/src/W32/thread.c: -------------------------------------------------------------------------------- 1 | /* thread.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_OS_EXPORT 9 | #include "tl_thread.h" 10 | #include "os.h" 11 | 12 | struct tl_thread { 13 | int state; 14 | void *retval; 15 | tl_thread_function function; 16 | void *argument; 17 | CRITICAL_SECTION mutex; 18 | HANDLE thread; 19 | }; 20 | 21 | static DWORD WINAPI thread_wrapper(LPVOID param) 22 | { 23 | tl_thread *this = param; 24 | void *retval; 25 | 26 | EnterCriticalSection(&this->mutex); 27 | this->state = TL_RUNNING; 28 | LeaveCriticalSection(&this->mutex); 29 | 30 | retval = this->function(this->argument); 31 | 32 | EnterCriticalSection(&this->mutex); 33 | this->state = TL_TERMINATED; 34 | this->retval = retval; 35 | LeaveCriticalSection(&this->mutex); 36 | return 0; 37 | } 38 | 39 | tl_thread *tl_thread_create(tl_thread_function function, void *arg) 40 | { 41 | tl_thread *this = calloc(1, sizeof(*this)); 42 | 43 | if (!this) 44 | return NULL; 45 | 46 | InitializeCriticalSection(&this->mutex); 47 | 48 | this->function = function; 49 | this->argument = arg; 50 | this->retval = NULL; 51 | this->state = TL_PENDING; 52 | this->thread = CreateThread(NULL, 0, thread_wrapper, this, 0, 0); 53 | 54 | if (!this->thread) { 55 | free(this); 56 | this = NULL; 57 | } 58 | 59 | return this; 60 | } 61 | 62 | int tl_thread_join(tl_thread *this, unsigned long timeout) 63 | { 64 | DWORD dt = timeout ? timeout : INFINITE; 65 | 66 | assert(this); 67 | return WaitForSingleObject(this->thread, dt) == WAIT_OBJECT_0; 68 | } 69 | 70 | void *tl_thread_get_return_value(tl_thread *this) 71 | { 72 | void *retval; 73 | 74 | assert(this); 75 | EnterCriticalSection(&this->mutex); 76 | retval = this->retval; 77 | LeaveCriticalSection(&this->mutex); 78 | 79 | return retval; 80 | } 81 | 82 | int tl_thread_get_state(tl_thread *this) 83 | { 84 | int state; 85 | 86 | assert(this); 87 | EnterCriticalSection(&this->mutex); 88 | state = this->state; 89 | LeaveCriticalSection(&this->mutex); 90 | 91 | return state; 92 | } 93 | 94 | void tl_thread_destroy(tl_thread *this) 95 | { 96 | assert(this); 97 | TerminateThread(this->thread, EXIT_FAILURE); 98 | CloseHandle(this->thread); 99 | DeleteCriticalSection(&this->mutex); 100 | free(this); 101 | } 102 | 103 | int tl_thread_get_id(tl_thread *this) 104 | { 105 | return this ? (int)this->thread : (int)GetCurrentThread(); 106 | } 107 | -------------------------------------------------------------------------------- /os/src/bsdsock/addr_v6.c: -------------------------------------------------------------------------------- 1 | /* addr_v6.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_OS_EXPORT 9 | #include "../platform.h" 10 | #include "bsdsock.h" 11 | 12 | #if defined(_WIN32) && !defined(s6_addr) 13 | #define s6_addr u.Byte 14 | #endif 15 | 16 | void convert_ipv6(const struct in6_addr *v6, tl_net_addr *addr) 17 | { 18 | addr->addr.ipv6[7] = (v6->s6_addr[0] << 8) | v6->s6_addr[1]; 19 | addr->addr.ipv6[6] = (v6->s6_addr[2] << 8) | v6->s6_addr[3]; 20 | addr->addr.ipv6[5] = (v6->s6_addr[4] << 8) | v6->s6_addr[5]; 21 | addr->addr.ipv6[4] = (v6->s6_addr[6] << 8) | v6->s6_addr[7]; 22 | addr->addr.ipv6[3] = (v6->s6_addr[8] << 8) | v6->s6_addr[9]; 23 | addr->addr.ipv6[2] = (v6->s6_addr[10] << 8) | v6->s6_addr[11]; 24 | addr->addr.ipv6[1] = (v6->s6_addr[12] << 8) | v6->s6_addr[13]; 25 | addr->addr.ipv6[0] = (v6->s6_addr[14] << 8) | v6->s6_addr[15]; 26 | } 27 | 28 | void convert_in6addr(const tl_net_addr *addr, struct in6_addr *v6) 29 | { 30 | v6->s6_addr[0] = (addr->addr.ipv6[7] >> 8) & 0xFF; 31 | v6->s6_addr[1] = addr->addr.ipv6[7] & 0xFF; 32 | v6->s6_addr[2] = (addr->addr.ipv6[6] >> 8) & 0xFF; 33 | v6->s6_addr[3] = addr->addr.ipv6[6] & 0xFF; 34 | v6->s6_addr[4] = (addr->addr.ipv6[5] >> 8) & 0xFF; 35 | v6->s6_addr[5] = addr->addr.ipv6[5] & 0xFF; 36 | v6->s6_addr[6] = (addr->addr.ipv6[4] >> 8) & 0xFF; 37 | v6->s6_addr[7] = addr->addr.ipv6[4] & 0xFF; 38 | v6->s6_addr[8] = (addr->addr.ipv6[3] >> 8) & 0xFF; 39 | v6->s6_addr[9] = addr->addr.ipv6[3] & 0xFF; 40 | v6->s6_addr[10] = (addr->addr.ipv6[2] >> 8) & 0xFF; 41 | v6->s6_addr[11] = addr->addr.ipv6[2] & 0xFF; 42 | v6->s6_addr[12] = (addr->addr.ipv6[1] >> 8) & 0xFF; 43 | v6->s6_addr[13] = addr->addr.ipv6[1] & 0xFF; 44 | v6->s6_addr[14] = (addr->addr.ipv6[0] >> 8) & 0xFF; 45 | v6->s6_addr[15] = addr->addr.ipv6[0] & 0xFF; 46 | } 47 | -------------------------------------------------------------------------------- /os/src/bsdsock/bsdsock.h: -------------------------------------------------------------------------------- 1 | /* bsdsock.h -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #ifndef BSD_SOCK_H 9 | #define BSD_SOCK_H 10 | 11 | #ifdef _WIN32 12 | #define WIN32_LEAN_AND_MEAN 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | typedef int ssize_t; 19 | 20 | #define MSG_NOSIGNAL 0 21 | 22 | #define convert_errno() WSAHandleFuckup() 23 | #define is_intr() (0) 24 | #define set_cloexec(fd) (0) 25 | #else 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | typedef int SOCKET; 33 | 34 | #define closesocket close 35 | #define INVALID_SOCKET (-1) 36 | #define SOCKET_ERROR (-1) 37 | 38 | #define winsock_acquire() (1) 39 | #define winsock_release() 40 | 41 | #define convert_errno() errno_to_fs(errno) 42 | #define is_intr() (errno == EINTR) 43 | #define set_cloexec(fd) (fcntl(fd, F_SETFD, FD_CLOEXEC)) 44 | #endif 45 | 46 | #include "tl_packetserver.h" 47 | #include "tl_network.h" 48 | #include "tl_server.h" 49 | 50 | typedef struct { 51 | tl_server super; 52 | SOCKET socket; 53 | int flags; 54 | } tcp_server; 55 | 56 | typedef struct { 57 | tl_packetserver super; 58 | unsigned long timeout; 59 | SOCKET sockfd; 60 | } tl_udp_packetserver; 61 | 62 | typedef enum { 63 | TL_ENFORCE_V6_ONLY = 0x1000 64 | } TL_NETWORK_INTERNAL_FLAGS; 65 | 66 | #ifdef __cplusplus 67 | extern "C" { 68 | #endif 69 | 70 | /** 71 | * \brief Convert an in6_addr structure to a tl_net_addr 72 | * 73 | * \param v6 Pointer to input data 74 | * \param addr Pointer to output structure 75 | */ 76 | void convert_ipv6(const struct in6_addr *v6, tl_net_addr *addr); 77 | 78 | /** 79 | * \brief Convert a tl_net_addr structure to an in6_addr 80 | * 81 | * \param addr Pointer to input data 82 | * \param v6 Pointer to output structure 83 | */ 84 | void convert_in6addr(const tl_net_addr *addr, struct in6_addr *v6); 85 | 86 | /** 87 | * \brief Convert a tl_net_addr structure to a sockaddr_in 88 | * 89 | * \param peer The intput address 90 | * \param addrbuffer A pointer to a buffer to write the sockaddr_in structure 91 | * data to 92 | * \param size Returns the number of bytes written to the addrbuffer 93 | * 94 | * \return Non-zero on success, zero on failure 95 | */ 96 | int encode_sockaddr(const tl_net_addr *peer, 97 | struct sockaddr_storage *addrbuffer, socklen_t *size); 98 | 99 | /** 100 | * \brief Decode a sockaddr_in or sockaddr_in6 structure to a tl_net_addr 101 | * 102 | * \param addr A pointer to the address structure 103 | * \param len The size of the address structure 104 | * \param out A pointer to the tl_net_addr structure to write to 105 | * 106 | * \return Non-zero on success, zero on failure 107 | */ 108 | int decode_sockaddr_in(const struct sockaddr_storage *addr, 109 | socklen_t len, tl_net_addr *out); 110 | 111 | /** 112 | * \brief Create a socket 113 | * 114 | * \param net A \ref TL_NETWORK_PROTOCOL enumerator vaule 115 | * \param transport A \ref TL_TRANSPORT_PROTOCOL enumerator vaule 116 | * 117 | * \return A socket file descriptor on success, -1 on failrue 118 | */ 119 | SOCKET create_socket(int net, int transport); 120 | 121 | int bind_socket(SOCKET s, const tl_net_addr * addr); 122 | 123 | int connect_socket(SOCKET s, const tl_net_addr * addr); 124 | 125 | /** \brief Perform actual name resolution */ 126 | int resolve_name(const char *hostname, int proto, 127 | tl_net_addr *addr, size_t count); 128 | 129 | #ifdef __cplusplus 130 | } 131 | #endif 132 | #endif /* BSD_SOCK_H */ 133 | -------------------------------------------------------------------------------- /os/src/bsdsock/network.c: -------------------------------------------------------------------------------- 1 | /* network.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_OS_EXPORT 9 | #include "../platform.h" 10 | #include "bsdsock.h" 11 | 12 | tl_iostream *tl_network_create_client(const tl_net_addr *peer, 13 | const tl_net_addr *local, int flags) 14 | { 15 | tl_iostream *stream; 16 | SOCKET sockfd; 17 | 18 | assert(peer); 19 | 20 | if (!winsock_acquire()) 21 | return NULL; 22 | 23 | sockfd = create_socket(peer->net, peer->transport); 24 | if (sockfd == INVALID_SOCKET) 25 | goto fail_release; 26 | 27 | if (!set_socket_flags(sockfd, peer->net, &flags)) 28 | goto fail; 29 | 30 | if (local && !bind_socket(sockfd, local)) 31 | goto fail; 32 | 33 | if (!connect_socket(sockfd, peer)) 34 | goto fail; 35 | 36 | if (!(stream = sock_stream_create(sockfd, peer->transport))) 37 | goto fail; 38 | 39 | return stream; 40 | fail: 41 | closesocket(sockfd); 42 | fail_release: 43 | winsock_release(); 44 | return NULL; 45 | } 46 | -------------------------------------------------------------------------------- /os/src/bsdsock/resolve_addr.c: -------------------------------------------------------------------------------- 1 | /* resolve_addr.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_OS_EXPORT 9 | #include "../platform.h" 10 | #include "bsdsock.h" 11 | 12 | int tl_network_resolve_address(const tl_net_addr *addr, tl_string *out) 13 | { 14 | struct sockaddr_storage addrbuf; 15 | char *host = NULL, *new; 16 | socklen_t size; 17 | size_t slen; 18 | int ret; 19 | 20 | assert(addr); 21 | 22 | if (!winsock_acquire()) 23 | return TL_ERR_INTERNAL; 24 | 25 | if (!encode_sockaddr(addr, &addrbuf, &size)) 26 | return TL_ERR_NET_ADDR; 27 | 28 | slen = NI_MAXHOST; 29 | #ifndef _WIN32 30 | for (ret = EAI_OVERFLOW; ret == EAI_OVERFLOW; slen *= 2) 31 | #endif 32 | { 33 | if (!(new = realloc(host, slen))) { 34 | ret = TL_ERR_ALLOC; 35 | goto out_free; 36 | } 37 | 38 | host = new; 39 | ret = getnameinfo((const void *)&addrbuf, size, 40 | host, slen, NULL, 0, NI_NAMEREQD); 41 | } 42 | 43 | switch (ret) { 44 | case 0: 45 | break; 46 | #ifndef _WIN32 47 | case EAI_SYSTEM: 48 | ret = errno_to_fs(errno); 49 | goto out_free; 50 | #endif 51 | case EAI_AGAIN: 52 | ret = TL_ERR_TIMEOUT; 53 | goto out_free; 54 | case EAI_FAMILY: 55 | ret = TL_ERR_NET_ADDR; 56 | goto out_free; 57 | case EAI_NONAME: 58 | ret = 0; 59 | goto out_free; 60 | case EAI_MEMORY: 61 | ret = TL_ERR_ALLOC; 62 | goto out_free; 63 | default: 64 | ret = TL_ERR_INTERNAL; 65 | goto out_free; 66 | } 67 | 68 | if (out) { 69 | memset(out, 0, sizeof(*out)); 70 | out->data.reserved = slen; 71 | out->data.used = strlen(host) + 1; 72 | out->data.unitsize = 1; 73 | out->data.data = host; 74 | out->mbseq = out->charcount = out->data.used - 1; 75 | } 76 | 77 | winsock_release(); 78 | return 1; 79 | out_free: 80 | free(host); 81 | winsock_release(); 82 | return ret; 83 | } 84 | -------------------------------------------------------------------------------- /os/src/bsdsock/resolve_name.c: -------------------------------------------------------------------------------- 1 | /* resolve_name.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_OS_EXPORT 9 | #include "../platform.h" 10 | #include "bsdsock.h" 11 | 12 | static int have_duplicate(const tl_net_addr *addr, size_t count, 13 | const tl_net_addr *find) 14 | { 15 | size_t i; 16 | int ret; 17 | 18 | for (i = 0; i < count; ++i) { 19 | if (addr[i].net != find->net) 20 | continue; 21 | 22 | if (find->net == TL_IPV4 23 | && find->addr.ipv4 == addr[i].addr.ipv4) 24 | return 1; 25 | 26 | if (find->net == TL_IPV6) { 27 | ret = memcmp(find->addr.ipv6, addr[i].addr.ipv6, 28 | sizeof(find->addr.ipv6)); 29 | if (ret == 0) 30 | return 1; 31 | } 32 | } 33 | 34 | return 0; 35 | } 36 | 37 | int resolve_name(const char *hostname, int proto, 38 | tl_net_addr *addr, size_t count) 39 | { 40 | struct addrinfo hints, *info, *p; 41 | struct in6_addr addr6; 42 | struct in_addr addr4; 43 | tl_net_addr conv; 44 | size_t i = 0; 45 | 46 | proto = (proto == TL_IPV6) ? AF_INET6 : 47 | ((proto == TL_IPV4) ? AF_INET : AF_UNSPEC); 48 | 49 | memset(&hints, 0, sizeof(hints)); 50 | hints.ai_family = proto; 51 | 52 | if (!winsock_acquire()) 53 | return 0; 54 | 55 | if (getaddrinfo(hostname, NULL, &hints, &info) != 0) 56 | goto out; 57 | 58 | for (p = info; p != NULL; p = p->ai_next) { 59 | if (p->ai_family != AF_INET && p->ai_family != AF_INET6) 60 | continue; 61 | 62 | if (proto != AF_UNSPEC && p->ai_family != proto) 63 | continue; 64 | 65 | if (addr) { 66 | if (i >= count) 67 | break; 68 | 69 | memset(&conv, 0, sizeof(conv)); 70 | 71 | if (p->ai_family == AF_INET6) { 72 | addr6 = 73 | ((struct sockaddr_in6 *)p->ai_addr)-> 74 | sin6_addr; 75 | convert_ipv6(&addr6, &conv); 76 | } else { 77 | addr4 = 78 | ((struct sockaddr_in *)p->ai_addr)-> 79 | sin_addr; 80 | conv.addr.ipv4 = ntohl(addr4.s_addr); 81 | } 82 | 83 | conv.net = p->ai_family == AF_INET6 ? 84 | TL_IPV6 : TL_IPV4; 85 | 86 | if (have_duplicate(addr, i, &conv)) 87 | continue; 88 | 89 | addr[i] = conv; 90 | } 91 | 92 | ++i; 93 | } 94 | 95 | freeaddrinfo(info); 96 | out: 97 | winsock_release(); 98 | return i; 99 | } 100 | -------------------------------------------------------------------------------- /os/src/bsdsock/sock.c: -------------------------------------------------------------------------------- 1 | /* sock.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_OS_EXPORT 9 | #include "../platform.h" 10 | #include "bsdsock.h" 11 | 12 | #include 13 | 14 | int decode_sockaddr_in(const struct sockaddr_storage *addr, socklen_t len, 15 | tl_net_addr *out) 16 | { 17 | const struct sockaddr_in6 *ipv6 = (const struct sockaddr_in6 *)addr; 18 | const struct sockaddr_in *ipv4 = (const struct sockaddr_in *)addr; 19 | 20 | if (len == sizeof(*ipv4) && ipv4->sin_family == AF_INET) { 21 | out->net = TL_IPV4; 22 | out->port = ntohs(ipv4->sin_port); 23 | out->addr.ipv4 = ntohl(ipv4->sin_addr.s_addr); 24 | return 1; 25 | } 26 | 27 | if (len == sizeof(*ipv6) && ipv6->sin6_family == AF_INET6) { 28 | convert_ipv6(&(ipv6->sin6_addr), out); 29 | out->net = TL_IPV6; 30 | out->port = ntohs(ipv6->sin6_port); 31 | return 1; 32 | } 33 | 34 | return 0; 35 | } 36 | 37 | int encode_sockaddr(const tl_net_addr *peer, 38 | struct sockaddr_storage *addrbuffer, socklen_t *size) 39 | { 40 | struct sockaddr_in6 *v6addr = (struct sockaddr_in6 *)addrbuffer; 41 | struct sockaddr_in *v4addr = (struct sockaddr_in *)addrbuffer; 42 | 43 | if (!peer) 44 | return 0; 45 | 46 | if (peer->net == TL_IPV4) { 47 | memset(v4addr, 0, sizeof(*v4addr)); 48 | v4addr->sin_addr.s_addr = htonl(peer->addr.ipv4); 49 | v4addr->sin_port = htons(peer->port); 50 | v4addr->sin_family = AF_INET; 51 | *size = sizeof(*v4addr); 52 | return 1; 53 | } 54 | if (peer->net == TL_IPV6) { 55 | memset(v6addr, 0, sizeof(*v6addr)); 56 | convert_in6addr(peer, &(v6addr->sin6_addr)); 57 | v6addr->sin6_port = htons(peer->port); 58 | v6addr->sin6_family = AF_INET6; 59 | *size = sizeof(*v6addr); 60 | return 1; 61 | } 62 | 63 | return 1; 64 | } 65 | 66 | SOCKET create_socket(int net, int transport) 67 | { 68 | int family, type, proto; 69 | SOCKET fd; 70 | 71 | switch (net) { 72 | case TL_IPV4: 73 | family = AF_INET; 74 | break; 75 | case TL_IPV6: 76 | family = AF_INET6; 77 | break; 78 | default: 79 | return INVALID_SOCKET; 80 | } 81 | 82 | switch (transport) { 83 | case TL_TCP: 84 | type = SOCK_STREAM; 85 | proto = IPPROTO_TCP; 86 | break; 87 | case TL_UDP: 88 | type = SOCK_DGRAM; 89 | proto = IPPROTO_UDP; 90 | break; 91 | default: 92 | return INVALID_SOCKET; 93 | } 94 | 95 | fd = socket(family, type, proto); 96 | 97 | if (fd != INVALID_SOCKET && set_cloexec(fd) == -1) { 98 | closesocket(fd); 99 | return INVALID_SOCKET; 100 | } 101 | return fd; 102 | } 103 | 104 | int bind_socket(SOCKET s, const tl_net_addr *addr) 105 | { 106 | struct sockaddr_storage addrbuffer; 107 | socklen_t size; 108 | 109 | if (!encode_sockaddr(addr, &addrbuffer, &size)) 110 | return 0; 111 | 112 | if (bind(s, (void *)&addrbuffer, size) == SOCKET_ERROR) 113 | return 0; 114 | 115 | return 1; 116 | } 117 | 118 | int connect_socket(SOCKET s, const tl_net_addr *addr) 119 | { 120 | struct sockaddr_storage addrbuffer; 121 | socklen_t size; 122 | 123 | if (!encode_sockaddr(addr, &addrbuffer, &size)) 124 | return 0; 125 | 126 | if (connect(s, (void *)&addrbuffer, size) == SOCKET_ERROR) 127 | return 0; 128 | 129 | return 1; 130 | } 131 | -------------------------------------------------------------------------------- /os/src/bsdsock/tcpserver.c: -------------------------------------------------------------------------------- 1 | /* tcpserver.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_OS_EXPORT 9 | #include "../platform.h" 10 | #include "tl_server.h" 11 | #include "bsdsock.h" 12 | 13 | static void tcp_destroy(tl_server *this) 14 | { 15 | assert(this); 16 | closesocket(((tcp_server *)this)->socket); 17 | free(this); 18 | winsock_release(); 19 | } 20 | 21 | static int is_v6(SOCKET peer) 22 | { 23 | struct sockaddr_storage addr; 24 | socklen_t len = sizeof(addr); 25 | struct sockaddr_in6 *v6; 26 | int x, y; 27 | 28 | if (getpeername(peer, (void *)&addr, &len) != 0) 29 | return 0; 30 | if (addr.ss_family != AF_INET6) 31 | return 0; 32 | 33 | v6 = (struct sockaddr_in6 *)&addr; 34 | 35 | x = v6->sin6_addr.s6_addr[0] | v6->sin6_addr.s6_addr[1] | 36 | v6->sin6_addr.s6_addr[2] | v6->sin6_addr.s6_addr[3] | 37 | v6->sin6_addr.s6_addr[4] | v6->sin6_addr.s6_addr[5] | 38 | v6->sin6_addr.s6_addr[6] | v6->sin6_addr.s6_addr[7] | 39 | v6->sin6_addr.s6_addr[8] | v6->sin6_addr.s6_addr[9]; 40 | 41 | y = v6->sin6_addr.s6_addr[10] & v6->sin6_addr.s6_addr[11]; 42 | 43 | if (x == 0 && y == 0xFF) 44 | return 0; 45 | 46 | return 1; 47 | } 48 | 49 | static tl_iostream *tcp_wait_for_client(tl_server *super, int timeout) 50 | { 51 | tcp_server *this = (tcp_server *)super; 52 | tl_iostream *client; 53 | SOCKET peer; 54 | 55 | assert(this); 56 | 57 | if (!wait_for_fd(this->socket, timeout, 0)) 58 | return NULL; 59 | 60 | peer = accept(this->socket, 0, 0); 61 | if (peer == INVALID_SOCKET) 62 | return NULL; 63 | 64 | if (this->flags & TL_ENFORCE_V6_ONLY && !is_v6(peer)) 65 | goto ignore; 66 | 67 | if (set_cloexec(peer) == -1) { 68 | closesocket(peer); 69 | return NULL; 70 | } 71 | 72 | client = sock_stream_create(peer, TL_TCP); 73 | if (!client) 74 | goto ignore; 75 | return client; 76 | ignore: 77 | closesocket(peer); 78 | return NULL; 79 | } 80 | 81 | tl_server *tl_network_create_server(const tl_net_addr *addr, 82 | unsigned int backlog, int flags) 83 | { 84 | tcp_server *this; 85 | tl_server *super; 86 | SOCKET sockfd; 87 | 88 | assert(addr); 89 | 90 | if (addr->transport != TL_TCP) 91 | return NULL; 92 | 93 | if (!winsock_acquire()) 94 | return NULL; 95 | 96 | sockfd = create_socket(addr->net, addr->transport); 97 | if (sockfd == INVALID_SOCKET) 98 | goto fail; 99 | 100 | if (!set_socket_flags(sockfd, addr->net, &flags)) 101 | goto failclose; 102 | 103 | if (!bind_socket(sockfd, addr)) 104 | goto failclose; 105 | 106 | if (listen(sockfd, backlog) == SOCKET_ERROR) 107 | goto failclose; 108 | 109 | this = calloc(1, sizeof(*this)); 110 | super = (tl_server *)this; 111 | if (!this) 112 | goto failclose; 113 | 114 | this->flags = flags; 115 | this->socket = sockfd; 116 | super->destroy = tcp_destroy; 117 | super->wait_for_client = tcp_wait_for_client; 118 | return super; 119 | failclose: 120 | closesocket(sockfd); 121 | fail: 122 | winsock_release(); 123 | return NULL; 124 | } 125 | -------------------------------------------------------------------------------- /os/src/network.c: -------------------------------------------------------------------------------- 1 | /* network.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_OS_EXPORT 9 | #include "tl_network.h" 10 | 11 | #include 12 | #include 13 | 14 | int tl_network_get_special_address(tl_net_addr *addr, int type, int net) 15 | { 16 | assert(addr); 17 | 18 | switch (net) { 19 | case TL_IPV4: 20 | switch (type) { 21 | case TL_LOOPBACK: 22 | addr->addr.ipv4 = (127 << 24) | (1); 23 | break; 24 | case TL_BROADCAST: 25 | addr->addr.ipv4 = 0xFFFFFFFF; 26 | break; 27 | case TL_ALL: 28 | addr->addr.ipv4 = 0; 29 | break; 30 | default: 31 | return 0; 32 | } 33 | break; 34 | case TL_IPV6: 35 | switch (type) { 36 | case TL_LOOPBACK: 37 | memset(addr->addr.ipv6, 0, sizeof(addr->addr.ipv6)); 38 | addr->addr.ipv6[0] = 0x0001; 39 | break; 40 | case TL_ALL: 41 | memset(addr->addr.ipv6, 0, sizeof(addr->addr.ipv6)); 42 | break; 43 | default: 44 | return 0; 45 | } 46 | break; 47 | default: 48 | return 0; 49 | } 50 | 51 | addr->net = net; 52 | return 1; 53 | } 54 | 55 | static int is_actually_v4(const tl_net_addr *a) 56 | { 57 | if (a->addr.ipv6[7] || a->addr.ipv6[6]) 58 | return 0; 59 | if (a->addr.ipv6[5] || a->addr.ipv6[4]) 60 | return 0; 61 | /* IPv4-mapped-IPv6 address */ 62 | if (a->addr.ipv6[3] == 0x0000 && a->addr.ipv6[2] == 0xFFFF) 63 | return 1; 64 | /* SIIT address */ 65 | if (a->addr.ipv6[3] == 0xFFFF && a->addr.ipv6[2] == 0x0000) 66 | return 1; 67 | return 0; 68 | } 69 | 70 | int tl_net_addr_convert(tl_net_addr *dst, const tl_net_addr *src, int target) 71 | { 72 | if (src->net == target) { 73 | memcpy(dst, src, sizeof(*src)); 74 | return 1; 75 | } 76 | 77 | switch (target) { 78 | case TL_IPV4: 79 | if (src->net != TL_IPV6) 80 | return 0; 81 | if (!is_actually_v4(src)) 82 | return 0; 83 | dst->addr.ipv4 = ((tl_u32) src->addr.ipv6[1] << 16) | 84 | ((tl_u32) src->addr.ipv6[0]); 85 | break; 86 | case TL_IPV6: 87 | if (src->net != TL_IPV4) 88 | return 0; 89 | memset(dst->addr.ipv6, 0, sizeof(dst->addr.ipv6)); 90 | dst->addr.ipv6[2] = 0xFFFF; 91 | dst->addr.ipv6[1] = (src->addr.ipv4 >> 16) & 0xFFFF; 92 | dst->addr.ipv6[0] = src->addr.ipv4 & 0xFFFF; 93 | break; 94 | default: 95 | return 0; 96 | } 97 | 98 | dst->transport = src->transport; 99 | dst->net = target; 100 | dst->port = src->port; 101 | return 1; 102 | } 103 | 104 | int tl_net_addr_equal(const tl_net_addr *a, const tl_net_addr *b) 105 | { 106 | tl_net_addr conv; 107 | 108 | assert(a && b); 109 | 110 | if ((a->transport != b->transport) || (a->port != b->port)) 111 | return 0; 112 | 113 | switch (a->net) { 114 | case TL_IPV4: 115 | switch (b->net) { 116 | case TL_IPV4: 117 | return a->addr.ipv4 == b->addr.ipv4; 118 | case TL_IPV6: 119 | if (!tl_net_addr_convert(&conv, b, TL_IPV4)) 120 | return 0; 121 | return a->addr.ipv4 == conv.addr.ipv4; 122 | } 123 | break; 124 | case TL_IPV6: 125 | switch (b->net) { 126 | case TL_IPV4: 127 | if (!tl_net_addr_convert(&conv, a, TL_IPV4)) 128 | return 0; 129 | return b->addr.ipv4 == conv.addr.ipv4; 130 | case TL_IPV6: 131 | return memcmp(a->addr.ipv6, b->addr.ipv6, 132 | sizeof(b->addr.ipv6)) == 0; 133 | } 134 | break; 135 | } 136 | return 0; 137 | } 138 | -------------------------------------------------------------------------------- /os/src/platform.h: -------------------------------------------------------------------------------- 1 | /* platform.h -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #ifndef TL_INTERNAL_PLATFORM_H 9 | #define TL_INTERNAL_PLATFORM_H 10 | 11 | #if defined(_WIN32) 12 | #include "W32/os.h" 13 | #else 14 | #include "unix/os.h" 15 | #endif 16 | 17 | #ifdef __cplusplus 18 | extern "C" { 19 | #endif 20 | 21 | /* Possible implementation of tl_iostream_splice. Pointers and count are 22 | already sanity checked. If this returns TL_ERR_NOT_SUPPORTED, a fallback 23 | is used that copies chunks manually. */ 24 | int __tl_os_splice(tl_iostream *out, tl_iostream *in, 25 | size_t count, size_t *actual); 26 | 27 | #ifdef __cplusplus 28 | } 29 | #endif 30 | 31 | #endif /* TL_INTERNAL_PLATFORM_H */ 32 | -------------------------------------------------------------------------------- /os/src/splice.c: -------------------------------------------------------------------------------- 1 | /* splice.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_OS_EXPORT 9 | #include "tl_splice.h" 10 | #include "platform.h" 11 | 12 | static int splice_copy(tl_iostream *out, tl_iostream *in, 13 | size_t count, size_t *actual) 14 | { 15 | size_t indiff, outdiff, outcount = 0; 16 | int res_r = 0, res_w = 0, res = 0; 17 | char buffer[1024]; 18 | 19 | while (count) { 20 | indiff = count > sizeof(buffer) ? sizeof(buffer) : count; 21 | res_r = in->read(in, buffer, indiff, &indiff); 22 | 23 | if (res_r == 0 && !indiff) { 24 | res = res_r; 25 | break; 26 | } 27 | 28 | if (res_r != 0 && res_r != TL_EOF) { 29 | res = res_r; 30 | break; 31 | } 32 | 33 | while (indiff) { 34 | res_w = out->write(out, buffer, indiff, &outdiff); 35 | 36 | if (res_w != 0) { 37 | res = res_w; 38 | goto out; 39 | } 40 | 41 | indiff -= outdiff; 42 | count -= outdiff; 43 | outcount += outdiff; 44 | } 45 | 46 | if (res_r == TL_EOF) { 47 | res = res_r; 48 | break; 49 | } 50 | } 51 | out: 52 | if (actual) 53 | *actual = outcount; 54 | 55 | return res; 56 | } 57 | 58 | int tl_iostream_splice(tl_iostream *out, tl_iostream *in, 59 | size_t count, size_t *actual, int flags) 60 | { 61 | int res; 62 | 63 | assert(out && in); 64 | 65 | if (actual) 66 | *actual = 0; 67 | 68 | if (!count) 69 | return 0; 70 | 71 | if (flags & (~TL_SPLICE_ALL_FLAGS)) 72 | return TL_ERR_ARG; 73 | 74 | res = __tl_os_splice(out, in, count, actual); 75 | 76 | if ((res == TL_ERR_NOT_SUPPORTED) && !(flags & TL_SPLICE_NO_FALLBACK)) 77 | res = splice_copy(out, in, count, actual); 78 | 79 | return res; 80 | } 81 | -------------------------------------------------------------------------------- /os/src/unix/dir_it.c: -------------------------------------------------------------------------------- 1 | /* dir_it.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_OS_EXPORT 9 | #include "tl_iterator.h" 10 | #include "tl_dir.h" 11 | #include "os.h" 12 | 13 | #include 14 | 15 | typedef struct { 16 | tl_iterator super; /* inherits iterator interface */ 17 | tl_string current; /* current directory name */ 18 | struct dirent *ent; /* current directory entry */ 19 | DIR *dir; /* pointer to directory */ 20 | } dir_iterator; 21 | 22 | static void find_next(dir_iterator *this) 23 | { 24 | retry: 25 | this->ent = readdir(this->dir); 26 | 27 | if (!this->ent) 28 | return; 29 | if (!strcmp(this->ent->d_name, ".")) 30 | goto retry; 31 | if (!strcmp(this->ent->d_name, "..")) 32 | goto retry; 33 | 34 | tl_string_init_local(&this->current, this->ent->d_name); 35 | } 36 | 37 | static void dir_iterator_destroy(tl_iterator *super) 38 | { 39 | dir_iterator *this = (dir_iterator *)super; 40 | 41 | closedir(this->dir); 42 | free(this); 43 | } 44 | 45 | static void dir_iterator_reset(tl_iterator *super) 46 | { 47 | dir_iterator *this = (dir_iterator *)super; 48 | rewinddir(this->dir); 49 | find_next(this); 50 | } 51 | 52 | static int dir_iterator_has_data(tl_iterator *this) 53 | { 54 | return (((dir_iterator *)this)->ent != NULL); 55 | } 56 | 57 | static void dir_iterator_next(tl_iterator *super) 58 | { 59 | dir_iterator *this = (dir_iterator *)super; 60 | 61 | if (this->ent) 62 | find_next(this); 63 | } 64 | 65 | static void *dir_iterator_get_value(tl_iterator *super) 66 | { 67 | dir_iterator *this = (dir_iterator *)super; 68 | 69 | return this->ent ? &this->current : NULL; 70 | } 71 | 72 | static void dir_iterator_remove(tl_iterator *this) 73 | { 74 | (void)this; 75 | } 76 | 77 | tl_iterator *tl_dir_iterate(const char *path) 78 | { 79 | dir_iterator *it; 80 | DIR *dir; 81 | 82 | if (!(dir = opendir(path))) 83 | return NULL; 84 | 85 | if (!(it = calloc(1, sizeof(*it)))) { 86 | closedir(dir); 87 | return NULL; 88 | } 89 | 90 | it->dir = dir; 91 | find_next(it); 92 | 93 | it->super.destroy = dir_iterator_destroy; 94 | it->super.reset = dir_iterator_reset; 95 | it->super.has_data = dir_iterator_has_data; 96 | it->super.next = dir_iterator_next; 97 | it->super.get_value = dir_iterator_get_value; 98 | it->super.remove = dir_iterator_remove; 99 | return (tl_iterator *)it; 100 | } 101 | -------------------------------------------------------------------------------- /os/src/unix/dir_scan.c: -------------------------------------------------------------------------------- 1 | /* dir_scan.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_OS_EXPORT 9 | #include "tl_array.h" 10 | #include "tl_dir.h" 11 | #include "os.h" 12 | 13 | #include 14 | 15 | int tl_dir_scan(const char *path, tl_array *list) 16 | { 17 | struct dirent *ent; 18 | tl_string str; 19 | DIR *dir; 20 | 21 | assert(list && path); 22 | 23 | if (!(dir = opendir(path))) 24 | return errno_to_fs(errno); 25 | 26 | while ((ent = readdir(dir))) { 27 | if (strcmp(ent->d_name, ".") != 0 28 | && strcmp(ent->d_name, "..") != 0) { 29 | tl_string_init_local(&str, ent->d_name); 30 | tl_array_append(list, &str); 31 | } 32 | } 33 | 34 | closedir(dir); 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /os/src/unix/fdstream.c: -------------------------------------------------------------------------------- 1 | /* fdstream.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_OS_EXPORT 9 | #include "os.h" 10 | #include "tl_iostream.h" 11 | 12 | static void fd_stream_destroy(tl_iostream *super) 13 | { 14 | fd_stream *this = (fd_stream *)super; 15 | assert(this); 16 | if (this->readfd >= 0) 17 | close(this->readfd); 18 | if ((this->readfd != this->writefd) && (this->writefd >= 0)) 19 | close(this->writefd); 20 | free(this); 21 | } 22 | 23 | static int fd_stream_set_timeout(tl_iostream *this, unsigned int timeout) 24 | { 25 | assert(this); 26 | ((fd_stream *)this)->timeout = timeout; 27 | return 0; 28 | } 29 | 30 | static int fd_stream_write(tl_iostream *super, const void *buffer, 31 | size_t size, size_t *actual) 32 | { 33 | fd_stream *this = (fd_stream *)super; 34 | ssize_t result = 0, intr_count = 0; 35 | int ret = 0; 36 | 37 | assert(this && buffer); 38 | 39 | if (this->writefd < 0) 40 | return TL_ERR_NOT_SUPPORTED; 41 | if (!size) 42 | goto out; 43 | 44 | retry: 45 | if (!wait_for_fd(this->writefd, this->timeout, 1)) 46 | return TL_ERR_TIMEOUT; 47 | 48 | if (super->type == TL_STREAM_TYPE_SOCK) { 49 | result = sendto(this->writefd, buffer, size, 50 | MSG_NOSIGNAL, NULL, 0); 51 | } else { 52 | result = write(this->writefd, buffer, size); 53 | } 54 | 55 | if (result < 0) { 56 | if (errno == EINTR && (intr_count++) < 3) 57 | goto retry; 58 | ret = errno_to_fs(errno); 59 | } 60 | 61 | out: 62 | if (actual) 63 | *actual = result; 64 | return ret; 65 | } 66 | 67 | static int fd_stream_read(tl_iostream *super, void *buffer, 68 | size_t size, size_t *actual) 69 | { 70 | fd_stream *this = (fd_stream *)super; 71 | ssize_t result = 0, intr_count = 0; 72 | int ret = 0; 73 | 74 | assert(this && buffer); 75 | 76 | if (this->readfd < 0) { 77 | ret = TL_ERR_NOT_SUPPORTED; 78 | goto out; 79 | } 80 | if (!size) 81 | goto out; 82 | 83 | retry: 84 | if (!wait_for_fd(this->readfd, this->timeout, 0)) 85 | return TL_ERR_TIMEOUT; 86 | 87 | if (super->type == TL_STREAM_TYPE_SOCK) { 88 | result = recvfrom(this->readfd, buffer, size, 89 | MSG_NOSIGNAL, NULL, NULL); 90 | } else { 91 | result = read(this->readfd, buffer, size); 92 | } 93 | 94 | if (result < 0 && errno == EINTR && (intr_count++) < 3) 95 | goto retry; 96 | 97 | ret = result < 0 ? errno_to_fs(errno) : 98 | (result == 0 ? TL_ERR_CLOSED : 0); 99 | out: 100 | if (actual) 101 | *actual = result > 0 ? result : 0; 102 | return ret; 103 | } 104 | 105 | /****************************************************************************/ 106 | 107 | fd_stream tl_stdio = { 108 | { 109 | TL_STREAM_TYPE_FILE, 110 | NULL, 111 | fd_stream_set_timeout, 112 | fd_stream_write, 113 | fd_stream_read}, 114 | 0, 115 | STDIN_FILENO, 116 | STDOUT_FILENO, 117 | 0 118 | }; 119 | 120 | fd_stream tl_stderr = { 121 | { 122 | TL_STREAM_TYPE_FILE, 123 | NULL, 124 | fd_stream_set_timeout, 125 | fd_stream_write, 126 | fd_stream_read}, 127 | 0, 128 | -1, 129 | STDERR_FILENO, 130 | 0 131 | }; 132 | 133 | /****************************************************************************/ 134 | 135 | tl_iostream *fdstream_create(int readfd, int writefd, int type, int flags) 136 | { 137 | fd_stream *this = calloc(1, sizeof(*this)); 138 | tl_iostream *super = (tl_iostream *)this; 139 | 140 | if (!this) 141 | return NULL; 142 | 143 | this->readfd = readfd; 144 | this->writefd = writefd; 145 | this->flags = flags; 146 | super->type = type; 147 | super->destroy = fd_stream_destroy; 148 | super->set_timeout = fd_stream_set_timeout; 149 | super->write = fd_stream_write; 150 | super->read = fd_stream_read; 151 | return super; 152 | } 153 | -------------------------------------------------------------------------------- /os/src/unix/fs.c: -------------------------------------------------------------------------------- 1 | /* fs.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_OS_EXPORT 9 | #include "tl_fs.h" 10 | #include "os.h" 11 | 12 | #include 13 | 14 | const char *tl_fs_get_dir_sep(void) 15 | { 16 | return "/"; 17 | } 18 | 19 | int tl_fs_exists(const char *path) 20 | { 21 | struct stat sb; 22 | assert(path); 23 | 24 | if (stat(path, &sb) != 0) 25 | return errno == ENOENT ? 1 : errno_to_fs(errno); 26 | 27 | return 0; 28 | } 29 | 30 | int tl_fs_is_directory(const char *path) 31 | { 32 | struct stat sb; 33 | assert(path); 34 | 35 | if (stat(path, &sb) != 0) 36 | return errno_to_fs(errno); 37 | 38 | return S_ISDIR(sb.st_mode) ? 0 : 1; 39 | } 40 | 41 | int tl_fs_is_symlink(const char *path) 42 | { 43 | struct stat sb; 44 | assert(path); 45 | 46 | if (lstat(path, &sb) != 0) 47 | return errno_to_fs(errno); 48 | 49 | return S_ISLNK(sb.st_mode) ? 0 : 1; 50 | } 51 | 52 | int tl_fs_mkdir(const char *path) 53 | { 54 | struct stat sb; 55 | 56 | assert(path); 57 | 58 | if (stat(path, &sb) == 0) 59 | return S_ISDIR(sb.st_mode) ? 0 : TL_ERR_EXISTS; 60 | 61 | if (mkdir(path, S_IRWXU) != 0) 62 | return errno_to_fs(errno); 63 | 64 | return 0; 65 | } 66 | 67 | int tl_fs_cwd(const char *path) 68 | { 69 | assert(path); 70 | return chdir(path) == 0 ? 0 : errno_to_fs(errno); 71 | } 72 | 73 | int tl_fs_delete(const char *path) 74 | { 75 | struct stat sb; 76 | 77 | assert(path); 78 | 79 | if (stat(path, &sb) != 0) 80 | goto fail; 81 | 82 | if (S_ISDIR(sb.st_mode)) { 83 | if (rmdir(path) != 0) 84 | goto fail; 85 | } else if (unlink(path) != 0) { 86 | goto fail; 87 | } 88 | 89 | return 0; 90 | fail: 91 | return errno_to_fs(errno); 92 | } 93 | 94 | int tl_fs_get_wd(tl_string *path) 95 | { 96 | char *str, *new; 97 | size_t size; 98 | 99 | assert(path); 100 | 101 | /* Benny Hill theme starts playing */ 102 | for (size = 256, str = NULL; ; size *= 2) { 103 | if (!(new = realloc(str, size))) 104 | goto fail; 105 | 106 | str = new; 107 | 108 | if (getcwd(str, size)) 109 | break; 110 | 111 | if (errno != ERANGE) 112 | goto fail; 113 | } 114 | 115 | /* copy to string */ 116 | tl_string_init_local(path, str); 117 | path->data.reserved = size; 118 | 119 | if (tl_string_last(path) != '/' && 120 | !tl_string_append_code_point(path, '/')) { 121 | tl_string_cleanup(path); 122 | return TL_ERR_ALLOC; 123 | } 124 | return 0; 125 | fail: 126 | free(str); 127 | return errno_to_fs(errno); 128 | } 129 | 130 | int tl_fs_get_user_dir(tl_string *path) 131 | { 132 | struct passwd *pw; 133 | int pw_err = 0; 134 | char *dir; 135 | 136 | assert(path); 137 | 138 | /* try to get passwd entry */ 139 | errno = 0; 140 | pw = getpwuid(getuid()); 141 | pw_err = errno; 142 | 143 | if (pw && pw->pw_dir) { 144 | dir = pw->pw_dir; 145 | goto done; 146 | } 147 | 148 | /* try environment */ 149 | dir = getenv("HOME"); 150 | if (dir) 151 | goto done; 152 | 153 | return pw_err ? errno_to_fs(pw_err) : 1; 154 | done: 155 | tl_string_init_cstr(path, dir); 156 | 157 | if (tl_string_last(path) != '/' && 158 | !tl_string_append_code_point(path, '/')) { 159 | tl_string_cleanup(path); 160 | return TL_ERR_ALLOC; 161 | } 162 | return 0; 163 | } 164 | 165 | int tl_fs_get_file_size(const char *path, tl_u64 *size) 166 | { 167 | struct stat sb; 168 | 169 | assert(path && size); 170 | 171 | if (stat(path, &sb) != 0) 172 | return errno_to_fs(errno); 173 | 174 | if (!S_ISREG(sb.st_mode)) 175 | return TL_ERR_NOT_FILE; 176 | 177 | *size = sb.st_size; 178 | return 0; 179 | } 180 | -------------------------------------------------------------------------------- /os/src/unix/iostream.c: -------------------------------------------------------------------------------- 1 | /* iostream.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_OS_EXPORT 9 | #include "tl_iostream.h" 10 | #include "tl_unix.h" 11 | #include "os.h" 12 | 13 | #ifdef __linux__ 14 | #include 15 | 16 | int __tl_os_splice(tl_iostream *out, tl_iostream *in, 17 | size_t count, size_t *actual) 18 | { 19 | int infd, outfd, fds[2]; 20 | ssize_t res = -1; 21 | off_t old = 0; 22 | 23 | /* get fds */ 24 | tl_unix_iostream_fd(in, fds); 25 | infd = fds[0]; 26 | 27 | tl_unix_iostream_fd(out, fds); 28 | outfd = fds[1]; 29 | 30 | if (infd == -1 || outfd == -1) 31 | return TL_ERR_NOT_SUPPORTED; 32 | 33 | if (!wait_for_fd(infd, ((fd_stream *)in)->timeout, 0)) 34 | return TL_ERR_TIMEOUT; 35 | 36 | if (!wait_for_fd(outfd, ((fd_stream *)out)->timeout, 1)) 37 | return TL_ERR_TIMEOUT; 38 | 39 | /* splice */ 40 | if (out->type == TL_STREAM_TYPE_FILE && 41 | (((file_stream *)out)->flags & TL_APPEND)) { 42 | old = lseek(outfd, 0, SEEK_END); 43 | if (old == (off_t)-1) 44 | return TL_ERR_INTERNAL; 45 | } 46 | 47 | if ((in->type == TL_STREAM_TYPE_PIPE) 48 | || (out->type == TL_STREAM_TYPE_PIPE)) { 49 | res = splice(infd, NULL, outfd, NULL, count, SPLICE_F_MOVE); 50 | } else if (in->type == TL_STREAM_TYPE_FILE) { 51 | res = sendfile(outfd, infd, NULL, count); 52 | } 53 | 54 | if (out->type == TL_STREAM_TYPE_FILE && 55 | (((file_stream *) out)->flags & TL_APPEND)) { 56 | lseek(outfd, old, SEEK_SET); 57 | } 58 | 59 | /* let the fallback implementation retry and figure that out */ 60 | if (res <= 0) 61 | return TL_ERR_NOT_SUPPORTED; 62 | 63 | if (actual) 64 | *actual = res; 65 | return 0; 66 | } 67 | #else /* __linux__ */ 68 | int __tl_os_splice(tl_iostream *out, tl_iostream *in, 69 | size_t count, size_t *actual) 70 | { 71 | (void)out; 72 | (void)in; 73 | (void)count; 74 | (void)actual; 75 | return TL_ERR_NOT_SUPPORTED; 76 | } 77 | #endif 78 | 79 | void tl_unix_iostream_fd(tl_iostream *str, int *fds) 80 | { 81 | fds[0] = -1; 82 | fds[1] = -1; 83 | 84 | switch (str->type) { 85 | case TL_STREAM_TYPE_PIPE: 86 | case TL_STREAM_TYPE_FILE: 87 | fds[0] = (((file_stream *) str)->flags & TL_READ) ? 88 | ((file_stream *) str)->fd : -1; 89 | fds[1] = (((file_stream *) str)->flags & TL_WRITE) ? 90 | ((file_stream *) str)->fd : -1; 91 | break; 92 | case TL_STREAM_TYPE_SOCK: 93 | fds[0] = ((fd_stream *) str)->readfd; 94 | fds[1] = ((fd_stream *) str)->writefd; 95 | break; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /os/src/unix/monitor.c: -------------------------------------------------------------------------------- 1 | /* monitor.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_OS_EXPORT 9 | #include "tl_thread.h" 10 | #include "os.h" 11 | 12 | int tl_monitor_init(tl_monitor *this) 13 | { 14 | assert(this); 15 | 16 | if (pthread_mutex_init(&this->mutex, NULL) != 0) 17 | return 0; 18 | 19 | if (pthread_cond_init(&this->cond, NULL) != 0) { 20 | pthread_mutex_destroy(&this->mutex); 21 | return 0; 22 | } 23 | 24 | return 1; 25 | } 26 | 27 | void tl_monitor_cleanup(tl_monitor *this) 28 | { 29 | assert(this); 30 | pthread_cond_destroy(&this->cond); 31 | pthread_mutex_destroy(&this->mutex); 32 | } 33 | 34 | tl_monitor *tl_monitor_create(void) 35 | { 36 | tl_monitor *this = calloc(1, sizeof(*this)); 37 | 38 | if (this && !tl_monitor_init(this)) { 39 | free(this); 40 | this = NULL; 41 | } 42 | 43 | return this; 44 | } 45 | 46 | int tl_monitor_lock(tl_monitor *this, unsigned long timeout) 47 | { 48 | assert(this); 49 | return tl_mutex_lock((tl_mutex *)&this->mutex, timeout); 50 | } 51 | 52 | void tl_monitor_unlock(tl_monitor *this) 53 | { 54 | assert(this); 55 | pthread_mutex_unlock(&this->mutex); 56 | } 57 | 58 | int tl_monitor_wait(tl_monitor *this, unsigned long timeout) 59 | { 60 | struct timespec ts; 61 | 62 | assert(this); 63 | 64 | if (timeout > 0) { 65 | timeout_to_abs(timeout, &ts); 66 | return pthread_cond_timedwait(&this->cond, &this->mutex, 67 | &ts) == 0; 68 | } 69 | 70 | return pthread_cond_wait(&this->cond, &this->mutex) == 0; 71 | } 72 | 73 | void tl_monitor_notify(tl_monitor *this) 74 | { 75 | assert(this); 76 | pthread_cond_signal(&this->cond); 77 | } 78 | 79 | void tl_monitor_notify_all(tl_monitor *this) 80 | { 81 | assert(this); 82 | pthread_cond_broadcast(&this->cond); 83 | } 84 | 85 | void tl_monitor_destroy(tl_monitor *this) 86 | { 87 | assert(this); 88 | tl_monitor_cleanup(this); 89 | free(this); 90 | } 91 | -------------------------------------------------------------------------------- /os/src/unix/mutex.c: -------------------------------------------------------------------------------- 1 | /* mutex.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_OS_EXPORT 9 | #include "tl_thread.h" 10 | #include "os.h" 11 | 12 | tl_mutex *tl_mutex_create(int recursive) 13 | { 14 | pthread_mutex_t *this = calloc(1, sizeof(*this)); 15 | pthread_mutexattr_t attr; 16 | 17 | if (!this) 18 | return NULL; 19 | 20 | if (recursive) { 21 | if (pthread_mutexattr_init(&attr) != 0) 22 | goto fail; 23 | if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) 24 | goto failattr; 25 | if (pthread_mutex_init(this, &attr) != 0) 26 | goto failattr; 27 | pthread_mutexattr_destroy(&attr); 28 | } else if (pthread_mutex_init(this, NULL) != 0) { 29 | goto fail; 30 | } 31 | 32 | return (tl_mutex *)this; 33 | failattr: 34 | pthread_mutexattr_destroy(&attr); 35 | fail: 36 | free(this); 37 | return NULL; 38 | } 39 | 40 | int tl_mutex_lock(tl_mutex *this, unsigned long timeout) 41 | { 42 | struct timespec ts; 43 | 44 | assert(this); 45 | 46 | if (timeout > 0) { 47 | timeout_to_abs(timeout, &ts); 48 | return pthread_mutex_timedlock((pthread_mutex_t *) this, 49 | &ts) == 0; 50 | } 51 | 52 | return pthread_mutex_lock((pthread_mutex_t *)this) == 0; 53 | } 54 | 55 | void tl_mutex_unlock(tl_mutex * this) 56 | { 57 | assert(this); 58 | pthread_mutex_unlock((pthread_mutex_t *)this); 59 | } 60 | 61 | void tl_mutex_destroy(tl_mutex * this) 62 | { 63 | assert(this); 64 | pthread_mutex_destroy((pthread_mutex_t *)this); 65 | free(this); 66 | } 67 | -------------------------------------------------------------------------------- /os/src/unix/network.c: -------------------------------------------------------------------------------- 1 | /* network.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_OS_EXPORT 9 | #include "os.h" 10 | 11 | int tl_network_resolve_name(const char *hostname, int proto, 12 | tl_net_addr *addr, size_t count) 13 | { 14 | struct in6_addr addr6; 15 | struct in_addr addr4; 16 | 17 | assert(hostname); 18 | 19 | /* check if hostname is actually a numeric IPv4 address */ 20 | if (inet_pton(AF_INET, hostname, &addr4) > 0) { 21 | if (proto != TL_IPV4 && proto != TL_ANY) 22 | return 0; 23 | if (addr && count > 0) { 24 | addr->addr.ipv4 = ntohl(addr4.s_addr); 25 | addr->net = TL_IPV4; 26 | } 27 | return 1; 28 | } 29 | 30 | /* check if hostname is acutally a numeric IPv6 address */ 31 | if (inet_pton(AF_INET6, hostname, &addr6) > 0) { 32 | if (proto != TL_IPV6 && proto != TL_ANY) 33 | return 0; 34 | if (addr && count > 0) { 35 | convert_ipv6(&addr6, addr); 36 | addr->net = TL_IPV6; 37 | } 38 | return 1; 39 | } 40 | 41 | return resolve_name(hostname, proto, addr, count); 42 | } 43 | 44 | int tl_network_get_peer_address(tl_iostream *stream, tl_net_addr *addr) 45 | { 46 | fd_stream *fd = (fd_stream *)stream; 47 | struct sockaddr_storage buffer; 48 | socklen_t len = sizeof(buffer); 49 | 50 | assert(stream && addr); 51 | 52 | if (stream->type == TL_STREAM_TYPE_SOCK) { 53 | addr->transport = (fd->flags & STREAM_UDP) ? TL_UDP : TL_TCP; 54 | 55 | if (getpeername(fd->writefd, (void *)&buffer, &len) == 0) 56 | return decode_sockaddr_in(&buffer, len, addr); 57 | } 58 | 59 | return 0; 60 | } 61 | 62 | int tl_network_get_local_address(tl_iostream *stream, tl_net_addr *addr) 63 | { 64 | fd_stream *fd = (fd_stream *)stream; 65 | struct sockaddr_storage buffer; 66 | socklen_t len = sizeof(buffer); 67 | 68 | assert(stream && addr); 69 | 70 | if (stream->type == TL_STREAM_TYPE_SOCK) { 71 | addr->transport = (fd->flags & STREAM_UDP) ? TL_UDP : TL_TCP; 72 | 73 | if (getsockname(fd->writefd, (void *)&buffer, &len) == 0) 74 | return decode_sockaddr_in(&buffer, len, addr); 75 | } 76 | 77 | return 0; 78 | } 79 | 80 | int tl_unix_packetserver_fd(tl_packetserver *srv) 81 | { 82 | return ((tl_udp_packetserver *)srv)->sockfd; 83 | } 84 | 85 | int tl_unix_server_fd(tl_server *srv) 86 | { 87 | return ((tcp_server *)srv)->socket; 88 | } 89 | -------------------------------------------------------------------------------- /os/src/unix/rwlock.c: -------------------------------------------------------------------------------- 1 | /* rwlock.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_OS_EXPORT 9 | #include "tl_thread.h" 10 | #include "os.h" 11 | 12 | tl_rwlock *tl_rwlock_create(void) 13 | { 14 | pthread_rwlock_t *this = calloc(1, sizeof(*this)); 15 | 16 | if (this && pthread_rwlock_init(this, NULL) != 0) { 17 | free(this); 18 | this = NULL; 19 | } 20 | 21 | return (tl_rwlock *)this; 22 | } 23 | 24 | int tl_rwlock_lock_read(tl_rwlock *this, unsigned long timeout) 25 | { 26 | struct timespec ts; 27 | 28 | assert(this); 29 | 30 | if (timeout > 0) { 31 | timeout_to_abs(timeout, &ts); 32 | return pthread_rwlock_timedrdlock((pthread_rwlock_t *)this, 33 | &ts) == 0; 34 | } 35 | 36 | return pthread_rwlock_rdlock((pthread_rwlock_t *)this) == 0; 37 | } 38 | 39 | int tl_rwlock_lock_write(tl_rwlock *this, unsigned long timeout) 40 | { 41 | struct timespec ts; 42 | 43 | assert(this); 44 | 45 | if (timeout > 0) { 46 | timeout_to_abs(timeout, &ts); 47 | return pthread_rwlock_timedwrlock((pthread_rwlock_t *) this, 48 | &ts) == 0; 49 | } 50 | 51 | return pthread_rwlock_wrlock((pthread_rwlock_t *)this) == 0; 52 | } 53 | 54 | void tl_rwlock_unlock_read(tl_rwlock *this) 55 | { 56 | assert(this); 57 | pthread_rwlock_unlock((pthread_rwlock_t *)this); 58 | } 59 | 60 | void tl_rwlock_unlock_write(tl_rwlock *this) 61 | { 62 | assert(this); 63 | pthread_rwlock_unlock((pthread_rwlock_t *)this); 64 | } 65 | 66 | void tl_rwlock_destroy(tl_rwlock *this) 67 | { 68 | assert(this); 69 | pthread_rwlock_destroy((pthread_rwlock_t *)this); 70 | free(this); 71 | } 72 | -------------------------------------------------------------------------------- /os/src/unix/thread.c: -------------------------------------------------------------------------------- 1 | /* thread.c -- This file is part of ctools 2 | * 3 | * Copyright (C) 2015 - David Oberhollenzer 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #define TL_OS_EXPORT 9 | #include "tl_thread.h" 10 | #include "os.h" 11 | 12 | struct tl_thread { 13 | pthread_t thread; 14 | tl_monitor monitor; 15 | int state; 16 | void *retval; 17 | tl_thread_function function; 18 | void *argument; 19 | }; 20 | 21 | static void *pthread_wrapper(void *arg) 22 | { 23 | void (*cleanup_fun) (void *) = (void (*)(void *))tl_monitor_unlock; 24 | tl_thread *this = arg; 25 | void *retval; 26 | 27 | pthread_cleanup_push(cleanup_fun, &this->monitor); 28 | 29 | tl_monitor_lock(&this->monitor, 0); 30 | this->state = TL_RUNNING; 31 | tl_monitor_unlock(&this->monitor); 32 | 33 | retval = this->function(this->argument); 34 | 35 | tl_monitor_lock(&this->monitor, 0); 36 | this->retval = retval; 37 | this->state = TL_TERMINATED; 38 | tl_monitor_notify(&this->monitor); 39 | tl_monitor_unlock(&this->monitor); 40 | 41 | pthread_cleanup_pop(0); 42 | return NULL; 43 | } 44 | 45 | tl_thread *tl_thread_create(tl_thread_function function, void *arg) 46 | { 47 | tl_thread *this; 48 | 49 | assert(function); 50 | 51 | this = calloc(1, sizeof(*this)); 52 | if (!this) 53 | return NULL; 54 | 55 | this->state = TL_PENDING; 56 | this->retval = NULL; 57 | this->function = function; 58 | this->argument = arg; 59 | 60 | if (!tl_monitor_init(&this->monitor)) 61 | goto fail; 62 | if (pthread_create(&this->thread, NULL, pthread_wrapper, this) != 0) 63 | goto failthread; 64 | 65 | return this; 66 | failthread: 67 | tl_monitor_cleanup(&this->monitor); 68 | fail: 69 | free(this); 70 | return NULL; 71 | } 72 | 73 | int tl_thread_join(tl_thread *this, unsigned long timeout) 74 | { 75 | int status = 1; 76 | 77 | assert(this); 78 | 79 | if (timeout > 0) { 80 | tl_monitor_lock(&this->monitor, 0); 81 | if (this->state != TL_TERMINATED) { 82 | tl_monitor_wait(&this->monitor, timeout); 83 | status = (this->state == TL_TERMINATED); 84 | } 85 | tl_monitor_unlock(&this->monitor); 86 | } else { 87 | pthread_join(this->thread, NULL); 88 | } 89 | 90 | return status; 91 | } 92 | 93 | void *tl_thread_get_return_value(tl_thread *this) 94 | { 95 | void *retval; 96 | 97 | assert(this); 98 | 99 | tl_monitor_lock(&this->monitor, 0); 100 | retval = this->retval; 101 | tl_monitor_unlock(&this->monitor); 102 | 103 | return retval; 104 | } 105 | 106 | int tl_thread_get_state(tl_thread *this) 107 | { 108 | int state; 109 | 110 | assert(this); 111 | 112 | tl_monitor_lock(&this->monitor, 0); 113 | state = this->state; 114 | tl_monitor_unlock(&this->monitor); 115 | 116 | return state; 117 | } 118 | 119 | void tl_thread_destroy(tl_thread *this) 120 | { 121 | assert(this); 122 | 123 | if (this->state != TL_TERMINATED) { 124 | pthread_cancel(this->thread); 125 | pthread_join(this->thread, NULL); 126 | } 127 | 128 | tl_monitor_cleanup(&this->monitor); 129 | free(this); 130 | } 131 | 132 | int tl_thread_get_id(tl_thread *this) 133 | { 134 | return this ? this->thread : pthread_self(); 135 | } 136 | -------------------------------------------------------------------------------- /samples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable( compress compress.c ) 2 | add_executable( genpng genpng.c ) 3 | add_executable( stdio stdio.c ) 4 | add_executable( lookup lookup.c ) 5 | add_executable( dirlist dirlist.c ) 6 | add_executable( cmdline cmdline.c ) 7 | 8 | target_link_libraries( dirlist tlcore tlos ${CTOOLS_SYSLIBS} ) 9 | target_link_libraries( compress tlcore tlos ${CTOOLS_SYSLIBS} ) 10 | target_link_libraries( genpng tlcore tlos ${CTOOLS_SYSLIBS} ) 11 | target_link_libraries( lookup tlcore tlos ${CTOOLS_SYSLIBS} ) 12 | target_link_libraries( stdio tlcore tlos ${CTOOLS_SYSLIBS} ) 13 | target_link_libraries( cmdline tlcore ) 14 | 15 | -------------------------------------------------------------------------------- /samples/Makemodule.am: -------------------------------------------------------------------------------- 1 | compress_SOURCES = samples/compress.c 2 | compress_CPPFLAGS = $(AM_CPPFLAGS) 3 | compress_CFLAGS = $(AM_CFLAGS) 4 | compress_LDFLAGS = $(AM_LDFLAGS) 5 | compress_LDADD = libtlcore.la libtlos.la 6 | 7 | genpng_SOURCES = samples/genpng.c 8 | genpng_CPPFLAGS = $(AM_CPPFLAGS) 9 | genpng_CFLAGS = $(AM_CFLAGS) 10 | genpng_LDFLAGS = $(AM_LDFLAGS) 11 | genpng_LDADD = libtlcore.la libtlos.la 12 | 13 | stdio_SOURCES = samples/stdio.c 14 | stdio_CPPFLAGS = $(AM_CPPFLAGS) 15 | stdio_CFLAGS = $(AM_CFLAGS) 16 | stdio_LDFLAGS = $(AM_LDFLAGS) 17 | stdio_LDADD = libtlcore.la libtlos.la 18 | 19 | lookup_SOURCES = samples/lookup.c 20 | lookup_CPPFLAGS = $(AM_CPPFLAGS) 21 | lookup_CFLAGS = $(AM_CFLAGS) 22 | lookup_LDFLAGS = $(AM_LDFLAGS) 23 | lookup_LDADD = libtlcore.la libtlos.la 24 | 25 | dirlist_SOURCES = samples/dirlist.c 26 | dirlist_CPPFLAGS = $(AM_CPPFLAGS) 27 | dirlist_CFLAGS = $(AM_CFLAGS) 28 | dirlist_LDFLAGS = $(AM_LDFLAGS) 29 | dirlist_LDADD = libtlcore.la libtlos.la 30 | 31 | cmdline_SOURCES = samples/cmdline.c 32 | cmdline_CPPFLAGS = $(AM_CPPFLAGS) 33 | cmdline_CFLAGS = $(AM_CFLAGS) 34 | cmdline_LDFLAGS = $(AM_LDFLAGS) 35 | cmdline_LDADD = libtlcore.la libtlos.la 36 | 37 | noinst_PROGRAMS += compress genpng stdio lookup dirlist cmdline 38 | -------------------------------------------------------------------------------- /samples/cmdline.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "tl_opt.h" 5 | 6 | #define FLAG_FOO 0x01 7 | #define FLAG_BAR 0x02 8 | 9 | static unsigned long flags = 0; 10 | 11 | 12 | static void print_help(tl_option *opt, const char *value) 13 | { 14 | (void)opt; 15 | (void)value; 16 | 17 | puts("Usage: cmdline [files...]\n\n" 18 | " --help, -h Print this help text and exit\n" 19 | " --version, -V Print version information and exit\n" 20 | " --foo-flag, -f Set the foo flag\n" 21 | " --bar-flag, -b Set the bar flag\n"); 22 | exit(EXIT_SUCCESS); 23 | } 24 | 25 | static void print_version(tl_option *opt, const char *value) 26 | { 27 | (void)opt; 28 | (void)value; 29 | 30 | puts("cmdline version 5000"); 31 | exit(EXIT_SUCCESS); 32 | } 33 | 34 | static tl_option options[] = { 35 | { TL_OPT_ARG_OPTIONAL, "help", 'h', 0, NULL, print_help }, 36 | { TL_OPT_ARG_NONE, "version", 'V', 0, NULL, print_version }, 37 | { TL_OPT_ARG_NONE, "foo-flag", 'f', FLAG_FOO, &flags, NULL }, 38 | { TL_OPT_ARG_NONE, "bar-flag", 'b', FLAG_BAR, &flags, NULL }, 39 | { 0, NULL, 0, 0, NULL, NULL }, 40 | }; 41 | 42 | int main(int argc, char **argv) 43 | { 44 | int optind, ret; 45 | 46 | if (argc < 2) 47 | print_help(NULL, NULL); 48 | 49 | ret = tl_process_args(options, argc, argv, &optind); 50 | 51 | if (ret < 0) { 52 | if (ret == TL_OPT_UNKNOWN) { 53 | fprintf(stderr, "Unknown option '%s'\n", argv[optind]); 54 | } else if (ret == TL_OPT_MISSING_ARGUMENT) { 55 | fprintf(stderr, 56 | "Option '%s' requires an argument\n", 57 | argv[optind]); 58 | } else if (ret == TL_OPT_EXTRA_ARGUMENT) { 59 | fprintf(stderr, 60 | "Option '%s' does not accept arguments\n", 61 | argv[optind]); 62 | } else { 63 | fprintf(stderr, "Malformed options '%s'\n", 64 | argv[optind]); 65 | } 66 | return EXIT_FAILURE; 67 | } 68 | 69 | if (flags & FLAG_FOO) 70 | puts("The foo flag is set"); 71 | 72 | if (flags & FLAG_BAR) 73 | puts("The bar flag is set"); 74 | 75 | puts("Extra, non option arguments (e.g. file names):"); 76 | 77 | while (optind < argc) { 78 | printf("%s\n", argv[optind++]); 79 | } 80 | 81 | return EXIT_SUCCESS; 82 | } 83 | -------------------------------------------------------------------------------- /samples/dirlist.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "tl_iterator.h" 4 | #include "tl_string.h" 5 | #include "tl_array.h" 6 | #include "tl_dir.h" 7 | #include "tl_fs.h" 8 | 9 | int main(void) 10 | { 11 | tl_iterator* it; 12 | tl_array array; 13 | tl_string path; 14 | size_t i; 15 | 16 | if( tl_fs_get_wd( &path ) == 0 ) 17 | { 18 | printf("Current working directory: %s\n", tl_string_cstr( &path )); 19 | tl_string_cleanup( &path ); 20 | } 21 | 22 | /* Use iterator interface */ 23 | puts("--------- unsorted ---------"); 24 | 25 | it = tl_dir_iterate( "." ); 26 | 27 | while( it->has_data( it ) ) 28 | { 29 | puts( tl_string_cstr( it->get_value( it ) ) ); 30 | it->next( it ); 31 | } 32 | 33 | it->destroy( it ); 34 | 35 | /* Use directory to array interface */ 36 | puts("---------- sorted ----------"); 37 | 38 | tl_array_init( &array, sizeof(tl_string), tl_string_get_allocator( ) ); 39 | 40 | tl_dir_scan( ".", &array ); 41 | tl_array_sort( &array, (tl_compare)tl_string_compare ); 42 | 43 | it = tl_array_first( &array ); 44 | 45 | for( i = 0; i < tl_array_get_size( &array ); ++i ) 46 | { 47 | tl_string* str = tl_array_at( &array, i ); 48 | 49 | puts( tl_string_cstr( str ) ); 50 | } 51 | 52 | tl_array_cleanup( &array ); 53 | return 0; 54 | } 55 | 56 | -------------------------------------------------------------------------------- /samples/lookup.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "tl_network.h" 5 | #include "tl_string.h" 6 | 7 | /* helper function for printing network addresses */ 8 | static void print_address( tl_net_addr* a ) 9 | { 10 | switch( a->net ) 11 | { 12 | case TL_IPV4: 13 | printf( "%d.%d.%d.%d", 14 | (a->addr.ipv4>>24) & 0xFF, (a->addr.ipv4>>16) & 0xFF, 15 | (a->addr.ipv4>> 8) & 0xFF, a->addr.ipv4 & 0xFF ); 16 | break; 17 | case TL_IPV6: 18 | printf( "%X:%X:%X:%X:%X:%X:%X:%X", 19 | a->addr.ipv6[7], a->addr.ipv6[6], 20 | a->addr.ipv6[5], a->addr.ipv6[4], 21 | a->addr.ipv6[3], a->addr.ipv6[2], 22 | a->addr.ipv6[1], a->addr.ipv6[0] ); 23 | break; 24 | default: 25 | printf("unknown address type"); 26 | break; 27 | } 28 | } 29 | 30 | int main( int argc, char** argv ) 31 | { 32 | tl_net_addr addr[20]; 33 | int i, count, ret; 34 | tl_string str; 35 | 36 | if( argc != 2 ) 37 | { 38 | fputs("Usage: lookup \n", stderr); 39 | return EXIT_FAILURE; 40 | } 41 | 42 | /* resolve a name into a list of addresses */ 43 | printf("Looking up name '%s'....\n", argv[1]); 44 | 45 | count = tl_network_resolve_name( argv[1], TL_ANY, 46 | addr, sizeof(addr)/sizeof(addr[0]) ); 47 | 48 | if( count <= 0 ) 49 | { 50 | fputs("Name lookup failed!\n", stderr); 51 | return EXIT_FAILURE; 52 | } 53 | 54 | /* print all addresses we got */ 55 | printf("Got %d addresses:\n", count); 56 | 57 | for( i=0; i "); 72 | 73 | ret = tl_network_resolve_address( addr + i, &str ); 74 | 75 | if( ret == 0 ) 76 | { 77 | printf("\n"); 78 | } 79 | else if( ret < 0 ) 80 | { 81 | printf("\n"); 82 | } 83 | else 84 | { 85 | printf("%s\n", tl_string_cstr(&str)); 86 | tl_string_cleanup(&str); 87 | } 88 | } 89 | 90 | return EXIT_SUCCESS; 91 | } 92 | 93 | -------------------------------------------------------------------------------- /samples/stdio.c: -------------------------------------------------------------------------------- 1 | #include "tl_iostream.h" 2 | #include "tl_process.h" 3 | 4 | 5 | int main( void ) 6 | { 7 | tl_iostream* stdio = tl_process_get_stdio( NULL ); 8 | tl_string line; 9 | 10 | tl_iostream_printf( stdio, "Hello World!\nEnter some text: " ); 11 | 12 | tl_iostream_read_line( stdio, &line, TL_LINE_READ_UTF8 ); 13 | 14 | tl_iostream_printf( stdio, "The line you entered: %s\n", 15 | tl_string_cstr(&line) ); 16 | 17 | tl_string_cleanup( &line ); 18 | return 0; 19 | } 20 | 21 | -------------------------------------------------------------------------------- /tests/childproc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #ifdef _WIN32 5 | #include 6 | #else 7 | #include 8 | #endif 9 | 10 | #include "tl_process.h" 11 | 12 | #ifndef _WIN32 13 | static volatile int run = 1; 14 | 15 | static void handle_sigterm( int sig ) 16 | { 17 | if( sig==SIGTERM ) 18 | run = 0; 19 | } 20 | #endif 21 | 22 | int main( int argc, char** argv ) 23 | { 24 | #ifdef _WIN32 25 | MSG msg; 26 | #endif 27 | char buffer[ 128 ]; 28 | int i; 29 | 30 | for( i=1; i 5 | #include 6 | #include 7 | 8 | const char* strings[] = { 9 | "", "", 10 | "A", "QQ==", 11 | "AA", "QUE=", 12 | "AAA", "QUFB", 13 | "AAAA", "QUFBQQ==", 14 | "AAAAA", "QUFBQUE=", 15 | "AAAAAA", "QUFBQUFB", 16 | "Foobar Test", "Rm9vYmFyIFRlc3Q=", 17 | "Foobartest", "Rm9vYmFydGVzdA==", 18 | "Foobar", "Rm9vYmFy", 19 | }; 20 | 21 | int main( void ) 22 | { 23 | unsigned int i; 24 | tl_blob b1; 25 | 26 | for (i = 0; i < sizeof(strings) / sizeof(strings[0]); i += 2) { 27 | if (tl_transform_chunk(&b1, strings[i], strlen(strings[i]), 28 | TL_BASE64_ENCODE, 0)) { 29 | return EXIT_FAILURE; 30 | } 31 | 32 | if (b1.size != strlen(strings[i + 1])) 33 | return EXIT_FAILURE; 34 | 35 | if (strncmp(b1.data, strings[i + 1], strlen(strings[i + 1]))) 36 | return EXIT_FAILURE; 37 | 38 | tl_blob_cleanup(&b1); 39 | 40 | if (tl_transform_chunk(&b1, strings[i + 1], 41 | strlen(strings[i + 1]), 42 | TL_BASE64_DECODE, 0)) { 43 | return EXIT_FAILURE; 44 | } 45 | 46 | if (b1.size != strlen(strings[i])) 47 | return EXIT_FAILURE; 48 | 49 | if (strncmp(b1.data, strings[i], strlen(strings[i]))) 50 | return EXIT_FAILURE; 51 | 52 | tl_blob_cleanup(&b1); 53 | } 54 | 55 | return EXIT_SUCCESS; 56 | } 57 | -------------------------------------------------------------------------------- /tests/test_fs.c: -------------------------------------------------------------------------------- 1 | #include "tl_iterator.h" 2 | #include "tl_string.h" 3 | #include "tl_array.h" 4 | #include "tl_dir.h" 5 | #include "tl_fs.h" 6 | 7 | #include 8 | #include 9 | 10 | 11 | 12 | int main( void ) 13 | { 14 | tl_iterator* dir; 15 | tl_array strlist; 16 | tl_string str; 17 | tl_u64 size; 18 | size_t i; 19 | FILE* f; 20 | 21 | /* print system & setup dependend values */ 22 | printf( "OS dir seperator: '%s'\n", tl_fs_get_dir_sep( ) ); 23 | 24 | tl_fs_get_user_dir( &str ); 25 | printf( "User home directory: '%s'\n", tl_string_cstr( &str ) ); 26 | tl_string_cleanup( &str ); 27 | 28 | tl_fs_get_wd( &str ); 29 | printf( "Current working directory: '%s'\n", tl_string_cstr( &str ) ); 30 | tl_string_cleanup( &str ); 31 | 32 | /* print contents of working directory */ 33 | puts( "********************************" ); 34 | 35 | tl_array_init( &strlist, sizeof(tl_string), tl_string_get_allocator( ) ); 36 | tl_dir_scan( ".", &strlist ); 37 | tl_array_stable_sort( &strlist, (tl_compare)tl_string_compare ); 38 | 39 | for( i=0; ihas_data(dir); dir->next(dir) ) 49 | puts( tl_string_cstr( dir->get_value( dir ) ) ); 50 | 51 | dir->destroy( dir ); 52 | 53 | /* test filesystem functions */ 54 | if( tl_fs_exists( "FOO" )==0 ) return EXIT_FAILURE; 55 | if( tl_fs_is_directory( "FOO" )==0 ) return EXIT_FAILURE; 56 | if( tl_fs_mkdir( "FOO" )!=0 ) return EXIT_FAILURE; 57 | if( tl_fs_exists( "FOO" )!=0 ) return EXIT_FAILURE; 58 | if( tl_fs_is_directory( "FOO" )!=0 ) return EXIT_FAILURE; 59 | if( tl_fs_exists( "FOO/bar" )==0 ) return EXIT_FAILURE; 60 | if( tl_fs_is_directory( "FOO/bar" )==0 ) return EXIT_FAILURE; 61 | 62 | if( tl_fs_cwd( "FOO" )!=0 ) return EXIT_FAILURE; 63 | if( tl_fs_exists( "FOO" )==0 ) return EXIT_FAILURE; 64 | if( tl_fs_is_directory( "FOO" )==0 ) return EXIT_FAILURE; 65 | if( tl_fs_get_file_size( "bar", &size )==0 ) return EXIT_FAILURE; 66 | f = fopen( "bar", "wb" ); 67 | if( tl_fs_get_file_size( "bar", &size )!=0 ) return EXIT_FAILURE; 68 | if( size != 0 ) return EXIT_FAILURE; 69 | fwrite( "Hello World", 1, 11, f ); 70 | fclose( f ); 71 | if( tl_fs_get_file_size( "bar", &size )!=0 ) return EXIT_FAILURE; 72 | if( size != 11 ) return EXIT_FAILURE; 73 | if( tl_fs_cwd( ".." )!=0 ) return EXIT_FAILURE; 74 | if( tl_fs_exists( "FOO" )!=0 ) return EXIT_FAILURE; 75 | if( tl_fs_is_directory( "FOO" )!=0 ) return EXIT_FAILURE; 76 | if( tl_fs_exists( "FOO/bar" )!=0 ) return EXIT_FAILURE; 77 | if( tl_fs_is_directory( "FOO/bar" )==0 ) return EXIT_FAILURE; 78 | 79 | if( tl_fs_delete( "FOO" )!=TL_ERR_NOT_EMPTY ) 80 | return EXIT_FAILURE; 81 | 82 | if( tl_fs_delete( "FOO/bar" )!=0 ) return EXIT_FAILURE; 83 | if( tl_fs_exists( "FOO/bar" )==0 ) return EXIT_FAILURE; 84 | if( tl_fs_is_directory( "FOO/bar" )==0 ) return EXIT_FAILURE; 85 | if( tl_fs_delete( "FOO" )!=0 ) return EXIT_FAILURE; 86 | if( tl_fs_exists( "FOO" )==0 ) return EXIT_FAILURE; 87 | if( tl_fs_is_directory( "FOO" )==0 ) return EXIT_FAILURE; 88 | 89 | #if 0 90 | int tl_fs_is_symlink( const char* path ); 91 | #endif 92 | 93 | return EXIT_SUCCESS; 94 | } 95 | 96 | 97 | -------------------------------------------------------------------------------- /tests/test_hash.c: -------------------------------------------------------------------------------- 1 | #include "tl_hash.h" 2 | #include 3 | 4 | int main( void ) 5 | { 6 | tl_u32 v; 7 | 8 | /* CRC-32 */ 9 | v = tl_hash_crc32( 0, "", 0 ); 10 | 11 | if( v!=0 ) 12 | return EXIT_FAILURE; 13 | 14 | v = tl_hash_crc32( 0, "Hello, World!", 13 ); 15 | 16 | if( v!=0xEC4AC3D0 ) 17 | return EXIT_FAILURE; 18 | 19 | v = tl_hash_crc32( 0, "The quick brown fox jumps over the lazy dog", 43 ); 20 | 21 | if( v!=0x414FA339 ) 22 | return EXIT_FAILURE; 23 | 24 | v = tl_hash_crc32( 0, "Test vector from febooti.com", 28 ); 25 | 26 | if( v!=0x0C877F61 ) 27 | return EXIT_FAILURE; 28 | 29 | return EXIT_SUCCESS; 30 | } 31 | 32 | -------------------------------------------------------------------------------- /tests/test_namelookup.c: -------------------------------------------------------------------------------- 1 | #include "tl_network.h" 2 | 3 | #include 4 | #include 5 | 6 | 7 | 8 | int main( void ) 9 | { 10 | tl_net_addr addr; 11 | 12 | /* resolve IPv4 addresses */ 13 | if( !tl_network_resolve_name( "127.0.0.1", TL_ANY, &addr, 1 ) ) 14 | return EXIT_FAILURE; 15 | if( addr.net!=TL_IPV4 ) 16 | return EXIT_FAILURE; 17 | if( addr.addr.ipv4!=0x7F000001 ) 18 | return EXIT_FAILURE; 19 | 20 | if( !tl_network_resolve_name( "192.168.1.1", TL_ANY, &addr, 1 ) ) 21 | return EXIT_FAILURE; 22 | if( addr.net!=TL_IPV4 ) 23 | return EXIT_FAILURE; 24 | if( addr.addr.ipv4!=0xC0A80101 ) 25 | return EXIT_FAILURE; 26 | 27 | /* resolve IPv6 addresses */ 28 | if( !tl_network_resolve_name( "::1", TL_ANY, &addr, 1 ) ) 29 | return EXIT_FAILURE; 30 | if( addr.net!=TL_IPV6 ) 31 | return EXIT_FAILURE; 32 | if( addr.addr.ipv6[7]!=0x0000 ) return EXIT_FAILURE; 33 | if( addr.addr.ipv6[6]!=0x0000 ) return EXIT_FAILURE; 34 | if( addr.addr.ipv6[5]!=0x0000 ) return EXIT_FAILURE; 35 | if( addr.addr.ipv6[4]!=0x0000 ) return EXIT_FAILURE; 36 | if( addr.addr.ipv6[3]!=0x0000 ) return EXIT_FAILURE; 37 | if( addr.addr.ipv6[2]!=0x0000 ) return EXIT_FAILURE; 38 | if( addr.addr.ipv6[1]!=0x0000 ) return EXIT_FAILURE; 39 | if( addr.addr.ipv6[0]!=0x0001 ) return EXIT_FAILURE; 40 | 41 | if( !tl_network_resolve_name("FE80::0202:B3FF:FE1E:8329",TL_ANY,&addr,1) ) 42 | return EXIT_FAILURE; 43 | if( addr.net!=TL_IPV6 ) 44 | return EXIT_FAILURE; 45 | if( addr.addr.ipv6[7]!=0xFE80 ) return EXIT_FAILURE; 46 | if( addr.addr.ipv6[6]!=0x0000 ) return EXIT_FAILURE; 47 | if( addr.addr.ipv6[5]!=0x0000 ) return EXIT_FAILURE; 48 | if( addr.addr.ipv6[4]!=0x0000 ) return EXIT_FAILURE; 49 | if( addr.addr.ipv6[3]!=0x0202 ) return EXIT_FAILURE; 50 | if( addr.addr.ipv6[2]!=0xB3FF ) return EXIT_FAILURE; 51 | if( addr.addr.ipv6[1]!=0xFE1E ) return EXIT_FAILURE; 52 | if( addr.addr.ipv6[0]!=0x8329 ) return EXIT_FAILURE; 53 | 54 | 55 | if( !tl_network_resolve_name("::ffff:192.0.2.128",TL_ANY,&addr,1) ) 56 | return EXIT_FAILURE; 57 | if( addr.net!=TL_IPV6 ) 58 | return EXIT_FAILURE; 59 | if( addr.addr.ipv6[7]!=0x0000 ) return EXIT_FAILURE; 60 | if( addr.addr.ipv6[6]!=0x0000 ) return EXIT_FAILURE; 61 | if( addr.addr.ipv6[5]!=0x0000 ) return EXIT_FAILURE; 62 | if( addr.addr.ipv6[4]!=0x0000 ) return EXIT_FAILURE; 63 | if( addr.addr.ipv6[3]!=0x0000 ) return EXIT_FAILURE; 64 | if( addr.addr.ipv6[2]!=0xFFFF ) return EXIT_FAILURE; 65 | if( addr.addr.ipv6[1]!=0xC000 ) return EXIT_FAILURE; 66 | if( addr.addr.ipv6[0]!=0x0280 ) return EXIT_FAILURE; 67 | 68 | /* resolve hostname */ 69 | if( !tl_network_resolve_name( "localhost", TL_IPV4, &addr,1 ) ) 70 | return EXIT_FAILURE; 71 | if( addr.net!=TL_IPV4 ) 72 | return EXIT_FAILURE; 73 | 74 | if( !tl_network_resolve_name( "localhost", TL_IPV6, &addr, 1 ) ) 75 | return EXIT_FAILURE; 76 | if( addr.net!=TL_IPV6 ) 77 | return EXIT_FAILURE; 78 | 79 | /* resolve DNS name */ 80 | if( !tl_network_resolve_name( "www.example.com", TL_IPV4, &addr, 1 ) ) 81 | return EXIT_FAILURE; 82 | if( addr.net!=TL_IPV4 ) 83 | return EXIT_FAILURE; 84 | 85 | if( !tl_network_resolve_name( "www.example.com", TL_IPV6, &addr,1 ) ) 86 | return EXIT_FAILURE; 87 | if( addr.net!=TL_IPV6 ) 88 | return EXIT_FAILURE; 89 | 90 | return EXIT_SUCCESS; 91 | } 92 | 93 | -------------------------------------------------------------------------------- /tests/test_packetserver.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "tl_packetserver.h" 6 | #include "tl_network.h" 7 | 8 | 9 | 10 | static int addrcmp( const tl_net_addr* a, const tl_net_addr* b ) 11 | { 12 | if( a->net!=b->net || a->transport!=b->transport || a->port!=b->port ) 13 | return 0; 14 | if( a->net==TL_IPV4 && a->addr.ipv4!=b->addr.ipv4 ) 15 | return 0; 16 | if( a->net==TL_IPV6 && 17 | memcmp(a->addr.ipv6,b->addr.ipv6,sizeof(a->addr.ipv6))!=0 ) 18 | { 19 | return 0; 20 | } 21 | return 1; 22 | } 23 | 24 | static int test_send( tl_packetserver* src, tl_packetserver* dst, 25 | tl_net_addr* srcaddr, tl_net_addr* dstaddr, 26 | const char* msg ) 27 | { 28 | size_t val, len = msg ? strlen(msg) : 0; 29 | tl_net_addr temp; 30 | char buffer[32]; 31 | 32 | if( src->send( src, msg, dstaddr, len, &val )!=0 || val!=len ) 33 | return 0; 34 | if( dst->receive( dst, buffer, &temp, sizeof(buffer), &val )!=0 ) 35 | return 0; 36 | if( val!=len ) 37 | return 0; 38 | if( msg && strncmp( buffer, msg, len )!=0 ) 39 | return 0; 40 | if( !addrcmp( &temp, srcaddr ) ) 41 | return 0; 42 | return 1; 43 | } 44 | 45 | static int run_test( int net, int transport, int aport, int bport ) 46 | { 47 | tl_net_addr a_addr, b_addr; 48 | tl_packetserver *a, *b; 49 | char buffer[ 32 ]; 50 | int i; 51 | 52 | /* address where B can reach A */ 53 | if( !tl_network_get_special_address( &a_addr, TL_LOOPBACK, net ) ) 54 | return 0; 55 | a_addr.transport = transport; 56 | a_addr.port = aport; 57 | 58 | /* address where A can reach B */ 59 | if( !tl_network_get_special_address( &b_addr, TL_LOOPBACK, net ) ) 60 | return 0; 61 | b_addr.transport = transport; 62 | b_addr.port = bport; 63 | 64 | /* create servers */ 65 | a = tl_network_create_packet_server( &a_addr, NULL, TL_DONT_FRAGMENT ); 66 | if( !a ) 67 | return 0; 68 | 69 | b = tl_network_create_packet_server( &b_addr, NULL, TL_DONT_FRAGMENT ); 70 | if( !b ) 71 | return 0; 72 | 73 | a->set_timeout( a, 1500 ); 74 | b->set_timeout( b, 1500 ); 75 | 76 | /* test transmissions */ 77 | for( i=0; i<20; ++i ) 78 | { 79 | sprintf( buffer, "Hello B %c", 'A'+i ); 80 | 81 | if( !test_send( a, b, &a_addr, &b_addr, buffer ) ) 82 | return 0; 83 | 84 | sprintf( buffer, "Hello B %c", 'a'+i ); 85 | 86 | if( !test_send( b, a, &b_addr, &a_addr, buffer ) ) 87 | return 0; 88 | 89 | if( !test_send( a, b, &a_addr, &b_addr, NULL ) ) 90 | return 0; 91 | 92 | if( !test_send( b, a, &b_addr, &a_addr, NULL ) ) 93 | return 0; 94 | } 95 | 96 | /* cleanup */ 97 | a->destroy( a ); 98 | b->destroy( b ); 99 | return 1; 100 | } 101 | 102 | 103 | 104 | int main( void ) 105 | { 106 | if( !run_test( TL_IPV4, TL_UDP, 15000, 15010 ) ) return EXIT_FAILURE; 107 | if( !run_test( TL_IPV4, TL_UDP, 15010, 15000 ) ) return EXIT_FAILURE; 108 | if( !run_test( TL_IPV6, TL_UDP, 15000, 15010 ) ) return EXIT_FAILURE; 109 | if( !run_test( TL_IPV6, TL_UDP, 15010, 15000 ) ) return EXIT_FAILURE; 110 | return EXIT_SUCCESS; 111 | } 112 | 113 | -------------------------------------------------------------------------------- /tests/test_process.c: -------------------------------------------------------------------------------- 1 | #include "tl_iostream.h" 2 | #include "tl_process.h" 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | const char* args[] = 9 | { 10 | "dummy", 11 | "argA", 12 | "argB", 13 | "argC", 14 | NULL 15 | }; 16 | 17 | 18 | static int receive_message( tl_iostream* stream, const char* message ) 19 | { 20 | size_t value, len = strlen(message); 21 | char buffer[ 64 ]; 22 | 23 | if( stream->read( stream, buffer, len, &value )!=0 || value!=len ) 24 | return 0; 25 | if( strncmp( buffer, message, len )!=0 ) 26 | return 0; 27 | #ifdef _WIN32 28 | if( stream->read( stream, buffer, 2, &value )!=0 || value!=2 ) 29 | return 0; 30 | return (buffer[0]=='\r' && buffer[1]=='\n'); 31 | #else 32 | if( stream->read( stream, buffer, 1, &value )!=0 || value!=1 ) 33 | return 0; 34 | return buffer[0]=='\n'; 35 | #endif 36 | } 37 | 38 | 39 | static int test_process( const char* path, int flags ) 40 | { 41 | tl_process* proc = tl_process_create( path, args, NULL, flags ); 42 | tl_iostream* err = tl_process_get_stderr( proc ); 43 | tl_iostream* io = tl_process_get_stdio( proc ); 44 | size_t value; 45 | int i; 46 | 47 | if( !proc || !io ) return 0; 48 | if( (flags & TL_STDERR_TO_STDOUT) && err!=NULL ) return 0; 49 | if( !(flags & TL_STDERR_TO_STDOUT) && err==NULL ) return 0; 50 | 51 | io->set_timeout( io, 5000 ); 52 | if( err ) 53 | err->set_timeout( err, 5000 ); 54 | 55 | io->write( io, "Hello, World!\n", 14, &value ); 56 | if( value!=14 ) 57 | return 0; 58 | 59 | for( i=1; args[i]; ++i ) 60 | { 61 | if( !receive_message( io, args[i] ) ) 62 | return 0; 63 | } 64 | 65 | if( !receive_message( io, "STDOUT: Hello, World!" ) ) 66 | return 0; 67 | if( !receive_message( err ? err : io, "STDERR: Hello, World!" ) ) 68 | return 0; 69 | 70 | tl_process_terminate( proc ); 71 | tl_process_wait( proc, &i, 0 ); 72 | tl_process_destroy( proc ); 73 | return i==100; 74 | } 75 | 76 | int main( int argc, char** argv ) 77 | { 78 | int flags = TL_PIPE_STDIN|TL_PIPE_STDOUT|TL_PIPE_STDERR; 79 | 80 | if( argc<2 ) 81 | return EXIT_FAILURE; 82 | if( !test_process( argv[1], flags ) ) 83 | return EXIT_FAILURE; 84 | if( !test_process( argv[1], flags|TL_STDERR_TO_STDOUT ) ) 85 | return EXIT_FAILURE; 86 | return EXIT_SUCCESS; 87 | } 88 | 89 | -------------------------------------------------------------------------------- /tests/test_process_wrap.sh.in: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | exec @abs_top_builddir@/test_process @abs_top_builddir@/childproc 4 | -------------------------------------------------------------------------------- /tests/test_rwlock.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "tl_thread.h" 5 | #include "tl_process.h" 6 | 7 | static tl_rwlock* rwlock; 8 | static tl_mutex* countmutex; 9 | static int readers = 0; 10 | static int writers = 0; 11 | 12 | void* read_thread( void* arg ) 13 | { 14 | if( !tl_rwlock_lock_read( rwlock, 0 ) ) 15 | exit( EXIT_FAILURE ); 16 | 17 | if( writers!=0 ) 18 | exit( EXIT_FAILURE ); 19 | 20 | tl_mutex_lock( countmutex, 0 ); 21 | ++readers; 22 | tl_mutex_unlock( countmutex ); 23 | tl_sleep( 300 ); 24 | tl_mutex_lock( countmutex, 0 ); 25 | --readers; 26 | tl_mutex_unlock( countmutex ); 27 | 28 | tl_rwlock_unlock_read( rwlock ); 29 | return arg; 30 | } 31 | 32 | void* write_thread( void* arg ) 33 | { 34 | if( !tl_rwlock_lock_write( rwlock, 0 ) ) 35 | exit( EXIT_FAILURE ); 36 | 37 | if( writers!=0 || readers!=0 ) 38 | exit( EXIT_FAILURE ); 39 | 40 | ++writers; 41 | tl_sleep( 100 ); 42 | --writers; 43 | 44 | tl_rwlock_unlock_write( rwlock ); 45 | return arg; 46 | } 47 | 48 | int main( void ) 49 | { 50 | tl_thread *t0, *t1, *t2, *t3; 51 | 52 | rwlock = tl_rwlock_create( ); 53 | 54 | countmutex = tl_mutex_create( 1 ); 55 | 56 | tl_rwlock_lock_read( rwlock, 0 ); 57 | tl_rwlock_lock_read( rwlock, 0 ); 58 | 59 | t0 = tl_thread_create( read_thread, NULL ); 60 | t1 = tl_thread_create( read_thread, NULL ); 61 | tl_rwlock_unlock_read( rwlock ); 62 | 63 | t2 = tl_thread_create( write_thread, NULL ); 64 | t3 = tl_thread_create( write_thread, NULL ); 65 | tl_sleep( 300 ); 66 | tl_rwlock_unlock_read( rwlock ); 67 | 68 | tl_thread_join( t0, 0 ); 69 | tl_thread_join( t1, 0 ); 70 | tl_thread_join( t2, 0 ); 71 | tl_thread_join( t3, 0 ); 72 | 73 | tl_rwlock_destroy( rwlock ); 74 | tl_thread_destroy( t0 ); 75 | tl_thread_destroy( t1 ); 76 | tl_thread_destroy( t2 ); 77 | tl_thread_destroy( t3 ); 78 | tl_mutex_destroy( countmutex ); 79 | return EXIT_SUCCESS; 80 | } 81 | 82 | -------------------------------------------------------------------------------- /tests/test_thread.c: -------------------------------------------------------------------------------- 1 | #include "tl_process.h" 2 | #include "tl_thread.h" 3 | #include 4 | #include 5 | 6 | 7 | 8 | static volatile int value = 0; 9 | static tl_mutex* mutex; 10 | static tl_monitor* mon; 11 | 12 | 13 | 14 | static void* mutex_thread( void* arg ) 15 | { 16 | tl_sleep( 100 ); 17 | 18 | if( !tl_mutex_lock( mutex, 1000 ) ) 19 | exit( EXIT_FAILURE ); 20 | if( !tl_mutex_lock( mutex, 1000 ) ) 21 | exit( EXIT_FAILURE ); 22 | 23 | value += 5; 24 | 25 | tl_mutex_unlock( mutex ); 26 | tl_mutex_unlock( mutex ); 27 | return arg; 28 | } 29 | 30 | static void* mon_thread( void* arg ) 31 | { 32 | if( !tl_monitor_lock( mon, 5000 ) ) 33 | exit( EXIT_FAILURE ); 34 | if( !tl_monitor_wait( mon, 5000 ) ) 35 | exit( EXIT_FAILURE ); 36 | 37 | value += 5; 38 | tl_monitor_unlock( mon ); 39 | return arg; 40 | } 41 | 42 | 43 | int main( void ) 44 | { 45 | void *a = (void*)0xDEADBEEF, *b = (void*)0xCAFEBABE; 46 | tl_thread *t0, *t1; 47 | 48 | /* mutex & thread */ 49 | mutex = tl_mutex_create( 1 ); 50 | 51 | t0 = tl_thread_create( mutex_thread, a ); 52 | t1 = tl_thread_create( mutex_thread, b ); 53 | 54 | if( !tl_thread_join( t0, 5000 ) ) return EXIT_FAILURE; 55 | if( !tl_thread_join( t1, 5000 ) ) return EXIT_FAILURE; 56 | 57 | if( tl_thread_get_return_value( t0 ) != a ) return EXIT_FAILURE; 58 | if( tl_thread_get_return_value( t1 ) != b ) return EXIT_FAILURE; 59 | if( value!=10 ) return EXIT_FAILURE; 60 | 61 | tl_thread_destroy( t0 ); 62 | tl_thread_destroy( t1 ); 63 | tl_mutex_destroy( mutex ); 64 | 65 | /* monitor & thread */ 66 | mon = tl_monitor_create( ); 67 | 68 | value = 0; 69 | t0 = tl_thread_create( mon_thread, a ); 70 | t1 = tl_thread_create( mon_thread, b ); 71 | 72 | tl_sleep( 100 ); 73 | tl_monitor_lock( mon, 5000 ); 74 | tl_monitor_notify_all( mon ); 75 | tl_monitor_unlock( mon ); 76 | 77 | if( !tl_thread_join( t0, 5000 ) ) return EXIT_FAILURE; 78 | if( !tl_thread_join( t1, 5000 ) ) return EXIT_FAILURE; 79 | 80 | if( tl_thread_get_return_value( t0 ) != a ) return EXIT_FAILURE; 81 | if( tl_thread_get_return_value( t1 ) != b ) return EXIT_FAILURE; 82 | if( value!=10 ) return EXIT_FAILURE; 83 | 84 | tl_monitor_destroy( mon ); 85 | tl_thread_destroy( t0 ); 86 | tl_thread_destroy( t1 ); 87 | 88 | /* monitor & thread */ 89 | mon = tl_monitor_create( ); 90 | 91 | value = 0; 92 | t0 = tl_thread_create( mon_thread, a ); 93 | t1 = tl_thread_create( mon_thread, b ); 94 | 95 | tl_sleep( 100 ); 96 | tl_monitor_lock( mon, 5000 ); 97 | tl_monitor_notify( mon ); 98 | tl_monitor_notify( mon ); 99 | tl_monitor_unlock( mon ); 100 | 101 | if( !tl_thread_join( t0, 5000 ) ) return EXIT_FAILURE; 102 | if( !tl_thread_join( t1, 5000 ) ) return EXIT_FAILURE; 103 | 104 | if( tl_thread_get_return_value( t0 ) != a ) return EXIT_FAILURE; 105 | if( tl_thread_get_return_value( t1 ) != b ) return EXIT_FAILURE; 106 | if( value!=10 ) return EXIT_FAILURE; 107 | 108 | tl_monitor_destroy( mon ); 109 | tl_thread_destroy( t0 ); 110 | tl_thread_destroy( t1 ); 111 | return EXIT_SUCCESS; 112 | } 113 | 114 | -------------------------------------------------------------------------------- /tests/test_threadpool.c: -------------------------------------------------------------------------------- 1 | #include "tl_threadpool.h" 2 | #include "tl_process.h" 3 | #include 4 | 5 | 6 | 7 | static void test_task( void* number ) 8 | { 9 | *((int*)number) = 42; 10 | tl_sleep( 5 ); 11 | } 12 | 13 | static void test_task2( void* pointer ) 14 | { 15 | int* iptr = *((int**)pointer); 16 | 17 | *iptr = 1337; 18 | tl_sleep( 5 ); 19 | } 20 | 21 | 22 | 23 | int main( void ) 24 | { 25 | tl_threadpool* pool; 26 | int data[ 512 ]; 27 | unsigned int i; 28 | int* iptr; 29 | 30 | /* simple data type */ 31 | pool = tl_threadpool_create( 4, NULL, NULL, NULL, NULL ); 32 | 33 | for( i=0; i<512; ++i ) 34 | tl_threadpool_add_task( pool, test_task, data+i, 0, NULL ); 35 | 36 | if( !tl_threadpool_wait( pool, 1000 ) ) 37 | return EXIT_FAILURE; 38 | 39 | for( i=0; i<512; ++i ) 40 | { 41 | if( data[i]!=42 ) 42 | return EXIT_FAILURE; 43 | } 44 | 45 | tl_threadpool_destroy( pool ); 46 | 47 | /* copy data */ 48 | pool = tl_threadpool_create( 4, NULL, NULL, NULL, NULL ); 49 | 50 | for( i=0; i<512; ++i ) 51 | { 52 | iptr = data + i; 53 | 54 | tl_threadpool_add_task( pool, test_task2, &iptr, sizeof(int*), NULL ); 55 | } 56 | 57 | if( !tl_threadpool_wait( pool, 1000 ) ) 58 | return EXIT_FAILURE; 59 | 60 | for( i=0; i<512; ++i ) 61 | { 62 | if( data[i]!=1337 ) 63 | return EXIT_FAILURE; 64 | } 65 | 66 | tl_threadpool_destroy( pool ); 67 | 68 | return EXIT_SUCCESS; 69 | } 70 | 71 | -------------------------------------------------------------------------------- /tests/test_udp.c: -------------------------------------------------------------------------------- 1 | #include "tl_packetserver.h" 2 | #include "tl_iostream.h" 3 | #include "tl_network.h" 4 | 5 | #include 6 | #include 7 | 8 | int main( void ) 9 | { 10 | tl_packetserver* pserver; 11 | char buffer[ 16 ]; 12 | tl_net_addr addr; 13 | tl_iostream* str; 14 | size_t val; 15 | 16 | /* create server */ 17 | if( !tl_network_get_special_address( &addr, TL_ALL, TL_IPV4 ) ) 18 | return EXIT_FAILURE; 19 | 20 | addr.transport = TL_UDP; 21 | addr.port = 15000; 22 | 23 | pserver = tl_network_create_packet_server( &addr, NULL, 0 ); 24 | if( !pserver ) 25 | return EXIT_FAILURE; 26 | 27 | pserver->set_timeout( pserver, 1500 ); 28 | 29 | /* create client */ 30 | if( !tl_network_resolve_name( "127.0.0.1", TL_IPV4, &addr, 1 ) ) 31 | return EXIT_FAILURE; 32 | 33 | addr.transport = TL_UDP; 34 | addr.port = 15000; 35 | 36 | str = tl_network_create_client( &addr, NULL, 0 ); 37 | if( !str ) 38 | return EXIT_FAILURE; 39 | 40 | str->set_timeout( str, 1500 ); 41 | 42 | /* send packet to server */ 43 | if( str->write( str, "Hello", 5, &val )!=0 || val!=5 ) 44 | return EXIT_FAILURE; 45 | if( pserver->receive( pserver, buffer, &addr, 5, &val )!=0 || val!=5 ) 46 | return EXIT_FAILURE; 47 | if( strncmp( buffer, "Hello", 5 )!=0 ) 48 | return EXIT_FAILURE; 49 | 50 | /* send response to client */ 51 | if( pserver->send( pserver, "World", &addr, 5, &val )!=0 || val!=5 ) 52 | return EXIT_FAILURE; 53 | if( str->read( str, buffer, 5, &val )!=0 || val!=5 ) 54 | return EXIT_FAILURE; 55 | if( strncmp( buffer, "World", 5 )!=0 ) 56 | return EXIT_FAILURE; 57 | 58 | /* cleanup */ 59 | str->destroy( str ); 60 | pserver->destroy( pserver ); 61 | return EXIT_SUCCESS; 62 | } 63 | 64 | -------------------------------------------------------------------------------- /tests/test_udpbroadcast.c: -------------------------------------------------------------------------------- 1 | #include "tl_packetserver.h" 2 | #include "tl_network.h" 3 | 4 | #include 5 | #include 6 | 7 | 8 | 9 | int main( void ) 10 | { 11 | tl_packetserver* pserver1; 12 | tl_packetserver* pserver2; 13 | char buffer[ 16 ]; 14 | tl_net_addr addr; 15 | size_t val; 16 | 17 | /* create servers */ 18 | if( !tl_network_get_special_address( &addr, TL_ALL, TL_IPV4 ) ) 19 | return EXIT_FAILURE; 20 | 21 | addr.transport = TL_UDP; 22 | addr.port = 15000; 23 | 24 | pserver1 = tl_network_create_packet_server(&addr,NULL,TL_ALLOW_BROADCAST); 25 | if( !pserver1 ) 26 | return EXIT_FAILURE; 27 | 28 | addr.port = 16000; 29 | 30 | pserver2 = tl_network_create_packet_server( &addr, NULL, 0 ); 31 | if( !pserver2 ) 32 | return EXIT_FAILURE; 33 | 34 | pserver1->set_timeout( pserver1, 1500 ); 35 | pserver2->set_timeout( pserver2, 1500 ); 36 | 37 | /* send broadcast from first server */ 38 | if( !tl_network_get_special_address( &addr, TL_BROADCAST, TL_IPV4 ) ) 39 | return EXIT_FAILURE; 40 | 41 | addr.transport = TL_UDP; 42 | addr.port = 16000; 43 | 44 | if( pserver1->send( pserver1, "Test", &addr, 4, &val )!=0 || val!=4 ) 45 | return EXIT_FAILURE; 46 | 47 | /* receive broadcast and send response */ 48 | if( pserver2->receive(pserver2, buffer, &addr, sizeof(buffer), &val)!=0 ) 49 | return EXIT_FAILURE; 50 | if( val!=4 || strncmp( buffer, "Test", 4 )!=0 ) 51 | return EXIT_FAILURE; 52 | if( addr.transport != TL_UDP || addr.port != 15000 ) 53 | return EXIT_FAILURE; 54 | 55 | if( pserver2->send( pserver2, "Hello", &addr, 5, &val )!=0 || val!=5 ) 56 | return EXIT_FAILURE; 57 | 58 | /* receive respone */ 59 | if( pserver1->receive( pserver1, buffer, &addr, sizeof(buffer), &val )!=0 ) 60 | return EXIT_FAILURE; 61 | if( val!=5 || strncmp( buffer, "Hello", 5 )!=0 ) 62 | return EXIT_FAILURE; 63 | if( addr.transport != TL_UDP || addr.port != 16000 ) 64 | return EXIT_FAILURE; 65 | 66 | /* cleanup */ 67 | pserver1->destroy( pserver1 ); 68 | pserver2->destroy( pserver2 ); 69 | return EXIT_SUCCESS; 70 | } 71 | 72 | --------------------------------------------------------------------------------