From 92ed2019e4948f1feb32d9c3ecfb0455323bbe3a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonathan=20Sch=C3=B6bel?= <jonathan@xn--schbel-yxa.info>
Date: Mon, 13 Mar 2023 20:23:14 +0100
Subject: [PATCH] Fragment: added parent

Every fragment has a parent now, this is useful for both traversing the
tree and checking for cycles when a node is added, which would cause
problems, like freeing things twice or similar nice bugs. Both wouldn't
be possible otherwise. These features are not implemented yet.
---
 sefht.geany                    | 14 ++++++------
 src/lib/sefht/fragment.c       | 10 ++++++++-
 src/lib/sefht/fragment.h       |  4 ++++
 src/lib/sefht/fragment_class.c | 41 +++++++++++++++++++++++++++++-----
 src/lib/sefht/fragment_data.c  |  6 +++--
 src/lib/sefht/node_fragment.c  | 17 +++++++++++---
 src/lib/sefht/node_fragment.h  |  6 +++++
 tests/test_node_fragment.c     | 15 +++++++++++++
 8 files changed, 94 insertions(+), 19 deletions(-)

diff --git a/sefht.geany b/sefht.geany
index 49a3bad..d24bc35 100644
--- a/sefht.geany
+++ b/sefht.geany
@@ -37,12 +37,12 @@ FILE_NAME_4=1593;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fpr
 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=7399;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_8=1550;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=1562;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=2022;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=2558;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=6660;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=2360;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
@@ -56,7 +56,7 @@ FILE_NAME_23=1078;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fp
 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=15178;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_node_fragment.c;0;8
+FILE_NAME_27=9757;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
diff --git a/src/lib/sefht/fragment.c b/src/lib/sefht/fragment.c
index 6a306bd..72d4707 100644
--- a/src/lib/sefht/fragment.c
+++ b/src/lib/sefht/fragment.c
@@ -27,11 +27,12 @@
 #include "status.h"
 
 #include "text.h"
+#include "node_fragment.h"
 
 #include "fragment.h"
 
 
-#include "fragment_data.c"
+#include "fragment_class.c"
 
 /*@null@*/
 /*@only@*/
@@ -54,6 +55,13 @@ SH_Fragment_free (/*@only@*/ struct SH_Fragment * fragment)
 	return;
 }
 
+bool
+SH_Fragment_is_orphan (const struct SH_Fragment * fragment)
+	/*@*/
+{
+	return get_parent (fragment) == NULL;
+}
+
 /*@null@*/
 /*@only@*/
 SH_Text *
diff --git a/src/lib/sefht/fragment.h b/src/lib/sefht/fragment.h
index f2602e8..b55542c 100644
--- a/src/lib/sefht/fragment.h
+++ b/src/lib/sefht/fragment.h
@@ -58,6 +58,10 @@ SH_Fragment_free (/*@only@*/ SH_Fragment * fragment)
 	/*@modifies fragment@*/
 	/*@releases fragment@*/;
 
+bool
+SH_Fragment_is_orphan (const SH_Fragment * fragment)
+	/*@*/;
+
 /*@null@*/
 /*@only@*/
 SH_Text *
diff --git a/src/lib/sefht/fragment_class.c b/src/lib/sefht/fragment_class.c
index 3a478d1..8fd9a41 100644
--- a/src/lib/sefht/fragment_class.c
+++ b/src/lib/sefht/fragment_class.c
@@ -41,18 +41,24 @@
 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@*/
+               const struct fragment_methods * const methods,
+               /*@dependent@*/ SH_Data * data,
+               /*@null@*/ /*@dependent@*/
+               struct SH_NodeFragment * parent)
 	/*@modifies fragment->type@*/
 	/*@modifies fragment->methods@*/
+	/*@modifies fragment->data@*/
+	/*@modifies fragment->parent@*/
 {
-	fragment->data = data;
 	fragment->type = type;
 	fragment->methods = methods;
 
+	fragment->data = data;
+
+	fragment->parent = parent;
+
 	return;
 }
 
@@ -70,14 +76,18 @@ static inline
 void
 copy_fragment (/*@out@*/ struct SH_Fragment * copy,
                const struct SH_Fragment * fragment)
-	/*@modifies copy->data@*/
 	/*@modifies copy->type@*/
 	/*@modifies copy->methods@*/
+	/*@modifies copy->data@*/
+	/*@modifies copy->parent@*/
 {
-	copy->data = fragment->data;
 	copy->type = fragment->type;
 	copy->methods = fragment->methods;
 
+	copy->data = fragment->data;
+
+	copy->parent = NULL;
+
 	return;
 }
 
@@ -89,5 +99,24 @@ get_type (const struct SH_Fragment * fragment)
 	return fragment->type;
 }
 
+static inline
+/*@null@*/
+/*@dependent@*/
+struct SH_NodeFragment *
+get_parent (const struct SH_Fragment * fragment)
+{
+	return fragment->parent;
+}
+
+static inline
+void
+set_parent (struct SH_Fragment * fragment,
+            /*@null@*/ /*@dependent@*/ struct SH_NodeFragment * parent)
+	/*@modifies fragment->parent@*/
+{
+	fragment->parent = parent;
+	return;
+}
+
 #endif /* SEFHT_COMPILATION */
 #endif /* SEFHT_FRAGMENT_CLASS_C */
diff --git a/src/lib/sefht/fragment_data.c b/src/lib/sefht/fragment_data.c
index f55a71c..617f629 100644
--- a/src/lib/sefht/fragment_data.c
+++ b/src/lib/sefht/fragment_data.c
@@ -76,10 +76,12 @@ struct fragment_methods
 
 struct SH_Fragment
 {
-	/*@dependent@*/ SH_Data * data;
-
 	enum SH_FRAGMENT_TYPE type;
 	/*@shared@*/ const struct fragment_methods * methods;
+
+	/*@dependent@*/ SH_Data * data;
+
+	/*@null@*/ /*@dependent@*/ struct SH_NodeFragment * parent;
 };
 
 #endif /* SEFHT_COMPILATION */
diff --git a/src/lib/sefht/node_fragment.c b/src/lib/sefht/node_fragment.c
index c9a518d..d3dcf04 100644
--- a/src/lib/sefht/node_fragment.c
+++ b/src/lib/sefht/node_fragment.c
@@ -49,7 +49,7 @@ struct SH_NodeFragment
 	/*@only@*/ char * tag;
 
 	size_t child_n;
-	struct SH_Fragment ** childs;
+	/*@only@*/ struct SH_Fragment ** childs;
 };
 
 #define OPEN_TAG_BEGIN "<"
@@ -100,7 +100,7 @@ SH_NodeFragment_new (const char * tag,
 		return NULL;
 	}
 
-	init_fragment (&(fragment->base), data, NODE, &methods);
+	init_fragment (&(fragment->base), NODE, &methods, data, NULL);
 
 	fragment->tag = strdup (tag);
 	if (fragment->tag == NULL)
@@ -146,9 +146,10 @@ SH_NodeFragment_raw_new (/*@only@*/ char * tag,
 		return NULL;
 	}
 
-	init_fragment (&(fragment->base), data, NODE, &methods);
+	init_fragment (&(fragment->base), NODE, &methods, data, NULL);
 
 	fragment->tag = tag;
+
 	fragment->child_n = 0;
 	fragment->childs = malloc (0);
 
@@ -296,6 +297,7 @@ SH_NodeFragment_deepcopy (const struct SH_NodeFragment * fragment,
 		}
 
 		copy->childs[index] = child;
+		child->parent = copy;
 	}
 
 	set_success (status);
@@ -353,6 +355,15 @@ SH_NodeFragment_raw_get_tag (const struct SH_NodeFragment * fragment)
 	return get_tag (fragment);
 }
 
+/*@null@*/
+/*@dependent@*/
+struct SH_NodeFragment *
+SH_Fragment_get_parent (const struct SH_Fragment * fragment)
+	/*@*/
+{
+	return get_parent (fragment);
+}
+
 /*@null@*/
 /*@observer@*/
 struct SH_Fragment *
diff --git a/src/lib/sefht/node_fragment.h b/src/lib/sefht/node_fragment.h
index 46be532..f325428 100644
--- a/src/lib/sefht/node_fragment.h
+++ b/src/lib/sefht/node_fragment.h
@@ -80,6 +80,12 @@ bool
 SH_Fragment_is_NodeFragment (const SH_Fragment * fragment)
 	/*@*/;
 
+/*@null@*/
+/*@dependent@*/
+SH_NodeFragment *
+SH_Fragment_get_parent (const SH_Fragment * fragment)
+	/*@*/;
+
 /*@null@*/
 /*@only@*/
 char *
diff --git a/tests/test_node_fragment.c b/tests/test_node_fragment.c
index 6c53371..23cf298 100644
--- a/tests/test_node_fragment.c
+++ b/tests/test_node_fragment.c
@@ -45,6 +45,7 @@ START_TEST(test_node_fragment)
 	fragment = SH_NodeFragment_new (tag, data, NULL);
 	ck_assert_int_ne ((long int) fragment, (long int) NULL);
 
+	ck_assert_ptr_eq (NULL, fragment->parent);
 	ck_assert_str_eq (((struct SH_NodeFragment *) fragment)->tag, tag);
 
 	SH_Fragment_free (fragment);
@@ -55,6 +56,7 @@ START_TEST(test_node_fragment)
 	ck_assert_int_ne ((long int) fragment, (long int) NULL);
 	ck_assert_int_eq (status.status, SUCCESS);
 
+	ck_assert_ptr_eq (NULL, fragment->parent);
 	ck_assert_str_eq (((struct SH_NodeFragment *) fragment)->tag, tag);
 
 	SH_Fragment_free (fragment);
@@ -77,6 +79,7 @@ START_TEST(test_node_fragment_raw_new)
 	fragment = SH_NodeFragment_raw_new (tag1, data, NULL);
 	ck_assert_int_ne ((long int) fragment, (long int) NULL);
 
+	ck_assert_ptr_eq (NULL, fragment->parent);
 	ck_assert_ptr_eq (((struct SH_NodeFragment *) fragment)->tag, tag1);
 
 	SH_Fragment_free (fragment);
@@ -87,6 +90,7 @@ START_TEST(test_node_fragment_raw_new)
 	ck_assert_int_ne ((long int) fragment, (long int) NULL);
 	ck_assert_int_eq (status.status, SUCCESS);
 
+	ck_assert_ptr_eq (NULL, fragment->parent);
 	ck_assert_ptr_eq (((struct SH_NodeFragment *) fragment)->tag, tag2);
 
 	SH_Fragment_free (fragment);
@@ -112,6 +116,7 @@ START_TEST(test_node_fragment_copy)
 
 	ck_assert_ptr_ne (copy, NULL);
 	ck_assert_ptr_ne (fragment, copy);
+	ck_assert_ptr_eq (NULL, copy->parent);
 	ck_assert_str_eq (((struct SH_NodeFragment *) fragment)->tag,
 			  ((struct SH_NodeFragment *) copy)->tag);
 	ck_assert_int_eq (((struct SH_NodeFragment *) copy)->child_n, 0);
@@ -128,6 +133,7 @@ START_TEST(test_node_fragment_copy)
 
 	ck_assert_ptr_ne (copy, NULL);
 	ck_assert_ptr_ne (fragment, copy);
+	ck_assert_ptr_eq (NULL, copy->parent);
 	ck_assert_str_eq (((struct SH_NodeFragment *) fragment)->tag,
 			  ((struct SH_NodeFragment *) copy)->tag);
 	ck_assert_int_eq (((struct SH_NodeFragment *) copy)->child_n, 0);
@@ -150,6 +156,7 @@ check_childs (struct SH_NodeFragment * fragment, struct SH_NodeFragment * copy)
 	{
 		ck_assert_ptr_ne (((struct SH_NodeFragment *) fragment->childs[index]),
 				  ((struct SH_NodeFragment *) copy->childs[index]));
+		ck_assert_ptr_eq (copy, get_parent (copy->childs[index]));
 		ck_assert_str_eq (((struct SH_NodeFragment *) fragment->childs[index])->tag,
 				  ((struct SH_NodeFragment *) copy->childs[index])->tag);
 		ck_assert_int_eq (((struct SH_NodeFragment *) fragment->childs[index])->child_n,
@@ -206,6 +213,7 @@ START_TEST(test_node_fragment_deepcopy)
 
 	ck_assert_ptr_ne (copy, NULL);
 	ck_assert_ptr_ne (fragment, copy);
+	ck_assert_ptr_eq (NULL, copy->parent);
 	ck_assert_str_eq (((struct SH_NodeFragment *) fragment)->tag,
 			  ((struct SH_NodeFragment *) copy)->tag);
 	ck_assert_int_eq (((struct SH_NodeFragment *) fragment)->child_n,
@@ -225,6 +233,7 @@ START_TEST(test_node_fragment_deepcopy)
 
 	ck_assert_ptr_ne (copy, NULL);
 	ck_assert_ptr_ne (fragment, copy);
+	ck_assert_ptr_eq (NULL, copy->parent);
 	ck_assert_str_eq (((struct SH_NodeFragment *) fragment)->tag,
 			  ((struct SH_NodeFragment *) copy)->tag);
 	ck_assert_int_eq (((struct SH_NodeFragment *) fragment)->child_n,
@@ -307,6 +316,9 @@ START_TEST(test_node_fragment_child)
 	ck_assert_ptr_eq (((struct SH_NodeFragment *) parent)->childs[0],
 			  child1);
 
+	/* TODO: not implemented yet. */
+	//~ ck_assert_ptr_eq (parent, get_parent (child1));
+
 	/* with error */
 	ck_assert_int_eq (((struct SH_NodeFragment *) parent)->child_n, 1);
 
@@ -320,6 +332,9 @@ START_TEST(test_node_fragment_child)
 	ck_assert_ptr_eq (((struct SH_NodeFragment *) parent)->childs[1],
 			  child2);
 
+	/* TODO: not implemented yet. */
+	//~ ck_assert_ptr_eq (parent, get_parent (child2));
+
 	SH_Fragment_free (parent);
 
 	SH_Data_free (data);
-- 
GitLab