diff options
Diffstat (limited to 'libcmd')
| -rw-r--r-- | libcmd/Makefile | 43 | ||||
| -rw-r--r-- | libcmd/cmd.c | 544 | ||||
| -rw-r--r-- | libcmd/cmd.h | 85 | ||||
| -rw-r--r-- | libcmd/cmd_parse.c | 309 | ||||
| -rw-r--r-- | libcmd/cmd_parse.h | 8 | ||||
| -rw-r--r-- | libcmd/cmd_parse.ragel | 86 | ||||
| -rw-r--r-- | libcmd/debug.h | 69 | ||||
| -rw-r--r-- | libcmd/queue.h | 533 | 
8 files changed, 1677 insertions, 0 deletions
| diff --git a/libcmd/Makefile b/libcmd/Makefile new file mode 100644 index 0000000..86f0ae6 --- /dev/null +++ b/libcmd/Makefile @@ -0,0 +1,43 @@ +PROJ=libcmd +CC=gcc +CFLAGS=-g3 +LDFLAGS= +RAGEL=ragel +DOT=dot + +SOURCE=cmd cmd_parse +OBJECTS=$(SOURCE:=.o) +SOURCES=$(SOURCE:=.c) + +%.o: %.c +	$(CC) $(CFLAGS) -c $< + + +make: dynamic static object +	 +dynamic: CFLAGS+=-fPIC +dynamic: clean $(OBJECTS) +	$(CC) $(CFLAGS) $(OBJECTS) -shared -o $(PROJ).so + +static: clean $(OBJECTS) +	ar rcs $(PROJ).a $(OBJECTS) + +object: clean $(OBJECTS) +	ld -r $(OBJECTS) -o $(PROJ).o + +ragel: +	$(RAGEL) cmd_parse.ragel + +cli: +	$(CC) $(CFLAGS) -L./ -I./ -lcmd ./test/cmd_cli.c -o ./cmd_cli + +pdf: +	$(RAGEL) -V cmd_parse.ragel -o cmd_parse.dot +	$(DOT) -Tpdf cmd_parse.dot -o cmd_parse.pdf + +leak: +	valgrind --leak-check=full --track-origins=yes --log-file=log.txt ./cmd_cli + +clean: +	rm -f cmd_cli +	rm -rf *.so *.o *.dot *.pdf  diff --git a/libcmd/cmd.c b/libcmd/cmd.c new file mode 100644 index 0000000..c1d43fc --- /dev/null +++ b/libcmd/cmd.c @@ -0,0 +1,544 @@ +#include "cmd.h" + +cmd_tok_t* cmd_tok_create(  char *s, char *e, int sz, int type ) +{ +	cmd_tok_t *ret = NULL; + +	ret = malloc( sizeof(cmd_tok_t) ); +	if ( ret == NULL ) +		return ret; + +	memset( ret, 0, sizeof(cmd_tok_t) ); + +	ret->s = s; +	ret->e = e; +	ret->sz = sz; +	ret->type = type; +	ret->next = NULL; //no need, but sec programming says we need it + +	return ret; +} + + +int cmd_tok_add( cmd_tok_t *tok, cmd_tok_t *next ) +{ +	int ret = 0; + +	if ( tok == NULL ) +	{ +		return -1; +	} +	 +	if ( next == NULL ) +	{ +		return -1; +	} + +	if ( tok->next != NULL ) +	{ +		printf("next token allready set\n"); +		return -1; +	} + +	tok->next = next; + +	return ret; +} + + +int cmd_tok_print( cmd_tok_t *tok ) +{ +	int ret = 0; + +	printf("TOK %p\n",tok); +	if (tok) +	{ +		printf("S:%p E:%p SZ:%d \n", tok->s, tok->e, tok->sz); +		printf("TYPE: "); +		switch (tok->type) +		{ +		case CMDT_NONE: +			printf("NONE"); +			break; +		case CMDT_INT: +			printf("INT"); +			break; +		case CMDT_HEX: +			printf("HEX"); +			break; +		case CMDT_BIN: +			printf("BIN"); +			break; +		case CMDT_STR: +			printf("STR"); +			break; +		case CMDT_WORD: +			printf("WORD"); +			break; +		case CMDT_SP: +			printf("SP"); +			break; +		default: +			printf("UNKNOWN"); +		} +		printf("\n"); +		printf("NEXT: %p\n", tok->next ); +	} + +	return ret; +} + + +void cmd_tok_destroy( cmd_tok_t *tok ) +{ +	cmd_tok_t *t=NULL, *n=NULL; + +	if (tok == NULL) +	{ +		return; +	} + +	if ( tok->next == NULL ) +	{ +		free( tok ); +		return; +	} + +	t = tok; +	n = t; +	while ( n != NULL) +	{ +		n = t->next; +		t->next = NULL; +		free(t); +		t = n; +	} +} + + +int cmd_tok_count( cmd_tok_t *tok ) +{ +	int ret = 0; +	cmd_tok_t *iter = NULL; + +	if (tok == NULL) +		return 0; + +	iter = tok; +	while( iter != NULL ) +	{ +		ret += 1; +		iter = iter->next; +	} + +	return ret; +} + + + +cmd_arg_t* cmd_arg_create(  cmd_tok_t *tok ) +{ +	cmd_arg_t *ret = NULL; +	int argc = -1; +	cmd_tok_t *iter = NULL; +	int i = 0; + +	ret = malloc( sizeof(cmd_arg_t) ); +	if ( ret == NULL ) +	{ +		return NULL; +	} +	memset( ret, 0, sizeof( cmd_arg_t )); + +	//get number of arguments in command line +	argc = cmd_tok_count( tok ); +	ret->argc = argc; + + +	//alloc mem for argument string values +	ret->argv = malloc( sizeof(int*)*argc ); +	if ( ret->argv == NULL ) +	{ +		//printf("ERR:err_malloc_argv\n"); +		goto err_malloc_argv; +	} +	memset( ret->argv, 0, sizeof(int*)*argc ); + +	//alloc mem for argument type values +	ret->type = malloc( sizeof(int)*argc ); +	if ( ret->type == NULL ) +	{ +		//printf("ERR:err_malloc_type\n"); +		goto err_malloc_type; +	} +	memset( ret->type, 0, sizeof(int)*argc ); + +	//create for each cmd token string and set type +	iter = tok; +	for (i=0; i<argc; i++,iter=iter->next) +	{ +		ret->argv[i] = malloc( iter->sz+1 ); +		memcpy(ret->argv[i], iter->s, iter->sz ); +		ret->argv[i][iter->sz] = 0x0; +		ret->type[i] = iter->type; +	} + +	return ret; + +err_malloc_type: +	free( ret->argv ); +err_malloc_argv: +	free( ret ); +err_exit: +	return NULL; +} + + +cmd_arg_t* cmd_arg_sub( cmd_arg_t *arg ) +{ +	cmd_arg_t *ret = NULL; + +	int i=0; + +	if ( arg == NULL ) +		return NULL; + +	if ( arg->argc == 1 ) +	{ +		ret = cmd_arg_sub_empty(); +		return ret; +	} + +	ret = malloc( sizeof(cmd_arg_t) ); +	 +	ret->argc = arg->argc-1; + +	ret->type = malloc(sizeof(int)*(arg->argc-1)); +	memset(ret->type, 0, sizeof(int)*(arg->argc-1) ); +	 +	ret->argv = malloc( sizeof(char*)*(arg->argc-1) ); +	memset(ret->argv, 0, sizeof(char*)*(arg->argc-1) ); + +	ret->__sub_cmd = 1; + +	for (i=0; i<ret->argc; i++) +	{ +		ret->argv[i] = arg->argv[i+1]; +		ret->type[i] = arg->type[i+1]; +	} + +	return ret; +} + + +cmd_arg_t* cmd_arg_sub_empty() +{ +	cmd_arg_t *ret = NULL; + +	ret = malloc( sizeof(cmd_arg_t) ); +	ret->argc = 0; +	ret->argv = NULL; +	ret->type = NULL; +	ret->__sub_cmd = 1; + +	return ret; +} + +void cmd_arg_destroy( cmd_arg_t *arg ) +{ +	int i; + +	if ( arg == NULL ) +		return; + +	for ( i=0; i<arg->argc; i++) +	{ +		if ( arg->__sub_cmd == 0 ) +			free( arg->argv[i] ); +	} + +	free( arg->argv ); + +	free( arg->type ); + +	free( arg ); +} + +int  cmd_exec( cmd_table_t *tbl, cmd_arg_t *arg ) +{ +	int ret = -1; +	int fret = 0; +	int i; + +	cmd_arg_t *sub_arg = NULL; + +	if ( arg->argc < 1 ) +	{ +		printf("Hm ... no arguments\n"); +		return -1; +	} + +	i = 0; +	while ( (tbl[i].cmd != NULL) && (tbl[i].clb != NULL) ) +	{ +		//printf("tbl.cmd %s\n", tbl[i].cmd ); +		if ((strlen(tbl[i].cmd) == strlen(arg->argv[0])) //if there is 0 args then here could be non-0 and we get troubles +		     && (strlen(tbl[i].cmd) != 0)) //combo if +		if ( strncmp( tbl[i].cmd, arg->argv[0], strlen(arg->argv[0]) ) == 0 ) +		{ +			//never will exec becouse of statment in while +			if ( tbl[i].clb == NULL ) +			{ +				printf("Empty callback %s\n", tbl[i].cmd); +				ret = -1; +				break; +			} + +			sub_arg = cmd_arg_sub( arg ); +			fret = tbl[i].clb( sub_arg ); + +			//if command whent wrong or not still clean mem +			if ( sub_arg != NULL ) +			{ +				cmd_arg_destroy( sub_arg ); +			} + +			//command execution whent wrong lets go out +			if ( fret != 0 ) +			{ +				printf("Command broken execution\n"); +				ret = -1; +				break; +			} +			ret = 0; //succesfull execution +			break; +		} + +		i++; +	}	 + + + +	return ret; +} + +int cmd_exec_ev( cmd_table_t *tbl, cmd_arg_t *arg, int event ) +{ +	int ret = -1; +	int fret = 0; +	int i; + +	cmd_arg_t *sub_arg = NULL; + +	if ( arg->argc < 1 ) +	{ +		printf("Hm ... no arguments\n"); +		return -1; +	} + +	i = 0; +	while ( (tbl[i].cmd != NULL) && (tbl[i].clb != NULL) ) +	{ +		//printf("tbl.cmd %s\n", tbl[i].cmd ); +		if ((strlen(tbl[i].cmd) == strlen(arg->argv[0])) //if there is 0 args then here could be non-0 and we get troubles +		     && (strlen(tbl[i].cmd) != 0)) //combo if +		if ( strncmp( tbl[i].cmd, arg->argv[0], strlen(arg->argv[0]) ) == 0 ) +		{ +			//never will exec becouse of statment in while +			if ( tbl[i].clb == NULL ) +			{ +				printf("Empty callback %s\n", tbl[i].cmd); +				ret = -1; +				break; +			} + +			sub_arg = cmd_arg_sub( arg ); + +			if ( sub_arg == NULL ) +				sub_arg = cmd_arg_sub_empty(); + +			fret = tbl[i].clb( sub_arg ); + +			//if command whent wrong or not still clean mem +			if ( sub_arg != NULL ) +			{ +				cmd_arg_destroy( sub_arg ); +			} + +			//command execution whent wrong lets go out +			if ( fret != 0 ) +			{ +				printf("Command broken execution\n"); +				ret = -1; +				break; +			} +			ret = 0; +			break; +		} + +		i++; +	} + + +	return ret; +} + +/* +For now support only first command autocomplete, and return first cmd +RETURN: string to command, dont modify it +*/ +char* cmd_ac( cmd_table_t *tbl, const char *s ) +{ +	char *ret = NULL; +	int i = -1; +	int idx = -1, match=-1;//best match +	int ret_match; +	int str_ac_sz = strlen(s); + + +	i = 0; +	while ( (tbl[i].cmd != NULL) && (tbl[i].clb != NULL) ) +	{ +		ret_match = strncmp_ac( s, tbl[i].cmd, str_ac_sz ); +		if (ret_match > 0) +		{ +			if (ret_match == str_ac_sz+1) +			{ +				idx = i; +				break; +			} else +			{ +				if (ret_match > match) +				{ +					idx = i; +					match = ret_match; +				} +			} +		} +		i++; +	} +	 +	if ( idx >= 0 ) +	{ +		ret = tbl[idx].cmd; +	} + +	return ret; +} + +struct cmd_acq_head_t* cmd_acq( cmd_table_t *tbl, const char *s ) +{ +	struct cmd_acq_head_t *ret = NULL; + +	int i = -1; +	int ret_match; +	int str_ac_sz = strlen(s); + +	struct cmd_acq_head_t *ac = malloc(sizeof(struct cmd_acq_t)); + +	SLIST_INIT(ac); +	i = 0; +	while ( (tbl[i].cmd != NULL) && (tbl[i].clb != NULL) ) +	{ +		ret_match = strncmp_ac( s, tbl[i].cmd, str_ac_sz ); +		if (ret_match > 0) +		{ +			//found 100% match +			if (ret_match == str_ac_sz+1) +			{ +				PRINT("Unknown state\n"); +				break; +			//partial match +			} else +			{ +				struct cmd_acq_t *acq = malloc(sizeof(struct cmd_acq_t)); +				acq->suggestion = tbl[i].cmd; +				SLIST_INSERT_HEAD(ac,acq,next_sugg); +			} +		} +		i++; +	} + +	ret = ac; + +	return ret; +} + +void cmd_acq_free( struct cmd_acq_head_t *acq ) +{ +	struct cmd_acq_t *iter; +	struct cmd_acq_t *prev; + +	prev = NULL; +	iter = NULL; +	SLIST_FOREACH(iter,acq,next_sugg) +	{ +		if ( prev != NULL ) +		{ +			free( prev ); +			prev = NULL; +		} +		prev = iter; +	} + +	return; +} + +/* +Clothest match function +AA AB  = (1) equile <100% +AA AA  = (3) equite 100%  +AA AAA = (2) equile 100% but there is more +A  B   = (0) not equile at all +*/ +int strncmp_ac(const char *s1, const char *s2, const int n) +{ +	int i=0; + +	if (n<0) +	{ +		printf("n<0 wrong argument value\n"); +		return 0; +	} + +	/* not equile at all */ +	/* A B */ +	if ( s1[0] != s2[0] ) +	{ +		return 0; +	} + +	i = 0; +	while ( (s1[i] == s2[i]) && (i<n)) +	{ +		i++; +	} + +	//printf("i"); +	/* AA AA */ +	if ( (s1[i]==0x00) && (s2[i]==0x0) && (i==n) ) +	{ +		//printf("1 "); +		return i+1; +	/* AA AAA */ +	} else if ( (s1[i]==0x0) && (s2[i]!=0x0) && (i==n) ) +	{ +		//printf("2 "); +		return i; +	/* AAA AA */ +	} else if ( (s1[i]!=0x0) && (s2[i]==0x0) && (i<n) ) +	{ +		//printf("3 "); +		return -i; +	/* AA AB */ +	} else if ( (s1[i]!=0x0) && (s2[i]!=0x0) && (s1[i]!=s2[i]) && (i<n) ) +	{ +		//printf("4 "); +		return -i; +	} else  +	{ +		printf("Unknown condition\n"); +	} + +	return 0; +}
\ No newline at end of file diff --git a/libcmd/cmd.h b/libcmd/cmd.h new file mode 100644 index 0000000..736cb2b --- /dev/null +++ b/libcmd/cmd.h @@ -0,0 +1,85 @@ +#ifndef __CMD_H +#define __CMD_H + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + +#include "debug.h" +#include "queue.h" + +#define CMDT_NONE   0 +#define CMDT_INT    1 +#define CMDT_HEX    2 +#define CMDT_BIN    3 +#define CMDT_STR    4 +#define CMDT_WORD   5 +#define CMDT_SP     6 + +#define CMDE_NONE         0 //do nothing +#define CMDE_AUTOCOMPLETE 1 //try to auto complete first command +#define CMDE_ALIAS        2 //command aliases + +typedef struct cmd_tok_t +{ +	char             *s,*e; +	int               sz; +	int               type; +	struct cmd_tok_t *next; +} cmd_tok_t; + +typedef struct cmd_arg_t +{ +	int    argc; +	char **argv; +	int   *type; + +	/* bad practice stuff */ +	int    __sub_cmd; // if 1 then dont free argv stuff +} cmd_arg_t; + + +typedef struct cmd_table_t +{ +	char *cmd; +	int (*clb)(cmd_arg_t*); +} cmd_table_t; + +struct cmd_acq_t +{ +	char *suggestion; +	SLIST_ENTRY(cmd_acq_t) next_sugg; +}; +SLIST_HEAD(cmd_acq_head_t,cmd_acq_t); + +cmd_tok_t* cmd_tok_create(  char *s, char *e, int sz, int type ); +int        cmd_tok_add( cmd_tok_t *tok, cmd_tok_t *next ); +int        cmd_tok_print( cmd_tok_t *tok ); +void       cmd_tok_destroy( cmd_tok_t *tok ); //clean token by ->next token +int        cmd_tok_count( cmd_tok_t *tok ); + +cmd_arg_t* cmd_arg_create(  cmd_tok_t *tok ); +cmd_arg_t* cmd_arg_sub( cmd_arg_t *arg ); //just return without first arg +cmd_arg_t* cmd_arg_sub_empty(); +void       cmd_arg_destroy( cmd_arg_t *arg ); + +int        cmd_exec( cmd_table_t *tbl, cmd_arg_t *arg ); +int        cmd_exec_ev( cmd_table_t *tbl, cmd_arg_t *arg, int event ); //auto complete and all other +char*      cmd_ac( cmd_table_t *tbl, const char *s ); //autocomplete +struct cmd_acq_head_t* cmd_acq( cmd_table_t *tbl, const char *s ); //autocomplete +void       cmd_acq_free( struct cmd_acq_head_t *acq ); + +#define STR_AC_EQ(A,B)  (strncmp_ac((A),(B),strlen(A))==(strlen(A)+1)) +#define STR_AC_PEQ(A,B) (strncmp_ac((A),(B),strlen(A))<(strlen(A))) + +/* +Clothest match function +AA AB  = (1) equile <100% +AA AA  = (3) equite 100%  +AA AAA = (2) equile 100% but there is more +A  B   = (0) not equile at all +*/ +int strncmp_ac( const char *s1, const char *s2, const int n); + +#endif
\ No newline at end of file diff --git a/libcmd/cmd_parse.c b/libcmd/cmd_parse.c new file mode 100644 index 0000000..ee6b3ca --- /dev/null +++ b/libcmd/cmd_parse.c @@ -0,0 +1,309 @@ + +#line 1 "cmd_parse.ragel" +#include "cmd_parse.h" + +//#define CTS(X) {if (!dm_current_tok)token_s = p; printf("%s ",#X);if (!dm_current_tok) dm_current_tok = TOK_##X;} +//#define CTE() {token_e = p;} +#define TADD(T,S,E,SZ) {cmd_tok_t *t=cmd_tok_create(S,E,SZ,T);cmd_tok_add(tl,t);tl=tl->next;} +//#define TADD(T,S,E) + +char *new_string( const char *start, const char *end ) +{ +	int str_s = end-start+1; +	char *new_str=malloc( str_s+1 ); +	memcpy( new_str, start, str_s ); +	if ( new_str != NULL ) +		new_str[str_s]=0x0; +	return new_str; +} + +int print_token( char *s, char *e, int tok) +{ +	char *p = new_string( s, e ); +	printf("t=%d,p=%s\n",tok,p); +	free( p ); +	return 0; +} + + + +#line 31 "cmd_parse.c" +static const char _cmd_actions[] = { +	0, 1, 0, 1, 1, 1, 2, 1,  +	3, 1, 4, 1, 5, 1, 6, 1,  +	7, 1, 8, 1, 9, 1, 10 +}; + +static const char _cmd_key_offsets[] = { +	0, 0, 8, 17, 19, 25, 31, 43,  +	47, 49, 51, 57 +}; + +static const char _cmd_trans_keys[] = { +	32, 39, 48, 57, 65, 90, 97, 122,  +	32, 34, 39, 48, 57, 65, 90, 97,  +	122, 48, 49, 48, 57, 65, 70, 97,  +	102, 48, 57, 65, 90, 97, 122, 32,  +	34, 48, 59, 9, 10, 49, 57, 65,  +	90, 97, 122, 98, 120, 48, 57, 48,  +	57, 48, 49, 48, 57, 65, 70, 97,  +	102, 48, 57, 65, 90, 97, 122, 0 +}; + +static const char _cmd_single_lengths[] = { +	0, 2, 3, 0, 0, 0, 4, 2,  +	0, 0, 0, 0 +}; + +static const char _cmd_range_lengths[] = { +	0, 3, 3, 1, 3, 3, 4, 1,  +	1, 1, 3, 3 +}; + +static const char _cmd_index_offsets[] = { +	0, 0, 6, 13, 15, 19, 23, 32,  +	36, 38, 40, 44 +}; + +static const char _cmd_indicies[] = { +	0, 0, 0, 0, 0, 1, 0, 2,  +	0, 0, 0, 0, 1, 4, 3, 5,  +	5, 5, 3, 6, 6, 6, 1, 7,  +	8, 9, 11, 7, 10, 12, 12, 1,  +	14, 15, 10, 13, 10, 13, 4, 16,  +	5, 5, 5, 17, 6, 6, 6, 18,  +	0 +}; + +static const char _cmd_trans_targs[] = { +	2, 0, 6, 6, 9, 10, 11, 6,  +	1, 7, 8, 6, 5, 6, 3, 4,  +	6, 6, 6 +}; + +static const char _cmd_trans_actions[] = { +	0, 0, 9, 21, 0, 0, 0, 7,  +	0, 5, 0, 11, 0, 15, 0, 0,  +	17, 13, 19 +}; + +static const char _cmd_to_state_actions[] = { +	0, 0, 0, 0, 0, 0, 1, 0,  +	0, 0, 0, 0 +}; + +static const char _cmd_from_state_actions[] = { +	0, 0, 0, 0, 0, 0, 3, 0,  +	0, 0, 0, 0 +}; + +static const char _cmd_eof_trans[] = { +	0, 0, 0, 4, 4, 0, 0, 14,  +	14, 17, 18, 19 +}; + +static const int cmd_start = 6; +static const int cmd_first_final = 6; +static const int cmd_error = 0; + +static const int cmd_en_main = 6; + + +#line 53 "cmd_parse.ragel" + + +int parse_cmd( cmd_tok_t *tl, const char *str ) +{ +	static uint8_t cs; +	const int stacksize = 10; +	int res=0, *stack=NULL, act=0; +	stack = malloc( sizeof(stack)*stacksize ); +	char *p=(char *)str, *pe = (char *)str + strlen( str ), *eof=NULL; +	char *ts, *te = 0; + +	/* +	variables used in state machine +	*/ + +	 +#line 130 "cmd_parse.c" +	{ +	cs = cmd_start; +	ts = 0; +	te = 0; +	act = 0; +	} + +#line 69 "cmd_parse.ragel" +	 +#line 140 "cmd_parse.c" +	{ +	int _klen; +	unsigned int _trans; +	const char *_acts; +	unsigned int _nacts; +	const char *_keys; + +	if ( p == pe ) +		goto _test_eof; +	if ( cs == 0 ) +		goto _out; +_resume: +	_acts = _cmd_actions + _cmd_from_state_actions[cs]; +	_nacts = (unsigned int) *_acts++; +	while ( _nacts-- > 0 ) { +		switch ( *_acts++ ) { +	case 1: +#line 1 "NONE" +	{ts = p;} +	break; +#line 161 "cmd_parse.c" +		} +	} + +	_keys = _cmd_trans_keys + _cmd_key_offsets[cs]; +	_trans = _cmd_index_offsets[cs]; + +	_klen = _cmd_single_lengths[cs]; +	if ( _klen > 0 ) { +		const char *_lower = _keys; +		const char *_mid; +		const char *_upper = _keys + _klen - 1; +		while (1) { +			if ( _upper < _lower ) +				break; + +			_mid = _lower + ((_upper-_lower) >> 1); +			if ( (*p) < *_mid ) +				_upper = _mid - 1; +			else if ( (*p) > *_mid ) +				_lower = _mid + 1; +			else { +				_trans += (unsigned int)(_mid - _keys); +				goto _match; +			} +		} +		_keys += _klen; +		_trans += _klen; +	} + +	_klen = _cmd_range_lengths[cs]; +	if ( _klen > 0 ) { +		const char *_lower = _keys; +		const char *_mid; +		const char *_upper = _keys + (_klen<<1) - 2; +		while (1) { +			if ( _upper < _lower ) +				break; + +			_mid = _lower + (((_upper-_lower) >> 1) & ~1); +			if ( (*p) < _mid[0] ) +				_upper = _mid - 2; +			else if ( (*p) > _mid[1] ) +				_lower = _mid + 2; +			else { +				_trans += (unsigned int)((_mid - _keys)>>1); +				goto _match; +			} +		} +		_trans += _klen; +	} + +_match: +	_trans = _cmd_indicies[_trans]; +_eof_trans: +	cs = _cmd_trans_targs[_trans]; + +	if ( _cmd_trans_actions[_trans] == 0 ) +		goto _again; + +	_acts = _cmd_actions + _cmd_trans_actions[_trans]; +	_nacts = (unsigned int) *_acts++; +	while ( _nacts-- > 0 ) +	{ +		switch ( *_acts++ ) +		{ +	case 2: +#line 1 "NONE" +	{te = p+1;} +	break; +	case 3: +#line 42 "cmd_parse.ragel" +	{te = p+1;} +	break; +	case 4: +#line 43 "cmd_parse.ragel" +	{te = p+1;{printf("str = ");fwrite(ts,1,te-ts,stdout);printf("\n");TADD(CMDT_STR,ts,te,te-ts);}} +	break; +	case 5: +#line 46 "cmd_parse.ragel" +	{te = p+1;{printf("sep = ");fwrite(ts,1,te-ts,stdout);printf("\n");TADD(CMDT_SP,ts,te,te-ts);}} +	break; +	case 6: +#line 41 "cmd_parse.ragel" +	{te = p;p--;{printf("hex = ");fwrite(ts,1,te-ts,stdout);printf("\n");TADD(CMDT_HEX,ts,te,te-ts);}} +	break; +	case 7: +#line 44 "cmd_parse.ragel" +	{te = p;p--;{printf("dec = ");fwrite(ts,1,te-ts,stdout);printf("\n");TADD(CMDT_INT,ts,te,te-ts);}} +	break; +	case 8: +#line 45 "cmd_parse.ragel" +	{te = p;p--;{printf("bin = ");fwrite(ts,1,te-ts,stdout);printf("\n");TADD(CMDT_BIN,ts,te,te-ts);}} +	break; +	case 9: +#line 47 "cmd_parse.ragel" +	{te = p;p--;{printf("wrd = ");fwrite(ts,1,te-ts,stdout);printf("\n");TADD(CMDT_WORD,ts,te,te-ts);}} +	break; +	case 10: +#line 44 "cmd_parse.ragel" +	{{p = ((te))-1;}{printf("dec = ");fwrite(ts,1,te-ts,stdout);printf("\n");TADD(CMDT_INT,ts,te,te-ts);}} +	break; +#line 263 "cmd_parse.c" +		} +	} + +_again: +	_acts = _cmd_actions + _cmd_to_state_actions[cs]; +	_nacts = (unsigned int) *_acts++; +	while ( _nacts-- > 0 ) { +		switch ( *_acts++ ) { +	case 0: +#line 1 "NONE" +	{ts = 0;} +	break; +#line 276 "cmd_parse.c" +		} +	} + +	if ( cs == 0 ) +		goto _out; +	if ( ++p != pe ) +		goto _resume; +	_test_eof: {} +	if ( p == eof ) +	{ +	if ( _cmd_eof_trans[cs] > 0 ) { +		_trans = _cmd_eof_trans[cs] - 1; +		goto _eof_trans; +	} +	} + +	_out: {} +	} + +#line 70 "cmd_parse.ragel" + +	if ( cs == cmd_error ) +	{ +		printf("CLIPARSE ERR state [%d] pos[%d]:[%s]\n", res, p-str, p); +		res = -1; +	} + +	free( stack ); + +	return res; +} + + + diff --git a/libcmd/cmd_parse.h b/libcmd/cmd_parse.h new file mode 100644 index 0000000..88a02e8 --- /dev/null +++ b/libcmd/cmd_parse.h @@ -0,0 +1,8 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> + +#include "cmd.h" + +int parse_cmd( cmd_tok_t *tl, const char *str );
\ No newline at end of file diff --git a/libcmd/cmd_parse.ragel b/libcmd/cmd_parse.ragel new file mode 100644 index 0000000..85aa7d8 --- /dev/null +++ b/libcmd/cmd_parse.ragel @@ -0,0 +1,86 @@ +#include "cmd_parse.h" + +//#define CTS(X) {if (!dm_current_tok)token_s = p; printf("%s ",#X);if (!dm_current_tok) dm_current_tok = TOK_##X;} +//#define CTE() {token_e = p;} +#define TADD(T,S,E,SZ) {cmd_tok_t *t=cmd_tok_create(S,E,SZ,T);cmd_tok_add(tl,t);tl=tl->next;} +//#define TADD(T,S,E) + +#define PR_TK_DBG(S) printf(S);fwrite(ts,1,te-ts,stdout);printf("\n"); +//#define PR_TK_DBG(S)  + +char *new_string( const char *start, const char *end ) +{ +	int str_s = end-start+1; +	char *new_str=malloc( str_s+1 ); +	memcpy( new_str, start, str_s ); +	if ( new_str != NULL ) +		new_str[str_s]=0x0; +	return new_str; +} + +int print_token( char *s, char *e, int tok) +{ +	char *p = new_string( s, e ); +	printf("t=%d,p=%s\n",tok,p); +	free( p ); +	return 0; +} + + +%%{ +	machine cmd; + +	 +	hex          = '0x' [a-fA-F0-9]+; +	decimal      = [0-9]+; +	binary       = '0b' [0-1]+; +	string       = ('"' ([a-zA-Z0-9' '])+ '"'); +	seperate     = ';'; +	word         = [a-zA-Z] ([a-zA-Z0-9])+; + +	sp           = (' ' | '\t' | '\n'); + +	main := |* +		hex      {PR_TK_DBG("hex = ");TADD(CMDT_HEX, ts,te,te-ts);}; +		sp       {}; +		string   {PR_TK_DBG("str = ");TADD(CMDT_STR, ts,te,te-ts);}; +		decimal  {PR_TK_DBG("dec = ");TADD(CMDT_INT, ts,te,te-ts);}; +		binary   {PR_TK_DBG("bin = ");TADD(CMDT_BIN, ts,te,te-ts);}; +		seperate {PR_TK_DBG("sep = ");TADD(CMDT_SP,  ts,te,te-ts);}; +		word     {PR_TK_DBG("wrd = ");TADD(CMDT_WORD,ts,te,te-ts);}; +	*|; + +	#main := lang; + +	write data; +}%% + +int parse_cmd( cmd_tok_t *tl, const char *str ) +{ +	static uint8_t cs; +	const int stacksize = 10; +	int res=0, *stack=NULL, act=0; +	stack = malloc( sizeof(stack)*stacksize ); +	char *p=(char *)str, *pe = (char *)str + strlen( str ), *eof=NULL; +	char *ts, *te = 0; + +	/* +	variables used in state machine +	*/ + +	%%write init; +	%%write exec; + +	if ( cs == cmd_error ) +	{ +		printf("CLIPARSE ERR state [%d] pos[%d]:[%s]\n", res, p-str, p); +		res = -1; +	} + +	free( stack ); + +	return res; +} + + + diff --git a/libcmd/debug.h b/libcmd/debug.h new file mode 100644 index 0000000..a8bf211 --- /dev/null +++ b/libcmd/debug.h @@ -0,0 +1,69 @@ +#ifndef __RB_DEBUG_UTILS_H +#define __RB_DEBUG_UTILS_H + +//what about kprintf? + +//config options +#define PRINTF printf +#define COLORIZE +#define PRINT_LINENUM +#define PRINT_FILENAME +#define PRINT_DEBUG + + +//use color +#ifdef COLORIZE +	#define D_COLOR "1;32m" +	#define D_COLOR_S "\033[" D_COLOR +	#define D_COLOR_E "\033[0m" +	#define E_COLOR "1;31m" +	#define E_COLOR_S "\033[" E_COLOR +	#define E_COLOR_E "\033[0m" +#else +	#define D_COLOR +	#define D_COLOR_S +	#define D_COLOR_E +	#define E_COLOR +	#define E_COLOR_S +	#define E_COLOR_E +#endif + +//print debug line +#ifdef PRINT_LINENUM +	#define PRINT_LINE_F "LINE:%d " +	#define PRINT_LINE_D __LINE__ +#else +	#define PRINT_LINE_F "" +	#define PRINT_LINE_D "" +#endif + +//print +#ifdef PRINT_FILENAME +	#define PRINT_FILE_F "FILE:%s " +	#define PRINT_FILE_D __FILE__ +#else +	#define PRINT_FILE_F "" +	#define PRINT_FILE_D "" +#endif + +//print debug string +#ifdef PRINT_DEBUG +	#define PRINT_DEBUG_F "Debug: " +#else +	#define PRINT_DEBUG_F "" +#endif + +#define PRINT( format, args ... ) PRINTF( D_COLOR_S PRINT_DEBUG_F \ +	PRINT_FILE_F PRINT_LINE_F format D_COLOR_E, PRINT_FILE_D, \ +	PRINT_LINE_D, ##args); + +#define ERROR( format, args ... ) PRINTF( E_COLOR_S PRINT_DEBUG_F \ +	PRINT_FILE_F PRINT_LINE_F format E_COLOR_E, PRINT_FILE_D, \ +	PRINT_LINE_D, ##args); + +#define PNL() PRINT("\n"); + +#define ENL() ERROR("\n"); + + +#endif diff --git a/libcmd/queue.h b/libcmd/queue.h new file mode 100644 index 0000000..cc2b25e --- /dev/null +++ b/libcmd/queue.h @@ -0,0 +1,533 @@ +/*	$OpenBSD: queue.h,v 1.43 2015/12/28 19:38:40 millert Exp $	*/ +/*	$NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $	*/ + +/* + * Copyright (c) 1991, 1993 + *	The Regents of the University of California.  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. Neither the name of the University 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 THE REGENTS 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. + * + *	@(#)queue.h	8.5 (Berkeley) 8/20/94 + */ + +#ifndef	_SYS_QUEUE_H_ +#define	_SYS_QUEUE_H_ + +/* + * This file defines five types of data structures: singly-linked lists, + * lists, simple queues, tail queues and XOR simple queues. + * + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction.  Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A simple queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are singly + * linked to save space, so elements can only be removed from the + * head of the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the + * list. A simple queue may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * An XOR simple queue is used in the same way as a regular simple queue. + * The difference is that the head structure also includes a "cookie" that + * is XOR'd with the queue pointer (first, last or next) to generate the + * real pointer value. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC)) +#define _Q_INVALIDATE(a) (a) = ((void *)-1) +#else +#define _Q_INVALIDATE(a) +#endif + +/* + * Singly-linked List definitions. + */ +#define SLIST_HEAD(name, type)						\ +struct name {								\ +	struct type *slh_first;	/* first element */			\ +} + +#define	SLIST_HEAD_INITIALIZER(head)					\ +	{ NULL } + +#define SLIST_ENTRY(type)						\ +struct {								\ +	struct type *sle_next;	/* next element */			\ +} + +/* + * Singly-linked List access methods. + */ +#define	SLIST_FIRST(head)	((head)->slh_first) +#define	SLIST_END(head)		NULL +#define	SLIST_EMPTY(head)	(SLIST_FIRST(head) == SLIST_END(head)) +#define	SLIST_NEXT(elm, field)	((elm)->field.sle_next) + +#define	SLIST_FOREACH(var, head, field)					\ +	for((var) = SLIST_FIRST(head);					\ +	    (var) != SLIST_END(head);					\ +	    (var) = SLIST_NEXT(var, field)) + +#define	SLIST_FOREACH_SAFE(var, head, field, tvar)			\ +	for ((var) = SLIST_FIRST(head);				\ +	    (var) && ((tvar) = SLIST_NEXT(var, field), 1);		\ +	    (var) = (tvar)) + +/* + * Singly-linked List functions. + */ +#define	SLIST_INIT(head) {						\ +	SLIST_FIRST(head) = SLIST_END(head);				\ +} + +#define	SLIST_INSERT_AFTER(slistelm, elm, field) do {\n			\ +	(elm)->field.sle_next = (slistelm)->field.sle_next;\n		\ +	(slistelm)->field.sle_next = (elm);\n				\ +} while (0) + +#define	SLIST_INSERT_HEAD(head, elm, field) do {			\ +	(elm)->field.sle_next = (head)->slh_first;			\ +	(head)->slh_first = (elm);					\ +} while (0) + +#define	SLIST_REMOVE_AFTER(elm, field) do {				\ +	(elm)->field.sle_next = (elm)->field.sle_next->field.sle_next;	\ +} while (0) + +#define	SLIST_REMOVE_HEAD(head, field) do {				\ +	(head)->slh_first = (head)->slh_first->field.sle_next;		\ +} while (0) + +#define SLIST_REMOVE(head, elm, type, field) do {			\ +	if ((head)->slh_first == (elm)) {				\ +		SLIST_REMOVE_HEAD((head), field);			\ +	} else {							\ +		struct type *curelm = (head)->slh_first;		\ +									\ +		while (curelm->field.sle_next != (elm))			\ +			curelm = curelm->field.sle_next;		\ +		curelm->field.sle_next =				\ +		    curelm->field.sle_next->field.sle_next;		\ +	}								\ +	_Q_INVALIDATE((elm)->field.sle_next);				\ +} while (0) + +/* + * List definitions. + */ +#define LIST_HEAD(name, type)						\ +struct name {								\ +	struct type *lh_first;	/* first element */			\ +} + +#define LIST_HEAD_INITIALIZER(head)					\ +	{ NULL } + +#define LIST_ENTRY(type)						\ +struct {								\ +	struct type *le_next;	/* next element */			\ +	struct type **le_prev;	/* address of previous next element */	\ +} + +/* + * List access methods. + */ +#define	LIST_FIRST(head)		((head)->lh_first) +#define	LIST_END(head)			NULL +#define	LIST_EMPTY(head)		(LIST_FIRST(head) == LIST_END(head)) +#define	LIST_NEXT(elm, field)		((elm)->field.le_next) + +#define LIST_FOREACH(var, head, field)					\ +	for((var) = LIST_FIRST(head);					\ +	    (var)!= LIST_END(head);					\ +	    (var) = LIST_NEXT(var, field)) + +#define	LIST_FOREACH_SAFE(var, head, field, tvar)			\ +	for ((var) = LIST_FIRST(head);				\ +	    (var) && ((tvar) = LIST_NEXT(var, field), 1);		\ +	    (var) = (tvar)) + +/* + * List functions. + */ +#define	LIST_INIT(head) do {						\ +	LIST_FIRST(head) = LIST_END(head);				\ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do {			\ +	if (((elm)->field.le_next = (listelm)->field.le_next) != NULL)	\ +		(listelm)->field.le_next->field.le_prev =		\ +		    &(elm)->field.le_next;				\ +	(listelm)->field.le_next = (elm);				\ +	(elm)->field.le_prev = &(listelm)->field.le_next;		\ +} while (0) + +#define	LIST_INSERT_BEFORE(listelm, elm, field) do {			\ +	(elm)->field.le_prev = (listelm)->field.le_prev;		\ +	(elm)->field.le_next = (listelm);				\ +	*(listelm)->field.le_prev = (elm);				\ +	(listelm)->field.le_prev = &(elm)->field.le_next;		\ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do {				\ +	if (((elm)->field.le_next = (head)->lh_first) != NULL)		\ +		(head)->lh_first->field.le_prev = &(elm)->field.le_next;\ +	(head)->lh_first = (elm);					\ +	(elm)->field.le_prev = &(head)->lh_first;			\ +} while (0) + +#define LIST_REMOVE(elm, field) do {					\ +	if ((elm)->field.le_next != NULL)				\ +		(elm)->field.le_next->field.le_prev =			\ +		    (elm)->field.le_prev;				\ +	*(elm)->field.le_prev = (elm)->field.le_next;			\ +	_Q_INVALIDATE((elm)->field.le_prev);				\ +	_Q_INVALIDATE((elm)->field.le_next);				\ +} while (0) + +#define LIST_REPLACE(elm, elm2, field) do {				\ +	if (((elm2)->field.le_next = (elm)->field.le_next) != NULL)	\ +		(elm2)->field.le_next->field.le_prev =			\ +		    &(elm2)->field.le_next;				\ +	(elm2)->field.le_prev = (elm)->field.le_prev;			\ +	*(elm2)->field.le_prev = (elm2);				\ +	_Q_INVALIDATE((elm)->field.le_prev);				\ +	_Q_INVALIDATE((elm)->field.le_next);				\ +} while (0) + +/* + * Simple queue definitions. + */ +#define SIMPLEQ_HEAD(name, type)					\ +struct name {								\ +	struct type *sqh_first;	/* first element */			\ +	struct type **sqh_last;	/* addr of last next element */		\ +} + +#define SIMPLEQ_HEAD_INITIALIZER(head)					\ +	{ NULL, &(head).sqh_first } + +#define SIMPLEQ_ENTRY(type)						\ +struct {								\ +	struct type *sqe_next;	/* next element */			\ +} + +/* + * Simple queue access methods. + */ +#define	SIMPLEQ_FIRST(head)	    ((head)->sqh_first) +#define	SIMPLEQ_END(head)	    NULL +#define	SIMPLEQ_EMPTY(head)	    (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head)) +#define	SIMPLEQ_NEXT(elm, field)    ((elm)->field.sqe_next) + +#define SIMPLEQ_FOREACH(var, head, field)				\ +	for((var) = SIMPLEQ_FIRST(head);				\ +	    (var) != SIMPLEQ_END(head);					\ +	    (var) = SIMPLEQ_NEXT(var, field)) + +#define	SIMPLEQ_FOREACH_SAFE(var, head, field, tvar)			\ +	for ((var) = SIMPLEQ_FIRST(head);				\ +	    (var) && ((tvar) = SIMPLEQ_NEXT(var, field), 1);		\ +	    (var) = (tvar)) + +/* + * Simple queue functions. + */ +#define	SIMPLEQ_INIT(head) do {						\ +	(head)->sqh_first = NULL;					\ +	(head)->sqh_last = &(head)->sqh_first;				\ +} while (0) + +#define SIMPLEQ_INSERT_HEAD(head, elm, field) do {			\ +	if (((elm)->field.sqe_next = (head)->sqh_first) == NULL)	\ +		(head)->sqh_last = &(elm)->field.sqe_next;		\ +	(head)->sqh_first = (elm);					\ +} while (0) + +#define SIMPLEQ_INSERT_TAIL(head, elm, field) do {			\ +	(elm)->field.sqe_next = NULL;					\ +	*(head)->sqh_last = (elm);					\ +	(head)->sqh_last = &(elm)->field.sqe_next;			\ +} while (0) + +#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do {		\ +	if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ +		(head)->sqh_last = &(elm)->field.sqe_next;		\ +	(listelm)->field.sqe_next = (elm);				\ +} while (0) + +#define SIMPLEQ_REMOVE_HEAD(head, field) do {			\ +	if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ +		(head)->sqh_last = &(head)->sqh_first;			\ +} while (0) + +#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do {			\ +	if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \ +	    == NULL)							\ +		(head)->sqh_last = &(elm)->field.sqe_next;		\ +} while (0) + +#define SIMPLEQ_CONCAT(head1, head2) do {				\ +	if (!SIMPLEQ_EMPTY((head2))) {					\ +		*(head1)->sqh_last = (head2)->sqh_first;		\ +		(head1)->sqh_last = (head2)->sqh_last;			\ +		SIMPLEQ_INIT((head2));					\ +	}								\ +} while (0) + +/* + * XOR Simple queue definitions. + */ +#define XSIMPLEQ_HEAD(name, type)					\ +struct name {								\ +	struct type *sqx_first;	/* first element */			\ +	struct type **sqx_last;	/* addr of last next element */		\ +	unsigned long sqx_cookie;					\ +} + +#define XSIMPLEQ_ENTRY(type)						\ +struct {								\ +	struct type *sqx_next;	/* next element */			\ +} + +/* + * XOR Simple queue access methods. + */ +#define XSIMPLEQ_XOR(head, ptr)	    ((__typeof(ptr))((head)->sqx_cookie ^ \ +					(unsigned long)(ptr))) +#define	XSIMPLEQ_FIRST(head)	    XSIMPLEQ_XOR(head, ((head)->sqx_first)) +#define	XSIMPLEQ_END(head)	    NULL +#define	XSIMPLEQ_EMPTY(head)	    (XSIMPLEQ_FIRST(head) == XSIMPLEQ_END(head)) +#define	XSIMPLEQ_NEXT(head, elm, field)    XSIMPLEQ_XOR(head, ((elm)->field.sqx_next)) + + +#define XSIMPLEQ_FOREACH(var, head, field)				\ +	for ((var) = XSIMPLEQ_FIRST(head);				\ +	    (var) != XSIMPLEQ_END(head);				\ +	    (var) = XSIMPLEQ_NEXT(head, var, field)) + +#define	XSIMPLEQ_FOREACH_SAFE(var, head, field, tvar)			\ +	for ((var) = XSIMPLEQ_FIRST(head);				\ +	    (var) && ((tvar) = XSIMPLEQ_NEXT(head, var, field), 1);	\ +	    (var) = (tvar)) + +/* + * XOR Simple queue functions. + */ +#define	XSIMPLEQ_INIT(head) do {					\ +	arc4random_buf(&(head)->sqx_cookie, sizeof((head)->sqx_cookie)); \ +	(head)->sqx_first = XSIMPLEQ_XOR(head, NULL);			\ +	(head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first);	\ +} while (0) + +#define XSIMPLEQ_INSERT_HEAD(head, elm, field) do {			\ +	if (((elm)->field.sqx_next = (head)->sqx_first) ==		\ +	    XSIMPLEQ_XOR(head, NULL))					\ +		(head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \ +	(head)->sqx_first = XSIMPLEQ_XOR(head, (elm));			\ +} while (0) + +#define XSIMPLEQ_INSERT_TAIL(head, elm, field) do {			\ +	(elm)->field.sqx_next = XSIMPLEQ_XOR(head, NULL);		\ +	*(XSIMPLEQ_XOR(head, (head)->sqx_last)) = XSIMPLEQ_XOR(head, (elm)); \ +	(head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next);	\ +} while (0) + +#define XSIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do {		\ +	if (((elm)->field.sqx_next = (listelm)->field.sqx_next) ==	\ +	    XSIMPLEQ_XOR(head, NULL))					\ +		(head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \ +	(listelm)->field.sqx_next = XSIMPLEQ_XOR(head, (elm));		\ +} while (0) + +#define XSIMPLEQ_REMOVE_HEAD(head, field) do {				\ +	if (((head)->sqx_first = XSIMPLEQ_XOR(head,			\ +	    (head)->sqx_first)->field.sqx_next) == XSIMPLEQ_XOR(head, NULL)) \ +		(head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first); \ +} while (0) + +#define XSIMPLEQ_REMOVE_AFTER(head, elm, field) do {			\ +	if (((elm)->field.sqx_next = XSIMPLEQ_XOR(head,			\ +	    (elm)->field.sqx_next)->field.sqx_next)			\ +	    == XSIMPLEQ_XOR(head, NULL))				\ +		(head)->sqx_last = 					\ +		    XSIMPLEQ_XOR(head, &(elm)->field.sqx_next);		\ +} while (0) + + +/* + * Tail queue definitions. + */ +#define TAILQ_HEAD(name, type)						\ +struct name {								\ +	struct type *tqh_first;	/* first element */			\ +	struct type **tqh_last;	/* addr of last next element */		\ +} + +#define TAILQ_HEAD_INITIALIZER(head)					\ +	{ NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type)						\ +struct {								\ +	struct type *tqe_next;	/* next element */			\ +	struct type **tqe_prev;	/* address of previous next element */	\ +} + +/* + * Tail queue access methods. + */ +#define	TAILQ_FIRST(head)		((head)->tqh_first) +#define	TAILQ_END(head)			NULL +#define	TAILQ_NEXT(elm, field)		((elm)->field.tqe_next) +#define TAILQ_LAST(head, headname)					\ +	(*(((struct headname *)((head)->tqh_last))->tqh_last)) +/* XXX */ +#define TAILQ_PREV(elm, headname, field)				\ +	(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) +#define	TAILQ_EMPTY(head)						\ +	(TAILQ_FIRST(head) == TAILQ_END(head)) + +#define TAILQ_FOREACH(var, head, field)					\ +	for((var) = TAILQ_FIRST(head);					\ +	    (var) != TAILQ_END(head);					\ +	    (var) = TAILQ_NEXT(var, field)) + +#define	TAILQ_FOREACH_SAFE(var, head, field, tvar)			\ +	for ((var) = TAILQ_FIRST(head);					\ +	    (var) != TAILQ_END(head) &&					\ +	    ((tvar) = TAILQ_NEXT(var, field), 1);			\ +	    (var) = (tvar)) + + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field)		\ +	for((var) = TAILQ_LAST(head, headname);				\ +	    (var) != TAILQ_END(head);					\ +	    (var) = TAILQ_PREV(var, headname, field)) + +#define	TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar)	\ +	for ((var) = TAILQ_LAST(head, headname);			\ +	    (var) != TAILQ_END(head) &&					\ +	    ((tvar) = TAILQ_PREV(var, headname, field), 1);		\ +	    (var) = (tvar)) + +/* + * Tail queue functions. + */ +#define	TAILQ_INIT(head) do {						\ +	(head)->tqh_first = NULL;					\ +	(head)->tqh_last = &(head)->tqh_first;				\ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do {			\ +	if (((elm)->field.tqe_next = (head)->tqh_first) != NULL)	\ +		(head)->tqh_first->field.tqe_prev =			\ +		    &(elm)->field.tqe_next;				\ +	else								\ +		(head)->tqh_last = &(elm)->field.tqe_next;		\ +	(head)->tqh_first = (elm);					\ +	(elm)->field.tqe_prev = &(head)->tqh_first;			\ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do {			\ +	(elm)->field.tqe_next = NULL;					\ +	(elm)->field.tqe_prev = (head)->tqh_last;			\ +	*(head)->tqh_last = (elm);					\ +	(head)->tqh_last = &(elm)->field.tqe_next;			\ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do {		\ +	if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ +		(elm)->field.tqe_next->field.tqe_prev =			\ +		    &(elm)->field.tqe_next;				\ +	else								\ +		(head)->tqh_last = &(elm)->field.tqe_next;		\ +	(listelm)->field.tqe_next = (elm);				\ +	(elm)->field.tqe_prev = &(listelm)->field.tqe_next;		\ +} while (0) + +#define	TAILQ_INSERT_BEFORE(listelm, elm, field) do {			\ +	(elm)->field.tqe_prev = (listelm)->field.tqe_prev;		\ +	(elm)->field.tqe_next = (listelm);				\ +	*(listelm)->field.tqe_prev = (elm);				\ +	(listelm)->field.tqe_prev = &(elm)->field.tqe_next;		\ +} while (0) + +#define TAILQ_REMOVE(head, elm, field) do {				\ +	if (((elm)->field.tqe_next) != NULL)				\ +		(elm)->field.tqe_next->field.tqe_prev =			\ +		    (elm)->field.tqe_prev;				\ +	else								\ +		(head)->tqh_last = (elm)->field.tqe_prev;		\ +	*(elm)->field.tqe_prev = (elm)->field.tqe_next;			\ +	_Q_INVALIDATE((elm)->field.tqe_prev);				\ +	_Q_INVALIDATE((elm)->field.tqe_next);				\ +} while (0) + +#define TAILQ_REPLACE(head, elm, elm2, field) do {			\ +	if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL)	\ +		(elm2)->field.tqe_next->field.tqe_prev =		\ +		    &(elm2)->field.tqe_next;				\ +	else								\ +		(head)->tqh_last = &(elm2)->field.tqe_next;		\ +	(elm2)->field.tqe_prev = (elm)->field.tqe_prev;			\ +	*(elm2)->field.tqe_prev = (elm2);				\ +	_Q_INVALIDATE((elm)->field.tqe_prev);				\ +	_Q_INVALIDATE((elm)->field.tqe_next);				\ +} while (0) + +#define TAILQ_CONCAT(head1, head2, field) do {				\ +	if (!TAILQ_EMPTY(head2)) {					\ +		*(head1)->tqh_last = (head2)->tqh_first;		\ +		(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last;	\ +		(head1)->tqh_last = (head2)->tqh_last;			\ +		TAILQ_INIT((head2));					\ +	}								\ +} while (0) + +#endif	/* !_SYS_QUEUE_H_ */ | 
