File:  [ELWIX - Embedded LightWeight unIX -] / libaitio / inc / aitio.h
Revision 1.12: download - view: text, annotated - select for diffs - revision graph
Mon Oct 31 13:53:51 2011 UTC (12 years, 7 months ago) by misho
Branches: MAIN
CVS tags: io2_2, IO2_1, HEAD
ver 2.1

/*************************************************************************
* (C) 2010 AITNET ltd - Sofia/Bulgaria - <misho@aitnet.org>
*  by Michael Pounov <misho@elwix.org>
*
* $Author: misho $
* $Id: aitio.h,v 1.12 2011/10/31 13:53:51 misho Exp $
*
**************************************************************************
The ELWIX and AITNET software is distributed under the following
terms:

All of the documentation and software included in the ELWIX and AITNET
Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>

Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
	by Michael Pounov <misho@elwix.org>.  All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in the
   documentation and/or other materials provided with the distribution.
3. All advertising materials mentioning features or use of this software
   must display the following acknowledgement:
This product includes software developed by Michael Pounov <misho@elwix.org>
ELWIX - Embedded LightWeight unIX and its contributors.
4. Neither the name of AITNET nor the names of its contributors
   may be used to endorse or promote products derived from this software
   without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
*/
#ifndef __AITIO_H
#define __AITIO_H


#define COMPAT_43TTY

#include <assert.h>
#include <openssl/evp.h>
#include <openssl/aes.h>
#include <sys/tty.h>
#include <sys/ioctl_compat.h>


#define VACUUM_LEFT	1
#define VACUUM_BETWEEN	2

/* AIT arrays */

typedef void ** sarr_seg_t;
typedef struct _tagSplitArray {
	int		sarr_num;
	int		sarr_seg;
	int		sarr_siz;
	sarr_seg_t	*sarr_data;
} sarr_t;

typedef struct _tagArray {
	int	arr_num;
	void	**arr_data;
} array_t;

/* URL staff ... */

typedef struct _tagURLItem {
	int	vallen;
	char	*value;
} url_Item_t;

struct tagIOURL {
	unsigned char	url_line[BUFSIZ];

	url_Item_t	url_tech;
	url_Item_t	url_user;
	url_Item_t	url_pass;
	url_Item_t	url_host;
	url_Item_t	url_port;
	url_Item_t	url_path;
	url_Item_t	url_args;

	char		*url_reserved;
};

struct tagReqXML {
	unsigned char	xml_line[BUFSIZ];

	url_Item_t	xml_namespace;
	union {
		url_Item_t	container;
		url_Item_t	path;
	}		xml_node;
	url_Item_t	xml_data;
	url_Item_t	xml_attribute;
	url_Item_t	xml_value;
};

/* AIT RPC variables and managment */

typedef enum {
	empty, 				/* empty -> variable is not set */
	buffer, string, blob, 		/* buffer -> uint8_t*; string -> int8_t*; blob -> void*(+socket); */
	f32, f64, 			/* float -> f32; double -> f64 */
	u8, u16, u32, u64,		/* unsigned integers ... */
	i8, i16, i32, i64,		/* integers ... */
} ait_type_t;

typedef struct {
	uint8_t		val_type;
	uint32_t	val_len;
	union {
		uint64_t	net;

		uint8_t		*buffer;
		int8_t		*string;
		uint32_t	blob;
		float		f32;
		double		f64;
		uint8_t		u8;
		uint16_t	u16;
		uint32_t	u32;
		uint64_t	u64;
		int8_t		i8;
		int16_t		i16;
		int32_t		i32;
		int64_t		i64;
	} val;
} __packed ait_val_t;

#define AIT_TYPE(_vl)			((ait_type_t) (_vl)->val_type)
#define AIT_LEN(_vl)			(_vl)->val_len
#define AIT_BLOB_CHUNKS(_vl, _n)	(assert((_vl)), AIT_LEN((_vl)) / _n + (AIT_LEN((_vl)) % _n) ? 1 : 0)
#define AIT_ISEMPTY(_vl)		(assert((_vl)), AIT_TYPE((_vl)) == empty)

#define AIT_GET_BUF(_vl)		(assert((_vl)), assert(AIT_TYPE((_vl)) == buffer), (_vl)->val.buffer)
#define AIT_GET_STR(_vl)		(assert((_vl)), assert(AIT_TYPE((_vl)) == string), (_vl)->val.string)
#define AIT_GET_BLOB(_vl)		(assert((_vl)), assert(AIT_TYPE((_vl)) == blob), (_vl)->val.blob)
#define AIT_GET_U8(_vl)			(assert((_vl)), assert(AIT_TYPE((_vl)) == u8), (_vl)->val.u8)
#define AIT_GET_U16(_vl)		(assert((_vl)), assert(AIT_TYPE((_vl)) == u16), (_vl)->val.u16)
#define AIT_GET_U32(_vl)		(assert((_vl)), assert(AIT_TYPE((_vl)) == u32), (_vl)->val.u32)
#define AIT_GET_U64(_vl)		(assert((_vl)), assert(AIT_TYPE((_vl)) == u64), (_vl)->val.u64)
#define AIT_GET_I8(_vl)			(assert((_vl)), assert(AIT_TYPE((_vl)) == i8), (_vl)->val.i8)
#define AIT_GET_I16(_vl)		(assert((_vl)), assert(AIT_TYPE((_vl)) == i16), (_vl)->val.i16)
#define AIT_GET_I32(_vl)		(assert((_vl)), assert(AIT_TYPE((_vl)) == i32), (_vl)->val.i32)
#define AIT_GET_I64(_vl)		(assert((_vl)), assert(AIT_TYPE((_vl)) == i64), (_vl)->val.i64)
#define AIT_GET_F32(_vl)		(assert((_vl)), assert(AIT_TYPE((_vl)) == f32), (_vl)->val.f32)
#define AIT_GET_F64(_vl)		(assert((_vl)), assert(AIT_TYPE((_vl)) == f64), (_vl)->val.f64)

#define AIT_SET_BUF(_vl, _v, _len)	do { ait_val_t *__val = (_vl); assert(__val); assert((_v)); \
						__val->val.buffer = malloc(_len); \
						if (__val->val.buffer) { \
							__val->val_type = buffer; AIT_LEN(__val) = _len; \
							memcpy(__val->val.buffer, (_v), _len); \
						} } while (0)
#define AIT_SET_STR(_vl, _v)		do { ait_val_t *__val = (_vl); assert(__val); assert((_v)); \
						__val->val.string = (int8_t*) strdup((_v)); \
						if (__val->val.string) { \
							__val->val_type = string; \
							AIT_LEN(__val) = strlen((_v)) + 1; \
						} } while (0)
#define AIT_SET_BLOB(_vl, _n, _len)	do { ait_val_t *__val = (_vl); assert(__val); \
						__val->val_type = blob; AIT_LEN(__val) = _len; \
						__val->val.blob = _n; } while (0)
#define AIT_SET_BLOB2(_vl, _bv)		do { ait_val_t *__val = (_vl); assert(__val); assert((_bv)); \
						__val->val_type = blob; AIT_LEN(__val) = (_bv)->blob_len; \
						__val->val.blob = (_bv)->blob_var; } while (0)
#define AIT_NEW_BLOB(_vl, _len)		AIT_SET_BLOB((_vl), 0, _len)

#define AIT_SET_U8(_vl, _n)		do { ait_val_t *__val = (_vl); assert(__val); \
						__val->val_type = u8; __val->val.u8 = _n; \
						AIT_LEN(__val) = sizeof(uint8_t); } while (0)
#define AIT_SET_U16(_vl, _n)		do { ait_val_t *__val = (_vl); assert(__val); \
						__val->val_type = u16; __val->val.u16 = _n; \
						AIT_LEN(__val) = sizeof(uint16_t); } while (0)
#define AIT_SET_U32(_vl, _n)		do { ait_val_t *__val = (_vl); assert(__val); \
						__val->val_type = u32; __val->val.u32 = _n; \
						AIT_LEN(__val) = sizeof(uint32_t); } while (0)
#define AIT_SET_U64(_vl, _n)		do { ait_val_t *__val = (_vl); assert(__val); \
						__val->val_type = u64; __val->val.u64 = _n; \
						AIT_LEN(__val) = sizeof(uint64_t); } while (0)
#define AIT_SET_I8(_vl, _n)		do { ait_val_t *__val = (_vl); assert(__val); \
						__val->val_type = i8; __val->val.i8 = _n; \
						AIT_LEN(__val) = sizeof(int8_t); } while (0)
#define AIT_SET_I16(_vl, _n)		do { ait_val_t *__val = (_vl); assert(__val); \
						__val->val_type = i16; __val->val.i16 = _n; \
						AIT_LEN(__val) = sizeof(int16_t); } while (0)
#define AIT_SET_I32(_vl, _n)		do { ait_val_t *__val = (_vl); assert(__val); \
						__val->val_type = i32; __val->val.i32 = _n; \
						AIT_LEN(__val) = sizeof(int32_t); } while (0)
#define AIT_SET_I64(_vl, _n)		do { ait_val_t *__val = (_vl); assert(__val); \
						__val->val_type = i64; __val->val.i64 = _n; \
						AIT_LEN(__val) = sizeof(int64_t); } while (0)
#define AIT_SET_F32(_vl, _n)		do { ait_val_t *__val = (_vl); assert(__val); \
						__val->val_type = f32; __val->val.f32 = _n; \
						AIT_LEN(__val) = sizeof(float); } while (0)
#define AIT_SET_F64(_vl, _n)		do { ait_val_t *__val = (_vl); assert(__val); \
						__val->val_type = f64; __val->val.f64 = _n; \
						AIT_LEN(__val) = sizeof(double); } while (0)

					/* if attribute zeroCopy is set not execute free() */
#define AIT_FREE_VAL(_vl)		do { ait_val_t *__val = (_vl); assert(__val); \
						switch (__val->val_type) { \
							case buffer: \
								if (__val->val.buffer) { \
									free(__val->val.buffer); \
									__val->val.buffer = NULL; \
								} \
								break; \
							case string: \
								if (__val->val.string) { \
									free(__val->val.string); \
									__val->val.string = NULL; \
								} \
								break; \
							default: \
								break; \
						} \
						__val->val_type = empty; \
						AIT_LEN(__val) = 0; \
					} while (0)

struct io_ether_addr {
	u_int8_t ether_addr_octet[6];
};


// io_GetErrno() Get error code of last operation
inline int io_GetErrno();
// io_GetError() Get error text of last operation
inline const char *io_GetError();


/*
 * io_ether_ntoa() Convert ethernet address to string
 * @n = ethernet address structure, like struct ether_addr
 * @a = string
 * @len = string length
 * return: NULL error or !=NULL string a
 */
inline char *io_ether_ntoa(const struct io_ether_addr *n, char * __restrict a, int len);
/*
 * io_ether_aton() Convert string to ethernet address
 * @a = string
 * @e = ethernet address structure, like struct ether_addr
 * return: NULL error or !=NULL ethernet address structure
 */
inline struct io_ether_addr *io_ether_aton(const char *a, struct io_ether_addr *e);

/*
 * io_vals2buffer() Marshaling data from array with variables to buffer
 * @buf = Buffer
 * @buflen = Size of buffer
 * @vars = Variable array
 * return: -1 error, 0 nothing done or >0 size of marshaled data
 */
int io_vals2buffer(unsigned char *buf, int buflen, array_t *vars);
/*
 * io_buffer2vals() De-marshaling data from buffer to array with variables
 * @buf = Buffer
 * @buflen = Size of buffer
 * @vnum = Number of variables into buffer
 * @zcpy = Zero-copy for variables, if !=0 don't use io_arrayFree() for free variables and 
 		*DON'T MODIFY OR DESTROY BUFFER*. =0 call io_arrayFree() before io_arrayDestroy()
 * return: =NULL error, !=NULL allocated variable array, after use must free with io_arrayDestroy()
 */
array_t *io_buffer2vals(unsigned char *buf, int buflen, int vnum, int zcpy);
/*
 * io_vals2map() Marshaling data from array with variables to memory map
 * @buf = Buffer
 * @buflen = Size of buffer
 * @vars = Variable array
 * return: -1 error, 0 nothing done or >0 size of marshaled data
 */
int io_vals2map(u_char *buf, int buflen, array_t *vars);
/*
 * io_map2vals() De-marshaling data from memory map to array with variables
 * @buf = Buffer
 * @buflen = Size of buffer
 * @vnum = Number of variables into buffer
 * @zcpy = Zero-copy for variables, if !=0 don't use io_arrayFree() for free variables and 
 		*DON'T MODIFY OR DESTROY BUFFER*. =0 call io_arrayFree() before io_arrayDestroy()
 * return: =NULL error, !=NULL allocated variable array, after use must free with io_arrayDestroy()
 */
array_t *io_map2vals(u_char *buf, int buflen, int vnum, int zcpy);

/*
 * ioPromptRead() Read data from input h[0] with prompt to output h[1]
 * @h = file handles h[0] = input, h[1] = output, if NULL use stdin, stdout
 * @csPrompt = Prompt before input, may be NULL
 * @psData = Readed data
 * @dataLen = Length of data
 * return: 0 EOF; -1 error:: can`t read; >0 count of readed chars
*/
int ioPromptRead(int *h, const char *csPrompt, char * __restrict psData, int dataLen);
/*
 * ioPromptPassword() Read password from input h[0] with prompt to output h[1]
 * @h = file handles h[0] = input, h[1] = output, if NULL use stdin, stdout
 * @csPrompt = Prompt before input, may be NULL
 * @psPass = Readed password
 * @passLen = Length of password
 * @confirm = Confirm password, 0 - get password, !=0 Ask for confirmation
 * return: 0 EOF; -1 error:: can`t read; >0 count of readed chars
*/
int ioPromptPassword(int *h, const char *csPrompt, char * __restrict psPass, int passLen, int confirm);

/*
 * ioRegexVerify() Function for verify data match in regex expression
 * @csRegex = Regulare expression pattern
 * @csData = Data for check and verify
 * @startPos = Return start positions
 * @endPos = Return end positions
 * return: NULL not match or error; !=NULL begin of matched data
*/
const char *ioRegexVerify(const char *csRegex, const char *csData, int *startPos, int *endPos);
/*
 * ioRegexGet() Function for get data match in regex expression
 * @csRegex = Regulare expression pattern
 * @csData = Data from get
 * @psString = Returned string if match
 * @strLen = Length of string
 * return: 0 not match; >0 count of returned chars
*/
int ioRegexGet(const char *csRegex, const char *csData, char * __restrict psString, int strLen);
/*
 * ioRegexReplace() Function for replace data match in regex expression with newdata
 * @csRegex = Regulare expression pattern
 * @csData = Source data
 * @csNew = Data for replace
 * return: NULL not match or error; !=NULL allocated new string, must be free after use!
*/
char *ioRegexReplace(const char *csRegex, const char *csData, const char *csNew);

/*
 * ioVarAst() Function for evaluate string like asterisk variable "{text[:[-]#[:#]]}"
 * @csString = Input string
 * return: NULL error, !=NULL Allocated new string evaluated from input string, must be free()
*/
char *ioVarAst(const char *csString);

/*
 * io_Path2File() Parse and make path/filename pair
 * @csArgs = Input argument line
 * @psPath = Output Path, if ==NULL path not returned
 * @pathLen = Size of path array
 * @psFile = Output File
 * @fileLen = Size of file array
 * return: 0 error format; -1 error:: can`t read; >0 ok, number of readed items
*/
inline int io_Path2File(const char * __restrict csArgs, char * __restrict psPath, int pathLen, 
		char * __restrict psFile, int fileLen);

/*
 * io_UnquotStr() Remove quots from input text string 
 * @psLine = Text string
 * return: 0 nothing to do; 1 successful unquoted string
*/
inline int io_UnquotStr(unsigned char * __restrict psLine);
/*
 * io_LTrimStr() Remove left whitespaces from text string
 * @psLine = Text string
 * return: 0 nothing to do; !=0 Removed bytes
*/
inline int io_LTrimStr(unsigned char * __restrict psLine);
/*
 * io_RTrimStr() Remove right whitespaces from text string
 * @psLine = Text string
 * return: 0 nothing to do; !=0 Removed bytes
*/
inline int io_RTrimStr(unsigned char * __restrict psLine);
/*
 * io_TrimStr() Remove left and right whitespaces from text string
 * @psLine = Text string
 * return: 0 nothing to do; !=0 Removed bytes
*/
inline int io_TrimStr(unsigned char * __restrict psLine);
/*
 * io_Ch2Hex() Convert from Char string to Hex string
 * @psLine = Text string
 * @lineLen = Length of Text string
 * return: NULL nothing to do or error; !=0 Allocated new converted data without term\0 (must be free)
*/
inline unsigned char *io_Ch2Hex(unsigned char *psLine, int lineLen);
/*
 * io_Hex2Ch() Convert from Hex string to Char string
 * @psLine = Text string
 * @lineLen = Length of Text string
 * return: NULL nothing to do or error; !=0 Allocated new converted string(must be free)
*/
inline char *io_Hex2Ch(unsigned char *psLine, int lineLen);

/*
 * io_arrayInit() - Create and initialize dynamic array
 * @numItems = Number of Items
 * return: NULL error, != NULL allocated memory for array
 */
inline array_t *io_arrayInit(int numItems);
/*
 * io_arrayDestroy() - Free and destroy dynamic array
 * @parr = Array
 * return: none
 */
inline void io_arrayDestroy(array_t ** __restrict parr);
/*
 * io_arrayFree() - Free all data in dynamic array items
 *	(WARNING! If assign static array dont use this!!!)
 * @arr = Array
 * return: none
 */
inline void io_arrayFree(array_t * __restrict arr);
/*
 * io_arrayFrom() - Create and fill array from array with pointers
 * @pargv = Array with pointers
 * @argc = Number of Items, if 0 walk through argv and stop when reach NULL item
 * return: NULL error, != NULL allocated new array
 */
inline array_t *io_arrayFrom(const char *** __restrict pargv, int argc);
/*
 * io_arrayTo() - Create and fill array with pointers from dynamic array
 * @arr = Array
 * return: NULL error, != NULL allocated memory for array, NULL terminated
 */
inline char **io_arrayTo(array_t * __restrict arr);
/*
 * io_arrayLen() - Get last used element in dynamic array (array Length)
 * @arr = Array
 * return: -1 error, 0 empty or >0 position of last used element
 */
inline int io_arrayLen(array_t * __restrict arr);
/*
 * io_arrayConcat() Concat source array to destination array
 * @dest = Destination array
 * @src = Source array
 * return: -1 error; >0 new count of destination array
 */
int io_arrayConcat(array_t * __restrict dest, array_t * __restrict src);
/*
 * io_arrayCopy() Copy source array to destination array
 * @dest = Destination array, after use free with io_arrayDestroy()
 * @src = Source array
 * return: -1 error; >0 count of destination array
 */
int io_arrayCopy(array_t ** __restrict dest, array_t * __restrict src);
/*
 * io_arrayGrow() - Grow/Shrink dynamic array, Use with care when it shrink!!!
 * @arr = Array
 * @newNumItems = Number of Items
 * @freeShrink = Free elements before shrink array
 * return: -1 error, 0 ok
 */
int io_arrayGrow(array_t * __restrict arr, int newNumItems, int freeShrink);
/*
 * io_arrayVacuum() - Vacuum dynamic array, empty elements will be deleted
 * @arr = Array
 * @fromWhere = 1 begin, 2 ALL empty elements
 * return: -1 error, 0 ok
 */
int io_arrayVacuum(array_t * __restrict arr, int fromWhere);

#define io_arraySize(_arr)		((_arr) ? (_arr)->arr_num : 0)
#define io_arrayZero(_arr)		(assert((_arr)), memset((_arr)->arr_data, 0, \
						io_arraySize((_arr)) * sizeof(void*)))

#define io_arrayGet(_arr, _d)		(assert((_arr) && (_arr)->arr_num > _d), *((_arr)->arr_data + _d))
#define io_array(_arr, _d, _type)	(assert((_arr) && (_arr)->arr_num > _d), \
						((_type) *((_arr)->arr_data + _d)))
#define io_arraySet(_arr, _d, _ptr)	do { \
						assert((_arr) && (_arr)->arr_num > _d); \
						*((_arr)->arr_data + _d) = (void*) (_ptr); \
					} while (0)
#define io_arrayDel(_arr, _d, _fri)	do { \
						assert((_arr) && (_arr)->arr_num > _d); \
						if (_fri) \
							free(*((_arr)->arr_data + _d)); \
						*((_arr)->arr_data + _d) = NULL; \
					} while (0)

/*
 * io_arrayPush() - Push element into dynamic array like stack manner, place at first empty position
 * @arr = Array
 * @data = Element, if set NULL return only first empty position
 * return: -1 not found empty position, array is full!, >-1 return position of stored element into array
 */
inline int io_arrayPush(array_t * __restrict arr, void **data);
/*
 * io_arrayPop() - Pop element from dynamic array like stack manner, last used position
 * @arr = Array
 * @data = Element, if set NULL return only last used position
 * @delAfter = Delete after Pop element, !=0 delete element from array after return data
 * return: -1 not found used position, array is empty!, >-1 return element position
 */
inline int io_arrayPop(array_t * __restrict arr, void ** __restrict data, int delAfter);

/*
 * io_argsNum() Parse and calculate number of arguments
 * @csArgs = Input arguments line
 * @csDelim = Delimiter(s) for separate
 * return: 0 error format; -1 error:: can`t read; >0 ok, number of items
 */
inline int io_argsNum(const char *csArgs, const char *csDelim);

/*
 * io_arrayMake() Parse and make array from arguments ... (input string will be modified!!! 
 *	and output array must be free with io_arrayDestroy() after use!)
 * @psArgs = Input arguments line, after execute string is modified!!!
 * @nargs = Maximum requested count of arguments from input string psArgs, if 0 all psArgs
 * @csDelim = Delimiter(s) for separate
 * @parr = Output array of arguments ... (must be free with io_arrayDestroy() after use!)
 * return: 0 error format; -1 error:: can`t read; >0 ok, number of readed items
 */
int io_arrayMake(char * __restrict psArgs, int nargs, const char *csDelim, 
		array_t ** __restrict parr);

/*
 * io_MakeAV() Parse and make attribute/value pair
 * @csArgs = Input argument line
 * @csDelim = Delimiter for separate
 * @psAttr = Output Attribute
 * @attrLen = Size of attribute array
 * @psValue = Output Value, if ==NULL this element not present value or not wanted for return
 * @valLen = Size of value array
 * return: 0 error format; -1 error:: can`t read; >0 ok, number of readed items
*/
int io_MakeAV(const char * __restrict csArgs, const char *csDelim, 
		char * __restrict psAttr, int attrLen, char * __restrict psValue, int valLen);

/*
 * io_sarrInit() - Create and initialize dynamic split-order array
 * @numItems = Number of Items
 * @segLen = Length of segment
 * return: NULL error, != NULL allocated memory for array
 */
inline sarr_t *io_sarrInit(int numItems, int segLen);
/*
 * io_sarrDestroy() - Free all data in dynamic split-order array and Destroy array
 * @parr = Array
 * return: none
 */
inline void io_sarrDestroy(sarr_t ** __restrict parr);
/*
 * io_sarrGrow() - Grow/Shrink dynamic split-order array, Use with care when it shrink!!!
 * @arr = Array
 * @newNumItems = Number of Items
 * return: -1 error, 0 ok
 */
int io_sarrGrow(sarr_t * __restrict arr, int newNumItems);
/*
 * io_sarrVacuum() - Vacuum dynamic split-order array, empty segments will be freed
 * @arr = Array
 * return: -1 error, >-1 freed segments
 */
inline int io_sarrVacuum(sarr_t * __restrict arr);
#define io_sarrSize(_arr)		((_arr) ? (_arr)->sarr_num : 0)
#define io_sarrSeg(_arr)		(assert((_arr)), (_arr)->sarr_seg)
/*
 * io_sarrCopy() Copy source split array to destination split array
 * @dest = Destination split array, after use free with io_sarrDestroy()
 * @src = Source split array
 * return: -1 error; >0 count of destination split array
 */
int io_sarrCopy(sarr_t ** __restrict dest, sarr_t * __restrict src);
/*
 * io_sarrGet() - Get element from dynamic split-order array
 * @arr = Array
 * @idx = Index (warning 1st element is at position 1)
 * return: NULL not found, !=NULL element
 */
inline void *io_sarrGet(sarr_t * __restrict arr, unsigned int idx);
/*
 * io_sarrGet2() - Always get element from dynamic split-order array
 *	Function automatic grow array. Good use for Hash tables! 
 * @arr = Array
 * @idx = Index (warning 1st element is at position 1)
 * return: NULL not found, !=NULL element
 */
void *io_sarrGet2(sarr_t * __restrict arr, unsigned int idx);
/*
 * io_sarrSet() - Set element to dynamic split-order array
 * @arr = Array
 * @idx = Index (warning 1st element is at position 1)
 * @data = Value
 * return: NULL error or empty, !=NULL old value in element
 */
inline void *io_sarrSet(sarr_t * __restrict arr, unsigned int idx, void *data);
#define io_sarrDel(_arr, _idx)		io_sarrSet((_arr), _idx, NULL)
#define io_sarr(_arr, _idx, _type)	(_type)io_sarrGet((_arr), _idx)
/*
 * io_sarr2array() - Convert from split-order array to dynamic array
 * @sa = split array
 * @sarrFree = after convert split array !=0 will be destroyed sarray
 * return: NULL error or != NULL new array
 */
array_t *io_sarr2array(sarr_t ** __restrict sa, int sarrFree);
/*
 * io_array2sarr() - Convert from dynamic array to split-order array
 * @a = array
 * @segLen = Length of segment
 * @arrFree = after convert array !=0 will be destroyed
 * return: NULL error or != NULL new sarr
 */
sarr_t *io_array2sarr(array_t ** __restrict a, int segLen, int arrFree);

/*
 * io_CopyEnv() Copy environment to new environment array;
 * @oldenv = Environment array
 * return: NULL error; !=NULL Allocated new environment array(must be free)
*/
char **io_CopyEnv(const char **oldenv);
/*
 * io_ExecArgs() Build exec arguments from other array
 * @psProg = Program name for execute
 * @oldarg = Arguments array
 * return: NULL error; !=NULL Allocated execution array(must be free)
*/
char **io_ExecArgs(const char *psProg, const char **oldarg);
/*
 * io_FreeNullTerm() Free dynamic allocated null terminated array with strings
 * @arr = Pointer to array for free
 * return: none
*/
inline void io_FreeNullTerm(char *** __restrict arr);

/*
 * ioURLGet() Parse and get data from input URL
 * @csURL = Input URL line
 * @url = Output parsed URL
 * return: 0 error format not find tech:// and return URL like path; 
 		-1 error:: can`t read; >0 ok, up bits for known elements
*/
int ioURLGet(const char *csURL, struct tagIOURL *url);
/*
 * ioURLGetValue() Get value from parsed URL
 * @url = Input parsed URL
 * @csAttr = Attribute for search
 * @psValue = Return value of attribute, if ==NULL only check for existence of attribute
 * @valLen = Size of psValue array
 * return: 0 error attribute not find; -1 error:: can`t read; >0 ok, find at position
*/
int ioURLGetValue(struct tagIOURL *url, const char *csAttr, char * __restrict psValue, int valLen);
/*
 * ioURLGetFile() Get file from parsed URL
 * @url = Input parsed URL
 * @psValue = Return filename, if not specified file in url path, replace with /
 * @valLen = Size of psValue array
 * return: -1 error:: can`t read; 0 ok
*/
int ioURLGetFile(struct tagIOURL *url, char * __restrict psValue, int valLen);


/*
 * ioXMLGet() Parse and get data from input XML request string [ns:]container[|attribute[=value]][?data]
 * @csXML = Input XML request line
 * @xml = Output parsed XML request
 * return: 0 error format incorrect, -1 error:: can`t read; >0 ok readed elements bits
*/
int ioXMLGet(const char *csXML, struct tagReqXML *xml);


/*
 * ioMkDir() Function for racursive directory creation and validation
 * @csDir = Full directory path
 * @mode = Mode for directory creation if missing dir
 * return: -1 error, 0 directory path exist, >0 created missing dirs
*/
int ioMkDir(const char *csDir, int mode);

/*
 * ioWatchDirLoop() Function for watching changes in directory and fire callback
 * @csDir = Full directory path
 * @callback = Callback if raise event! nOp -1 delete, 0 change/move, 1 create
 * return: -1 error, !=-1 ok, number of total signaled events
*/
int ioWatchDirLoop(const char *csDir, int (*callback)(const char *csName, int nOp));


/*
 * io_rread() Raw VFS read function
 * @fd = File handle
 * @buf = Read buffer
 * @nbytes = Read buffer size
 * @offset = Read from position, if -1 read nbytes from current position
 * @update = Update file handle position !0
 * return: -1 error or !=-1 readed bytes
 */
inline int io_rread(int fd, void * __restrict buf, size_t nbytes, off_t offset, int update);
/*
 * io_rwrite() Raw VFS write function
 * @fd = File handle
 * @buf = Write buffer
 * @nbytes = Write bytes from buffer
 * @offset = Write at position, if -1 write nbytes from current position
 * @update = Update file handle position !0
 * return: -1 error or !=-1 writed bytes
 */
inline int io_rwrite(int fd, void * __restrict buf, size_t nbytes, off_t offset, int update);

/* Disk I/O helper macros */
#define io_read(f, b, n) io_rread(f, b, n, -1, 1)
#define io_write(f, b, n) io_rwrite(f, b, n, -1, 1)


/* Debug helper macros */
extern int io_Debug;

#define io_initDebug(x)		io_Debug = (x);
#define io_addDebug		io_Debug++
#define ioDEBUG(x, fmt, ...)	do { \
					assert((fmt)); \
					char str[STRSIZ] = { 0 }; \
					snprintf(str, sizeof str, (fmt), ##__VA_ARGS__); \
					if ((x) <= io_Debug) \
						syslog(LOG_DEBUG, "ioDebug(%d):%s(%d): %s\n", \
								(x), __func__, __LINE__, str); \
				} while (0)

#define ioERROR(x, fmt, ...)	do { \
					assert((fmt)); \
					char str[STRSIZ] = { 0 }; \
					snprintf(str, sizeof str, (fmt), ##__VA_ARGS__); \
					syslog(LOG_ERR, "ioError():%s(%d): #%d - %s\n", \
							 __func__, __LINE__, (x), str); \
				} while (0)
#define io_sysERROR(x)		do { \
					if (x > 0 || errno) \
						syslog(LOG_ERR, "ioError(sys):%s(%d): #%d - %s\n", \
								__func__, __LINE__, x > 0 ? x : errno, \
								strerror(x > 0 ? x : errno)); \
				} while (0)
#define io_aitERROR(ait)	do { \
					if (ait##_GetErrno()) \
						syslog(LOG_ERR, "ioError(ait):%s(%d): #%d - %s\n", \
								__func__, __LINE__, ait##_GetErrno(), \
								ait##_GetError()); \
				} while (0)


/* Crypto framework */

/*
 * ioCipher() Cipher wrapper for all supported crypto algorythms
 * @pInput = input buffer
 * @inLen = input buffer len
 * @ppOutput = output allocated buffe, must be free after use
 * @Cipher = cipher engine, like EVP_bf_cbc() or etc...
 * @pKey = key
 * @pIV = IV, salt (8 bytes)
 * @nMode = Mode 0 - decrypting or 1 - encrypting
 * return: 0 not present data or error!; >0 number of processed and returned bytes into ppOutput
*/
int ioCipher(unsigned char *pInput, int inLen, unsigned char **ppOutput, const EVP_CIPHER *Cipher, 
		unsigned char *pKey, unsigned char *pIV, int nMode);

/*
 * io_Blowfish() Blowfish cipher algorythm, work with ASCII hex strings
 * @pInput = input buffer
 * @inLen = input buffer len
 * @ppOutput = output allocated buffe, must be free after use
 * @pKey = key
 * @pIV = IV, salt (8 bytes)
 * @nMode = Mode 0 - decrypting or 1 - encrypting
 * return: 0 not present data or error!; >0 number of processed and returned bytes into ppOutput
*/
int io_Blowfish(unsigned char *pInput, int inLen, unsigned char **ppOutput, 
		unsigned char *pKey, unsigned char *pIV, int nMode);
/*
 * io_ctr_AES() Encrypt/Decrypt stream cipher CTR_AES
 * @pInput = Input buffer with ASCII
 * @inLen = Input buffer data length
 * @ppOutput = Output buffer with cipher data, must be free after use
 * @pKey = Key
 * @IV = IVector/Nonce/Counter, Warning: IV must be variable, because we write there!!!
 * return: -1 error or >-1 how many cipher blocks proceeded
 */
int io_ctr_AES(unsigned char *pInput, int inLen, unsigned char **ppOutput, 
		unsigned char *pKey, unsigned char IV[AES_BLOCK_SIZE]);


/*
 * ioAllocPTY() Allocate new PTY and TTY
 * @ptyfd = master fd, pty
 * @ttyfd = slave fd, tty
 * @name = tty device name if not null
 * @namesiz = name length, must be above 63 bytes.
 * @term = termios for terminal
 * @winz = winsize for terminal
 * return: -1 error or 0 ok
 */
inline int ioAllocPTY(int *ptyfd, int *ttyfd, char * __restrict name, int namesiz, 
		struct termios * __restrict term, struct winsize * __restrict winz);
/*
 * ioFreePTY() Release PTY and TTY device
 * @ptyfd = master fd, pty (==-1 skip closing pty)
 * @ttyname = tty filename
 * return: none
 */
inline void ioFreePTY(int ptyfd, const char *ttyname);
/*
 * ioChgWinPTY() Change window size of PTY
 * @ptyfd = master fd, pty
 * @row = row
 * @col = col
 * @xpxl = x pixels
 * @ypxl = y pixels
 * return: -1 error or 0 ok
 */
inline int ioChgWinPTY(int ptyfd, unsigned short row, unsigned short col, 
		unsigned short xpxl, unsigned short ypxl);
/*
 * ioSetOwnerTTY() Set owner to TTY
 * @ttyname = tty filename
 * @UID = uid
 * @GID = gid
 * return: -1 error or 0 ok
 */
int ioSetOwnerTTY(const char *ttyname, uid_t UID, gid_t GID);
/*
 * ioSetSidTTY() Makes the process's controlling TTY and sets it to sane modes.
 * @ttyfd = slave fd, tty
 * @ttyname = tty filename
 * return: -1 error or 0 ok
 */
int ioSetSidTTY(int *ttyfd, const char *ttyname);
/*
 * ioSetRAWMode() Enter into RAW mode
 * @fd = tty fd
 * @otio = saved old termios for later restore if !=NULL
 * return: -1 error or 0 ok
 */
inline int ioSetRAWMode(int fd, struct termios *otio);
/*
 * ioRestoreMode() Restore termios to tty fd
 * @fd = tty fd
 * @tio = termios structure for restore
 * return: -1 error or 0 ok
 */
inline int ioRestoreMode(int fd, struct termios tio);
/*
 * ioForkPTY() Fork new process with session leader and new TTY
 * @ptyfd = master fd, pty
 * @name = tty device name if not null
 * @namesiz = name length, must be above 63 bytes.
 * @term = termios for terminal
 * @winz = winsize for terminal
 * @otio = old termios structure for restore
 * return: -1 error, 0 child process or >0 parent: pid of child
 */
pid_t ioForkPTY(int *ptyfd, char * __restrict name, int namesiz, struct termios * __restrict term, 
		struct winsize * __restrict winz, struct termios * __restrict otio);

/*
 * ioCreatePIDFile() Create PID file
 * @csName = PID filename
 * @ifExists = !=0 if filename exists return error
 * return: -1 error or 0 ok
 */
inline int ioCreatePIDFile(const char *csName, int ifExists);


#endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>