├── .gitignore
├── .travis.yml
├── LICENSE
├── Makefile.am
├── README.md
├── configure.ac
├── m4
└── ax_pthread.m4
├── man
├── hashbase.1
├── hashbase.1.html
└── hashbase.ronn
├── screenshot-1.png
├── screenshot-2.png
├── src
├── Makefile.am
├── hb.c
├── hb_args.c
├── hb_args.h
├── hb_ascii.c
├── hb_ascii.h
├── hb_core.c
├── hb_core.h
├── hb_map.c
├── hb_map.h
├── hb_net.c
├── hb_net.h
├── hb_pipe.c
├── hb_pipe.h
├── hb_util.c
└── hb_util.h
└── tests
├── Python
├── hashbase.py
└── tests.py
└── client.py
/.gitignore:
--------------------------------------------------------------------------------
1 | autom4te.cache/*
2 |
3 | build/*
4 |
5 | src/.deps/*
6 | src/hashbase
7 | src/Makefile
8 | src/Makefile.in
9 |
10 | aclocal.m4
11 | config.log
12 | config.status
13 | configure
14 |
15 | Makefile
16 | Makefile.in
17 |
18 | *.o
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: c
2 | compiler:
3 | - gcc
4 | script: autoreconf -fvi && ./configure && make
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Maciej A. Czyzewski
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/Makefile.am:
--------------------------------------------------------------------------------
1 | SUBDIRS = src
2 | ACLOCAL_AMFLAGS = -I m4
3 | man1_MANS = man/hashbase.1
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |

3 |
4 |
5 | # hashbase [](https://travis-ci.org/MaciejCzyzewski/hashbase)
6 |
7 | Flexible hackable-storage.
8 |
9 | ## Introduction
10 |
11 | It's a fast, efficient on-disk/in-memory database with many different kind of data structures.
12 |
13 | Hashbase is written in ANSI C comes with a broad range of features including metrics, multi-client API and rich advanced data structure (KV, List, Hash, ZSet, Bit).
14 |
15 | #### More reading:
16 |
17 | - [Installation](#installation): Step-by-step instructions for getting hashbase running on your computer.
18 | - [Usage](#usage): List of commands.
19 | - [Contributing](#contributing): Explanation of how you can join the project.
20 | - [License](#license): Clarification of certain rules.
21 |
22 | ## Installation
23 |
24 | When an archive file of hashbase is extracted, change the current working directory to the generated directory and perform installation.
25 |
26 | Run the configuration script.
27 |
28 | ```bash
29 | $ autoreconf -fvi
30 | $ ./configure
31 | ```
32 |
33 | Build programs.
34 |
35 | ```bash
36 | $ make
37 | ```
38 |
39 | Perform self-diagnostic test. This takes a while.
40 |
41 | ```bash
42 | $ make check
43 | ```
44 |
45 | Install programs. This operation must be carried out by the root user.
46 |
47 | ```bash
48 | $ make install
49 | ```
50 |
51 | ## Usage
52 |
53 |
54 |

55 |
56 |
57 | This script is the primary interface for starting and stopping the hashbase server.
58 |
59 | ### Start
60 |
61 | To start a daemonized (background) instance of hashbase.
62 |
63 | ```bash
64 | $ hashbase -d
65 | ```
66 |
67 | ### Console
68 |
69 | Alternatively, if you want to run a foreground instance of hashbase.
70 |
71 | ```bash
72 | $ hashbase
73 | ```
74 |
75 | ### Stop
76 |
77 | Stopping a foreground or background instance of hashbase can be done from a shell prompt.
78 |
79 | ```bash
80 | $ hashbase -s
81 | ```
82 |
83 | ### Help
84 |
85 | Displays a brief summary of the basic options.
86 |
87 | ```bash
88 | $ hashbase -h
89 | ```
90 |
91 | ## Contributing
92 |
93 | Please feel free to contribute to this project! Pull requests and feature requests welcome! :v:
94 |
95 | ## License
96 |
97 | See LICENSE file in this repository.
--------------------------------------------------------------------------------
/configure.ac:
--------------------------------------------------------------------------------
1 | # Define the package version numbers and the bug reporting address
2 | m4_define([HB_MAJOR], 0)
3 | m4_define([HB_MINOR], 0)
4 | m4_define([HB_PATCH], 1)
5 | m4_define([HB_BUGS], [maciejanthonyczyzewski@gmail.com])
6 |
7 | # Include m4 macros
8 | m4_include([m4/ax_pthread.m4])
9 |
10 | # Initialize autoconf
11 | AC_PREREQ([2.64])
12 | AC_INIT([hashbase], [HB_MAJOR.HB_MINOR.HB_PATCH], [HB_BUGS])
13 | AC_CONFIG_SRCDIR([src/hb.c])
14 | AC_CONFIG_AUX_DIR([build])
15 | AC_CONFIG_MACRO_DIR([m4])
16 | AC_CANONICAL_SYSTEM
17 |
18 | # Initialize automake
19 | AM_INIT_AUTOMAKE(1.9 foreign)
20 | AM_SILENT_RULES([yes])
21 |
22 | # Define macro variables for the package version numbers
23 | AC_DEFINE(HB_VERSION_MAJOR, HB_MAJOR, [Define the major version number])
24 | AC_DEFINE(HB_VERSION_MINOR, HB_MINOR, [Define the minor version number])
25 | AC_DEFINE(HB_VERSION_PATCH, HB_PATCH, [Define the patch version number])
26 | AC_DEFINE(HB_VERSION_STRING, "HB_MAJOR.HB_MINOR.HB_PATCH", [Define the version string])
27 |
28 | # Checks for language
29 | AC_LANG([C])
30 |
31 | # Checks for programs
32 | AC_PROG_CC
33 | AC_PROG_INSTALL
34 | AC_PROG_MAKE_SET
35 | AM_PROG_CC_C_O
36 |
37 | # Define Makefiles
38 | AC_CONFIG_FILES([Makefile src/Makefile])
39 |
40 | # Pthread
41 | AX_PTHREAD([AC_DEFINE(HAVE_PTHREAD, 1, [Define if you have POSIX threads libraries and header files.])
42 | CLIBS="$PTHREAD_LIBS $LIBS"
43 | CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
44 | LDFLAGS="$LDFLAGS $PTHREAD_CFLAGS"
45 | CC="$PTHREAD_CC"], [])
46 |
47 | # Generate the "configure" script
48 | AC_OUTPUT
49 |
--------------------------------------------------------------------------------
/m4/ax_pthread.m4:
--------------------------------------------------------------------------------
1 | # ===========================================================================
2 | # http://www.gnu.org/software/autoconf-archive/ax_pthread.html
3 | # ===========================================================================
4 | #
5 | # SYNOPSIS
6 | #
7 | # AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
8 | #
9 | # DESCRIPTION
10 | #
11 | # This macro figures out how to build C programs using POSIX threads. It
12 | # sets the PTHREAD_LIBS output variable to the threads library and linker
13 | # flags, and the PTHREAD_CFLAGS output variable to any special C compiler
14 | # flags that are needed. (The user can also force certain compiler
15 | # flags/libs to be tested by setting these environment variables.)
16 | #
17 | # Also sets PTHREAD_CC to any special C compiler that is needed for
18 | # multi-threaded programs (defaults to the value of CC otherwise). (This
19 | # is necessary on AIX to use the special cc_r compiler alias.)
20 | #
21 | # NOTE: You are assumed to not only compile your program with these flags,
22 | # but also link it with them as well. e.g. you should link with
23 | # $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
24 | #
25 | # If you are only building threads programs, you may wish to use these
26 | # variables in your default LIBS, CFLAGS, and CC:
27 | #
28 | # LIBS="$PTHREAD_LIBS $LIBS"
29 | # CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
30 | # CC="$PTHREAD_CC"
31 | #
32 | # In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
33 | # has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name
34 | # (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
35 | #
36 | # Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the
37 | # PTHREAD_PRIO_INHERIT symbol is defined when compiling with
38 | # PTHREAD_CFLAGS.
39 | #
40 | # ACTION-IF-FOUND is a list of shell commands to run if a threads library
41 | # is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it
42 | # is not found. If ACTION-IF-FOUND is not specified, the default action
43 | # will define HAVE_PTHREAD.
44 | #
45 | # Please let the authors know if this macro fails on any platform, or if
46 | # you have any other suggestions or comments. This macro was based on work
47 | # by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help
48 | # from M. Frigo), as well as ac_pthread and hb_pthread macros posted by
49 | # Alejandro Forero Cuervo to the autoconf macro repository. We are also
50 | # grateful for the helpful feedback of numerous users.
51 | #
52 | # Updated for Autoconf 2.68 by Daniel Richard G.
53 | #
54 | # LICENSE
55 | #
56 | # Copyright (c) 2008 Steven G. Johnson
57 | # Copyright (c) 2011 Daniel Richard G.
58 | #
59 | # This program is free software: you can redistribute it and/or modify it
60 | # under the terms of the GNU General Public License as published by the
61 | # Free Software Foundation, either version 3 of the License, or (at your
62 | # option) any later version.
63 | #
64 | # This program is distributed in the hope that it will be useful, but
65 | # WITHOUT ANY WARRANTY; without even the implied warranty of
66 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
67 | # Public License for more details.
68 | #
69 | # You should have received a copy of the GNU General Public License along
70 | # with this program. If not, see .
71 | #
72 | # As a special exception, the respective Autoconf Macro's copyright owner
73 | # gives unlimited permission to copy, distribute and modify the configure
74 | # scripts that are the output of Autoconf when processing the Macro. You
75 | # need not follow the terms of the GNU General Public License when using
76 | # or distributing such scripts, even though portions of the text of the
77 | # Macro appear in them. The GNU General Public License (GPL) does govern
78 | # all other use of the material that constitutes the Autoconf Macro.
79 | #
80 | # This special exception to the GPL applies to versions of the Autoconf
81 | # Macro released by the Autoconf Archive. When you make and distribute a
82 | # modified version of the Autoconf Macro, you may extend this special
83 | # exception to the GPL to apply to your modified version as well.
84 |
85 | #serial 18
86 |
87 | AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
88 | AC_DEFUN([AX_PTHREAD], [
89 | AC_REQUIRE([AC_CANONICAL_HOST])
90 | AC_LANG_PUSH([C])
91 | ax_pthread_ok=no
92 |
93 | # We used to check for pthread.h first, but this fails if pthread.h
94 | # requires special compiler flags (e.g. on True64 or Sequent).
95 | # It gets checked for in the link test anyway.
96 |
97 | # First of all, check if the user has set any of the PTHREAD_LIBS,
98 | # etcetera environment variables, and if threads linking works using
99 | # them:
100 | if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
101 | save_CFLAGS="$CFLAGS"
102 | CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
103 | save_LIBS="$LIBS"
104 | LIBS="$PTHREAD_LIBS $LIBS"
105 | AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
106 | AC_TRY_LINK_FUNC(pthread_join, ax_pthread_ok=yes)
107 | AC_MSG_RESULT($ax_pthread_ok)
108 | if test x"$ax_pthread_ok" = xno; then
109 | PTHREAD_LIBS=""
110 | PTHREAD_CFLAGS=""
111 | fi
112 | LIBS="$save_LIBS"
113 | CFLAGS="$save_CFLAGS"
114 | fi
115 |
116 | # We must check for the threads library under a number of different
117 | # names; the ordering is very important because some systems
118 | # (e.g. DEC) have both -lpthread and -lpthreads, where one of the
119 | # libraries is broken (non-POSIX).
120 |
121 | # Create a list of thread flags to try. Items starting with a "-" are
122 | # C compiler flags, and other items are library names, except for "none"
123 | # which indicates that we try without any flags at all, and "pthread-config"
124 | # which is a program returning the flags for the Pth emulation library.
125 |
126 | ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
127 |
128 | # The ordering *is* (sometimes) important. Some notes on the
129 | # individual items follow:
130 |
131 | # pthreads: AIX (must check this before -lpthread)
132 | # none: in case threads are in libc; should be tried before -Kthread and
133 | # other compiler flags to prevent continual compiler warnings
134 | # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
135 | # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
136 | # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
137 | # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
138 | # -pthreads: Solaris/gcc
139 | # -mthreads: Mingw32/gcc, Lynx/gcc
140 | # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
141 | # doesn't hurt to check since this sometimes defines pthreads too;
142 | # also defines -D_REENTRANT)
143 | # ... -mt is also the pthreads flag for HP/aCC
144 | # pthread: Linux, etcetera
145 | # --thread-safe: KAI C++
146 | # pthread-config: use pthread-config program (for GNU Pth library)
147 |
148 | case ${host_os} in
149 | solaris*)
150 |
151 | # On Solaris (at least, for some versions), libc contains stubbed
152 | # (non-functional) versions of the pthreads routines, so link-based
153 | # tests will erroneously succeed. (We need to link with -pthreads/-mt/
154 | # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
155 | # a function called by this macro, so we could check for that, but
156 | # who knows whether they'll stub that too in a future libc.) So,
157 | # we'll just look for -pthreads and -lpthread first:
158 |
159 | ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags"
160 | ;;
161 |
162 | darwin*)
163 | ax_pthread_flags="-pthread $ax_pthread_flags"
164 | ;;
165 | esac
166 |
167 | if test x"$ax_pthread_ok" = xno; then
168 | for flag in $ax_pthread_flags; do
169 |
170 | case $flag in
171 | none)
172 | AC_MSG_CHECKING([whether pthreads work without any flags])
173 | ;;
174 |
175 | -*)
176 | AC_MSG_CHECKING([whether pthreads work with $flag])
177 | PTHREAD_CFLAGS="$flag"
178 | ;;
179 |
180 | pthread-config)
181 | AC_CHECK_PROG(ax_pthread_config, pthread-config, yes, no)
182 | if test x"$ax_pthread_config" = xno; then continue; fi
183 | PTHREAD_CFLAGS="`pthread-config --cflags`"
184 | PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
185 | ;;
186 |
187 | *)
188 | AC_MSG_CHECKING([for the pthreads library -l$flag])
189 | PTHREAD_LIBS="-l$flag"
190 | ;;
191 | esac
192 |
193 | save_LIBS="$LIBS"
194 | save_CFLAGS="$CFLAGS"
195 | LIBS="$PTHREAD_LIBS $LIBS"
196 | CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
197 |
198 | # Check for various functions. We must include pthread.h,
199 | # since some functions may be macros. (On the Sequent, we
200 | # need a special flag -Kthread to make this header compile.)
201 | # We check for pthread_join because it is in -lpthread on IRIX
202 | # while pthread_create is in libc. We check for pthread_attr_init
203 | # due to DEC craziness with -lpthreads. We check for
204 | # pthread_cleanup_push because it is one of the few pthread
205 | # functions on Solaris that doesn't have a non-functional libc stub.
206 | # We try pthread_create on general principles.
207 | AC_LINK_IFELSE([AC_LANG_PROGRAM([#include
208 | static void routine(void *a) { a = 0; }
209 | static void *start_routine(void *a) { return a; }],
210 | [pthread_t th; pthread_attr_t attr;
211 | pthread_create(&th, 0, start_routine, 0);
212 | pthread_join(th, 0);
213 | pthread_attr_init(&attr);
214 | pthread_cleanup_push(routine, 0);
215 | pthread_cleanup_pop(0) /* ; */])],
216 | [ax_pthread_ok=yes],
217 | [])
218 |
219 | LIBS="$save_LIBS"
220 | CFLAGS="$save_CFLAGS"
221 |
222 | AC_MSG_RESULT($ax_pthread_ok)
223 | if test "x$ax_pthread_ok" = xyes; then
224 | break;
225 | fi
226 |
227 | PTHREAD_LIBS=""
228 | PTHREAD_CFLAGS=""
229 | done
230 | fi
231 |
232 | # Various other checks:
233 | if test "x$ax_pthread_ok" = xyes; then
234 | save_LIBS="$LIBS"
235 | LIBS="$PTHREAD_LIBS $LIBS"
236 | save_CFLAGS="$CFLAGS"
237 | CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
238 |
239 | # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
240 | AC_MSG_CHECKING([for joinable pthread attribute])
241 | attr_name=unknown
242 | for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
243 | AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ],
244 | [int attr = $attr; return attr /* ; */])],
245 | [attr_name=$attr; break],
246 | [])
247 | done
248 | AC_MSG_RESULT($attr_name)
249 | if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
250 | AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
251 | [Define to necessary symbol if this constant
252 | uses a non-standard name on your system.])
253 | fi
254 |
255 | AC_MSG_CHECKING([if more special flags are required for pthreads])
256 | flag=no
257 | case ${host_os} in
258 | aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";;
259 | osf* | hpux*) flag="-D_REENTRANT";;
260 | solaris*)
261 | if test "$GCC" = "yes"; then
262 | flag="-D_REENTRANT"
263 | else
264 | flag="-mt -D_REENTRANT"
265 | fi
266 | ;;
267 | esac
268 | AC_MSG_RESULT(${flag})
269 | if test "x$flag" != xno; then
270 | PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
271 | fi
272 |
273 | AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
274 | ax_cv_PTHREAD_PRIO_INHERIT, [
275 | AC_LINK_IFELSE([
276 | AC_LANG_PROGRAM([[#include ]], [[int i = PTHREAD_PRIO_INHERIT;]])],
277 | [ax_cv_PTHREAD_PRIO_INHERIT=yes],
278 | [ax_cv_PTHREAD_PRIO_INHERIT=no])
279 | ])
280 | AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"],
281 | AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], 1, [Have PTHREAD_PRIO_INHERIT.]))
282 |
283 | LIBS="$save_LIBS"
284 | CFLAGS="$save_CFLAGS"
285 |
286 | # More AIX lossage: must compile with xlc_r or cc_r
287 | if test x"$GCC" != xyes; then
288 | AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC})
289 | else
290 | PTHREAD_CC=$CC
291 | fi
292 | else
293 | PTHREAD_CC="$CC"
294 | fi
295 |
296 | AC_SUBST(PTHREAD_LIBS)
297 | AC_SUBST(PTHREAD_CFLAGS)
298 | AC_SUBST(PTHREAD_CC)
299 |
300 | # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
301 | if test x"$ax_pthread_ok" = xyes; then
302 | ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
303 | :
304 | else
305 | ax_pthread_ok=no
306 | $2
307 | fi
308 | AC_LANG_POP
309 | ])dnl AX_PTHREAD
--------------------------------------------------------------------------------
/man/hashbase.1:
--------------------------------------------------------------------------------
1 | .\" generated with Ronn/v0.7.3
2 | .\" http://github.com/rtomayko/ronn/tree/0.7.3
3 | .
4 | .TH "HASHBASE" "1" "July 2014" "" ""
5 | .
6 | .SH "NAME"
7 | \fBhashbase\fR \- flexible hackable\-storage
8 | .
9 | .SH "SYNOPSIS"
10 | \fBhashbase\fR
11 | .
12 | .br
13 | \fBhashbase\fR [\fIoptions\fR\.\.\.]
14 | .
15 | .br
16 | \fBhashbase\fR \fB\-d\fR|\fB\-\-daemonize\fR
17 | .
18 | .br
19 | \fBhashbase\fR \fB\-\-port\fR=\fINUMBER\fR
20 | .
21 | .br
22 | .
23 | .SH "DESCRIPTION"
24 | It\'s a fast, efficient on\-disk/in\-memory database with many different kind of data structures\.
25 | .
26 | .SH "OPTIONS"
27 | .
28 | .TP
29 | \fB\-d\fR, \fB\-\-daemonize\fR
30 | Run in the background as daemon\.
31 | .
32 | .TP
33 | \fB\-s\fR, \fB\-\-stop\fR
34 | Close running daemon\.
35 | .
36 | .TP
37 | \fB\-p\fR=\fINUMBER\fR, \fB\-\-port\fR=\fINUMBER\fR
38 | Set port for server\.
39 | .
40 | .TP
41 | \fB\-v\fR, \fB\-\-version\fR
42 | Show hashbase version and exit\.
43 | .
44 | .TP
45 | \fB\-h\fR, \fB\-\-help\fR
46 | Show help and exit\.
47 | .
48 | .SH "EXAMPLES"
49 | Serve TCP server with debug logging:
50 | .
51 | .IP "" 4
52 | .
53 | .nf
54 |
55 | $ hashbase
56 | .
57 | .fi
58 | .
59 | .IP "" 0
60 | .
61 | .P
62 | Serve TCP server at localhost:1207 as daemon:
63 | .
64 | .IP "" 4
65 | .
66 | .nf
67 |
68 | $ hashbase \-d \-p 1207
69 | .
70 | .fi
71 | .
72 | .IP "" 0
73 | .
74 | .P
75 | Close server:
76 | .
77 | .IP "" 4
78 | .
79 | .nf
80 |
81 | $ hashbase \-s
82 | .
83 | .fi
84 | .
85 | .IP "" 0
86 | .
87 | .SH "BUGS"
88 | \fBHashbase\fR is written in ANSI C and depends on autoconf and extension libraries that are non\-trivial to install on some systems\. A more portable version of this program would be welcome\.
89 | .
90 | .SH "COPYRIGHT"
91 | Hashbase is Copyright (C) 2014 Maciej A\. Czyzewski
92 | .
93 | .SH "SEE ALSO"
94 | man(1), manpages(5)
95 |
--------------------------------------------------------------------------------
/man/hashbase.1.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | hashbase(1) - flexible hackable-storage
7 |
44 |
45 |
52 |
53 |
54 |
55 |
65 |
66 |
67 | - hashbase(1)
68 |
69 | - hashbase(1)
70 |
71 |
72 |
NAME
73 |
74 | hashbase
- flexible hackable-storage
75 |
76 |
77 |
SYNOPSIS
78 |
79 |
hashbase
80 | hashbase
[options...]
81 | hashbase
-d
|--daemonize
82 | hashbase
--port
=NUMBER
83 |
84 |
DESCRIPTION
85 |
86 |
It's a fast, efficient on-disk/in-memory database with many different kind of
87 | data structures.
88 |
89 |
OPTIONS
90 |
91 |
92 | -d
, --daemonize
Run in the background as daemon.
93 | -s
, --stop
Close running daemon.
94 | -p
=NUMBER, --port
=NUMBERSet port for server.
95 | -v
, --version
Show hashbase version and exit.
96 | -h
, --help
Show help and exit.
97 |
98 |
99 |
100 |
EXAMPLES
101 |
102 |
Serve TCP server with debug logging:
103 |
104 |
$ hashbase
105 |
106 |
107 |
Serve TCP server at localhost:1207 as daemon:
108 |
109 |
$ hashbase -d -p 1207
110 |
111 |
112 |
Close server:
113 |
114 |
$ hashbase -s
115 |
116 |
117 |
BUGS
118 |
119 |
Hashbase is written in ANSI C and depends on autoconf and extension
120 | libraries that are non-trivial to install on some systems. A more portable
121 | version of this program would be welcome.
122 |
123 |
COPYRIGHT
124 |
125 |
Hashbase is Copyright (C) 2014 Maciej A. Czyzewski
126 |
127 |
SEE ALSO
128 |
129 |
man(1), manpages(5)
130 |
131 |
132 |
137 |
138 |
139 |
140 |
141 |
--------------------------------------------------------------------------------
/man/hashbase.ronn:
--------------------------------------------------------------------------------
1 | hashbase(1) -- flexible hackable-storage
2 | ========================================
3 |
4 | ## SYNOPSIS
5 |
6 | `hashbase`
7 | `hashbase` [...]
8 | `hashbase` `-d`|`--daemonize`
9 | `hashbase` `--port`=
10 |
11 | ## DESCRIPTION
12 |
13 | It's a fast, efficient on-disk/in-memory database with many different kind of
14 | data structures.
15 |
16 | ## OPTIONS
17 |
18 | * `-d`, `--daemonize`:
19 | Run in the background as daemon.
20 |
21 | * `-s`, `--stop`:
22 | Close running daemon.
23 |
24 | * `-p`=, `--port`=:
25 | Set port for server.
26 |
27 | * `-v`, `--version`:
28 | Show hashbase version and exit.
29 |
30 | * `-h`, `--help`:
31 | Show help and exit.
32 |
33 | ## EXAMPLES
34 |
35 | Serve TCP server with debug logging:
36 |
37 | $ hashbase
38 |
39 | Serve TCP server at localhost:1207 as daemon:
40 |
41 | $ hashbase -d -p 1207
42 |
43 | Close server:
44 |
45 | $ hashbase -s
46 |
47 | ## BUGS
48 |
49 | **Hashbase** is written in ANSI C and depends on autoconf and extension
50 | libraries that are non-trivial to install on some systems. A more portable
51 | version of this program would be welcome.
52 |
53 | ## COPYRIGHT
54 |
55 | Hashbase is Copyright (C) 2014 Maciej A. Czyzewski
56 |
57 | ## SEE ALSO
58 |
59 | man(1), manpages(5)
--------------------------------------------------------------------------------
/screenshot-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maciejczyzewski/hashbase/04d7c8cc40dab40ad9870949f16458afaa37a40c/screenshot-1.png
--------------------------------------------------------------------------------
/screenshot-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maciejczyzewski/hashbase/04d7c8cc40dab40ad9870949f16458afaa37a40c/screenshot-2.png
--------------------------------------------------------------------------------
/src/Makefile.am:
--------------------------------------------------------------------------------
1 | bin_PROGRAMS = hashbase
2 |
3 | AM_CPPFLAGS = -D_GNU_SOURCE
4 |
5 | AM_CFLAGS = -O2 -Wall
6 | AM_CFLAGS += -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls
7 | AM_CFLAGS += -fno-strict-aliasing
8 |
9 | LDFLAGS += -rdynamic -lpthread
10 |
11 | hashbase_SOURCES = \
12 | hb_core.c hb_core.h \
13 | hb_net.c hb_net.h \
14 | hb_map.c hb_map.h \
15 | hb_pipe.c hb_pipe.h \
16 | hb_util.c hb_util.h \
17 | hb_ascii.c hb_ascii.h \
18 | hb_args.c hb_args.h \
19 | hb.c
20 |
--------------------------------------------------------------------------------
/src/hb.c:
--------------------------------------------------------------------------------
1 | /*
2 | * hashbase - https://github.com/MaciejCzyzewski/hashbase
3 | *
4 | * The MIT License (MIT)
5 | *
6 | * Copyright (c) 2014 Maciej A. Czyzewski
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of
9 | * this software and associated documentation files (the "Software"), to deal in
10 | * the Software without restriction, including without limitation the rights to
11 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
12 | * the Software, and to permit persons to whom the Software is furnished to do so,
13 | * subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
20 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
21 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
22 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 | *
25 | * Author: Maciej A. Czyzewski
26 | */
27 |
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 | #include
36 |
37 | #include
38 |
39 | struct server server;
40 | struct client client;
41 |
42 | map_t database;
43 |
44 | /* ================================ Globals ================================ */
45 |
46 | int main(int argc , char *argv[])
47 | {
48 | signal(SIGINT, core_close);
49 |
50 | server.pid = getpid();
51 | server.lock = HB_CORE_LOCK;
52 |
53 | server.port = HB_NET_PORT;
54 | server.backlog = HB_NET_BACKLOG;
55 | server.buffer = HB_NET_BUFFER;
56 |
57 | server.daemonize = false;
58 |
59 | client.size = sizeof(struct sockaddr_in);
60 |
61 | core_init(argc, argv);
62 |
63 | char *ascii_logo =
64 | " \n"
65 | " XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX \n"
66 | " XXXXXXXXXXXXXXXXXXXXXXXXXX _ X \n"
67 | " XX|`|XXXXXXXXXXXXX|`|XXXXX | |__ __ _ ___ ___ X \n"
68 | " XX| '_ \\X/`_``/`__| '_`\\XX | '_ \\ / _` / __|/ _ \\ X\n"
69 | " XX| |X| | (X| \\__ \\ |X| XX | |_) | (_| \\__ \\ __/ X\n"
70 | " XX|_|X|_|\\__,_|___/_|X|_XX |_.__/ \\__,_|___/\\___| X \n"
71 | " XXXXXXXXXXXXXXXXXXXXXXXXXX ver %s X \n"
72 | " XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX \n"
73 | " port: %d, pid: %ld \n\n";
74 |
75 | printf(ascii_logo, HB_VERSION, server.port, server.pid);
76 |
77 | server.status = net_init();
78 | if (server.status == HB_ERR) core_close(1);
79 |
80 | server.status = map_init();
81 | if (server.status == HB_ERR) core_close(1);
82 |
83 | fprintf(stdout, "hb: %s waiting for incoming connections...\n", HB_LOG_INF);
84 |
85 | struct ascii_t commands [] = {
86 | { "inf", ascii_inf },
87 | { "set", ascii_set },
88 | { "get", ascii_get },
89 | { "del", ascii_del },
90 | { "len", ascii_len },
91 | { "clr", ascii_clr },
92 | };
93 |
94 | server.commands = commands;
95 |
96 | net_loop();
97 |
98 | return 0;
99 | }
--------------------------------------------------------------------------------
/src/hb_args.c:
--------------------------------------------------------------------------------
1 | /*
2 | * ARGS Provides functionality to parse standard argc/argv in an easy manner.
3 | *
4 | * Version: @(#)args.c 0.0.1 09/07/14
5 | * Authors: Maciej A. Czyzewski,
6 | *
7 | */
8 |
9 | #include /* for vsnprintf */
10 | #include /* for va_list */
11 | #include
12 | #if !defined(_MSC_VER)
13 | # include /* for strncasecmp */
14 | #else
15 | # include /* tolower */
16 | #endif
17 |
18 | #include
19 |
20 | static int str_case_cmp_len(const char* s1, const char* s2, unsigned int len)
21 | {
22 | #if defined (_MSC_VER)
23 | for(unsigned int i = 0; i < len; i++) {
24 | int c1 = tolower(s1[i]);
25 | int c2 = tolower(s2[i]);
26 | if(c1 < c2) return -1;
27 | if(c1 > c2) return 1;
28 | if(c1 == '\0' && c1 == c2) return 0;
29 | }
30 | return 0;
31 | #else /* defined (_MSC_VER) */
32 | return strncasecmp(s1, s2, len);
33 | #endif /* defined (_MSC_VER) */
34 | }
35 |
36 | static int str_format(char* buf, size_t buf_size, const char* fmt, ...)
37 | {
38 | va_list args;
39 | va_start( args, fmt );
40 | int ret = vsnprintf( buf, buf_size, fmt, args );
41 | #if defined(_MSC_VER)
42 | buf[buf_size - 1] = '\0';
43 | #endif
44 | va_end( args );
45 | return ret;
46 | }
47 |
48 | int args_create_context( args_context_t* ctx, int argc, const char** argv, const args_option_t* opts )
49 | {
50 | ctx->argc = argc - 1; /* stripping away file-name! */
51 | ctx->argv = argv + 1; /* stripping away file-name! */
52 | ctx->opts = opts;
53 | ctx->current_index = 0;
54 | ctx->current_opt_arg = 0x0;
55 |
56 | /* count opts */
57 | ctx->num_opts = 0;
58 | args_option_t cmp_opt;
59 | memset( &cmp_opt, 0x0, sizeof(args_option_t) );
60 | const args_option_t* opt = opts;
61 | while( memcmp( opt, &cmp_opt, sizeof(args_option_t) ) != 0 ) {
62 | if( opt->value == '!' ||
63 | opt->value == '?' ||
64 | opt->value == '+' ||
65 | opt->value == 0 ||
66 | opt->value == -1)
67 | return -1;
68 |
69 | ctx->num_opts++;
70 | opt++;
71 | }
72 |
73 | ctx->num_opts = (int)(opt - opts);
74 |
75 | return 0;
76 | }
77 |
78 | int args_next( args_context_t* ctx )
79 | {
80 | /* are all options processed? */
81 | if(ctx->current_index == ctx->argc )
82 | return -1;
83 |
84 | /* reset opt-arg */
85 | ctx->current_opt_arg = 0x0;
86 |
87 | const char* curr_token = ctx->argv[ ctx->current_index ];
88 |
89 | /* this token has been processed! */
90 | ctx->current_index++;
91 |
92 | /* check if item is no option */
93 | if( curr_token[0] && curr_token[0] != '-' ) {
94 | ctx->current_opt_arg = curr_token;
95 | return '+'; /* return '+' as identifier for no option! */
96 | }
97 |
98 | const args_option_t* found_opt = 0x0;
99 | const char* found_arg = 0x0;
100 |
101 | /* short opt */
102 | if( curr_token[1] != '\0' && curr_token[1] != '-' && curr_token[2] == '\0' ) {
103 | int i = 0;
104 | for( ; i < ctx->num_opts; i++ ) {
105 | const args_option_t* opt = ctx->opts + i;
106 |
107 | if( opt->name_short == curr_token[1] ) {
108 | found_opt = opt;
109 |
110 | /* if there is an value when: - current_index < argc and value in argv[current_index] do not start with '-' */
111 | if( ( ( ctx->current_index != ctx->argc) && ( ctx->argv[ctx->current_index][0] != '-' ) ) &&
112 | ( opt->type == ARGS_OPTION_TYPE_OPTIONAL || opt->type == ARGS_OPTION_TYPE_REQUIRED ) ) {
113 | found_arg = ctx->argv[ctx->current_index];
114 | ctx->current_index++; /* next token has been processed aswell! */
115 | }
116 | break;
117 | }
118 | }
119 | }
120 | /* long opt */
121 | else if(curr_token[1] == '-' && curr_token[2] != '\0') {
122 | const char* check_option = curr_token + 2;
123 |
124 | int i = 0;
125 | for( ; i < ctx->num_opts; i++ ) {
126 | const args_option_t* opt = ctx->opts + i;
127 |
128 | unsigned int name_len = (unsigned int)strlen( opt->name );
129 |
130 | if( str_case_cmp_len( opt->name, check_option, name_len ) == 0 ) {
131 | check_option += name_len;
132 |
133 | /* find arg if there is any */
134 | switch( *check_option ) {
135 | case '\0': {
136 | if( ctx->current_index < ctx->argc ) { /* are there more tokens that can contain the '='? */
137 | const char* next_token = ctx->argv[ ctx->current_index ];
138 | if( next_token[0] == '=' ) {
139 | ctx->current_index++; /* next token has been processed aswell! */
140 |
141 | if( next_token[1] != '\0' ) /* does this token contain the arg-value? */
142 | found_arg = next_token + 1;
143 | else if( ctx->current_index < ctx->argc )
144 | found_arg = ctx->argv[ ctx->current_index++ ]; /* next token has been processed aswell! */
145 | }
146 | }
147 | }
148 | break;
149 | case '=':
150 | if( check_option[1] != '\0' )
151 | found_arg = check_option + 1;
152 | else if( ctx->current_index < ctx->argc )
153 | found_arg = ctx->argv[ ctx->current_index++ ]; /* next token has been processed aswell! */
154 | break;
155 | default:
156 | /* not found, matched for example --test but it was --testing*/
157 | continue;
158 | }
159 |
160 | found_opt = opt;
161 | break;
162 | }
163 | }
164 | }
165 | /* malformed opt "-", "-xyz" or "--" */
166 | else {
167 | ctx->current_opt_arg = curr_token;
168 | return '!';
169 | }
170 |
171 | /* found no matching option! */
172 | if(found_opt == 0x0) {
173 | ctx->current_opt_arg = curr_token;
174 | return '?';
175 | }
176 |
177 | if(found_arg != 0x0) {
178 | switch(found_opt->type) {
179 | case ARGS_OPTION_TYPE_FLAG_SET:
180 | case ARGS_OPTION_TYPE_FLAG_AND:
181 | case ARGS_OPTION_TYPE_FLAG_OR:
182 | case ARGS_OPTION_TYPE_NO_ARG:
183 | /* these types should have no argument, usage error! */
184 | ctx->current_opt_arg = found_opt->name;
185 | return '!';
186 |
187 | case ARGS_OPTION_TYPE_OPTIONAL:
188 | case ARGS_OPTION_TYPE_REQUIRED:
189 | ctx->current_opt_arg = found_arg;
190 | return found_opt->value;
191 | }
192 | }
193 | /* no argument found */
194 | else {
195 | switch(found_opt->type) {
196 | case ARGS_OPTION_TYPE_FLAG_SET:
197 | *found_opt->flag = found_opt->value;
198 | return 0;
199 | case ARGS_OPTION_TYPE_FLAG_AND:
200 | *found_opt->flag &= found_opt->value;
201 | return 0;
202 | case ARGS_OPTION_TYPE_FLAG_OR:
203 | *found_opt->flag |= found_opt->value;
204 | return 0; /* zero is "a flag was set!" */
205 |
206 | case ARGS_OPTION_TYPE_NO_ARG:
207 | case ARGS_OPTION_TYPE_OPTIONAL:
208 | return found_opt->value;
209 |
210 | /* the option requires an argument! (--option=arg, -o arg) */
211 | case ARGS_OPTION_TYPE_REQUIRED:
212 | ctx->current_opt_arg = found_opt->name;
213 | return '!';
214 | }
215 | }
216 |
217 | return -1;
218 | }
219 |
220 | const char* args_create_help_string( args_context_t* ctx, char* buffer, size_t buffer_size )
221 | {
222 | size_t buffer_pos = 0;
223 | int opt_index = 0;
224 | for( ; opt_index < ctx->num_opts; ++opt_index ) {
225 | const args_option_t* opt = ctx->opts + opt_index;
226 |
227 | char long_name[64];
228 | int chars_written = str_format( long_name, 64, "--%s", opt->name );
229 | if( chars_written < 0 )
230 | return buffer;
231 |
232 | size_t outpos = (size_t)chars_written;
233 |
234 | switch( opt->type ) {
235 | case ARGS_OPTION_TYPE_REQUIRED:
236 | str_format(long_name + outpos, 64 - outpos, "=<%s>", opt->value_desc);
237 | break;
238 | case ARGS_OPTION_TYPE_OPTIONAL:
239 | str_format(long_name + outpos, 64 - outpos, "(=%s)", opt->value_desc);
240 | break;
241 | default:
242 | break;
243 | }
244 |
245 | if(opt->name_short == 0x0)
246 | chars_written = str_format( buffer + buffer_pos, buffer_size - buffer_pos, " %-32s - %s\n", long_name, opt->desc );
247 | else
248 | chars_written = str_format( buffer + buffer_pos, buffer_size - buffer_pos, "-%c %-32s - %s\n", opt->name_short, long_name, opt->desc);
249 |
250 | if( chars_written < 0 )
251 | return buffer;
252 |
253 | buffer_pos += (size_t)chars_written;
254 | }
255 |
256 | return buffer;
257 | }
--------------------------------------------------------------------------------
/src/hb_args.h:
--------------------------------------------------------------------------------
1 | /*
2 | * hashbase - https://github.com/MaciejCzyzewski/hashbase
3 | *
4 | * The MIT License (MIT)
5 | *
6 | * Copyright (c) 2014 Maciej A. Czyzewski
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of
9 | * this software and associated documentation files (the "Software"), to deal in
10 | * the Software without restriction, including without limitation the rights to
11 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
12 | * the Software, and to permit persons to whom the Software is furnished to do so,
13 | * subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
20 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
21 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
22 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 | *
25 | * Author: Maciej A. Czyzewski
26 | */
27 |
28 | #ifndef _HB_ARGS_H_
29 | #define _HB_ARGS_H_
30 |
31 | #include
32 |
33 | /*
34 | Enum: args_option_type_t
35 | Types of supported options by system.
36 |
37 | ARGS_OPTION_TYPE_NO_ARG - The option can have no argument
38 | ARGS_OPTION_TYPE_REQUIRED - The option requires an argument (--option=arg, -o arg)
39 | ARGS_OPTION_TYPE_OPTIONAL - The option-argument is optional
40 |
41 | ARGS_OPTION_TYPE_FLAG_SET - The option is a flag and value will be set to flag
42 | ARGS_OPTION_TYPE_FLAG_AND - The option is a flag and value will be and:ed with flag
43 | ARGS_OPTION_TYPE_FLAG_OR - The option is a flag and value will be or:ed with flag
44 | */
45 | typedef enum args_option_type {
46 | ARGS_OPTION_TYPE_NO_ARG,
47 | ARGS_OPTION_TYPE_REQUIRED,
48 | ARGS_OPTION_TYPE_OPTIONAL,
49 | ARGS_OPTION_TYPE_FLAG_SET,
50 | ARGS_OPTION_TYPE_FLAG_AND,
51 | ARGS_OPTION_TYPE_FLAG_OR
52 | } args_option_type_t;
53 |
54 | /**
55 | * Helper-macro to define end-element in options-array.
56 | * Mostly helpful on higher warning-level where compiler would complain for { 0 }
57 | */
58 | #define ARGS_OPTIONS_END { 0, 0, ARGS_OPTION_TYPE_NO_ARG, 0, 0, 0, 0 }
59 |
60 | /*
61 | Struct: args_option
62 | Option in system.
63 |
64 | Members:
65 | name - Long name of argument, set to NULL if only short name is valid.
66 | name_short - Short name of argument, set to 0 if only long name is valid.
67 | type - Type of option, see .
68 | flag - Pointer to flag to set if option is of flag-type, set to null NULL if option is not of flag-type.
69 | value - If option is of flag-type, this value will be set/and:ed/or:ed to the flag, else it will be returned from GetOpt when option is found.
70 | desc - Description of option.
71 | value_desc - Short description of valid values to the option, will only be used when generating help-text. example: "--my_option="
72 | */
73 | typedef struct args_option {
74 | const char* name;
75 | int name_short;
76 | args_option_type_t type;
77 | int* flag;
78 | int value;
79 | const char* desc;
80 | const char* value_desc;
81 | } args_option_t;
82 |
83 | /*
84 | Struct: args_context_t
85 | Context used while parsing options.
86 | Need to be initialized by before usage. If reused a re-initialization by is needed.
87 | Do not modify data in this struct manually!
88 |
89 | Members:
90 | argc - Internal variable
91 | argv - Internal variable
92 | opts - Internal variable
93 | num_opts - Internal variable
94 | current_index - Internal variable
95 | current_opt_arg - Used to return values. See
96 | */
97 | typedef struct args_context {
98 | int argc;
99 | const char** argv;
100 | const args_option_t* opts;
101 | int num_opts;
102 | int current_index;
103 | const char* current_opt_arg;
104 | } args_context_t;
105 |
106 | /*
107 | Function: args_create_context
108 | Initializes an args_context_t-struct to be used by
109 |
110 | Arguments:
111 | ctx - Pointer to context to initialize.
112 | argc - argc from "int main(int argc, char** argv)" or equal.
113 | argv - argv from "int main(int argc, char** argv)" or equal. Data need to be valid during option-parsing and usage of data.
114 | opts - Pointer to array with options that should be looked for. Should end with an option that is all zeroed!
115 |
116 | Returns:
117 | 0 on success, otherwise error-code.
118 | */
119 | int args_create_context( args_context_t* ctx, int argc, const char** argv, const args_option_t* opts );
120 |
121 | /*
122 | Function: args_next
123 | Used to parse argc/argv with the help of a args_context_t.
124 | Tries to parse the next token in ctx and return id depending on status.
125 |
126 | Arguments:
127 | ctx - Pointer to a initialized
128 |
129 | Returns:
130 | - '!' on error. ctx->current_opt_arg will be set to flag-name! Errors that can occur,
131 | Argument missing if argument is required or Argument found when there should be none.
132 | - '?' if item was an unrecognized option, ctx->current_opt_arg will be set to item!
133 | - '+' if item was no option, ctx->current_opt_arg will be set to item!
134 | - '0' if the opt was a flag and it was set. ctx->current_opt_arg will be set to flag-name!
135 | the value stored is value in the found option.
136 | - -1 no more options to parse!
137 | */
138 | int args_next( args_context_t* ctx );
139 |
140 | /*
141 | Function: GetOptCreateHelpString
142 | Builds a string that describes all options for use with the --help-flag etc.
143 |
144 | Arguments:
145 | ctx - Pointer to a initialized
146 | buffer - Pointer to buffer to build string in.
147 | buffer_size - Size of buffer.
148 |
149 | Returns:
150 | buffer filled with a help-string.
151 | */
152 | const char* args_create_help_string( args_context_t* ctx, char* buffer, size_t buffer_size );
153 |
154 | #endif
--------------------------------------------------------------------------------
/src/hb_ascii.c:
--------------------------------------------------------------------------------
1 | /*
2 | * ASCII An implementation of hashbase commands.
3 | *
4 | * Version: @(#)ascii.c 0.0.1 09/07/14
5 | * Authors: Maciej A. Czyzewski,
6 | *
7 | */
8 |
9 | #include
10 |
11 | extern map_t database;
12 |
13 | pipe_t ascii_inf(pipe_t *tokens)
14 | {
15 | pipe_t buffer = pipe_empty();
16 |
17 | buffer = pipe_new("hashbase ");
18 | buffer = pipe_cat(buffer, HB_VERSION);
19 | buffer = pipe_cat(buffer, " (c) 2014 Maciej A. Czyzewski");
20 |
21 | return buffer;
22 | }
23 |
24 | pipe_t ascii_set(pipe_t *tokens)
25 | {
26 | pipe_t buffer = pipe_empty();
27 |
28 | map_put(&database, tokens[1], tokens[2]);
29 | buffer = pipe_fromlonglong(HB_OK);
30 |
31 | return buffer;
32 | }
33 |
34 | pipe_t ascii_get(pipe_t *tokens)
35 | {
36 | pipe_t buffer = pipe_empty();
37 |
38 | if ((map_get(&database, tokens[1], (void**)(&buffer))) != HB_ERR) {
39 | buffer = pipe_new(buffer);
40 | }else{
41 | buffer = pipe_fromlonglong(HB_ERR);
42 | }
43 |
44 | return buffer;
45 | }
46 |
47 | pipe_t ascii_del(pipe_t *tokens)
48 | {
49 | pipe_t buffer = pipe_empty();
50 |
51 | map_remove(&database, tokens[1]);
52 | buffer = pipe_fromlonglong(HB_OK);
53 |
54 | return buffer;
55 | }
56 |
57 | pipe_t ascii_len(pipe_t *tokens)
58 | {
59 | pipe_t buffer = pipe_empty();
60 |
61 | buffer = pipe_fromlonglong(map_length(&database));
62 |
63 | return buffer;
64 | }
65 |
66 | pipe_t ascii_clr(pipe_t *tokens)
67 | {
68 | pipe_t buffer = pipe_empty();
69 |
70 | map_free(&database);
71 | buffer = pipe_fromlonglong(HB_OK);
72 |
73 | return buffer;
74 | }
--------------------------------------------------------------------------------
/src/hb_ascii.h:
--------------------------------------------------------------------------------
1 | /*
2 | * hashbase - https://github.com/MaciejCzyzewski/hashbase
3 | *
4 | * The MIT License (MIT)
5 | *
6 | * Copyright (c) 2014 Maciej A. Czyzewski
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of
9 | * this software and associated documentation files (the "Software"), to deal in
10 | * the Software without restriction, including without limitation the rights to
11 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
12 | * the Software, and to permit persons to whom the Software is furnished to do so,
13 | * subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
20 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
21 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
22 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 | *
25 | * Author: Maciej A. Czyzewski
26 | */
27 |
28 | #ifndef _HB_ASCII_H_
29 | #define _HB_ASCII_H_
30 |
31 | struct ascii_t {
32 | const char *name;
33 | pipe_t (*func)(pipe_t *);
34 | };
35 |
36 | pipe_t ascii_inf(pipe_t *);
37 | pipe_t ascii_set(pipe_t *);
38 | pipe_t ascii_get(pipe_t *);
39 | pipe_t ascii_del(pipe_t *);
40 | pipe_t ascii_len(pipe_t *);
41 | pipe_t ascii_clr(pipe_t *);
42 |
43 | #endif
--------------------------------------------------------------------------------
/src/hb_core.c:
--------------------------------------------------------------------------------
1 | /*
2 | * CORE ---
3 | *
4 | * Version: @(#)core.c 0.0.1 09/07/14
5 | * Authors: Maciej A. Czyzewski,
6 | *
7 | * Fixes:
8 | * M. A. Czyzewski : Some small cleanups, optimizations, and fixed a
9 | * core_close() bug.
10 | *
11 | */
12 |
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 |
19 | #include
20 |
21 | extern struct server server;
22 | extern struct client client;
23 |
24 | static void do_daemonize();
25 | static void do_stop();
26 |
27 | static void print_help(args_context_t);
28 | static void print_version(args_context_t);
29 |
30 | static void do_daemonize()
31 | {
32 | server.daemonize = true;
33 | server.pid = fork();
34 |
35 | if (server.pid < 0) {
36 | fprintf(stdout, "hb: %s fork failed\n", HB_LOG_ERR);
37 | core_close(1);
38 | }
39 |
40 | if (server.pid > 0) {
41 | FILE *f = fopen(server.lock, "w+");
42 |
43 | if (f != NULL) {
44 | fprintf(f, "%d", server.pid);
45 | fclose(f);
46 | }
47 |
48 | fprintf(stdout, "hb: %s daemon process running [fd: %d]...\n", HB_LOG_OK, server.pid);
49 | exit(0);
50 | }
51 |
52 | umask(0);
53 |
54 | if ((server.pid = setsid()) < 0) {
55 | core_close(1);
56 | }
57 |
58 | server.status = chdir("/");
59 |
60 | close(STDIN_FILENO);
61 | close(STDOUT_FILENO);
62 | close(STDERR_FILENO);
63 | }
64 |
65 | static void do_stop()
66 | {
67 | pid_t pid;
68 |
69 | FILE *f = fopen(server.lock, "r");
70 |
71 | if (f != NULL) {
72 | fscanf(f, "%d", &pid);
73 | fclose(f);
74 |
75 | kill(pid, SIGKILL);
76 | kill(pid, SIGTERM);
77 |
78 | remove(server.lock);
79 | }
80 |
81 | core_close(2);
82 | }
83 |
84 | static void print_help(args_context_t ctx)
85 | {
86 | char buffer[2048];
87 | printf("\nUsage: hashbase [options]\n\n");
88 | printf("%s\n", args_create_help_string(&ctx, buffer, sizeof(buffer)));
89 | core_close(0);
90 | }
91 |
92 | static void print_version(args_context_t ctx)
93 | {
94 | printf("%s\n", HB_VERSION);
95 | core_close(0);
96 | }
97 |
98 | static const args_option_t option_list[] = {
99 | { "daemonize", 'd', ARGS_OPTION_TYPE_NO_ARG, 0x0, 'd', "run hashbase as a daemon", 0x0 },
100 | { "stop", 's', ARGS_OPTION_TYPE_NO_ARG, 0x0, 's', "close running daemon", 0x0 },
101 | { "port", 'p', ARGS_OPTION_TYPE_REQUIRED, 0x0, 'p', "set the tcp port to listen on", "NUMBER" },
102 | { "help", 'h', ARGS_OPTION_TYPE_NO_ARG, 0x0, 'h', "show hashbase version, usage, options, and exit", 0x0 },
103 | { "version", 'v', ARGS_OPTION_TYPE_NO_ARG, 0x0, 'v', "show version and exit", 0x0 },
104 | ARGS_OPTIONS_END
105 | };
106 |
107 | void core_init(int argc, char *argv[])
108 | {
109 | args_context_t ctx;
110 | args_create_context(&ctx, argc, argv, option_list);
111 |
112 | int opt;
113 |
114 | while ( ( opt = args_next( &ctx ) ) != -1 ) {
115 | switch ( opt ) {
116 | /* Warnings */
117 | case '+':
118 | fprintf(stdout, "hb: %s got argument without flag [%s]\n", HB_LOG_WRN, ctx.current_opt_arg);
119 | break;
120 | case '?':
121 | fprintf(stdout, "hb: %s unknown flag [%s]\n", HB_LOG_WRN, ctx.current_opt_arg);
122 | break;
123 | case '!':
124 | fprintf(stdout, "hb: %s invalid use of flag [%s]\n", HB_LOG_WRN, ctx.current_opt_arg);
125 | break;
126 | /* Options */
127 | case 'd':
128 | do_daemonize();
129 | break;
130 | case 's':
131 | do_stop();
132 | break;
133 | case 'p':
134 | server.port = atoi(ctx.current_opt_arg);
135 | break;
136 | /* Help & Version */
137 | case 'h':
138 | print_help(ctx);
139 | break;
140 | case 'v':
141 | print_version(ctx);
142 | break;
143 | default:
144 | break;
145 | }
146 | }
147 | }
148 |
149 | void core_close(int code)
150 | {
151 | server.keepRunning = false;
152 |
153 | close(client.socket);
154 | close(server.socket);
155 |
156 | switch (code) {
157 | /* Signal close */
158 | case 2:
159 | fprintf(stdout, "hb: %s closing hashbase...\n", HB_LOG_INF);
160 | exit(0);
161 | break;
162 | /* Error */
163 | case 1:
164 | exit(1);
165 | break;
166 | /* Default */
167 | default:
168 | exit(0);
169 | break;
170 | }
171 | }
172 |
--------------------------------------------------------------------------------
/src/hb_core.h:
--------------------------------------------------------------------------------
1 | /*
2 | * hashbase - https://github.com/MaciejCzyzewski/hashbase
3 | *
4 | * The MIT License (MIT)
5 | *
6 | * Copyright (c) 2014 Maciej A. Czyzewski
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of
9 | * this software and associated documentation files (the "Software"), to deal in
10 | * the Software without restriction, including without limitation the rights to
11 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
12 | * the Software, and to permit persons to whom the Software is furnished to do so,
13 | * subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
20 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
21 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
22 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 | *
25 | * Author: Maciej A. Czyzewski
26 | */
27 |
28 | #ifndef _HB_CORE_H_
29 | #define _HB_CORE_H_
30 |
31 | #include
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include
37 | #include
38 | #include
39 | #include
40 | #include
41 | #include
42 | #include
43 | #include
44 | #include
45 |
46 | #include
47 | #include
48 | #include
49 | #include
50 | #include
51 | #include
52 | #include
53 | #include
54 |
55 | /*-----------------------------------------------------------------------------
56 | * HASHBASE config/macros
57 | *-------------------------------------------------------------------------- */
58 |
59 | #define HB_VERSION "0.0.1"
60 |
61 | #define HB_OK 0
62 | #define HB_ERR -1
63 |
64 | #define HB_LOG_OK "\033[1;32m ok >>\033[0m"
65 | #define HB_LOG_ERR "\033[1;31merror >>\033[0m"
66 | #define HB_LOG_WRN "\033[1;33m warn >>\033[0m"
67 | #define HB_LOG_INF " info >>"
68 |
69 | #define HB_MAP_SIZE 512
70 | #define HB_MAP_LENGTH 256
71 |
72 | #define HB_NET_PORT 5555
73 | #define HB_NET_BUFFER 512
74 | #define HB_NET_BACKLOG 256
75 |
76 | #define HB_CORE_LOCK "/tmp/hashbase.pid"
77 | #define HB_CORE_MAX_OPTIONS 32
78 | #define HB_CORE_MAX_ARGS 32
79 |
80 | #define HB_PIPE_PREALLOC (1024*1024)
81 |
82 | /*-----------------------------------------------------------------------------
83 | * HASHBASE modules
84 | *-------------------------------------------------------------------------- */
85 |
86 | #include
87 | #include
88 | #include
89 | #include
90 | #include
91 | #include
92 |
93 | /*-----------------------------------------------------------------------------
94 | * HASHBASE server/client
95 | *-------------------------------------------------------------------------- */
96 |
97 | struct server {
98 | /* options with no argument */
99 |
100 | int status; /* memory : last status code */
101 |
102 | struct ascii_t * commands; /* ascii : commands map */
103 |
104 | int buffer; /* network : packet lenght */
105 | int backlog; /* network : tcp backlog */
106 | int port; /* network : tcp listening port */
107 | int socket; /* network : tcp socket */
108 | struct sockaddr_in addr; /* network : tcp addr */
109 |
110 | pid_t pid; /* process : pid */
111 | char * lock; /* process : lock */
112 | bool daemonize:1; /* process : daemon */
113 | bool keepRunning:1; /* process : status */
114 | };
115 |
116 | struct client {
117 | /* options with no argument */
118 |
119 | int socket; /* network : tcp socket */
120 | struct sockaddr_in addr; /* network : tcp addr */
121 | int size; /* network : tcp size */
122 | };
123 |
124 | /*-----------------------------------------------------------------------------
125 | * HASHBASE functions
126 | *-------------------------------------------------------------------------- */
127 |
128 | void core_init(int, char * []);
129 | void core_close(int);
130 |
131 | #endif
--------------------------------------------------------------------------------
/src/hb_map.c:
--------------------------------------------------------------------------------
1 | /*
2 | * MAP Generic hash map/table manipulation functions.
3 | *
4 | * Version: @(#)map.c 0.0.1 09/07/14
5 | * Authors: Maciej A. Czyzewski,
6 | *
7 | */
8 |
9 | #include
10 | #include
11 | #include
12 |
13 | #include
14 |
15 | extern map_t database;
16 |
17 | static unsigned long crc32(const unsigned char *, unsigned int);
18 | static unsigned int map_hash_int(map_t *, char *);
19 | static int map_hash(map_t *, char *);
20 | static int map_rehash(map_t *);
21 |
22 | int map_init(void)
23 | {
24 | database = * map_new();
25 |
26 | return HB_OK;
27 | }
28 |
29 | map_t *map_new()
30 | {
31 | map_t* m = (map_t*) malloc(sizeof(map_t));
32 | if(!m) goto err;
33 |
34 | m->data = (map_bucket_t*) calloc(HB_MAP_SIZE, sizeof(map_bucket_t));
35 | if(!m->data) goto err;
36 |
37 | m->table_size = HB_MAP_SIZE;
38 | m->size = 0;
39 |
40 | return m;
41 | err:
42 | if (m)
43 | map_free(m);
44 | return NULL;
45 | }
46 |
47 | /* The implementation here was originally done by Gary S. Brown. I have
48 | * borrowed the tables directly, and made some minor changes to the
49 | * crc32-function (including changing the interface). //ylo */
50 |
51 | /* ============================================================= */
52 | /* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or */
53 | /* code or tables extracted from it, as desired without restriction. */
54 | /* */
55 | /* First, the polynomial itself and its table of feedback terms. The */
56 | /* polynomial is */
57 | /* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */
58 | /* */
59 | /* Note that we take it "backwards" and put the highest-order term in */
60 | /* the lowest-order bit. The X^32 term is "implied"; the LSB is the */
61 | /* X^31 term, etc. The X^0 term (usually shown as "+1") results in */
62 | /* the MSB being 1. */
63 | /* */
64 | /* Note that the usual hardware shift register implementation, which */
65 | /* is what we're using (we're merely optimizing it by doing eight-bit */
66 | /* chunks at a time) shifts bits into the lowest-order term. In our */
67 | /* implementation, that means shifting towards the right. Why do we */
68 | /* do it this way? Because the calculated CRC must be transmitted in */
69 | /* order from highest-order term to lowest-order term. UARTs transmit */
70 | /* characters in order from LSB to MSB. By storing the CRC this way, */
71 | /* we hand it to the UART in the order low-byte to high-byte; the UART */
72 | /* sends each low-bit to hight-bit; and the result is transmission bit */
73 | /* by bit from highest- to lowest-order term without requiring any bit */
74 | /* shuffling on our part. Reception works similarly. */
75 | /* */
76 | /* The feedback terms table consists of 256, 32-bit entries. Notes: */
77 | /* */
78 | /* The table can be generated at runtime if desired; code to do so */
79 | /* is shown later. It might not be obvious, but the feedback */
80 | /* terms simply represent the results of eight shift/xor opera- */
81 | /* tions for all combinations of data and CRC register values. */
82 | /* */
83 | /* The values must be right-shifted by eight bits by the "updcrc" */
84 | /* logic; the shift must be unsigned (bring in zeroes). On some */
85 | /* hardware you could probably optimize the shift in assembler by */
86 | /* using byte-swap instructions. */
87 | /* polynomial $edb88320 */
88 | /* */
89 | /* -------------------------------------------------------------------- */
90 |
91 | static unsigned long crc32_tab[] = {
92 | 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
93 | 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
94 | 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
95 | 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
96 | 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
97 | 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
98 | 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
99 | 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
100 | 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
101 | 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
102 | 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
103 | 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
104 | 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
105 | 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
106 | 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
107 | 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
108 | 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
109 | 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
110 | 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
111 | 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
112 | 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
113 | 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
114 | 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
115 | 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
116 | 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
117 | 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
118 | 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
119 | 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
120 | 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
121 | 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
122 | 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
123 | 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
124 | 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
125 | 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
126 | 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
127 | 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
128 | 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
129 | 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
130 | 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
131 | 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
132 | 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
133 | 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
134 | 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
135 | 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
136 | 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
137 | 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
138 | 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
139 | 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
140 | 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
141 | 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
142 | 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
143 | 0x2d02ef8dL
144 | };
145 |
146 | /* Return a 32-bit CRC of the contents of the buffer. */
147 | static unsigned long crc32(const unsigned char *s, unsigned int len)
148 | {
149 | unsigned int i;
150 | unsigned long crc32val;
151 |
152 | crc32val = 0;
153 | for (i = 0; i < len; i ++) {
154 | crc32val =
155 | crc32_tab[(crc32val ^ s[i]) & 0xff] ^
156 | (crc32val >> 8);
157 | }
158 | return crc32val;
159 | }
160 |
161 | static unsigned int map_hash_int(map_t * m, char* keystring)
162 | {
163 | /* CRC32 initial key */
164 | unsigned long key = crc32((unsigned char*)(keystring), strlen(keystring));
165 |
166 | /* Robert Jenkins' 32 bit Mix Function */
167 | key += (key << 12);
168 | key ^= (key >> 22);
169 | key += (key << 4);
170 | key ^= (key >> 9);
171 | key += (key << 10);
172 | key ^= (key >> 2);
173 | key += (key << 7);
174 | key ^= (key >> 12);
175 |
176 | /* Knuth's Multiplicative Method */
177 | key = (key >> 3) * 2654435761;
178 |
179 | return key % m->table_size;
180 | }
181 |
182 | /* Return the integer of the location in data
183 | * to store the point to the item, or HB_MAP_FULL. */
184 | static int map_hash(map_t * m, char* key)
185 | {
186 | int curr;
187 | int i;
188 |
189 | /* If full, return immediately */
190 | if(m->size >= (m->table_size/2)) return HB_MAP_FULL;
191 |
192 | /* Find the best index */
193 | curr = map_hash_int(m, key);
194 |
195 | /* Linear probing */
196 | for(i = 0; idata[curr].in_use == 0)
198 | return curr;
199 |
200 | if(m->data[curr].in_use == 1 && (strcmp(m->data[curr].key,key)==0))
201 | return curr;
202 |
203 | curr = (curr + 1) % m->table_size;
204 | }
205 |
206 | return HB_MAP_FULL;
207 | }
208 |
209 | /* Doubles the size of the map, and rehashes all the elements */
210 | static int map_rehash(map_t * m)
211 | {
212 | int i;
213 | int old_size;
214 | map_bucket_t* curr;
215 |
216 | /* Setup the new elements */
217 | map_bucket_t* temp = (map_bucket_t *)
218 | calloc(2 * m->table_size, sizeof(map_bucket_t));
219 | if(!temp) return HB_MAP_OMEM;
220 |
221 | /* Update the array */
222 | curr = m->data;
223 | m->data = temp;
224 |
225 | /* Update the size */
226 | old_size = m->table_size;
227 | m->table_size = 2 * m->table_size;
228 | m->size = 0;
229 |
230 | /* Rehash the elements */
231 | for(i = 0; i < old_size; i++) {
232 | int status;
233 |
234 | if (curr[i].in_use == 0)
235 | continue;
236 |
237 | status = map_put(m, curr[i].key, curr[i].data);
238 | if (status != HB_OK)
239 | return status;
240 | }
241 |
242 | free(curr);
243 |
244 | return HB_OK;
245 | }
246 |
247 | /* Add a pointer to the map with some key */
248 | int map_put(map_t * m, char* key, any_t value)
249 | {
250 | int index;
251 |
252 | /* Find a place to put our value */
253 | index = map_hash(m, key);
254 | while(index == HB_MAP_FULL) {
255 | if (map_rehash(m) == HB_MAP_OMEM) {
256 | return HB_MAP_OMEM;
257 | }
258 | index = map_hash(m, key);
259 | }
260 |
261 | /* Set the data */
262 | m->data[index].data = value;
263 | m->data[index].key = key;
264 | m->data[index].in_use = 1;
265 | m->size++;
266 |
267 | return HB_OK;
268 | }
269 |
270 | /* Get your pointer out of the map with a key */
271 | int map_get(map_t * m, char* key, any_t *arg)
272 | {
273 | int curr;
274 | int i;
275 |
276 | /* Find data location */
277 | curr = map_hash_int(m, key);
278 |
279 | /* Linear probing, if necessary */
280 | for(i = 0; idata[curr].in_use;
283 | if (in_use == 1) {
284 | if (strcmp(m->data[curr].key,key)==0) {
285 | *arg = (m->data[curr].data);
286 | return HB_OK;
287 | }
288 | }
289 |
290 | curr = (curr + 1) % m->table_size;
291 | }
292 |
293 | *arg = NULL;
294 |
295 | /* Not found */
296 | return HB_ERR;
297 | }
298 |
299 | /* Iterate the function parameter over each element in the map. The
300 | * additional any_t argument is passed to the function as its first
301 | * argument and the map element is the second. */
302 | int map_iterate(map_t * m, PFany f, any_t item)
303 | {
304 | int i;
305 |
306 | /* On empty map, return immediately */
307 | if (map_length(m) <= 0)
308 | return HB_ERR;
309 |
310 | /* Linear probing */
311 | for(i = 0; i< m->table_size; i++)
312 | if(m->data[i].in_use != 0) {
313 | any_t data = (any_t) (m->data[i].data);
314 | int status = f(item, data);
315 | if (status != HB_OK) {
316 | return status;
317 | }
318 | }
319 |
320 | return HB_OK;
321 | }
322 |
323 | /* Remove an element with that key from the map */
324 | int map_remove(map_t * m, char* key)
325 | {
326 | int i;
327 | int curr;
328 |
329 | /* Find key */
330 | curr = map_hash_int(m, key);
331 |
332 | /* Linear probing, if necessary */
333 | for(i = 0; idata[curr].in_use;
336 | if (in_use == 1) {
337 | if (strcmp(m->data[curr].key,key)==0) {
338 | /* Blank out the fields */
339 | m->data[curr].in_use = 0;
340 | m->data[curr].data = NULL;
341 | m->data[curr].key = NULL;
342 |
343 | /* Reduce the size */
344 | m->size--;
345 | return HB_OK;
346 | }
347 | }
348 | curr = (curr + 1) % m->table_size;
349 | }
350 |
351 | /* Data not found */
352 | return HB_ERR;
353 | }
354 |
355 | /* Deallocate the map */
356 | void map_free(map_t * m)
357 | {
358 | free(m->data);
359 | free(m);
360 | }
361 |
362 | /* Return the length of the map */
363 | int map_length(map_t * m)
364 | {
365 | if(m != NULL) return m->size;
366 | else return 0;
367 | }
--------------------------------------------------------------------------------
/src/hb_map.h:
--------------------------------------------------------------------------------
1 | /*
2 | * hashbase - https://github.com/MaciejCzyzewski/hashbase
3 | *
4 | * The MIT License (MIT)
5 | *
6 | * Copyright (c) 2014 Maciej A. Czyzewski
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of
9 | * this software and associated documentation files (the "Software"), to deal in
10 | * the Software without restriction, including without limitation the rights to
11 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
12 | * the Software, and to permit persons to whom the Software is furnished to do so,
13 | * subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
20 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
21 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
22 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 | *
25 | * Author: Maciej A. Czyzewski
26 | */
27 |
28 | #ifndef _HB_MAP_H_
29 | #define _HB_MAP_H_
30 |
31 | #define HB_MAP_FULL -3 /* Hashmap is full */
32 | #define HB_MAP_OMEM -2 /* Out of Memory */
33 |
34 | /* any_t is a pointer. This allows you to put arbitrary structures in
35 | * the map. */
36 | typedef void *any_t;
37 |
38 | /* PFany is a pointer to a function that can take two any_t arguments
39 | * and return an integer. Returns status code.. */
40 | typedef int (*PFany)(any_t, any_t);
41 |
42 | /* We need to keep keys and values. */
43 | typedef struct _map_bucket {
44 | char* key;
45 | int in_use;
46 | any_t data;
47 | } map_bucket_t;
48 |
49 | /* A map has some maximum size and current size,
50 | * as well as the data to hold. */
51 | typedef struct _map {
52 | int table_size;
53 | int size;
54 | map_bucket_t *data;
55 | } map_t;
56 |
57 | /* Create global database. */
58 | int map_init(void);
59 |
60 | /* Return an empty map. Returns NULL if empty. */
61 | map_t *map_new(void);
62 |
63 | /* Iteratively call f with argument (item, data) for
64 | * each element data in the map. The function must
65 | * return a map status code. If it returns anything other
66 | * than HB_OK the traversal is terminated. f must
67 | * not reenter any map functions, or deadlock may arise. */
68 | int map_iterate(map_t *, PFany, any_t);
69 |
70 | /* Add an element to the map. Return HB_OK or MAP_OMEM. */
71 | int map_put(map_t *, char *, any_t);
72 |
73 | /* Get an element from the map. Return HB_OK or HB_ERR. */
74 | int map_get(map_t *, char *, any_t *);
75 |
76 | /* Remove an element from the map. Return HB_OK or HB_ERR. */
77 | int map_remove(map_t *, char *);
78 |
79 | /* Get any element. Return HB_OK or HB_ERR.
80 | * remove - should the element be removed from the map */
81 | int map_get_one(map_t *, any_t *, int);
82 |
83 | /* Free the map. */
84 | void map_free(map_t *);
85 |
86 | /* Get the current size of a map. */
87 | int map_length(map_t *);
88 |
89 | #endif
--------------------------------------------------------------------------------
/src/hb_net.c:
--------------------------------------------------------------------------------
1 | /*
2 | * NET An implementation of the TCP/UDP network access protocol.
3 | *
4 | * Version: @(#)net.c 0.0.1 09/07/14
5 | * Authors: Maciej A. Czyzewski,
6 | *
7 | */
8 |
9 | #include
10 | #include
11 | #include
12 |
13 | #include
14 |
15 | extern struct server server;
16 | extern struct client client;
17 |
18 | int net_init(void)
19 | {
20 | if ((server.socket = socket(AF_INET, SOCK_STREAM, 0)) == HB_ERR) {
21 | fprintf(stdout, "hb: %s could not create socket\n", HB_LOG_ERR);
22 | return HB_ERR;
23 | }
24 |
25 | server.addr.sin_family = AF_INET;
26 | server.addr.sin_addr.s_addr = INADDR_ANY;
27 | server.addr.sin_port = htons(server.port);
28 |
29 | if (bind(server.socket, (struct sockaddr *)&server.addr, sizeof(server.addr)) < HB_OK) {
30 | fprintf(stdout, "hb: %s port is already in use\n", HB_LOG_ERR);
31 | return HB_ERR;
32 | }
33 |
34 | listen(server.socket, server.backlog);
35 |
36 | return HB_OK;
37 | }
38 |
39 | int net_loop(void)
40 | {
41 | pthread_t thread_id;
42 |
43 | while ((client.socket = accept(server.socket, (struct sockaddr *)&client.addr, (socklen_t*)&client.size)) || server.keepRunning) {
44 | if (client.socket < HB_OK) {
45 | fprintf(stdout, "hb: %s connection failed\n", HB_LOG_ERR);
46 | return HB_ERR;
47 | }
48 |
49 | fprintf(stdout, "hb: %s connection accepted [fd: %d]\n", HB_LOG_OK, client.socket);
50 |
51 | if (pthread_create(&thread_id, NULL, net_handler, (void*) &client.socket) < HB_OK) {
52 | fprintf(stdout, "hb: %s could not create thread\n", HB_LOG_ERR);
53 | return HB_ERR;
54 | }
55 | }
56 |
57 | return HB_OK;
58 | }
59 |
60 | void *net_handler(void *socket_desc)
61 | {
62 | int sock = *(int*)socket_desc;
63 | int read_size = 0;
64 |
65 | char assocc[HB_NET_BUFFER];
66 | pipe_t buffer = pipe_empty();
67 |
68 | while ((read_size = recv(sock, assocc, HB_NET_BUFFER, 0)) > 0) {
69 | pipe_t packet = pipe_newlen(assocc, read_size);
70 |
71 | buffer = pipe_catpipe(buffer, packet);
72 | packet = pipe_empty();
73 |
74 | if (pipe_len(buffer) > 1) {
75 | if (buffer[(pipe_len(buffer)-1)] == '\n' && buffer[(pipe_len(buffer)-2)] == '\r') {
76 | pipe_trim(buffer, "\r\n");
77 | packet = net_command(buffer);
78 | packet = pipe_cat(packet, "\r\n");
79 | server.status = write(sock, packet, (int) pipe_len(packet));
80 |
81 | buffer = pipe_empty();
82 | packet = pipe_empty();
83 | }
84 | }
85 |
86 | pipe_free(packet);
87 | }
88 |
89 | switch (read_size) {
90 | case HB_OK:
91 | fprintf(stdout, "hb: %s client disconnected [fd: %d]\n", HB_LOG_OK, sock);
92 | fflush(stdout);
93 | break;
94 | case HB_ERR:
95 | fprintf(stdout, "hb: %s client receive failed [fd: %d]\n", HB_LOG_ERR, sock);
96 | break;
97 | }
98 |
99 | return HB_OK;
100 | }
101 |
102 | void *net_command(void *buffer)
103 | {
104 | pipe_t *tokens;
105 | int count, i;
106 |
107 | tokens = pipe_splitargs(buffer, &count);
108 |
109 | for (i = 0 ;; i++) {
110 | if ( server.commands[i].name == NULL ) {
111 | break;
112 | } else if (!strcmp(server.commands[i].name, tokens[0]) && server.commands[i].func) {
113 | return buffer = server.commands[i].func(tokens);
114 | }
115 | }
116 |
117 | return buffer = pipe_fromlonglong(HB_ERR);
118 | }
119 |
--------------------------------------------------------------------------------
/src/hb_net.h:
--------------------------------------------------------------------------------
1 | /*
2 | * hashbase - https://github.com/MaciejCzyzewski/hashbase
3 | *
4 | * The MIT License (MIT)
5 | *
6 | * Copyright (c) 2014 Maciej A. Czyzewski
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of
9 | * this software and associated documentation files (the "Software"), to deal in
10 | * the Software without restriction, including without limitation the rights to
11 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
12 | * the Software, and to permit persons to whom the Software is furnished to do so,
13 | * subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
20 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
21 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
22 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 | *
25 | * Author: Maciej A. Czyzewski
26 | */
27 |
28 | #ifndef _HB_NET_H_
29 | #define _HB_NET_H_
30 |
31 | int net_init(void);
32 | int net_loop(void);
33 | void *net_handler(void *);
34 | void *net_command(void *);
35 |
36 | #endif
--------------------------------------------------------------------------------
/src/hb_pipe.c:
--------------------------------------------------------------------------------
1 | /*
2 | * PIPE A simple thread-safe FIFO
3 | *
4 | * Version: @(#)pipe.c 0.0.1 09/07/14
5 | * Authors: Clark Gaebel,
6 | * Salvatore Sanfilippo
7 | * Maciej A. Czyzewski,
8 | *
9 | */
10 |
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 |
17 | #include
18 |
19 | /* Create a new pipe_t string with the content specified by the 'init' pointer
20 | * and 'initlen'.
21 | * If NULL is used for 'init' the string is initialized with zero bytes.
22 | *
23 | * The string is always null-termined (all the pipe_t strings are, always) so
24 | * even if you create an pipe_t string with:
25 | *
26 | * mystring = pipe_newlen("abc",3");
27 | *
28 | * You can print the string with printf() as there is an implicit \0 at the
29 | * end of the string. However the string is binary safe and can contain
30 | * \0 characters in the middle, as the length is stored in the pipe_t header. */
31 | pipe_t pipe_newlen(const void *init, size_t initlen)
32 | {
33 | struct pipe_hdr_t *sh;
34 |
35 | if (init) {
36 | sh = malloc(sizeof *sh+initlen+1);
37 | } else {
38 | sh = calloc(sizeof *sh+initlen+1,1);
39 | }
40 | if (sh == NULL) return NULL;
41 | sh->len = initlen;
42 | sh->free = 0;
43 | if (initlen && init)
44 | memcpy(sh->buf, init, initlen);
45 | sh->buf[initlen] = '\0';
46 | return (char*)sh->buf;
47 | }
48 |
49 | /* Create an empty (zero length) pipe_t string. Even in this case the string
50 | * always has an implicit null term. */
51 | pipe_t pipe_empty(void)
52 | {
53 | return pipe_newlen("",0);
54 | }
55 |
56 | /* Create a new pipe_t string starting from a null termined C string. */
57 | pipe_t pipe_new(const char *init)
58 | {
59 | size_t initlen = (init == NULL) ? 0 : strlen(init);
60 | return pipe_newlen(init, initlen);
61 | }
62 |
63 | size_t pipe_len(const pipe_t s)
64 | {
65 | struct pipe_hdr_t *sh = (void*)(s-sizeof *sh);
66 | return sh->len;
67 | }
68 |
69 | /* Duplicate an pipe_t string. */
70 | pipe_t pipe_dup(const pipe_t s)
71 | {
72 | return pipe_newlen(s, pipe_len(s));
73 | }
74 |
75 | /* Free an pipe_t string. No operation is performed if 's' is NULL. */
76 | void pipe_free(pipe_t s)
77 | {
78 | if (s == NULL) return;
79 | free(s-sizeof(struct pipe_hdr_t));
80 | }
81 |
82 | size_t pipe_avail(const pipe_t s)
83 | {
84 | struct pipe_hdr_t *sh = (void*)(s-sizeof *sh);
85 | return sh->free;
86 | }
87 |
88 | /* Set the pipe_t string length to the length as obtained with strlen(), so
89 | * considering as content only up to the first null term character.
90 | *
91 | * This function is useful when the pipe_t string is hacked manually in some
92 | * way, like in the following example:
93 | *
94 | * s = pipe_new("foobar");
95 | * s[2] = '\0';
96 | * pipe_updatelen(s);
97 | * printf("%d\n", pipe_len(s));
98 | *
99 | * The output will be "2", but if we comment out the call to pipe_updatelen()
100 | * the output will be "6" as the string was modified but the logical length
101 | * remains 6 bytes. */
102 | void pipe_updatelen(pipe_t s)
103 | {
104 | struct pipe_hdr_t *sh = (void*) (s-sizeof *sh);;
105 | int reallen = strlen(s);
106 | sh->free += (sh->len-reallen);
107 | sh->len = reallen;
108 | }
109 |
110 | /* Modify an pipe_t string on-place to make it empty (zero length).
111 | * However all the existing buffer is not discarded but set as free space
112 | * so that next append operations will not require allocations up to the
113 | * number of bytes previously available. */
114 | void pipe_clear(pipe_t s)
115 | {
116 | struct pipe_hdr_t *sh = (void*) (s-sizeof *sh);;
117 | sh->free += sh->len;
118 | sh->len = 0;
119 | sh->buf[0] = '\0';
120 | }
121 |
122 | /* Enlarge the free space at the end of the pipe_t string so that the caller
123 | * is sure that after calling this function can overwrite up to addlen
124 | * bytes after the end of the string, plus one more byte for nul term.
125 | *
126 | * Note: this does not change the *length* of the pipe_t string as returned
127 | * by pipelen(), but only the free buffer space we have. */
128 | pipe_t pipe_MakeRoomFor(pipe_t s, size_t addlen)
129 | {
130 | struct pipe_hdr_t *sh, *newsh;
131 | size_t free = pipe_avail(s);
132 | size_t len, newlen;
133 |
134 | if (free >= addlen) return s;
135 | len = pipe_len(s);
136 | sh = (void*) (s-sizeof *sh);;
137 | newlen = (len+addlen);
138 | if (newlen < HB_PIPE_PREALLOC)
139 | newlen *= 2;
140 | else
141 | newlen += HB_PIPE_PREALLOC;
142 | newsh = realloc(sh, sizeof *newsh+newlen+1);
143 | if (newsh == NULL) return NULL;
144 |
145 | newsh->free = newlen - len;
146 | return newsh->buf;
147 | }
148 |
149 | /* Reallocate the pipe_t string so that it has no free space at the end. The
150 | * contained string remains not altered, but next concatenation operations
151 | * will require a reallocation.
152 | *
153 | * After the call, the passed pipe_t string is no longer valid and all the
154 | * references must be substituted with the new pointer returned by the call. */
155 | pipe_t pipe_RemoveFreeSpace(pipe_t s)
156 | {
157 | struct pipe_hdr_t *sh;
158 |
159 | sh = (void*) (s-sizeof *sh);;
160 | sh = realloc(sh, sizeof *sh+sh->len+1);
161 | sh->free = 0;
162 | return sh->buf;
163 | }
164 |
165 | /* Return the total size of the allocation of the specifed pipe_t string,
166 | * including:
167 | * 1) The pipe_t header before the pointer.
168 | * 2) The string.
169 | * 3) The free buffer at the end if any.
170 | * 4) The implicit null term.
171 | */
172 | size_t pipe_AllocSize(pipe_t s)
173 | {
174 | struct pipe_hdr_t *sh = (void*) (s-sizeof *sh);;
175 |
176 | return sizeof(*sh)+sh->len+sh->free+1;
177 | }
178 |
179 | /* Increment the pipe_t length and decrements the left free space at the
180 | * end of the string according to 'incr'. Also set the null term
181 | * in the new end of the string.
182 | *
183 | * This function is used in order to fix the string length after the
184 | * user calls pipe_MakeRoomFor(), writes something after the end of
185 | * the current string, and finally needs to set the new length.
186 | *
187 | * Note: it is possible to use a negative increment in order to
188 | * right-trim the string.
189 | *
190 | * Usage example:
191 | *
192 | * Using pipe_IncrLen() and pipe_MakeRoomFor() it is possible to mount the
193 | * following schema, to cat bytes coming from the kernel to the end of an
194 | * pipe_t string without copying into an intermediate buffer:
195 | *
196 | * oldlen = pipe_len(s);
197 | * s = pipe_MakeRoomFor(s, BUFFER_SIZE);
198 | * nread = read(fd, s+oldlen, BUFFER_SIZE);
199 | * ... check for nread <= 0 and handle it ...
200 | * pipe_IncrLen(s, nread);
201 | */
202 | void pipe_IncrLen(pipe_t s, int incr)
203 | {
204 | struct pipe_hdr_t *sh = (void*) (s-sizeof *sh);;
205 |
206 | assert(sh->free >= incr);
207 | sh->len += incr;
208 | sh->free -= incr;
209 | assert(sh->free >= 0);
210 | s[sh->len] = '\0';
211 | }
212 |
213 | /* Grow the pipe_t to have the specified length. Bytes that were not part of
214 | * the original length of the pipe_t will be set to zero.
215 | *
216 | * if the specified length is smaller than the current length, no operation
217 | * is performed. */
218 | pipe_t pipe_growzero(pipe_t s, size_t len)
219 | {
220 | struct pipe_hdr_t *sh = (void*) (s-sizeof *sh);
221 | size_t totlen, curlen = sh->len;
222 |
223 | if (len <= curlen) return s;
224 | s = pipe_MakeRoomFor(s,len-curlen);
225 | if (s == NULL) return NULL;
226 |
227 | /* Make sure added region doesn't contain garbage */
228 | sh = (void*)(s-sizeof *sh);
229 | memset(s+curlen,0,(len-curlen+1)); /* also set trailing \0 byte */
230 | totlen = sh->len+sh->free;
231 | sh->len = len;
232 | sh->free = totlen-sh->len;
233 | return s;
234 | }
235 |
236 | /* Append the specified binary-safe string pointed by 't' of 'len' bytes to the
237 | * end of the specified pipe_t string 's'.
238 | *
239 | * After the call, the passed pipe_t string is no longer valid and all the
240 | * references must be substituted with the new pointer returned by the call. */
241 | pipe_t pipe_catlen(pipe_t s, const void *t, size_t len)
242 | {
243 | struct pipe_hdr_t *sh;
244 | size_t curlen = pipe_len(s);
245 |
246 | s = pipe_MakeRoomFor(s,len);
247 | if (s == NULL) return NULL;
248 | sh = (void*) (s-sizeof *sh);;
249 | memcpy(s+curlen, t, len);
250 | sh->len = curlen+len;
251 | sh->free = sh->free-len;
252 | s[curlen+len] = '\0';
253 | return s;
254 | }
255 |
256 | /* Append the specified null termianted C string to the pipe_t string 's'.
257 | *
258 | * After the call, the passed pipe_t string is no longer valid and all the
259 | * references must be substituted with the new pointer returned by the call. */
260 | pipe_t pipe_cat(pipe_t s, const char *t)
261 | {
262 | return pipe_catlen(s, t, strlen(t));
263 | }
264 |
265 | /* Append the specified pipe_t 't' to the existing pipe_t 's'.
266 | *
267 | * After the call, the modified pipe_t string is no longer valid and all the
268 | * references must be substituted with the new pointer returned by the call. */
269 | pipe_t pipe_catpipe(pipe_t s, const pipe_t t)
270 | {
271 | return pipe_catlen(s, t, pipe_len(t));
272 | }
273 |
274 | /* Destructively modify the pipe_t string 's' to hold the specified binary
275 | * safe string pointed by 't' of length 'len' bytes. */
276 | pipe_t pipe_cpylen(pipe_t s, const char *t, size_t len)
277 | {
278 | struct pipe_hdr_t *sh = (void*) (s-sizeof *sh);;
279 | size_t totlen = sh->free+sh->len;
280 |
281 | if (totlen < len) {
282 | s = pipe_MakeRoomFor(s,len-sh->len);
283 | if (s == NULL) return NULL;
284 | sh = (void*) (s-sizeof *sh);;
285 | totlen = sh->free+sh->len;
286 | }
287 | memcpy(s, t, len);
288 | s[len] = '\0';
289 | sh->len = len;
290 | sh->free = totlen-len;
291 | return s;
292 | }
293 |
294 | /* Like pipe_cpylen() but 't' must be a null-termined string so that the length
295 | * of the string is obtained with strlen(). */
296 | pipe_t pipe_cpy(pipe_t s, const char *t)
297 | {
298 | return pipe_cpylen(s, t, strlen(t));
299 | }
300 |
301 | /* Like pipe_catpritf() but gets va_list instead of being variadic. */
302 | pipe_t pipe_catvprintf(pipe_t s, const char *fmt, va_list ap)
303 | {
304 | va_list cpy;
305 | char *buf, *t;
306 | size_t buflen = 16;
307 |
308 | while(1) {
309 | buf = malloc(buflen);
310 | if (buf == NULL) return NULL;
311 | buf[buflen-2] = '\0';
312 | va_copy(cpy,ap);
313 | vsnprintf(buf, buflen, fmt, cpy);
314 | if (buf[buflen-2] != '\0') {
315 | free(buf);
316 | buflen *= 2;
317 | continue;
318 | }
319 | break;
320 | }
321 | t = pipe_cat(s, buf);
322 | free(buf);
323 | return t;
324 | }
325 |
326 | /* Append to the pipe_t string 's' a string obtained using printf-alike format
327 | * specifier.
328 | *
329 | * After the call, the modified pipe_t string is no longer valid and all the
330 | * references must be substituted with the new pointer returned by the call.
331 | *
332 | * Example:
333 | *
334 | * s = pipe_empty("Sum is: ");
335 | * s = pipe_catprintf(s,"%d+%d = %d",a,b,a+b).
336 | *
337 | * Often you need to create a string from scratch with the printf-alike
338 | * format. When this is the need, just use pipe_empty() as the target string:
339 | *
340 | * s = pipe_catprintf(pipe_empty(), "... your format ...", args);
341 | */
342 | pipe_t pipe_catprintf(pipe_t s, const char *fmt, ...)
343 | {
344 | va_list ap;
345 | char *t;
346 | va_start(ap, fmt);
347 | t = pipe_catvprintf(s,fmt,ap);
348 | va_end(ap);
349 | return t;
350 | }
351 |
352 | /* Remove the part of the string from left and from right composed just of
353 | * contiguous characters found in 'cset', that is a null terminted C string.
354 | *
355 | * After the call, the modified pipe_t string is no longer valid and all the
356 | * references must be substituted with the new pointer returned by the call.
357 | *
358 | * Example:
359 | *
360 | * s = pipe_new("AA...AA.a.aa.aHelloWorld :::");
361 | * s = pipe_trim(s,"A. :");
362 | * printf("%s\n", s);
363 | *
364 | * Output will be just "Hello World".
365 | */
366 | void pipe_trim(pipe_t s, const char *cset)
367 | {
368 | struct pipe_hdr_t *sh = (void*) (s-sizeof *sh);;
369 | char *start, *end, *sp, *ep;
370 | size_t len;
371 |
372 | sp = start = s;
373 | ep = end = s+pipe_len(s)-1;
374 | while(sp <= end && strchr(cset, *sp)) sp++;
375 | while(ep > start && strchr(cset, *ep)) ep--;
376 | len = (sp > ep) ? 0 : ((ep-sp)+1);
377 | if (sh->buf != sp) memmove(sh->buf, sp, len);
378 | sh->buf[len] = '\0';
379 | sh->free = sh->free+(sh->len-len);
380 | sh->len = len;
381 | }
382 |
383 | /* Turn the string into a smaller (or equal) string containing only the
384 | * substring specified by the 'start' and 'end' indexes.
385 | *
386 | * start and end can be negative, where -1 means the last character of the
387 | * string, -2 the penultimate character, and so forth.
388 | *
389 | * The interval is inclusive, so the start and end characters will be part
390 | * of the resulting string.
391 | *
392 | * The string is modified in-place.
393 | *
394 | * Example:
395 | *
396 | * s = pipe_new("Hello World");
397 | * pipe_range(s,1,-1); => "ello World"
398 | */
399 | void pipe_range(pipe_t s, int start, int end)
400 | {
401 | struct pipe_hdr_t *sh = (void*) (s-sizeof *sh);;
402 | size_t newlen, len = pipe_len(s);
403 |
404 | if (len == 0) return;
405 | if (start < 0) {
406 | start = len+start;
407 | if (start < 0) start = 0;
408 | }
409 | if (end < 0) {
410 | end = len+end;
411 | if (end < 0) end = 0;
412 | }
413 | newlen = (start > end) ? 0 : (end-start)+1;
414 | if (newlen != 0) {
415 | if (start >= (signed)len) {
416 | newlen = 0;
417 | } else if (end >= (signed)len) {
418 | end = len-1;
419 | newlen = (start > end) ? 0 : (end-start)+1;
420 | }
421 | } else {
422 | start = 0;
423 | }
424 | if (start && newlen) memmove(sh->buf, sh->buf+start, newlen);
425 | sh->buf[newlen] = 0;
426 | sh->free = sh->free+(sh->len-newlen);
427 | sh->len = newlen;
428 | }
429 |
430 | /* Apply tolower() to every character of the pipe_t string 's'. */
431 | void pipe_tolower(pipe_t s)
432 | {
433 | int len = pipe_len(s), j;
434 |
435 | for (j = 0; j < len; j++) s[j] = tolower(s[j]);
436 | }
437 |
438 | /* Apply toupper() to every character of the pipe_t string 's'. */
439 | void pipe_toupper(pipe_t s)
440 | {
441 | int len = pipe_len(s), j;
442 |
443 | for (j = 0; j < len; j++) s[j] = toupper(s[j]);
444 | }
445 |
446 | /* Compare two pipe_t strings s1 and s2 with memcmp().
447 | *
448 | * Return value:
449 | *
450 | * 1 if s1 > s2.
451 | * -1 if s1 < s2.
452 | * 0 if s1 and s2 are exactly the same binary string.
453 | *
454 | * If two strings share exactly the same prefix, but one of the two has
455 | * additional characters, the longer string is considered to be greater than
456 | * the smaller one. */
457 | int pipe_cmp(const pipe_t s1, const pipe_t s2)
458 | {
459 | size_t l1, l2, minlen;
460 | int cmp;
461 |
462 | l1 = pipe_len(s1);
463 | l2 = pipe_len(s2);
464 | minlen = (l1 < l2) ? l1 : l2;
465 | cmp = memcmp(s1,s2,minlen);
466 | if (cmp == 0) return l1-l2;
467 | return cmp;
468 | }
469 |
470 | /* Split 's' with separator in 'sep'. An array
471 | * of pipe_t strings is returned. *count will be set
472 | * by reference to the number of tokens returned.
473 | *
474 | * On out of memory, zero length string, zero length
475 | * separator, NULL is returned.
476 | *
477 | * Note that 'sep' is able to split a string using
478 | * a multi-character separator. For example
479 | * pipe_split("foo_-_bar","_-_"); will return two
480 | * elements "foo" and "bar".
481 | *
482 | * This version of the function is binary-safe but
483 | * requires length arguments. pipe_split() is just the
484 | * same function but for zero-terminated strings.
485 | */
486 | pipe_t *pipe_splitlen(const char *s, int len, const char *sep, int seplen, int *count)
487 | {
488 | int elements = 0, slots = 5, start = 0, j;
489 | pipe_t *tokens;
490 |
491 | if (seplen < 1 || len < 0) return NULL;
492 |
493 | tokens = malloc(sizeof(pipe)*slots);
494 | if (tokens == NULL) return NULL;
495 |
496 | if (len == 0) {
497 | *count = 0;
498 | return tokens;
499 | }
500 | for (j = 0; j < (len-(seplen-1)); j++) {
501 | /* make sure there is room for the next element and the final one */
502 | if (slots < elements+2) {
503 | pipe_t *newtokens;
504 |
505 | slots *= 2;
506 | newtokens = realloc(tokens,sizeof(pipe)*slots);
507 | if (newtokens == NULL) goto cleanup;
508 | tokens = newtokens;
509 | }
510 | /* search the separator */
511 | if ((seplen == 1 && *(s+j) == sep[0]) || (memcmp(s+j,sep,seplen) == 0)) {
512 | tokens[elements] = pipe_newlen(s+start,j-start);
513 | if (tokens[elements] == NULL) goto cleanup;
514 | elements++;
515 | start = j+seplen;
516 | j = j+seplen-1; /* skip the separator */
517 | }
518 | }
519 | /* Add the final element. We are sure there is room in the tokens array. */
520 | tokens[elements] = pipe_newlen(s+start,len-start);
521 | if (tokens[elements] == NULL) goto cleanup;
522 | elements++;
523 | *count = elements;
524 | return tokens;
525 |
526 | cleanup: {
527 | int i;
528 | for (i = 0; i < elements; i++) pipe_free(tokens[i]);
529 | free(tokens);
530 | *count = 0;
531 | return NULL;
532 | }
533 | }
534 |
535 | /* Free the result returned by pipe_splitlen(), or do nothing if 'tokens' is NULL. */
536 | void pipe_freesplitres(pipe_t *tokens, int count)
537 | {
538 | if (!tokens) return;
539 | while(count--)
540 | pipe_free(tokens[count]);
541 | free(tokens);
542 | }
543 |
544 | /* Create an pipe_t string from a long long value. It is much faster than:
545 | *
546 | * pipe_catprintf(pipeempty(),"%lld\n", value);
547 | */
548 | pipe_t pipe_fromlonglong(long long value)
549 | {
550 | char buf[32], *p;
551 | unsigned long long v;
552 |
553 | v = (value < 0) ? -value : value;
554 | p = buf+31; /* point to the last character */
555 | do {
556 | *p-- = '0'+(v%10);
557 | v /= 10;
558 | } while(v);
559 | if (value < 0) *p-- = '-';
560 | p++;
561 | return pipe_newlen(p,32-(p-buf));
562 | }
563 |
564 | /* Append to the pipe_t string "s" an escaped string representation where
565 | * all the non-printable characters (tested with isprint()) are turned into
566 | * escapes in the form "\n\r\a...." or "\x".
567 | *
568 | * After the call, the modified pipe_t string is no longer valid and all the
569 | * references must be substituted with the new pointer returned by the call. */
570 | pipe_t pipe_catrepr(pipe_t s, const char *p, size_t len)
571 | {
572 | s = pipe_catlen(s,"\"",1);
573 | while(len--) {
574 | switch(*p) {
575 | case '\\':
576 | case '"':
577 | s = pipe_catprintf(s,"\\%c",*p);
578 | break;
579 | case '\n':
580 | s = pipe_catlen(s,"\\n",2);
581 | break;
582 | case '\r':
583 | s = pipe_catlen(s,"\\r",2);
584 | break;
585 | case '\t':
586 | s = pipe_catlen(s,"\\t",2);
587 | break;
588 | case '\a':
589 | s = pipe_catlen(s,"\\a",2);
590 | break;
591 | case '\b':
592 | s = pipe_catlen(s,"\\b",2);
593 | break;
594 | default:
595 | if (isprint(*p))
596 | s = pipe_catprintf(s,"%c",*p);
597 | else
598 | s = pipe_catprintf(s,"\\x%02x",(unsigned char)*p);
599 | break;
600 | }
601 | p++;
602 | }
603 | return pipe_catlen(s,"\"",1);
604 | }
605 |
606 | /* Helper function for pipesplitargs() that returns non zero if 'c'
607 | * is a valid hex digit. */
608 | static int is_hex_digit(char c)
609 | {
610 | return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') ||
611 | (c >= 'A' && c <= 'F');
612 | }
613 |
614 | /* Helper function for pipesplitargs() that converts a hex digit into an
615 | * integer from 0 to 15 */
616 | static int hex_digit_to_int(char c)
617 | {
618 | switch(c) {
619 | case '0':
620 | return 0;
621 | case '1':
622 | return 1;
623 | case '2':
624 | return 2;
625 | case '3':
626 | return 3;
627 | case '4':
628 | return 4;
629 | case '5':
630 | return 5;
631 | case '6':
632 | return 6;
633 | case '7':
634 | return 7;
635 | case '8':
636 | return 8;
637 | case '9':
638 | return 9;
639 | case 'a':
640 | case 'A':
641 | return 10;
642 | case 'b':
643 | case 'B':
644 | return 11;
645 | case 'c':
646 | case 'C':
647 | return 12;
648 | case 'd':
649 | case 'D':
650 | return 13;
651 | case 'e':
652 | case 'E':
653 | return 14;
654 | case 'f':
655 | case 'F':
656 | return 15;
657 | default:
658 | return 0;
659 | }
660 | }
661 |
662 | /* Split a line into arguments, where every argument can be in the
663 | * following programming-language REPL-alike form:
664 | *
665 | * foo bar "newline are supported\n" and "\xff\x00otherstuff"
666 | *
667 | * The number of arguments is stored into *argc, and an array
668 | * of pipe_t is returned.
669 | *
670 | * The caller should free the resulting array of pipe_t strings with
671 | * pipe_freesplitres().
672 | *
673 | * Note that pipe_catrepr() is able to convert back a string into
674 | * a quoted string in the same format pipe_splitargs() is able to parse.
675 | *
676 | * The function returns the allocated tokens on success, even when the
677 | * input string is empty, or NULL if the input contains unbalanced
678 | * quotes or closed quotes followed by non space characters
679 | * as in: "foo"bar or "foo'
680 | */
681 | pipe_t *pipe_splitargs(const char *line, int *argc)
682 | {
683 | const char *p = line;
684 | char *current = NULL;
685 | char **vector = NULL;
686 |
687 | *argc = 0;
688 | while(1) {
689 | /* skip blanks */
690 | while(*p && isspace(*p)) p++;
691 | if (*p) {
692 | /* get a token */
693 | int inq=0; /* set to 1 if we are in "quotes" */
694 | int insq=0; /* set to 1 if we are in 'single quotes' */
695 | int done=0;
696 |
697 | if (current == NULL) current = pipe_empty();
698 | while(!done) {
699 | if (inq) {
700 | if (*p == '\\' && *(p+1) == 'x' &&
701 | is_hex_digit(*(p+2)) &&
702 | is_hex_digit(*(p+3))) {
703 | unsigned char byte;
704 |
705 | byte = (hex_digit_to_int(*(p+2))*16)+
706 | hex_digit_to_int(*(p+3));
707 | current = pipe_catlen(current,(char*)&byte,1);
708 | p += 3;
709 | } else if (*p == '\\' && *(p+1)) {
710 | char c;
711 |
712 | p++;
713 | switch(*p) {
714 | case 'n':
715 | c = '\n';
716 | break;
717 | case 'r':
718 | c = '\r';
719 | break;
720 | case 't':
721 | c = '\t';
722 | break;
723 | case 'b':
724 | c = '\b';
725 | break;
726 | case 'a':
727 | c = '\a';
728 | break;
729 | default:
730 | c = *p;
731 | break;
732 | }
733 | current = pipe_catlen(current,&c,1);
734 | } else if (*p == '"') {
735 | /* closing quote must be followed by a space or
736 | * nothing at all. */
737 | if (*(p+1) && !isspace(*(p+1))) goto err;
738 | done=1;
739 | } else if (!*p) {
740 | /* unterminated quotes */
741 | goto err;
742 | } else {
743 | current = pipe_catlen(current,p,1);
744 | }
745 | } else if (insq) {
746 | if (*p == '\\' && *(p+1) == '\'') {
747 | p++;
748 | current = pipe_catlen(current,"'",1);
749 | } else if (*p == '\'') {
750 | /* closing quote must be followed by a space or
751 | * nothing at all. */
752 | if (*(p+1) && !isspace(*(p+1))) goto err;
753 | done=1;
754 | } else if (!*p) {
755 | /* unterminated quotes */
756 | goto err;
757 | } else {
758 | current = pipe_catlen(current,p,1);
759 | }
760 | } else {
761 | switch(*p) {
762 | case ' ':
763 | case '\n':
764 | case '\r':
765 | case '\t':
766 | case '\0':
767 | done=1;
768 | break;
769 | case '"':
770 | inq=1;
771 | break;
772 | case '\'':
773 | insq=1;
774 | break;
775 | default:
776 | current = pipe_catlen(current,p,1);
777 | break;
778 | }
779 | }
780 | if (*p) p++;
781 | }
782 | /* add the token to the vector */
783 | vector = realloc(vector,((*argc)+1)*sizeof(char*));
784 | vector[*argc] = current;
785 | (*argc)++;
786 | current = NULL;
787 | } else {
788 | /* Even on empty input string return something not NULL. */
789 | if (vector == NULL) vector = malloc(sizeof(void*));
790 | return vector;
791 | }
792 | }
793 |
794 | err:
795 | while((*argc)--)
796 | pipe_free(vector[*argc]);
797 | free(vector);
798 | if (current) pipe_free(current);
799 | *argc = 0;
800 | return NULL;
801 | }
802 |
803 | /* Modify the string substituting all the occurrences of the set of
804 | * characters specified in the 'from' string to the corresponding character
805 | * in the 'to' array.
806 | *
807 | * For instance: pipe_mapchars(mystring, "ho", "01", 2)
808 | * will have the effect of turning the string "hello" into "0ell1".
809 | *
810 | * The function returns the pipe_t string pointer, that is always the same
811 | * as the input pointer since no resize is needed. */
812 | pipe_t pipe_mapchars(pipe_t s, const char *from, const char *to, size_t setlen)
813 | {
814 | size_t j, i, l = pipe_len(s);
815 |
816 | for (j = 0; j < l; j++) {
817 | for (i = 0; i < setlen; i++) {
818 | if (s[j] == from[i]) {
819 | s[j] = to[i];
820 | break;
821 | }
822 | }
823 | }
824 | return s;
825 | }
826 |
827 | /* Join an array of C strings using the specified separator (also a C string).
828 | * Returns the result as an pipe_t string. */
829 | pipe_t pipe_join(char **argv, int argc, char *sep, size_t seplen)
830 | {
831 | pipe_t join = pipe_empty();
832 | int j;
833 |
834 | for (j = 0; j < argc; j++) {
835 | join = pipe_cat(join, argv[j]);
836 | if (j != argc-1) join = pipe_catlen(join,sep,seplen);
837 | }
838 | return join;
839 | }
840 |
841 | /* Like pipejoin, but joins an array of pipe strings. */
842 | pipe_t pipe_joinpipe(pipe_t *argv, int argc, const char *sep, size_t seplen)
843 | {
844 | pipe_t join = pipe_empty();
845 | int j;
846 |
847 | for (j = 0; j < argc; j++) {
848 | join = pipe_catpipe(join, argv[j]);
849 | if (j != argc-1) join = pipe_catlen(join,sep,seplen);
850 | }
851 | return join;
852 | }
--------------------------------------------------------------------------------
/src/hb_pipe.h:
--------------------------------------------------------------------------------
1 | /*
2 | * hashbase - https://github.com/MaciejCzyzewski/hashbase
3 | *
4 | * The MIT License (MIT)
5 | *
6 | * Copyright (c) 2014 Maciej A. Czyzewski
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of
9 | * this software and associated documentation files (the "Software"), to deal in
10 | * the Software without restriction, including without limitation the rights to
11 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
12 | * the Software, and to permit persons to whom the Software is furnished to do so,
13 | * subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
20 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
21 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
22 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 | *
25 | * Author: Maciej A. Czyzewski
26 | */
27 |
28 | #ifndef _HB_PIPE_H_
29 | #define _HB_PIPE_H_
30 |
31 | #include
32 | #include
33 |
34 | typedef char *pipe_t;
35 |
36 | struct pipe_hdr_t {
37 | int len;
38 | int free;
39 | char buf[];
40 | };
41 |
42 | pipe_t pipe_newlen(const void *init, size_t initlen);
43 | pipe_t pipe_new(const char *init);
44 | pipe_t pipe_empty(void);
45 | size_t pipe_len(const pipe_t s);
46 | pipe_t pipe_dup(const pipe_t s);
47 | void pipe_free(pipe_t s);
48 | size_t pipe_avail(const pipe_t s);
49 | pipe_t pipe_growzero(pipe_t s, size_t len);
50 | pipe_t pipe_catlen(pipe_t s, const void *t, size_t len);
51 | pipe_t pipe_cat(pipe_t s, const char *t);
52 | pipe_t pipe_catpipe(pipe_t s, const pipe_t t);
53 | pipe_t pipe_cpylen(pipe_t s, const char *t, size_t len);
54 | pipe_t pipe_cpy(pipe_t s, const char *t);
55 |
56 | pipe_t pipe_catvprintf(pipe_t s, const char *fmt, va_list ap);
57 | #ifdef __GNUC__
58 | pipe_t pipe_catprintf(pipe_t s, const char *fmt, ...)
59 | __attribute__((format(printf, 2, 3)));
60 | #else
61 | pipe_t pipe_catprintf(pipe_t s, const char *fmt, ...);
62 | #endif
63 |
64 | void pipe_trim(pipe_t s, const char *cset);
65 | void pipe_range(pipe_t s, int start, int end);
66 | void pipe_updatelen(pipe_t s);
67 | void pipe_clear(pipe_t s);
68 | int pipe_cmp(const pipe_t s1, const pipe_t s2);
69 | pipe_t *pipe_splitlen(const char *s, int len, const char *sep, int seplen, int *count);
70 | void pipe_freesplitres(pipe_t *tokens, int count);
71 | void pipe_tolower(pipe_t s);
72 | void pipe_toupper(pipe_t s);
73 | pipe_t pipe_fromlonglong(long long value);
74 | pipe_t pipe_catrepr(pipe_t s, const char *p, size_t len);
75 | pipe_t *pipe_splitargs(const char *line, int *argc);
76 | pipe_t pipe_mapchars(pipe_t s, const char *from, const char *to, size_t setlen);
77 | pipe_t pipe_join(char **argv, int argc, char *sep, size_t seplen);
78 | pipe_t pipe_joinpipe(pipe_t *argv, int argc, const char *sep, size_t seplen);
79 |
80 | /* Low level functions exposed to the user API */
81 | pipe_t pipe_MakeRoomFor(pipe_t s, size_t addlen);
82 | void pipe_IncrLen(pipe_t s, int incr);
83 | pipe_t pipe_RemoveFreeSpace(pipe_t s);
84 | size_t pipe_AllocSize(pipe_t s);
85 |
86 | #endif
--------------------------------------------------------------------------------
/src/hb_util.c:
--------------------------------------------------------------------------------
1 | /*
2 | * UTIL A utility functions.
3 | *
4 | * Version: @(#)util.c 0.0.1 09/07/14
5 | * Authors: Maciej A. Czyzewski,
6 | *
7 | */
8 |
9 |
--------------------------------------------------------------------------------
/src/hb_util.h:
--------------------------------------------------------------------------------
1 | /*
2 | * hashbase - https://github.com/MaciejCzyzewski/hashbase
3 | *
4 | * The MIT License (MIT)
5 | *
6 | * Copyright (c) 2014 Maciej A. Czyzewski
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of
9 | * this software and associated documentation files (the "Software"), to deal in
10 | * the Software without restriction, including without limitation the rights to
11 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
12 | * the Software, and to permit persons to whom the Software is furnished to do so,
13 | * subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
20 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
21 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
22 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 | *
25 | * Author: Maciej A. Czyzewski
26 | */
27 |
28 | #ifndef _HB_UTIL_H_
29 | #define _HB_UTIL_H_
30 |
31 | #define KB (1024)
32 | #define MB (1024 * KB)
33 | #define GB (1024 * MB)
34 |
35 | #define CRLF "\x0d\x0a"
36 |
37 | #define MIN(a, b) ((a) < (b) ? (a) : (b))
38 | #define MAX(a, b) ((a) > (b) ? (a) : (b))
39 |
40 | #define COUNT(a) (sizeof(a) / sizeof(*(a)))
41 |
42 | #endif
43 |
--------------------------------------------------------------------------------
/tests/Python/hashbase.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | import socket # hashbase
4 |
5 | class hashbase:
6 | def __init__(self):
7 | self.buffer = 1024
8 | self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
9 |
10 | def connect(self, host, port):
11 | self.host = str(host)
12 | self.port = int(port)
13 |
14 | self.socket.connect((self.host, self.port))
15 |
16 | def set(self, key, value):
17 | self.socket.send("set \"" + str(key) + "\" \"" + str(value) + "\"\r\n")
18 | return self.socket.recv(self.buffer)[:-2]
19 |
20 | def get(self, key):
21 | self.socket.send("get \"" + str(key) + "\"\r\n")
22 | return self.socket.recv(self.buffer)[:-2]
23 |
24 | def delete(self, key): # del -> delete
25 | self.socket.send("del \"" + str(key) + "\"\r\n")
26 | return self.socket.recv(self.buffer)[:-2]
--------------------------------------------------------------------------------
/tests/Python/tests.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | import hashbase # hashbase
4 | import sys
5 |
6 | if len(sys.argv) != 3:
7 | print "Usage: python tests.py "
8 | raise SystemExit
9 |
10 | # Connect
11 | hb = hashbase.hashbase()
12 | hb.connect(sys.argv[1], sys.argv[2])
13 |
14 | # Write
15 | hb.set("foo", "bar")
16 | hb.set("maciej a.", "czyzewski")
17 | hb.set("delete", "me")
18 | hb.set("plus", "minus")
19 |
20 | # Delete
21 | hb.delete("delete")
22 |
23 | # Get
24 | print hb.get("foo") # bar
25 | print hb.get("maciej a.") # czyzewski
26 | print hb.get("delete") # -1
27 | print hb.get("plus") # minus
--------------------------------------------------------------------------------
/tests/client.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | import socket # hashbase
4 | import sys
5 |
6 | ###########################################################
7 | # Command-line interface #
8 | ###########################################################
9 | # >> | Client input #
10 | # => | Server output #
11 | ###########################################################
12 |
13 | if len(sys.argv) != 3:
14 | print "Usage: python client.py "
15 | raise SystemExit
16 |
17 | TCP_IP = str(sys.argv[1])
18 | TCP_PORT = int(sys.argv[2])
19 | BUFFER_SIZE = 1024
20 |
21 | try:
22 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
23 | s.connect((TCP_IP, TCP_PORT))
24 | except:
25 | print "Error: Cannot connect to the hashbase..."
26 | raise SystemExit
27 |
28 | def run():
29 | while True:
30 | try:
31 | g = raw_input(">> ")
32 | except KeyboardInterrupt:
33 | print "Warning: Closing connection..."
34 | raise SystemExit
35 |
36 | s.send(g + "\r\n")
37 | r = s.recv(BUFFER_SIZE)[:-2]
38 | print "=>", r
39 |
40 | s.close()
41 |
42 | run()
--------------------------------------------------------------------------------