1%%	options
2
3copyright owner	=	Dirk Krause
4copyright year	=	2013-xxxx
5SPDX-License-Identifier:	BSD-3-Clause
6
7
8
9%%	header
10
11#ifdef __cplusplus
12extern "C" {
13#endif
14
15/**	Compare two nodes.
16	@param	l	Pointer to left node.
17	@param	r	Pointer to right node.
18	@param	cr	Comparison criteria (ignored).
19	@return	Comparison result.
20*/
21int
22hb_node_compare(void const *l, void const *r, int cr);
23
24/**	Create node, allocate memory.
25	@param	job	Job structure.
26	@param	parent	Parent node.
27	@param	lineno	Line number where object was created.
28	@param	objno	Object number (in order of creation).
29	@param	indent	Line indent.
30	@return	Pointer to new node on success, NULL on error.
31*/
32hb_node_t *
33hb_node_new(
34  hb_job_t		*job,
35  hb_node_t		*parent,
36  unsigned long		 lineno,
37  unsigned long		 objno,
38  int			 indent
39);
40
41/**	Destroy node, release memory.
42	@param	ptr	Node to destroy.
43*/
44void
45hb_node_delete(hb_node_t *ptr);
46
47/**	Search for variable in node and parents.
48	@param	node	Start node for search.
49	@param	name	Variable name.
50	@return	Pointer to value on success, NULL on error.
51*/
52dkChar const *
53hbnode_variable(hb_node_t *node, dkChar const *name);
54
55/**	Create link structure.
56	@param	url	URL to store.
57	@param	lno	Link number.
58	@param	app	Application structure for diagnostics, may be NULL.
59	@return	Pointer to new link structure on success, NULL on error.
60*/
61hb_link_t *
62hbnode_link_new(dkChar const *url, unsigned long lno, dk3_app_t *app);
63
64/**	Delete link structure.
65	@param	ptr	Link structure to delete.
66*/
67void
68hbnode_link_delete(hb_link_t *ptr);
69
70/**	Compare two link structures.
71	@param	l	Left structure.
72	@param	r	Right structure or URL.
73	@param	cr	Comparison criteria
74			(0=obj/obj by URL, 1=obj/URL, 2=obj/obj by lno).
75	@return	Comparison result.
76*/
77int
78hbnode_link_compare(const void *l, const void *r, int cr);
79
80#ifdef __cplusplus
81}
82#endif
83
84%%	module
85
86#include <htmlbook/htmlbook.h>
87#include <libdk3c/dk3all.h>
88#include <libdk3c/dk3unused.h>
89
90
91
92$!trace-include
93
94
95
96void
97hbnode_link_delete(hb_link_t *ptr)
98{
99  $? "+ hbnode_link_delete"
100  if(ptr) {
101    ptr->lno = 0UL;
102    dk3_release(ptr->url);
103    dk3_delete(ptr);
104  } $? "- hbnode_link_delete"
105}
106
107
108
109hb_link_t *
110hbnode_link_new(dkChar const *url, unsigned long lno, dk3_app_t *app)
111{
112  hb_link_t	*back	= NULL;
113  $? "+ hbnode_link_new"
114  if(url) {
115    back = dk3_new_app(hb_link_t,1,app);
116    if(back) {
117      back->lno		= lno;
118      back->url		= dk3str_dup_app(url,app);
119      back->flags	= 0;
120      if(!(back->url)) {
121        hbnode_link_delete(back);
122	back = NULL;
123      }
124    }
125  } $? "- hbnode_link_new PTR=%d", TR_IPTR(back)
126  return back;
127}
128
129
130
131int
132hbnode_link_compare(const void *l, const void *r, int cr)
133{
134  hb_link_t	*pl;
135  hb_link_t	*pr;
136  int		 back	= 0;
137  $? "+ hbnode_link_compare PTR=%d PTR=%d", TR_IPTR(l), TR_IPTR(r)
138  if(l) {
139    if(r) {
140      pl = (hb_link_t *)l;
141      switch(cr) {
142        case 0: {
143	  pr = (hb_link_t *)r;
144	  back = dk3str_cmp(pl->url, pr->url);
145	} break;
146	case 1: {
147	  back = dk3str_cmp(pl->url, (dkChar const *)r);
148	} break;
149	default: {
150	  pr = (hb_link_t *)r;
151	  if(pl->lno > pr->lno) {
152	    back = 1;
153	  } else {
154	    if(pl->lno < pr->lno) {
155	      back = -1;
156	    }
157	  }
158	} break;
159      }
160      if(-1 > back) { back = -1; }
161      if( 1 < back) { back =  1; }
162    } else back = 1;
163  } else {
164    if(r) back = -1;
165  } $? "- hbnode_link_compare %d", back
166  return back;
167}
168
169
170
171int
172hb_node_compare(void const *l, void const *r, int DK3_ARG_UNUSED(cr) )
173{
174  hb_node_t const	*pl;
175  hb_node_t const	*pr;
176  int			 back = 0;
177  $? "+ hb_node_compare PTR=%d PTR=%d", TR_IPTR(l), TR_IPTR(r)
178  DK3_UNUSED_ARG(cr)
179  if(l) {
180    if(r) {
181      pl = (hb_node_t const *)l;
182      pr = (hb_node_t const *)r;
183      if(pl->objno > pr->objno) {
184        back = 1;
185      } else {
186        if(pr->objno > pl->objno) {
187	  back = -1;
188	}
189      }
190    } else {
191      back = 1;
192    }
193  } else {
194    if(r) {
195      back = -1;
196    }
197  } $? "- hb_node_compare %d", back
198  return back;
199}
200
201
202
203void
204hb_node_delete(hb_node_t *ptr)
205{
206  hb_link_t		*linkptr;
207  hb_line_t		*hp;
208  dk3_key_value_t	*kp;
209  if(ptr) {
210    $? "+ hb_node_delete \"%!ds\"", TR_STR(ptr->title)
211    if(ptr->s_lbylno) {
212      if(ptr->i_lbylno) {
213        dk3sto_it_close(ptr->i_lbylno);
214      }
215      dk3sto_close(ptr->s_lbylno);
216    }
217    ptr->s_lbylno = NULL; ptr->i_lbylno = NULL;
218    if(ptr->s_lbyurl) {
219      if(ptr->i_lbyurl) {
220        dk3sto_it_reset(ptr->i_lbyurl);
221	while(NULL != (linkptr = (hb_link_t *)dk3sto_it_next(ptr->i_lbyurl))) {
222	  hbnode_link_delete(linkptr);
223	}
224        dk3sto_it_close(ptr->i_lbyurl);
225      }
226      dk3sto_close(ptr->s_lbyurl);
227    }
228    ptr->s_lbyurl = NULL; ptr->i_lbyurl = NULL;
229    if(ptr->s_lines) {
230      if(ptr->i_lines) {
231        dk3sto_it_reset(ptr->i_lines);
232	while(NULL != (hp = (hb_line_t *)dk3sto_it_next(ptr->i_lines))) {
233	  hbcont_line_delete(hp);
234	}
235        dk3sto_it_close(ptr->i_lines);
236      }
237      dk3sto_close(ptr->s_lines);
238    } ptr->s_lines = NULL; ptr->i_lines = NULL;
239    if(ptr->s_variables) {
240      if(ptr->i_variables) {
241        dk3sto_it_reset(ptr->i_variables);
242	do {
243	  kp = (dk3_key_value_t *)dk3sto_it_next(ptr->i_variables);
244	  if(kp) { dk3kv_delete(kp); }
245	} while(kp);
246        dk3sto_it_close(ptr->i_variables);
247      }
248      dk3sto_close(ptr->s_variables);
249    }
250    ptr->s_variables = NULL; ptr->i_variables = NULL;
251    if(ptr->s_jsfiles) {
252      if(ptr->i_jsfiles) {
253        dk3sto_it_reset(ptr->i_jsfiles);
254	while(NULL != (linkptr = (hb_link_t *)dk3sto_it_next(ptr->i_jsfiles))) {
255	  $? ". js file %lu \"%!ds\"", linkptr->lno, linkptr->url
256	  hbnode_link_delete(linkptr);
257	}
258        dk3sto_it_close(ptr->i_jsfiles);
259      }
260      dk3sto_close(ptr->s_jsfiles);
261    } ptr->s_jsfiles = NULL; ptr->i_jsfiles = NULL;
262    /*	We can simply close the storage here, all nodes are listed
263    	in the s_nodes storage of the job structure.
264    */
265    if(ptr->s_subnodes) {
266      if(ptr->i_subnodes) {
267        dk3sto_it_close(ptr->i_subnodes);
268      }
269      dk3sto_close(ptr->s_subnodes);
270    }
271    ptr->s_subnodes = NULL;
272    ptr->i_subnodes = NULL;
273    ptr->parent = NULL;
274    ptr->curchild = NULL;
275    ptr->jumpnode = NULL;
276#if TRACE_DEBUG
277    $? ". objno = %lu", ptr->objno
278    $? ". lineno = %lu", ptr->lineno
279    $? ". options = %u", ptr->options
280    $? ". indent = %d", ptr->indent
281    if(ptr->parent) {	$? ". have parent"
282    }
283    if(ptr->title) {	$? ". title = \"%!ds\"", ptr->title
284    }
285    if(ptr->shorttitle) {	$? ". shorttitle = \"%!ds\"", ptr->shorttitle
286    }
287    if(ptr->fulltitle) {	$? ". fulltitle= = \"%!ds\"", ptr->fulltitle
288    }
289    if(ptr->filename) {	$? ". filename = \"%!ds\"", ptr->filename
290    }
291    if(ptr->suffix) {	$? ". suffix = \"%!ds\"", ptr->suffix
292    }
293    if(ptr->templatefi) {	$? ". templatefi = \"%!ds\"", ptr->templatefi
294    }
295    if(ptr->stylefile) {	$? ". stylefile = \"%!ds\"", ptr->stylefile
296    }
297    if(ptr->author) {	$? ". author = \"%!ds\"", ptr->author
298    }
299    if(ptr->location) {	$? ". location = \"%!ds\"", ptr->location
300    }
301    if(ptr->icontoc) {	$? ". icontoc = \"%!ds\"", ptr->icontoc
302    }
303    if(ptr->iconprev) {	$? ". iconprev = \"%!ds\"", ptr->iconprev
304    }
305    if(ptr->iconnext) {	$? ". iconnext = \"%!ds\"", ptr->iconnext
306    }
307    if(ptr->iconhome) {	$? ". iconhome = \"%!ds\"", ptr->iconhome
308    }
309    if(ptr->iconindex) {	$? ". iconindex = \"%!ds\"", ptr->iconindex
310    }
311    if(ptr->favicon) {	$? ". favicon = \"%!ds\"", ptr->favicon
312    }
313    if(ptr->metadesc) {	$? ". metadesc = \"%!ds\"", ptr->metadesc
314    }
315    if(ptr->metakeyw) {	$? ". metakeyw = \"%!ds\"", ptr->metakeyw
316    }
317#endif
318    dk3_release(ptr->title);
319    dk3_release(ptr->shorttitle);
320    dk3_release(ptr->fulltitle);
321    dk3_release(ptr->filename);
322    dk3_release(ptr->suffix);
323    dk3_release(ptr->templatefi);
324    dk3_release(ptr->stylefile);
325    dk3_release(ptr->author);
326    dk3_release(ptr->location);
327    dk3_release(ptr->icontoc);
328    dk3_release(ptr->iconprev);
329    dk3_release(ptr->iconnext);
330    dk3_release(ptr->iconindex);
331    dk3_release(ptr->iconhome);
332    dk3_release(ptr->favicon);
333    dk3_release(ptr->metadesc);
334    dk3_release(ptr->metakeyw);
335    ptr->lineno = 0UL;
336    ptr->objno = 0UL;
337    ptr->indent = 0;
338    ptr->inenc = 0;
339    ptr->options = 0U;
340    ptr->havenavimenu = 0;
341    dk3_delete(ptr);
342    $? "- hb_node_delete"
343  }
344}
345
346
347
348/**	Find depth of a node.
349	@param	ptr	Node to inspect.
350	@return	Node depth.
351*/
352static
353int
354hbnode_find_depth(hb_node_t *ptr)
355{
356  int		 back = 0;
357  $? "+ hbnode_find_depth"
358  ptr = ptr->parent;
359  while(ptr) {
360    back++;
361    ptr = ptr->parent;
362  } $? "- hbnode_find_depth %d", back
363  return back;
364}
365
366
367
368hb_node_t *
369hb_node_new(
370  hb_job_t		*job,
371  hb_node_t		*parent,
372  unsigned long		 lineno,
373  unsigned long		 objno,
374  int			 indent
375)
376{
377  hb_node_t		*back	= NULL;
378  int			 ok	= 0;
379  $? "+ hb_node_new"
380  back = dk3_new_app(hb_node_t,1,job->app);
381  if(back) {
382    back->parent = parent;
383    back->curchild = NULL;
384    back->jumpnode = NULL;
385    back->s_subnodes = NULL;
386    back->i_subnodes = NULL;
387    back->s_variables = NULL;
388    back->i_variables = NULL;
389    back->s_lines = NULL;
390    back->i_lines = NULL;
391    back->s_lbyurl = NULL;
392    back->i_lbyurl = NULL;
393    back->s_lbylno = NULL;
394    back->i_lbylno = NULL;
395    back->s_jsfiles = NULL;
396    back->i_jsfiles = NULL;
397    back->title = NULL;
398    back->shorttitle = NULL;
399    back->fulltitle = NULL;
400    back->filename = NULL;
401    back->suffix = NULL;
402    back->templatefi = NULL;
403    back->stylefile = NULL;
404    back->author = NULL;
405    back->location = NULL;
406    back->icontoc = NULL;
407    back->iconprev = NULL;
408    back->iconnext = NULL;
409    back->iconindex = NULL;
410    back->iconhome = NULL;
411    back->favicon = NULL;
412    back->metadesc = NULL;
413    back->metakeyw = NULL;
414    back->lineno = lineno;
415    back->objno = objno;
416    back->pobjno = 0UL;
417    back->nextlink = 0UL;
418    back->nextindex = 0UL;
419    back->outFileName = NULL;
420    back->headno = 0UL;
421    back->nextsubheadno = 0UL;
422    back->nextjs = 0UL;
423    back->contnum = 0L;
424    back->havenavimenu = 0;
425    back->htdt = HTML_DOCTYPE_UNSPECIFIED;
426    /* back->inenc = -1; */
427    if(parent) {
428      back->inenc = parent->inenc;
429    } else {
430      back->inenc = job->iecmd;
431    }
432    /*	As each node is configured after the parent is finished we can
433    	implement option inheritance by simply copying the parents options.
434    */
435    back->options = 0U; if(parent) { back->options = parent->options; }
436    back->indent = indent;
437    back->depth = 0;
438    back->tocstate = HB_TOC_STATE_INIT;
439    back->s_subnodes = dk3sto_open_app(job->app);
440    if(back->s_subnodes) {
441      dk3sto_set_comp(back->s_subnodes, hb_node_compare, 0);
442      back->i_subnodes = dk3sto_it_open(back->s_subnodes);
443      if(back->i_subnodes) {
444        back->s_variables = dk3sto_open_app(job->app);
445	if(back->s_variables) {
446	  dk3sto_set_comp(back->s_variables, dk3kv_compare, 0);
447	  back->i_variables = dk3sto_it_open(back->s_variables);
448	  if(back->i_variables) {
449	    back->s_lbyurl = dk3sto_open_app(job->app);
450	    if(back->s_lbyurl) {
451	      dk3sto_set_comp(back->s_lbyurl, hbnode_link_compare, 0);
452	      back->i_lbyurl = dk3sto_it_open(back->s_lbyurl);
453	      if(back->i_lbyurl) {
454	        back->s_lbylno = dk3sto_open_app(job->app);
455		if(back->s_lbylno) {
456		  dk3sto_set_comp(back->s_lbylno, hbnode_link_compare, 2);
457		  back->i_lbylno = dk3sto_it_open(back->s_lbylno);
458		  if(back->i_lbylno) {
459		    ok = 1;
460		  }
461		}
462	      }
463	    }
464	  }
465	}
466      }
467    }
468    if(!(ok)) {
469      hb_node_delete(back);
470      back = NULL;
471    }
472    if(back) {
473      back->depth = hbnode_find_depth(back);
474    }
475  } $? "- hb_node_new PTR=%d", TR_IPTR(back)
476  return back;
477}
478
479
480
481dkChar const *
482hbnode_variable(hb_node_t *node, dkChar const *name)
483{
484  dk3_key_value_t	*kvp;
485  dkChar const		*back	= NULL;
486  int			 cc	= 1;
487  $? "+ hbnode_variable \"%!ds\"", TR_STR(name)
488  if((node) && (name)) {
489    while(cc) {
490      if(node) {
491        kvp = (dk3_key_value_t *)dk3sto_it_find_like(node->i_variables,name,1);
492	if(kvp) {
493	  cc = 0;
494	  back = kvp->val;
495	} else {
496	  node = node->parent;
497	}
498      } else {
499        cc = 0;
500      }
501    }
502  } $? "- hbnode_variable \"%!ds\"", TR_STR(back)
503  return back;
504}
505
506
507
508