diff --git a/configure.ac b/configure.ac index e430e8a7c38b1e633573f62ca97ffe6ac9ecd2fb..13e1ff8571638bd727366243fb3022b6a6f27625 100644 --- a/configure.ac +++ b/configure.ac @@ -25,6 +25,7 @@ AC_CHECK_HEADER([errno.h]) AC_CHECK_HEADER([limits.h]) AC_CHECK_HEADER([math.h]) AC_CHECK_HEADER([stdbool.h]) +AC_CHECK_HEADER([stdint.h]) AC_CHECK_HEADER([stdio.h]) AC_CHECK_HEADER([stdlib.h]) AC_CHECK_HEADER([string.h]) diff --git a/sefht.geany b/sefht.geany index a3b4c4c0a9787067d24c8167443deca4d7eed593..ece6a791b2dd21666dc0ea9f93e7a8fcb3ac9ab1 100644 --- a/sefht.geany +++ b/sefht.geany @@ -28,37 +28,39 @@ long_line_behaviour=1 long_line_column=72 [files] -current_page=26 +current_page=22 FILE_NAME_0=923;Sh;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fconfigure.ac;0;8 FILE_NAME_1=73;Make;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2FMakefile.am;0;8 FILE_NAME_2=1082;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Fmain.c;0;8 -FILE_NAME_3=298;Make;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2FMakefile.am;0;8 +FILE_NAME_3=640;Make;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2FMakefile.am;0;8 FILE_NAME_4=1381;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fcms.c;0;8 FILE_NAME_5=1359;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fcms.h;0;8 -FILE_NAME_6=1438;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fdata.c;0;8 +FILE_NAME_6=4939;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fdata.c;0;8 FILE_NAME_7=1376;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fdata.h;0;8 FILE_NAME_8=1171;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Ffragment.c;0;8 FILE_NAME_9=2843;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Ffragment.h;0;8 -FILE_NAME_10=4671;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fnode_fragment.c;0;8 +FILE_NAME_10=1609;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fnode_fragment.c;0;8 FILE_NAME_11=3013;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fnode_fragment.h;0;8 FILE_NAME_12=3572;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Ftext.c;0;8 FILE_NAME_13=1833;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Ftext.h;0;8 -FILE_NAME_14=3449;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator.c;0;8 -FILE_NAME_15=1058;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator.h;0;8 -FILE_NAME_16=4232;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fstatus.h;0;8 -FILE_NAME_17=1017;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Flog.h;0;4 -FILE_NAME_18=1077;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fmacro.h;0;8 -FILE_NAME_19=937;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fsefht.h;0;8 -FILE_NAME_20=98;Make;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2FMakefile.am;0;8 -FILE_NAME_21=872;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_cms.c;0;8 -FILE_NAME_22=3552;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_data.c;0;8 -FILE_NAME_23=10063;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_node_fragment.c;0;8 -FILE_NAME_24=5736;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_text.c;0;8 -FILE_NAME_25=6532;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_validator.c;0;8 -FILE_NAME_26=119;None;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftodo.txt;0;8 +FILE_NAME_14=1520;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator.c;0;8 +FILE_NAME_15=1503;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator.h;0;8 +FILE_NAME_16=10187;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_tag.c;0;8 +FILE_NAME_17=1828;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_tag.h;0;8 +FILE_NAME_18=4232;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fstatus.h;0;8 +FILE_NAME_19=1017;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Flog.h;0;4 +FILE_NAME_20=1077;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fmacro.h;0;8 +FILE_NAME_21=937;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fsefht.h;0;8 +FILE_NAME_22=1408;Make;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2FMakefile.am;0;8 +FILE_NAME_23=872;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_cms.c;0;8 +FILE_NAME_24=3552;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_data.c;0;8 +FILE_NAME_25=2373;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_node_fragment.c;0;8 +FILE_NAME_26=5736;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_text.c;0;8 +FILE_NAME_27=4687;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_validator.c;0;8 +FILE_NAME_28=165;None;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftodo.txt;0;8 [VTE] -last_dir=/home/jonathan/Dokumente/projekte/prgm/internet/web/SeFHT/tests +last_dir=/home/jonathan/Documents/projects/prgm/internet/web/SeFHT/tests [prjorg] source_patterns=*.c;*.C;*.cpp;*.cxx;*.c++;*.cc;*.m; diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 721a0093b70ab28724cf25f6cc7deb8264271cd8..7dc0a0f832f106354f5f663c0fe0ce7933cf0f9c 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -16,6 +16,9 @@ libsefht_la_SOURCES += sefht/node_fragment.c sefht/node_fragment.h libsefht_la_SOURCES += sefht/text.c sefht/text.h libsefht_la_SOURCES += sefht/validator.c sefht/validator.h +EXTRA_DIST = +EXTRA_DIST += sefht/validator_tag.c + nobase_include_HEADERS = nobase_include_HEADERS += sefht/sefht.h nobase_include_HEADERS += sefht/macro.h @@ -27,6 +30,7 @@ nobase_include_HEADERS += sefht/fragment.h nobase_include_HEADERS += sefht/node_fragment.h nobase_include_HEADERS += sefht/text.h nobase_include_HEADERS += sefht/validator.h +nobase_include_HEADERS += sefht/validator_tag.h libsefht_la_CPPFLAGS = -DLIB_SEFHT_COMPILATION libsefht_la_LDFLAGS = -version_info 0:0:0 diff --git a/src/lib/sefht/node_fragment.c b/src/lib/sefht/node_fragment.c index 07ce9e96a0031f398309b9de881b2e99b44fb814..2c274fbcf878c7232de10ff0707cfe346f70bd22 100644 --- a/src/lib/sefht/node_fragment.c +++ b/src/lib/sefht/node_fragment.c @@ -61,14 +61,6 @@ SH_NodeFragment_new (const char * tag, struct SH_Data * data, { struct SH_NodeFragment * fragment; - if (!SH_Validator_check_tag (data->validator, tag)) - { - set_status_ (status, E_VALUE, 2, strlen (tag), - "Tag %s is'nt valid.\n", tag); - - return NULL; - } - fragment = malloc (sizeof (struct SH_NodeFragment)); if (fragment == NULL) { diff --git a/src/lib/sefht/validator.c b/src/lib/sefht/validator.c index 55584063cfb5dcb1d4c25e7202bf6d9217cf669d..4f871f65b26a3da9f46db832f20ce97fe0f09007 100644 --- a/src/lib/sefht/validator.c +++ b/src/lib/sefht/validator.c @@ -22,22 +22,20 @@ */ -#include <errno.h> -#include <stdbool.h> #include <stdlib.h> -#include <string.h> -#include "macro.h" #include "log.h" #include "status.h" #include "validator.h" -static inline void init_tags (struct SH_Validator * validator); +#include "validator_tag.c" + +/*@null@*/ struct SH_Validator * -SH_Validator_new (struct SH_Status * status) +SH_Validator_new (/*@null@*/ /*@out@*/ struct SH_Status * status) { struct SH_Validator * validator; validator = malloc (sizeof (struct SH_Validator)); @@ -51,130 +49,58 @@ SH_Validator_new (struct SH_Status * status) return NULL; } - init_tags (validator); + if (!init_tags (validator, status)) + { +/* dangerous call to silence splint, should never be executed. */ +#ifdef S_SPLINT_S + free (validator->tags); +#endif + free (validator); + return NULL; + } set_success (status); return validator; } -static inline void free_tags (struct SH_Validator * validator); - -void -SH_Validator_free (struct SH_Validator * validator) -{ - free_tags (validator); - free (validator); - - return; -} - -static inline void -init_tags (struct SH_Validator * validator) -{ - validator->tag_n = 0; - validator->tags = malloc (0); - validator->last_tag = TAG_ERR; - - return; -} - -static inline void -free_tags (struct SH_Validator * validator) +/*@null@*/ +struct SH_Validator * +SH_Validator_copy (const struct SH_Validator * validator, + /*@null@*/ /*@out@*/ struct SH_Status * status) { - unsigned int index; + struct SH_Validator * copy; + copy = malloc (sizeof (struct SH_Validator)); - for (index = 0; index < validator->tag_n; index++) + if (copy == NULL) { - free (validator->tags[index].name); - } - - free (validator->tags); - return; -} - + set_status (status, E_ALLOC, 4, + "Memory allocation for " + "SH_Validator failed.\n"); -static inline tag_t -SH_Validator_get_tag (struct SH_Validator * validator, const char * tag) -{ - unsigned int index; + return NULL; + } - for (index = 0; index < validator->tag_n; index++) + if (!copy_tags (copy, validator, status)) { - if (strcmp (validator->tags[index].name, tag) == 0) - { - return validator->tags[index].id; - } +/* dangerous call to silence splint, should never be executed. */ +#ifdef S_SPLINT_S + free (copy->tags); +#endif + free (copy); + return NULL; } - return TAG_ERR; -} + set_success (status); -bool -SH_Validator_check_tag (struct SH_Validator * validator, - const char * tag) -{ - if (SH_Validator_get_tag (validator, tag) == TAG_ERR) - { - return FALSE; - } - else - { - return TRUE; - } + return copy; } -tag_t -SH_Validator_register_tag (struct SH_Validator * validator, - const char * tag, - struct SH_Status * status) +void +SH_Validator_free (/*@only@*/ struct SH_Validator * validator) { - tag_t tag_id; - - /* tag already registered */ - tag_id = SH_Validator_get_tag (validator, tag); - if (tag_id != TAG_ERR) - { - return tag_id; - } - - /* abort on overflow */ - if (validator->tag_n == UINT_MAX - || validator->last_tag == TAG_MAX) - { - set_status (status, E_DOMAIN, 3, - "Maximum number of tags reached.\n"); - - return TAG_ERR; - } - - validator->tags = realloc (validator->tags, - (validator->tag_n + 1) * sizeof (struct SH_Tag)); - - if (validator->tags == NULL) - { - set_status (status, E_ALLOC, 5, - "Memory allocation for tag failed.\n"); - - return TAG_ERR; - } - - NEXT_TAG(validator->last_tag); - - validator->tags[validator->tag_n].id = validator->last_tag; - validator->tags[validator->tag_n].name = strdup (tag); - - if (validator->tags[validator->tag_n].name == NULL) - { - set_status (status, E_ALLOC, 4, - "Memory allocation for tag failed.\n"); - - return TAG_ERR; - } - - validator->tag_n++; - - set_success (status); + free_tags (validator); + free (validator); - return validator->last_tag; + return; } diff --git a/src/lib/sefht/validator.h b/src/lib/sefht/validator.h index a078adaa11f81e2d59e2017df41101781e0b0be4..6afdbd93fe601993ff9a731d27bc1b2d5856d681 100644 --- a/src/lib/sefht/validator.h +++ b/src/lib/sefht/validator.h @@ -29,53 +29,36 @@ #error "Only <sefht/sefht.h> can be included directly." #endif -#include <limits.h> -#include <stdbool.h> - #include "status.h" -typedef unsigned int tag_t; -#define TAG_ERR 0 -#define TAG_MIN 1 -#define TAG_MAX UINT_MAX - -#ifdef LIB_SEFHT_COMPILATION +typedef struct SH_Validator SH_Validator; -#define NEXT_TAG(tag) tag++ +#define __VALIDATOR_H_INSIDE__ +#include "validator_tag.h" +#undef __VALIDATOR_H_INSIDE__ -struct SH_Tag -{ - tag_t id; - char * name; -}; +#ifdef LIB_SEFHT_COMPILATION struct SH_Validator { - unsigned int tag_n; - struct SH_Tag * tags; - tag_t last_tag; + TAG_DATA }; #endif /* LIB_SEFHT_COMPILATION */ -typedef struct SH_Validator SH_Validator; - +/*@null@*/ SH_Validator * -SH_Validator_new (struct SH_Status * status); +SH_Validator_new (/*@null@*/ /*@out@*/ struct SH_Status * status); -void -SH_Validator_free (SH_Validator * validator); - -tag_t -SH_Validator_register_tag (SH_Validator * validator, - const char * tag, - struct SH_Status * status); +/*@null@*/ +struct SH_Validator * +SH_Validator_copy (const SH_Validator * validator, + /*@null@*/ /*@out@*/ struct SH_Status * status); +void +SH_Validator_free (/*@only@*/ SH_Validator * validator); -bool -SH_Validator_check_tag (SH_Validator * validator, - const char * tag); #endif /* __VALIDATOR_H__ */ diff --git a/src/lib/sefht/validator_tag.c b/src/lib/sefht/validator_tag.c new file mode 100644 index 0000000000000000000000000000000000000000..1bdf6989fd15f9cdd883a6e51298e695c65182b5 --- /dev/null +++ b/src/lib/sefht/validator_tag.c @@ -0,0 +1,528 @@ +/* + * validator_tag.c + * + * Copyright 2022 Jonathan Schöbel <jonathan@Ubermos-2019> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * + */ + + +#include <stdbool.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "macro.h" +#include "log.h" +#include "status.h" + +#include "validator_tag.h" + + +static inline +bool +init_tags (/*@out@*/ struct SH_Validator * validator, + /*@null@*/ /*@out@*/ struct SH_Status * status); + +static inline +bool +copy_tags (/*@out@*/ struct SH_Validator * copy, + const struct SH_Validator * validator, + /*@null@*/ /*@out@*/ struct SH_Status * status); + +static inline +void +free_tags (/*@special@*/ struct SH_Validator * validator) + /*@releases validator->tags@*/; + +static inline +size_t +get_tag_number (const struct SH_Validator * validator); + +static inline +Tag +add_tag (struct SH_Validator * validator, + const char * tag, + /*@null@*/ /*@out@*/ struct SH_Status * status); + +/*@unused@*/ +static inline +bool +is_tag_id (struct SH_Validator * validator, Tag id); + +static inline +bool +is_tag_name (struct SH_Validator * validator, const char * name); + +/*@unused@*/ +static inline +/*@null@*/ +char * +get_tag_name_by_id (struct SH_Validator * validator, Tag id, + /*@null@*/ /*@out@*/ struct SH_Status * status); + +static inline +Tag +get_tag_id_by_name (struct SH_Validator * validator, + const char * name); + + + +#define EXECUTE_ON_ALL_TAGS_IF(ITER, CONDITION, BLOCK) \ +do \ +{ \ + bool is_free; \ + size_t index; \ + size_t free_index; \ + \ + for (index = 1; index <= ITER##_n; index++) \ + { \ + /* if tag is not in the list of free blocks */ \ + is_free = FALSE; \ + for (free_index = ITER##s[0].next; \ + free_index != 0; \ + free_index = ITER##s[free_index].next) \ + { \ + if (index == free_index) \ + { \ + is_free = TRUE; \ + break; \ + } \ + } \ + \ + if (!is_free && CONDITION) BLOCK \ + } \ +} \ +while (0) + +#define EXECUTE_ON_ALL_TAGS(BASE, BLOCK) \ + EXECUTE_ON_ALL_TAGS_IF (BASE, TRUE, BLOCK) + + +static inline +bool +init_tags (/*@out@*/ struct SH_Validator * validator, + /*@null@*/ /*@out@*/ struct SH_Status * status) +{ + validator->tags = malloc (sizeof (struct tag_info)); + if (validator->tags == NULL) + { + set_status (status, E_ALLOC, 3, "malloc failed"); + return FALSE; + } + + validator->tags[0].next = 0; + validator->tag_n = 0; + validator->last_tag = TAG_ERR; + + return TRUE; +} + +static inline +bool +copy_tags (/*@out@*/ struct SH_Validator * copy, + const struct SH_Validator * validator, + /*@null@*/ /*@out@*/ struct SH_Status * status) +{ + bool is_free; + size_t index; + size_t free_index; + size_t copy_index; + size_t tag_n; + + tag_n = get_tag_number (validator); + + /* The size calculation is save, + * because validator is already allocated. */ + copy->tags = malloc ((tag_n + 1) * sizeof (struct tag_info)); + + if (copy->tags == NULL) + { + set_status (status, E_ALLOC, 5, "malloc failed"); + return FALSE; + } + + /* copy allocation info */ + copy->tags[0].next = 0; + copy->tag_n = tag_n; + copy->last_tag = validator->last_tag; + + + /* copy data */ + copy_index = 0; + for (index = 1; index <= validator->tag_n; index++) + { + /* if tag is not in the list of free blocks */ + is_free = FALSE; + for (free_index = validator->tags[0].next; + free_index != 0; + free_index = validator->tags[free_index].next) + { + if (index == free_index) + { + is_free = TRUE; + break; + } + } + + if (!is_free) + { + copy->tags[copy_index].data.id = + validator->tags[index].data.id; + + copy->tags[copy_index].data.name = strdup ( + validator->tags[index].data.name); + + if (copy->tags[copy_index].data.name == NULL) + { + size_t index; + + set_status (status, E_ALLOC, 5, + "strdup failed"); + + for (index = 0; index < copy_index; + index++) + { + free (copy->tags[index] + .data.name); + } + + free (copy->tags); + + return FALSE; + } + + copy_index++; + } + } + + return TRUE; +} + +static inline void +free_tags (/*@special@*/ struct SH_Validator * validator) + /*@releases validator->tags@*/ +{ + EXECUTE_ON_ALL_TAGS ( + validator->tag, + { + free (validator->tags[index].data.name); + }); + + free (validator->tags); + return; +} + +static inline +size_t +get_tag_number (const struct SH_Validator * validator) +{ + size_t tag_n; + + tag_n = 0; + + EXECUTE_ON_ALL_TAGS ( + validator->tag, + { + /* This addition is always save, + * because tag_n is always smaller than + * validator->tag_n and it is also of size_t. */ + tag_n++; + }); + + return tag_n; +} + +static inline +Tag +add_tag (struct SH_Validator * validator, + const char * tag, + /*@null@*/ /*@out@*/ struct SH_Status * status) +{ + Tag tag_id; + size_t index; + bool is_new; + + /* abort on overflow: + * - no unused Tag or + * - no unused index */ + if ((validator->last_tag == TAG_MAX) + || ((validator->tags[0].next == 0) + && ((validator->tag_n >= SIZE_MAX - 1) + || ((validator->tag_n + 2) + > (SIZE_MAX / sizeof (struct tag_info)))))) + { + set_status (status, E_DOMAIN, 2, + "maximum number of tags reached"); + return TAG_ERR; + } + + if (validator->tags[0].next == 0) + /* allocate new space */ + { + struct tag_info * new_tags; + + /* The addition and the multiplication is save, + * because we have tested for this + * in the first condition. */ + new_tags = realloc (validator->tags, + sizeof (struct tag_info) + * (validator->tag_n + 2)); + + if (new_tags == NULL) + { + set_status (status, E_ALLOC, 6, + "realloc failed"); + +/* bad code to silence splint, should never be executed. */ +#ifdef S_SPLINT_S + validator->tags = (void *) 0x12345; +#endif + return TAG_ERR; + } + + validator->tags = new_tags; + index = validator->tag_n + 1; + is_new = TRUE; + } + /* reuse old space */ + else + { + index = validator->tags[0].next; + validator->tags[0].next = validator->tags[index].next; + is_new = FALSE; + } + + tag_id = NEXT_TAG (validator->last_tag); + validator->tags[index].data.id = tag_id; + validator->tags[index].data.name = strdup (tag); + + if (validator->tags[index].data.name == NULL) + { + set_status (status, E_ALLOC, 4, "strdup failed"); + + /* restore free space list */ + if (!is_new) + { + validator->tags[index].next = \ + validator->tags[0].next; + validator->tags[0].next = index; + } + + return TAG_ERR; + } + + /* commit changes */ + if (is_new) + { + validator->tag_n++; + } + + validator->last_tag = tag_id; + + set_success (status); + + return tag_id; +} + +/*@unused@*/ +static inline +bool +is_tag_id (struct SH_Validator * validator, Tag id) +{ + EXECUTE_ON_ALL_TAGS_IF ( + validator->tag, + (validator->tags[index].data.id == id), + { + return TRUE; + }); + + return FALSE; +} + +static inline +bool +is_tag_name (struct SH_Validator * validator, const char * name) +{ + EXECUTE_ON_ALL_TAGS_IF ( + validator->tag, + (strcmp (validator->tags[index].data.name, name) == 0), + { + return TRUE; + }); + + return FALSE; +} + +/*@unused@*/ +static inline +/*@null@*/ +char * +get_tag_name_by_id (struct SH_Validator * validator, Tag id, + /*@null@*/ /*@out@*/ struct SH_Status * status) +{ + char * name; + + EXECUTE_ON_ALL_TAGS_IF ( + validator->tag, + (validator->tags[index].data.id == id), + { + name = strdup (validator->tags[index].data.name); + if (name == NULL) + { + set_status (status, E_ALLOC, 3, + "strdup failed"); + return NULL; + } + + return name; + }); + + return NULL; +} + +static inline +Tag +get_tag_id_by_name (struct SH_Validator * validator, + const char * name) +{ + EXECUTE_ON_ALL_TAGS_IF ( + validator->tag, + (strcmp (validator->tags[index].data.name, name) == 0), + { + return validator->tags[index].data.id; + }); + + return TAG_ERR; +} + +static inline +bool +remove_tag (struct SH_Validator * validator, Tag id, + /*@null@*/ /*@out@*/ struct SH_Status * status) +{ + #define tags validator->tags + #define tag_n validator->tag_n + EXECUTE_ON_ALL_TAGS_IF ( + tag, + (tags[index].data.id == id), + { + free (tags[index].data.name); + + if (index == tag_n) + { + struct tag_info * new_tags; + + do + { + /* find next last free blocks + * in the list of free blocks */ + is_free = FALSE; + for (free_index = tags[0].next; + free_index != 0; + free_index = tags[free_index].next) + { + + if (tags[free_index].next == (index - 1)) + { + is_free = TRUE; + index--; + + tags[free_index].next = + tags[tags[free_index].next].next; + break; + } + } + } + while (is_free); + + if (index + > (SIZE_MAX / sizeof (struct tag_info))) + { + set_status (status, E_DOMAIN, 2, + "overflow while calling realloc"); + } + + new_tags = realloc (tags, + sizeof (struct tag_info) + * index); + + if (new_tags == NULL) + { + set_status (status, E_ALLOC, 4, + "realloc failed"); + +/* bad code to silence splint, should never be executed. */ +#ifdef S_SPLINT_S + tags = (void *) 0x12345; +#endif + return FALSE; + } + + tags = new_tags; + } + else + { + tags[index].next = tags[0].next; + tags[0].next = index; + } + + set_success (status); + return TRUE; + }); + #undef tags + #undef tag_n + + set_status (status, E_VALUE, 68, "unknown Tag id"); + return FALSE; +} + + +bool +SH_Validator_check_tag (struct SH_Validator * validator, + const char * tag) +{ + return is_tag_name (validator, tag); +} + +Tag +SH_Validator_register_tag (struct SH_Validator * validator, + const char * tag, + /*@null@*/ /*@out@*/ + struct SH_Status * status) +{ + Tag tag_id; + + /* tag already registered */ + tag_id = get_tag_id_by_name (validator, tag); + if (tag_id != TAG_ERR) + { + return tag_id; + } + + return add_tag (validator, tag, status); +} + +bool +SH_Validator_deregister_tag (struct SH_Validator * validator, + Tag id, + /*@null@*/ /*@out@*/ + struct SH_Status * status) +{ + return remove_tag (validator, id, status); +} diff --git a/src/lib/sefht/validator_tag.h b/src/lib/sefht/validator_tag.h new file mode 100644 index 0000000000000000000000000000000000000000..c5ec3d99a9a94eb9f0547a09591abb4341dbf64e --- /dev/null +++ b/src/lib/sefht/validator_tag.h @@ -0,0 +1,86 @@ +/* + * validator_tag.h + * + * Copyright 2022 Jonathan Schöbel <jonathan@Ubermos-2019> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * + */ + + +#ifndef __VALIDATOR_TAG_H__ +#define __VALIDATOR_TAG_H__ + +#if !defined (__VALIDATOR_H__) +#error "Please include only <sefht/validator.h>." +#endif + +#include <stdbool.h> +#include <stdint.h> + +#include "status.h" + + +typedef unsigned int Tag; +#define TAG_ERR (Tag) 0 +#define TAG_MIN (Tag) 1 +#define TAG_MAX (Tag) SIZE_MAX + +#ifdef LIB_SEFHT_COMPILATION + +#define NEXT_TAG(tag) (tag + 1) + +struct tag_info +{ + union + { + struct + { + Tag id; + /*@only@*/ char * name; + } data; + size_t next; + }; +}; + +#define TAG_DATA \ + /*@only@*/ struct tag_info * tags; \ + size_t tag_n; \ + Tag last_tag; \ + + +#endif /* LIB_SEFHT_COMPILATION */ + + + +Tag +SH_Validator_register_tag (SH_Validator * validator, + const char * tag, + /*@null@*/ /*@out@*/ + struct SH_Status * status); + +bool +SH_Validator_deregister_tag (SH_Validator * validator, + Tag id, + /*@null@*/ /*@out@*/ + struct SH_Status * status); + +bool +SH_Validator_check_tag (SH_Validator * validator, + const char * tag); + +#endif /* __VALIDATOR_TAG_H__ */ diff --git a/tests/Makefile.am b/tests/Makefile.am index 1fa43a0952b81e7946c9e84871e55917a0874d9d..ad3158300aeb2ae5c66eb21677424b941fb20db2 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -7,7 +7,6 @@ TESTS += sefht_cms_test TESTS += sefht_data_test TESTS += sefht_node_fragment_test TESTS += sefht_text_test -TESTS += sefht_validator_test check_PROGRAMS = $(TESTS) @@ -44,7 +43,3 @@ sefht_node_fragment_test_LDADD += $(LDADD) sefht_text_test_SOURCES = test_text.c sefht_text_test_LDADD = sefht_text_test_LDADD += $(LDADD) - -sefht_validator_test_SOURCES = test_validator.c -sefht_validator_test_LDADD = -sefht_validator_test_LDADD += $(LDADD) diff --git a/tests/test_node_fragment.c b/tests/test_node_fragment.c index 203d5bb32c3372dc4068320f029ba32e52449c25..be2e1a3ea010eccd065aca56b7a0d109af2e21b4 100644 --- a/tests/test_node_fragment.c +++ b/tests/test_node_fragment.c @@ -37,10 +37,8 @@ START_TEST(test_node_fragment) struct SH_Fragment * fragment; struct SH_Data * data; const char * tag = "tag"; - const char * no_tag = "no_tag"; data = SH_Data_new (NULL); - SH_Validator_register_tag (data->validator, tag, NULL); /* valid tag - no error */ fragment = SH_NodeFragment_new (tag, data, NULL); @@ -50,10 +48,6 @@ START_TEST(test_node_fragment) SH_Fragment_free (fragment); - /* invalid tag - no error */ - fragment = SH_NodeFragment_new (no_tag, data, NULL); - ck_assert_int_eq ((long int) fragment, (long int) NULL); - /* valid tag - error */ status.status = UNDEFINED; fragment = SH_NodeFragment_new (tag, data, &status); @@ -64,12 +58,6 @@ START_TEST(test_node_fragment) SH_Fragment_free (fragment); - /* invalid tag - error */ - status.status = UNDEFINED; - fragment = SH_NodeFragment_new (no_tag, data, &status); - ck_assert_int_eq ((long int) fragment, (long int) NULL); - ck_assert_int_eq (status.status, E_VALUE); - SH_Data_free (data); } END_TEST @@ -231,8 +219,6 @@ START_TEST(test_node_fragment_tag) const char * tag2 = "body"; data = SH_Data_new (NULL); - SH_Validator_register_tag (data->validator, tag1, NULL); - SH_Validator_register_tag (data->validator, tag2, NULL); /* no error */ fragment = SH_NodeFragment_new (tag1, data, NULL); @@ -449,7 +435,6 @@ START_TEST(test_node_fragment_html) size_t length; data = SH_Data_new (NULL); - SH_Validator_register_tag (data->validator, "html", NULL); /* no error */ fragment1 = SH_NodeFragment_new ("html", data, NULL); diff --git a/tests/test_validator.c b/tests/test_validator.c index 12fb4b0ff0ae70afa457ebdd10cc7b59a81b41d5..a17a27d754e096481fe0494303e5b14e90755c4d 100644 --- a/tests/test_validator.c +++ b/tests/test_validator.c @@ -31,14 +31,14 @@ /* test static method */ #define static -/* lower UINT_MAX as we try to reach it */ +/* lower SIZE_MAX as we try to reach it */ #include <limits.h> -#define UINT_MAX 20 +#define SIZE_MAX 10 * sizeof (struct tag_info) #include "macro.h" #include "status.h" -/* C file is needed, because we wan't to override UINT_MAX and static */ +/* C file is needed, because we wan't to override SIZE_MAX and static */ #include "validator.c" @@ -72,8 +72,8 @@ START_TEST(test_validator_tag) const char * tag5 = "main"; const char * tag6 = "article"; char * tagN; - tag_t tag; - tag_t tag_return; + Tag tag; + Tag tag_return; bool check; validator = SH_Validator_new (NULL); @@ -85,10 +85,10 @@ START_TEST(test_validator_tag) ck_assert_int_eq (validator->tag_n, 1); ck_assert_int_eq (validator->last_tag, tag); - ck_assert_int_eq (validator->tags[0].id, tag); - ck_assert_str_eq (validator->tags[0].name, tag1); + ck_assert_int_eq (validator->tags[1].data.id, tag); + ck_assert_str_eq (validator->tags[1].data.name, tag1); - tag_return = SH_Validator_get_tag (validator, tag1); + tag_return = get_tag_id_by_name (validator, tag1); ck_assert_int_eq (tag_return, tag); /* retry without error */ @@ -98,8 +98,8 @@ START_TEST(test_validator_tag) ck_assert_int_eq (validator->tag_n, 1); ck_assert_int_eq (validator->last_tag, tag); - ck_assert_int_eq (validator->tags[0].id, tag); - ck_assert_str_eq (validator->tags[0].name, tag1); + ck_assert_int_eq (validator->tags[1].data.id, tag); + ck_assert_str_eq (validator->tags[1].data.name, tag1); /* fail without error */ /* make method fail by filling with garbage until @@ -110,15 +110,15 @@ START_TEST(test_validator_tag) /* +3 "tag" */ /* +1 NULL */ /* = +5 */ - tagN = calloc (((int) floor (log10 ((double) UINT_MAX))) + 5, + tagN = calloc (((int) floor (log10 ((double) SIZE_MAX))) + 5, sizeof (char)); /* fill with garbage */ - while (validator->tag_n != UINT_MAX) + sprintf (tagN, "tag%lu", validator->tag_n); + while (SH_Validator_register_tag (validator, tagN, NULL) != TAG_ERR) { - printf ("tag%d\n", validator->tag_n); - sprintf (tagN, "tag%d", validator->tag_n); - SH_Validator_register_tag (validator, tagN, NULL); + printf ("tag%lu\n", validator->tag_n); + sprintf (tagN, "tag%lu", validator->tag_n); } free (tagN); @@ -126,10 +126,9 @@ START_TEST(test_validator_tag) tag = SH_Validator_register_tag (validator, tag2, NULL); ck_assert_int_eq (tag, TAG_ERR); - ck_assert_int_eq (validator->tag_n, UINT_MAX); - ck_assert_int_eq (validator->last_tag, (tag_t) UINT_MAX); + ck_assert_int_eq (validator->tag_n, 9); - tag_return = SH_Validator_get_tag (validator, tag2); + tag_return = get_tag_id_by_name (validator, tag2); ck_assert_int_eq (tag_return, TAG_ERR); /* fail2 without error */ @@ -142,11 +141,11 @@ START_TEST(test_validator_tag) ck_assert_int_eq (validator->tag_n, 1); ck_assert_int_eq (validator->last_tag, TAG_MAX); - tag_return = SH_Validator_get_tag (validator, tag3); + tag_return = get_tag_id_by_name (validator, tag3); ck_assert_int_eq (tag_return, TAG_ERR); /* also free garbage created for overflow test */ - validator->tag_n = UINT_MAX; + validator->tag_n = 9; /* check tag */ check = SH_Validator_check_tag (validator, tag1); @@ -172,10 +171,10 @@ START_TEST(test_validator_tag) ck_assert_int_eq (validator->tag_n, 1); ck_assert_int_eq (validator->last_tag, tag); - ck_assert_int_eq (validator->tags[0].id, tag); - ck_assert_str_eq (validator->tags[0].name, tag4); + ck_assert_int_eq (validator->tags[1].data.id, tag); + ck_assert_str_eq (validator->tags[1].data.name, tag4); - tag_return = SH_Validator_get_tag (validator, tag4); + tag_return = get_tag_id_by_name (validator, tag4); ck_assert_int_eq (tag_return, tag); /* fail with error */ @@ -187,15 +186,15 @@ START_TEST(test_validator_tag) /* +3 "tag" */ /* +1 NULL */ /* = +5 */ - tagN = calloc (((int) floor (log10 ((double) UINT_MAX))) + 5, + tagN = calloc (((int) floor (log10 ((double) SIZE_MAX))) + 5, sizeof (char)); /* fill with garbage */ - while (validator->tag_n != UINT_MAX) + sprintf (tagN, "tag%lu", validator->tag_n); + while (SH_Validator_register_tag (validator, tagN, NULL) != TAG_ERR) { - printf ("tag%d\n", validator->tag_n); - sprintf (tagN, "tag%d", validator->tag_n); - SH_Validator_register_tag (validator, tagN, NULL); + printf ("tag%lu\n", validator->tag_n); + sprintf (tagN, "tag%lu", validator->tag_n); } free (tagN); @@ -205,10 +204,9 @@ START_TEST(test_validator_tag) ck_assert_int_eq (tag, TAG_ERR); ck_assert_int_eq (status.status, E_DOMAIN); - ck_assert_int_eq (validator->tag_n, UINT_MAX); - ck_assert_int_eq (validator->last_tag, (tag_t) UINT_MAX); + ck_assert_int_eq (validator->tag_n, 9); - tag_return = SH_Validator_get_tag (validator, tag5); + tag_return = get_tag_id_by_name (validator, tag5); ck_assert_int_eq (tag_return, TAG_ERR); /* fail2 with error */ @@ -223,7 +221,7 @@ START_TEST(test_validator_tag) ck_assert_int_eq (validator->tag_n, 1); ck_assert_int_eq (validator->last_tag, TAG_MAX); - tag_return = SH_Validator_get_tag (validator, tag6); + tag_return = get_tag_id_by_name (validator, tag6); ck_assert_int_eq (tag_return, TAG_ERR); @@ -238,7 +236,7 @@ START_TEST(test_validator_tag) ck_assert_int_eq (check, FALSE); /* also free garbage created for overflow test */ - validator->tag_n = UINT_MAX; + validator->tag_n = 9; SH_Validator_free (validator); } diff --git a/todo.txt b/todo.txt index 688c4f4cc3a447b91b89abcdddcd69fa7da5bb46..e99c86c32a2cfc571af67384635d3dc41df0cd13 100644 --- a/todo.txt +++ b/todo.txt @@ -6,3 +6,6 @@ dynamic Validator initialization remove -Wno-nonnull from AM_CFLAGS fix warnings for tests + +rewrite validator test +restructure validator