From 6c3915214387ebe3748f539cadf074731186388e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonathan=20Sch=C3=B6bel?= <jonathan@xn--schbel-yxa.info>
Date: Mon, 24 Jul 2023 18:09:05 +0200
Subject: [PATCH] Validator: added attrs

The Validator also contains information about supported attrs. Currently
they can't be initialized by a spec. Also it can only be queried whether
an attr does exist at all and not whether it is supported in combination
with a specific tag. The tests are missing.
---
 sefht.geany                         |  49 +--
 src/lib/Makefile.am                 |   3 +
 src/lib/sefht/validator.c           |  18 ++
 src/lib/sefht/validator.h           |   1 +
 src/lib/sefht/validator_attr.c      | 448 ++++++++++++++++++++++++++++
 src/lib/sefht/validator_attr.h      |  59 ++++
 src/lib/sefht/validator_attr_data.h |  45 +++
 7 files changed, 600 insertions(+), 23 deletions(-)
 create mode 100644 src/lib/sefht/validator_attr.c
 create mode 100644 src/lib/sefht/validator_attr.h
 create mode 100644 src/lib/sefht/validator_attr_data.h

diff --git a/sefht.geany b/sefht.geany
index a59df6f..522e02b 100644
--- a/sefht.geany
+++ b/sefht.geany
@@ -28,13 +28,13 @@ long_line_behaviour=1
 long_line_column=72
 
 [files]
-current_page=32
+current_page=35
 FILE_NAME_0=139;None;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2FREADME;0;8
 FILE_NAME_1=134;None;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2F.gitignore;0;8
 FILE_NAME_2=1737;Sh;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fconfigure.ac;0;8
 FILE_NAME_3=73;Make;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2FMakefile.am;0;8
 FILE_NAME_4=19;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Fmain.c;0;8
-FILE_NAME_5=1091;Make;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2FMakefile.am;0;8
+FILE_NAME_5=1867;Make;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2FMakefile.am;0;8
 FILE_NAME_6=18;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fcms.c;0;8
 FILE_NAME_7=18;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fcms.h;0;8
 FILE_NAME_8=19;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fdata.c;0;8
@@ -58,31 +58,34 @@ FILE_NAME_25=8479;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fp
 FILE_NAME_26=1083;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Ftext_segment.h;0;8
 FILE_NAME_27=900;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Ftext_segment_mark.c;0;8
 FILE_NAME_28=1867;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Ftext_mark_static.c;0;8
-FILE_NAME_29=1005;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator.c;0;8
-FILE_NAME_30=1531;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator.h;0;8
+FILE_NAME_29=3036;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator.c;0;8
+FILE_NAME_30=1159;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator.h;0;8
 FILE_NAME_31=1111;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_html.h;0;8
 FILE_NAME_32=5802;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_33=1148;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_34=1124;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_tag_data.h;0;8
-FILE_NAME_35=924;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fstatus.h;0;8
-FILE_NAME_36=18;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Flog.h;0;4
-FILE_NAME_37=20;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fmacro.h;0;8
-FILE_NAME_38=20;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fsefht.h;0;8
-FILE_NAME_39=2902;Make;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2FMakefile.am;0;8
-FILE_NAME_40=218;Sh;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Fno_test.sh.in;0;8
-FILE_NAME_41=23;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_cms.c;0;8
-FILE_NAME_42=24;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_data.c;0;8
-FILE_NAME_43=8232;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_fragment.c;0;8
-FILE_NAME_44=33;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_node_fragment.c;0;8
-FILE_NAME_45=5714;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_text_fragment.c;0;8
-FILE_NAME_46=24;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_attr.c;0;8
-FILE_NAME_47=4221;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_text.c;0;8
-FILE_NAME_48=994;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_text_mark.c;0;8
-FILE_NAME_49=10556;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_validator.c;0;8
-FILE_NAME_50=536;None;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftodo.txt;0;8
-FILE_NAME_51=201;YAML;0;EUTF-8;0;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2F.gitlab-ci.yml;0;4
-FILE_NAME_52=71;Sh;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fgitlab-ci%2Fupload.sh.in;0;8
-FILE_NAME_53=806;Sh;0;EUTF-8;0;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fgitlab-ci%2Frelease.sh.in;0;4
+FILE_NAME_35=9882;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_attr.c;0;8
+FILE_NAME_36=1627;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_attr.h;0;8
+FILE_NAME_37=1099;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_attr_data.h;0;8
+FILE_NAME_38=924;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fstatus.h;0;8
+FILE_NAME_39=18;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Flog.h;0;4
+FILE_NAME_40=20;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fmacro.h;0;8
+FILE_NAME_41=20;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fsefht.h;0;8
+FILE_NAME_42=2902;Make;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2FMakefile.am;0;8
+FILE_NAME_43=218;Sh;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Fno_test.sh.in;0;8
+FILE_NAME_44=23;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_cms.c;0;8
+FILE_NAME_45=24;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_data.c;0;8
+FILE_NAME_46=8232;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_fragment.c;0;8
+FILE_NAME_47=33;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_node_fragment.c;0;8
+FILE_NAME_48=5714;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_text_fragment.c;0;8
+FILE_NAME_49=24;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_attr.c;0;8
+FILE_NAME_50=4221;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_text.c;0;8
+FILE_NAME_51=994;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_text_mark.c;0;8
+FILE_NAME_52=10556;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_validator.c;0;8
+FILE_NAME_53=536;None;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftodo.txt;0;8
+FILE_NAME_54=201;YAML;0;EUTF-8;0;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2F.gitlab-ci.yml;0;4
+FILE_NAME_55=71;Sh;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fgitlab-ci%2Fupload.sh.in;0;8
+FILE_NAME_56=806;Sh;0;EUTF-8;0;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fgitlab-ci%2Frelease.sh.in;0;4
 
 [VTE]
 last_dir=/home/jonathan/Documents/projects/prgm/internet/web/SeFHT/tests
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index f976962..126dfd9 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -29,6 +29,8 @@ EXTRA_DIST += sefht/text_segment_mark.c
 EXTRA_DIST += sefht/validator_html.h
 EXTRA_DIST += sefht/validator_tag.c
 EXTRA_DIST += sefht/validator_tag_data.h
+EXTRA_DIST += sefht/validator_attr.c
+EXTRA_DIST += sefht/validator_attr_data.h
 
 nobase_include_HEADERS =
 nobase_include_HEADERS += sefht/sefht.h
@@ -44,6 +46,7 @@ nobase_include_HEADERS += sefht/text_fragment.h
 nobase_include_HEADERS += sefht/text.h
 nobase_include_HEADERS += sefht/validator.h
 nobase_include_HEADERS += sefht/validator_tag.h
+nobase_include_HEADERS += sefht/validator_attr.h
 
 libsefht_la_CPPFLAGS = -DSEFHT_COMPILATION
 libsefht_la_LDFLAGS = -version_info 0:0:0
diff --git a/src/lib/sefht/validator.c b/src/lib/sefht/validator.c
index 4700bb2..fa6aecd 100644
--- a/src/lib/sefht/validator.c
+++ b/src/lib/sefht/validator.c
@@ -31,14 +31,17 @@
 
 
 #include "validator_tag_data.h"
+#include "validator_attr_data.h"
 
 struct SH_Validator
 {
 	TAG_DATA
+	ATTR_DATA
 };
 
 
 #include "validator_tag.c"
+#include "validator_attr.c"
 
 
 /*@null@*/
@@ -62,6 +65,7 @@ SH_Validator_new (/*@null@*/ /*@out@*/ struct SH_Status * status)
 	}
 
 	init_tags (validator);
+	init_attrs (validator);
 
 	set_success (status);
 
@@ -91,6 +95,8 @@ SH_Validator_new_html5 (/*@null@*/ /*@out@*/ struct SH_Status * status)
 		return NULL;
 	}
 
+	init_attrs (validator);
+
 	set_success (status);
 	return validator;
 }
@@ -126,6 +132,17 @@ SH_Validator_copy (const struct SH_Validator * validator,
 		return NULL;
 	}
 
+	if (!copy_attrs (copy, validator, status))
+	{
+		free_tags (copy);
+/* dangerous call to silence splint, should never be executed. */
+#ifdef S_SPLINT_S
+		free (copy->attrs);
+#endif
+		free (copy);
+		return NULL;
+	}
+
 	set_success (status);
 
 	return copy;
@@ -137,6 +154,7 @@ SH_Validator_free (/*@only@*/ struct SH_Validator * validator)
 	/*@releases validator@*/
 {
 	free_tags (validator);
+	free_attrs (validator);
 	free (validator);
 
 	return;
diff --git a/src/lib/sefht/validator.h b/src/lib/sefht/validator.h
index 1221643..6e5fa17 100644
--- a/src/lib/sefht/validator.h
+++ b/src/lib/sefht/validator.h
@@ -36,6 +36,7 @@ typedef struct SH_Validator SH_Validator;
 
 #define __VALIDATOR_H_INSIDE__
 #include "validator_tag.h"
+#include "validator_attr.h"
 #undef __VALIDATOR_H_INSIDE__
 
 
diff --git a/src/lib/sefht/validator_attr.c b/src/lib/sefht/validator_attr.c
new file mode 100644
index 0000000..0041186
--- /dev/null
+++ b/src/lib/sefht/validator_attr.c
@@ -0,0 +1,448 @@
+/*
+ * validator_attr.c
+ *
+ * Copyright 2023 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.
+ *
+ *
+ */
+
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "macro.h"
+#include "log.h"
+#include "status.h"
+
+#include "validator_attr.h"
+
+
+static inline
+bool
+init_attrs (/*@special@*/ struct SH_Validator * validator)
+	/*@defines validator->attrs,
+	           validator->attr_n,
+	           validator->last_attr@*/
+	/*@modifies validator->attrs@*/
+	/*@modifies validator->attr_n@*/
+	/*@modifies validator->last_attr@*/;
+
+static inline
+bool
+copy_attrs (/*@special@*/ struct SH_Validator * copy,
+            const struct SH_Validator * validator,
+            /*@null@*/ /*@out@*/ struct SH_Status * status)
+	/*@defines copy->attrs,
+	           copy->attr_n,
+	           copy->last_attr@*/
+	/*@modifies copy->attrs@*/
+	/*@modifies copy->attr_n@*/
+	/*@modifies copy->last_attr@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/;
+
+static inline
+void
+free_attrs (/*@special@*/ struct SH_Validator * validator)
+	/*@modifies validator->attrs@*/
+	/*@releases validator->attrs@*/;
+
+static inline
+bool
+find_attr (const struct SH_Validator * validator,
+           const char * attr,
+           /*@out@*/ size_t * index)
+	/*@modifies index@*/;
+
+static inline
+Attr
+add_attr (struct SH_Validator * validator,
+          const char * attr,
+          size_t index,
+          /*@null@*/ /*@out@*/ struct SH_Status * status)
+	/*@modifies validator->attrs@*/
+	/*@modifies validator->attr_n@*/
+	/*@modifies validator->last_attr@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/;
+
+/*@unused@*/
+static inline
+bool
+is_attr_id (struct SH_Validator * validator, Attr id)
+	/*@*/;
+
+static inline
+bool
+is_attr_name (struct SH_Validator * validator, const char * name)
+	/*@*/;
+
+/*@unused@*/
+static inline
+/*@null@*/
+char *
+get_attr_name_by_id (struct SH_Validator * validator, Attr id,
+                     /*@null@*/ /*@out@*/ struct SH_Status * status)
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/;
+
+static inline
+Attr
+get_attr_id_by_name (struct SH_Validator * validator,
+                     const char * name,
+                     /*@out@*/ size_t * index)
+	/*@modifies index@*/;
+
+
+
+static inline
+bool
+init_attrs (/*@special@*/ struct SH_Validator * validator)
+	/*@defines validator->attrs,
+	           validator->attr_n,
+	           validator->last_attr@*/
+	/*@modifies validator->attrs@*/
+	/*@modifies validator->attr_n@*/
+	/*@modifies validator->last_attr@*/
+{
+	validator->attrs = malloc (0);
+	validator->attr_n = 0;
+	validator->last_attr = ATTR_ERR;
+	return TRUE;
+}
+
+static inline
+bool
+copy_attr (/*@special@*/ struct attr_info * copy,
+           const struct attr_info * attr,
+          /*@null@*/ /*@out@*/ struct SH_Status * status)
+	/*@defines copy->id,
+	           copy->name,
+	           copy->tag_n,
+	           copy->tags@*/
+	/*@modifies copy->id@*/
+	/*@modifies copy->name@*/
+	/*@modifies copy->tag_n@*/
+	/*@modifies copy->tags@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/
+{
+	char * name;
+
+	name = strdup (attr->name);
+	if (NULL == name)
+	{
+		set_status (status, E_ALLOC, 3, "strdup failed");
+		return FALSE;
+	}
+
+	copy->id = attr->id;
+	copy->name = name;
+
+	return TRUE;
+}
+
+static inline
+bool
+copy_attrs (/*@special@*/ struct SH_Validator * copy,
+            const struct SH_Validator * validator,
+            /*@null@*/ /*@out@*/ struct SH_Status * status)
+	/*@defines copy->attrs,
+	           copy->attr_n,
+	           copy->last_attr@*/
+	/*@modifies copy->attrs@*/
+	/*@modifies copy->attr_n@*/
+	/*@modifies copy->last_attr@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/
+{
+	size_t index;
+
+	/* The size calculation is save,
+	 * because validator is already allocated. */
+	copy->attrs = malloc (validator->attr_n
+	                      * sizeof (struct attr_info));
+
+	if (NULL == copy->attrs)
+	{
+		set_status (status, E_ALLOC, 5, "malloc failed");
+		return FALSE;
+	}
+
+	/* copy data */
+	for (index = 0; index < validator->attr_n; index++)
+	{
+		if (!copy_attr (&copy->attrs[index],
+		                &validator->attrs[index], status))
+		{
+			copy->attr_n = index;
+			free_attrs (copy);
+			return FALSE;
+		}
+	}
+
+	copy->attr_n = validator->attr_n;
+	copy->last_attr = validator->last_attr;
+
+	return TRUE;
+}
+
+static inline
+void
+free_attrs (/*@special@*/ struct SH_Validator * validator)
+	/*@modifies validator->attrs@*/
+	/*@releases validator->attrs@*/
+{
+	size_t index;
+
+	for (index = 0; index < validator->attr_n; index++)
+	{
+		free (validator->attrs[index].name);
+	}
+
+	free (validator->attrs);
+	return;
+}
+
+static inline
+bool
+find_attr (const struct SH_Validator * validator,
+           const char * attr,
+           /*@out@*/ size_t * index)
+	/*@modifies index@*/
+{
+	size_t start;
+	size_t end;
+	size_t pivot;
+
+	start = 0;
+	end = validator->attr_n;
+	pivot = (end - start) / 2;
+
+	while (start != end)
+	{
+		int cmp = strcmp (attr, validator->attrs[pivot].name);
+
+		if (0 > cmp)
+		{
+			end = pivot;
+			pivot = (pivot - start) / 2 + start;
+		}
+		else if (0 == cmp)
+		{
+			*index = pivot;
+			return TRUE;
+		}
+		else
+		{
+			start = pivot + 1;
+			pivot = (end - pivot) / 2 + pivot;
+		}
+	}
+
+	*index = start;
+	return FALSE;
+}
+
+static inline
+Attr
+add_attr (struct SH_Validator * validator,
+          const char * attr,
+          size_t index,
+          /*@null@*/ /*@out@*/ struct SH_Status * status)
+	/*@modifies validator->attrs@*/
+	/*@modifies validator->attr_n@*/
+	/*@modifies validator->last_attr@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/
+{
+	struct attr_info attr_data;
+	struct attr_info * new_attrs;
+
+	/* abort on overflow:
+	 * - no unused Attr or
+	 * - no unused index */
+	if ((validator->last_attr == ATTR_MAX)
+	|| (validator->attr_n == SIZE_MAX)
+	|| ((validator->attr_n + 1)
+	            > (SIZE_MAX / sizeof (struct attr_info))))
+	{
+		set_status (status, E_DOMAIN, 2,
+		            "maximum number of attributes reached");
+		return ATTR_ERR;
+	}
+
+	attr_data.id = NEXT_ATTR (validator->last_attr);
+	attr_data.name = strdup (attr);
+	if (NULL == attr_data.name)
+	{
+		set_status (status, E_ALLOC, 3, "strdup failed");
+		return ATTR_ERR;
+	}
+
+	/* allocate new space */
+	/* The addition and the multiplication is save,
+	 * because we have tested for this
+	 * in the first condition. */
+	new_attrs = realloc (validator->attrs,
+			     sizeof (struct attr_info)
+			     * (validator->attr_n + 1));
+
+	if (new_attrs == NULL)
+	{
+		set_status (status, E_ALLOC, 6, "realloc failed");
+
+/* bad code to silence splint, should never be executed. */
+#ifdef S_SPLINT_S
+		validator->attrs = (void *) 0x12345;
+#endif
+		free (attr_data.name);
+		return ATTR_ERR;
+	}
+
+	validator->attrs = new_attrs;
+
+	for (size_t index2 = validator->attr_n; index2 > index; index2--)
+	{
+		validator->attrs[index2] = validator->attrs[index2-1];
+	}
+
+	/* commit changes */
+	validator->attrs[index] = attr_data;
+	validator->attr_n++;
+	validator->last_attr = attr_data.id;
+
+	set_success (status);
+	return attr_data.id;
+}
+
+/*@unused@*/
+static inline
+bool
+is_attr_id (struct SH_Validator * validator, Attr id)
+	/*@*/
+{
+	size_t index;
+
+	for (index = 0; index < validator->attr_n; index++)
+	{
+		if (id == validator->attrs[index].id)
+		{
+			return TRUE;
+		}
+	}
+
+	return FALSE;
+}
+
+static inline
+bool
+is_attr_name (struct SH_Validator * validator, const char * name)
+	/*@*/
+{
+	size_t index;
+	return find_attr (validator, name, &index);
+}
+
+/*@unused@*/
+static inline
+/*@null@*/
+char *
+get_attr_name_by_id (struct SH_Validator * validator, Attr id,
+                     /*@null@*/ /*@out@*/ struct SH_Status * status)
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/
+{
+	size_t index;
+	char * name;
+
+	for (index = 0; index < validator->attr_n; index++)
+	{
+		if (id == validator->attrs[index].id)
+		{
+			name = strdup (validator->attrs[index].name);
+			if (name == NULL)
+			{
+				set_status (status, E_ALLOC, 3,
+				            "strdup failed");
+				return NULL;
+			}
+
+			return name;
+		}
+	}
+
+	return NULL;
+}
+
+static inline
+Attr
+get_attr_id_by_name (struct SH_Validator * validator,
+                     const char * name,
+                     /*@out@*/ size_t * index)
+	/*@modifies index@*/
+{
+	if (!find_attr (validator, name, index))
+	{
+		return ATTR_ERR;
+	}
+
+	return validator->attrs[*index].id;
+}
+
+bool
+SH_Validator_check_attr (struct SH_Validator * validator,
+                         const char * attr)
+	/*@*/
+{
+	return is_attr_name (validator, attr);
+}
+
+Attr
+SH_Validator_register_attr (struct SH_Validator * validator,
+                            const char * attr,
+                            /*@null@*/ /*@out@*/
+                            struct SH_Status * status)
+	/*@modifies validator->attrs@*/
+	/*@modifies validator->attr_n@*/
+	/*@modifies validator->last_attr@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/
+{
+	Attr attr_id;
+	size_t index;
+
+	/* attr already registered */
+	attr_id = get_attr_id_by_name (validator, attr, &index);
+	if (attr_id != ATTR_ERR)
+	{
+		return attr_id;
+	}
+
+	return add_attr (validator, attr, index, status);
+}
diff --git a/src/lib/sefht/validator_attr.h b/src/lib/sefht/validator_attr.h
new file mode 100644
index 0000000..a89a72b
--- /dev/null
+++ b/src/lib/sefht/validator_attr.h
@@ -0,0 +1,59 @@
+/*
+ * validator_attr.h
+ *
+ * Copyright 2023 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_VALIDATOR_ATTR_H
+#define SEFHT_VALIDATOR_ATTR_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 Attr;
+#define ATTR_ERR (Attr) 0
+#define ATTR_MIN (Attr) 1
+#define ATTR_MAX (Attr) SIZE_MAX
+
+
+Attr
+SH_Validator_register_attr (SH_Validator * validator,
+                            const char * attr,
+                            /*@null@*/ /*@out@*/
+                            struct SH_Status * status)
+	/*@modifies validator@*/
+	/*@globals fileSystem@*/
+	/*@modifies fileSystem@*/
+	/*@modifies status@*/;
+
+bool
+SH_Validator_check_attr (struct SH_Validator * validator,
+                         const char * attr)
+	/*@*/;
+
+#endif /* SEFHT_VALIDATOR_ATTR_H */
diff --git a/src/lib/sefht/validator_attr_data.h b/src/lib/sefht/validator_attr_data.h
new file mode 100644
index 0000000..ff9d6cf
--- /dev/null
+++ b/src/lib/sefht/validator_attr_data.h
@@ -0,0 +1,45 @@
+/*
+ * validator_attr_data.h
+ *
+ * Copyright 2023 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_VALIDATOR_ATTR_DATA_H
+#define SEFHT_VALIDATOR_ATTR_DATA_H
+
+#if !defined (SEFHT_SEFHT_H_INSIDE) && !defined (SEFHT_COMPILATION)
+#error "Only <sefht/sefht.h> can be included directly."
+#endif
+
+struct attr_info
+{
+	Attr id;
+	/*@only@*/ char * name;
+};
+
+#define NEXT_ATTR(attr) (attr + 1)
+
+#define ATTR_DATA                                                      \
+	/*@only@*/ struct attr_info * attrs;                           \
+	size_t attr_n;                                                 \
+	Attr last_attr;                                                \
+
+#endif /* SEFHT_VALIDATOR_ATTR_DATA_H */
-- 
GitLab