commit 0d2779e0069c78ac218d39da6d2dfdbc4bd133be Author: Alexander Vdolainen Date: Fri Nov 24 23:54:42 2017 +0200 Initial one: moving useful code to separate tiny lib; diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..05a3327 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +*~ +*.o +*.a +*.lo +*.la +*.dvi +*.synctex.gz +.deps +.libs +autom4te.cache/ +Makefile +Makefile.in +aclocal.m4 +config.guess +config.h +config.h.in +config.log +config.status +config.sub +configure +depcomp +install-sh +intltool-extract.in +intltool-merge.in +intltool-update.in +libtool +ltmain.sh +missing +mkinstalldirs +stamp-h1 +.emacs.desktop +nbproject +config.guess.dh-orig +config.sub.dh-orig +aclocal +coq +*.log +*.crt +*.pc +compile +test-driver +\#* + diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..427a65a --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ + * Alexander Vdolainen diff --git a/BUGS b/BUGS new file mode 100644 index 0000000..e69de29 diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..0a04128 --- /dev/null +++ b/COPYING @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..7b5756e --- /dev/null +++ b/ChangeLog @@ -0,0 +1,4 @@ +0.0.1 (24-nov-2017) + * initial version with all functions done + * tired from reuse this code and ... now it's lib + diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..2099840 --- /dev/null +++ b/INSTALL @@ -0,0 +1,370 @@ +Installation Instructions +************************* + +Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation, +Inc. + + Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. This file is offered as-is, +without warranty of any kind. + +Basic Installation +================== + + Briefly, the shell command `./configure && make && make install' +should configure, build, and install this package. The following +more-detailed instructions are generic; see the `README' file for +instructions specific to this package. Some packages provide this +`INSTALL' file but do not implement all of the features documented +below. The lack of an optional feature in a given package is not +necessarily a bug. More recommendations for GNU packages can be found +in *note Makefile Conventions: (standards)Makefile Conventions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. Caching is +disabled by default to prevent problems with accidental use of stale +cache files. + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You need `configure.ac' if +you want to change it or regenerate `configure' using a newer version +of `autoconf'. + + The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. + + Running `configure' might take a while. While running, it prints + some messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package, generally using the just-built uninstalled binaries. + + 4. Type `make install' to install the programs and any data files and + documentation. When installing into a prefix owned by root, it is + recommended that the package be configured and built as a regular + user, and only the `make install' phase executed with root + privileges. + + 5. Optionally, type `make installcheck' to repeat any self-tests, but + this time using the binaries in their final installed location. + This target does not install anything. Running this target as a + regular user, particularly if the prior `make install' required + root privileges, verifies that the installation completed + correctly. + + 6. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + + 7. Often, you can also type `make uninstall' to remove the installed + files again. In practice, not all packages have tested that + uninstallation works correctly, even though it is required by the + GNU Coding Standards. + + 8. Some packages, particularly those that use Automake, provide `make + distcheck', which can by used by developers to test that all other + targets like `make install' and `make uninstall' work correctly. + This target is generally not run by end users. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. Run `./configure --help' +for details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c99 CFLAGS=-g LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you can use GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. This +is known as a "VPATH" build. + + With a non-GNU `make', it is safer to compile the package for one +architecture at a time in the source code directory. After you have +installed the package for one architecture, use `make distclean' before +reconfiguring for another architecture. + + On MacOS X 10.5 and later systems, you can create libraries and +executables that work on multiple system types--known as "fat" or +"universal" binaries--by specifying multiple `-arch' options to the +compiler but only a single `-arch' option to the preprocessor. Like +this: + + ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CPP="gcc -E" CXXCPP="g++ -E" + + This is not guaranteed to produce working output in all cases, you +may have to build one architecture at a time and combine the results +using the `lipo' tool if you have problems. + +Installation Names +================== + + By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX', where PREFIX must be an +absolute file name. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. In general, the +default for these options is expressed in terms of `${prefix}', so that +specifying just `--prefix' will affect all of the other directory +specifications that were not explicitly provided. + + The most portable way to affect installation locations is to pass the +correct locations to `configure'; however, many packages provide one or +both of the following shortcuts of passing variable assignments to the +`make install' command line to change installation locations without +having to reconfigure or recompile. + + The first method involves providing an override variable for each +affected directory. For example, `make install +prefix=/alternate/directory' will choose an alternate location for all +directory configuration variables that were expressed in terms of +`${prefix}'. Any directories that were specified during `configure', +but not in terms of `${prefix}', must each be overridden at install +time for the entire installation to be relocated. The approach of +makefile variable overrides for each directory variable is required by +the GNU Coding Standards, and ideally causes no recompilation. +However, some platforms have known limitations with the semantics of +shared libraries that end up requiring recompilation when using this +method, particularly noticeable in packages that use GNU Libtool. + + The second method involves providing the `DESTDIR' variable. For +example, `make install DESTDIR=/alternate/directory' will prepend +`/alternate/directory' before all installation names. The approach of +`DESTDIR' overrides is not required by the GNU Coding Standards, and +does not work on platforms that have drive letters. On the other hand, +it does better at avoiding recompilation issues, and works well even +when some directory options were not specified in terms of `${prefix}' +at `configure' time. + +Optional Features +================= + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + + Some packages offer the ability to configure how verbose the +execution of `make' will be. For these packages, running `./configure +--enable-silent-rules' sets the default to minimal output, which can be +overridden with `make V=1'; while running `./configure +--disable-silent-rules' sets the default to verbose, which can be +overridden with `make V=0'. + +Particular systems +================== + + On HP-UX, the default C compiler is not ANSI C compatible. If GNU +CC is not installed, it is recommended to use the following options in +order to use an ANSI C compiler: + + ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" + +and if that doesn't work, install pre-built binaries of GCC for HP-UX. + + HP-UX `make' updates targets which have the same time stamps as +their prerequisites, which makes it generally unusable when shipped +generated files such as `configure' are involved. Use GNU `make' +instead. + + On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot +parse its `' header file. The option `-nodtk' can be used as +a workaround. If GNU CC is not installed, it is therefore recommended +to try + + ./configure CC="cc" + +and if that doesn't work, try + + ./configure CC="cc -nodtk" + + On Solaris, don't put `/usr/ucb' early in your `PATH'. This +directory contains several dysfunctional programs; working variants of +these programs are available in `/usr/bin'. So, if you need `/usr/ucb' +in your `PATH', put it _after_ `/usr/bin'. + + On Haiku, software installed for all users goes in `/boot/common', +not `/usr/local'. It is recommended to use the following options: + + ./configure --prefix=/boot/common + +Specifying the System Type +========================== + + There may be some features `configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, `configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS + KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + + Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). + +Unfortunately, this technique does not work for `CONFIG_SHELL' due to +an Autoconf limitation. Until the limitation is lifted, you can use +this workaround: + + CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash + +`configure' Invocation +====================== + + `configure' recognizes the following options to control how it +operates. + +`--help' +`-h' + Print a summary of all of the options to `configure', and exit. + +`--help=short' +`--help=recursive' + Print a summary of the options unique to this package's + `configure', and exit. The `short' variant lists options used + only in the top level, while the `recursive' variant lists options + also present in any nested packages. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--prefix=DIR' + Use DIR as the installation prefix. *note Installation Names:: + for more details, including other options available for fine-tuning + the installation locations. + +`--no-create' +`-n' + Run the configure checks, but stop before creating any output + files. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..409ce47 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,35 @@ +## Sample for libndbuf automaken stuff +## (c) alex@vapaa.xyz +## Process this file with automake to produce Makefile.in + +SUBDIRS = include + +clean-local: + +## what actually to build + +AM_CPPFLAGS = \ + -DPACKAGE_LOCALE_DIR=\""$(localedir)"\" \ + -DPACKAGE_SRC_DIR=\""$(srcdir)"\" \ + -DPACKAGE_DATA_DIR=\""$(pkgdatadir)"\" \ + -I$(srcdir)/include + +AM_CFLAGS =\ + -Wall\ + -g + +lib_LTLIBRARIES = libndbuf.la + + +libndbuf_la_SOURCES = \ + ndbuf.c + +libndbuf_la_LDFLAGS = + +libndbuf_la_LIBADD = + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libndbuf.pc + +EXTRA_DIST = \ + libndbuf.pc.in diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..e69de29 diff --git a/README b/README new file mode 100644 index 0000000..66e9e89 --- /dev/null +++ b/README @@ -0,0 +1,30 @@ +libndbuf: Network designed buffer ops library +---------------------------------------------- + +1. What the shit is that ? +This is a quite small library to manipulate with binary packed buffers +in a normal network manner (i.e. bigendian). It might be useful to +apply for network packet creating/parsing. +Anyway, originally this code was resided in my different other *small* +projects - and i hate copy-paste -- well, that's why it gone to +this quite small library. + +2. API +Check out include directory... +btw, might be later i will write manpages, but for now didn't see any +sense for those effort. +Generally speaking - all is quite simple - create ndbuf_t structure fill +it in printf() style, read with sscanf() style, take raw data pointer and ... +send it somewhere whatever bla bla - you get a point. + +3. Future plans +Fix bugs (but ... there are no bugs found, since this code was heavly used +already, but ... report me if found). +Write manpages (in my few projects those API is like a part of POSIX - +still cannot remember all). +Maybe will add a new functions (useful ones). + +4. Contact +That's simple - +Email/XMPP: alex@vapaa.xyz + diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..3ebea8c --- /dev/null +++ b/VERSION @@ -0,0 +1,2 @@ +0.0.1 + diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..01c075c --- /dev/null +++ b/autogen.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +echo "Generating configure files... may take a while." + +autoreconf --install --force && \ + echo "Preparing was successful if there was no error messages above." && \ + echo "Now type:" && \ + echo " ./configure && make" && \ + echo "Run './configure --help' for more information" diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..828aa87 --- /dev/null +++ b/configure.ac @@ -0,0 +1,19 @@ +dnl Process this file with autoconf to produce a configure script. + +AC_INIT(libndbuf, m4_esyscmd([tr -d '\n' < VERSION])) + +AC_CONFIG_HEADERS([config.h]) + +AM_INIT_AUTOMAKE([1.11]) + +AM_SILENT_RULES([yes]) + +AC_PROG_CC + +LT_INIT + +AC_OUTPUT([ +Makefile +libndbuf.pc +include/Makefile +]) diff --git a/include/Makefile.am b/include/Makefile.am new file mode 100644 index 0000000..59501bd --- /dev/null +++ b/include/Makefile.am @@ -0,0 +1 @@ +nobase_include_HEADERS = ndbuf/ndbuf.h diff --git a/include/ndbuf/ndbuf.h b/include/ndbuf/ndbuf.h new file mode 100644 index 0000000..d1a5687 --- /dev/null +++ b/include/ndbuf/ndbuf.h @@ -0,0 +1,161 @@ +/* + * Networking binary buffers pack/unpack library + * + * + * (c) Alexander Vdolainen 2016 + * (c) Alexander Vdolainen 2017 + * + * libtbusd is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libtbusd is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see ."; + * + */ + +#ifndef __NDBUF_H__ +#define __NDBUF_H__ + +#include + +#define NDBUF_TERMINAT 0xdeadbeef + +#define NDBUF_BURN (1 << 1) /* burn buffer data before free */ +#define NDBUF_NREA (1 << 2) /* non reallocatable buffer */ + +typedef struct __rawdatabuffer_type { + char *raw; + uint32_t rlength; /* raw buffer allocated length */ + uint32_t ulength; /* length of used allocated space */ + uint32_t curr; /* cursor for read/write operations */ + int flags; + void (*freebuf)(char *); +} ndbuf_t; + +/* variadic macro workaround */ +#define VA_APPLY_VARIADIC_MACRO(macro, tuple) macro tuple + +#define __VA_NARG__(...) \ + (__VA_NARG_(_0, ## __VA_ARGS__, __RSEQ_N()) - 1) +#define __VA_NARG_(...) \ + VA_APPLY_VARIADIC_MACRO(__VA_ARG_N, (__VA_ARGS__)) +#define __VA_ARG_N( \ + _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \ + _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \ + _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \ + _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \ + _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \ + _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \ + _61,_62,_63,N,...) N +#define __RSEQ_N() \ + 63, 62, 61, 60, \ + 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, \ + 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, \ + 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, \ + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, \ + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, \ + 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 + +/* allocation, freeing */ +/* allocate raw buffer with defaults preallocation */ +ndbuf_t *ndbuf_new(void); + +/* will do the same as ndbuf_new but will allocate given length */ +ndbuf_t *ndbuf_new_palloc(uint32_t); + +/* create ndbuf from raw buffer */ +ndbuf_t *ndbuf_new_frombuf(char *buf, size_t buf_len, void (*freebuf)(char *)); + +/* free all allocated space and buffer itself */ +void ndbuf_free(ndbuf_t *); + +/* read/write */ +/* read different types, should return the size of the + * ridden data, otherwise error occurs */ +uint32_t ndbuf_read_u8(ndbuf_t *, uint8_t *); +uint32_t ndbuf_read_u16(ndbuf_t *, uint16_t *); +uint32_t ndbuf_read_u32(ndbuf_t *, uint32_t *); +uint32_t ndbuf_read_u64(ndbuf_t *, uint64_t *); + +/* get raw data, pointer must be allocated with at least required length, + * will return size of ridden data + */ +uint32_t ndbuf_read_raw(ndbuf_t *, void *, uint32_t); + +/* write different types, should return the size of the + * written data, otherwise error occurs */ +uint32_t ndbuf_write_u8(ndbuf_t *, uint8_t); +uint32_t ndbuf_write_u16(ndbuf_t *, uint16_t); +uint32_t ndbuf_write_u32(ndbuf_t *, uint32_t); +uint32_t ndbuf_write_u64(ndbuf_t *, uint64_t); + +/* write raw data with the given length */ +uint32_t ndbuf_write_raw(ndbuf_t *, void *, uint32_t); + +/* write raw data *before* existing data */ +uint32_t ndbuf_write_raw_head(ndbuf_t *, void *, uint32_t); + +/* parse */ +int ndbuf_escan_va(ndbuf_t *b, const char *fmt, int argc, va_list ap); + +int ndbuf_escan_wot(ndbuf_t *b, const char *fmt, int argc, ...); + +#define ndbuf_escan(b, fmt, ...) \ + ndbuf_escan_wot((b), (fmt), __VA_NARG__(__VA_ARGS__), __VA_ARGS__, NDBUF_TERMINAT) + +/* print */ +uint32_t ndbuf_print_va(ndbuf_t *b, const char *fmt, int argc, va_list ap); + +uint32_t ndbuf_print_wot(ndbuf_t *b, const char *fmt, int argc, ...); + +#define ndbuf_print(b, fmt, ...) \ + ndbuf_print_wot((b), (fmt), __VA_NARG__(__VA_ARGS__), __VA_ARGS__, NDBUF_TERMINAT) + +/* misc */ +/* returns length of used space in the buffer */ +uint32_t ndbuf_length(ndbuf_t *); + +/* set used length */ +int ndbuf_setlength(ndbuf_t *, uint32_t); + +/* returns length of allocated space in the buffer */ +uint32_t ndbuf_alength(ndbuf_t *); + +/* returns length of the left data to read */ +uint32_t ndbuf_leftlength(ndbuf_t *); + +/* returns a pointer to the raw data */ +void *ndbuf_rdata(ndbuf_t *); + +/* return pointer to the data currently being read/write */ +void *ndbuf_rdatacur(ndbuf_t *); + +/* set flags to the raw buffer */ +void ndbuf_setflags(ndbuf_t *, int); + +/* exchange flags for raw buff */ +void ndbuf_exflags(ndbuf_t *, int); + +/* reset current pointer */ +void ndbuf_resetcur(ndbuf_t *); + +/* reset all the flags */ +#define ndbuf_flagsreset(a) ndbuf_exflags((a), 0) + +/* compare buffers, returns 0 if equal */ +int ndbuf_cmp(ndbuf_t *, ndbuf_t *); + +/* let the buffer to use actually used bytes, not all allocated space + * will return 0 on success (or in case if it doesn't required), + * ENOMEM or other error if fails + */ +int ndbuf_memopt(ndbuf_t *); + +#endif /* __NDBUF_H__ */ diff --git a/libndbuf.pc.in b/libndbuf.pc.in new file mode 100644 index 0000000..d84ac80 --- /dev/null +++ b/libndbuf.pc.in @@ -0,0 +1,13 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +datarootdir=@datarootdir@ +datadir=@datadir@ +includedir=@includedir@ + +Name: libndbuf +Description: Network designed binary buffer pack/unpack library +Version: @LIBNDBUF_VERSION@ +Requires: +Libs: -L${libdir} -lndbuf +Cflags: -I${includedir} diff --git a/ndbuf.c b/ndbuf.c new file mode 100644 index 0000000..00063c1 --- /dev/null +++ b/ndbuf.c @@ -0,0 +1,777 @@ +/* + * Networking binary buffers pack/unpack library + * + * (c) Alexander Vdolainen 2016 + * (c) Alexander Vdolainen 2017 + * + * libtbusd is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libtbusd is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see ."; + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +static inline uint64_t ntohll(uint64_t n) +{ +#ifdef WORDS_BIGENDIAN + return n; +#else /* WORDS_BIGENDIAN */ + return (((uint64_t)(n) << 56) | \ + (((uint64_t)(n) << 40) & 0xff000000000000ULL) | \ + (((uint64_t)(n) << 24) & 0xff0000000000ULL) | \ + (((uint64_t)(n) << 8) & 0xff00000000ULL) | \ + (((uint64_t)(n) >> 8) & 0xff000000ULL) | \ + (((uint64_t)(n) >> 24) & 0xff0000ULL) | \ + (((uint64_t)(n) >> 40) & 0xff00ULL) | \ + ((uint64_t)(n) >> 56)); +#endif /* WORDS_BIGENDIAN */ +} + +/* allocation, freeing */ +#define DEFAULT_PREALLOC_SIZE 256 +#define NDBUF_MAXLENGTH 6*(1024*1024) + +/* allocate raw buffer with defaults preallocation */ +ndbuf_t *ndbuf_new(void) +{ + ndbuf_t *b = malloc(sizeof(ndbuf_t)); + + if(!b) return NULL; + + if(!(b->raw = malloc(DEFAULT_PREALLOC_SIZE))) { + free(b); + b = NULL; + } else { + b->rlength = DEFAULT_PREALLOC_SIZE; + b->ulength = b->curr = 0; + b->flags = 0; + } + + return b; +} + +/* create ndbuf from raw buffer */ +ndbuf_t *ndbuf_new_frombuf(char *buf, size_t buf_len, void (*freebuf)(char *)) +{ + ndbuf_t *b = NULL; + + if(!buf || !buf_len) return NULL; + if(!(b = malloc(sizeof(ndbuf_t)))) return NULL; + + /* init buffer */ + b->raw = buf; + b->rlength = b->ulength = buf_len; + b->flags = b->curr = 0; + b->freebuf = freebuf; + b->flags |= NDBUF_NREA; + + return b; +} + +/* will do the same as ndbuf_new but will allocate given length */ +ndbuf_t *ndbuf_new_palloc(uint32_t alen) +{ + ndbuf_t *b = NULL; + + if(alen > NDBUF_MAXLENGTH) return NULL; + + if(!(b = malloc(sizeof(ndbuf_t)))) return NULL; + else memset(b, 0, sizeof(ndbuf_t)); + + if(!(b->raw = malloc(alen))) { + free(b); + b = NULL; + } else b->rlength = alen; + + return b; +} + +/* free all allocated space and buffer itself */ +void ndbuf_free(ndbuf_t *b) +{ + if(!b) return; + + if((b->flags & NDBUF_BURN) && b->raw) + memset(b->raw, 0, b->rlength); + + if((b->flags & NDBUF_NREA) && b->freebuf) b->freebuf(b->raw); + else if(b->raw) free(b->raw); + + if(b->flags & NDBUF_BURN) memset(b, 0, sizeof(ndbuf_t)); + free(b); + + return; +} + +/* read/write */ +/* read different types, should return the size of the + * ridden data, otherwise error occurs */ +uint32_t ndbuf_read_u8(ndbuf_t *b, uint8_t *o) +{ + uint8_t u; + + if(!b || !o) return 0; + if(!b->raw) return 0; + + if(b->curr >= b->ulength) return 0; + u = *((uint8_t*)(b->raw + b->curr)); + b->curr += sizeof(uint8_t); + *o = u; + + return sizeof(uint8_t); +} + +uint32_t ndbuf_read_u16(ndbuf_t *b, uint16_t *o) +{ + uint16_t u; + + if(!b || !o) return 0; + if(!b->raw) return 0; + + if(b->curr >= b->ulength) return 0; + if(b->curr + sizeof(uint16_t) > b->ulength) return 0; + + u = *((uint16_t *)(b->raw + b->curr)); + b->curr += sizeof(uint16_t); + *o = ntohs(u); + + return sizeof(uint16_t); +} + +uint32_t ndbuf_read_u32(ndbuf_t *b, uint32_t *o) +{ + uint32_t u; + + if(!b || !o) return 0; + if(!b->raw) return 0; + + if(b->curr >= b->ulength) return 0; + if(b->curr + sizeof(uint32_t) > b->ulength) return 0; + + u = *((uint32_t *)(b->raw + b->curr)); + b->curr += sizeof(uint32_t); + *o = ntohl(u); + + return sizeof(uint32_t); +} + +uint32_t ndbuf_read_u64(ndbuf_t *b, uint64_t *o) +{ + uint64_t u; + + if(!b || !o) return 0; + if(!b->raw) return 0; + + if(b->curr >= b->ulength) return 0; + if(b->curr + sizeof(uint64_t) > b->ulength) return 0; + + u = *((uint64_t *)(b->raw + b->curr)); + b->curr += sizeof(uint64_t); + *o = ntohll(u); + + return sizeof(uint64_t); +} + +/* get raw data, pointer must be allocated with at least required length, + * will return size of ridden data + */ +uint32_t ndbuf_read_raw(ndbuf_t *b, void *o, uint32_t rlen) +{ + if(!b || !o) return 0; + if(!rlen || !b->raw) return 0; + if(b->curr >= b->ulength) return 0; + if(b->curr + rlen > b->ulength) return 0; + + memcpy(o, (const void*)b->raw + b->curr, rlen); + b->curr += rlen; + + return rlen; +} + +static int __rdb_grow(ndbuf_t *b, uint32_t len) +{ + uint32_t rlen; + char *ne = NULL; + + if(!len) return -1; + if(b->rlength + len > NDBUF_MAXLENGTH) return -1; + + rlen = len + + (len%DEFAULT_PREALLOC_SIZE != 0 ? (DEFAULT_PREALLOC_SIZE - len%DEFAULT_PREALLOC_SIZE) : 0); + if(b->rlength + rlen > NDBUF_MAXLENGTH) rlen = len; + + rlen += b->rlength; + if(!(ne = malloc(rlen))) return -1; + + if(b->flags & NDBUF_BURN) memset(ne, 0, rlen); + + memcpy(ne, b->raw, b->ulength); + + if(b->flags & NDBUF_BURN) memset(b->raw, 0, b->rlength); + free(b->raw); + b->raw = ne; + b->rlength = rlen; + + return 0; +} + +/* write different types, should return the size of the + * written data, otherwise error occurs */ +uint32_t ndbuf_write_u8(ndbuf_t *b, uint8_t u) +{ + if(!b || !b->raw) return 0; + if(b->ulength == b->rlength) { + if(__rdb_grow(b, sizeof(uint8_t))) return 0; + } + + *(uint8_t *)(b->raw + b->ulength) = u; + b->ulength += sizeof(uint8_t); + + return sizeof(uint8_t); +} + +uint32_t ndbuf_write_u16(ndbuf_t *b, uint16_t uu) +{ + if(!b || !b->raw) return 0; + if(b->ulength + sizeof(uint16_t) >= b->rlength) { + if(__rdb_grow(b, sizeof(uint16_t))) return 0; + } + + *(uint16_t *)(b->raw + b->ulength) = htons(uu); + b->ulength += sizeof(uint16_t); + + return sizeof(uint16_t); +} + +uint32_t ndbuf_write_u32(ndbuf_t *b, uint32_t uu) +{ + if(!b || !b->raw) return 0; + if(b->ulength + sizeof(uint32_t) >= b->rlength) { + if(__rdb_grow(b, sizeof(uint32_t))) return 0; + } + + *(uint32_t *)(b->raw + b->ulength) = htonl(uu); + b->ulength += sizeof(uint32_t); + + return sizeof(uint32_t); +} + +uint32_t ndbuf_write_u64(ndbuf_t *b, uint64_t uu) +{ + if(!b || !b->raw) return 0; + if(b->ulength + sizeof(uint64_t) >= b->rlength) { + if(__rdb_grow(b, sizeof(uint64_t))) return 0; + } + + *(uint64_t *)(b->raw + b->ulength) = ntohll(uu); + b->ulength += sizeof(uint64_t); + + return sizeof(uint64_t); +} + +/* write raw data with the given length */ +uint32_t ndbuf_write_raw(ndbuf_t *b, void *wi, uint32_t len) +{ + if(!b || !b->raw) return 0; + if(!wi || !len) return 0; + if(b->ulength + len >= b->rlength) { + if(__rdb_grow(b, len)) return 0; + } + + memcpy((void *)b->raw + b->ulength, (const void *)wi, len); + b->ulength += len; + + return len; +} + +/* write raw data *before* existing data */ +uint32_t ndbuf_write_raw_head(ndbuf_t *b, void *wi, uint32_t len) +{ + char *ne; + uint32_t rlen; + + if(!b || !b->raw) return 0; + if(!wi || !len) return 0; + if(b->ulength + len > b->rlength) { + /* allocate a new one and copy it right */ + if(b->rlength + len > NDBUF_MAXLENGTH) return -1; + + rlen = len + + (len%DEFAULT_PREALLOC_SIZE != 0 ? (DEFAULT_PREALLOC_SIZE - len%DEFAULT_PREALLOC_SIZE) : 0); + if(b->rlength + rlen > NDBUF_MAXLENGTH) rlen = len; + + rlen += b->rlength; + if(!(ne = malloc(rlen))) return -1; + + if(b->flags & NDBUF_BURN) memset(ne, 0, rlen); + + memcpy((void *)ne + len, b->raw, b->ulength); + + if(b->flags & NDBUF_BURN) memset(b->raw, 0, b->rlength); + free(b->raw); + b->raw = ne; + b->rlength = rlen; + } else { + memmove((void *)b->raw + b->ulength, b->raw, b->ulength); + } + memcpy(b->raw, wi, len); + b->ulength += len; + + return len; +} + +/* parse */ +int ndbuf_escan_va(ndbuf_t *b, const char *fmt, int argc, va_list ap) +{ + va_list ap_copy; + union { + uint8_t *_u8; + uint16_t *_u16; + uint32_t *_u32; + uint64_t *_u64; + void **_dp; + char **_cstr; + ndbuf_t **_rdb; + } d; + const char *t, *last; + uint32_t len, clen; + int r, count; + + va_copy(ap_copy, ap); + + for(t = fmt, count = 0; *t != '\0'; t++, count++) { + if(count > argc && argc != -1) { + va_end(ap_copy); + return EINVAL; + } + + switch(*t) { + case 'b': + d._u8 = va_arg(ap, uint8_t *); + len = ndbuf_read_u8(b, d._u8); + r = (len == sizeof(uint8_t)) ? 0 : -1; + break; + case 'w': + d._u16 = va_arg(ap, uint16_t *); + len = ndbuf_read_u16(b, d._u16); + r = (len == sizeof(uint16_t)) ? 0 : -1; + break; + case 'd': + d._u32 = va_arg(ap, uint32_t *); + len = ndbuf_read_u32(b, d._u32); + r = (len == sizeof(uint32_t)) ? 0 : -1; + break; + case 'q': + d._u64 = va_arg(ap, uint64_t *); + len = ndbuf_read_u64(b, d._u64); + r = (len == sizeof(uint64_t)) ? 0 : -1; + break; + case 's': + d._cstr = va_arg(ap, char **); + *d._cstr = NULL; + len = ndbuf_read_u32(b, &clen); + if(len != sizeof(uint32_t)) { + __errrbread: + r = -1; + break; + } + if(clen > NDBUF_MAXLENGTH) goto __errrbread; + if((*d._cstr = malloc(clen + sizeof(char))) == NULL) { + r = -ENOMEM; + break; + } + len = ndbuf_read_raw(b, *d._cstr, clen); + if(len != clen) { + free(*d._cstr); + goto __errrbread; + } + (*d._cstr)[len] = '\0'; + d._cstr = NULL; + r = 0; + break; + case 'p': + clen = va_arg(ap, size_t); + + d._dp = va_arg(ap, void **); + *d._dp = NULL; + count++; + + if((*d._dp = malloc(clen)) == NULL) { + r = -ENOMEM; + break; + } + len = ndbuf_read_raw(b, *d._dp, clen); + if(len != clen) { + free(*d._dp); + goto __errrbread; + } + d._dp = NULL; + r = 0; + break; + case 'P': + d._dp = va_arg(ap, void **); + *d._dp = NULL; + + len = ndbuf_read_u32(b, &clen); + if(len != sizeof(uint32_t)) { + r = -1; + break; + } + if((*d._dp = malloc(clen)) == NULL) { + r = -ENOMEM; + break; + } + len = ndbuf_read_raw(b, *d._dp, clen); + if(len != clen) { + free(*d._dp); + goto __errrbread; + } + d._dp = NULL; + r = 0; + break; + case 'R': + d._rdb = va_arg(ap, ndbuf_t **); + *d._rdb = NULL; + + len = ndbuf_read_u32(b, &clen); + if(len != sizeof(uint32_t)) { + r = -1; + break; + } + /* allocate rdb and write to it */ + if((*d._rdb = ndbuf_new_palloc(clen)) == NULL) { + r = -ENOMEM; + break; + } else ndbuf_setflags(*d._rdb, NDBUF_BURN); + len = ndbuf_read_raw(b, ndbuf_rdata(*d._rdb), clen); + if(len != clen) { + ndbuf_free(*d._dp); + goto __errrbread; + } else ndbuf_setlength(*d._rdb, clen); + + d._rdb = NULL; + r = 0; + break; + } + + if(r) break; + } + + if(argc != -1 && argc != count) r = -EINVAL; + + if(!r) { + clen = va_arg(ap, uint32_t); + if(clen != NDBUF_TERMINAT) { + if(argc == -1) r = -EINVAL; + else abort(); + } + } + + /* clean up all the stuff on error */ + if(r) { + last = t; + for(t = fmt; t < last; ++t) { + switch(*t) { + case 'b': + case 'w': + case 'd': + case 'q': + (void)va_arg(ap_copy, void *); + break; + case 's': + d._cstr = va_arg(ap_copy, char **); + if(*d._cstr) { + memset(*d._cstr, 0, strlen(*d._cstr)); + free(*d._cstr); + } + break; + case 'R': + d._rdb = va_arg(ap_copy, ndbuf_t **); + if(*d._rdb) ndbuf_free(*d._rdb); + break; + case 'p': + (void)va_arg(ap_copy, size_t); + case 'P': + d._dp = va_arg(ap_copy, void **); + if(*d._dp) free(*d._dp); + break; + default: + (void)va_arg(ap_copy, void *); + break; + } + } + } + va_end(ap_copy); + + return r; +} + +int ndbuf_escan_wot(ndbuf_t *b, const char *fmt, int argc, ...) +{ + va_list ap; + int r; + + va_start(ap, argc); + r = ndbuf_escan_va(b, fmt, argc, ap); + va_end(ap); + + return r; +} + +/* print FIXME: TODO: add errno setting upon failure */ +uint32_t ndbuf_print_va(ndbuf_t *b, const char *fmt, int argc, va_list ap) +{ + const char *t; + char *cstr; + ndbuf_t *rdb; + union { + uint8_t _u8; + uint16_t _u16; + uint32_t _u32; + uint64_t _u64; + void *_dp; + } d; + uint32_t len = 0, clen; + int r, count; + + for(t = fmt, count = 0; *t != '\0'; t++, count++) { + if(count > argc && argc != -1) return 0; + switch(*t) { + case 'b': + d._u8 = (uint8_t)va_arg(ap, unsigned int); + r = ndbuf_write_u8(b, d._u8); + if(r != sizeof(uint8_t)) return 0; + else len += r; + break; + case 'w': + d._u16 = (uint16_t)va_arg(ap, unsigned int); + r = ndbuf_write_u16(b, d._u16); + if(r != sizeof(uint16_t)) return 0; + else len += r; + break; + case 'd': + d._u32 = (uint32_t)va_arg(ap, uint32_t); + r = ndbuf_write_u32(b, d._u32); + if(r != sizeof(uint32_t)) return 0; + else len += r; + break; + case 'q': + d._u64 = (uint64_t)va_arg(ap, uint64_t); + r = ndbuf_write_u64(b, d._u64); + if(r != sizeof(uint64_t)) return 0; + else len += r; + break; + case 's': + cstr = (char *)va_arg(ap, char *); + clen = strlen(cstr); + r = ndbuf_write_u32(b, (uint32_t)clen); + if(r != sizeof(uint32_t)) return 0; + else len += r; + r = ndbuf_write_raw(b, cstr, clen); + if(r != clen) return 0; + else len += clen; + break; + case 'R': + rdb = (ndbuf_t *)va_arg(ap, ndbuf_t *); + clen = ndbuf_length(rdb); + r = ndbuf_write_u32(b, (uint32_t)clen); + if(r != sizeof(uint32_t)) return 0; + else len += r; + r = ndbuf_write_raw(b, ndbuf_rdata(rdb), (uint32_t)clen); + if(r != clen) return 0; + else len += clen; + break; + case 'P': + clen = va_arg(ap, size_t); + d._dp = va_arg(ap, void *); + count++; + r = ndbuf_write_u32(b, (uint32_t)clen); + if(r != sizeof(uint32_t)) return 0; + else len += r; + r = ndbuf_write_raw(b, d._dp, (uint32_t)clen); + if(r != clen) return 0; + else len += clen; + break; + case 'p': + clen = va_arg(ap, size_t); + d._dp = va_arg(ap, void *); + count++; + r = ndbuf_write_raw(b, d._dp, (uint32_t)clen); + if(r != clen) return 0; + else len += clen; + break; + default: + return 0; + break; + } + } + + if(argc != count && argc != -1) return 0; + + clen = va_arg(ap, uint32_t); + if(clen != NDBUF_TERMINAT) { + if(argc == -1) return 0; + else abort(); /* corruption */ + } + + return len; +} + +uint32_t ndbuf_print_wot(ndbuf_t *b, const char *fmt, int argc, ...) +{ + va_list ap; + uint32_t wrl; + + va_start(ap, argc); + wrl = ndbuf_print_va(b, fmt, argc, ap); + va_end(ap); + + return wrl; +} + +/* misc */ +/* returns length of used space in the buffer */ +uint32_t ndbuf_length(ndbuf_t *b) +{ + if(!b || !b->raw) return 0; + + return b->ulength; +} + +/* returns length of allocated space in the buffer */ +uint32_t ndbuf_alength(ndbuf_t *b) +{ + if(!b || !b->raw) return 0; + + return b->rlength; +} + +/* returns length of the left data to read */ +uint32_t ndbuf_leftlength(ndbuf_t *b) +{ + if(!b || !b->raw) return 0; + if(b->curr > b->ulength) return 0; + + return b->ulength - b->curr; +} + +/* reaturn a pointer to the raw data */ +void *ndbuf_rdata(ndbuf_t *b) +{ + if(!b || !b->raw) return NULL; + + return (void *)b->raw; +} + +/* return pointer to the data currently being read/write */ +void *ndbuf_rdatacur(ndbuf_t *b) +{ + if(!b || !b->raw) return NULL; + + if(b->curr >= b->ulength) return NULL; + + return (void *)(b->raw + b->curr); +} + +/* reset current pointer */ +void ndbuf_resetcur(ndbuf_t *b) +{ + if(!b || b->raw) return; + else b->curr = 0; + + return; +} + +/* set flags to the raw buffer */ +void ndbuf_setflags(ndbuf_t *b, int af) +{ + if(!b) return; + + b->flags |= af; + + return; +} + +/* exchange flags for raw buff */ +void ndbuf_exflags(ndbuf_t *b, int nf) +{ + if(!b) return; + + b->flags = nf; + + return; +} + +int ndbuf_setlength(ndbuf_t *b, uint32_t s) +{ + if(!b) return EINVAL; + + if(s > b->rlength) return EINVAL; + else b->ulength = s; + + return 0; +} + +/* compare buffers, returns 0 if equal */ +int ndbuf_cmp(ndbuf_t *b1, ndbuf_t *b2) +{ + int c = 0; + + if(!b1 | !b2) return -1; + + if((c = ndbuf_length(b1) - ndbuf_length(b2)) != 0) return c; + else c = memcmp((const void *)ndbuf_rdata(b1), + (const void *)ndbuf_rdata(b2), + ndbuf_length(b1)); + + return c; +} + + +/* let the buffer to use actually used bytes, not all allocated space + * will return 0 on success (or in case if it doesn't required), + * ENOMEM or other error if fails + */ +int ndbuf_memopt(ndbuf_t *b) +{ + uint32_t len; + char *ne; + + if(!b || !b->raw) return EINVAL; + + if((b->rlength - b->ulength) > DEFAULT_PREALLOC_SIZE) { + len = b->ulength + + (b->ulength%DEFAULT_PREALLOC_SIZE != 0 ? + (DEFAULT_PREALLOC_SIZE - b->ulength%DEFAULT_PREALLOC_SIZE) : 0); + if(!(ne = malloc(len))) return ENOMEM; + + if(b->flags & NDBUF_BURN) memset(ne, 0, len); + memcpy(ne, b->raw, b->ulength); + if(b->flags & NDBUF_BURN) memset(b->raw, 0, b->ulength); + free(b->raw); + b->raw = ne; + b->rlength = len; + } + + return 0; +} + +#undef DEFAULT_PREALLOC_SIZE