diff --git a/configure.ac b/configure.ac index a9bd36d47f78316399d1bd155314fcd8fac03b01..13e1ff8571638bd727366243fb3022b6a6f27625 100644 --- a/configure.ac +++ b/configure.ac @@ -12,16 +12,20 @@ AM_INIT_AUTOMAKE([foreign -Wall -Werror subdir-objects]) # Checks for programs. AC_PROG_CC +AM_PROG_AR +AC_PROG_LIBTOOL PKG_CHECK_MODULES([CHECK], [check >= 0.9.4]) # Checks for libraries. +LT_INIT() # Checks for header files. 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]) @@ -33,6 +37,7 @@ AC_CHECK_HEADER([string.h]) # Makefiles AC_CONFIG_FILES([Makefile src/Makefile + src/lib/Makefile tests/Makefile]) AC_OUTPUT diff --git a/sefht.geany b/sefht.geany index c890b137309778bf4945c7251121c6832203046e..4f9cbf8e4e8412fdce22ae688ed0cfa175a51571 100644 --- a/sefht.geany +++ b/sefht.geany @@ -28,36 +28,41 @@ long_line_behaviour=1 long_line_column=72 [files] -current_page=22 -FILE_NAME_0=607;Sh;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fconfigure.ac;0;8 -FILE_NAME_1=384;Make;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2FMakefile.am;0;8 -FILE_NAME_2=2517;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Fmain.c;0;8 -FILE_NAME_3=1280;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Fcms.c;0;8 -FILE_NAME_4=1148;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Fcms.h;0;8 -FILE_NAME_5=4036;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Fdata.c;0;8 -FILE_NAME_6=1099;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Fdata.h;0;8 -FILE_NAME_7=1500;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Ffragment.c;0;8 -FILE_NAME_8=1058;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Ffragment.h;0;8 -FILE_NAME_9=1420;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Fnode_fragment.c;0;8 -FILE_NAME_10=1574;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Fnode_fragment.h;0;8 -FILE_NAME_11=1528;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Ftext.c;0;8 -FILE_NAME_12=1397;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Ftext.h;0;8 -FILE_NAME_13=1351;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Fvalidator.c;0;8 -FILE_NAME_14=1130;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Fvalidator.h;0;8 -FILE_NAME_15=994;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Ferror.h;0;4 -FILE_NAME_16=881;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flog.h;0;4 -FILE_NAME_17=938;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Fmacro.h;0;8 -FILE_NAME_18=847;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Fsefht.h;0;8 -FILE_NAME_19=1089;Make;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2FMakefile.am;0;8 -FILE_NAME_20=1113;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_cms.c;0;8 -FILE_NAME_21=3059;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_data.c;0;8 -FILE_NAME_22=8535;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_node_fragment.c;0;8 -FILE_NAME_23=5331;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_text.c;0;8 -FILE_NAME_24=6057;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_validator.c;0;8 -FILE_NAME_25=55;None;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftodo.txt;0;8 +current_page=21 +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=1143;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Fmain.c;0;8 +FILE_NAME_3=1260;Make;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2FMakefile.am;0;8 +FILE_NAME_4=1593;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=901;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=2921;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=904;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=1185;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=916;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=1975;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Ffragment_data.c;0;8 +FILE_NAME_11=2173;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Ffragment_class.c;0;8 +FILE_NAME_12=8225;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_13=931;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_14=25820;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Ftext.c;0;8 +FILE_NAME_15=904;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Ftext.h;0;8 +FILE_NAME_16=1779;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator.c;0;8 +FILE_NAME_17=919;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator.h;0;8 +FILE_NAME_18=14237;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_19=859;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_20=4608;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fstatus.h;0;8 +FILE_NAME_21=901;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Flog.h;0;4 +FILE_NAME_22=907;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fmacro.h;0;8 +FILE_NAME_23=1078;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fsefht.h;0;8 +FILE_NAME_24=290;Make;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2FMakefile.am;0;8 +FILE_NAME_25=1085;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_cms.c;0;8 +FILE_NAME_26=3283;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_data.c;0;8 +FILE_NAME_27=13617;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_node_fragment.c;0;8 +FILE_NAME_28=11068;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_text.c;0;8 +FILE_NAME_29=5744;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_validator.c;0;8 +FILE_NAME_30=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/Makefile.am b/src/Makefile.am index f720509f6f670fa580e327d27fa41fec0f7468ef..211dd58bd9a275df055225ff186f97962d4a016e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,20 +1,13 @@ ## Process this file with automake to produce Makefile.in +SUBDIRS = lib + AM_CFLAGS = -Wall -Wextra -bin_PROGRAMS = sefht.fcgi +bin_PROGRAMS = sefht_demo -sefht_fcgi_SOURCES = -sefht_fcgi_SOURCES += main.c -sefht_fcgi_SOURCES += macro.h -sefht_fcgi_SOURCES += sefht.h -sefht_fcgi_SOURCES += error.h -sefht_fcgi_SOURCES += log.h -sefht_fcgi_SOURCES += cms.c cms.h -sefht_fcgi_SOURCES += data.c data.h -sefht_fcgi_SOURCES += fragment.c fragment.h -sefht_fcgi_SOURCES += node_fragment.c node_fragment.h -sefht_fcgi_SOURCES += text.c text.h -sefht_fcgi_SOURCES += validator.c validator.h +sefht_demo_SOURCES = +sefht_demo_SOURCES += main.c -sefht_fcgi_LDADD = -lm +sefht_demo_CPPFLAGS = -I$(srcdir)/lib +sefht_demo_LDADD = -lm lib/libsefht.la diff --git a/src/data.c b/src/data.c deleted file mode 100644 index 2dd0bddcc2ab09c4e663d261ba257d4232075e9c..0000000000000000000000000000000000000000 --- a/src/data.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * data.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 <errno.h> -#include <stdbool.h> -#include <stdlib.h> -#include <string.h> - -#include "macro.h" -#include "error.h" -#include "log.h" - -#include "validator.h" - -#include "data.h" - - - -static inline bool init_validator (struct SH_Data * data, - struct SH_Error * error); -static inline void init_pages (struct SH_Data * data); - -struct SH_Data * -SH_Data_new (struct SH_Error * error) -{ - struct SH_Data * data; - data = malloc (sizeof (struct SH_Data)); - - if (data == NULL) - { - ERROR1 ("Memory allocation for SH_Data failed.\n"); - - if (error != NULL) - { - error->type = ALLOCATION_FAILED; - } - - return NULL; - } - - if (!init_validator (data, error)) - { - free (data); - - return NULL; - } - - init_pages (data); - - if (error != NULL) - { - error->type = SUCCESS; - } - - return data; -} - -static inline void free_validator (struct SH_Data * data); -static inline void free_pages (struct SH_Data * data); - -void -SH_Data_free (struct SH_Data * data, struct SH_Error * error) -{ - free_validator (data); - free_pages (data); - - free (data); - - if (error != NULL) - { - error->type = SUCCESS; - } - - return; -} - -static inline bool -init_validator (struct SH_Data * data, struct SH_Error * error) -{ - data->validator = SH_Validator_new (error); - - if (data->validator == NULL) - { - return FALSE; - } - - SH_Validator_register_tag (data->validator, "html", NULL); - SH_Validator_register_tag (data->validator, "head", NULL); - SH_Validator_register_tag (data->validator, "body", NULL); - SH_Validator_register_tag (data->validator, "meta", NULL); - SH_Validator_register_tag (data->validator, "link", NULL); - SH_Validator_register_tag (data->validator, "title", NULL); - SH_Validator_register_tag (data->validator, "main", NULL); - SH_Validator_register_tag (data->validator, "article", NULL); - SH_Validator_register_tag (data->validator, "section", NULL); - SH_Validator_register_tag (data->validator, "header", NULL); - SH_Validator_register_tag (data->validator, "footer", NULL); - SH_Validator_register_tag (data->validator, "h1", NULL); - SH_Validator_register_tag (data->validator, "h2", NULL); - SH_Validator_register_tag (data->validator, "h3", NULL); - SH_Validator_register_tag (data->validator, "h4", NULL); - SH_Validator_register_tag (data->validator, "h5", NULL); - SH_Validator_register_tag (data->validator, "h6", NULL); - SH_Validator_register_tag (data->validator, "p", NULL); - SH_Validator_register_tag (data->validator, "br", NULL); - SH_Validator_register_tag (data->validator, "i", NULL); - SH_Validator_register_tag (data->validator, "b", NULL); - SH_Validator_register_tag (data->validator, "strong", NULL); - SH_Validator_register_tag (data->validator, "em", NULL); - SH_Validator_register_tag (data->validator, "small", NULL); - - return TRUE; -} - -static inline void -free_validator (struct SH_Data * data) -{ - SH_Validator_free (data->validator, NULL); - return; -} - -static inline void -init_pages (struct SH_Data * data) -{ - data->page_n = 0; - data->pages = malloc (0); - data->last_page = PAGE_ERR; - - return; -} - -static inline void -free_pages (struct SH_Data * data) -{ - unsigned int index; - - for (index = 0; index < data->page_n; index++) - { - free (data->pages[index].name); - } - - free (data->pages); - return; -} - -page_t -SH_Data_register_page (struct SH_Data * data, const char * name, - struct SH_Error * error) -{ - /* abort on overflow */ - if (data->page_n == UINT_MAX || data->last_page == PAGE_MAX) - { - ERROR1 ("Maximum number of pages reached.\n"); - - if (error != NULL) - { - error->type = DOMAIN_ERROR; - } - - return PAGE_ERR; - } - - data->pages = realloc (data->pages, - (data->page_n + 1) * sizeof (struct SH_Page)); - - if (errno == ENOMEM) - { - ERROR1 ("Memory allocation for page data failed.\n"); - - if (error != NULL) - { - error->type = ALLOCATION_FAILED; - } - - return PAGE_ERR; - } - - NEXT_PAGE(data->last_page); - - data->pages[data->page_n].id = data->last_page; - data->pages[data->page_n].name = strdup (name); - - if (errno == ENOMEM) - { - ERROR1 ("Memory allocation for page data failed.\n"); - - if (error != NULL) - { - error->type = ALLOCATION_FAILED; - } - - return PAGE_ERR; - } - - data->page_n++; - - if (error != NULL) - { - error->type = SUCCESS; - } - - return data->last_page; -} diff --git a/src/error.h b/src/error.h deleted file mode 100644 index f8e2e5ec2b31d79116ea91949ffe1780f7c0f1a1..0000000000000000000000000000000000000000 --- a/src/error.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * error.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 _ERROR_H -#define _ERROR_H - - -enum SH_ErrorType -{ - UNDEFINED, - ALLOCATION_FAILED, - DOMAIN_ERROR, - VALUE_ERROR, - SUCCESS -}; - -struct SH_Error -{ - enum SH_ErrorType type; -}; - -#endif /* _ERROR_H */ diff --git a/src/fragment.c b/src/fragment.c deleted file mode 100644 index 8fecbd22100d57b256f97d96b0191a51f49f47a2..0000000000000000000000000000000000000000 --- a/src/fragment.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * fragment.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 "macro.h" -#include "error.h" -#include "log.h" - -#include "text.h" - -#include "fragment.h" - - -struct SH_Fragment * -SH_Fragment_copy (struct SH_Fragment * fragment, - struct SH_Error * error) -{ - return fragment->methods->copy (fragment, error); -} - -void -SH_Fragment_free (struct SH_Fragment * fragment, - struct SH_Error * error) -{ - return fragment->methods->free (fragment, error); -} - -struct SH_Text * -SH_Fragment_to_html (struct SH_Fragment * fragment, - enum HTML_MODE mode, - unsigned int indent_base, - unsigned int indent_step, - char * indent_char, - struct SH_Error * error) -{ - return fragment->methods->to_html (fragment, mode, - indent_base, - indent_step, - indent_char, - error); -} diff --git a/src/fragment.h b/src/fragment.h deleted file mode 100644 index c15ed290142b7fa58697f4d6689019c12b4a98a6..0000000000000000000000000000000000000000 --- a/src/fragment.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * fragment.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 _FRAGMENT_H -#define _FRAGMENT_H - -#include "data.h" -#include "text.h" - - -enum HTML_MODE -{ - INLINE, - WRAP -}; - -enum SH_FRAGMENT_TYPE -{ - NODE -}; - -struct fragment_methods; - -struct SH_Fragment; -struct SH_Fragment -{ - struct SH_Data * data; - - enum SH_FRAGMENT_TYPE type; - const struct fragment_methods * methods; -}; - -struct fragment_methods -{ - struct SH_Fragment * (*copy) (struct SH_Fragment *, - struct SH_Error *); - - void (*free) (struct SH_Fragment *, - struct SH_Error *); - - struct SH_Text * (*to_html) (struct SH_Fragment *, - enum HTML_MODE, - unsigned int, - unsigned int, - const char *, - struct SH_Error *); -}; - - -static inline -void -init_fragment (struct SH_Fragment * fragment, - struct SH_Data * data, - const enum SH_FRAGMENT_TYPE type, - const struct fragment_methods * const methods) -{ - fragment->data = data; - fragment->type = type; - fragment->methods = methods; - - return; -} - -static inline -void -free_fragment (struct SH_Fragment * fragment) -{ - return; -} - -static inline -void -copy_fragment (struct SH_Fragment * copy, - struct SH_Fragment * fragment) -{ - copy->data = fragment->data; - copy->type = fragment->type; - copy->methods = fragment->methods; - - return; -} - -static inline -enum SH_FRAGMENT_TYPE -get_type (struct SH_Fragment * fragment) -{ - return fragment->type; -} - - -struct SH_Fragment * -SH_Fragment_copy (struct SH_Fragment * fragment, - struct SH_Error * error); - -void -SH_Fragment_free (struct SH_Fragment * fragment, - struct SH_Error * error); - -struct SH_Text * -SH_Fragment_to_html (struct SH_Fragment * fragment, - enum HTML_MODE mode, - unsigned int indent_base, - unsigned int indent_step, - char * indent_char, - struct SH_Error * error); - -#endif /* _FRAGMENT_H */ diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..38a43da3fcc74c31cb77038637ad7ba63fcdee93 --- /dev/null +++ b/src/lib/Makefile.am @@ -0,0 +1,38 @@ +## Process this file with automake to produce Makefile.in + +AM_CFLAGS = -Wall -Wextra -Wno-nonnull + +lib_LTLIBRARIES = libsefht.la + +libsefht_la_SOURCES = +libsefht_la_SOURCES += sefht/sefht.h +libsefht_la_SOURCES += sefht/macro.h +libsefht_la_SOURCES += sefht/log.h +libsefht_la_SOURCES += sefht/status.h +libsefht_la_SOURCES += sefht/cms.c sefht/cms.h +libsefht_la_SOURCES += sefht/data.c sefht/data.h +libsefht_la_SOURCES += sefht/fragment.c sefht/fragment.h +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/fragment_class.c +EXTRA_DIST += sefht/fragment_data.c +EXTRA_DIST += sefht/validator_tag.c + +nobase_include_HEADERS = +nobase_include_HEADERS += sefht/sefht.h +nobase_include_HEADERS += sefht/macro.h +nobase_include_HEADERS += sefht/log.h +nobase_include_HEADERS += sefht/status.h +nobase_include_HEADERS += sefht/cms.h +nobase_include_HEADERS += sefht/data.h +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 = -DSEFHT_COMPILATION +libsefht_la_LDFLAGS = -version_info 0:0:0 diff --git a/src/cms.c b/src/lib/sefht/cms.c similarity index 62% rename from src/cms.c rename to src/lib/sefht/cms.c index 7651c0d606aa0d02fd69393c6e622b0520db9d1e..b76720e6e3949b63198fa237fedb419924be0ecb 100644 --- a/src/cms.c +++ b/src/lib/sefht/cms.c @@ -25,67 +25,71 @@ #include <stdlib.h> #include "macro.h" -#include "error.h" #include "log.h" +#include "status.h" #include "data.h" #include "cms.h" +struct SH_Cms +{ + /*@only@*/ SH_Data * data; +}; + + +/*@null@*/ +/*@only@*/ struct SH_Cms * -SH_Cms_new (struct SH_Error * error) +SH_Cms_new (/*@null@*/ /*@out@*/ struct SH_Status * status) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/ { struct SH_Cms * cms; cms = malloc (sizeof (struct SH_Cms)); if (cms == NULL) { - ERROR1 ("Memory allocation for SH_Cms failed.\n"); - - if (error != NULL) - { - error->type = ALLOCATION_FAILED; - } + set_status (status, E_ALLOC, 4, + "Memory allocation for SH_Cms failed.\n"); return NULL; } - cms->data = SH_Data_new (error); + cms->data = SH_Data_new (status); if (cms->data == NULL) { free (cms); - return NULL; } - if (error != NULL) - { - error->type = SUCCESS; - } - + set_success (status); return cms; } void -SH_Cms_free (struct SH_Cms * cms, struct SH_Error * error) +SH_Cms_free (/*@only@*/ struct SH_Cms * cms) + /*@modifies cms->data@*/ + /*@modifies cms@*/ + /*@releases cms@*/ { - SH_Data_free (cms->data, NULL); + SH_Data_free (cms->data); free (cms); - if (error != NULL) - { - error->type = SUCCESS; - } - return; } page_t SH_Cms_register_page (struct SH_Cms * cms, const char * name, - struct SH_Error * error) + struct SH_Status * status) + /*@modifies cms->data@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/ { - return SH_Data_register_page (cms->data, name, error); + return SH_Data_register_page (cms->data, name, status); } diff --git a/src/cms.h b/src/lib/sefht/cms.h similarity index 53% rename from src/cms.h rename to src/lib/sefht/cms.h index 683f0cbc10e56d8d3086bce60edab3fb916176c7..73030b1462756a0feac2dc49982e776040b77c7d 100644 --- a/src/cms.h +++ b/src/lib/sefht/cms.h @@ -22,23 +22,40 @@ */ -#ifndef _CMS_H -#define _CMS_H +#ifndef SEFHT_CMS_H +#define SEFHT_CMS_H -#include "error.h" +#if !defined (SEFHT_SEFHT_H_INSIDE) && !defined (SEFHT_COMPILATION) +#error "Only <sefht/sefht.h> can be included directly." +#endif + +#include "status.h" #include "data.h" -struct SH_Cms -{ - struct SH_Data * data; -}; +typedef /*@abstract@*/ struct SH_Cms SH_Cms; + + +/*@null@*/ +/*@only@*/ +SH_Cms * +SH_Cms_new (/*@null@*/ /*@out@*/ struct SH_Status * status) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; -struct SH_Cms * SH_Cms_new (struct SH_Error * error); -void SH_Cms_free (struct SH_Cms * cms, struct SH_Error * error); +void +SH_Cms_free (/*@only@*/ SH_Cms * cms) + /*@modifies cms@*/ + /*@releases cms@*/; -page_t SH_Cms_register_page (struct SH_Cms * cms, const char * name, - struct SH_Error * error); +page_t +SH_Cms_register_page (struct SH_Cms * cms, const char * name, + struct SH_Status * status) + /*@modifies cms@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; -#endif /* _CMS_H */ +#endif /* SEFHT_CMS_H */ diff --git a/src/lib/sefht/data.c b/src/lib/sefht/data.c new file mode 100644 index 0000000000000000000000000000000000000000..4c3da9327d3c997bdd1f3944ec137c339728c605 --- /dev/null +++ b/src/lib/sefht/data.c @@ -0,0 +1,306 @@ +/* + * data.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 <errno.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "macro.h" +#include "log.h" +#include "status.h" + +#include "validator.h" + +#include "data.h" + + +struct SH_Page +{ + page_t id; + char * name; +}; + +struct SH_Data +{ + SH_Validator * validator; + size_t page_n; + struct SH_Page * pages; + page_t last_page; +}; + + +static inline +page_t +next_page (struct SH_Data * data) + /*@*/ +{ + if (data->last_page == PAGE_MAX) + { + return PAGE_ERR; + } + return data->last_page + 1; +} + +static inline +bool +init_validator (/*@special@*/ struct SH_Data * data, + /*@null@*/ /*@out@*/ struct SH_Status * status) + /*@allocates data->validator@*/ + /*@defines *(data->validator)@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; + +static inline +void +init_pages (/*@special@*/ struct SH_Data * data) + /*@allocates data->pages@*/ + /*@defines data->page_n, + * data->last_page@*/ + /*@modifies data->page_n@*/ + /*@modifies data->pages@*/ + /*@modifies data->last_page@*/; + +/*@null@*/ +/*@only@*/ +struct SH_Data * +SH_Data_new (/*@out@*/ /*@null@*/ struct SH_Status * status) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/ + +{ + struct SH_Data * data; + data = malloc (sizeof (struct SH_Data)); + + if (data == NULL) + { + set_status (status, E_ALLOC, 4, + "Memory allocation for SH_Data failed.\n"); + + return NULL; + } + + if (!init_validator (data, status)) + { + +/* dangerous call to silence splint, should never be executed. */ +#ifdef S_SPLINT_S + free (data->validator); +#endif + + free (data); + + return NULL; + } + + init_pages (data); + + set_success (status); + return data; +} + +static inline +void +free_validator (/*@special@*/ struct SH_Data * data) + /*@modifies data->validator@*/ + /*@releases data->validator@*/; + +static inline +void +free_pages (/*@special@*/ struct SH_Data * data) + /*@modifies data->pages@*/ + /*@releases data->pages@*/ + /*@requires maxRead(data->pages) == (data->page_n - 1)@*/; + +void +SH_Data_free (/*@only@*/ struct SH_Data * data) + /*@modifies data->validator@*/ + /*@modifies data->pages@*/ + /*@modifies data@*/ + /*@releases data@*/ +{ + free_validator (data); + free_pages (data); + + free (data); + + return; +} + +static inline +bool +init_validator (struct SH_Data * data, + /*@out@*/ /*@null@*/ struct SH_Status * status) + /*@allocates data->validator@*/ + /*@defines *(data->validator)@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/ +{ + data->validator = SH_Validator_new (status); + + if (data->validator == NULL) + { + return FALSE; + } + + SH_Validator_register_tag (data->validator, "html", NULL); + SH_Validator_register_tag (data->validator, "head", NULL); + SH_Validator_register_tag (data->validator, "body", NULL); + SH_Validator_register_tag (data->validator, "meta", NULL); + SH_Validator_register_tag (data->validator, "link", NULL); + SH_Validator_register_tag (data->validator, "title", NULL); + SH_Validator_register_tag (data->validator, "main", NULL); + SH_Validator_register_tag (data->validator, "article", NULL); + SH_Validator_register_tag (data->validator, "section", NULL); + SH_Validator_register_tag (data->validator, "header", NULL); + SH_Validator_register_tag (data->validator, "footer", NULL); + SH_Validator_register_tag (data->validator, "h1", NULL); + SH_Validator_register_tag (data->validator, "h2", NULL); + SH_Validator_register_tag (data->validator, "h3", NULL); + SH_Validator_register_tag (data->validator, "h4", NULL); + SH_Validator_register_tag (data->validator, "h5", NULL); + SH_Validator_register_tag (data->validator, "h6", NULL); + SH_Validator_register_tag (data->validator, "p", NULL); + SH_Validator_register_tag (data->validator, "br", NULL); + SH_Validator_register_tag (data->validator, "i", NULL); + SH_Validator_register_tag (data->validator, "b", NULL); + SH_Validator_register_tag (data->validator, "strong", NULL); + SH_Validator_register_tag (data->validator, "em", NULL); + SH_Validator_register_tag (data->validator, "small", NULL); + + return TRUE; +} + +static inline +void +free_validator (/*@special@*/ struct SH_Data * data) + /*@modifies data->validator@*/ + /*@releases data->validator@*/ +{ + SH_Validator_free (data->validator); + return; +} + +static inline +void +init_pages (/*@special@*/ struct SH_Data * data) + /*@allocates data->pages@*/ + /*@defines data->page_n, + * data->last_page@*/ + /*@modifies data->page_n@*/ + /*@modifies data->pages@*/ + /*@modifies data->last_page@*/ +{ + data->page_n = 0; + data->pages = malloc (0); + data->last_page = PAGE_ERR; + + return; +} + +static inline +void +free_pages (/*@special@*/ struct SH_Data * data) + /*@modifies data->pages@*/ + /*@releases data->pages@*/ + /*@requires maxRead(data->pages) == (data->page_n - 1)@*/ +{ + size_t index; + + for (index = 0; index < data->page_n; index++) + { + free (data->pages[index].name); + } + + free (data->pages); + return; +} + +page_t +SH_Data_register_page (struct SH_Data * data, const char * name, + struct SH_Status * status) + /*@modifies data->page_n@*/ + /*@modifies data->pages@*/ + /*@modifies data->last_page@*/ + /*@requires maxRead(data->pages) == (data->page_n - 1)@*/ + /*@ensures maxRead(data->pages) == (data->page_n - 1)@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/ +{ + struct SH_Page * new_pages; + page_t page_id; + + page_id = next_page (data); + /* abort on overflow */ + if ((page_id == PAGE_ERR) || (data->page_n == SIZE_MAX)) + { + set_status (status, E_DOMAIN, 0, + "Maximum number of pages reached.\n"); + + return PAGE_ERR; + } + + new_pages = realloc (data->pages, + sizeof (struct SH_Page) + * (data->page_n + 1)); + + if (new_pages == NULL) + { + set_status (status, E_ALLOC, 5, + "Memory allocation for page data failed.\n"); + +/* bad code to silence splint, should never be executed. */ +#ifdef S_SPLINT_S + data->pages = (void *) 0x12345; +#endif + + return PAGE_ERR; + } + + new_pages[data->page_n].id = page_id; + new_pages[data->page_n].name = strdup (name); + + if (new_pages[data->page_n].name == NULL) + { + set_status (status, E_ALLOC, 4, + "Memory allocation for page data failed.\n"); + + data->pages = new_pages; + return PAGE_ERR; + } + + /* commit changes */ + data->pages = new_pages; + data->last_page = page_id; + data->page_n++; + + set_success (status); + + return data->last_page; +} diff --git a/src/data.h b/src/lib/sefht/data.h similarity index 54% rename from src/data.h rename to src/lib/sefht/data.h index 4b502d308f62163ba27aafb5ac09812882b7d21d..8aa817b3e33e49b731fc3e8022124edbb6703147 100644 --- a/src/data.h +++ b/src/lib/sefht/data.h @@ -22,41 +22,47 @@ */ -#ifndef _DATA_H -#define _DATA_H +#ifndef SEFHT_DATA_H +#define SEFHT_DATA_H + +#if !defined (SEFHT_SEFHT_H_INSIDE) && !defined (SEFHT_COMPILATION) +#error "Only <sefht/sefht.h> can be included directly." +#endif #include <limits.h> -#include "error.h" +#include "status.h" #include "validator.h" -typedef unsigned int page_t; +typedef /*@abstract@*/ unsigned int page_t; #define PAGE_ERR 0 #define PAGE_MIN 1 #define PAGE_MAX UINT_MAX -#define NEXT_PAGE(page) page++ -struct SH_Page -{ - page_t id; - char * name; -}; +typedef /*@abstract@*/ struct SH_Data SH_Data; -struct SH_Data -{ - struct SH_Validator * validator; - unsigned int page_n; - struct SH_Page * pages; - page_t last_page; -}; -struct SH_Data * SH_Data_new (struct SH_Error * error); -void SH_Data_free (struct SH_Data * data, struct SH_Error * error); +/*@null@*/ +/*@only@*/ +SH_Data * +SH_Data_new (/*@out@*/ /*@null@*/ struct SH_Status * status) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; +void +SH_Data_free (/*@only@*/ struct SH_Data * data) + /*@modifies data@*/ + /*@releases data@*/; -page_t SH_Data_register_page (struct SH_Data * data, const char * name, - struct SH_Error * error); +page_t +SH_Data_register_page (SH_Data * data, const char * name, + struct SH_Status * status) + /*@modifies data@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; -#endif /* _DATA_H */ +#endif /* SEFHT_DATA_H */ diff --git a/src/lib/sefht/fragment.c b/src/lib/sefht/fragment.c new file mode 100644 index 0000000000000000000000000000000000000000..6a306bd388983053c8d14ed6a0d5fd9f9de15a57 --- /dev/null +++ b/src/lib/sefht/fragment.c @@ -0,0 +1,75 @@ +/* + * fragment.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 "macro.h" +#include "log.h" +#include "status.h" + +#include "text.h" + +#include "fragment.h" + + +#include "fragment_data.c" + +/*@null@*/ +/*@only@*/ +struct SH_Fragment * +SH_Fragment_copy (const struct SH_Fragment * fragment, + /*@out@*/ /*@null@*/ struct SH_Status * status) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/ +{ + return fragment->methods->copy (fragment, status); +} + +void +SH_Fragment_free (/*@only@*/ struct SH_Fragment * fragment) + /*@modifies fragment@*/ + /*@releases fragment@*/ +{ + fragment->methods->free (fragment); + return; +} + +/*@null@*/ +/*@only@*/ +SH_Text * +SH_Fragment_to_html (const struct SH_Fragment * fragment, + enum HTML_MODE mode, + unsigned int indent_base, + unsigned int indent_step, + const char * indent_char, + /*@out@*/ /*@null@*/ struct SH_Status * status) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/ +{ + return fragment->methods->to_html (fragment, mode, + indent_base, + indent_step, + indent_char, + status); +} diff --git a/src/lib/sefht/fragment.h b/src/lib/sefht/fragment.h new file mode 100644 index 0000000000000000000000000000000000000000..f2602e810ed359ed3ab32df60a59dab440952aa0 --- /dev/null +++ b/src/lib/sefht/fragment.h @@ -0,0 +1,74 @@ +/* + * fragment.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 SEFHT_FRAGMENT_H +#define SEFHT_FRAGMENT_H + +#if !defined (SEFHT_SEFHT_H_INSIDE) && !defined (SEFHT_COMPILATION) +#error "Only <sefht/sefht.h> can be included directly." +#endif + +#include "status.h" + +#include "data.h" +#include "text.h" + + +enum HTML_MODE +{ + INLINE, + WRAP +}; + +typedef /*@abstract@*/ struct SH_Fragment SH_Fragment; + + +/*@null@*/ +/*@only@*/ +struct SH_Fragment * +SH_Fragment_copy (const SH_Fragment * fragment, + /*@out@*/ /*@null@*/ struct SH_Status * status) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; + +void +SH_Fragment_free (/*@only@*/ SH_Fragment * fragment) + /*@modifies fragment@*/ + /*@releases fragment@*/; + +/*@null@*/ +/*@only@*/ +SH_Text * +SH_Fragment_to_html (const struct SH_Fragment * fragment, + enum HTML_MODE mode, + unsigned int indent_base, + unsigned int indent_step, + const char * indent_char, + /*@out@*/ /*@null@*/ struct SH_Status * status) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; + +#endif /* SEFHT_FRAGMENT_H */ diff --git a/src/lib/sefht/fragment_class.c b/src/lib/sefht/fragment_class.c new file mode 100644 index 0000000000000000000000000000000000000000..3a478d1f017f5d57b0554c92f921e7dc0b6eaeeb --- /dev/null +++ b/src/lib/sefht/fragment_class.c @@ -0,0 +1,93 @@ +/* + * fragment_class.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. + * + * + */ + + +#ifndef SEFHT_FRAGMENT_CLASS_C +#define SEFHT_FRAGMENT_CLASS_C + +#if !defined (SEFHT_SEFHT_H_INSIDE) && !defined (SEFHT_COMPILATION) +#error "Only <sefht/sefht.h> can be included directly." +#endif + +#include "status.h" + +#include "data.h" +#include "text.h" + + +#ifdef SEFHT_COMPILATION +#include "fragment_data.c" + +static inline +void +init_fragment (/*@out@*/ struct SH_Fragment * fragment, + /*@dependent@*/ SH_Data * data, + const enum SH_FRAGMENT_TYPE type, + /*@shared@*/ + const struct fragment_methods * const methods) + /*@modifies fragment->data@*/ + /*@modifies fragment->type@*/ + /*@modifies fragment->methods@*/ +{ + fragment->data = data; + fragment->type = type; + fragment->methods = methods; + + return; +} + +static inline +void +free_fragment (struct SH_Fragment * fragment) + /*@modifies fragment@*/ + /*@releases fragment@*/ +{ + (void) fragment; + return; +} + +static inline +void +copy_fragment (/*@out@*/ struct SH_Fragment * copy, + const struct SH_Fragment * fragment) + /*@modifies copy->data@*/ + /*@modifies copy->type@*/ + /*@modifies copy->methods@*/ +{ + copy->data = fragment->data; + copy->type = fragment->type; + copy->methods = fragment->methods; + + return; +} + +static inline +enum SH_FRAGMENT_TYPE +get_type (const struct SH_Fragment * fragment) + /*@*/ +{ + return fragment->type; +} + +#endif /* SEFHT_COMPILATION */ +#endif /* SEFHT_FRAGMENT_CLASS_C */ diff --git a/src/lib/sefht/fragment_data.c b/src/lib/sefht/fragment_data.c new file mode 100644 index 0000000000000000000000000000000000000000..f55a71c764e29281f9b748ea258d97aab6b7aa31 --- /dev/null +++ b/src/lib/sefht/fragment_data.c @@ -0,0 +1,86 @@ +/* + * fragment_data.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. + * + * + */ + + +#ifndef SEFHT_FRAGMENT_DATA_C +#define SEFHT_FRAGMENT_DATA_C + +#if !defined (SEFHT_SEFHT_H_INSIDE) && !defined (SEFHT_COMPILATION) +#error "Only <sefht/sefht.h> can be included directly." +#endif + +#include "status.h" + +#include "data.h" +#include "text.h" + + +#ifdef SEFHT_COMPILATION + +enum SH_FRAGMENT_TYPE +{ + NODE +}; + +struct SH_Fragment; + +struct fragment_methods +{ + /*@null@*/ + /*@only@*/ + struct SH_Fragment * + (*copy) (const struct SH_Fragment *, + /*@out@*/ /*@null@*/ struct SH_Status *) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; + + void + (*free) (/*@only@*/ struct SH_Fragment *) + /*@modifies fragment@*/ + /*@releases fragment@*/; + + /*@null@*/ + /*@only@*/ + struct SH_Text * + (*to_html) (const struct SH_Fragment *, + enum HTML_MODE, + unsigned int, + unsigned int, + const char *, + /*@out@*/ /*@null@*/ struct SH_Status *) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; +}; + +struct SH_Fragment +{ + /*@dependent@*/ SH_Data * data; + + enum SH_FRAGMENT_TYPE type; + /*@shared@*/ const struct fragment_methods * methods; +}; + +#endif /* SEFHT_COMPILATION */ +#endif /* SEFHT_FRAGMENT_DATA_C */ diff --git a/src/log.h b/src/lib/sefht/log.h similarity index 77% rename from src/log.h rename to src/lib/sefht/log.h index 8e5c3a7c8d95ac096118975f85277d5911044ba1..2f81d238db1c48be1d2fa8c09586b25a9148cb2f 100644 --- a/src/log.h +++ b/src/lib/sefht/log.h @@ -22,15 +22,17 @@ */ -#ifndef _LOG_H -#define _LOG_H +#ifndef SEFHT_LOG_H +#define SEFHT_LOG_H + +#if !defined (SEFHT_SEFHT_H_INSIDE) && !defined (SEFHT_COMPILATION) +#error "Only <sefht/sefht.h> can be included directly." +#endif #include <stdio.h> #define ERROR1(message) printf (message) -#define ERROR2(message, arg1) printf (message, arg1) -#define ERROR3(message, arg1, arg2) printf (message, arg1, arg2) -#define ERROR4(message, arg1, arg2, arg3) printf (message, arg1, arg2, arg3) +#define ERROR_(message, ...) printf (message, __VA_ARGS__) -#endif /* _LOG_H */ +#endif /* SEFHT_LOG_H */ diff --git a/src/macro.h b/src/lib/sefht/macro.h similarity index 81% rename from src/macro.h rename to src/lib/sefht/macro.h index 844daa805a74ab15b2c89c9bcfc649f7971155f6..71286e65492069c6dbd47885ed3bd43e53173830 100644 --- a/src/macro.h +++ b/src/lib/sefht/macro.h @@ -22,12 +22,16 @@ */ -#ifndef _MACRO_H -#define _MACRO_H +#ifndef SEFHT_MACRO_H +#define SEFHT_MACRO_H + +#if !defined (SEFHT_SEFHT_H_INSIDE) && !defined (SEFHT_COMPILATION) +#error "Only <sefht/sefht.h> can be included directly." +#endif #include <stdbool.h> #define TRUE (bool) 1 #define FALSE (bool) 0 -#endif /* _MACRO_H */ +#endif /* SEFHT_MACRO_H */ diff --git a/src/lib/sefht/node_fragment.c b/src/lib/sefht/node_fragment.c new file mode 100644 index 0000000000000000000000000000000000000000..b1294cdf3288ffa92432734f8b314531a4aaf956 --- /dev/null +++ b/src/lib/sefht/node_fragment.c @@ -0,0 +1,594 @@ +/* + * node_fragment.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 <errno.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> + +#include "macro.h" +#include "log.h" +#include "status.h" + +#include "data.h" +#include "text.h" +#include "validator.h" + +#include "fragment.h" + +#include "node_fragment.h" + + +#include "fragment_class.c" + +struct SH_NodeFragment +{ + struct SH_Fragment base; + + char * tag; + + size_t child_n; + struct SH_Fragment ** childs; +}; + +#define OPEN_TAG_BEGIN "<" +#define OPEN_TAG_END ">" +#define CLOSE_TAG_BEGIN "</" +#define CLOSE_TAG_END ">" + +#define NEWLINE "\n" + + +static const struct fragment_methods methods = { + (struct SH_Fragment * (*)(const struct SH_Fragment *, + /*@out@*/ /*@null@*/ + struct SH_Status *)) + SH_NodeFragment_deepcopy, + + (void (*)(/*@only@*/ struct SH_Fragment *)) + SH_NodeFragment_free, + + (struct SH_Text * (*)(const struct SH_Fragment *, + enum HTML_MODE, + unsigned int, unsigned int, const char *, + /*@out@*/ /*@null@*/ struct SH_Status *)) + SH_NodeFragment_to_html +}; + + +/*@null@*/ +/*@only@*/ +struct SH_Fragment /*@alt struct SH_NodeFragment@*/ * +SH_NodeFragment_new (const char * tag, + /*@dependent@*/ SH_Data * data, + /*@out@*/ /*@null@*/ struct SH_Status * status) + /*@globals NODE, + fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/ +{ + struct SH_NodeFragment * fragment; + + fragment = malloc (sizeof (struct SH_NodeFragment)); + if (fragment == NULL) + { + set_status (status, E_ALLOC, 3, + "Memory allocation for " + "SH_NodeFragment failed.\n"); + + return NULL; + } + + init_fragment (&(fragment->base), data, NODE, &methods); + + fragment->tag = strdup (tag); + if (fragment->tag == NULL) + { + set_status (status, E_ALLOC, 3, + "Memory allocation for " + "fragment tag failed.\n"); + + free (fragment); + + return NULL; + } + + + fragment->child_n = 0; + fragment->childs = malloc (0); + + set_success (status); + + return (struct SH_Fragment *) fragment; +} + +void +SH_NodeFragment_free (/*@only@*/ struct SH_NodeFragment * fragment) + /*@modifies fragment@*/ + /*@releases fragment@*/ +{ + size_t index; + + free (fragment->tag); + + for (index = 0; index < fragment->child_n; index++) + { + SH_Fragment_free (fragment->childs[index]); + } + free (fragment->childs); + + free_fragment (&fragment->base); + + free (fragment); + + return; +} + +/*@null@*/ +/*@only@*/ +struct SH_Fragment /*@alt struct SH_NodeFragment@*/ * +SH_NodeFragment_copy (const struct SH_NodeFragment * fragment, + /*@out@*/ /*@null@*/ struct SH_Status * status) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/ +{ + struct SH_NodeFragment * copy; + + copy = malloc (sizeof (struct SH_NodeFragment)); + if (copy == NULL) + { + set_status (status, E_ALLOC, 3, + "Memory allocation for " + "SH_NodeFragment failed.\n"); + + return NULL; + } + + copy_fragment (&(copy->base), &(fragment->base)); + + copy->tag = strdup (fragment->tag); + if (copy->tag == NULL) + { + set_status (status, E_ALLOC, 3, + "Memory allocation for " + "fragment tag failed.\n"); + + free (copy); + + return NULL; + } + + + copy->child_n = 0; + copy->childs = malloc (0); + + set_success (status); + + return (struct SH_Fragment *) copy; +} + +/*@null@*/ +/*@only@*/ +struct SH_Fragment /*@alt struct SH_NodeFragment@*/ * +SH_NodeFragment_deepcopy (const struct SH_NodeFragment * fragment, + /*@out@*/ /*@null@*/ + struct SH_Status * status) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/ +{ + struct SH_NodeFragment * copy; + struct SH_Fragment * child; + size_t index; + + copy = malloc (sizeof (struct SH_NodeFragment)); + if (copy == NULL) + { + set_status (status, E_ALLOC, 3, + "Memory allocation for " + "SH_NodeFragment failed.\n"); + + return NULL; + } + + copy_fragment (&(copy->base), &(fragment->base)); + + copy->tag = strdup (fragment->tag); + if (copy->tag == NULL) + { + set_status (status, E_ALLOC, 3, + "Memory allocation for " + "fragment tag failed.\n"); + + free (copy); + + return NULL; + } + + + copy->child_n = fragment->child_n; + copy->childs = malloc (sizeof (struct SH_NodeFragment *) + * fragment->child_n); + + if (copy->child_n != 0 && copy->childs == NULL) + { + set_status (status, E_ALLOC, 5, + "Memory allocation for " + "fragment child failed.\n"); + + free (copy->tag); +/* dangerous call to silence splint, should never be executed. */ +#ifdef S_SPLINT_S + free (copy->childs); +#endif + free (copy); + + return NULL; + } + + for (index = 0; index < fragment->child_n; index++) + { + child = SH_Fragment_copy (fragment->childs[index], + status); + + if (child == NULL) + { + copy->child_n = index; + SH_NodeFragment_free (copy); + + return NULL; + } + + copy->childs[index] = child; + } + + set_success (status); + + return (struct SH_Fragment *) copy; +} + +bool +SH_Fragment_is_NodeFragment (const struct SH_Fragment * fragment) + /*@*/ +{ + return get_type (fragment) == NODE; +} + +/*@null@*/ +/*@only@*/ +char * +SH_NodeFragment_get_tag (const struct SH_NodeFragment * fragment, + /*@out@*/ /*@null@*/ struct SH_Status * status) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/ +{ + char * tag; + + tag = strdup (fragment->tag); + + if (tag == NULL) + { + set_status (status, E_ALLOC, 4, + "Memory allocation for " + "fragment tag failed.\n"); + + return NULL; + } + + set_success (status); + + return tag; +} + +/*@null@*/ +/*@observer@*/ +struct SH_Fragment * +SH_NodeFragment_get_child (const struct SH_NodeFragment * fragment, + size_t index, + /*@out@*/ /*@null@*/ + struct SH_Status * status) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/ +{ + if (index >= fragment->child_n) + { + set_status (status, E_VALUE, 2, + "Fragment: Child index out of range.\n"); + + return NULL; + } + + set_success (status); + + return fragment->childs[index]; +} + +bool +SH_NodeFragment_is_child (const struct SH_NodeFragment * fragment, + const struct SH_Fragment * child) + /*@*/ +{ + size_t index; + + for (index = 0; index < fragment->child_n; index++) + { + if (fragment->childs[index] == child) + { + return TRUE; + } + } + return FALSE; +} + +bool +SH_NodeFragment_is_descendant (const struct SH_NodeFragment * fragment, + const struct SH_Fragment * child) + /*@*/ +{ + size_t index; + + for (index = 0; index < fragment->child_n; index++) + { + if (fragment->childs[index] == child + || (SH_Fragment_is_NodeFragment (child) + && SH_NodeFragment_is_descendant ( + (struct SH_NodeFragment *) + fragment->childs[index], + child))) + { + return TRUE; + } + } + return FALSE; +} + +bool +SH_NodeFragment_append_child (struct SH_NodeFragment * fragment, + /*@only@*/ struct SH_Fragment * child, + /*@out@*/ /*@null@*/ + struct SH_Status * status) + /*@modifies fragment->childs@*/ + /*@modifies fragment->child_n@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/ +{ + struct SH_Fragment ** new_childs; + + new_childs = realloc (fragment->childs, + sizeof (struct SH_Fragment *) + * (fragment->child_n + 1)); + + if (new_childs == NULL) + { + set_status (status, E_ALLOC, 6, + "Memory allocation for " + "fragment child failed.\n"); + +/* bad code to silence splint, should never be executed. */ +#ifdef S_SPLINT_S + fragment->childs = (void *) 0x12345; +#endif + return FALSE; + } + + new_childs[fragment->child_n] = child; + + fragment->childs = new_childs; + fragment->child_n++; + + set_success (status); + + return TRUE; +} + +/*@null@*/ +/*@only@*/ +struct SH_Text * +SH_NodeFragment_to_html (const struct SH_NodeFragment * fragment, + enum HTML_MODE mode, + unsigned int indent_base, + unsigned int indent_step, + const char * indent_char, + /*@out@*/ /*@null@*/ struct SH_Status * status) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/ +{ + struct SH_Text * html; + struct SH_Text * child; + struct SH_Text * indent_text; + size_t index; + + html = SH_Text_new (status); + if (html == NULL) + { + return NULL; + } + + if (mode == WRAP) + { + indent_text = SH_Text_new (status); + if (indent_text == NULL) + { + SH_Text_free (html); + return NULL; + } + + for (index = 0; ((unsigned int) index) < indent_base; + index++) + { + if (!SH_Text_append_string (indent_text, + indent_char, + status)) + { + SH_Text_free (html); + SH_Text_free (indent_text); + return NULL; + } + } + + if (!SH_Text_append_text (html, indent_text, status)) + { + SH_Text_free (html); + SH_Text_free (indent_text); + return NULL; + } + } + + if (!SH_Text_append_string (html, OPEN_TAG_BEGIN, status)) + { + SH_Text_free (html); + + if (mode == WRAP) + { + SH_Text_free (indent_text); + } + + return NULL; + } + + if (!SH_Text_append_string (html, fragment->tag, status)) + { + SH_Text_free (html); + + if (mode == WRAP) + { + SH_Text_free (indent_text); + } + + return NULL; + } + + if (!SH_Text_append_string (html, OPEN_TAG_END, status)) + { + SH_Text_free (html); + + if (mode == WRAP) + { + SH_Text_free (indent_text); + } + + return NULL; + } + + if (mode == WRAP) + { + if (!SH_Text_append_string (html, NEWLINE, status)) + { + SH_Text_free (html); + SH_Text_free (indent_text); + return NULL; + } + } + + for (index = 0; index < fragment->child_n; index++) + { + child = SH_Fragment_to_html (fragment->childs[index], + mode, + indent_base + indent_step, + indent_step, + indent_char, + status); + + if (child == NULL) + { + SH_Text_free (html); + + if (mode == WRAP) + { + SH_Text_free (indent_text); + } + + return NULL; + } + + SH_Text_join (html, child); + } + + if (mode == WRAP) + { + if (!SH_Text_append_text (html, indent_text, status)) + { + SH_Text_free (html); + SH_Text_free (indent_text); + return NULL; + } + } + + if (!SH_Text_append_string (html, CLOSE_TAG_BEGIN, status)) + { + SH_Text_free (html); + + if (mode == WRAP) + { + SH_Text_free (indent_text); + } + + return NULL; + } + + if (!SH_Text_append_string (html, fragment->tag, status)) + { + SH_Text_free (html); + + if (mode == WRAP) + { + SH_Text_free (indent_text); + } + + return NULL; + } + + if (!SH_Text_append_string (html, CLOSE_TAG_END, status)) + { + SH_Text_free (html); + + if (mode == WRAP) + { + SH_Text_free (indent_text); + } + + return NULL; + } + + if (mode == WRAP) + { + if (!SH_Text_append_string (html, NEWLINE, status)) + { + SH_Text_free (html); + SH_Text_free (indent_text); + return NULL; + } + + SH_Text_free (indent_text); + } + + set_success (status); + + return html; +} diff --git a/src/lib/sefht/node_fragment.h b/src/lib/sefht/node_fragment.h new file mode 100644 index 0000000000000000000000000000000000000000..46be532032aa5df8eb7fd6b8d4db5b0648d5a442 --- /dev/null +++ b/src/lib/sefht/node_fragment.h @@ -0,0 +1,136 @@ +/* + * node_fragment.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 SEFHT_NODE_FRAGMENT_H +#define SEFHT_NODE_FRAGMENT_H + +#if !defined (SEFHT_SEFHT_H_INSIDE) && !defined (SEFHT_COMPILATION) +#status "Only <sefht/sefht.h> can be included directly." +#endif + +#include "status.h" + +#include "data.h" +#include "text.h" + +#include "fragment.h" + + +#define INDENT_TEXT "\t" + +typedef /*@abstract@*/ struct SH_NodeFragment SH_NodeFragment; + + +/*@null@*/ +/*@only@*/ +SH_Fragment /*@alt SH_NodeFragment@*/ * +SH_NodeFragment_new (const char * tag, + /*@dependent@*/ SH_Data * data, + /*@out@*/ /*@null@*/ struct SH_Status * status) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; + +void +SH_NodeFragment_free (/*@only@*/ SH_NodeFragment * fragment) + /*@modifies fragment@*/ + /*@releases fragment@*/; + +/*@null@*/ +/*@only@*/ +SH_Fragment /*@alt SH_NodeFragment@*/ * +SH_NodeFragment_copy (const SH_NodeFragment * fragment, + /*@out@*/ /*@null@*/ struct SH_Status * status) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; + +/*@null@*/ +/*@only@*/ +SH_Fragment /*@alt SH_NodeFragment@*/ * +SH_NodeFragment_deepcopy (const SH_NodeFragment * fragment, + /*@out@*/ /*@null@*/ + struct SH_Status * status) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; + +bool +SH_Fragment_is_NodeFragment (const SH_Fragment * fragment) + /*@*/; + +/*@null@*/ +/*@only@*/ +char * +SH_NodeFragment_get_tag (const SH_NodeFragment * fragment, + /*@out@*/ /*@null@*/ struct SH_Status * status) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; + +/*@null@*/ +/*@observer@*/ +SH_Fragment * +SH_NodeFragment_get_child (const SH_NodeFragment * fragment, + size_t index, + /*@out@*/ /*@null@*/ + struct SH_Status * status) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; + +bool +SH_NodeFragment_is_child (const SH_NodeFragment * fragment, + const SH_Fragment * child) + /*@*/; + +bool +SH_NodeFragment_is_descendant (const struct SH_NodeFragment * fragment, + const struct SH_Fragment * child) + /*@*/; + +bool +SH_NodeFragment_append_child (struct SH_NodeFragment * fragment, + /*@only@*/ struct SH_Fragment * child, + /*@out@*/ /*@null@*/ + struct SH_Status * status) + /*@modifies fragment@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; + +/*@null@*/ +/*@only@*/ +SH_Text * +SH_NodeFragment_to_html (const SH_NodeFragment * fragment, + enum HTML_MODE mode, + unsigned int indent_base, + unsigned int indent_step, + const char * indent_char, + /*@out@*/ /*@null@*/ struct SH_Status * status) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; + +#endif /* SEFHT_NODE_FRAGMENT_H */ diff --git a/src/sefht.h b/src/lib/sefht/sefht.h similarity index 72% rename from src/sefht.h rename to src/lib/sefht/sefht.h index 74f46dbd5ba8f931e6e3a18d1a58c777900f805b..b94c2672cbd221d297d60003e865547022eacb4a 100644 --- a/src/sefht.h +++ b/src/lib/sefht/sefht.h @@ -22,7 +22,22 @@ */ -#ifndef _SEFHT_H -#define _SEFHT_H +#ifndef SEFHT_SEFHT_H +#define SEFHT_SEFHT_H -#endif /* _SEFHT_H */ +#define SEFHT_SEFHT_H_INSIDE + +#include "log.h" +#include "macro.h" +#include "status.h" + +#include "cms.h" +#include "data.h" +#include "fragment.h" +#include "node_fragment.h" +#include "text.h" +#include "validator.h" + +#undef SEFHT_SEFHT_H_INSIDE + +#endif /* SEFHT_SEFHT_H */ diff --git a/src/lib/sefht/status.h b/src/lib/sefht/status.h new file mode 100644 index 0000000000000000000000000000000000000000..4b4b479ee2b7fb623f650127ab686e3b939f49ae --- /dev/null +++ b/src/lib/sefht/status.h @@ -0,0 +1,127 @@ +/* + * status.h + * + * Copyright 2022 Jonathan Schöbel <jonathan@xn--schbel-yxa.info> + * + * 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 SEFHT_STATUS_H +#define SEFHT_STATUS_H + +#include <errno.h> +#include <string.h> + +#include "macro.h" + +#if !defined (SEFHT_SEFHT_H_INSIDE) && !defined (SEFHT_COMPILATION) +#error "Only <sefht/sefht.h> can be included directly." +#endif + + +#ifdef SEFHT_COMPILATION + +#define succeed(STATUS) \ + (((STATUS) != NULL) && ((STATUS)->status == SUCCESS)) + +#define failed(STATUS) \ + (((STATUS) != NULL) && ((STATUS)->status != SUCCESS)) + +#define unknown(STATUS) ((STATUS) == NULL) + +#define set_status(STATUS, ERROR, OFFSET, MESSAGE) \ +do \ +{ \ + if ((STATUS) != NULL) \ + { \ + (STATUS)->status = (ERROR); \ + (STATUS)->errno_ = ((ERROR) == SUCCESS) ? 0: errno; \ + (STATUS)->file = (__FILE__); \ + (STATUS)->function = (__FUNCTION__); \ + (STATUS)->line = (unsigned long) ((__LINE__)-(OFFSET));\ + (STATUS)->message = (MESSAGE); \ + }; \ + \ + if ((MESSAGE) != NULL) \ + { \ + ERROR1 ((MESSAGE)); \ + } \ +} \ +while (FALSE) + +#define set_status_(STATUS, ERROR, OFFSET, LENGTH, MESSAGE, ...) \ +do \ +{ \ + if ((STATUS) != NULL) \ + { \ + (STATUS)->status = (ERROR); \ + (STATUS)->errno_ = ((ERROR) == SUCCESS) ? 0: errno; \ + (STATUS)->file = (__FILE__); \ + (STATUS)->function = (__FUNCTION__); \ + (STATUS)->line = (unsigned long) ((__LINE__)-(OFFSET));\ + (STATUS)->message = malloc(strlen(MESSAGE)+1 + LENGTH);\ + if ((STATUS)->message == NULL) \ + { \ + set_status ((STATUS), E_ALLOC, (OFFSET), \ + "malloc failed while generating " \ + "error message"); \ + } \ + sprintf ((STATUS)->message, (MESSAGE), __VA_ARGS__); \ + }; \ + \ + ERROR_ ((MESSAGE), __VA_ARGS__); \ +} \ +while (FALSE) + +#define set_success(STATUS) set_status(STATUS, SUCCESS, 0, NULL) + +#define _status_preinit(STATUS) \ +do { \ + (STATUS).status = UNDEFINED; \ + (STATUS).errno_ = 0; \ + (STATUS).file = NULL; \ + (STATUS).line = 0; \ + (STATUS).message = NULL; \ +} \ +while (FALSE) + +#endif /* SEFHT_COMPILATION */ + + +struct SH_Status +{ + enum + { + UNDEFINED, + SUCCESS, + E_ALLOC, + E_DOMAIN, + E_VALUE + } status; + + int errno_; + + /*@observer@*/ const char * file; + /*@observer@*/ const char * function; + unsigned long int line; + + /*@observer@*/ /*@null@*/ char * message; +}; + +#endif /* SEFHT_STATUS_H */ diff --git a/src/lib/sefht/text.c b/src/lib/sefht/text.c new file mode 100644 index 0000000000000000000000000000000000000000..b071c508670cccfd7bf68bdbe316cbc313b05776 --- /dev/null +++ b/src/lib/sefht/text.c @@ -0,0 +1,1054 @@ +/* + * text.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 <errno.h> +#include <math.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "macro.h" +#include "log.h" +#include "status.h" + +#include "text.h" + + +#ifndef CHUNK_SIZE +#define CHUNK_SIZE 64 +#endif /* CHUNK_SIZE */ + +#if CHUNK_SIZE == 0 +#error "CHUNK_SIZE can't be 0." +#endif /* CHUNK_SIZE == 0 */ + +struct text_segment; +struct text_segment +{ + size_t length; + size_t size; + char * text; + /*@relnull@*/ struct text_segment * next; +}; + +struct SH_Text +{ + /*@notnull@*/ struct text_segment * data; +}; + + +/*@null@*/ +/*@only@*/ +struct SH_Text * +SH_Text_new (/*@null@*/ /*@out@*/ struct SH_Status * status) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/ +{ + struct SH_Text * text; + text = malloc (sizeof (struct SH_Text)); + + if (text == NULL) + { + set_status (status, E_ALLOC, 4, + "Memory allocation for SH_Text failed.\n"); + + return NULL; + } + + text->data = malloc (sizeof (struct text_segment)); + + if (text->data == NULL) + { + set_status (status, E_ALLOC, 4, + "Memory allocation for SH_Text failed.\n"); + + free (text); + + return NULL; + } + + text->data->length = 0; + text->data->text = malloc (CHUNK_SIZE * sizeof (char)); + + if (text->data->text == NULL) + { + set_status (status, E_ALLOC, 4, + "Memory allocation for SH_Text failed.\n"); + + free (text->data); + free (text); + + return NULL; + } + + text->data->text[0] = (char) 0; + text->data->size = (size_t) CHUNK_SIZE; + text->data->next = NULL; + + set_success (status); + + return text; +} + +/*@null@*/ +/*@only@*/ +struct SH_Text * +SH_Text_new_from_string (const char * string, + /*@null@*/ /*@out@*/ struct SH_Status * status) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/ +{ + struct SH_Text * text; + text = malloc (sizeof (struct SH_Text)); + + if (text == NULL) + { + set_status (status, E_ALLOC, 4, + "Memory allocation for SH_Text failed.\n"); + + return NULL; + } + + text->data = malloc (sizeof (struct text_segment)); + + if (text->data == NULL) + { + set_status (status, E_ALLOC, 4, + "Memory allocation for SH_Text failed.\n"); + + free (text); + + return NULL; + } + + text->data->length = strlen (string); + + if (text->data->length == SIZE_MAX) + { + set_status (status, E_DOMAIN, 2, + "Maximum length of SH_Text reached.\n"); + + free (text->data); + free (text); + + return NULL; + } + + text->data->text = strdup (string); + + if (text->data->text == NULL) + { + set_status (status, E_ALLOC, 4, + "Memory allocation for SH_Text failed.\n"); + + free (text->data); + free (text); + + return NULL; + } + + text->data->size = text->data->length + 1; + text->data->next = NULL; + + set_success (status); + + return text; +} + +void +SH_Text_free (/*@only@*/ struct SH_Text * text) + /*@modifies text@*/ + /*@releases text@*/ +{ + struct text_segment * next; + + for (next = text->data; next != NULL; text->data = next) + { + next = next->next; + + free (text->data->text); + free (text->data); + } + + free (text); + + return; +} + +/*@null@*/ +/*@only@*/ +struct SH_Text * +SH_Text_copy (const struct SH_Text * text, + /*@null@*/ /*@out@*/ struct SH_Status * status) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/ +{ + const struct text_segment * start; + const struct text_segment * end; + struct text_segment * copy_seg; + + struct SH_Text * copy; + copy = malloc (sizeof (struct SH_Text)); + + if (copy == NULL) + { + set_status (status, E_ALLOC, 4, + "Memory allocation for SH_Text failed.\n"); + + return NULL; + } + + copy->data = malloc (sizeof (struct text_segment)); + + if (copy->data == NULL) + { + set_status (status, E_ALLOC, 4, + "Memory allocation for SH_Text failed.\n"); + + free (copy); + + return NULL; + } + + copy->data->next = NULL; + + /* copy_seg is the segment we're currently copying to */ + copy_seg = copy->data; + + /* start to end are the segments we're copying from. */ + /* start points to the first segment to copy. + * end points to the first segment not being copied in + * the current iteration. */ + end = text->data; + start = end; + + /* At the beginning of each iteration start == end. + * This is ensured before the loop and at the end of the outer + * loop with the last for loop, which does the actual copying. + * + * Then end is adjusted to point after the last segment to be + * copied. If it isn't NULL afterwards another loop iteration + * has to take place. + * + * With start and end properly set, and the length and size of + * the resulting segment determined, the copying can start, + * which is just a repeated string concatenation. + * + * If another iteration is following, the next segment has to be + * allocated. This can't be done at the beginning, because + * before the first iteration the pointer to the allocated + * segment must be written to copy->data directly to create the + * anchor of the linked list. (So there is no ?->next + * to write to.) + * Actually copy_seg can also be set to &(copy->data) before + * the loop and to &((*copy_seg)->next) after each iteration, + * but that would be complicate things... + * Implementing the loop as for loop and writing the allocation + * code into their head is also not possible, because compound + * statements aren't allowed there. + * Thus the allocating has to take place at the end of the loop + * (if necessary) and the strange if(end==NULL){break;} has to + * stay there to. */ + /* Actually while (TRUE) would also work, because the loop is + * always aborted with break. + * (See comment above, last paragraph.) */ + while (end != NULL) + { + /* Adjusting end and determine length of the resulting + * segment. Actually the end is determined by the + * length, because the segment can't be greather than + * numbers in size_t. Otherwise we can't address + * everything nor save the length. */ + for (copy_seg->length = 0; end != NULL; end = end->next) + { + /* Stop moving the end further then what we + * can address. Actually copy_seg->length could + * be one greater, so the comparison could be + * with >=, but copy_seg->size should also be + * expressible and this is always at least by + * one greater, because of the terminating + * NULL-byte. */ + if (SIZE_MAX - end->length > copy_seg->length) + { + copy_seg->length += end->length; + } + /* This can't be moved after the loop, because, + * if the loop exits normally, this must not be + * executed. */ + else + { + end = end->next; + + /*@innerbreak@*/ + break; + } + } + + /* This addition can not overflow, because in the + * for-loop it was tested with > instead of >= which + * would be appropriate. See comment there. */ + copy_seg->size = copy_seg->length + 1; + + copy_seg->text = malloc (copy_seg->size * sizeof (char)); + + if (copy_seg->text == NULL) + { + set_status (status, E_ALLOC, 4, + "Memory allocation for SH_Text " + "failed.\n"); + + for (copy_seg = copy->data->next; + copy_seg != NULL; + copy->data = copy_seg, + copy_seg = copy_seg->next) + { + if (copy->data->text != NULL) + { + free (copy->data->text); + } + + free (copy->data); + } + free (copy->data); + + free (copy); + + return NULL; + } + + copy_seg->text[0] = (char) 0; + + /* actual copying */ + /* Initialization was done since the beginning of + * the outer loop. So think of all this code standing + * | here. + * v */ + for (; start != end; start = start->next) + { + strcat (copy_seg->text, start->text); + } + + /* See comment of outer loop. (3rd paragraph) */ + if (end == NULL) + { + break; + } + + copy_seg->next = malloc (sizeof (struct text_segment)); + + if (copy_seg->next == NULL) + { + set_status (status, E_ALLOC, 4, + "Memory allocation for SH_Text " + "failed.\n"); + + for (copy_seg = copy->data->next; + copy_seg != NULL; + copy->data = copy_seg, + copy_seg = copy_seg->next) + { + if (copy->data->text != NULL) + { + free (copy->data->text); + } + + free (copy->data); + } + free (copy->data); + + free (copy); + + return NULL; + } + + copy_seg = copy_seg->next; + copy_seg->next = NULL; + } + + /* This could be also moved inside the loop instead of the + * break, because the loop quits always by this break. + * Also see the comment of the outer loop above. */ + set_success (status); + + return copy; +} + +size_t +SH_Text_get_length (const struct SH_Text * text, + /*@null@*/ /*@out@*/ struct SH_Status * status) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/ +{ + size_t length; + const struct text_segment * seg; + + length = 0; + for (seg = text->data; seg != NULL; seg = seg->next) + { + if (SIZE_MAX - seg->length >= length) + { + length += seg->length; + } + else + { + set_status (status, E_DOMAIN, 6, + "SH_Text: length >= SIZE_MAX\n"); + + return SIZE_MAX; + } + } + + set_success (status); + + return length; +} + +/*@null@*/ +/*@only@*/ +char * +SH_Text_get_char (const struct SH_Text * text, + size_t index, + /*@null@*/ /*@out@*/ struct SH_Status * status) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/ +{ + char * character; + const struct text_segment * seg; + + /* find seg, where the index points to OR set seg to NULL */ + for (seg = text->data; (seg != NULL) && (index >= seg->length); + index -= seg->length, seg = seg->next); + + if (seg == NULL) + { + set_status (status, E_VALUE, 2, + "SH_Text: index out of range.\n"); + + return NULL; + } + + /* allocate char to be returned */ + character = malloc (sizeof (char)); + + if (character == NULL) + { + set_status (status, E_ALLOC, 4, + "Memory allocation for SH_Text failed.\n"); + + return NULL; + } + + /* set char */ + *character = seg->text[index]; + + set_success (status); + + return character; +} + +/*@null@*/ +/*@only@*/ +char * +SH_Text_get_string (const struct SH_Text * text, + size_t index, size_t offset, + /*@null@*/ /*@out@*/ size_t * length, + /*@null@*/ /*@out@*/ struct SH_Status * status) + /*@modifies length@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/ +{ + size_t len; + char * string; + const struct text_segment * start; + const struct text_segment * end; + + /* Determine the begin of the requested string. + * start: The segment where the requested string starts. + * index: The index of the first char relative to + the first segment. */ + for (start = text->data; + (start != NULL) && (index >= start->length); + start = start->next) + { + /* The subtraction is save, because this is, + * what is tested for in the condition. */ + index -= start->length; + } + + /* The end of text was encountered while looking for + * the start segment. Those the index is out of range. */ + if (start == NULL) + { + set_status (status, E_VALUE, 2, + "SH_Text: index out of range.\n"); + + if (length != NULL) + { + *length = 0; + } + + return NULL; + } + + /* The requested string is fully inside one segment. + * So set end and len offset appropriately. + * Note that offset isn't relative to the segment, + * but to index, but this is what we need, since we + * want to copy relative to index. */ + if ((offset < SIZE_MAX - index) + && (index + offset <= start->length)) + { + end = start; + len = offset; + } + + /* The requested string is in more than one segment. + * Find the segment of the text, where the last part of + * the string is contained and set offset relative to it. + * end: The segment where the last part of the string + * is located. + * offset: The remaining length of the string inside + * this last segment. + * + * Also the absolute length is needed for allocating the string + * and returning it. This would be the original value of offset, + * but it can not be set directly, because offset could be + * longer then the text actually is. Those both has to be set + * in each iteration over the text, till the last segment + * is encountered (the offset is smaller then the length of + * the segment). */ + else + { + /* skip the remaining of the start segment */ + /* The subtraction is save, because index is relative + * to the start segment (smaller then start->length). */ + len = start->length - index; + /* The subtraction is save, because this is the + * else branch. (offset + index > start->length) */ + offset -= len; + + /* Iterate over the text till the offset is inside + * the current segment. Actually the comparison has + * to be made against end->next, because, if offset + * points outside of the text, a pointer to the last + * segment has to be preserved. Otherwise we would + * have to iterate over the text another time. */ + for (end = start; + (end->next != NULL) && (offset > end->next->length); + end = end->next) + { + /* The subtraction is save because this is, + * what is tested for. + * The addition is save, because len will be + * equal or smaller then the original offset + * and this is also of size_t. Note that + * len = offset; + * is not possible in the first place, + * see the comment before the else branch. */ + len += end->next->length; + offset -= end->next->length; + } + + /* We have encountered the end of text. Set offset to + * the length of the last segment (making it smaller); + * end already points to the last (non-NULL) segment. */ + if (end->next == NULL) + { + offset = end->length; + } + /* The end of the requested string is inside the + * next segment. The variable offset is already + * relative to it, so just add it to the length. + * Also set end to the next segment, this can't + * be done earlier, because it may be NULL. + * (See comment before if.) */ + else + { + /* The addition is save, because len will be + * equal or smaller then the original offset + * and this is also of size_t. + * Note that len = offset is not possible in + * the first place, see the comment before + * the outer else branch. */ + len += offset; + end = end->next; + } + } + + /* Allocate the string to be returned. The multiplication is + * save, as long is sizeof (char) == 1. (Should be ...) */ + string = malloc ((len + 1) * sizeof (char)); + + /* Allocating has failed. Nothing has to be freed, because we + * just have some stack vars and pointers to segments. */ + if (string == NULL) + { + set_status (status, E_ALLOC, 6, + "Memory allocation for SH_Text failed.\n"); + + if (length != NULL) + { + *length = 0; + } + + return NULL; + } + + /* add terminating NULL byte. */ + string[0] = (char) 0; + + /* The requested string is fully inside one segment. */ + if (start == end) + { + strncat (string, start->text + index, offset); + } + /* The requested string is in more than one segment. */ + else + { + /* copy part of the start segment */ + strcat (string, start->text + index); + + /* copy all segments, that are contained in the + * requested string fully */ + for (start = start->next; start != end; + start = start->next) + { + strcat (string, start->text); + } + + /* copy part of the last segment */ + strncat (string, end->text, offset); + } + + + if (length != NULL) + { + *length = len; + } + + set_success (status); + + return string; +} + +/*@null@*/ +/*@only@*/ +char * +SH_Text_get_range (const struct SH_Text * text, + size_t start, size_t end, + /*@null@*/ /*@out@*/ size_t * length, + /*@null@*/ /*@out@*/ struct SH_Status * status) + /*@modifies length@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/ +{ + size_t len; + char * string; + const struct text_segment * start_seg; + const struct text_segment * end_seg; + + /* Determine the begin of the requested string. + * start_seg: The segment where the requested string starts. + * start: The index of the first char relative to + * the first segment. + * end: The index after the last char relative to + * the first segment */ + for (start_seg = text->data; + (start_seg != NULL) && (start >= start_seg->length); + start_seg = start_seg->next) + { + /* The subtraction is save, because this is, + * what is tested for in the condition. */ + start -= start_seg->length; + + /* The variable end has also to be adjusted, because + * otherwise we would have to start iterating at + * the beginning again. + * So this way it is more efficiently. + * + * The subtraction is save, because the end is always + * greater than start and the last was save also. */ + end -= start_seg->length; + } + + /* The end of text was encountered while looking for + * the start segment. Those the index is out of range. */ + if (start_seg == NULL) + { + set_status (status, E_VALUE, 2, + "SH_Text: index out of range.\n"); + + if (length != NULL) + { + *length = 0; + } + + return NULL; + } + + /* The requested string is fully inside one segment. + * So set end_seg and len appropriately; end is already + * relative to the first segment. */ + if (end <= start_seg->length) + { + end_seg = start_seg; + len = end - start; + } + + /* The requested string is in more than one segment. + * Find the segment of the text, where the last part of + * the string is contained and set end relative to it. + * end_seg: The segment where the last part of the string + * is located. + * end: The remaining length of the string inside + * this last segment. + * + * Also the absolute length is needed for allocating the string + * and returning it. This would be the original value of + * (end - start), but it can not be set directly, because end + * could be point outside of the text. Those both has to be set + * in each iteration over the text, till the last segment + * is encountered (the end is smaller then the length of + * the segment). */ + else + { + /* skip the remaining of the start segment */ + /* The subtraction is save, because start is relative + * to the start segment (start < start_seg->length). */ + len = start_seg->length - start; + /* The subtraction is save, because this is the + * else branch. (end > start->length) */ + end -= start_seg->length; + + /* Iterate over the text till the end is inside + * the current segment. Actually the comparison has + * to be made against end_seg->next, because, if end + * points outside of the text, a pointer to the last + * segment has to be preserved. Otherwise we would + * have to iterate over the text another time. */ + for (end_seg = start_seg; + (end_seg->next != NULL) + && (end > end_seg->next->length); + end_seg = end_seg->next) + { + /* The subtraction is save because this is, + * what is tested for. + * The addition is save, because len will be + * equal or smaller then the original + * (end - start) + * and they is also of size_t and end > start. + * Note that len = offset; is not possible + * in the first place, + * see the comment before the else branch. */ + len += end_seg->next->length; + end -= end_seg->next->length; + } + + /* We have encountered the end of text. Set end to + * the length of the last segment (making it smaller); + * end_seg already points to the last (non-NULL) + * segment. */ + if (end_seg->next == NULL) + { + end = end_seg->length; + } + /* The end of the requested string is inside the + * next segment. The variable end is already + * relative to it, so just add it to the length. + * Also set end_seg to the next segment, this can't + * be done earlier, because it may be NULL. + * (See comment before if.) */ + else + { + /* The addition is save, because len will be + * equal or smaller then the original + * (end - start) + * and they is also of size_t and end > start. + * Note that len = offset is not possible in + * the first place, see the comment before + * the outer else branch. */ + len += end; + end_seg = end_seg->next; + } + } + + /* Allocate the string to be returned. The multiplication is + * save, as long as sizeof (char) == 1. (Should be ...) */ + string = malloc ((len + 1) * sizeof (char)); + + /* Allocating has failed. Nothing has to be freed, because we + * just have some stack vars and pointers to segments. */ + if (string == NULL) + { + set_status (status, E_ALLOC, 6, + "Memory allocation for SH_Text failed.\n"); + + if (length != NULL) + { + *length = 0; + } + + return NULL; + } + + + /* add terminating NULL byte. */ + string[0] = (char) 0; + + /* The requested string is fully inside one segment. */ + if (start_seg == end_seg) + { + strncat (string, start_seg->text + start, len); + } + /* The requested string is in more than one segment. */ + else + { + /* copy part of the start segment */ + strcat (string, start_seg->text + start); + + /* copy all segments, that are contained in the + * requested string fully */ + for (start_seg = start_seg->next; start_seg != end_seg; + start_seg = start_seg->next) + { + strcat (string, start_seg->text); + } + + /* copy part of the last segment */ + strncat (string, end_seg->text, end); + } + + + if (length != NULL) + { + *length = len; + } + + set_success (status); + + return string; +} + +bool +SH_Text_append_string (struct SH_Text * text, const char * string, + /*@null@*/ /*@out@*/ struct SH_Status * status) + /*@modifies text->data@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/ +{ + size_t length; + size_t size; + char * new_text; + struct text_segment * seg; + + length = strlen (string); + + /* Fiddling around with more than one segment + * would be to cumbersome. */ + if (length == SIZE_MAX) + { + set_status (status, E_DOMAIN, 2, + "Maximum length of SH_Text reached.\n"); + + return FALSE; + } + + /* iterate to last segment + * This can't be done in the end, because it is tried + * to write the string to the last segment, if there + * is still enough space. */ + for (seg = text->data; seg->next != NULL; seg = seg->next); + + /* The string fits at the end of the last segment. */ + if (SIZE_MAX - seg->length > length) + { + length += seg->length; + } + /* It doesn't, so create a new segment after it. */ + else + { + seg->next = malloc (sizeof (struct text_segment)); + + if (seg->next == NULL) + { + set_status (status, E_ALLOC, 4, + "Memory allocation for " + "SH_Text data failed.\n"); + +/* useless assignment to silence splint */ +#ifdef S_SPLINT_S + seg->next = NULL; +#endif + + return FALSE; + } + } + + + /* Figure out how much memory has to be allocated + * in multiplies of chunk size. If this would overflow, + * just take the really needed size. */ + /* If both operands were integers, this operation would fail + * as the division will behave, like calling floor + * in the first place. */ + /* length + 1 is save, because at the last if + * we tested for > instead of >= */ + size = (size_t) ceilf ((float) (length+1) / (float) CHUNK_SIZE); + if (size > (SIZE_MAX / (float) CHUNK_SIZE)) + { + size = length + 1; + } + else + { + size *= CHUNK_SIZE; + } + + /* Enlarge the text. */ + if (seg->next == NULL) + { + new_text = realloc (seg->text, size * sizeof (char)); + } + /* If a new segment is made, there is also a new text */ + else + { + new_text = malloc (size * sizeof (char)); + } + + /* Allocation failed */ + if (new_text == NULL) + { + set_status (status, E_ALLOC, + (seg->next == NULL) ? 11: 6, + "Memory allocation for " + "SH_Text data failed.\n"); + + /* Clean-up, if new segment was to be made. */ + if (seg->next != NULL) + { + free (seg->next); + seg->next = NULL; + } + +/* useless assignment to silence splint */ +#ifdef S_SPLINT_S + seg->next = NULL; +#endif + + return FALSE; + } + + /* If a new text is made, add the terminating NULL to + * the string and switch to the new segment. */ + if (seg->next != NULL) + { + new_text[0] = (char) 0; + + seg = seg->next; + seg->next = NULL; + } + + /* Save string and write changes */ + seg->text = strcat (new_text, string); + seg->length = length; + seg->size = size; + + set_success (status); + + return TRUE; +} + +bool +SH_Text_append_text (struct SH_Text * text, + const struct SH_Text * text2, + /*@null@*/ /*@out@*/ struct SH_Status * status) + /*@modifies text->data@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/ +{ + struct SH_Text * copy; + struct text_segment * seg; + + copy = SH_Text_copy (text2, status); + + if (copy == NULL) + { + return FALSE; + } + + /* go to last segment */ + for (seg = text->data; seg->next != NULL; seg = seg->next); + + /* append */ + seg->next = copy->data; + + free (copy); + + return TRUE; +} + +void +SH_Text_join (struct SH_Text * text, + /*@only@*/ struct SH_Text * text2) + /*@modifies text->data@*/ + /*@modifies text2@*/ + /*@releases text2@*/ +{ + struct text_segment * seg; + + /* go to last segment */ + for (seg = text->data; seg->next != NULL; seg = seg->next); + + /* append contents */ + seg->next = text2->data; + + /* destroy text2 */ + free (text2); + + return; +} + +void +SH_Text_print (const struct SH_Text * text) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ +{ + const struct text_segment * seg; + + for (seg = text->data; seg != NULL; seg = seg->next) + { + printf ("%s", seg->text); + } + + return; +} diff --git a/src/lib/sefht/text.h b/src/lib/sefht/text.h new file mode 100644 index 0000000000000000000000000000000000000000..b4bfa9632e63eb8adefa0773319a57c836c9dd4d --- /dev/null +++ b/src/lib/sefht/text.h @@ -0,0 +1,141 @@ +/* + * text.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 SEFHT_TEXT_H +#define SEFHT_TEXT_H + +#if !defined (SEFHT_SEFHT_H_INSIDE) && !defined (SEFHT_COMPILATION) +#error "Only <sefht/sefht.h> can be included directly." +#endif + +#include <stdbool.h> + +#include "status.h" + + +typedef /*@abstract@*/ struct SH_Text SH_Text; + + +/*@null@*/ +/*@only@*/ +SH_Text * +SH_Text_new (/*@null@*/ /*@out@*/ struct SH_Status * status) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; + +/*@null@*/ +/*@only@*/ +SH_Text * +SH_Text_new_from_string (const char * string, + /*@null@*/ /*@out@*/ struct SH_Status * status) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; + +void +SH_Text_free (/*@only@*/ SH_Text * text) + /*@modifies text@*/ + /*@releases text@*/; + +/*@null@*/ +/*@only@*/ +SH_Text * +SH_Text_copy (const SH_Text * text, + /*@null@*/ /*@out@*/ struct SH_Status * status) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; + +size_t +SH_Text_get_length (const struct SH_Text * text, + /*@null@*/ /*@out@*/ struct SH_Status * status) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; + +/*@null@*/ +/*@only@*/ +char * +SH_Text_get_char (const SH_Text * text, + size_t index, + /*@null@*/ /*@out@*/ struct SH_Status * status) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; + +/*@null@*/ +/*@only@*/ +char * +SH_Text_get_string (const SH_Text * text, + size_t index, size_t offset, + /*@null@*/ /*@out@*/ size_t * length, + /*@null@*/ /*@out@*/ struct SH_Status * status) + /*@modifies length@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; + +/*@null@*/ +/*@only@*/ +char * +SH_Text_get_range (const SH_Text * text, + size_t start, size_t end, + /*@null@*/ /*@out@*/ size_t * length, + /*@null@*/ /*@out@*/ struct SH_Status * status) + /*@modifies length@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; + +bool +SH_Text_append_string (SH_Text * text, const char * string, + /*@null@*/ /*@out@*/ struct SH_Status * status) + /*@modifies text@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; + +bool +SH_Text_append_text (SH_Text * text, + const SH_Text * text2, + /*@null@*/ /*@out@*/ struct SH_Status * status) + /*@modifies text@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; + +void +SH_Text_join (SH_Text * text, + /*@only@*/ SH_Text * text2) + /*@modifies text@*/ + /*@modifies text2@*/ + /*@releases text2@*/; + +void +SH_Text_print (const SH_Text * text) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/; + +#endif /* SEFHT_TEXT_H */ diff --git a/src/lib/sefht/validator.c b/src/lib/sefht/validator.c new file mode 100644 index 0000000000000000000000000000000000000000..9c6ad8ce01b8e40816f7518757dcff4067447b93 --- /dev/null +++ b/src/lib/sefht/validator.c @@ -0,0 +1,131 @@ +/* + * validator.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 <stdlib.h> + +#include "log.h" +#include "status.h" + +#include "validator.h" + + +/* "validator_tag.c" is included twice, + * because TAG_DATA must be defined, + * before SH_VAlidator can be defined, + * but SH_Validator must be defined, + * before the functions in "validator_tag.c" + * can use the definition, which themselves + * are needed before the functions in this + * file can be defined. */ +#include "validator_tag.c" +struct SH_Validator +{ + TAG_DATA +}; + +#define VALIDATOR_IS_DEFINED +#include "validator_tag.c" + + +/*@null@*/ +/*@only@*/ +struct SH_Validator * +SH_Validator_new (/*@null@*/ /*@out@*/ struct SH_Status * status) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/ +{ + struct SH_Validator * validator; + validator = malloc (sizeof (struct SH_Validator)); + + if (validator == NULL) + { + set_status (status, E_ALLOC, 4, + "Memory allocation for " + "SH_Validator failed.\n"); + + return NULL; + } + + 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; +} + +/*@null@*/ +/*@only@*/ +struct SH_Validator * +SH_Validator_copy (const struct SH_Validator * validator, + /*@null@*/ /*@out@*/ struct SH_Status * status) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/ +{ + struct SH_Validator * copy; + copy = malloc (sizeof (struct SH_Validator)); + + if (copy == NULL) + { + set_status (status, E_ALLOC, 4, + "Memory allocation for " + "SH_Validator failed.\n"); + + return NULL; + } + + if (!copy_tags (copy, validator, status)) + { +/* dangerous call to silence splint, should never be executed. */ +#ifdef S_SPLINT_S + free (copy->tags); +#endif + free (copy); + return NULL; + } + + set_success (status); + + return copy; +} + +void +SH_Validator_free (/*@only@*/ struct SH_Validator * validator) + /*@modifies validator@*/ + /*@releases validator@*/ +{ + free_tags (validator); + free (validator); + + return; +} diff --git a/src/lib/sefht/validator.h b/src/lib/sefht/validator.h new file mode 100644 index 0000000000000000000000000000000000000000..55de52ab711b8b9957d4d5e3d8ca326c2e9348d4 --- /dev/null +++ b/src/lib/sefht/validator.h @@ -0,0 +1,65 @@ +/* + * validator.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 SEFHT_VALIDATOR_H +#define SEFHT_VALIDATOR_H + +#if !defined (SEFHT_SEFHT_H_INSIDE) && !defined (SEFHT_COMPILATION) +#error "Only <sefht/sefht.h> can be included directly." +#endif + +#include "status.h" + + +typedef struct SH_Validator SH_Validator; + +#define __VALIDATOR_H_INSIDE__ +#include "validator_tag.h" +#undef __VALIDATOR_H_INSIDE__ + + +/*@null@*/ +/*@only@*/ +SH_Validator * +SH_Validator_new (/*@null@*/ /*@out@*/ struct SH_Status * status) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; + +/*@null@*/ +/*@only@*/ +SH_Validator * +SH_Validator_copy (const SH_Validator * validator, + /*@null@*/ /*@out@*/ struct SH_Status * status) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; + +void +SH_Validator_free (/*@only@*/ struct SH_Validator * validator) + /*@modifies validator@*/ + /*@releases validator@*/; + + +#endif /* SEFHT_VALIDATOR_H */ diff --git a/src/lib/sefht/validator_tag.c b/src/lib/sefht/validator_tag.c new file mode 100644 index 0000000000000000000000000000000000000000..887b996c54ce188f6acc159ab5f08ab76552b447 --- /dev/null +++ b/src/lib/sefht/validator_tag.c @@ -0,0 +1,663 @@ +/* + * 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" + + +#ifndef VALIDATOR_IS_DEFINED + +#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; \ + +#else /* VALIDATOR_IS_DEFINED */ + +static inline +bool +init_tags (/*@special@*/ struct SH_Validator * validator, + /*@null@*/ /*@out@*/ struct SH_Status * status) + /*@defines validator->tags, + validator->tag_n, + validator->last_tag@*/ + /*@modifies validator->tags@*/ + /*@modifies validator->tag_n@*/ + /*@modifies validator->last_tag@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; + +static inline +bool +copy_tags (/*@special@*/ struct SH_Validator * copy, + const struct SH_Validator * validator, + /*@null@*/ /*@out@*/ struct SH_Status * status) + /*@defines copy->tags, + copy->tag_n, + copy->last_tag@*/ + /*@modifies copy->tags@*/ + /*@modifies copy->tag_n@*/ + /*@modifies copy->last_tag@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; + +static inline +void +free_tags (/*@special@*/ struct SH_Validator * validator) + /*@modifies validator->tags@*/ + /*@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) + /*@modifies validator->tags@*/ + /*@modifies validator->tag_n@*/ + /*@modifies validator->last_tag@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; + +/*@unused@*/ +static inline +bool +is_tag_id (const struct SH_Validator * validator, Tag id) + /*@*/; + +static inline +bool +is_tag_name (const struct SH_Validator * validator, const char * name) + /*@*/; + +/*@unused@*/ +static inline +/*@null@*/ +/*@only@*/ +char * +get_tag_name_by_id (const struct SH_Validator * validator, Tag id, + /*@null@*/ /*@out@*/ struct SH_Status * status) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; + +static inline +Tag +get_tag_id_by_name (const struct SH_Validator * validator, + const char * name) + /*@*/; + +static inline +bool +remove_tag (struct SH_Validator * validator, Tag id, + /*@null@*/ /*@out@*/ struct SH_Status * status) + /*@modifies validator->tag_n@*/ + /*@modifies validator->tags@*/ + /*@modifies validator->last_tag@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; + + +#define EXECUTE_ON_ALL_TAGS_IF(ITER, CONDITION, BLOCK) \ +do \ +{ \ + bool is_free; \ + size_t index; \ + size_t free_index; \ + \ + for (index = (size_t) 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; \ + \ + /*@innerbreak@*/ \ + break; \ + } \ + } \ + \ + if (!is_free && CONDITION) BLOCK \ + } \ +} \ +while (FALSE) + +#define EXECUTE_ON_ALL_TAGS(BASE, BLOCK) \ + EXECUTE_ON_ALL_TAGS_IF (BASE, TRUE, BLOCK) + + +static inline +bool +init_tags (/*@special@*/ struct SH_Validator * validator, + /*@null@*/ /*@out@*/ struct SH_Status * status) + /*@defines validator->tags, + validator->tag_n, + validator->last_tag@*/ + /*@modifies validator->tags@*/ + /*@modifies validator->tag_n@*/ + /*@modifies validator->last_tag@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/ +{ + validator->tags = malloc (sizeof (struct tag_info)); + if (validator->tags == NULL) + { + set_status (status, E_ALLOC, 3, "malloc failed"); + + validator->tag_n = 0; + validator->last_tag = TAG_ERR; + return FALSE; + } + + validator->tags[0].next = 0; + validator->tag_n = 0; + validator->last_tag = TAG_ERR; + + return TRUE; +} + +static inline +bool +copy_tags (/*@special@*/ struct SH_Validator * copy, + const struct SH_Validator * validator, + /*@null@*/ /*@out@*/ struct SH_Status * status) + /*@defines copy->tags, + copy->tag_n, + copy->last_tag@*/ + /*@modifies copy->tags@*/ + /*@modifies copy->tag_n@*/ + /*@modifies copy->last_tag@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies 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"); + + copy->tag_n = 0; + copy->last_tag = TAG_ERR; + 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 = (size_t) 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; + + /*@innerbreak@*/ + 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) + /*@modifies validator->tags@*/ + /*@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) + /*@modifies validator->tags@*/ + /*@modifies validator->tag_n@*/ + /*@modifies validator->last_tag@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies 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 (const 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 (const 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@*/ +/*@only@*/ +char * +get_tag_name_by_id (const struct SH_Validator * validator, Tag id, + /*@null@*/ /*@out@*/ struct SH_Status * status) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies 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 (const 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) + /*@modifies validator->tag_n@*/ + /*@modifies validator->tags@*/ + /*@modifies validator->last_tag@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies 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; + + /*@innerbreak@*/ + 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 +/*@alt void@*/ +SH_Validator_register_tag (struct SH_Validator * validator, + const char * tag, + /*@null@*/ /*@out@*/ + struct SH_Status * status) + /*@modifies validator->tags@*/ + /*@modifies validator->tag_n@*/ + /*@modifies validator->last_tag@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies 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) + /*@modifies validator->tag_n@*/ + /*@modifies validator->tags@*/ + /*@modifies validator->last_tag@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/ +{ + return remove_tag (validator, id, status); +} + +#endif /* VALIDATOR_IS_DEFINED */ diff --git a/src/lib/sefht/validator_tag.h b/src/lib/sefht/validator_tag.h new file mode 100644 index 0000000000000000000000000000000000000000..185ff88b2e250e64c222d4e9ef62598115450bdc --- /dev/null +++ b/src/lib/sefht/validator_tag.h @@ -0,0 +1,70 @@ +/* + * 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 SEFHT_VALIDATOR_TAG_H +#define SEFHT_VALIDATOR_TAG_H + +#if !defined (SEFHT_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 + + +Tag +/*@alt void@*/ +SH_Validator_register_tag (SH_Validator * validator, + const char * tag, + /*@null@*/ /*@out@*/ + struct SH_Status * status) + /*@modifies validator@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; + +bool +SH_Validator_deregister_tag (SH_Validator * validator, + Tag id, + /*@null@*/ /*@out@*/ + struct SH_Status * status) + /*@modifies validator@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; + +bool +SH_Validator_check_tag (struct SH_Validator * validator, + const char * tag) + /*@*/; + +#endif /* SEFHT_VALIDATOR_TAG_H */ diff --git a/src/main.c b/src/main.c index 95c0d761ae5dc9f61e1cbe7dd9ec51308ccccea6..c869541b2bbe466d5a96aea7c6e45e4a22208490 100644 --- a/src/main.c +++ b/src/main.c @@ -23,32 +23,33 @@ #include <stdio.h> -#include "cms.h" -#include "data.h" -#include "fragment.h" -#include "node_fragment.h" -#include "text.h" +#include <stdlib.h> + +#include <sefht/sefht.h> int main(int argc, char **argv) { page_t page; /* startup */ - struct SH_Cms * cms = SH_Cms_new (NULL); + SH_Cms * cms = SH_Cms_new (NULL); /* startup */ page = SH_Cms_register_page (cms, "Startpage", NULL); /* shutdown */ - SH_Cms_free (cms, NULL); + SH_Cms_free (cms); /* shutdown */ + (void) argc; + (void) argv; + (void) page; - struct SH_Data * data; - struct SH_Fragment * root; - struct SH_Fragment * child1; - struct SH_Fragment * child2; - struct SH_Text * text; + SH_Data * data; + SH_Fragment * root; + SH_Fragment * child1; + SH_Fragment * child2; + SH_Text * text; data = SH_Data_new (NULL); @@ -80,20 +81,20 @@ int main(int argc, char **argv) child2, NULL); text = SH_Fragment_to_html (root, WRAP, 0, 1, INDENT_TEXT, NULL); + SH_Text_print (text); + printf ("\n"); - printf ("%s\n", text->text); - - SH_Text_free (text, NULL); + SH_Text_free (text); text = SH_Fragment_to_html (root, INLINE, 0, 1, INDENT_TEXT, NULL); + SH_Text_print (text); + printf ("\n"); - printf ("%s\n", text->text); - - SH_Text_free (text, NULL); + SH_Text_free (text); - SH_Fragment_free (root, NULL); + SH_Fragment_free (root); - SH_Data_free (data, NULL); + SH_Data_free (data); return 0; } diff --git a/src/node_fragment.c b/src/node_fragment.c deleted file mode 100644 index 58d93ff392a1fda5e2bb47496fa6078693ef71db..0000000000000000000000000000000000000000 --- a/src/node_fragment.c +++ /dev/null @@ -1,596 +0,0 @@ -/* - * node_fragment.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 <errno.h> -#include <stdbool.h> -#include <stdlib.h> -#include <string.h> - -#include "macro.h" -#include "error.h" -#include "log.h" - -#include "data.h" -#include "text.h" -#include "validator.h" - -#include "fragment.h" - -#include "node_fragment.h" - - -static const struct fragment_methods methods = { - (struct SH_Fragment * (*)(struct SH_Fragment *, - struct SH_Error *)) - SH_NodeFragment_deepcopy, - - (void (*)(struct SH_Fragment *, struct SH_Error *)) - SH_NodeFragment_free, - - (struct SH_Text * (*)(struct SH_Fragment *, enum HTML_MODE, - unsigned int, unsigned int, const char *, - struct SH_Error *)) - SH_NodeFragment_to_html -}; - - -struct SH_Fragment * -SH_NodeFragment_new (const char * tag, struct SH_Data * data, - struct SH_Error * error) -{ - struct SH_NodeFragment * fragment; - - if (!SH_Validator_check_tag (data->validator, tag)) - { - ERROR2 ("Tag %s is'nt valid.\n", tag); - - if (error != NULL) - { - error->type = VALUE_ERROR; - } - - return NULL; - } - - fragment = malloc (sizeof (struct SH_NodeFragment)); - if (fragment == NULL) - { - ERROR1 ("Memory allocation for " - "SH_NodeFragment failed.\n"); - - if (error != NULL) - { - error->type = ALLOCATION_FAILED; - } - - return NULL; - } - - init_fragment (&(fragment->base), data, NODE, &methods); - - fragment->tag = strdup (tag); - if (errno == ENOMEM) - { - ERROR1 ("Memory allocation for fragment tag failed.\n"); - - if (error != NULL) - { - error->type = ALLOCATION_FAILED; - } - - free (fragment); - - return NULL; - } - - - fragment->child_n = 0; - fragment->childs = malloc (0); - - if (error != NULL) - { - error->type = SUCCESS; - } - - return (struct SH_Fragment *) fragment; -} - -void -SH_NodeFragment_free (struct SH_NodeFragment * fragment, - struct SH_Error * error) -{ - size_t index; - - free (fragment->tag); - - for (index = 0; index < fragment->child_n; index++) - { - SH_Fragment_free (fragment->childs[index], error); - } - free (fragment->childs); - - free_fragment (&fragment->base); - - free (fragment); - - if (error != NULL) - { - error->type = SUCCESS; - } - - return; -} - -struct SH_Fragment * -SH_NodeFragment_copy (struct SH_NodeFragment * fragment, - struct SH_Error * error) -{ - struct SH_NodeFragment * copy; - - copy = malloc (sizeof (struct SH_NodeFragment)); - if (copy == NULL) - { - ERROR1 ("Memory allocation for " - "SH_NodeFragment failed.\n"); - - if (error != NULL) - { - error->type = ALLOCATION_FAILED; - } - - return NULL; - } - - copy_fragment (&(copy->base), &(fragment->base)); - - copy->tag = strdup (fragment->tag); - if (errno == ENOMEM) - { - ERROR1 ("Memory allocation for fragment tag failed.\n"); - - if (error != NULL) - { - error->type = ALLOCATION_FAILED; - } - - free (copy); - - return NULL; - } - - - copy->child_n = 0; - copy->childs = malloc (0); - - if (error != NULL) - { - error->type = SUCCESS; - } - - return (struct SH_Fragment *) copy; -} - -struct SH_Fragment * -SH_NodeFragment_deepcopy (struct SH_NodeFragment * fragment, - struct SH_Error * error) -{ - struct SH_NodeFragment * copy; - struct SH_Fragment * child; - size_t index; - - copy = malloc (sizeof (struct SH_NodeFragment)); - if (copy == NULL) - { - ERROR1 ("Memory allocation for " - "SH_NodeFragment failed.\n"); - - if (error != NULL) - { - error->type = ALLOCATION_FAILED; - } - - return NULL; - } - - copy_fragment (&(copy->base), &(fragment->base)); - - copy->tag = strdup (fragment->tag); - if (errno == ENOMEM) - { - ERROR1 ("Memory allocation for fragment tag failed.\n"); - - if (error != NULL) - { - error->type = ALLOCATION_FAILED; - } - - free (copy); - - return NULL; - } - - - copy->child_n = fragment->child_n; - copy->childs = malloc (sizeof (struct SH_NodeFragment *) - * fragment->child_n); - - if (copy->child_n != 0 && copy->childs == NULL) - { - ERROR1 ("Memory allocation for fragment child failed.\n"); - - if (error != NULL) - { - error->type = ALLOCATION_FAILED; - } - - free (copy->tag); - free (copy); - - return NULL; - } - - for (index = 0; index < fragment->child_n; index++) - { - child = SH_Fragment_copy (fragment->childs[index], - error); - - if (child == NULL) - { - copy->child_n = index; - SH_NodeFragment_free (copy, NULL); - - return NULL; - } - - copy->childs[index] = child; - } - - if (error != NULL) - { - error->type = SUCCESS; - } - - return (struct SH_Fragment *) copy; -} - -bool -SH_Fragment_is_NodeFragment (struct SH_Fragment * fragment) -{ - return get_type (fragment) == NODE; -} - -char * -SH_NodeFragment_get_tag (struct SH_NodeFragment * fragment, - struct SH_Error * error) -{ - char * tag; - - tag = strdup (fragment->tag); - - if (errno == ENOMEM) - { - ERROR1 ("Memory allocation for fragment tag failed.\n"); - - if (error != NULL) - { - error->type = ALLOCATION_FAILED; - } - - return NULL; - } - - if (error != NULL) - { - error->type = SUCCESS; - } - - return tag; -} - -struct SH_Fragment * -SH_NodeFragment_get_child (struct SH_NodeFragment * fragment, size_t index, - struct SH_Error * error) -{ - if (index >= fragment->child_n) - { - ERROR1 ("Fragment: Child index out of range.\n"); - - if (error != NULL) - { - error->type = VALUE_ERROR; - } - - return NULL; - } - - if (error != NULL) - { - error->type = SUCCESS; - } - - return fragment->childs[index]; -} - -bool -SH_NodeFragment_is_child (struct SH_NodeFragment * fragment, - struct SH_Fragment * child) -{ - size_t index; - - for (index = 0; index < fragment->child_n; index++) - { - if (fragment->childs[index] == child) - { - return TRUE; - } - } - return FALSE; -} - -bool -SH_NodeFragment_is_descendant (struct SH_NodeFragment * fragment, - struct SH_Fragment * child) -{ - size_t index; - - for (index = 0; index < fragment->child_n; index++) - { - if (fragment->childs[index] == child - || (SH_Fragment_is_NodeFragment (child) - && SH_NodeFragment_is_descendant ( - (struct SH_NodeFragment *) - fragment->childs[index], - child))) - { - return TRUE; - } - } - return FALSE; -} - -bool -SH_NodeFragment_append_child (struct SH_NodeFragment * fragment, - struct SH_Fragment * child, - struct SH_Error * error) -{ - fragment->childs = realloc (fragment->childs, - sizeof (struct SH_Fragment *) - * (fragment->child_n + 1)); - - if (errno == ENOMEM) - { - ERROR1 ("Memory allocation for fragment child failed.\n"); - - if (error != NULL) - { - error->type = ALLOCATION_FAILED; - } - - return FALSE; - } - - fragment->childs[fragment->child_n] = child; - fragment->child_n++; - - if (error != NULL) - { - error->type = SUCCESS; - } - - return TRUE; -} - -struct SH_Text * -SH_NodeFragment_to_html (struct SH_NodeFragment * fragment, - enum HTML_MODE mode, - unsigned int indent_base, - unsigned int indent_step, - char * indent_char, - struct SH_Error * error) -{ - struct SH_Text * html; - struct SH_Text * child; - struct SH_Text * indent_text; - size_t index; - - html = SH_Text_new (error); - if (error != NULL && error->type != SUCCESS) - { - return NULL; - } - - if (mode == WRAP) - { - indent_text = SH_Text_new (error); - if (indent_text == NULL) - { - SH_Text_free (html, NULL); - return NULL; - } - - for (index = 0; index < indent_base; index++) - { - if (!SH_Text_append_string (indent_text, - indent_char, error)) - { - SH_Text_free (html, NULL); - SH_Text_free (indent_text, NULL); - return NULL; - } - } - - if (!SH_Text_append_text (html, indent_text, error)) - { - SH_Text_free (html, NULL); - SH_Text_free (indent_text, NULL); - return NULL; - } - } - - if (!SH_Text_append_string (html, OPEN_TAG_BEGIN, error)) - { - SH_Text_free (html, NULL); - - if (mode == WRAP) - { - SH_Text_free (indent_text, NULL); - } - - return NULL; - } - - if (!SH_Text_append_string (html, fragment->tag, error)) - { - SH_Text_free (html, NULL); - - if (mode == WRAP) - { - SH_Text_free (indent_text, NULL); - } - - return NULL; - } - - if (!SH_Text_append_string (html, OPEN_TAG_END, error)) - { - SH_Text_free (html, NULL); - - if (mode == WRAP) - { - SH_Text_free (indent_text, NULL); - } - - return NULL; - } - - if (mode == WRAP) - { - if (!SH_Text_append_string (html, NEWLINE, error)) - { - SH_Text_free (html, NULL); - SH_Text_free (indent_text, NULL); - return NULL; - } - } - - for (index = 0; index < fragment->child_n; index++) - { - child = SH_Fragment_to_html (fragment->childs[index], - mode, - indent_base + indent_step, - indent_step, - indent_char, - error); - - if (child == NULL) - { - SH_Text_free (html, NULL); - - if (mode == WRAP) - { - SH_Text_free (indent_text, NULL); - } - - return NULL; - } - - if (!SH_Text_join (html, child, error)) - { - SH_Text_free (html, NULL); - SH_Text_free (child, NULL); - - if (mode == WRAP) - { - SH_Text_free (indent_text, NULL); - } - - return NULL; - } - } - - if (mode == WRAP) - { - if (!SH_Text_append_text (html, indent_text, error)) - { - SH_Text_free (html, NULL); - SH_Text_free (indent_text, NULL); - return NULL; - } - } - - if (!SH_Text_append_string (html, CLOSE_TAG_BEGIN, error)) - { - SH_Text_free (html, NULL); - - if (mode == WRAP) - { - SH_Text_free (indent_text, NULL); - } - - return NULL; - } - - if (!SH_Text_append_string (html, fragment->tag, error)) - { - SH_Text_free (html, NULL); - - if (mode == WRAP) - { - SH_Text_free (indent_text, NULL); - } - - return NULL; - } - - if (!SH_Text_append_string (html, CLOSE_TAG_END, error)) - { - SH_Text_free (html, NULL); - - if (mode == WRAP) - { - SH_Text_free (indent_text, NULL); - } - - return NULL; - } - - if (mode == WRAP) - { - if (!SH_Text_append_string (html, NEWLINE, error)) - { - SH_Text_free (html, NULL); - SH_Text_free (indent_text, NULL); - return NULL; - } - - SH_Text_free (indent_text, NULL); - } - - if (error != NULL) - { - error->type = SUCCESS; - } - - return html; -} diff --git a/src/node_fragment.h b/src/node_fragment.h deleted file mode 100644 index fecfafe6f108d1163d92126f2abcf2c9b614df82..0000000000000000000000000000000000000000 --- a/src/node_fragment.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * node_fragment.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 _NODE_FRAGMENT_H -#define _NODE_FRAGMENT_H - -#include "data.h" -#include "text.h" - -#include "fragment.h" - - -struct SH_NodeFragment; -struct SH_NodeFragment -{ - struct SH_Fragment base; - - char * tag; - - size_t child_n; - struct SH_Fragment ** childs; -}; - -#define OPEN_TAG_BEGIN "<" -#define OPEN_TAG_END ">" -#define CLOSE_TAG_BEGIN "</" -#define CLOSE_TAG_END ">" - -#define INDENT_TEXT "\t" -#define NEWLINE "\n" - -struct SH_Fragment * -SH_NodeFragment_new (const char * tag, - struct SH_Data * data, - struct SH_Error * error); - -void -SH_NodeFragment_free (struct SH_NodeFragment * fragment, - struct SH_Error * error); - -struct SH_Fragment * -SH_NodeFragment_copy (struct SH_NodeFragment * fragment, - struct SH_Error * error); - -struct SH_Fragment * -SH_NodeFragment_deepcopy (struct SH_NodeFragment * fragment, - struct SH_Error * error); - -bool -SH_Fragment_is_NodeFragment (struct SH_Fragment * fragment); - -char * -SH_NodeFragment_get_tag (struct SH_NodeFragment * fragment, - struct SH_Error * error); - -struct SH_Fragment * -SH_NodeFragment_get_child (struct SH_NodeFragment * fragment, - size_t index, - struct SH_Error * error); - -bool -SH_NodeFragment_is_child (struct SH_NodeFragment * fragment, - struct SH_Fragment * child); - -bool -SH_NodeFragment_is_descendant (struct SH_NodeFragment * fragment, - struct SH_Fragment * child); - -bool -SH_NodeFragment_append_child (struct SH_NodeFragment * fragment, - struct SH_Fragment * child, - struct SH_Error * error); - -struct SH_Text * -SH_NodeFragment_to_html (struct SH_NodeFragment * fragment, - enum HTML_MODE mode, - unsigned int indent_base, - unsigned int indent_step, - char * indent_char, - struct SH_Error * error); - -#endif /* _NODE_FRAGMENT_H */ diff --git a/src/text.c b/src/text.c deleted file mode 100644 index 33d88cf0e6948a4f0201135feb22b66fad9c69c1..0000000000000000000000000000000000000000 --- a/src/text.c +++ /dev/null @@ -1,236 +0,0 @@ -/* - * text.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 <errno.h> -#include <math.h> -#include <stdbool.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> - -#include "macro.h" -#include "error.h" -#include "log.h" - -#include "text.h" - - -struct SH_Text * -SH_Text_new (struct SH_Error * error) -{ - struct SH_Text * text; - text = malloc (sizeof (struct SH_Text)); - - if (text == NULL) - { - ERROR1 ("Memory allocation for SH_Text failed.\n"); - - if (error != NULL) - { - error->type = ALLOCATION_FAILED; - } - - return NULL; - } - - text->length = 0; - text->text = malloc (CHUNK_SIZE * sizeof (char)); - - if (text->text == NULL) - { - ERROR1 ("Memory allocation for SH_Text failed.\n"); - - if (error != NULL) - { - error->type = ALLOCATION_FAILED; - } - - free (text); - - return NULL; - } - - text->text[0] = 0; - text->size = CHUNK_SIZE; - - if (error != NULL) - { - error->type = SUCCESS; - } - - return text; -} - -void -SH_Text_free (struct SH_Text * text, struct SH_Error * error) -{ - free (text->text); - - free (text); - - if (error != NULL) - { - error->type = SUCCESS; - } - - return; -} - -bool -SH_Text_enlarge (struct SH_Text * text, size_t size, - struct SH_Error * error) -{ - size_t new_size; - - if (size <= text->size) - { - if (error != NULL) - { - error->type = SUCCESS; - } - return TRUE; - } - - /* if both operands were integers, - * this operation would fail - * as the division will behave like - * calling floor in the first place. */ - new_size = (size_t) ceilf ((float) size / (float) CHUNK_SIZE); - if (new_size >= (SIZE_MAX / (float) CHUNK_SIZE)) - { - ERROR1 ("Maximum length of SH_Text reached.\n"); - - if (error != NULL) - { - error->type = DOMAIN_ERROR; - } - - return FALSE; - } - - new_size *= CHUNK_SIZE; - text->text = realloc (text->text, new_size * sizeof (char)); - - if (errno == ENOMEM) - { - ERROR1 ("Memory allocation for SH_Text data failed.\n"); - - if (error != NULL) - { - error->type = ALLOCATION_FAILED; - } - - return FALSE; - } - - text->size = new_size; - - if (error != NULL) - { - error->type = SUCCESS; - } - - return TRUE; -}; - -bool -SH_Text_append_string (struct SH_Text * text, char * string, - struct SH_Error * error) -{ - size_t length; - - length = strlen (string); - - if (((SIZE_MAX - length) == 0) - || ((SIZE_MAX - length - 1) < text->length)) - { - ERROR1 ("Maximum length of SH_Text reached.\n"); - - if (error != NULL) - { - error->type = DOMAIN_ERROR; - } - - return FALSE; - } - - if (!SH_Text_enlarge (text, text->length + length + 1, error)) - { - return FALSE; - } - - text->text = strcat (text->text, string); - - /* this is save as text->size is always at least one greater - * and SH_Text_enlarge hasn't failed. */ - text->length += length; - - return TRUE; -} - -bool -SH_Text_append_text (struct SH_Text * text, struct SH_Text * text2, - struct SH_Error * error) -{ - if (((SIZE_MAX - text->length) == 0) - || ((SIZE_MAX - text->length - 1) < text2->length)) - { - ERROR1 ("Maximum length of SH_Text reached.\n"); - - if (error != NULL) - { - error->type = DOMAIN_ERROR; - } - - return FALSE; - } - - if (!SH_Text_enlarge (text, text->length + text2->length + 1, - error)) - { - return FALSE; - } - - text->text = strcat (text->text, text2->text); - - /* this is save as text->size is always at least one greater - * and SH_Text_enlarge hasn't failed. */ - text->length += text2->length; - - return TRUE; -} - -bool -SH_Text_join (struct SH_Text * text, struct SH_Text * text2, - struct SH_Error * error) -{ - if (!SH_Text_append_text (text, text2, error)) - { - return FALSE; - } - - SH_Text_free (text2, error); - - return TRUE; -} diff --git a/src/text.h b/src/text.h deleted file mode 100644 index 8c6bfb6041cbd2cafc4efe1cb21ff5589d4dde2a..0000000000000000000000000000000000000000 --- a/src/text.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * text.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 _TEXT_H -#define _TEXT_H - -#include <stdbool.h> - -#include "error.h" - - -#define CHUNK_SIZE 64 - -struct SH_Text -{ - size_t length; - size_t size; - char * text; -}; - -struct SH_Text * SH_Text_new (struct SH_Error * error); -void SH_Text_free (struct SH_Text * text, struct SH_Error * error); - -bool SH_Text_enlarge (struct SH_Text * text, size_t size, - struct SH_Error * error); - -bool SH_Text_append_string (struct SH_Text * text, char * string, - struct SH_Error * error); - -bool SH_Text_append_text (struct SH_Text * text, struct SH_Text * text2, - struct SH_Error * error); - -bool SH_Text_join (struct SH_Text * text, struct SH_Text * text2, - struct SH_Error * error); - -#endif /* _TEXT_H */ diff --git a/src/validator.c b/src/validator.c deleted file mode 100644 index c52c2554bd86fb73bff90983c76fd334bdbabb56..0000000000000000000000000000000000000000 --- a/src/validator.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - * validator.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 <errno.h> -#include <stdbool.h> -#include <stdlib.h> -#include <string.h> - -#include "macro.h" -#include "error.h" -#include "log.h" - -#include "validator.h" - - -static inline void init_tags (struct SH_Validator * validator); - -struct SH_Validator * -SH_Validator_new (struct SH_Error * error) -{ - struct SH_Validator * validator; - validator = malloc (sizeof (struct SH_Validator)); - - if (validator == NULL) - { - ERROR1 ("Memory allocation for SH_Validator failed.\n"); - - if (error != NULL) - { - error->type = ALLOCATION_FAILED; - } - - return NULL; - } - - init_tags (validator); - - if (error != NULL) - { - error->type = SUCCESS; - } - - return validator; -} - -static inline void free_tags (struct SH_Validator * validator); - -void -SH_Validator_free (struct SH_Validator * validator, - struct SH_Error * error) -{ - free_tags (validator); - free (validator); - - if (error != NULL) - { - error->type = SUCCESS; - } - - 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) -{ - unsigned int index; - - for (index = 0; index < validator->tag_n; index++) - { - free (validator->tags[index].name); - } - - free (validator->tags); - return; -} - - -static inline tag_t -SH_Validator_get_tag (struct SH_Validator * validator, const char * tag) -{ - unsigned int index; - - for (index = 0; index < validator->tag_n; index++) - { - if (strcmp (validator->tags[index].name, tag) == 0) - { - return validator->tags[index].id; - } - } - - return TAG_ERR; -} - -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; - } -} - -tag_t -SH_Validator_register_tag (struct SH_Validator * validator, - const char * tag, struct SH_Error * error) -{ - 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) - { - ERROR1 ("Maximum number of tags reached.\n"); - - if (error != NULL) - { - error->type = DOMAIN_ERROR; - } - - return TAG_ERR; - } - - validator->tags = realloc (validator->tags, - (validator->tag_n + 1) * sizeof (struct SH_Tag)); - - if (errno == ENOMEM) - { - ERROR1 ("Memory allocation for tag failed.\n"); - - if (error != NULL) - { - error->type = ALLOCATION_FAILED; - } - - 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 (errno == ENOMEM) - { - ERROR1 ("Memory allocation for tag failed.\n"); - - if (error != NULL) - { - error->type = ALLOCATION_FAILED; - } - - return TAG_ERR; - } - - validator->tag_n++; - - if (error != NULL) - { - error->type = SUCCESS; - } - - return validator->last_tag; -} diff --git a/src/validator.h b/src/validator.h deleted file mode 100644 index f0fd7beca52d4dd695271471c1bf1dfeb547ccc3..0000000000000000000000000000000000000000 --- a/src/validator.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * validator.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_H -#define _VALIDATOR_H - -#include <limits.h> -#include <stdbool.h> - - -typedef unsigned int tag_t; -#define TAG_ERR 0 -#define TAG_MIN 1 -#define TAG_MAX UINT_MAX -#define NEXT_TAG(tag) tag++ - -struct SH_Tag -{ - tag_t id; - char * name; -}; - -struct SH_Validator -{ - unsigned int tag_n; - struct SH_Tag * tags; - tag_t last_tag; -}; - -struct SH_Validator * SH_Validator_new (struct SH_Error * error); -void SH_Validator_free (struct SH_Validator * validator, - struct SH_Error * error); - -tag_t SH_Validator_register_tag (struct SH_Validator * validator, - const char * tag, - struct SH_Error * error); - - -bool SH_Validator_check_tag (struct SH_Validator * validator, - const char * tag); - -#endif /* _VALIDATOR_H */ diff --git a/tests/Makefile.am b/tests/Makefile.am index 611f18abaa14ecaa588a25c074f0c29c9b0e8cd0..3053a22bd19ee3328a38ac7e9d429706061654b2 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,48 +1,42 @@ ## Process this file with automake to produce Makefile.in -AM_CFLAGS = -Wall -Wextra $(CHECK_CFLAGS) +AM_CFLAGS = -Wall -Wextra -Wno-nonnull $(CHECK_CFLAGS) TESTS = TESTS += sefht_cms_test TESTS += sefht_data_test TESTS += sefht_node_fragment_test TESTS += sefht_text_test -TESTS += sefht_validator_test check_PROGRAMS = $(TESTS) AM_CPPFLAGS = -AM_CPPFLAGS += -I$(top_srcdir)/src +AM_CPPFLAGS += -DSEFHT_COMPILATION +AM_CPPFLAGS += -I$(top_srcdir)/src/lib/sefht LDADD = $(CHECK_LIBS) +OBJECT_PREFIX = $(top_builddir)/src/lib/sefht/libsefht_la- + sefht_cms_test_SOURCES = test_cms.c sefht_cms_test_LDADD = -sefht_cms_test_LDADD += $(top_builddir)/src/cms.o -sefht_cms_test_LDADD += $(top_builddir)/src/data.o -sefht_cms_test_LDADD += $(top_builddir)/src/validator.o +sefht_cms_test_LDADD += $(OBJECT_PREFIX)data.o +sefht_cms_test_LDADD += $(OBJECT_PREFIX)validator.o sefht_cms_test_LDADD += $(LDADD) sefht_data_test_SOURCES = test_data.c sefht_data_test_LDADD = -sefht_data_test_LDADD += $(top_builddir)/src/data.o -sefht_data_test_LDADD += $(top_builddir)/src/validator.o +sefht_data_test_LDADD += $(OBJECT_PREFIX)validator.o sefht_data_test_LDADD += $(LDADD) sefht_node_fragment_test_SOURCES = test_node_fragment.c sefht_node_fragment_test_LDADD = -sefht_node_fragment_test_LDADD += $(top_builddir)/src/node_fragment.o -sefht_node_fragment_test_LDADD += $(top_builddir)/src/data.o -sefht_node_fragment_test_LDADD += $(top_builddir)/src/fragment.o -sefht_node_fragment_test_LDADD += $(top_builddir)/src/text.o -sefht_node_fragment_test_LDADD += $(top_builddir)/src/validator.o +sefht_node_fragment_test_LDADD += $(OBJECT_PREFIX)data.o +sefht_node_fragment_test_LDADD += $(OBJECT_PREFIX)fragment.o +sefht_node_fragment_test_LDADD += $(OBJECT_PREFIX)text.o +sefht_node_fragment_test_LDADD += $(OBJECT_PREFIX)validator.o sefht_node_fragment_test_LDADD += $(LDADD) sefht_text_test_SOURCES = test_text.c sefht_text_test_LDADD = -sefht_text_test_LDADD += $(top_builddir)/src/text.o 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_cms.c b/tests/test_cms.c index a6cc36fceb549bfe9f7bc03452f7d10cf64f3c14..f35935b9b93fd62dcb97988e0a083357a20d01c5 100644 --- a/tests/test_cms.c +++ b/tests/test_cms.c @@ -25,28 +25,27 @@ #include <check.h> #include <stdlib.h> -#include "error.h" -#include "cms.h" +#include "status.h" + +#include "cms.c" START_TEST(test_cms) { - struct SH_Error error; + struct SH_Status status; struct SH_Cms * cms; cms = SH_Cms_new (NULL); ck_assert_int_ne ((long int) cms, (long int) NULL); - SH_Cms_free (cms, NULL); + SH_Cms_free (cms); - error.type = UNDEFINED; - cms = SH_Cms_new (&error); + _status_preinit (status); + cms = SH_Cms_new (&status); ck_assert_int_ne ((long int) cms, (long int) NULL); - ck_assert_int_eq (error.type, SUCCESS); + ck_assert_int_eq (status.status, SUCCESS); - error.type = UNDEFINED; - SH_Cms_free (cms, &error); - ck_assert_int_eq (error.type, SUCCESS); + SH_Cms_free (cms); } END_TEST @@ -66,7 +65,7 @@ Suite * cms_suite (void) return s; } -int main (int argc, char **argv) +int main (void) { int number_failed; Suite *s; diff --git a/tests/test_data.c b/tests/test_data.c index 2fcd0bb072941e245f975bc17e95e53725a0f43f..9687a5ddf6a7d5bd21ab09ffece0859d76de04f2 100644 --- a/tests/test_data.c +++ b/tests/test_data.c @@ -25,13 +25,14 @@ #include <check.h> #include <stdlib.h> -#include "error.h" -#include "data.h" +#include "status.h" + +#include "data.c" START_TEST(test_data) { - struct SH_Error error; + struct SH_Status status; struct SH_Data * data; data = SH_Data_new (NULL); @@ -40,25 +41,23 @@ START_TEST(test_data) ck_assert_int_eq (data->page_n, 0); ck_assert_int_eq (data->last_page, PAGE_ERR); - SH_Data_free (data, NULL); + SH_Data_free (data); - error.type = UNDEFINED; - data = SH_Data_new (&error); + _status_preinit (status); + data = SH_Data_new (&status); ck_assert_int_ne ((long int) data, (long int) NULL); - ck_assert_int_eq (error.type, SUCCESS); + ck_assert_int_eq (status.status, SUCCESS); ck_assert_int_eq (data->page_n, 0); ck_assert_int_eq (data->last_page, PAGE_ERR); - error.type = UNDEFINED; - SH_Data_free (data, &error); - ck_assert_int_eq (error.type, SUCCESS); + SH_Data_free (data); } END_TEST START_TEST(test_data_register_page) { - struct SH_Error error; + struct SH_Status status; struct SH_Data * data; const char * page1 = "Homepage"; const char * page2 = "Login"; @@ -81,12 +80,12 @@ START_TEST(test_data_register_page) ck_assert_str_eq (data->pages[0].name, page1); /* fail without error */ - data->page_n = UINT_MAX; + data->page_n = SIZE_MAX; page = SH_Data_register_page (data, page2, NULL); ck_assert_int_eq (page, PAGE_ERR); - ck_assert_int_eq (data->page_n, UINT_MAX); + ck_assert_int_eq (data->page_n, SIZE_MAX); ck_assert_int_eq (data->last_page, 1); /* fail2 without error */ @@ -102,10 +101,10 @@ START_TEST(test_data_register_page) /* success with error */ data->last_page = 1; - error.type = UNDEFINED; - page = SH_Data_register_page (data, page4, &error); + _status_preinit (status); + page = SH_Data_register_page (data, page4, &status); ck_assert_int_eq (page, 2); - ck_assert_int_eq (error.type, SUCCESS); + ck_assert_int_eq (status.status, SUCCESS); ck_assert_int_eq (data->page_n, 2); ck_assert_int_eq (data->last_page, page); @@ -114,29 +113,29 @@ START_TEST(test_data_register_page) ck_assert_str_eq (data->pages[1].name, page4); /* fail with error */ - data->page_n = UINT_MAX; + data->page_n = SIZE_MAX; - error.type = UNDEFINED; - page = SH_Data_register_page (data, page5, &error); + _status_preinit (status); + page = SH_Data_register_page (data, page5, &status); ck_assert_int_eq (page, PAGE_ERR); - ck_assert_int_eq (error.type, DOMAIN_ERROR); + ck_assert_int_eq (status.status, E_DOMAIN); - ck_assert_int_eq (data->page_n, UINT_MAX); + ck_assert_int_eq (data->page_n, SIZE_MAX); ck_assert_int_eq (data->last_page, 2); /* fail2 with error */ data->page_n = 2; data->last_page = PAGE_MAX; - error.type = UNDEFINED; - page = SH_Data_register_page (data, page6, &error); + _status_preinit (status); + page = SH_Data_register_page (data, page6, &status); ck_assert_int_eq (page, PAGE_ERR); - ck_assert_int_eq (error.type, DOMAIN_ERROR); + ck_assert_int_eq (status.status, E_DOMAIN); ck_assert_int_eq (data->page_n, 2); ck_assert_int_eq (data->last_page, PAGE_MAX); - SH_Data_free (data, NULL); + SH_Data_free (data); } END_TEST @@ -157,7 +156,7 @@ Suite * data_suite (void) return s; } -int main (int argc, char **argv) +int main (void) { int number_failed; Suite *s; diff --git a/tests/test_node_fragment.c b/tests/test_node_fragment.c index 6ee394bfc85ce679f5af6203b852d01759269bf0..d7c14a1ec6d6d2bea92a06ea23ddeda1da0f18de 100644 --- a/tests/test_node_fragment.c +++ b/tests/test_node_fragment.c @@ -27,20 +27,19 @@ #include <stdlib.h> #include "macro.h" -#include "error.h" -#include "node_fragment.h" +#include "status.h" + +#include "node_fragment.c" START_TEST(test_node_fragment) { - struct SH_Error error; + struct SH_Status status; 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); @@ -48,37 +47,25 @@ START_TEST(test_node_fragment) ck_assert_str_eq (((struct SH_NodeFragment *) fragment)->tag, tag); - SH_Fragment_free (fragment, NULL); - - /* invalid tag - no error */ - fragment = SH_NodeFragment_new (no_tag, data, NULL); - ck_assert_int_eq ((long int) fragment, (long int) NULL); + SH_Fragment_free (fragment); /* valid tag - error */ - error.type = UNDEFINED; - fragment = SH_NodeFragment_new (tag, data, &error); + _status_preinit (status); + fragment = SH_NodeFragment_new (tag, data, &status); ck_assert_int_ne ((long int) fragment, (long int) NULL); - ck_assert_int_eq (error.type, SUCCESS); + ck_assert_int_eq (status.status, SUCCESS); ck_assert_str_eq (((struct SH_NodeFragment *) fragment)->tag, tag); - error.type = UNDEFINED; - SH_Fragment_free (fragment, &error); - ck_assert_int_eq (error.type, SUCCESS); - - /* invalid tag - error */ - error.type = UNDEFINED; - fragment = SH_NodeFragment_new (no_tag, data, &error); - ck_assert_int_eq ((long int) fragment, (long int) NULL); - ck_assert_int_eq (error.type, VALUE_ERROR); + SH_Fragment_free (fragment); - SH_Data_free (data, NULL); + SH_Data_free (data); } END_TEST START_TEST(test_node_fragment_copy) { - struct SH_Error error; + struct SH_Status status; struct SH_Fragment * fragment; struct SH_Fragment * copy; struct SH_Data * data; @@ -99,13 +86,13 @@ START_TEST(test_node_fragment_copy) ck_assert_ptr_ne (((struct SH_NodeFragment *) fragment)->childs, ((struct SH_NodeFragment *) copy)->childs); - SH_Fragment_free (copy, NULL); + SH_Fragment_free (copy); /* with error */ - error.type = UNDEFINED; + _status_preinit (status); copy = SH_NodeFragment_copy (((struct SH_NodeFragment *) fragment), - &error); - ck_assert_int_eq (error.type, SUCCESS); + &status); + ck_assert_int_eq (status.status, SUCCESS); ck_assert_ptr_ne (copy, NULL); ck_assert_ptr_ne (fragment, copy); @@ -115,10 +102,10 @@ START_TEST(test_node_fragment_copy) ck_assert_ptr_ne (((struct SH_NodeFragment *) fragment)->childs, ((struct SH_NodeFragment *) copy)->childs); - SH_Fragment_free (fragment, NULL); - SH_Fragment_free (copy, NULL); + SH_Fragment_free (fragment); + SH_Fragment_free (copy); - SH_Data_free (data, NULL); + SH_Data_free (data); } END_TEST @@ -145,7 +132,7 @@ check_childs (struct SH_NodeFragment * fragment, struct SH_NodeFragment * copy) START_TEST(test_node_fragment_deepcopy) { - struct SH_Error error; + struct SH_Status status; struct SH_Fragment * fragment; struct SH_Fragment * child1; struct SH_Fragment * child2; @@ -197,12 +184,12 @@ START_TEST(test_node_fragment_deepcopy) check_childs (((struct SH_NodeFragment *) fragment), ((struct SH_NodeFragment *) copy)); - SH_Fragment_free (copy, NULL); + SH_Fragment_free (copy); /* with error */ - error.type = UNDEFINED; - copy = SH_Fragment_copy (fragment, &error); - ck_assert_int_eq (error.type, SUCCESS); + _status_preinit (status); + copy = SH_Fragment_copy (fragment, &status); + ck_assert_int_eq (status.status, SUCCESS); ck_assert_ptr_ne (copy, NULL); ck_assert_ptr_ne (fragment, copy); @@ -216,16 +203,16 @@ START_TEST(test_node_fragment_deepcopy) check_childs (((struct SH_NodeFragment *) fragment), ((struct SH_NodeFragment *) copy)); - SH_Fragment_free (fragment, NULL); - SH_Fragment_free (copy, NULL); + SH_Fragment_free (fragment); + SH_Fragment_free (copy); - SH_Data_free (data, NULL); + SH_Data_free (data); } END_TEST START_TEST(test_node_fragment_tag) { - struct SH_Error error; + struct SH_Status status; struct SH_Fragment * fragment; struct SH_Data * data; char * tag; @@ -233,8 +220,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); @@ -244,26 +229,26 @@ START_TEST(test_node_fragment_tag) ck_assert_str_eq (tag, tag1); free (tag); - SH_Fragment_free (fragment, NULL); + SH_Fragment_free (fragment); /* error */ fragment = SH_NodeFragment_new (tag2, data, NULL); - error.type = UNDEFINED; + _status_preinit (status); tag = SH_NodeFragment_get_tag (((struct SH_NodeFragment *) fragment), - &error); + &status); ck_assert_str_eq (tag, tag2); - ck_assert_int_eq (error.type, SUCCESS); + ck_assert_int_eq (status.status, SUCCESS); free (tag); - SH_Fragment_free (fragment, NULL); - SH_Data_free (data, NULL); + SH_Fragment_free (fragment); + SH_Data_free (data); } END_TEST START_TEST(test_node_fragment_child) { - struct SH_Error error; + struct SH_Status status; struct SH_Fragment * parent; struct SH_Fragment * child1; struct SH_Fragment * child2; @@ -290,25 +275,25 @@ START_TEST(test_node_fragment_child) /* with error */ ck_assert_int_eq (((struct SH_NodeFragment *) parent)->child_n, 1); - error.type = UNDEFINED; + _status_preinit (status); boolean = SH_NodeFragment_append_child (((struct SH_NodeFragment *) parent), - child2, &error); + child2, &status); ck_assert_int_eq (boolean, TRUE); - ck_assert_int_eq (error.type, SUCCESS); + ck_assert_int_eq (status.status, SUCCESS); ck_assert_int_eq (((struct SH_NodeFragment *) parent)->child_n, 2); ck_assert_ptr_eq (((struct SH_NodeFragment *) parent)->childs[1], child2); - SH_Fragment_free (parent, NULL); + SH_Fragment_free (parent); - SH_Data_free (data, NULL); + SH_Data_free (data); } END_TEST START_TEST(test_node_fragment_get_child) { - struct SH_Error error; + struct SH_Status status; struct SH_Fragment * parent; struct SH_Fragment * child1; struct SH_Fragment * child2; @@ -332,21 +317,21 @@ START_TEST(test_node_fragment_get_child) ck_assert_ptr_eq (NULL, child2); /* with error */ - error.type = UNDEFINED; + _status_preinit (status); child2 = SH_NodeFragment_get_child (((struct SH_NodeFragment *) parent), - 0, &error); + 0, &status); ck_assert_ptr_eq (child1, child2); - ck_assert_int_eq (error.type, SUCCESS); + ck_assert_int_eq (status.status, SUCCESS); - error.type = UNDEFINED; + _status_preinit (status); child2 = SH_NodeFragment_get_child (((struct SH_NodeFragment *) parent), - 1, &error); + 1, &status); ck_assert_ptr_eq (NULL, child2); - ck_assert_int_eq (error.type, VALUE_ERROR); + ck_assert_int_eq (status.status, E_VALUE); - SH_Fragment_free (parent, NULL); + SH_Fragment_free (parent); - SH_Data_free (data, NULL); + SH_Data_free (data); } END_TEST @@ -381,9 +366,9 @@ START_TEST(test_node_fragment_is_child) child2); ck_assert_int_eq (boolean, TRUE); - SH_Fragment_free (parent, NULL); + SH_Fragment_free (parent); - SH_Data_free (data, NULL); + SH_Data_free (data); } END_TEST @@ -434,22 +419,23 @@ START_TEST(test_node_fragment_is_descendant) child3); ck_assert_int_eq (boolean, FALSE); - SH_Fragment_free (parent, NULL); + SH_Fragment_free (parent); - SH_Data_free (data, NULL); + SH_Data_free (data); } END_TEST START_TEST(test_node_fragment_html) { - struct SH_Error error; + struct SH_Status status; struct SH_Fragment * fragment1; struct SH_Fragment * fragment2; struct SH_Data * data; struct SH_Text * text; + char * string; + 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); @@ -459,14 +445,18 @@ START_TEST(test_node_fragment_html) text = SH_Fragment_to_html (fragment1, INLINE, 0, 1, INDENT_TEXT, NULL); - ck_assert_str_eq (text->text, "<html><body></body></html>"); + string = SH_Text_get_string (text, 0, SIZE_MAX, &length, NULL); + ck_assert_str_eq (string, "<html><body></body></html>"); + free (string); text = SH_Fragment_to_html (fragment1, WRAP, 0, 1, INDENT_TEXT, NULL); - ck_assert_str_eq (text->text, + string = SH_Text_get_string (text, 0, SIZE_MAX, &length, NULL); + ck_assert_str_eq (string, "<html>\n\t<body>\n\t</body>\n</html>\n"); + free (string); - SH_Fragment_free (fragment1, NULL); + SH_Fragment_free (fragment1); /* error */ fragment1 = SH_NodeFragment_new ("html", data, NULL); @@ -474,21 +464,25 @@ START_TEST(test_node_fragment_html) SH_NodeFragment_append_child (((struct SH_NodeFragment *) fragment1), fragment2, NULL); - error.type = UNDEFINED; + _status_preinit (status); text = SH_Fragment_to_html (fragment1, INLINE, 0, 1, INDENT_TEXT, - &error); - ck_assert_str_eq (text->text, "<html><body></body></html>"); - ck_assert_int_eq (error.type, SUCCESS); + &status); + string = SH_Text_get_string (text, 0, SIZE_MAX, &length, NULL); + ck_assert_str_eq (string, "<html><body></body></html>"); + free (string); + ck_assert_int_eq (status.status, SUCCESS); - error.type = UNDEFINED; + _status_preinit (status); text = SH_Fragment_to_html (fragment1, WRAP, 0, 1, INDENT_TEXT, - &error); - ck_assert_str_eq (text->text, + &status); + string = SH_Text_get_string (text, 0, SIZE_MAX, &length, NULL); + ck_assert_str_eq (string, "<html>\n\t<body>\n\t</body>\n</html>\n"); - ck_assert_int_eq (error.type, SUCCESS); + free (string); + ck_assert_int_eq (status.status, SUCCESS); - SH_Fragment_free (fragment1, NULL); - SH_Data_free (data, NULL); + SH_Fragment_free (fragment1); + SH_Data_free (data); } END_TEST @@ -516,7 +510,7 @@ Suite * fragment_suite (void) return s; } -int main (int argc, char **argv) +int main (void) { int number_failed; Suite *s; diff --git a/tests/test_text.c b/tests/test_text.c index 5158f122f59541aadcd975eb221fe285790e74b9..986ae71cfd80ff8c49e05a7ddaf896a9407b03fd 100644 --- a/tests/test_text.c +++ b/tests/test_text.c @@ -27,186 +27,432 @@ #include <stdbool.h> #include <stdlib.h> +/* lower SIZE_MAX as we try to reach it */ +#include <limits.h> +#undef SIZE_MAX +#define SIZE_MAX 30 + #include "macro.h" -#include "error.h" +#include "status.h" -#include "text.h" +/* C file is needed, because we want to override CHUNK_SIZE */ +#define CHUNK_SIZE 5 +#include "text.c" START_TEST(test_text) { - struct SH_Error error; + struct SH_Status status; struct SH_Text * text; text = SH_Text_new (NULL); ck_assert_int_ne ((long int) text, (long int) NULL); - ck_assert_int_ge (text->size, CHUNK_SIZE); + ck_assert_int_ge (text->data->size, CHUNK_SIZE); - SH_Text_free (text, NULL); + SH_Text_free (text); - error.type = UNDEFINED; - text = SH_Text_new (&error); + _status_preinit (status); + text = SH_Text_new (&status); ck_assert_int_ne ((long int) text, (long int) NULL); - ck_assert_int_eq (error.type, SUCCESS); + ck_assert_int_eq (status.status, SUCCESS); - ck_assert_int_ge (text->size, CHUNK_SIZE); + ck_assert_int_ge (text->data->size, CHUNK_SIZE); - error.type = UNDEFINED; - SH_Text_free (text, &error); - ck_assert_int_eq (error.type, SUCCESS); + SH_Text_free (text); } END_TEST -START_TEST(test_text_enlarge) +START_TEST(test_text_string) { - struct SH_Error error; + struct SH_Status status; struct SH_Text * text; - bool result; - size_t size1; - size_t size2; - size_t size2_; - size_t size3; + /* without error */ + text = SH_Text_new_from_string ("12345", NULL); + ck_assert_int_ne ((long int) text, (long int) NULL); - size1 = CHUNK_SIZE; - size2 = CHUNK_SIZE + 1; - size2_ = 2 * CHUNK_SIZE; - if (SIZE_MAX % CHUNK_SIZE == 0) - { - size3 = ((SIZE_MAX / CHUNK_SIZE) - 1) * CHUNK_SIZE; - } - else + ck_assert_int_eq (text->data->length, 5); + ck_assert_int_eq (text->data->size, 6); + ck_assert_str_eq (text->data->text, "12345"); + ck_assert_ptr_eq (text->data->next, NULL); + + SH_Text_free (text); + + + /* with error */ + _status_preinit (status); + text = SH_Text_new_from_string ("12345", &status); + ck_assert_int_ne ((long int) text, (long int) NULL); + ck_assert_int_eq (status.status, SUCCESS); + + ck_assert_int_eq (text->data->length, 5); + ck_assert_int_eq (text->data->size, 6); + ck_assert_str_eq (text->data->text, "12345"); + ck_assert_ptr_eq (text->data->next, NULL); + + SH_Text_free (text); + +} +END_TEST + +START_TEST (test_text_copy) +{ + struct SH_Status status; + struct SH_Text * text; + struct SH_Text * copy; + char * text_string; + char * copy_string; + + text = SH_Text_new_from_string ("Text12345", NULL); + text_string = SH_Text_get_string (text, 0, 10, NULL, NULL); + + /* without error */ + copy = SH_Text_copy (text, NULL); + ck_assert_ptr_ne (copy, NULL); + ck_assert_ptr_ne (copy, text); + copy_string = SH_Text_get_string (copy, 0, 10, NULL, NULL); + ck_assert_str_eq (copy_string, text_string); + + free (copy_string); + SH_Text_free (copy); + + /* with error */ + _status_preinit (status); + copy = SH_Text_copy (text, &status); + ck_assert_int_eq (status.status, SUCCESS); + ck_assert_ptr_ne (copy, NULL); + ck_assert_ptr_ne (copy, text); + copy_string = SH_Text_get_string (copy, 0, 10, NULL, NULL); + ck_assert_str_eq (copy_string, text_string); + + free (copy_string); + SH_Text_free (copy); + + free (text_string); + SH_Text_free (text); +} +END_TEST + +START_TEST(test_text_get_length) +{ + struct SH_Status status; + struct SH_Text * text; + size_t length; + char index[2] = {1, 0}; + + text = SH_Text_new (NULL); + + /* length == 0 - without error */ + length = SH_Text_get_length (text, NULL); + ck_assert_int_eq (length, 0); + + /* length == 0 - with error */ + _status_preinit (status); + length = SH_Text_get_length (text, &status); + ck_assert_int_eq (length, 0); + ck_assert_int_eq (status.status, SUCCESS); + + + for (; index[0] <= SIZE_MAX; index[0]++) { - size3 = (SIZE_MAX / CHUNK_SIZE) * CHUNK_SIZE; + SH_Text_append_string (text, index, NULL); } - text = SH_Text_new (NULL); + /* length == SIZE_MAX - without error */ + length = SH_Text_get_length (text, NULL); + ck_assert_int_eq (length, SIZE_MAX); - /* size == current size */ - result = SH_Text_enlarge (text, size1, NULL); - ck_assert_int_eq (result, TRUE); + /* length == SIZE_MAX - with error */ + _status_preinit (status); + length = SH_Text_get_length (text, &status); + ck_assert_int_eq (length, SIZE_MAX); + ck_assert_int_eq (status.status, SUCCESS); - ck_assert_int_eq (text->size, size1); + SH_Text_append_string (text, index, NULL); - /* size > current size */ - result = SH_Text_enlarge (text, size2, NULL); - ck_assert_int_eq (result, TRUE); + /* length > SIZE_MAX - without error */ + length = SH_Text_get_length (text, NULL); + ck_assert_int_eq (length, SIZE_MAX); - ck_assert_int_eq (text->size, size2_); + /* length > SIZE_MAX - with error */ + _status_preinit (status); + length = SH_Text_get_length (text, &status); + ck_assert_int_eq (length, SIZE_MAX); + ck_assert_int_eq (status.status, E_DOMAIN); - /* size < current size */ - result = SH_Text_enlarge (text, size1, NULL); - ck_assert_int_eq (result, TRUE); + SH_Text_free (text); +} +END_TEST - ck_assert_int_eq (text->size, size2_); +START_TEST(test_text_get_char) +{ + struct SH_Status status; + struct SH_Text * text; + unsigned int i; + char * c; - /* size throw overflow */ - result = SH_Text_enlarge (text, size3, NULL); - ck_assert_int_eq (result, FALSE); + text = SH_Text_new_from_string ("abcd", NULL); + SH_Text_append_string (text, "efgh", NULL); + SH_Text_append_string (text, "ijkl", NULL); - SH_Text_free (text, NULL); + /* success - without error */ + for (i = 0; i < 12; i++) + { + c = SH_Text_get_char (text, i, NULL); + ck_assert_ptr_ne (c, NULL); + ck_assert_int_eq (*c, 97 + i); + free (c); + } + /* wrong index - without error */ + c = SH_Text_get_char (text, 13, NULL); + ck_assert_ptr_eq (c, NULL); - text = SH_Text_new (NULL); + /* success - with error */ + for (i = 0; i < 12; i++) + { + _status_preinit (status); + c = SH_Text_get_char (text, i, &status); + ck_assert_ptr_ne (c, NULL); + ck_assert_int_eq (*c, 97 + i); + ck_assert_int_eq (status.status, SUCCESS); + free (c); + } - /* size == current size */ - error.type = UNDEFINED; - result = SH_Text_enlarge (text, size1, &error); - ck_assert_int_eq (result, TRUE); - ck_assert_int_eq (error.type, SUCCESS); + /* wrong index - with error */ + _status_preinit (status); + c = SH_Text_get_char (text, 13, &status); + ck_assert_ptr_eq (c, NULL); + ck_assert_int_eq (status.status, E_VALUE); - ck_assert_int_eq (text->size, size1); + SH_Text_free (text); +} +END_TEST - /* size > current size */ - error.type = UNDEFINED; - result = SH_Text_enlarge (text, size2, &error); - ck_assert_int_eq (result, TRUE); - ck_assert_int_eq (error.type, SUCCESS); +START_TEST(test_text_get_string) +{ + struct SH_Status status; + struct SH_Text * text; + char * result; + size_t length = -1; + char index[2] = {1, 0}; - ck_assert_int_eq (text->size, size2_); + text = SH_Text_new (NULL); + for (; index[0] < 100; index[0]++) + { + SH_Text_append_string (text, index, NULL); + } - /* size < current size */ - error.type = UNDEFINED; - result = SH_Text_enlarge (text, size1, &error); - ck_assert_int_eq (result, TRUE); - ck_assert_int_eq (error.type, SUCCESS); + /* single segment - without error */ + result = SH_Text_get_string (text, 59, 8, &length, NULL); + ck_assert_str_eq (result, "<=>?@ABC"); + ck_assert_int_eq (length, 8); + free (result); + + /* multiple segment - without error */ + result = SH_Text_get_string (text, 47, 43, &length, NULL); + ck_assert_str_eq (result, "0123456789:;<=>?@" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); + ck_assert_int_eq (length, 43); + free (result); + + /* pass over end - without error */ + result = SH_Text_get_string (text, 96, 10, &length, NULL); + ck_assert_str_eq (result, "abc"); + ck_assert_int_eq (length, 3); + free (result); + + /* out of range - without error */ + result = SH_Text_get_string (text, 99, 0, &length, NULL); + ck_assert_ptr_eq (result, NULL); + ck_assert_int_eq (length, 0); + + + /* single segment - with error */ + _status_preinit (status); + result = SH_Text_get_string (text, 59, 8, &length, &status); + ck_assert_str_eq (result, "<=>?@ABC"); + ck_assert_int_eq (length, 8); + ck_assert_int_eq (status.status, SUCCESS); + free (result); + + /* multiple segment - with error */ + _status_preinit (status); + result = SH_Text_get_string (text, 47, 43, &length, &status); + ck_assert_str_eq (result, "0123456789:;<=>?@" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); + ck_assert_int_eq (length, 43); + ck_assert_int_eq (status.status, SUCCESS); + free (result); + + /* pass over end - with error */ + _status_preinit (status); + result = SH_Text_get_string (text, 96, 10, &length, &status); + ck_assert_str_eq (result, "abc"); + ck_assert_int_eq (length, 3); + ck_assert_int_eq (status.status, SUCCESS); + free (result); + + /* out of range - without error */ + _status_preinit (status); + result = SH_Text_get_string (text, 99, 0, &length, &status); + ck_assert_ptr_eq (result, NULL); + ck_assert_int_eq (length, 0); + ck_assert_int_eq (status.status, E_VALUE); + + SH_Text_free (text); +} +END_TEST - ck_assert_int_eq (text->size, size2_); +START_TEST(test_text_get_range) +{ + struct SH_Status status; + struct SH_Text * text; + char * result; + size_t length = -1; + char index[2] = {1, 0}; - /* size throw overflow */ - error.type = UNDEFINED; - result = SH_Text_enlarge (text, size3, &error); - ck_assert_int_eq (result, FALSE); - ck_assert_int_eq (error.type, DOMAIN_ERROR); + text = SH_Text_new (NULL); + for (; index[0] < 100; index[0]++) + { + SH_Text_append_string (text, index, NULL); + } - SH_Text_free (text, NULL); + /* single segment - without error */ + result = SH_Text_get_range (text, 59, 67, &length, NULL); + ck_assert_str_eq (result, "<=>?@ABC"); + ck_assert_int_eq (length, 8); + free (result); + + /* multiple segment - without error */ + result = SH_Text_get_range (text, 47, 90, &length, NULL); + ck_assert_str_eq (result, "0123456789:;<=>?@" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); + ck_assert_int_eq (length, 43); + free (result); + + /* pass over end - without error */ + result = SH_Text_get_range (text, 96, 106, &length, NULL); + ck_assert_str_eq (result, "abc"); + ck_assert_int_eq (length, 3); + free (result); + + /* out of range - without error */ + result = SH_Text_get_range (text, 99, 99, &length, NULL); + ck_assert_ptr_eq (result, NULL); + ck_assert_int_eq (length, 0); + + + /* single segment - with error */ + _status_preinit (status); + result = SH_Text_get_range (text, 59, 67, &length, &status); + ck_assert_str_eq (result, "<=>?@ABC"); + ck_assert_int_eq (length, 8); + ck_assert_int_eq (status.status, SUCCESS); + free (result); + + /* multiple segment - with error */ + _status_preinit (status); + result = SH_Text_get_range (text, 47, 90, &length, &status); + ck_assert_str_eq (result, "0123456789:;<=>?@" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); + ck_assert_int_eq (length, 43); + ck_assert_int_eq (status.status, SUCCESS); + free (result); + + /* pass over end - with error */ + _status_preinit (status); + result = SH_Text_get_range (text, 96, 106, &length, &status); + ck_assert_str_eq (result, "abc"); + ck_assert_int_eq (length, 3); + ck_assert_int_eq (status.status, SUCCESS); + free (result); + + /* out of range - without error */ + _status_preinit (status); + result = SH_Text_get_range (text, 99, 99, &length, &status); + ck_assert_ptr_eq (result, NULL); + ck_assert_int_eq (length, 0); + ck_assert_int_eq (status.status, E_VALUE); + + SH_Text_free (text); } END_TEST START_TEST (test_text_append) { - struct SH_Error error; + struct SH_Status status; struct SH_Text * text1; struct SH_Text * text2; - struct SH_Text * text3; bool boolean; + char * string; + size_t length; text1 = SH_Text_new (NULL); text2 = SH_Text_new (NULL); - text3 = SH_Text_new (NULL); + /* append_string - without error */ boolean = SH_Text_append_string (text1, "Text1", NULL); ck_assert_int_eq (boolean, TRUE); - ck_assert_str_eq (text1->text, "Text1"); - ck_assert_int_eq (text1->length, 5); - ck_assert_int_ge (text1->size, 6); - - boolean = SH_Text_append_string (text2, "Text2", NULL); - ck_assert_int_eq (boolean, TRUE); - ck_assert_str_eq (text2->text, "Text2"); - ck_assert_int_eq (text2->length, 5); - ck_assert_int_ge (text2->size, 6); - - error.type = UNDEFINED; - boolean = SH_Text_append_string (text3, "Text3", &error); + string = SH_Text_get_string (text1, 0, SIZE_MAX, &length, NULL); + ck_assert_str_eq (string, "Text1"); + ck_assert_int_eq (length, 5); + free (string); + + /* append_string - with error */ + _status_preinit (status); + boolean = SH_Text_append_string (text2, "Text2", &status); ck_assert_int_eq (boolean, TRUE); - ck_assert_int_eq (error.type, SUCCESS); - ck_assert_str_eq (text3->text, "Text3"); - ck_assert_int_eq (text3->length, 5); - ck_assert_int_ge (text3->size, 6); + ck_assert_int_eq (status.status, SUCCESS); + string = SH_Text_get_string (text2, 0, SIZE_MAX, &length, NULL); + ck_assert_str_eq (string, "Text2"); + ck_assert_int_eq (length, 5); + free (string); + /* append_text - without error */ boolean = SH_Text_append_text (text1, text2, NULL); ck_assert_int_eq (boolean, TRUE); - ck_assert_str_eq (text1->text, "Text1Text2"); - ck_assert_int_eq (text1->length, 10); - ck_assert_int_ge (text1->size, 11); - - error.type = UNDEFINED; - boolean = SH_Text_append_text (text1, text3, &error); + string = SH_Text_get_string (text1, 0, SIZE_MAX, &length, NULL); + ck_assert_str_eq (string, "Text1Text2"); + ck_assert_int_eq (length, 10); + free (string); + + /* append_text - with error */ + _status_preinit (status); + boolean = SH_Text_append_text (text1, text2, &status); ck_assert_int_eq (boolean, TRUE); - ck_assert_int_eq (error.type, SUCCESS); - ck_assert_str_eq (text1->text, "Text1Text2Text3"); - ck_assert_int_eq (text1->length, 15); - ck_assert_int_ge (text1->size, 16); + ck_assert_int_eq (status.status, SUCCESS); + string = SH_Text_get_string (text1, 0, SIZE_MAX, &length, NULL); + ck_assert_str_eq (string, "Text1Text2Text2"); + ck_assert_int_eq (length, 15); + free (string); - boolean = SH_Text_join (text1, text2, NULL); - ck_assert_int_eq (boolean, TRUE); - ck_assert_str_eq (text1->text, "Text1Text2Text3Text2"); - ck_assert_int_eq (text1->length, 20); - ck_assert_int_ge (text1->size, 21); + /* join - no error */ + SH_Text_join (text1, text2); + string = SH_Text_get_string (text1, 0, SIZE_MAX, &length, NULL); + ck_assert_str_eq (string, "Text1Text2Text2Text2"); + ck_assert_int_eq (length, 20); + free (string); - error.type = UNDEFINED; - boolean = SH_Text_join (text1, text3, &error); - ck_assert_int_eq (boolean, TRUE); - ck_assert_int_eq (error.type, SUCCESS); - ck_assert_str_eq (text1->text, "Text1Text2Text3Text2Text3"); - ck_assert_int_eq (text1->length, 25); - ck_assert_int_ge (text1->size, 26); - SH_Text_free (text1, NULL); + SH_Text_free (text1); +} +END_TEST + +START_TEST(test_text_print) +{ + struct SH_Text * text; + + text = SH_Text_new_from_string ("abcdefghijkklmnopqrstuvwxyz", + NULL); + SH_Text_append_text (text, text, NULL); + + SH_Text_print (text); + + SH_Text_free (text); } END_TEST @@ -221,14 +467,20 @@ Suite * text_suite (void) tc_core = tcase_create ("Core"); tcase_add_test (tc_core, test_text); - tcase_add_test (tc_core, test_text_enlarge); + tcase_add_test (tc_core, test_text_string); + tcase_add_test (tc_core, test_text_copy); + tcase_add_test (tc_core, test_text_get_length); + tcase_add_test (tc_core, test_text_get_char); + tcase_add_test (tc_core, test_text_get_string); + tcase_add_test (tc_core, test_text_get_range); tcase_add_test (tc_core, test_text_append); + tcase_add_test (tc_core, test_text_print); suite_add_tcase (s, tc_core); return s; } -int main (int argc, char **argv) +int main (void) { int number_failed; Suite *s; diff --git a/tests/test_validator.c b/tests/test_validator.c index bb0f4826eb4d34bc7fbc60f586b81438d65205d8..73072bcc42036250f5040f01d56b466cc64a814a 100644 --- a/tests/test_validator.c +++ b/tests/test_validator.c @@ -31,41 +31,39 @@ /* 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 "error.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" START_TEST(test_validator) { - struct SH_Error error; + struct SH_Status status; struct SH_Validator * validator; validator = SH_Validator_new (NULL); ck_assert_int_ne ((long int) validator, (long int) NULL); - SH_Validator_free (validator, NULL); + SH_Validator_free (validator); - error.type = UNDEFINED; - validator = SH_Validator_new (&error); + _status_preinit (status); + validator = SH_Validator_new (&status); ck_assert_int_ne ((long int) validator, (long int) NULL); - ck_assert_int_eq (error.type, SUCCESS); + ck_assert_int_eq (status.status, SUCCESS); - error.type = UNDEFINED; - SH_Validator_free (validator, &error); - ck_assert_int_eq (error.type, SUCCESS); + SH_Validator_free (validator); } END_TEST START_TEST(test_validator_tag) { - struct SH_Error error; + struct SH_Status status; struct SH_Validator * validator; const char * tag1 = "html"; const char * tag2 = "head"; @@ -74,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); @@ -87,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 */ @@ -100,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 @@ -112,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); @@ -128,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 */ @@ -144,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); @@ -160,24 +157,24 @@ START_TEST(test_validator_tag) check = SH_Validator_check_tag (validator, tag3); ck_assert_int_eq (check, FALSE); - SH_Validator_free (validator, NULL); + SH_Validator_free (validator); validator = SH_Validator_new (NULL); /* success with error */ - error.type = UNDEFINED; - tag = SH_Validator_register_tag (validator, tag4, &error); + _status_preinit (status); + tag = SH_Validator_register_tag (validator, tag4, &status); ck_assert_int_eq (tag, 1); - ck_assert_int_eq (error.type, SUCCESS); + ck_assert_int_eq (status.status, SUCCESS); 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 */ @@ -189,43 +186,42 @@ 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); - error.type = UNDEFINED; - tag = SH_Validator_register_tag (validator, tag5, &error); + _status_preinit (status); + tag = SH_Validator_register_tag (validator, tag5, &status); ck_assert_int_eq (tag, TAG_ERR); - ck_assert_int_eq (error.type, DOMAIN_ERROR); + 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 */ validator->tag_n = 1; validator->last_tag = TAG_MAX; - error.type = UNDEFINED; - tag = SH_Validator_register_tag (validator, tag6, &error); + _status_preinit (status); + tag = SH_Validator_register_tag (validator, tag6, &status); ck_assert_int_eq (tag, TAG_ERR); - ck_assert_int_eq (error.type, DOMAIN_ERROR); + ck_assert_int_eq (status.status, E_DOMAIN); 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); @@ -240,9 +236,9 @@ 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, NULL); + SH_Validator_free (validator); } END_TEST @@ -263,7 +259,7 @@ Suite * validator_suite (void) return s; } -int main (int argc, char **argv) +int main (void) { int number_failed; Suite *s; diff --git a/todo.txt b/todo.txt index 4a979f61ab8d09de9510c027b892f046c40dd211..e99c86c32a2cfc571af67384635d3dc41df0cd13 100644 --- a/todo.txt +++ b/todo.txt @@ -3,3 +3,9 @@ create Logger create Docs dynamic Validator initialization + +remove -Wno-nonnull from AM_CFLAGS +fix warnings for tests + +rewrite validator test +restructure validator