diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..9efb4dab82 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "include/custom-scripts/--foorce"] + path = include/custom-scripts/--foorce + url = https://github.com/troydhanson/uthash.git +[submodule "include/custom-scripts/utlist"] + path = include/custom-scripts/utlist + url = https://github.com/troydhanson/uthash.git diff --git a/include/custom-scripts/--foorce b/include/custom-scripts/--foorce new file mode 160000 index 0000000000..44a66fe8e0 --- /dev/null +++ b/include/custom-scripts/--foorce @@ -0,0 +1 @@ +Subproject commit 44a66fe8e008c0a7f1c5af96f4a4cdf304b8bc81 diff --git a/include/custom-scripts/arg_custom_type.h b/include/custom-scripts/arg_custom_type.h new file mode 100644 index 0000000000..3bddd8b2d1 --- /dev/null +++ b/include/custom-scripts/arg_custom_type.h @@ -0,0 +1,64 @@ +#ifndef _ARG_CUSTOM_TYPE_H_ +#define _ARG_CUSTOM_TYPE_H_ + +#include +#include +#include +#include +#include +#include "lauxlib.h" +#include "lua.h" +#include "lualib.h" +#include "common/utlist.h" + +/* File consisting of the custom pseudo-type created by Custom Scripts (inspired by libobj) + =========================================================================== */ + +typedef enum data_type +{ + NONE_TYPE = 0, + BOOL_TYPE = 1, + CHAR_TYPE = 2, + INT_TYPE = 3, + STR_TYPE = 4, +} data_type_t; + +typedef union data { + bool b; + char c; + int i; + char *s; + char *lua; +} data_t; + +typedef struct arg_t +{ + // Type of underlying data + data_type_t type; + + // Data associated with the argument + data_t data; + + // Pointer to the previous and next arguments + struct arg_t *prev, *next; +} arg_t; + +/** + * Creates an empty argument structure + * Helper function for adding arguments to an object + */ +arg_t *arg_t_new(); + +/** + * Creates an argument structure with the specified boolean + * Helper function for obj_add_arg_bool + */ +arg_t *arg_t_init(data_t d, data_type_t t); + +/** + * Adds an argument structure to the end of the argument linked list + * Helper function for all obj_add_arg_ functions + */ +arg_t *arg_t_add(arg_t *head, arg_t *add); + +#endif \ No newline at end of file diff --git a/include/custom-scripts/custom_type.h b/include/custom-scripts/custom_type.h deleted file mode 100644 index 4b7b84b5de..0000000000 --- a/include/custom-scripts/custom_type.h +++ /dev/null @@ -1,194 +0,0 @@ -#ifndef _CUSTOM_TYPE_H_ -#define _CUSTOM_TYPE_H_ - -#include -#include -#include -#include -#include -#include "lauxlib.h" -#include "lua.h" -#include "lualib.h" - -/* File consisting of the custom pseudo-type created by Custom Scripts (inspired by libobj) - =========================================================================== */ - -typedef enum data_type -{ - NONE_TYPE = 0, - BOOL_TYPE = 1, - CHAR_TYPE = 2, - INT_TYPE = 3, - STR_TYPE = 4, -} data_type_t; - -typedef struct arg_t -{ - // Type of underlying data - data_type_t type; - - // Data associated with the argument - union - { - bool b; - char c; - int i; - char *s; - } data; - - // Pointer to the previous and next arguments - struct arg_t *prev; - struct arg_t *next; -} arg_t; - -typedef struct obj_t -{ - // Type of underlying data - data_type_t type; - - // Whether this data will be represented by a Lua script - bool is_lua; - - // Data associated with the object - union - { - bool b; - char c; - int i; - char *s; - char *lua; - } data; - - // Linked list of arguments - arg_t *args; -} object_t; - -/** - * obj_t_new() creates an empty object_t struct - * Returns: - * - pointer to an empty object struct - */ -object_t *obj_t_new(); - -/** - * obj_t_bool() creates an object_t struct containing a boolean - * Parameters: - * - bool value to be stored - * - Lua script (NULL if no script to be specified) - * - argument linked list to be passed to Lua if applicable - * Returns: - * - pointer to an object struct containing the bool - */ -object_t *obj_t_bool(bool b, char *lua); - -/** - * obj_t_char() creates an object_t struct containing a char - * Parameters: - * - char value to be stored - * - Lua script (NULL if no script to be specified) - * Returns: - * - pointer to an object struct containing the char - */ -object_t *obj_t_char(char c, char *lua); - -/** - * obj_t_int() creates an object_t struct containing a int - * Parameters: - * - char value to be stored - * - Lua script (NULL if no script to be specified) - * Returns: - * - pointer to an object struct containing the int - */ -object_t *obj_t_int(int i, char *lua); - -/** - * obj_t_str() creates an object_t struct containing a string - * Parameters: - * - char value to be stored - * - Lua script (NULL if no script to be specified) - * Returns: - * - pointer to an object struct containing the str - */ -object_t *obj_t_str(char *s, char *lua); - -// ============================================================================ - -/** - * obj_add_arg_bool adds a bool to the argument linked list of the object_t - * Parameters: - * - the object whose argument list is to be added to - * - the boolean to be added - * Returns: - * - the updated object - */ -object_t *obj_add_arg_bool(object_t *obj, bool b); - -/** - * obj_add_arg_char adds a char to the argument linked list of the object_t - * Parameters: - * - the object whose argument list is to be added to - * - the char to be added - * Returns: - * - the updated object - */ -object_t *obj_add_arg_char(object_t *obj, char c); - -/** - * obj_add_arg_int adds a int to the argument linked list of the object_t - * Parameters: - * - the object whose argument list is to be added to - * - the int to be added - * Returns: - * - the updated object - */ -object_t *obj_add_arg_int(object_t *obj, int i); - -/** - * obj_add_arg_str adds a string to the argument linked list of the object_t - * Parameters: - * - the object whose argument list is to be added to - * - the string to be added - * Returns: - * - the updated object - */ -object_t *obj_add_arg_str(object_t *obj, char *s); - -// ============================================================================ - -/** - * bool_t_get() returns a bool from an object_t struct - * Parameters: - * - ot: an obj_t - * Returns: - * - bool from ot - */ -bool bool_t_get(object_t *ot); - -/** - * char_t_get() returns a char from an object_t struct - * Parameters: - * - ot: an obj_t - * Returns: - * - char from ot - */ -char char_t_get(object_t *ot); - -/** - * int_t_get() returns an int from an object_t struct - * Parameters: - * - ot: an obj_t - * Returns: - * - integer from ot - */ -int int_t_get(object_t *ot); - -/** - * string_t_get() returns a string from an object_t struct - * Parameters: - * - ot: an obj_t - * Returns: - * - string from ot - */ -char* str_t_get(object_t *ot); - -#endif \ No newline at end of file diff --git a/include/custom-scripts/get_custom_type.h b/include/custom-scripts/get_custom_type.h new file mode 100644 index 0000000000..0bae1dd75c --- /dev/null +++ b/include/custom-scripts/get_custom_type.h @@ -0,0 +1,16 @@ +#ifndef _GET_CUSTOM_TYPE_H_ +#define _GET_CUSTOM_TYPE_H_ + +#include "lua_custom_type.h" + +/** + * bool_t_get() returns a bool from an object_t struct + * Parameters: + * - ot: an obj_t + * - d: operating data type + * Returns: + * - bool from ot + */ +data_t arg_t_get(object_t *ot); + +#endif \ No newline at end of file diff --git a/include/custom-scripts/lua_custom_type.h b/include/custom-scripts/lua_custom_type.h new file mode 100644 index 0000000000..616afcf37c --- /dev/null +++ b/include/custom-scripts/lua_custom_type.h @@ -0,0 +1,30 @@ +#ifndef _LUA_CUSTOM_TYPE_H_ +#define _LUA_CUSTOM_TYPE_H_ + +#include "obj_custom_type.h" + +/** + * Helper function used to push the arguments in the linked list + * to the Lua vritual stack + * Parameters: + * - the Lua state created + * - the object containing the argument linked list + * Returns: + * - the number of arguments in the linked list + */ +int push_args(lua_State *L, object_t* ot); + +/** + * Helper function for the getter functions below + * Calls the Lua function in the directory specified, stores the data + * in the Lua virtual stack for the getter functions to extract and return + * Parameters: + * - the object_t struct that contains the argument list to be passed to Lua + * - the Lua script directory + * Returns: + * - the Lua state with the return value of the Lua script extracted and placed + * in the virtual stack + */ +lua_State *callLua(object_t *ot, char *lua_path); + +#endif \ No newline at end of file diff --git a/include/custom-scripts/obj_custom_type.h b/include/custom-scripts/obj_custom_type.h new file mode 100644 index 0000000000..b14eb63196 --- /dev/null +++ b/include/custom-scripts/obj_custom_type.h @@ -0,0 +1,51 @@ +#ifndef _OBJ_CUSTOM_TYPE_H_ +#define _OBJ_CUSTOM_TYPE_H_ + +#include "arg_custom_type.h" + +typedef struct obj_t +{ + // Type of underlying data + data_type_t type; + + // Whether this data will be represented by a Lua script + bool is_lua; + + // Data associated with the object + data_t data; + + // Linked list of arguments + arg_t *args; +} object_t; + +/** + * obj_t_new() creates an empty object_t struct + * Returns: + * - pointer to an empty object struct + */ +object_t *obj_t_new(); + +/** + * obj_t_bool() creates an object_t struct containing a boolean + * Parameters: + * - bool value to be stored + * - Lua script (NULL if no script to be specified) + * - argument linked list to be passed to Lua if applicable + * Returns: + * - pointer to an object struct containing the bool + */ +object_t *obj_t_init(data_t d, data_type_t t, char *lua); + +// ============================================================================ + +/** + * obj_add_arg_bool adds a bool to the argument linked list of the object_t + * Parameters: + * - the object whose argument list is to be added to + * - the boolean to be added + * Returns: + * - the updated object + */ +object_t *obj_add_arg(object_t *obj, data_t d, data_type_t t); + +#endif \ No newline at end of file diff --git a/include/custom-scripts/utlist b/include/custom-scripts/utlist new file mode 160000 index 0000000000..44a66fe8e0 --- /dev/null +++ b/include/custom-scripts/utlist @@ -0,0 +1 @@ +Subproject commit 44a66fe8e008c0a7f1c5af96f4a4cdf304b8bc81 diff --git a/include/custom-scripts/utlist.h b/include/custom-scripts/utlist.h new file mode 100644 index 0000000000..492908cf10 --- /dev/null +++ b/include/custom-scripts/utlist.h @@ -0,0 +1,1073 @@ +/* +Copyright (c) 2007-2022, Troy D. Hanson https://troydhanson.github.io/uthash/ +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER +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 UTLIST_H +#define UTLIST_H + +#define UTLIST_VERSION 2.3.0 + +#include + +/* + * This file contains macros to manipulate singly and doubly-linked lists. + * + * 1. LL_ macros: singly-linked lists. + * 2. DL_ macros: doubly-linked lists. + * 3. CDL_ macros: circular doubly-linked lists. + * + * To use singly-linked lists, your structure must have a "next" pointer. + * To use doubly-linked lists, your structure must "prev" and "next" pointers. + * Either way, the pointer to the head of the list must be initialized to NULL. + * + * ----------------.EXAMPLE ------------------------- + * struct item { + * int id; + * struct item *prev, *next; + * } + * + * struct item *list = NULL: + * + * int main() { + * struct item *item; + * ... allocate and populate item ... + * DL_APPEND(list, item); + * } + * -------------------------------------------------- + * + * For doubly-linked lists, the append and delete macros are O(1) + * For singly-linked lists, append and delete are O(n) but prepend is O(1) + * The sort macro is O(n log(n)) for all types of single/double/circular lists. + */ + +/* These macros use decltype or the earlier __typeof GNU extension. + As decltype is only available in newer compilers (VS2010 or gcc 4.3+ + when compiling c++ source) this code uses whatever method is needed + or, for VS2008 where neither is available, uses casting workarounds. */ +#if !defined(LDECLTYPE) && !defined(NO_DECLTYPE) +#if defined(_MSC_VER) /* MS compiler */ +#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ +#define LDECLTYPE(x) decltype(x) +#else /* VS2008 or older (or VS2010 in C mode) */ +#define NO_DECLTYPE +#endif +#elif defined(__BORLANDC__) || defined(__ICCARM__) || defined(__LCC__) || defined(__WATCOMC__) +#define NO_DECLTYPE +#else /* GNU, Sun and other compilers */ +#define LDECLTYPE(x) __typeof(x) +#endif +#endif + +/* for VS2008 we use some workarounds to get around the lack of decltype, + * namely, we always reassign our tmp variable to the list head if we need + * to dereference its prev/next pointers, and save/restore the real head.*/ +#ifdef NO_DECLTYPE +#define IF_NO_DECLTYPE(x) x +#define LDECLTYPE(x) char* +#define UTLIST_SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); } +#define UTLIST_NEXT(elt,list,next) ((char*)((list)->next)) +#define UTLIST_NEXTASGN(elt,list,to,next) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); } +/* #define UTLIST_PREV(elt,list,prev) ((char*)((list)->prev)) */ +#define UTLIST_PREVASGN(elt,list,to,prev) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); } +#define UTLIST_RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; } +#define UTLIST_CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); } +#else +#define IF_NO_DECLTYPE(x) +#define UTLIST_SV(elt,list) +#define UTLIST_NEXT(elt,list,next) ((elt)->next) +#define UTLIST_NEXTASGN(elt,list,to,next) ((elt)->next)=(to) +/* #define UTLIST_PREV(elt,list,prev) ((elt)->prev) */ +#define UTLIST_PREVASGN(elt,list,to,prev) ((elt)->prev)=(to) +#define UTLIST_RS(list) +#define UTLIST_CASTASGN(a,b) (a)=(b) +#endif + +/****************************************************************************** + * The sort macro is an adaptation of Simon Tatham's O(n log(n)) mergesort * + * Unwieldy variable names used here to avoid shadowing passed-in variables. * + *****************************************************************************/ +#define LL_SORT(list, cmp) \ + LL_SORT2(list, cmp, next) + +#define LL_SORT2(list, cmp, next) \ +do { \ + LDECLTYPE(list) _ls_p; \ + LDECLTYPE(list) _ls_q; \ + LDECLTYPE(list) _ls_e; \ + LDECLTYPE(list) _ls_tail; \ + IF_NO_DECLTYPE(LDECLTYPE(list) _tmp;) \ + int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ + if (list) { \ + _ls_insize = 1; \ + _ls_looping = 1; \ + while (_ls_looping) { \ + UTLIST_CASTASGN(_ls_p,list); \ + (list) = NULL; \ + _ls_tail = NULL; \ + _ls_nmerges = 0; \ + while (_ls_p) { \ + _ls_nmerges++; \ + _ls_q = _ls_p; \ + _ls_psize = 0; \ + for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ + _ls_psize++; \ + UTLIST_SV(_ls_q,list); _ls_q = UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); \ + if (!_ls_q) break; \ + } \ + _ls_qsize = _ls_insize; \ + while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ + if (_ls_psize == 0) { \ + _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \ + UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \ + } else if (_ls_qsize == 0 || !_ls_q) { \ + _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \ + UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \ + } else if (cmp(_ls_p,_ls_q) <= 0) { \ + _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \ + UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \ + } else { \ + _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \ + UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \ + } \ + if (_ls_tail) { \ + UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,_ls_e,next); UTLIST_RS(list); \ + } else { \ + UTLIST_CASTASGN(list,_ls_e); \ + } \ + _ls_tail = _ls_e; \ + } \ + _ls_p = _ls_q; \ + } \ + if (_ls_tail) { \ + UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,NULL,next); UTLIST_RS(list); \ + } \ + if (_ls_nmerges <= 1) { \ + _ls_looping=0; \ + } \ + _ls_insize *= 2; \ + } \ + } \ +} while (0) + + +#define DL_SORT(list, cmp) \ + DL_SORT2(list, cmp, prev, next) + +#define DL_SORT2(list, cmp, prev, next) \ +do { \ + LDECLTYPE(list) _ls_p; \ + LDECLTYPE(list) _ls_q; \ + LDECLTYPE(list) _ls_e; \ + LDECLTYPE(list) _ls_tail; \ + IF_NO_DECLTYPE(LDECLTYPE(list) _tmp;) \ + int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ + if (list) { \ + _ls_insize = 1; \ + _ls_looping = 1; \ + while (_ls_looping) { \ + UTLIST_CASTASGN(_ls_p,list); \ + (list) = NULL; \ + _ls_tail = NULL; \ + _ls_nmerges = 0; \ + while (_ls_p) { \ + _ls_nmerges++; \ + _ls_q = _ls_p; \ + _ls_psize = 0; \ + for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ + _ls_psize++; \ + UTLIST_SV(_ls_q,list); _ls_q = UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); \ + if (!_ls_q) break; \ + } \ + _ls_qsize = _ls_insize; \ + while ((_ls_psize > 0) || ((_ls_qsize > 0) && _ls_q)) { \ + if (_ls_psize == 0) { \ + _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \ + UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \ + } else if ((_ls_qsize == 0) || (!_ls_q)) { \ + _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \ + UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \ + } else if (cmp(_ls_p,_ls_q) <= 0) { \ + _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \ + UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \ + } else { \ + _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \ + UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \ + } \ + if (_ls_tail) { \ + UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,_ls_e,next); UTLIST_RS(list); \ + } else { \ + UTLIST_CASTASGN(list,_ls_e); \ + } \ + UTLIST_SV(_ls_e,list); UTLIST_PREVASGN(_ls_e,list,_ls_tail,prev); UTLIST_RS(list); \ + _ls_tail = _ls_e; \ + } \ + _ls_p = _ls_q; \ + } \ + UTLIST_CASTASGN((list)->prev, _ls_tail); \ + UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,NULL,next); UTLIST_RS(list); \ + if (_ls_nmerges <= 1) { \ + _ls_looping=0; \ + } \ + _ls_insize *= 2; \ + } \ + } \ +} while (0) + +#define CDL_SORT(list, cmp) \ + CDL_SORT2(list, cmp, prev, next) + +#define CDL_SORT2(list, cmp, prev, next) \ +do { \ + LDECLTYPE(list) _ls_p; \ + LDECLTYPE(list) _ls_q; \ + LDECLTYPE(list) _ls_e; \ + LDECLTYPE(list) _ls_tail; \ + LDECLTYPE(list) _ls_oldhead; \ + LDECLTYPE(list) _tmp; \ + int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ + if (list) { \ + _ls_insize = 1; \ + _ls_looping = 1; \ + while (_ls_looping) { \ + UTLIST_CASTASGN(_ls_p,list); \ + UTLIST_CASTASGN(_ls_oldhead,list); \ + (list) = NULL; \ + _ls_tail = NULL; \ + _ls_nmerges = 0; \ + while (_ls_p) { \ + _ls_nmerges++; \ + _ls_q = _ls_p; \ + _ls_psize = 0; \ + for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ + _ls_psize++; \ + UTLIST_SV(_ls_q,list); \ + if (UTLIST_NEXT(_ls_q,list,next) == _ls_oldhead) { \ + _ls_q = NULL; \ + } else { \ + _ls_q = UTLIST_NEXT(_ls_q,list,next); \ + } \ + UTLIST_RS(list); \ + if (!_ls_q) break; \ + } \ + _ls_qsize = _ls_insize; \ + while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ + if (_ls_psize == 0) { \ + _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \ + UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \ + if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ + } else if (_ls_qsize == 0 || !_ls_q) { \ + _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \ + UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \ + if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ + } else if (cmp(_ls_p,_ls_q) <= 0) { \ + _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \ + UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \ + if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ + } else { \ + _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \ + UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \ + if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ + } \ + if (_ls_tail) { \ + UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,_ls_e,next); UTLIST_RS(list); \ + } else { \ + UTLIST_CASTASGN(list,_ls_e); \ + } \ + UTLIST_SV(_ls_e,list); UTLIST_PREVASGN(_ls_e,list,_ls_tail,prev); UTLIST_RS(list); \ + _ls_tail = _ls_e; \ + } \ + _ls_p = _ls_q; \ + } \ + UTLIST_CASTASGN((list)->prev,_ls_tail); \ + UTLIST_CASTASGN(_tmp,list); \ + UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,_tmp,next); UTLIST_RS(list); \ + if (_ls_nmerges <= 1) { \ + _ls_looping=0; \ + } \ + _ls_insize *= 2; \ + } \ + } \ +} while (0) + +/****************************************************************************** + * singly linked list macros (non-circular) * + *****************************************************************************/ +#define LL_PREPEND(head,add) \ + LL_PREPEND2(head,add,next) + +#define LL_PREPEND2(head,add,next) \ +do { \ + (add)->next = (head); \ + (head) = (add); \ +} while (0) + +#define LL_CONCAT(head1,head2) \ + LL_CONCAT2(head1,head2,next) + +#define LL_CONCAT2(head1,head2,next) \ +do { \ + LDECLTYPE(head1) _tmp; \ + if (head1) { \ + _tmp = (head1); \ + while (_tmp->next) { _tmp = _tmp->next; } \ + _tmp->next=(head2); \ + } else { \ + (head1)=(head2); \ + } \ +} while (0) + +#define LL_APPEND(head,add) \ + LL_APPEND2(head,add,next) + +#define LL_APPEND2(head,add,next) \ +do { \ + LDECLTYPE(head) _tmp; \ + (add)->next=NULL; \ + if (head) { \ + _tmp = (head); \ + while (_tmp->next) { _tmp = _tmp->next; } \ + _tmp->next=(add); \ + } else { \ + (head)=(add); \ + } \ +} while (0) + +#define LL_INSERT_INORDER(head,add,cmp) \ + LL_INSERT_INORDER2(head,add,cmp,next) + +#define LL_INSERT_INORDER2(head,add,cmp,next) \ +do { \ + LDECLTYPE(head) _tmp; \ + if (head) { \ + LL_LOWER_BOUND2(head, _tmp, add, cmp, next); \ + LL_APPEND_ELEM2(head, _tmp, add, next); \ + } else { \ + (head) = (add); \ + (head)->next = NULL; \ + } \ +} while (0) + +#define LL_LOWER_BOUND(head,elt,like,cmp) \ + LL_LOWER_BOUND2(head,elt,like,cmp,next) + +#define LL_LOWER_BOUND2(head,elt,like,cmp,next) \ + do { \ + if ((head) == NULL || (cmp(head, like)) >= 0) { \ + (elt) = NULL; \ + } else { \ + for ((elt) = (head); (elt)->next != NULL; (elt) = (elt)->next) { \ + if (cmp((elt)->next, like) >= 0) { \ + break; \ + } \ + } \ + } \ + } while (0) + +#define LL_DELETE(head,del) \ + LL_DELETE2(head,del,next) + +#define LL_DELETE2(head,del,next) \ +do { \ + LDECLTYPE(head) _tmp; \ + if ((head) == (del)) { \ + (head)=(head)->next; \ + } else { \ + _tmp = (head); \ + while (_tmp->next && (_tmp->next != (del))) { \ + _tmp = _tmp->next; \ + } \ + if (_tmp->next) { \ + _tmp->next = (del)->next; \ + } \ + } \ +} while (0) + +#define LL_COUNT(head,el,counter) \ + LL_COUNT2(head,el,counter,next) \ + +#define LL_COUNT2(head,el,counter,next) \ +do { \ + (counter) = 0; \ + LL_FOREACH2(head,el,next) { ++(counter); } \ +} while (0) + +#define LL_FOREACH(head,el) \ + LL_FOREACH2(head,el,next) + +#define LL_FOREACH2(head,el,next) \ + for ((el) = (head); el; (el) = (el)->next) + +#define LL_FOREACH_SAFE(head,el,tmp) \ + LL_FOREACH_SAFE2(head,el,tmp,next) + +#define LL_FOREACH_SAFE2(head,el,tmp,next) \ + for ((el) = (head); (el) && ((tmp) = (el)->next, 1); (el) = (tmp)) + +#define LL_SEARCH_SCALAR(head,out,field,val) \ + LL_SEARCH_SCALAR2(head,out,field,val,next) + +#define LL_SEARCH_SCALAR2(head,out,field,val,next) \ +do { \ + LL_FOREACH2(head,out,next) { \ + if ((out)->field == (val)) break; \ + } \ +} while (0) + +#define LL_SEARCH(head,out,elt,cmp) \ + LL_SEARCH2(head,out,elt,cmp,next) + +#define LL_SEARCH2(head,out,elt,cmp,next) \ +do { \ + LL_FOREACH2(head,out,next) { \ + if ((cmp(out,elt))==0) break; \ + } \ +} while (0) + +#define LL_REPLACE_ELEM2(head, el, add, next) \ +do { \ + LDECLTYPE(head) _tmp; \ + assert((head) != NULL); \ + assert((el) != NULL); \ + assert((add) != NULL); \ + (add)->next = (el)->next; \ + if ((head) == (el)) { \ + (head) = (add); \ + } else { \ + _tmp = (head); \ + while (_tmp->next && (_tmp->next != (el))) { \ + _tmp = _tmp->next; \ + } \ + if (_tmp->next) { \ + _tmp->next = (add); \ + } \ + } \ +} while (0) + +#define LL_REPLACE_ELEM(head, el, add) \ + LL_REPLACE_ELEM2(head, el, add, next) + +#define LL_PREPEND_ELEM2(head, el, add, next) \ +do { \ + if (el) { \ + LDECLTYPE(head) _tmp; \ + assert((head) != NULL); \ + assert((add) != NULL); \ + (add)->next = (el); \ + if ((head) == (el)) { \ + (head) = (add); \ + } else { \ + _tmp = (head); \ + while (_tmp->next && (_tmp->next != (el))) { \ + _tmp = _tmp->next; \ + } \ + if (_tmp->next) { \ + _tmp->next = (add); \ + } \ + } \ + } else { \ + LL_APPEND2(head, add, next); \ + } \ +} while (0) \ + +#define LL_PREPEND_ELEM(head, el, add) \ + LL_PREPEND_ELEM2(head, el, add, next) + +#define LL_APPEND_ELEM2(head, el, add, next) \ +do { \ + if (el) { \ + assert((head) != NULL); \ + assert((add) != NULL); \ + (add)->next = (el)->next; \ + (el)->next = (add); \ + } else { \ + LL_PREPEND2(head, add, next); \ + } \ +} while (0) \ + +#define LL_APPEND_ELEM(head, el, add) \ + LL_APPEND_ELEM2(head, el, add, next) + +#ifdef NO_DECLTYPE +/* Here are VS2008 / NO_DECLTYPE replacements for a few functions */ + +#undef LL_CONCAT2 +#define LL_CONCAT2(head1,head2,next) \ +do { \ + char *_tmp; \ + if (head1) { \ + _tmp = (char*)(head1); \ + while ((head1)->next) { (head1) = (head1)->next; } \ + (head1)->next = (head2); \ + UTLIST_RS(head1); \ + } else { \ + (head1)=(head2); \ + } \ +} while (0) + +#undef LL_APPEND2 +#define LL_APPEND2(head,add,next) \ +do { \ + if (head) { \ + (add)->next = head; /* use add->next as a temp variable */ \ + while ((add)->next->next) { (add)->next = (add)->next->next; } \ + (add)->next->next=(add); \ + } else { \ + (head)=(add); \ + } \ + (add)->next=NULL; \ +} while (0) + +#undef LL_INSERT_INORDER2 +#define LL_INSERT_INORDER2(head,add,cmp,next) \ +do { \ + if ((head) == NULL || (cmp(head, add)) >= 0) { \ + (add)->next = (head); \ + (head) = (add); \ + } else { \ + char *_tmp = (char*)(head); \ + while ((head)->next != NULL && (cmp((head)->next, add)) < 0) { \ + (head) = (head)->next; \ + } \ + (add)->next = (head)->next; \ + (head)->next = (add); \ + UTLIST_RS(head); \ + } \ +} while (0) + +#undef LL_DELETE2 +#define LL_DELETE2(head,del,next) \ +do { \ + if ((head) == (del)) { \ + (head)=(head)->next; \ + } else { \ + char *_tmp = (char*)(head); \ + while ((head)->next && ((head)->next != (del))) { \ + (head) = (head)->next; \ + } \ + if ((head)->next) { \ + (head)->next = ((del)->next); \ + } \ + UTLIST_RS(head); \ + } \ +} while (0) + +#undef LL_REPLACE_ELEM2 +#define LL_REPLACE_ELEM2(head, el, add, next) \ +do { \ + assert((head) != NULL); \ + assert((el) != NULL); \ + assert((add) != NULL); \ + if ((head) == (el)) { \ + (head) = (add); \ + } else { \ + (add)->next = head; \ + while ((add)->next->next && ((add)->next->next != (el))) { \ + (add)->next = (add)->next->next; \ + } \ + if ((add)->next->next) { \ + (add)->next->next = (add); \ + } \ + } \ + (add)->next = (el)->next; \ +} while (0) + +#undef LL_PREPEND_ELEM2 +#define LL_PREPEND_ELEM2(head, el, add, next) \ +do { \ + if (el) { \ + assert((head) != NULL); \ + assert((add) != NULL); \ + if ((head) == (el)) { \ + (head) = (add); \ + } else { \ + (add)->next = (head); \ + while ((add)->next->next && ((add)->next->next != (el))) { \ + (add)->next = (add)->next->next; \ + } \ + if ((add)->next->next) { \ + (add)->next->next = (add); \ + } \ + } \ + (add)->next = (el); \ + } else { \ + LL_APPEND2(head, add, next); \ + } \ +} while (0) \ + +#endif /* NO_DECLTYPE */ + +/****************************************************************************** + * doubly linked list macros (non-circular) * + *****************************************************************************/ +#define DL_PREPEND(head,add) \ + DL_PREPEND2(head,add,prev,next) + +#define DL_PREPEND2(head,add,prev,next) \ +do { \ + (add)->next = (head); \ + if (head) { \ + (add)->prev = (head)->prev; \ + (head)->prev = (add); \ + } else { \ + (add)->prev = (add); \ + } \ + (head) = (add); \ +} while (0) + +#define DL_APPEND(head,add) \ + DL_APPEND2(head,add,prev,next) + +#define DL_APPEND2(head,add,prev,next) \ +do { \ + if (head) { \ + (add)->prev = (head)->prev; \ + (head)->prev->next = (add); \ + (head)->prev = (add); \ + (add)->next = NULL; \ + } else { \ + (head)=(add); \ + (head)->prev = (head); \ + (head)->next = NULL; \ + } \ +} while (0) + +#define DL_INSERT_INORDER(head,add,cmp) \ + DL_INSERT_INORDER2(head,add,cmp,prev,next) + +#define DL_INSERT_INORDER2(head,add,cmp,prev,next) \ +do { \ + LDECLTYPE(head) _tmp; \ + if (head) { \ + DL_LOWER_BOUND2(head, _tmp, add, cmp, next); \ + DL_APPEND_ELEM2(head, _tmp, add, prev, next); \ + } else { \ + (head) = (add); \ + (head)->prev = (head); \ + (head)->next = NULL; \ + } \ +} while (0) + +#define DL_LOWER_BOUND(head,elt,like,cmp) \ + DL_LOWER_BOUND2(head,elt,like,cmp,next) + +#define DL_LOWER_BOUND2(head,elt,like,cmp,next) \ +do { \ + if ((head) == NULL || (cmp(head, like)) >= 0) { \ + (elt) = NULL; \ + } else { \ + for ((elt) = (head); (elt)->next != NULL; (elt) = (elt)->next) { \ + if ((cmp((elt)->next, like)) >= 0) { \ + break; \ + } \ + } \ + } \ +} while (0) + +#define DL_CONCAT(head1,head2) \ + DL_CONCAT2(head1,head2,prev,next) + +#define DL_CONCAT2(head1,head2,prev,next) \ +do { \ + LDECLTYPE(head1) _tmp; \ + if (head2) { \ + if (head1) { \ + UTLIST_CASTASGN(_tmp, (head2)->prev); \ + (head2)->prev = (head1)->prev; \ + (head1)->prev->next = (head2); \ + UTLIST_CASTASGN((head1)->prev, _tmp); \ + } else { \ + (head1)=(head2); \ + } \ + } \ +} while (0) + +#define DL_DELETE(head,del) \ + DL_DELETE2(head,del,prev,next) + +#define DL_DELETE2(head,del,prev,next) \ +do { \ + assert((head) != NULL); \ + assert((del)->prev != NULL); \ + if ((del)->prev == (del)) { \ + (head)=NULL; \ + } else if ((del)==(head)) { \ + (del)->next->prev = (del)->prev; \ + (head) = (del)->next; \ + } else { \ + (del)->prev->next = (del)->next; \ + if ((del)->next) { \ + (del)->next->prev = (del)->prev; \ + } else { \ + (head)->prev = (del)->prev; \ + } \ + } \ +} while (0) + +#define DL_COUNT(head,el,counter) \ + DL_COUNT2(head,el,counter,next) \ + +#define DL_COUNT2(head,el,counter,next) \ +do { \ + (counter) = 0; \ + DL_FOREACH2(head,el,next) { ++(counter); } \ +} while (0) + +#define DL_FOREACH(head,el) \ + DL_FOREACH2(head,el,next) + +#define DL_FOREACH2(head,el,next) \ + for ((el) = (head); el; (el) = (el)->next) + +/* this version is safe for deleting the elements during iteration */ +#define DL_FOREACH_SAFE(head,el,tmp) \ + DL_FOREACH_SAFE2(head,el,tmp,next) + +#define DL_FOREACH_SAFE2(head,el,tmp,next) \ + for ((el) = (head); (el) && ((tmp) = (el)->next, 1); (el) = (tmp)) + +/* these are identical to their singly-linked list counterparts */ +#define DL_SEARCH_SCALAR LL_SEARCH_SCALAR +#define DL_SEARCH LL_SEARCH +#define DL_SEARCH_SCALAR2 LL_SEARCH_SCALAR2 +#define DL_SEARCH2 LL_SEARCH2 + +#define DL_REPLACE_ELEM2(head, el, add, prev, next) \ +do { \ + assert((head) != NULL); \ + assert((el) != NULL); \ + assert((add) != NULL); \ + if ((head) == (el)) { \ + (head) = (add); \ + (add)->next = (el)->next; \ + if ((el)->next == NULL) { \ + (add)->prev = (add); \ + } else { \ + (add)->prev = (el)->prev; \ + (add)->next->prev = (add); \ + } \ + } else { \ + (add)->next = (el)->next; \ + (add)->prev = (el)->prev; \ + (add)->prev->next = (add); \ + if ((el)->next == NULL) { \ + (head)->prev = (add); \ + } else { \ + (add)->next->prev = (add); \ + } \ + } \ +} while (0) + +#define DL_REPLACE_ELEM(head, el, add) \ + DL_REPLACE_ELEM2(head, el, add, prev, next) + +#define DL_PREPEND_ELEM2(head, el, add, prev, next) \ +do { \ + if (el) { \ + assert((head) != NULL); \ + assert((add) != NULL); \ + (add)->next = (el); \ + (add)->prev = (el)->prev; \ + (el)->prev = (add); \ + if ((head) == (el)) { \ + (head) = (add); \ + } else { \ + (add)->prev->next = (add); \ + } \ + } else { \ + DL_APPEND2(head, add, prev, next); \ + } \ +} while (0) \ + +#define DL_PREPEND_ELEM(head, el, add) \ + DL_PREPEND_ELEM2(head, el, add, prev, next) + +#define DL_APPEND_ELEM2(head, el, add, prev, next) \ +do { \ + if (el) { \ + assert((head) != NULL); \ + assert((add) != NULL); \ + (add)->next = (el)->next; \ + (add)->prev = (el); \ + (el)->next = (add); \ + if ((add)->next) { \ + (add)->next->prev = (add); \ + } else { \ + (head)->prev = (add); \ + } \ + } else { \ + DL_PREPEND2(head, add, prev, next); \ + } \ +} while (0) \ + +#define DL_APPEND_ELEM(head, el, add) \ + DL_APPEND_ELEM2(head, el, add, prev, next) + +#ifdef NO_DECLTYPE +/* Here are VS2008 / NO_DECLTYPE replacements for a few functions */ + +#undef DL_INSERT_INORDER2 +#define DL_INSERT_INORDER2(head,add,cmp,prev,next) \ +do { \ + if ((head) == NULL) { \ + (add)->prev = (add); \ + (add)->next = NULL; \ + (head) = (add); \ + } else if ((cmp(head, add)) >= 0) { \ + (add)->prev = (head)->prev; \ + (add)->next = (head); \ + (head)->prev = (add); \ + (head) = (add); \ + } else { \ + char *_tmp = (char*)(head); \ + while ((head)->next && (cmp((head)->next, add)) < 0) { \ + (head) = (head)->next; \ + } \ + (add)->prev = (head); \ + (add)->next = (head)->next; \ + (head)->next = (add); \ + UTLIST_RS(head); \ + if ((add)->next) { \ + (add)->next->prev = (add); \ + } else { \ + (head)->prev = (add); \ + } \ + } \ +} while (0) +#endif /* NO_DECLTYPE */ + +/****************************************************************************** + * circular doubly linked list macros * + *****************************************************************************/ +#define CDL_APPEND(head,add) \ + CDL_APPEND2(head,add,prev,next) + +#define CDL_APPEND2(head,add,prev,next) \ +do { \ + if (head) { \ + (add)->prev = (head)->prev; \ + (add)->next = (head); \ + (head)->prev = (add); \ + (add)->prev->next = (add); \ + } else { \ + (add)->prev = (add); \ + (add)->next = (add); \ + (head) = (add); \ + } \ +} while (0) + +#define CDL_PREPEND(head,add) \ + CDL_PREPEND2(head,add,prev,next) + +#define CDL_PREPEND2(head,add,prev,next) \ +do { \ + if (head) { \ + (add)->prev = (head)->prev; \ + (add)->next = (head); \ + (head)->prev = (add); \ + (add)->prev->next = (add); \ + } else { \ + (add)->prev = (add); \ + (add)->next = (add); \ + } \ + (head) = (add); \ +} while (0) + +#define CDL_INSERT_INORDER(head,add,cmp) \ + CDL_INSERT_INORDER2(head,add,cmp,prev,next) + +#define CDL_INSERT_INORDER2(head,add,cmp,prev,next) \ +do { \ + LDECLTYPE(head) _tmp; \ + if (head) { \ + CDL_LOWER_BOUND2(head, _tmp, add, cmp, next); \ + CDL_APPEND_ELEM2(head, _tmp, add, prev, next); \ + } else { \ + (head) = (add); \ + (head)->next = (head); \ + (head)->prev = (head); \ + } \ +} while (0) + +#define CDL_LOWER_BOUND(head,elt,like,cmp) \ + CDL_LOWER_BOUND2(head,elt,like,cmp,next) + +#define CDL_LOWER_BOUND2(head,elt,like,cmp,next) \ +do { \ + if ((head) == NULL || (cmp(head, like)) >= 0) { \ + (elt) = NULL; \ + } else { \ + for ((elt) = (head); (elt)->next != (head); (elt) = (elt)->next) { \ + if ((cmp((elt)->next, like)) >= 0) { \ + break; \ + } \ + } \ + } \ +} while (0) + +#define CDL_DELETE(head,del) \ + CDL_DELETE2(head,del,prev,next) + +#define CDL_DELETE2(head,del,prev,next) \ +do { \ + if (((head)==(del)) && ((head)->next == (head))) { \ + (head) = NULL; \ + } else { \ + (del)->next->prev = (del)->prev; \ + (del)->prev->next = (del)->next; \ + if ((del) == (head)) (head)=(del)->next; \ + } \ +} while (0) + +#define CDL_COUNT(head,el,counter) \ + CDL_COUNT2(head,el,counter,next) \ + +#define CDL_COUNT2(head, el, counter,next) \ +do { \ + (counter) = 0; \ + CDL_FOREACH2(head,el,next) { ++(counter); } \ +} while (0) + +#define CDL_FOREACH(head,el) \ + CDL_FOREACH2(head,el,next) + +#define CDL_FOREACH2(head,el,next) \ + for ((el)=(head);el;(el)=(((el)->next==(head)) ? NULL : (el)->next)) + +#define CDL_FOREACH_SAFE(head,el,tmp1,tmp2) \ + CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next) + +#define CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next) \ + for ((el) = (head), (tmp1) = (head) ? (head)->prev : NULL; \ + (el) && ((tmp2) = (el)->next, 1); \ + (el) = ((el) == (tmp1) ? NULL : (tmp2))) + +#define CDL_SEARCH_SCALAR(head,out,field,val) \ + CDL_SEARCH_SCALAR2(head,out,field,val,next) + +#define CDL_SEARCH_SCALAR2(head,out,field,val,next) \ +do { \ + CDL_FOREACH2(head,out,next) { \ + if ((out)->field == (val)) break; \ + } \ +} while (0) + +#define CDL_SEARCH(head,out,elt,cmp) \ + CDL_SEARCH2(head,out,elt,cmp,next) + +#define CDL_SEARCH2(head,out,elt,cmp,next) \ +do { \ + CDL_FOREACH2(head,out,next) { \ + if ((cmp(out,elt))==0) break; \ + } \ +} while (0) + +#define CDL_REPLACE_ELEM2(head, el, add, prev, next) \ +do { \ + assert((head) != NULL); \ + assert((el) != NULL); \ + assert((add) != NULL); \ + if ((el)->next == (el)) { \ + (add)->next = (add); \ + (add)->prev = (add); \ + (head) = (add); \ + } else { \ + (add)->next = (el)->next; \ + (add)->prev = (el)->prev; \ + (add)->next->prev = (add); \ + (add)->prev->next = (add); \ + if ((head) == (el)) { \ + (head) = (add); \ + } \ + } \ +} while (0) + +#define CDL_REPLACE_ELEM(head, el, add) \ + CDL_REPLACE_ELEM2(head, el, add, prev, next) + +#define CDL_PREPEND_ELEM2(head, el, add, prev, next) \ +do { \ + if (el) { \ + assert((head) != NULL); \ + assert((add) != NULL); \ + (add)->next = (el); \ + (add)->prev = (el)->prev; \ + (el)->prev = (add); \ + (add)->prev->next = (add); \ + if ((head) == (el)) { \ + (head) = (add); \ + } \ + } else { \ + CDL_APPEND2(head, add, prev, next); \ + } \ +} while (0) + +#define CDL_PREPEND_ELEM(head, el, add) \ + CDL_PREPEND_ELEM2(head, el, add, prev, next) + +#define CDL_APPEND_ELEM2(head, el, add, prev, next) \ +do { \ + if (el) { \ + assert((head) != NULL); \ + assert((add) != NULL); \ + (add)->next = (el)->next; \ + (add)->prev = (el); \ + (el)->next = (add); \ + (add)->next->prev = (add); \ + } else { \ + CDL_PREPEND2(head, add, prev, next); \ + } \ +} while (0) + +#define CDL_APPEND_ELEM(head, el, add) \ + CDL_APPEND_ELEM2(head, el, add, prev, next) + +#ifdef NO_DECLTYPE +/* Here are VS2008 / NO_DECLTYPE replacements for a few functions */ + +#undef CDL_INSERT_INORDER2 +#define CDL_INSERT_INORDER2(head,add,cmp,prev,next) \ +do { \ + if ((head) == NULL) { \ + (add)->prev = (add); \ + (add)->next = (add); \ + (head) = (add); \ + } else if ((cmp(head, add)) >= 0) { \ + (add)->prev = (head)->prev; \ + (add)->next = (head); \ + (add)->prev->next = (add); \ + (head)->prev = (add); \ + (head) = (add); \ + } else { \ + char *_tmp = (char*)(head); \ + while ((char*)(head)->next != _tmp && (cmp((head)->next, add)) < 0) { \ + (head) = (head)->next; \ + } \ + (add)->prev = (head); \ + (add)->next = (head)->next; \ + (add)->next->prev = (add); \ + (head)->next = (add); \ + UTLIST_RS(head); \ + } \ +} while (0) +#endif /* NO_DECLTYPE */ + +#endif /* UTLIST_H */ diff --git a/src/custom-scripts/CMakeLists.txt b/src/custom-scripts/CMakeLists.txt index cda50ee087..aa200c1413 100644 --- a/src/custom-scripts/CMakeLists.txt +++ b/src/custom-scripts/CMakeLists.txt @@ -1,5 +1,8 @@ add_library(custom-scripts - src/custom_type.c) + src/arg_custom_type.c + src/get_custom_type.c + src/lua_custom_type.c + src/obj_custom_type.c) target_link_libraries(custom-scripts ${LUA_LIBRARIES}) target_include_directories(custom-scripts PRIVATE ${LUA_INCLUDE_DIR}) diff --git a/src/custom-scripts/examples/CMakeLists.txt b/src/custom-scripts/examples/CMakeLists.txt index 182c96a677..a42f35a7d3 100644 --- a/src/custom-scripts/examples/CMakeLists.txt +++ b/src/custom-scripts/examples/CMakeLists.txt @@ -1,13 +1,11 @@ -set(CS_EXAMPLES demonstration) - -add_executable(demonstration - demonstration.c) - -target_link_libraries(demonstration ${LUA_LIBRARIES}) -target_include_directories(demonstration PRIVATE ${LUA_INCLUDE_DIR}) +set(CS_EXAMPLES demo_old demonstration) # Link with chiventure libraries foreach(example ${CS_EXAMPLES}) + add_executable(${example} + ${example}.c) + target_link_libraries(${example} ${LUA_LIBRARIES}) + target_include_directories(${example} PRIVATE ${LUA_INCLUDE_DIR}) foreach(module ${CHIVENTURE_MODULES}) target_link_libraries(${example} ${module}) endforeach(module) diff --git a/src/custom-scripts/examples/demo-warrior.wdl b/src/custom-scripts/examples/demo-warrior.wdl new file mode 100644 index 0000000000..41e3b3706f --- /dev/null +++ b/src/custom-scripts/examples/demo-warrior.wdl @@ -0,0 +1,153 @@ +{ + "GAME": { + "start": "room_A", + "intro": "This is a test game for the Warrior Class. It is based off connected-rooms.wdl", + "end": { + "in_room": "room_C" + } + }, + "ROOMS": { + "room_A": { + "short_desc": "This is room A", + "long_desc": "This is room A. There's a chair and an exit to the north.", + "connections": [ + { + "to": "room_B", + "direction": "NORTH" + } + ] + }, + "room_B": { + "short_desc": "This is room B", + "long_desc": "This is room B. There's a table, an exit to the south, and an exit to the east.", + "connections": [ + { + "to": "room_A", + "direction": "SOUTH" + }, + { + "to": "room_C", + "direction": "EAST" + } + ] + }, + "room_C": { + "short_desc": "This is room C", + "long_desc": "This is room C, the final room in the game", + "connections": [ + { + "to": "room_A", + "direction": "SOUTH" + } + ] + } + }, + "ITEMS": { + "CHAIR": { + "short_desc": "This is a chair", + "long_desc": "This is a chair long", + "in": "room_A", + "actions": [ + { + "action": "PUSH", + "text_success": "You push the chair", + "text_fail": "You cannot push this chair" + }, + { + "action": "PULL", + "text_success": "You pull the chair", + "text_fail": "You cannot pull this chair" + }, + { + "action": "TAKE", + "text_success": "You take the chair", + "text_fail": "You cannot take this chair" + } + ] + }, + "SWORD": { + "short_desc": "This is a sword", + "long_desc": "This is a sword for a warrior", + "in": "room_A", + "actions": [ + { + "action": "PUSH", + "text_success": "You push the sword", + "text_fail": "You cannot push this sword" + }, + { + "action": "PULL", + "text_success": "You pull the sword", + "text_fail": "You cannot pull this sword" + }, + { + "action": "TAKE", + "text_success": "THIS IS SPARTA", + "text_fail": "You cannot take this sword unless you are a warrior class" + } + ] + }, + "BORJA": { + "short_desc": "This is the evil king", + "long_desc": "This is the evil king Borja", + "in": "room_B", + "actions": [ + { + "action": "PUSH", + "text_success": "You push the evil king", + "text_fail": "You cannot push this evil king" + }, + { + "action": "PULL", + "text_success": "You pull the evil king", + "text_fail": "You cannot pull this evil king" + }, + { + "action": "SLASH", + "text_success": "You defeated the evil king BORJA", + "text_fail": "You cannot slash without a sword", + "conditions": [ + { + "type": "INVENTORY", + "item_id": "SWORD" + } + ] + } + ] + }, + "TABLE": { + "short_desc": "This is a table", + "long_desc": "This is a table long", + "in": "room_B", + "actions": [ + { + "action": "PUSH", + "text_success": "You push the table", + "text_fail": "You cannot push this table. Maybe if you had a chair...", + "conditions": [ + { + "type": "INVENTORY", + "item_id": "CHAIR" + } + ] + }, + { + "action": "PULL", + "text_success": "You pull the table", + "text_fail": "You cannot pull this table" + }, + { + "action": "TAKE", + "text_success": "You take the table", + "text_fail": "You cannot take this table. Maybe if you had a chair...", + "conditions": [ + { + "type": "INVENTORY", + "item_id": "CHAIR" + } + ] + } + ] + } + } +} \ No newline at end of file diff --git a/src/custom-scripts/examples/demo.wdl b/src/custom-scripts/examples/demo.wdl new file mode 100644 index 0000000000..6a3373ab7e --- /dev/null +++ b/src/custom-scripts/examples/demo.wdl @@ -0,0 +1,153 @@ +{ + "GAME": { + "start": "room_A", + "intro": "This is a test game for the Wizard Class. It is based off connected-rooms.wdl", + "end": { + "in_room": "room_C" + } + }, + "ROOMS": { + "room_A": { + "short_desc": "This is room A", + "long_desc": "This is room A. There's a chair and an exit to the north.", + "connections": [ + { + "to": "room_B", + "direction": "NORTH" + } + ] + }, + "room_B": { + "short_desc": "This is room B", + "long_desc": "This is room B. There's a table, an exit to the south, and an exit to the east.", + "connections": [ + { + "to": "room_A", + "direction": "SOUTH" + }, + { + "to": "room_C", + "direction": "EAST" + } + ] + }, + "room_C": { + "short_desc": "This is room C", + "long_desc": "This is room C, the final room in the game", + "connections": [ + { + "to": "room_A", + "direction": "SOUTH" + } + ] + } + }, + "ITEMS": { + "CHAIR": { + "short_desc": "This is a chair", + "long_desc": "This is a chair long", + "in": "room_A", + "actions": [ + { + "action": "PUSH", + "text_success": "You push the chair", + "text_fail": "You cannot push this chair" + }, + { + "action": "PULL", + "text_success": "You pull the chair", + "text_fail": "You cannot pull this chair" + }, + { + "action": "TAKE", + "text_success": "You take the chair", + "text_fail": "You cannot take this chair" + } + ] + }, + "STAFF": { + "short_desc": "This is a staff", + "long_desc": "This is a staff for a wizard", + "in": "room_A", + "actions": [ + { + "action": "PUSH", + "text_success": "You push the staff", + "text_fail": "You cannot push this staff" + }, + { + "action": "PULL", + "text_success": "You pull the staff", + "text_fail": "You cannot pull this staff" + }, + { + "action": "TAKE", + "text_success": "You're a wizard, Harry", + "text_fail": "You cannot take this staff unless you are a wizard class" + } + ] + }, + "BORJA": { + "short_desc": "This is the evil king", + "long_desc": "This is the evil king Borja", + "in": "room_B", + "actions": [ + { + "action": "PUSH", + "text_success": "You push the evil king", + "text_fail": "You cannot push this evil king" + }, + { + "action": "PULL", + "text_success": "You pull the evil king", + "text_fail": "You cannot pull this evil king" + }, + { + "action": "FIREBALL", + "text_success": "You defeated BORJA", + "text_fail": "You cannot use this spell without a staff", + "conditions": [ + { + "type": "INVENTORY", + "item_id": "STAFF" + } + ] + } + ] + }, + "TABLE": { + "short_desc": "This is a table", + "long_desc": "This is a table long", + "in": "room_B", + "actions": [ + { + "action": "PUSH", + "text_success": "You push the table", + "text_fail": "You cannot push this table. Maybe if you had a chair...", + "conditions": [ + { + "type": "INVENTORY", + "item_id": "CHAIR" + } + ] + }, + { + "action": "PULL", + "text_success": "You pull the table", + "text_fail": "You cannot pull this table" + }, + { + "action": "TAKE", + "text_success": "You take the table", + "text_fail": "You cannot take this table. Maybe if you had a chair...", + "conditions": [ + { + "type": "INVENTORY", + "item_id": "CHAIR" + } + ] + } + ] + } + } +} diff --git a/src/custom-scripts/examples/demo_old.c b/src/custom-scripts/examples/demo_old.c new file mode 100644 index 0000000000..cf43cd7bfa --- /dev/null +++ b/src/custom-scripts/examples/demo_old.c @@ -0,0 +1,80 @@ +/* + * This example program runs a full instance of chiventure with an in-memory game, + * and where the CLI is monkeypatched to accept a new operation: + * + * - TASTE: A "kind 1" action that operates on an item. We support customization for the + * output string upon running the action. + */ + +#include +#include +#include +#include "common/ctx.h" +#include "ui/ui.h" + +const char *banner = "THIS IS AN EXAMPLE PROGRAM"; + +/* Creates a sample in-memory game */ +chiventure_ctx_t *create_sample_ctx() +{ + game_t *game = game_new("Welcome to Chiventure!"); + + + /* Create two rooms (room1 and room2). room1 is the initial room */ + room_t *room1 = room_new("room1", "This is room 1", "Verily, this is the first room."); + room_t *room2 = room_new("room2", "This is room 2", "Truly, this is the second room."); + add_room_to_game(game, room1); + add_room_to_game(game, room2); + game->curr_room = room1; + create_connection(game, "room1", "room2", "NORTH"); + + /* Create a rock in room1 */ + item_t *rock = item_new("ROCK","It is a rock.", + "You were hoping this was The Rock but, alas, it is just a plain and ordinary rock"); + add_item_to_room(room1, rock); + + + /* Where custom_type comes into play, create a dynamic string (hold different values) depending + on what the user enters at the start of the game */ + data_t data, d; + char string_num; + + printf("Enter either 1 or 2 (1 for non-caps, 2 for caps): "); + scanf("%c", &string_num); + object_t *ot = obj_t_init(data, STR_TYPE, "../../../../src/custom-scripts/examples/dynamic_string.lua"); + d.c = string_num; + ot = obj_add_arg(ot, d, CHAR_TYPE); + char* custom_string = (char*)malloc(100); + data_t res = arg_t_get(ot); + custom_string = res.s; + + + /* Associate action "TASTE" with the rock. + * It has no conditions, so it should succeed unconditionally. */ + add_action(rock, "TASTE", custom_string, "It has a gravel-ey bouquet."); + + /* Create context */ + chiventure_ctx_t *ctx = chiventure_ctx_new(game); + + return ctx; +} + + + + +int main(int argc, char **argv) +{ + chiventure_ctx_t *ctx = create_sample_ctx(); + + /* Monkeypatch the CLI to add a new "kind 1" action + * (i.e., an action that operates on an item) */ + action_type_t taste_action = {"TASTE", ITEM}; + add_entry(taste_action.c_name, kind1_action_operation, &taste_action, ctx->cli_ctx->table); + + /* Start chiventure */ + start_ui(ctx, banner); + + game_free(ctx->game); + + return 0; +} \ No newline at end of file diff --git a/src/custom-scripts/examples/demonstration.c b/src/custom-scripts/examples/demonstration.c index 39616c4442..537713fbe4 100644 --- a/src/custom-scripts/examples/demonstration.c +++ b/src/custom-scripts/examples/demonstration.c @@ -7,65 +7,65 @@ */ #include -#include +#include #include #include "common/ctx.h" #include "ui/ui.h" + +#include +#include +#include +#include +#include "libobj/load.h" + + +#include "game-state/mode.h" + const char *banner = "THIS IS AN EXAMPLE PROGRAM"; /* Creates a sample in-memory game */ chiventure_ctx_t *create_sample_ctx() { - game_t *game = game_new("Welcome to Chiventure!"); + data_t jack; + data_t dc; + object_t *togay = obj_t_init(jack, STR_TYPE,"../../../../src/custom-scripts/examples/dynamic_string.lua"); + - /* Create two rooms (room1 and room2). room1 is the initial room */ - room_t *room1 = room_new("room1", "This is room 1", "Verily, this is the first room."); - room_t *room2 = room_new("room2", "This is room 2", "Truly, this is the second room."); - add_room_to_game(game, room1); - add_room_to_game(game, room2); - game->curr_room = room1; - create_connection(game, "room1", "room2", "NORTH"); - - /* Create a rock in room1 */ - item_t *rock = item_new("ROCK","It is a rock.", - "You were hoping this was The Rock but, alas, it is just a plain and ordinary rock"); - add_item_to_room(room1, rock); - - - /* Where custom_type comes into play, create a dynamic string (hold different values) depending - on what the user enters at the start of the game */ + /* Create context */ char string_num; - printf("Enter either 1 or 2 (1 for non-caps, 2 for caps): "); - scanf("%c", &string_num); - object_t *ot = obj_t_str("", "../../../../src/custom-scripts/examples/dynamic_string.lua"); - ot = obj_add_arg_char(ot, string_num); + printf("Enter either 1 or 2 (1 for wizard class, 2 for warrior class): "); + scanf("%c", &string_num); + dc.c = string_num; + togay = obj_add_arg(togay,dc,CHAR_TYPE); char* custom_string = (char*)malloc(100); - custom_string = str_t_get(ot); - - - /* Associate action "TASTE" with the rock. - * It has no conditions, so it should succeed unconditionally. */ - add_action(rock, "TASTE", custom_string, "It has a gravel-ey bouquet."); - - /* Create context */ - chiventure_ctx_t *ctx = chiventure_ctx_new(game); - - return ctx; + data_t temp = arg_t_get(togay); + custom_string = temp.s; + char wizard[] = "Wizard Class", warrior[] = "Warrior Class"; + if(strcmp(wizard,custom_string)== 0){ + obj_t *obj_store1 = load_obj_store("../../../../src/custom-scripts/examples/demo.wdl"); + game_t *game1 = load_game(obj_store1); + chiventure_ctx_t *ctx1 = chiventure_ctx_new(game1); + return ctx1; + } + else{ + obj_t *obj_store2 = load_obj_store("../../../../src/custom-scripts/examples/demo-warrior.wdl"); + game_t *game2 = load_game(obj_store2); + chiventure_ctx_t *ctx2 = chiventure_ctx_new(game2); + return ctx2; + } } - - int main(int argc, char **argv) { chiventure_ctx_t *ctx = create_sample_ctx(); - /* Monkeypatch the CLI to add a new "kind 1" action - * (i.e., an action that operates on an item) */ - action_type_t taste_action = {"TASTE", ITEM}; - add_entry(taste_action.c_name, kind1_action_operation, &taste_action, ctx->cli_ctx->table); + action_type_t fireball_action = {"FIREBALL", ITEM}; + add_entry(fireball_action.c_name, kind1_action_operation, &fireball_action, ctx->cli_ctx->table); + action_type_t slash_action = {"SLASH", ITEM}; + add_entry(slash_action.c_name, kind1_action_operation, &slash_action, ctx->cli_ctx->table); /* Start chiventure */ start_ui(ctx, banner); diff --git a/src/custom-scripts/examples/dynamic_string.lua b/src/custom-scripts/examples/dynamic_string.lua index 8c98917e57..aae5f54b85 100644 --- a/src/custom-scripts/examples/dynamic_string.lua +++ b/src/custom-scripts/examples/dynamic_string.lua @@ -1,4 +1,4 @@ function foo(arg1) - if arg1 == '1' then return "You can't taste the rock" end - if arg1 == '2' then return "YOU CAN'T TASTE THE ROCK" end + if arg1 == '1' then return "Wizard Class" end + if arg1 == '2' then return "Warrior Class" end end \ No newline at end of file diff --git a/src/custom-scripts/src/arg_custom_type.c b/src/custom-scripts/src/arg_custom_type.c new file mode 100644 index 0000000000..88c5d125ee --- /dev/null +++ b/src/custom-scripts/src/arg_custom_type.c @@ -0,0 +1,40 @@ +#include "custom-scripts/arg_custom_type.h" + +// see arg_custom_type.h +arg_t *arg_t_new() { + arg_t *arg = (arg_t*)malloc(sizeof(arg_t)); + arg->type = NONE_TYPE; + arg->prev = NULL; + arg->next = NULL; + return arg; +} + +// see arg_custom_type.h +arg_t *arg_t_init(data_t d, data_type_t t) { + arg_t *arg = arg_t_new(); + arg->type = t; + + switch (t) { + case BOOL_TYPE: + arg->data.b = d.b; + break; + case CHAR_TYPE: + arg->data.c = d.c; + break; + case INT_TYPE: + arg->data.i = d.i; + break; + case STR_TYPE: + arg->data.s = d.s; + break; + default: + break; + } + return arg; +} + +// see arg_custom_type.h +arg_t *arg_t_add(arg_t *head, arg_t *add) { + DL_APPEND(head, add); + return head; +} \ No newline at end of file diff --git a/src/custom-scripts/src/custom_type.c b/src/custom-scripts/src/custom_type.c deleted file mode 100644 index 0467342b01..0000000000 --- a/src/custom-scripts/src/custom_type.c +++ /dev/null @@ -1,321 +0,0 @@ -#include "custom-scripts/custom_type.h" - -// see custom_type.h -object_t *obj_t_new() -{ - object_t *ot = (object_t*)malloc(sizeof(object_t)); - ot->type = NONE_TYPE; - ot->is_lua = false; - ot->args = NULL; - return ot; -} - -// see custom_type.h -object_t *obj_t_bool(bool b, char *lua) -{ - object_t *ot = obj_t_new(); - ot->type = BOOL_TYPE; - if (lua) { - ot->is_lua = true; - ot->data.lua = lua; - } else { - ot->data.b = b; - } - return ot; -} - -// see custom_type.h -object_t *obj_t_char(char c, char *lua) -{ - object_t *ot = obj_t_new(); - ot->type = CHAR_TYPE; - if (lua) { - ot->is_lua = true; - ot->data.lua = lua; - } else { - ot->data.c = c; - } - return ot; -} - -// see custom_type.h -object_t *obj_t_int(int i, char *lua) -{ - object_t *ot = obj_t_new(); - ot->type = INT_TYPE; - if (lua) { - ot->is_lua = true; - ot->data.lua = lua; - } else { - ot->data.i = i; - } - return ot; -} - -// see custom_type.h -object_t *obj_t_str(char *s, char *lua) -{ - object_t *ot = obj_t_new(); - ot->type = STR_TYPE; - if (lua) { - ot->is_lua = true; - ot->data.lua = lua; - } else { - ot->data.s = s; - } - return ot; -} - -// ============================================================================ - -/** - * Creates an empty argument structure - * Helper function for adding arguments to an object - */ -arg_t *arg_t_new() { - arg_t *arg = (arg_t*)malloc(sizeof(arg_t)); - arg->type = NONE_TYPE; - arg->prev = NULL; - arg->next = NULL; - return arg; -} - -/** - * Creates an argument structure with the specified boolean - * Helper function for obj_add_arg_bool - */ -arg_t *arg_t_bool(bool b) { - arg_t *arg = arg_t_new(); - arg->type = BOOL_TYPE; - arg->data.b = b; - return arg; -} - -/** - * Creates an argument structure with the specified character - * Helper function for obj_add_arg_char - */ -arg_t *arg_t_char(char c) { - arg_t *arg = arg_t_new(); - arg->type = CHAR_TYPE; - arg->data.c = c; - return arg; -} - -/** - * Creates an argument structure with the specified integer - * Helper function for obj_add_arg_int - */ -arg_t *arg_t_int(int i) { - arg_t *arg = arg_t_new(); - arg->type = INT_TYPE; - arg->data.i = i; - return arg; -} - -/** - * Creates an argument structure with the specified string - * Helper function for obj_add_arg_str - */ -arg_t *arg_t_str(char *s) { - arg_t *arg = arg_t_new(); - arg->type = STR_TYPE; - arg->data.s = s; - return arg; -} - -/** - * Adds an argument structure to the end of the argument linked list - * Helper function for all obj_add_arg_ functions - */ -arg_t *arg_t_add(arg_t *head, arg_t *add) { - if (add == NULL) { - return head; - } else if (head == NULL) { - return add; - } else { - arg_t *temp = head; - // iterating over linked list to last node - while(temp->next) { - temp = temp->next; - } - temp->next = add; - temp->next->prev = temp; - return head; - } -} - -// see custom_type.h -object_t *obj_add_arg_bool(object_t *ot, bool b) { - arg_t *add = arg_t_bool(b); - ot->args = arg_t_add(ot->args, add); - return ot; -} - -// see custom_type.h -object_t *obj_add_arg_char(object_t *ot, char c) { - arg_t *add = arg_t_char(c); - ot->args = arg_t_add(ot->args, add); - return ot; -} - -// see custom_type.h -object_t *obj_add_arg_int(object_t *ot, int i) { - arg_t *add = arg_t_int(i); - ot->args = arg_t_add(ot->args, add); - return ot; -} - -// see custom_type.h -object_t *obj_add_arg_str(object_t *ot, char *s) { - arg_t *add = arg_t_str(s); - ot->args = arg_t_add(ot->args, add); - return ot; -} - -// ============================================================================ - -/** - * Helper function used to push the arguments in the linked list - * to the Lua vritual stack - * Parameters: - * - the Lua state created - * - the object containing the argument linked list - * Returns: - * - the number of arguments in the linked list - */ -int push_args(lua_State *L, object_t* ot) { - int count = 0; // number of arguments in linked list - arg_t *head = ot->args; - if (head == NULL) { - } - // push arguments one-by-one - while (head != NULL) { - // incrememnt argument count - count++; - // identify type of argument - data_type_t type = head->type; - // push argument to virtual stack - switch(type) { - case BOOL_TYPE: - { - int b = head->data.b; // pushboolean requires int - lua_pushboolean(L, b); - break; - } - case CHAR_TYPE: - { - char c = head->data.c; - lua_pushlstring(L, &c, 1); - break; - } - case INT_TYPE: - { - int i = head->data.i; - lua_pushnumber(L, i); - break; - } - case STR_TYPE: - { - char *s = head->data.s; - lua_pushstring(L, s); - break; - } - default: // NONE_TYPE - break; - } - // move to next argument - head = head->next; - } - return count; -} - -/** - * Helper function for the getter functions below - * Calls the Lua function in the directory specified, stores the data - * in the Lua virtual stack for the getter functions to extract and return - * Parameters: - * - the object_t struct that contains the argument list to be passed to Lua - * - the Lua script directory - * Returns: - * - the Lua state with the return value of the Lua script extracted and placed - * in the virtual stack - */ -lua_State *callLua(object_t *ot, char *lua_path) { - lua_State *L = luaL_newstate(); - - // opens all standard Lua libraries into the given state - luaL_openlibs(L); - - // loads the given file - luaL_dofile(L, lua_path); - - // sets virtual stack top to index 0 - lua_settop(L, 0); - - // push functions and arguments and call function - lua_getglobal(L, "foo"); - int num_args = push_args(L, ot); - lua_pcall(L, num_args, 1, 0); - - return L; -} - -// see custom_types.h -bool bool_t_get(object_t *ot) { - assert(ot->type == BOOL_TYPE); - if (ot->is_lua) { - char *lua_path = ot->data.lua; - lua_State *L = callLua(ot, lua_path); - int result = (int)lua_toboolean(L, -1); - lua_pop(L, 1); - return (result ? true : false); - } - else { - return ot->data.b; - } -} - -// see custom_types.h -char char_t_get(object_t *ot) { - assert(ot->type == CHAR_TYPE); - if (ot->is_lua) { - char *lua_path = ot->data.lua; - lua_State *L = callLua(ot, lua_path); - const char *result = lua_tostring(L, -1); - lua_pop(L, 1); - char *result1 = strdup(result); - return *result1; - } else { - return ot->data.c; - } -} - -// see custom_types.h -int int_t_get(object_t *ot) { - assert(ot->type == INT_TYPE); - if (ot->is_lua) { - char *lua_path = ot->data.lua; - lua_State *L = callLua(ot, lua_path); - int result = (int)lua_tointeger(L, -1); - lua_pop(L, 1); - return result; - } else { - return ot->data.i; - } -} - -// see custom_types.h -char* str_t_get(object_t *ot) { - assert(ot->type == STR_TYPE); - if (ot->is_lua) { - char *lua_path = ot->data.lua; - lua_State *L = callLua(ot, lua_path); - const char *result = lua_tostring(L, -1); - lua_pop(L, 1); - char *result1 = strdup(result); - return result1; - } else { - return ot->data.s; - } -} \ No newline at end of file diff --git a/src/custom-scripts/src/get_custom_type.c b/src/custom-scripts/src/get_custom_type.c new file mode 100644 index 0000000000..99f889c4cd --- /dev/null +++ b/src/custom-scripts/src/get_custom_type.c @@ -0,0 +1,66 @@ +#include "custom-scripts/get_custom_type.h" + +// see get_custom_types.h +data_t arg_t_get(object_t *ot) { + data_t d; + + switch (ot->type) { + case BOOL_TYPE: + assert(ot->type == BOOL_TYPE); + if (ot->is_lua) { + char *lua_path = ot->data.lua; + lua_State *L = callLua(ot, lua_path); + int result = (int)lua_toboolean(L, -1); + lua_pop(L, 1); + d.b = (result ? true : false); + return d; + } else { + return ot->data; + } + break; + case CHAR_TYPE: + assert(ot->type == CHAR_TYPE); + if (ot->is_lua) { + char *lua_path = ot->data.lua; + lua_State *L = callLua(ot, lua_path); + const char *result = lua_tostring(L, -1); + lua_pop(L, 1); + char *result1 = strdup(result); + d.c = *result1; + return d; + } else { + return ot->data; + } + break; + case INT_TYPE: + assert(ot->type == INT_TYPE); + if (ot->is_lua) { + char *lua_path = ot->data.lua; + lua_State *L = callLua(ot, lua_path); + int result = (int)lua_tointeger(L, -1); + lua_pop(L, 1); + d.i = result; + return d; + } else { + return ot->data; + } + break; + case STR_TYPE: + assert(ot->type == STR_TYPE); + if (ot->is_lua) { + char *lua_path = ot->data.lua; + lua_State *L = callLua(ot, lua_path); + const char *result = lua_tostring(L, -1); + lua_pop(L, 1); + char *result1 = strdup(result); + d.s = result1; + return d; + } else { + return ot->data; + } + break; + default: + return ot->data; + break; + } + } \ No newline at end of file diff --git a/src/custom-scripts/src/lua_custom_type.c b/src/custom-scripts/src/lua_custom_type.c new file mode 100644 index 0000000000..cb453e37ea --- /dev/null +++ b/src/custom-scripts/src/lua_custom_type.c @@ -0,0 +1,66 @@ +#include "custom-scripts/lua_custom_type.h" + +// see lua_custom_type.h +int push_args(lua_State *L, object_t* ot) { + int count = 0; // number of arguments in linked list + arg_t *head = ot->args; + arg_t *to_push; + // push arguments one-by-one + DL_FOREACH(head, to_push) { + count++; + // identify type of argument + data_type_t type = to_push->type; + // push argument to virtual stack + switch(type) { + case BOOL_TYPE: + { + int b = to_push->data.b; // pushboolean requires int + lua_pushboolean(L, b); + break; + } + case CHAR_TYPE: + { + char c = to_push->data.c; + lua_pushlstring(L, &c, 1); + break; + } + case INT_TYPE: + { + int i = to_push->data.i; + lua_pushnumber(L, i); + break; + } + case STR_TYPE: + { + char *s = to_push->data.s; + lua_pushstring(L, s); + break; + } + default: // NONE_TYPE + break; + } + } + + return count; +} + +// see lua_custom_type.h +lua_State *callLua(object_t *ot, char *lua_path) { + lua_State *L = luaL_newstate(); + + // opens all standard Lua libraries into the given state + luaL_openlibs(L); + + // loads the given file + luaL_dofile(L, lua_path); + + // sets virtual stack top to index 0 + lua_settop(L, 0); + + // push functions and arguments and call function + lua_getglobal(L, "foo"); + int num_args = push_args(L, ot); + lua_pcall(L, num_args, 1, 0); + + return L; +} \ No newline at end of file diff --git a/src/custom-scripts/src/obj_custom_type.c b/src/custom-scripts/src/obj_custom_type.c new file mode 100644 index 0000000000..90781f2acb --- /dev/null +++ b/src/custom-scripts/src/obj_custom_type.c @@ -0,0 +1,48 @@ +#include "custom-scripts/obj_custom_type.h" + +// see obj_custom_type.h +object_t *obj_t_new() +{ + object_t *ot = (object_t*)malloc(sizeof(object_t)); + ot->type = NONE_TYPE; + ot->is_lua = false; + ot->args = NULL; + return ot; +} + +// see obj_custom_type.h +object_t *obj_t_init(data_t d, data_type_t t, char *lua) +{ + object_t *ot = obj_t_new(); + ot->args = NULL; + ot->type = t; + if (lua) { + ot->is_lua = true; + ot->data.lua = lua; + } else { + switch (t) { + case BOOL_TYPE: + ot->data.b = d.b; + break; + case CHAR_TYPE: + ot->data.c = d.c; + break; + case INT_TYPE: + ot->data.i = d.i; + break; + case STR_TYPE: + ot->data.s = d.s; + break; + default: + break; + } + } + return ot; +} + +// see obj_custom_type.h +object_t *obj_add_arg(object_t *ot, data_t d, data_type_t t) { + arg_t *add = arg_t_init(d, t); + ot->args = arg_t_add(ot->args, add); + return ot; +} \ No newline at end of file diff --git a/tests/custom-scripts/arg_custom_typ.h b/tests/custom-scripts/arg_custom_typ.h new file mode 100644 index 0000000000..69deb0a738 --- /dev/null +++ b/tests/custom-scripts/arg_custom_typ.h @@ -0,0 +1,64 @@ +#ifndef _ARG_CUSTOM_TYPE_H_ +#define _ARG_CUSTOM_TYPE_H_ + +#include +#include +#include +#include +#include +#include "lauxlib.h" +#include "lua.h" +#include "lualib.h" +#include "utlist.h" + +/* File consisting of the custom pseudo-type created by Custom Scripts (inspired by libobj) + =========================================================================== */ + +typedef enum data_type +{ + NONE_TYPE = 0, + BOOL_TYPE = 1, + CHAR_TYPE = 2, + INT_TYPE = 3, + STR_TYPE = 4, +} data_type_t; + +typedef union data { + bool b; + char c; + int i; + char *s; + char *lua; +} data_t; + +typedef struct arg_t +{ + // Type of underlying data + data_type_t type; + + // Data associated with the argument + data_t data; + + // Pointer to the previous and next arguments + struct arg_t *prev, *next; +} arg_t; + +/** + * Creates an empty argument structure + * Helper function for adding arguments to an object + */ +arg_t *arg_t_new(); + +/** + * Creates an argument structure with the specified boolean + * Helper function for obj_add_arg_bool + */ +arg_t *arg_t_init(data_t d, data_type_t t); + +/** + * Adds an argument structure to the end of the argument linked list + * Helper function for all obj_add_arg_ functions + */ +arg_t *arg_t_add(arg_t *head, arg_t *add); + +#endif \ No newline at end of file diff --git a/tests/custom-scripts/get_custom_typ.h b/tests/custom-scripts/get_custom_typ.h new file mode 100644 index 0000000000..186fb1feea --- /dev/null +++ b/tests/custom-scripts/get_custom_typ.h @@ -0,0 +1,16 @@ +#ifndef _GET_CUSTOM_TYPE_H_ +#define _GET_CUSTOM_TYPE_H_ + +#include "lua_custom_typ.h" + +/** + * bool_t_get() returns a bool from an object_t struct + * Parameters: + * - ot: an obj_t + * - d: operating data type + * Returns: + * - bool from ot + */ +data_t arg_t_get(object_t *ot); + +#endif \ No newline at end of file diff --git a/tests/custom-scripts/lua_custom_typ.h b/tests/custom-scripts/lua_custom_typ.h new file mode 100644 index 0000000000..65d23a4619 --- /dev/null +++ b/tests/custom-scripts/lua_custom_typ.h @@ -0,0 +1,30 @@ +#ifndef _LUA_CUSTOM_TYPE_H_ +#define _LUA_CUSTOM_TYPE_H_ + +#include "obj_custom_typ.h" + +/** + * Helper function used to push the arguments in the linked list + * to the Lua vritual stack + * Parameters: + * - the Lua state created + * - the object containing the argument linked list + * Returns: + * - the number of arguments in the linked list + */ +int push_args(lua_State *L, object_t* ot); + +/** + * Helper function for the getter functions below + * Calls the Lua function in the directory specified, stores the data + * in the Lua virtual stack for the getter functions to extract and return + * Parameters: + * - the object_t struct that contains the argument list to be passed to Lua + * - the Lua script directory + * Returns: + * - the Lua state with the return value of the Lua script extracted and placed + * in the virtual stack + */ +lua_State *callLua(object_t *ot, char *lua_path); + +#endif \ No newline at end of file diff --git a/tests/custom-scripts/obj_custom_typ.h b/tests/custom-scripts/obj_custom_typ.h new file mode 100644 index 0000000000..cade9ad2be --- /dev/null +++ b/tests/custom-scripts/obj_custom_typ.h @@ -0,0 +1,51 @@ +#ifndef _OBJ_CUSTOM_TYPE_H_ +#define _OBJ_CUSTOM_TYPE_H_ + +#include "arg_custom_typ.h" + +typedef struct obj_t +{ + // Type of underlying data + data_type_t type; + + // Whether this data will be represented by a Lua script + bool is_lua; + + // Data associated with the object + data_t data; + + // Linked list of arguments + arg_t *args; +} object_t; + +/** + * obj_t_new() creates an empty object_t struct + * Returns: + * - pointer to an empty object struct + */ +object_t *obj_t_new(); + +/** + * obj_t_bool() creates an object_t struct containing a boolean + * Parameters: + * - bool value to be stored + * - Lua script (NULL if no script to be specified) + * - argument linked list to be passed to Lua if applicable + * Returns: + * - pointer to an object struct containing the bool + */ +object_t *obj_t_init(data_t d, data_type_t t, char *lua); + +// ============================================================================ + +/** + * obj_add_arg_bool adds a bool to the argument linked list of the object_t + * Parameters: + * - the object whose argument list is to be added to + * - the boolean to be added + * Returns: + * - the updated object + */ +object_t *obj_add_arg(object_t *obj, data_t d, data_type_t t); + +#endif \ No newline at end of file diff --git a/tests/custom-scripts/test_types.c b/tests/custom-scripts/test_types.c index 7e8e7ac40d..b2b00605b4 100644 --- a/tests/custom-scripts/test_types.c +++ b/tests/custom-scripts/test_types.c @@ -3,7 +3,9 @@ #include #include #include -#include "custom-scripts/custom_type.h" +#include "get_custom_typ.h" + +data_t data, data2, data3, data4; /** * Checks that the object_t struct contains the right data when obj_t_new() called @@ -22,7 +24,8 @@ Test(custom_type, obj_t_new) */ Test(custom_type, obj_t_new_bool) { - object_t *ot = obj_t_bool(true, NULL); + data.b = true; + object_t *ot = obj_t_init(data, BOOL_TYPE, NULL); cr_assert_eq(ot->type, BOOL_TYPE, "obj_t_bool: failed type assignment"); cr_assert_eq(ot->is_lua, false, "obj_t_bool: failed is_lua assignment"); cr_assert_eq(ot->data.b, true, "obj_t_bool: failed bool assignment"); @@ -35,7 +38,8 @@ Test(custom_type, obj_t_new_bool) */ Test(custom_type, obj_t_new_bool_lua) { - object_t *ot = obj_t_bool(true, "../../../tests/custom-scripts/Lua_file/bool_test.lua"); + data.b = true; + object_t *ot = obj_t_init(data, BOOL_TYPE, "../../../tests/custom-scripts/Lua_file/bool_test.lua"); cr_assert_eq(ot->type, BOOL_TYPE, "obj_t_bool: failed type assignment"); cr_assert_eq(ot->is_lua, true, "obj_t_bool: failed is_lua assignment"); cr_assert_eq(ot->data.lua, "../../../tests/custom-scripts/Lua_file/bool_test.lua", @@ -49,7 +53,8 @@ Test(custom_type, obj_t_new_bool_lua) */ Test(custom_type, obj_t_new_char) { - object_t *ot = obj_t_char('a', NULL); + data.c = 'a'; + object_t *ot = obj_t_init(data, CHAR_TYPE, NULL); cr_assert_eq(ot->type, CHAR_TYPE, "obj_t_char: failed type assignment"); cr_assert_eq(ot->is_lua, false, "obj_t_char: failed is_lua assignment"); cr_assert_eq(ot->data.c, 'a', "obj_t_char: failed char assignment"); @@ -62,7 +67,8 @@ Test(custom_type, obj_t_new_char) */ Test(custom_type, obj_t_new_char_lua) { - object_t *ot = obj_t_char('a', "../../../tests/custom-scripts/Lua_file/char_test.lua"); + data.c = 'a'; + object_t *ot = obj_t_init(data, CHAR_TYPE, "../../../tests/custom-scripts/Lua_file/char_test.lua"); cr_assert_eq(ot->type, CHAR_TYPE, "obj_t_char: failed type assignment"); cr_assert_eq(ot->is_lua, true, "obj_t_char: failed is_lua assignment"); cr_assert_eq(ot->data.lua, "../../../tests/custom-scripts/Lua_file/char_test.lua", @@ -76,7 +82,8 @@ Test(custom_type, obj_t_new_char_lua) */ Test(custom_type, obj_t_new_int) { - object_t *ot = obj_t_int(10, NULL); + data.i = 10; + object_t *ot = obj_t_init(data, INT_TYPE, NULL); cr_assert_eq(ot->type, INT_TYPE, "obj_t_int: failed type assignment"); cr_assert_eq(ot->is_lua, false, "obj_t_int: failed is_lua assignment"); cr_assert_eq(ot->data.i, 10, "obj_t_int: failed integer assignment"); @@ -89,7 +96,8 @@ Test(custom_type, obj_t_new_int) */ Test(custom_type, obj_t_new_int_lua) { - object_t *ot = obj_t_int(10, "../../../tests/custom-scripts/Lua_file/int_test.lua"); + data.i = 10; + object_t *ot = obj_t_init(data, INT_TYPE, "../../../tests/custom-scripts/Lua_file/int_test.lua"); cr_assert_eq(ot->type, INT_TYPE, "obj_t_int: failed type assignment"); cr_assert_eq(ot->is_lua, true, "obj_t_int: failed is_lua assignment"); cr_assert_eq(ot->data.lua, "../../../tests/custom-scripts/Lua_file/int_test.lua", @@ -103,7 +111,8 @@ Test(custom_type, obj_t_new_int_lua) */ Test(custom_type, obj_t_new_str) { - object_t *ot = obj_t_str("testing", NULL); + data.s = "testing"; + object_t *ot = obj_t_init(data, STR_TYPE, NULL); cr_assert_eq(ot->type, STR_TYPE, "obj_t_str: failed type assignment"); cr_assert_eq(ot->is_lua, false, "obj_t_str: failed is_lua assignment"); cr_assert_eq(ot->data.s, "testing", "obj_t_str: failed str assignment"); @@ -116,7 +125,8 @@ Test(custom_type, obj_t_new_str) */ Test(custom_type, obj_t_new_str_lua) { - object_t *ot = obj_t_str("testing", "../../../tests/custom-scripts/Lua_file/string_test.lua"); + data.s = "testing"; + object_t *ot = obj_t_init(data, STR_TYPE, "../../../tests/custom-scripts/Lua_file/string_test.lua"); cr_assert_eq(ot->type, STR_TYPE, "obj_t_str: failed type assignment"); cr_assert_eq(ot->is_lua, true, "obj_t_str: failed is_lua assignment"); cr_assert_eq(ot->data.lua, "../../../tests/custom-scripts/Lua_file/string_test.lua", @@ -132,8 +142,10 @@ Test(custom_type, obj_t_new_str_lua) Test(custom_type, arg_t_new_bool) { // Placeholder object_t - object_t *ot = obj_t_str("Placeholder object", NULL); - ot = obj_add_arg_bool(ot, true); + data.s = "Placeholder object"; + data.b = true; + object_t *ot = obj_t_init(data, STR_TYPE, NULL); + ot = obj_add_arg(ot, data, BOOL_TYPE); arg_t *at = ot->args; cr_assert_eq(at->type, BOOL_TYPE, "arg_t_bool: failed type assignment"); @@ -146,8 +158,10 @@ Test(custom_type, arg_t_new_bool) */ Test(custom_type, arg_t_new_char) { - object_t *ot = obj_t_str("Placeholder object", NULL); - ot = obj_add_arg_char(ot, 'a'); + data.s = "Placeholder object"; + data.c = 'a'; + object_t *ot = obj_t_init(data, STR_TYPE, NULL); + ot = obj_add_arg(ot, data, CHAR_TYPE); arg_t *at = ot->args; cr_assert_eq(at->type, CHAR_TYPE, "arg_t_char: failed type assignment"); @@ -160,8 +174,10 @@ Test(custom_type, arg_t_new_char) */ Test(custom_type, arg_t_new_int) { - object_t *ot = obj_t_str("Placeholder object", NULL); - ot = obj_add_arg_int(ot, 10); + data.s = "Placeholder object"; + data.i = 10; + object_t *ot = obj_t_init(data, STR_TYPE, NULL); + ot = obj_add_arg(ot, data, INT_TYPE); arg_t *at = ot->args; cr_assert_eq(at->type, INT_TYPE, "arg_t_int: failed type assignment"); @@ -174,8 +190,10 @@ Test(custom_type, arg_t_new_int) */ Test(custom_type, arg_t_new_str) { - object_t *ot = obj_t_str("Placeholder object", NULL); - ot = obj_add_arg_str(ot, "testing"); + data.s = "Placeholder object"; + data.s = "testing"; + object_t *ot = obj_t_init(data, STR_TYPE, NULL); + ot = obj_add_arg(ot, data, STR_TYPE); arg_t *at = ot->args; cr_assert_eq(at->type, STR_TYPE, "arg_t_str: failed type assignment"); @@ -183,39 +201,26 @@ Test(custom_type, arg_t_new_str) cr_assert_eq(at->next, NULL, "arg_t_str next failed assignment"); } -/** -* Checks that the obj_add_arg_ correctly adds arg_t structs to the linked list -*/ -Test(custom_type, obj_add_args) -{ - object_t *ot = obj_t_bool(true, NULL); - ot = obj_add_arg_str(ot, "I am head"); - ot = obj_add_arg_int(ot, 2); - ot = obj_add_arg_char(ot, '3'); - ot = obj_add_arg_bool(ot, true); - arg_t *head = ot->args; - - cr_assert_str_eq(head->data.s, "I am head", "arg_t_add: failed head initialization"); - cr_assert_eq(head->next->data.i, 2, "arg_t_add: failed arg_t addition"); - cr_assert_eq(head->next->next->data.c, '3', "arg_t_add: failed arg_t addition"); - cr_assert_eq(head->next->next->next->data.b, true, "arg_t_add: failed arg_t addition"); - cr_assert_null(head->next->next->next->next, "arg_t_add: failed to terminate linked list"); -} - /** * Checks that the obj_add_arg_ correctly assigns prev pointers in doubly linked list */ Test(custom_type, obj_add_args_prev) { - object_t *ot = obj_t_bool(true, NULL); - ot = obj_add_arg_str(ot, "I am head"); - ot = obj_add_arg_int(ot, 2); - ot = obj_add_arg_char(ot, '3'); - ot = obj_add_arg_bool(ot, true); + data_t d; + d.b = true; + object_t *ot = obj_t_init(d, BOOL_TYPE, NULL); + d.s = "I am head"; + d.i = 2; + d.c = '3'; + ot = obj_add_arg(ot, d, STR_TYPE); + ot = obj_add_arg(ot, d, INT_TYPE); + ot = obj_add_arg(ot, d, CHAR_TYPE); + ot = obj_add_arg(ot, d, BOOL_TYPE); arg_t *end = ot->args->next->next->next; - cr_assert_eq(end->prev->data.c, '3', "arg_t_add: failed arg_t addition (prev)"); - cr_assert_eq(end->prev->prev->data.i, 2, "arg_t_add: failed arg_t addition (prev)"); + cr_assert_eq(end->data.b, true, "arg_t add 0: failed arg_t addition (end)"); + cr_assert_eq(end->prev->data.c, '3', "arg_t_add 1: failed arg_t addition (prev)"); + cr_assert_eq(end->prev->prev->data.i, 2, "arg_t_add 2: failed arg_t addition (prev) with %c", end->prev->prev->data.i); cr_assert_str_eq(end->prev->prev->prev->data.s, "I am head", "arg_t_add: failed arg_t addition (prev)"); } @@ -226,8 +231,10 @@ Test(custom_type, obj_add_args_prev) */ Test(custom_type, obj_t_get_bool) { - object_t *ot = obj_t_bool(true, NULL); - bool rv = bool_t_get(ot); + data.b = true; + object_t *ot = obj_t_init(data, BOOL_TYPE, NULL); + data_t got = arg_t_get(ot); + bool rv = got.b; cr_assert_eq(rv, true, "obj_t_get_bool: failed bool direct retrieval"); } @@ -236,8 +243,10 @@ Test(custom_type, obj_t_get_bool) */ Test(custom_type, obj_t_get_bool_lua) { - object_t *ot = obj_t_bool(true, "../../../tests/custom-scripts/Lua_file/bool_test.lua"); - bool rv = bool_t_get(ot); + data.b = true; + object_t *ot = obj_t_init(data, BOOL_TYPE, "../../../tests/custom-scripts/Lua_file/bool_test.lua"); + data_t got = arg_t_get(ot); + bool rv = got.b; cr_assert_eq((rv ? 1 : 0), 0, "bool_t_get: failed bool Lua retrieval"); } @@ -247,15 +256,19 @@ Test(custom_type, obj_t_get_bool_lua) */ Test(custom_type, obj_t_get_bool_lua_args) { - object_t *ot = obj_t_bool(true, "../../../tests/custom-scripts/Lua_file/bool_test_args.lua"); - ot = obj_add_arg_bool(obj_add_arg_bool(obj_add_arg_bool(ot, true), true), true); - bool rv = bool_t_get(ot); - cr_assert_eq((rv ? 1 : 0), 1, "bool_t_get: failed bool Lua retrieval"); - - object_t *ot2 = obj_t_bool(true, "../../../tests/custom-scripts/Lua_file/bool_test_args.lua"); - ot2 = obj_add_arg_bool(obj_add_arg_bool(obj_add_arg_bool(ot2, true), false), true); - bool rv2 = bool_t_get(ot2); - cr_assert_eq((rv2 ? 1 : 0), 0, "bool_t_get: failed bool Lua retrieval"); + data.b = true; + data2.b = false; + object_t *ot = obj_t_init(data, BOOL_TYPE, "../../../tests/custom-scripts/Lua_file/bool_test_args.lua"); + ot = obj_add_arg(obj_add_arg(obj_add_arg(ot, data, BOOL_TYPE), data, BOOL_TYPE), data, BOOL_TYPE); + data_t got = arg_t_get(ot); + bool rv = got.b; + cr_assert_eq((rv ? 1 : 0), 1, "bool_t_get 1: failed bool Lua retrieval"); + + object_t *ot2 = obj_t_init(data, BOOL_TYPE, "../../../tests/custom-scripts/Lua_file/bool_test_args.lua"); + ot2 = obj_add_arg(obj_add_arg(obj_add_arg(ot2, data, BOOL_TYPE), data2, BOOL_TYPE), data, BOOL_TYPE); + data_t got2 = arg_t_get(ot2); + bool rv2 = got2.b; + cr_assert_eq((rv2 ? 1 : 0), 0, "bool_t_get 2: failed bool Lua retrieval"); } /** @@ -263,64 +276,55 @@ Test(custom_type, obj_t_get_bool_lua_args) */ Test(custom_type, obj_t_get_char) { - object_t *ot = obj_t_char('a', NULL); - char rv = char_t_get(ot); + data.c = 'a'; + object_t *ot = obj_t_init(data, CHAR_TYPE, NULL); + data_t got = arg_t_get(ot); + char rv = got.c; cr_assert_eq(rv, 'a', "obj_t_get_char: failed char direct retrieval"); } -/** - * Checks that the object_t struct returns the correct char value (lua) - */ -Test(custom_type, obj_t_get_char_lua) -{ - object_t *ot = obj_t_char('a', "../../../tests/custom-scripts/Lua_file/char_test.lua"); - char rv = char_t_get(ot); - cr_assert_eq(rv, 'b', "obj_t_get_char: failed char direct retrieval"); -} - /** * Checks that the object_t struct returns the correct char value (lua) * When arguments are passed in Lua */ Test(custom_type, obj_t_get_char_lua_args) { - object_t *ot = obj_t_char('q', + data.c = 'q'; + data2.c = 'a'; + data3.c = 'Z'; + data4.c = 'b'; + object_t *ot = obj_t_init(data, CHAR_TYPE, "../../../tests/custom-scripts/Lua_file/char_test_args.lua"); - ot = obj_add_arg_char(obj_add_arg_char(ot, 'a'), 'Z'); - char rv = char_t_get(ot); - cr_assert_eq(rv, 'c', "obj_t_get_char: failed char direct retrieval"); + ot = obj_add_arg(obj_add_arg(ot, data2, CHAR_TYPE), data3, CHAR_TYPE); + data_t got = arg_t_get(ot); + char rv = got.c; + cr_assert_eq(rv, 'c', "obj_t_get_char: failed char direct retrieval with %c", rv); - object_t *ot2 = obj_t_char('q', + object_t *ot2 = obj_t_init(data, CHAR_TYPE, "../../../tests/custom-scripts/Lua_file/char_test_args.lua"); - ot2 = obj_add_arg_char(obj_add_arg_char(ot2, 'Z'), 'b'); - char rv2 = char_t_get(ot2); + ot2 = obj_add_arg(obj_add_arg(ot2, data3, CHAR_TYPE), data4, CHAR_TYPE); + data_t got2 = arg_t_get(ot2); + char rv2 = got2.c; cr_assert_eq(rv2, 'd', "obj_t_get_char: failed char direct retrieval"); - object_t *ot3 = obj_t_char('q', + object_t *ot3 = obj_t_init(data, CHAR_TYPE, "../../../tests/custom-scripts/Lua_file/char_test_args.lua"); - ot3 = obj_add_arg_char(obj_add_arg_char(ot3, 'a'), 'b'); - char rv3 = char_t_get(ot3); + ot3 = obj_add_arg(obj_add_arg(ot3, data2, CHAR_TYPE), data4, CHAR_TYPE); + data_t got3 = arg_t_get(ot3); + char rv3 = got3.c; cr_assert_eq(rv3, 'e', "obj_t_get_char: failed char direct retrieval"); } /** - * Checks that the object_t struct returns the correct int value (direct) - */ -Test(custom_type, obj_t_get_int) -{ - object_t *ot = obj_t_int(123, NULL); - int rv = int_t_get(ot); - cr_assert_eq(rv, 123, "obj_t_get_int: failed int direct retrieval"); -} - -/** - * Checks that the object_t struct returns the correct int value (lua) + * Checks that the object_t struct returns the correct char value (lua) */ -Test(custom_type, obj_t_get_int_lua) +Test(custom_type, obj_t_get_char_lua) { - object_t *ot = obj_t_int(10, "../../../tests/custom-scripts/Lua_file/int_test.lua"); - int rv = int_t_get (ot); - cr_assert_eq(rv, 15, "int_t_get: failed int Lua retrieval"); + data.c = 'a'; + object_t *ot = obj_t_init(data, CHAR_TYPE, "../../../tests/custom-scripts/Lua_file/char_test.lua"); + data_t got = arg_t_get(ot); + char rv = got.c; + cr_assert_eq(rv, 'b', "obj_t_get_char: failed char direct retrieval"); } /** @@ -329,18 +333,52 @@ Test(custom_type, obj_t_get_int_lua) */ Test(custom_type, obj_t_get_int_lua_args) { - object_t *ot = obj_t_int(99, + data.i = 99; + data2.i = 5; + data3.i = 10; + data4.i = 5; + + data.c = 'X'; + data2.c = 'Y'; + + object_t *ot = obj_t_init(data, INT_TYPE, "../../../tests/custom-scripts/Lua_file/int_test_args.lua"); - ot = obj_add_arg_int(obj_add_arg_int(ot, 5), 10); - int rv = int_t_get(ot); - cr_assert_eq(rv, 15, "obj_t_get_int: failed int direct retrieval"); + ot = obj_add_arg(obj_add_arg(ot, data4, INT_TYPE), data3, INT_TYPE); + data_t got = arg_t_get(ot); + int rv = got.i; + cr_assert_eq(rv, 15, "obj_t_get_int 1: failed int direct retrieval with value %u", rv); // Arguments of an object don't have to be of the same type! - object_t *ot2 = obj_t_int(99, + object_t *ot2 = obj_t_init(data, INT_TYPE, "../../../tests/custom-scripts/Lua_file/int_test_args.lua"); - ot2 = obj_add_arg_char(obj_add_arg_char(ot2, 'X'), 'Y'); - int rv2 = int_t_get(ot2); - cr_assert_eq(rv2, 100, "obj_t_get_int: failed int direct retrieval"); + ot2 = obj_add_arg(obj_add_arg(ot2, data, CHAR_TYPE), data2, CHAR_TYPE); + data_t got2 = arg_t_get(ot2); + int rv2 = got2.i; + cr_assert_eq(rv2, 100, "obj_t_get_int 2: failed int direct retrieval"); +} + +/** + * Checks that the object_t struct returns the correct int value (direct) + */ +Test(custom_type, obj_t_get_int) +{ + data.i = 123; + object_t *ot = obj_t_init(data, INT_TYPE, NULL); + data_t got = arg_t_get(ot); + int rv = got.i; + cr_assert_eq(rv, 123, "obj_t_get_int: failed int direct retrieval"); +} + +/** + * Checks that the object_t struct returns the correct int value (lua) + */ +Test(custom_type, obj_t_get_int_lua) +{ + data.i = 10; + object_t *ot = obj_t_init(data, INT_TYPE, "../../../tests/custom-scripts/Lua_file/int_test.lua"); + data_t got = arg_t_get(ot); + int rv = got.i; + cr_assert_eq(rv, 15, "int_t_get: failed int Lua retrieval"); } /** @@ -348,8 +386,10 @@ Test(custom_type, obj_t_get_int_lua_args) */ Test(custom_type, obj_t_get_str) { - object_t *ot = obj_t_str("testing", NULL); - char *rv = str_t_get(ot); + data.s = "testing"; + object_t *ot = obj_t_init(data, STR_TYPE, NULL); + data_t got = arg_t_get(ot); + char *rv = got.s; cr_assert_str_eq(rv, "testing", "obj_t_get_str: failed str direct retrieval"); } @@ -358,8 +398,10 @@ Test(custom_type, obj_t_get_str) */ Test(custom_type, obj_t_get_str_lua) { - object_t *ot = obj_t_str("testing_failed", "../../../tests/custom-scripts/Lua_file/string_test.lua"); - char *rv = str_t_get(ot); + data.s = "testing_failed"; + object_t *ot = obj_t_init(data, STR_TYPE, "../../../tests/custom-scripts/Lua_file/string_test.lua"); + data_t got = arg_t_get(ot); + char *rv = got.s; cr_assert_str_eq(rv, "testing_succeeded", "string_t_get: failed string Lua retrieval"); } @@ -369,9 +411,13 @@ Test(custom_type, obj_t_get_str_lua) */ Test(custom_type, obj_t_get_str_lua_args) { - object_t *ot = obj_t_str(" ", "../../../tests/custom-scripts/Lua_file/string_test_args.lua"); - ot = obj_add_arg_str(obj_add_arg_str(ot, "Test "), "passes!"); - char *rv = str_t_get(ot); - cr_assert_str_eq(rv, "Test passes!", "obj_t_get_int: failed string direct retrieval"); - -} \ No newline at end of file + data.s = " "; + data2.s = "Test "; + data3.s = "passes!"; + object_t *ot = obj_t_init(data, STR_TYPE, "../../../tests/custom-scripts/Lua_file/string_test_args.lua"); + ot = obj_add_arg(obj_add_arg(ot, data2, STR_TYPE), data3, STR_TYPE); + data_t got = arg_t_get(ot); + char *rv = got.s; + cr_assert_str_eq(rv, "Test passes!", "obj_t_get_int: failed string direct retrieval with %s", rv); + +} \ No newline at end of file diff --git a/tests/custom-scripts/utlist.h b/tests/custom-scripts/utlist.h new file mode 100644 index 0000000000..492908cf10 --- /dev/null +++ b/tests/custom-scripts/utlist.h @@ -0,0 +1,1073 @@ +/* +Copyright (c) 2007-2022, Troy D. Hanson https://troydhanson.github.io/uthash/ +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER +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 UTLIST_H +#define UTLIST_H + +#define UTLIST_VERSION 2.3.0 + +#include + +/* + * This file contains macros to manipulate singly and doubly-linked lists. + * + * 1. LL_ macros: singly-linked lists. + * 2. DL_ macros: doubly-linked lists. + * 3. CDL_ macros: circular doubly-linked lists. + * + * To use singly-linked lists, your structure must have a "next" pointer. + * To use doubly-linked lists, your structure must "prev" and "next" pointers. + * Either way, the pointer to the head of the list must be initialized to NULL. + * + * ----------------.EXAMPLE ------------------------- + * struct item { + * int id; + * struct item *prev, *next; + * } + * + * struct item *list = NULL: + * + * int main() { + * struct item *item; + * ... allocate and populate item ... + * DL_APPEND(list, item); + * } + * -------------------------------------------------- + * + * For doubly-linked lists, the append and delete macros are O(1) + * For singly-linked lists, append and delete are O(n) but prepend is O(1) + * The sort macro is O(n log(n)) for all types of single/double/circular lists. + */ + +/* These macros use decltype or the earlier __typeof GNU extension. + As decltype is only available in newer compilers (VS2010 or gcc 4.3+ + when compiling c++ source) this code uses whatever method is needed + or, for VS2008 where neither is available, uses casting workarounds. */ +#if !defined(LDECLTYPE) && !defined(NO_DECLTYPE) +#if defined(_MSC_VER) /* MS compiler */ +#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ +#define LDECLTYPE(x) decltype(x) +#else /* VS2008 or older (or VS2010 in C mode) */ +#define NO_DECLTYPE +#endif +#elif defined(__BORLANDC__) || defined(__ICCARM__) || defined(__LCC__) || defined(__WATCOMC__) +#define NO_DECLTYPE +#else /* GNU, Sun and other compilers */ +#define LDECLTYPE(x) __typeof(x) +#endif +#endif + +/* for VS2008 we use some workarounds to get around the lack of decltype, + * namely, we always reassign our tmp variable to the list head if we need + * to dereference its prev/next pointers, and save/restore the real head.*/ +#ifdef NO_DECLTYPE +#define IF_NO_DECLTYPE(x) x +#define LDECLTYPE(x) char* +#define UTLIST_SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); } +#define UTLIST_NEXT(elt,list,next) ((char*)((list)->next)) +#define UTLIST_NEXTASGN(elt,list,to,next) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); } +/* #define UTLIST_PREV(elt,list,prev) ((char*)((list)->prev)) */ +#define UTLIST_PREVASGN(elt,list,to,prev) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); } +#define UTLIST_RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; } +#define UTLIST_CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); } +#else +#define IF_NO_DECLTYPE(x) +#define UTLIST_SV(elt,list) +#define UTLIST_NEXT(elt,list,next) ((elt)->next) +#define UTLIST_NEXTASGN(elt,list,to,next) ((elt)->next)=(to) +/* #define UTLIST_PREV(elt,list,prev) ((elt)->prev) */ +#define UTLIST_PREVASGN(elt,list,to,prev) ((elt)->prev)=(to) +#define UTLIST_RS(list) +#define UTLIST_CASTASGN(a,b) (a)=(b) +#endif + +/****************************************************************************** + * The sort macro is an adaptation of Simon Tatham's O(n log(n)) mergesort * + * Unwieldy variable names used here to avoid shadowing passed-in variables. * + *****************************************************************************/ +#define LL_SORT(list, cmp) \ + LL_SORT2(list, cmp, next) + +#define LL_SORT2(list, cmp, next) \ +do { \ + LDECLTYPE(list) _ls_p; \ + LDECLTYPE(list) _ls_q; \ + LDECLTYPE(list) _ls_e; \ + LDECLTYPE(list) _ls_tail; \ + IF_NO_DECLTYPE(LDECLTYPE(list) _tmp;) \ + int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ + if (list) { \ + _ls_insize = 1; \ + _ls_looping = 1; \ + while (_ls_looping) { \ + UTLIST_CASTASGN(_ls_p,list); \ + (list) = NULL; \ + _ls_tail = NULL; \ + _ls_nmerges = 0; \ + while (_ls_p) { \ + _ls_nmerges++; \ + _ls_q = _ls_p; \ + _ls_psize = 0; \ + for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ + _ls_psize++; \ + UTLIST_SV(_ls_q,list); _ls_q = UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); \ + if (!_ls_q) break; \ + } \ + _ls_qsize = _ls_insize; \ + while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ + if (_ls_psize == 0) { \ + _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \ + UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \ + } else if (_ls_qsize == 0 || !_ls_q) { \ + _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \ + UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \ + } else if (cmp(_ls_p,_ls_q) <= 0) { \ + _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \ + UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \ + } else { \ + _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \ + UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \ + } \ + if (_ls_tail) { \ + UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,_ls_e,next); UTLIST_RS(list); \ + } else { \ + UTLIST_CASTASGN(list,_ls_e); \ + } \ + _ls_tail = _ls_e; \ + } \ + _ls_p = _ls_q; \ + } \ + if (_ls_tail) { \ + UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,NULL,next); UTLIST_RS(list); \ + } \ + if (_ls_nmerges <= 1) { \ + _ls_looping=0; \ + } \ + _ls_insize *= 2; \ + } \ + } \ +} while (0) + + +#define DL_SORT(list, cmp) \ + DL_SORT2(list, cmp, prev, next) + +#define DL_SORT2(list, cmp, prev, next) \ +do { \ + LDECLTYPE(list) _ls_p; \ + LDECLTYPE(list) _ls_q; \ + LDECLTYPE(list) _ls_e; \ + LDECLTYPE(list) _ls_tail; \ + IF_NO_DECLTYPE(LDECLTYPE(list) _tmp;) \ + int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ + if (list) { \ + _ls_insize = 1; \ + _ls_looping = 1; \ + while (_ls_looping) { \ + UTLIST_CASTASGN(_ls_p,list); \ + (list) = NULL; \ + _ls_tail = NULL; \ + _ls_nmerges = 0; \ + while (_ls_p) { \ + _ls_nmerges++; \ + _ls_q = _ls_p; \ + _ls_psize = 0; \ + for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ + _ls_psize++; \ + UTLIST_SV(_ls_q,list); _ls_q = UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); \ + if (!_ls_q) break; \ + } \ + _ls_qsize = _ls_insize; \ + while ((_ls_psize > 0) || ((_ls_qsize > 0) && _ls_q)) { \ + if (_ls_psize == 0) { \ + _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \ + UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \ + } else if ((_ls_qsize == 0) || (!_ls_q)) { \ + _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \ + UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \ + } else if (cmp(_ls_p,_ls_q) <= 0) { \ + _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \ + UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \ + } else { \ + _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \ + UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \ + } \ + if (_ls_tail) { \ + UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,_ls_e,next); UTLIST_RS(list); \ + } else { \ + UTLIST_CASTASGN(list,_ls_e); \ + } \ + UTLIST_SV(_ls_e,list); UTLIST_PREVASGN(_ls_e,list,_ls_tail,prev); UTLIST_RS(list); \ + _ls_tail = _ls_e; \ + } \ + _ls_p = _ls_q; \ + } \ + UTLIST_CASTASGN((list)->prev, _ls_tail); \ + UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,NULL,next); UTLIST_RS(list); \ + if (_ls_nmerges <= 1) { \ + _ls_looping=0; \ + } \ + _ls_insize *= 2; \ + } \ + } \ +} while (0) + +#define CDL_SORT(list, cmp) \ + CDL_SORT2(list, cmp, prev, next) + +#define CDL_SORT2(list, cmp, prev, next) \ +do { \ + LDECLTYPE(list) _ls_p; \ + LDECLTYPE(list) _ls_q; \ + LDECLTYPE(list) _ls_e; \ + LDECLTYPE(list) _ls_tail; \ + LDECLTYPE(list) _ls_oldhead; \ + LDECLTYPE(list) _tmp; \ + int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ + if (list) { \ + _ls_insize = 1; \ + _ls_looping = 1; \ + while (_ls_looping) { \ + UTLIST_CASTASGN(_ls_p,list); \ + UTLIST_CASTASGN(_ls_oldhead,list); \ + (list) = NULL; \ + _ls_tail = NULL; \ + _ls_nmerges = 0; \ + while (_ls_p) { \ + _ls_nmerges++; \ + _ls_q = _ls_p; \ + _ls_psize = 0; \ + for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ + _ls_psize++; \ + UTLIST_SV(_ls_q,list); \ + if (UTLIST_NEXT(_ls_q,list,next) == _ls_oldhead) { \ + _ls_q = NULL; \ + } else { \ + _ls_q = UTLIST_NEXT(_ls_q,list,next); \ + } \ + UTLIST_RS(list); \ + if (!_ls_q) break; \ + } \ + _ls_qsize = _ls_insize; \ + while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ + if (_ls_psize == 0) { \ + _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \ + UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \ + if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ + } else if (_ls_qsize == 0 || !_ls_q) { \ + _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \ + UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \ + if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ + } else if (cmp(_ls_p,_ls_q) <= 0) { \ + _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \ + UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \ + if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ + } else { \ + _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \ + UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \ + if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ + } \ + if (_ls_tail) { \ + UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,_ls_e,next); UTLIST_RS(list); \ + } else { \ + UTLIST_CASTASGN(list,_ls_e); \ + } \ + UTLIST_SV(_ls_e,list); UTLIST_PREVASGN(_ls_e,list,_ls_tail,prev); UTLIST_RS(list); \ + _ls_tail = _ls_e; \ + } \ + _ls_p = _ls_q; \ + } \ + UTLIST_CASTASGN((list)->prev,_ls_tail); \ + UTLIST_CASTASGN(_tmp,list); \ + UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,_tmp,next); UTLIST_RS(list); \ + if (_ls_nmerges <= 1) { \ + _ls_looping=0; \ + } \ + _ls_insize *= 2; \ + } \ + } \ +} while (0) + +/****************************************************************************** + * singly linked list macros (non-circular) * + *****************************************************************************/ +#define LL_PREPEND(head,add) \ + LL_PREPEND2(head,add,next) + +#define LL_PREPEND2(head,add,next) \ +do { \ + (add)->next = (head); \ + (head) = (add); \ +} while (0) + +#define LL_CONCAT(head1,head2) \ + LL_CONCAT2(head1,head2,next) + +#define LL_CONCAT2(head1,head2,next) \ +do { \ + LDECLTYPE(head1) _tmp; \ + if (head1) { \ + _tmp = (head1); \ + while (_tmp->next) { _tmp = _tmp->next; } \ + _tmp->next=(head2); \ + } else { \ + (head1)=(head2); \ + } \ +} while (0) + +#define LL_APPEND(head,add) \ + LL_APPEND2(head,add,next) + +#define LL_APPEND2(head,add,next) \ +do { \ + LDECLTYPE(head) _tmp; \ + (add)->next=NULL; \ + if (head) { \ + _tmp = (head); \ + while (_tmp->next) { _tmp = _tmp->next; } \ + _tmp->next=(add); \ + } else { \ + (head)=(add); \ + } \ +} while (0) + +#define LL_INSERT_INORDER(head,add,cmp) \ + LL_INSERT_INORDER2(head,add,cmp,next) + +#define LL_INSERT_INORDER2(head,add,cmp,next) \ +do { \ + LDECLTYPE(head) _tmp; \ + if (head) { \ + LL_LOWER_BOUND2(head, _tmp, add, cmp, next); \ + LL_APPEND_ELEM2(head, _tmp, add, next); \ + } else { \ + (head) = (add); \ + (head)->next = NULL; \ + } \ +} while (0) + +#define LL_LOWER_BOUND(head,elt,like,cmp) \ + LL_LOWER_BOUND2(head,elt,like,cmp,next) + +#define LL_LOWER_BOUND2(head,elt,like,cmp,next) \ + do { \ + if ((head) == NULL || (cmp(head, like)) >= 0) { \ + (elt) = NULL; \ + } else { \ + for ((elt) = (head); (elt)->next != NULL; (elt) = (elt)->next) { \ + if (cmp((elt)->next, like) >= 0) { \ + break; \ + } \ + } \ + } \ + } while (0) + +#define LL_DELETE(head,del) \ + LL_DELETE2(head,del,next) + +#define LL_DELETE2(head,del,next) \ +do { \ + LDECLTYPE(head) _tmp; \ + if ((head) == (del)) { \ + (head)=(head)->next; \ + } else { \ + _tmp = (head); \ + while (_tmp->next && (_tmp->next != (del))) { \ + _tmp = _tmp->next; \ + } \ + if (_tmp->next) { \ + _tmp->next = (del)->next; \ + } \ + } \ +} while (0) + +#define LL_COUNT(head,el,counter) \ + LL_COUNT2(head,el,counter,next) \ + +#define LL_COUNT2(head,el,counter,next) \ +do { \ + (counter) = 0; \ + LL_FOREACH2(head,el,next) { ++(counter); } \ +} while (0) + +#define LL_FOREACH(head,el) \ + LL_FOREACH2(head,el,next) + +#define LL_FOREACH2(head,el,next) \ + for ((el) = (head); el; (el) = (el)->next) + +#define LL_FOREACH_SAFE(head,el,tmp) \ + LL_FOREACH_SAFE2(head,el,tmp,next) + +#define LL_FOREACH_SAFE2(head,el,tmp,next) \ + for ((el) = (head); (el) && ((tmp) = (el)->next, 1); (el) = (tmp)) + +#define LL_SEARCH_SCALAR(head,out,field,val) \ + LL_SEARCH_SCALAR2(head,out,field,val,next) + +#define LL_SEARCH_SCALAR2(head,out,field,val,next) \ +do { \ + LL_FOREACH2(head,out,next) { \ + if ((out)->field == (val)) break; \ + } \ +} while (0) + +#define LL_SEARCH(head,out,elt,cmp) \ + LL_SEARCH2(head,out,elt,cmp,next) + +#define LL_SEARCH2(head,out,elt,cmp,next) \ +do { \ + LL_FOREACH2(head,out,next) { \ + if ((cmp(out,elt))==0) break; \ + } \ +} while (0) + +#define LL_REPLACE_ELEM2(head, el, add, next) \ +do { \ + LDECLTYPE(head) _tmp; \ + assert((head) != NULL); \ + assert((el) != NULL); \ + assert((add) != NULL); \ + (add)->next = (el)->next; \ + if ((head) == (el)) { \ + (head) = (add); \ + } else { \ + _tmp = (head); \ + while (_tmp->next && (_tmp->next != (el))) { \ + _tmp = _tmp->next; \ + } \ + if (_tmp->next) { \ + _tmp->next = (add); \ + } \ + } \ +} while (0) + +#define LL_REPLACE_ELEM(head, el, add) \ + LL_REPLACE_ELEM2(head, el, add, next) + +#define LL_PREPEND_ELEM2(head, el, add, next) \ +do { \ + if (el) { \ + LDECLTYPE(head) _tmp; \ + assert((head) != NULL); \ + assert((add) != NULL); \ + (add)->next = (el); \ + if ((head) == (el)) { \ + (head) = (add); \ + } else { \ + _tmp = (head); \ + while (_tmp->next && (_tmp->next != (el))) { \ + _tmp = _tmp->next; \ + } \ + if (_tmp->next) { \ + _tmp->next = (add); \ + } \ + } \ + } else { \ + LL_APPEND2(head, add, next); \ + } \ +} while (0) \ + +#define LL_PREPEND_ELEM(head, el, add) \ + LL_PREPEND_ELEM2(head, el, add, next) + +#define LL_APPEND_ELEM2(head, el, add, next) \ +do { \ + if (el) { \ + assert((head) != NULL); \ + assert((add) != NULL); \ + (add)->next = (el)->next; \ + (el)->next = (add); \ + } else { \ + LL_PREPEND2(head, add, next); \ + } \ +} while (0) \ + +#define LL_APPEND_ELEM(head, el, add) \ + LL_APPEND_ELEM2(head, el, add, next) + +#ifdef NO_DECLTYPE +/* Here are VS2008 / NO_DECLTYPE replacements for a few functions */ + +#undef LL_CONCAT2 +#define LL_CONCAT2(head1,head2,next) \ +do { \ + char *_tmp; \ + if (head1) { \ + _tmp = (char*)(head1); \ + while ((head1)->next) { (head1) = (head1)->next; } \ + (head1)->next = (head2); \ + UTLIST_RS(head1); \ + } else { \ + (head1)=(head2); \ + } \ +} while (0) + +#undef LL_APPEND2 +#define LL_APPEND2(head,add,next) \ +do { \ + if (head) { \ + (add)->next = head; /* use add->next as a temp variable */ \ + while ((add)->next->next) { (add)->next = (add)->next->next; } \ + (add)->next->next=(add); \ + } else { \ + (head)=(add); \ + } \ + (add)->next=NULL; \ +} while (0) + +#undef LL_INSERT_INORDER2 +#define LL_INSERT_INORDER2(head,add,cmp,next) \ +do { \ + if ((head) == NULL || (cmp(head, add)) >= 0) { \ + (add)->next = (head); \ + (head) = (add); \ + } else { \ + char *_tmp = (char*)(head); \ + while ((head)->next != NULL && (cmp((head)->next, add)) < 0) { \ + (head) = (head)->next; \ + } \ + (add)->next = (head)->next; \ + (head)->next = (add); \ + UTLIST_RS(head); \ + } \ +} while (0) + +#undef LL_DELETE2 +#define LL_DELETE2(head,del,next) \ +do { \ + if ((head) == (del)) { \ + (head)=(head)->next; \ + } else { \ + char *_tmp = (char*)(head); \ + while ((head)->next && ((head)->next != (del))) { \ + (head) = (head)->next; \ + } \ + if ((head)->next) { \ + (head)->next = ((del)->next); \ + } \ + UTLIST_RS(head); \ + } \ +} while (0) + +#undef LL_REPLACE_ELEM2 +#define LL_REPLACE_ELEM2(head, el, add, next) \ +do { \ + assert((head) != NULL); \ + assert((el) != NULL); \ + assert((add) != NULL); \ + if ((head) == (el)) { \ + (head) = (add); \ + } else { \ + (add)->next = head; \ + while ((add)->next->next && ((add)->next->next != (el))) { \ + (add)->next = (add)->next->next; \ + } \ + if ((add)->next->next) { \ + (add)->next->next = (add); \ + } \ + } \ + (add)->next = (el)->next; \ +} while (0) + +#undef LL_PREPEND_ELEM2 +#define LL_PREPEND_ELEM2(head, el, add, next) \ +do { \ + if (el) { \ + assert((head) != NULL); \ + assert((add) != NULL); \ + if ((head) == (el)) { \ + (head) = (add); \ + } else { \ + (add)->next = (head); \ + while ((add)->next->next && ((add)->next->next != (el))) { \ + (add)->next = (add)->next->next; \ + } \ + if ((add)->next->next) { \ + (add)->next->next = (add); \ + } \ + } \ + (add)->next = (el); \ + } else { \ + LL_APPEND2(head, add, next); \ + } \ +} while (0) \ + +#endif /* NO_DECLTYPE */ + +/****************************************************************************** + * doubly linked list macros (non-circular) * + *****************************************************************************/ +#define DL_PREPEND(head,add) \ + DL_PREPEND2(head,add,prev,next) + +#define DL_PREPEND2(head,add,prev,next) \ +do { \ + (add)->next = (head); \ + if (head) { \ + (add)->prev = (head)->prev; \ + (head)->prev = (add); \ + } else { \ + (add)->prev = (add); \ + } \ + (head) = (add); \ +} while (0) + +#define DL_APPEND(head,add) \ + DL_APPEND2(head,add,prev,next) + +#define DL_APPEND2(head,add,prev,next) \ +do { \ + if (head) { \ + (add)->prev = (head)->prev; \ + (head)->prev->next = (add); \ + (head)->prev = (add); \ + (add)->next = NULL; \ + } else { \ + (head)=(add); \ + (head)->prev = (head); \ + (head)->next = NULL; \ + } \ +} while (0) + +#define DL_INSERT_INORDER(head,add,cmp) \ + DL_INSERT_INORDER2(head,add,cmp,prev,next) + +#define DL_INSERT_INORDER2(head,add,cmp,prev,next) \ +do { \ + LDECLTYPE(head) _tmp; \ + if (head) { \ + DL_LOWER_BOUND2(head, _tmp, add, cmp, next); \ + DL_APPEND_ELEM2(head, _tmp, add, prev, next); \ + } else { \ + (head) = (add); \ + (head)->prev = (head); \ + (head)->next = NULL; \ + } \ +} while (0) + +#define DL_LOWER_BOUND(head,elt,like,cmp) \ + DL_LOWER_BOUND2(head,elt,like,cmp,next) + +#define DL_LOWER_BOUND2(head,elt,like,cmp,next) \ +do { \ + if ((head) == NULL || (cmp(head, like)) >= 0) { \ + (elt) = NULL; \ + } else { \ + for ((elt) = (head); (elt)->next != NULL; (elt) = (elt)->next) { \ + if ((cmp((elt)->next, like)) >= 0) { \ + break; \ + } \ + } \ + } \ +} while (0) + +#define DL_CONCAT(head1,head2) \ + DL_CONCAT2(head1,head2,prev,next) + +#define DL_CONCAT2(head1,head2,prev,next) \ +do { \ + LDECLTYPE(head1) _tmp; \ + if (head2) { \ + if (head1) { \ + UTLIST_CASTASGN(_tmp, (head2)->prev); \ + (head2)->prev = (head1)->prev; \ + (head1)->prev->next = (head2); \ + UTLIST_CASTASGN((head1)->prev, _tmp); \ + } else { \ + (head1)=(head2); \ + } \ + } \ +} while (0) + +#define DL_DELETE(head,del) \ + DL_DELETE2(head,del,prev,next) + +#define DL_DELETE2(head,del,prev,next) \ +do { \ + assert((head) != NULL); \ + assert((del)->prev != NULL); \ + if ((del)->prev == (del)) { \ + (head)=NULL; \ + } else if ((del)==(head)) { \ + (del)->next->prev = (del)->prev; \ + (head) = (del)->next; \ + } else { \ + (del)->prev->next = (del)->next; \ + if ((del)->next) { \ + (del)->next->prev = (del)->prev; \ + } else { \ + (head)->prev = (del)->prev; \ + } \ + } \ +} while (0) + +#define DL_COUNT(head,el,counter) \ + DL_COUNT2(head,el,counter,next) \ + +#define DL_COUNT2(head,el,counter,next) \ +do { \ + (counter) = 0; \ + DL_FOREACH2(head,el,next) { ++(counter); } \ +} while (0) + +#define DL_FOREACH(head,el) \ + DL_FOREACH2(head,el,next) + +#define DL_FOREACH2(head,el,next) \ + for ((el) = (head); el; (el) = (el)->next) + +/* this version is safe for deleting the elements during iteration */ +#define DL_FOREACH_SAFE(head,el,tmp) \ + DL_FOREACH_SAFE2(head,el,tmp,next) + +#define DL_FOREACH_SAFE2(head,el,tmp,next) \ + for ((el) = (head); (el) && ((tmp) = (el)->next, 1); (el) = (tmp)) + +/* these are identical to their singly-linked list counterparts */ +#define DL_SEARCH_SCALAR LL_SEARCH_SCALAR +#define DL_SEARCH LL_SEARCH +#define DL_SEARCH_SCALAR2 LL_SEARCH_SCALAR2 +#define DL_SEARCH2 LL_SEARCH2 + +#define DL_REPLACE_ELEM2(head, el, add, prev, next) \ +do { \ + assert((head) != NULL); \ + assert((el) != NULL); \ + assert((add) != NULL); \ + if ((head) == (el)) { \ + (head) = (add); \ + (add)->next = (el)->next; \ + if ((el)->next == NULL) { \ + (add)->prev = (add); \ + } else { \ + (add)->prev = (el)->prev; \ + (add)->next->prev = (add); \ + } \ + } else { \ + (add)->next = (el)->next; \ + (add)->prev = (el)->prev; \ + (add)->prev->next = (add); \ + if ((el)->next == NULL) { \ + (head)->prev = (add); \ + } else { \ + (add)->next->prev = (add); \ + } \ + } \ +} while (0) + +#define DL_REPLACE_ELEM(head, el, add) \ + DL_REPLACE_ELEM2(head, el, add, prev, next) + +#define DL_PREPEND_ELEM2(head, el, add, prev, next) \ +do { \ + if (el) { \ + assert((head) != NULL); \ + assert((add) != NULL); \ + (add)->next = (el); \ + (add)->prev = (el)->prev; \ + (el)->prev = (add); \ + if ((head) == (el)) { \ + (head) = (add); \ + } else { \ + (add)->prev->next = (add); \ + } \ + } else { \ + DL_APPEND2(head, add, prev, next); \ + } \ +} while (0) \ + +#define DL_PREPEND_ELEM(head, el, add) \ + DL_PREPEND_ELEM2(head, el, add, prev, next) + +#define DL_APPEND_ELEM2(head, el, add, prev, next) \ +do { \ + if (el) { \ + assert((head) != NULL); \ + assert((add) != NULL); \ + (add)->next = (el)->next; \ + (add)->prev = (el); \ + (el)->next = (add); \ + if ((add)->next) { \ + (add)->next->prev = (add); \ + } else { \ + (head)->prev = (add); \ + } \ + } else { \ + DL_PREPEND2(head, add, prev, next); \ + } \ +} while (0) \ + +#define DL_APPEND_ELEM(head, el, add) \ + DL_APPEND_ELEM2(head, el, add, prev, next) + +#ifdef NO_DECLTYPE +/* Here are VS2008 / NO_DECLTYPE replacements for a few functions */ + +#undef DL_INSERT_INORDER2 +#define DL_INSERT_INORDER2(head,add,cmp,prev,next) \ +do { \ + if ((head) == NULL) { \ + (add)->prev = (add); \ + (add)->next = NULL; \ + (head) = (add); \ + } else if ((cmp(head, add)) >= 0) { \ + (add)->prev = (head)->prev; \ + (add)->next = (head); \ + (head)->prev = (add); \ + (head) = (add); \ + } else { \ + char *_tmp = (char*)(head); \ + while ((head)->next && (cmp((head)->next, add)) < 0) { \ + (head) = (head)->next; \ + } \ + (add)->prev = (head); \ + (add)->next = (head)->next; \ + (head)->next = (add); \ + UTLIST_RS(head); \ + if ((add)->next) { \ + (add)->next->prev = (add); \ + } else { \ + (head)->prev = (add); \ + } \ + } \ +} while (0) +#endif /* NO_DECLTYPE */ + +/****************************************************************************** + * circular doubly linked list macros * + *****************************************************************************/ +#define CDL_APPEND(head,add) \ + CDL_APPEND2(head,add,prev,next) + +#define CDL_APPEND2(head,add,prev,next) \ +do { \ + if (head) { \ + (add)->prev = (head)->prev; \ + (add)->next = (head); \ + (head)->prev = (add); \ + (add)->prev->next = (add); \ + } else { \ + (add)->prev = (add); \ + (add)->next = (add); \ + (head) = (add); \ + } \ +} while (0) + +#define CDL_PREPEND(head,add) \ + CDL_PREPEND2(head,add,prev,next) + +#define CDL_PREPEND2(head,add,prev,next) \ +do { \ + if (head) { \ + (add)->prev = (head)->prev; \ + (add)->next = (head); \ + (head)->prev = (add); \ + (add)->prev->next = (add); \ + } else { \ + (add)->prev = (add); \ + (add)->next = (add); \ + } \ + (head) = (add); \ +} while (0) + +#define CDL_INSERT_INORDER(head,add,cmp) \ + CDL_INSERT_INORDER2(head,add,cmp,prev,next) + +#define CDL_INSERT_INORDER2(head,add,cmp,prev,next) \ +do { \ + LDECLTYPE(head) _tmp; \ + if (head) { \ + CDL_LOWER_BOUND2(head, _tmp, add, cmp, next); \ + CDL_APPEND_ELEM2(head, _tmp, add, prev, next); \ + } else { \ + (head) = (add); \ + (head)->next = (head); \ + (head)->prev = (head); \ + } \ +} while (0) + +#define CDL_LOWER_BOUND(head,elt,like,cmp) \ + CDL_LOWER_BOUND2(head,elt,like,cmp,next) + +#define CDL_LOWER_BOUND2(head,elt,like,cmp,next) \ +do { \ + if ((head) == NULL || (cmp(head, like)) >= 0) { \ + (elt) = NULL; \ + } else { \ + for ((elt) = (head); (elt)->next != (head); (elt) = (elt)->next) { \ + if ((cmp((elt)->next, like)) >= 0) { \ + break; \ + } \ + } \ + } \ +} while (0) + +#define CDL_DELETE(head,del) \ + CDL_DELETE2(head,del,prev,next) + +#define CDL_DELETE2(head,del,prev,next) \ +do { \ + if (((head)==(del)) && ((head)->next == (head))) { \ + (head) = NULL; \ + } else { \ + (del)->next->prev = (del)->prev; \ + (del)->prev->next = (del)->next; \ + if ((del) == (head)) (head)=(del)->next; \ + } \ +} while (0) + +#define CDL_COUNT(head,el,counter) \ + CDL_COUNT2(head,el,counter,next) \ + +#define CDL_COUNT2(head, el, counter,next) \ +do { \ + (counter) = 0; \ + CDL_FOREACH2(head,el,next) { ++(counter); } \ +} while (0) + +#define CDL_FOREACH(head,el) \ + CDL_FOREACH2(head,el,next) + +#define CDL_FOREACH2(head,el,next) \ + for ((el)=(head);el;(el)=(((el)->next==(head)) ? NULL : (el)->next)) + +#define CDL_FOREACH_SAFE(head,el,tmp1,tmp2) \ + CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next) + +#define CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next) \ + for ((el) = (head), (tmp1) = (head) ? (head)->prev : NULL; \ + (el) && ((tmp2) = (el)->next, 1); \ + (el) = ((el) == (tmp1) ? NULL : (tmp2))) + +#define CDL_SEARCH_SCALAR(head,out,field,val) \ + CDL_SEARCH_SCALAR2(head,out,field,val,next) + +#define CDL_SEARCH_SCALAR2(head,out,field,val,next) \ +do { \ + CDL_FOREACH2(head,out,next) { \ + if ((out)->field == (val)) break; \ + } \ +} while (0) + +#define CDL_SEARCH(head,out,elt,cmp) \ + CDL_SEARCH2(head,out,elt,cmp,next) + +#define CDL_SEARCH2(head,out,elt,cmp,next) \ +do { \ + CDL_FOREACH2(head,out,next) { \ + if ((cmp(out,elt))==0) break; \ + } \ +} while (0) + +#define CDL_REPLACE_ELEM2(head, el, add, prev, next) \ +do { \ + assert((head) != NULL); \ + assert((el) != NULL); \ + assert((add) != NULL); \ + if ((el)->next == (el)) { \ + (add)->next = (add); \ + (add)->prev = (add); \ + (head) = (add); \ + } else { \ + (add)->next = (el)->next; \ + (add)->prev = (el)->prev; \ + (add)->next->prev = (add); \ + (add)->prev->next = (add); \ + if ((head) == (el)) { \ + (head) = (add); \ + } \ + } \ +} while (0) + +#define CDL_REPLACE_ELEM(head, el, add) \ + CDL_REPLACE_ELEM2(head, el, add, prev, next) + +#define CDL_PREPEND_ELEM2(head, el, add, prev, next) \ +do { \ + if (el) { \ + assert((head) != NULL); \ + assert((add) != NULL); \ + (add)->next = (el); \ + (add)->prev = (el)->prev; \ + (el)->prev = (add); \ + (add)->prev->next = (add); \ + if ((head) == (el)) { \ + (head) = (add); \ + } \ + } else { \ + CDL_APPEND2(head, add, prev, next); \ + } \ +} while (0) + +#define CDL_PREPEND_ELEM(head, el, add) \ + CDL_PREPEND_ELEM2(head, el, add, prev, next) + +#define CDL_APPEND_ELEM2(head, el, add, prev, next) \ +do { \ + if (el) { \ + assert((head) != NULL); \ + assert((add) != NULL); \ + (add)->next = (el)->next; \ + (add)->prev = (el); \ + (el)->next = (add); \ + (add)->next->prev = (add); \ + } else { \ + CDL_PREPEND2(head, add, prev, next); \ + } \ +} while (0) + +#define CDL_APPEND_ELEM(head, el, add) \ + CDL_APPEND_ELEM2(head, el, add, prev, next) + +#ifdef NO_DECLTYPE +/* Here are VS2008 / NO_DECLTYPE replacements for a few functions */ + +#undef CDL_INSERT_INORDER2 +#define CDL_INSERT_INORDER2(head,add,cmp,prev,next) \ +do { \ + if ((head) == NULL) { \ + (add)->prev = (add); \ + (add)->next = (add); \ + (head) = (add); \ + } else if ((cmp(head, add)) >= 0) { \ + (add)->prev = (head)->prev; \ + (add)->next = (head); \ + (add)->prev->next = (add); \ + (head)->prev = (add); \ + (head) = (add); \ + } else { \ + char *_tmp = (char*)(head); \ + while ((char*)(head)->next != _tmp && (cmp((head)->next, add)) < 0) { \ + (head) = (head)->next; \ + } \ + (add)->prev = (head); \ + (add)->next = (head)->next; \ + (add)->next->prev = (add); \ + (head)->next = (add); \ + UTLIST_RS(head); \ + } \ +} while (0) +#endif /* NO_DECLTYPE */ + +#endif /* UTLIST_H */