summaryrefslogtreecommitdiff
path: root/support/dktools/htmlbook.ctr
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /support/dktools/htmlbook.ctr
Initial commit
Diffstat (limited to 'support/dktools/htmlbook.ctr')
-rw-r--r--support/dktools/htmlbook.ctr2867
1 files changed, 2867 insertions, 0 deletions
diff --git a/support/dktools/htmlbook.ctr b/support/dktools/htmlbook.ctr
new file mode 100644
index 0000000000..fd679bcad8
--- /dev/null
+++ b/support/dktools/htmlbook.ctr
@@ -0,0 +1,2867 @@
+%% options
+
+copyright owner = Dirk Krause
+copyright year = 2013-xxxx
+license = bsd
+
+
+
+%% header
+
+#include "dk3conf.h"
+#include "dk3types.h"
+#include "dk3numco.h"
+
+
+
+/** Image dimension cache entry.
+*/
+typedef struct {
+ dkChar *fn; /**< Image name. */
+ unsigned long w; /**< Image width. */
+ unsigned long h; /**< Image height. */
+} hb_img_dim_t;
+
+
+
+/** External link.
+*/
+typedef struct {
+ dkChar *url; /**< Link URL. */
+ unsigned long lno; /**< Link number within current page. */
+} hb_link_t;
+
+
+
+/** One contents line.
+*/
+typedef struct {
+ dkChar *text; /**< Allocated line text. */
+ dkChar *aname; /**< The a name text (if any). */
+ dkChar *realtext; /**< Real start of text for header. */
+ unsigned long lineno; /**< Line number. */
+ unsigned long header; /**< Running number of header. */
+ unsigned headlevel; /**< Header level (1 to 6). */
+ int lt; /**< Line type (0=normal, 1=header). */
+} hb_line_t;
+
+
+
+/** One node in the document tree.
+*/
+struct hb__node_t {
+ struct hb__node_t *parent; /**< Parent node. */
+ struct hb__node_t *curchild; /**< Current child to edit. */
+ struct hb__node_t *jumpnode; /**< Link target node. */
+ dk3_sto_t *s_subnodes; /**< Subnodes collection. */
+ dk3_sto_it_t *i_subnodes; /**< Subnodes iterator. */
+ dk3_sto_t *s_variables; /**< Variables storage. */
+ dk3_sto_it_t *i_variables; /**< Variables iterator. */
+ dk3_sto_t *s_lines; /**< Contents lines storage. */
+ dk3_sto_it_t *i_lines; /**< Contents lines iterator. */
+ dk3_sto_t *s_lbyurl; /**< Storage for links by URL. */
+ dk3_sto_it_t *i_lbyurl; /**< Iterator for links by URL. */
+ dk3_sto_t *s_lbylno; /**< Storage for links by number. */
+ dk3_sto_it_t *i_lbylno; /**< Iterator for links by number. */
+ dk3_sto_t *s_jsfiles; /**< Storage for JS files. */
+ dk3_sto_it_t *i_jsfiles; /**< Iterator for JS files. */
+ dkChar *title; /**< Node title. */
+ dkChar *shorttitle; /**< Short title (optional). */
+ dkChar *fulltitle; /**< Full title (browser title bar). */
+ dkChar *filename; /**< Text file name (optional). */
+ dkChar *suffix; /**< Output file name suffix (opt). */
+ dkChar *template; /**< Template file name (optional). */
+ dkChar *stylefile; /**< Style file. */
+ dkChar *author; /**< Name of author. */
+ dkChar *location; /**< Location (city) of author. */
+ dkChar *icontoc; /**< File name TOC icon. */
+ dkChar *iconprev; /**< File name previous section icon. */
+ dkChar *iconnext; /**< File name next section icon. */
+ dkChar *iconindex; /**< File name index icon. */
+ dkChar *iconhome; /**< File name home icon. */
+ dkChar *favicon; /**< favicon. */
+ dkChar *metadesc; /**< Meta description tag. */
+ dkChar *metakeyw; /**< Meta keywords tag. */
+ dkChar const *outFileName; /**< Output file name. */
+ unsigned long lineno; /**< Line number in project file. */
+ unsigned long objno; /**< Object index. */
+ unsigned long pobjno; /**< Printable object number. */
+ unsigned long nextlink; /**< Next link number. */
+ unsigned long nextindex; /**< Next index entry number. */
+ unsigned long headno; /**< Head number. */
+ unsigned long nextsubheadno; /**< Next head number for sub node. */
+ unsigned long nextjs; /**< Number of next js file. */
+ long contnum; /**< Context number. */
+ unsigned options; /**< Options for node. */
+ int indent; /**< Line indent (number o spaces). */
+ int depth; /**< Depth. */
+ int tocstate; /**< State when creating TOC. */
+ int inenc; /**< Text file input encoding. */
+ int havenavimenu; /**< Flag: Already have navi menu. */
+};
+
+/** One node in the document tree.
+*/
+typedef struct hb__node_t hb_node_t;
+
+
+
+/** Entry in keyword index.
+*/
+typedef struct {
+ dkChar *tx; /**< Keyword index text. */
+ dkChar *fn; /**< File name. */
+ dkChar *an; /**< Anchor name (optional). */
+ unsigned long ul; /**< Anchor number (if no name available). */
+ hb_node_t *no; /**< Node for file name (needed for title). */
+} hb_index_entry_t;
+
+
+
+/** Job type for the htmlbook program.
+ The s_nodes storage contains a plain list of all nodes,
+ this storage is used to release all nodes at the end of the program.
+ The s_pnodes storage contains a plain list of all nodes to
+ write output for.
+ The tree structure is below the rootnode element.
+*/
+typedef struct {
+ dk3_tm_t starttime; /**< Start time. */
+ dk3_app_t *app; /**< Application structure. */
+ dkChar const * const *msg; /**< Localized messages. */
+ dkChar const * const *kwnl; /**< Keywords, not localized. */
+ dk3_option_set_t *opt; /**< Command line options. */
+ dk3_sto_t *s_nodes; /**< All nodes storage. */
+ dk3_sto_it_t *i_nodes; /**< All nodes storage iterator. */
+ dk3_sto_t *s_pnodes; /**< Leaf nodes storage. */
+ dk3_sto_it_t *i_pnodes; /**< Leaf nodes storage iterator. */
+ dk3_sto_t *s_files; /**< Additional files storage. */
+ dk3_sto_it_t *i_files; /**< Additional files iterator. */
+ dk3_sto_t *s_index; /**< Index entries storage. */
+ dk3_sto_it_t *i_index; /**< Index entries storage iterator. */
+ dk3_sto_t *s_optsect; /**< Optional sections storage. */
+ dk3_sto_it_t *i_optsect; /**< Optional sections iterator. */
+ dk3_sto_t *s_imgdim; /**< Image dimension cache storage. */
+ dk3_sto_it_t *i_imgdim; /**< Image dimension cache iterator. */
+ hb_node_t *rootnode; /**< Root node. */
+ hb_node_t *currentnode; /**< Current node to modify. */
+ hb_node_t *impressumnode; /**< Impressum node. */
+ hb_node_t *firstnode; /**< First pnode. */
+ hb_node_t *lastnode; /**< Last pnode. */
+ dkChar const *infilename; /**< Input file name (project). */
+ dkChar const *outputdir; /**< Output directory (allocated). */
+ dkChar const *outputscript; /**< Name of script to produce. */
+ dkChar const *url; /**< URL to publish the results. */
+ dkChar const *indexfile; /**< Typically index html. */
+ dkChar const *impressumlink; /**< Link to impressum. */
+ dkChar const *chmlang; /**< Language setting for CHM. */
+ dkChar *shipbuffer; /**< Shipout buffer. */
+ dkChar *iltemplate; /**< Input line from template. */
+ dkChar *ilfile; /**< Input line from file. */
+ dkChar *special; /**< Buffer for current special. */
+ dk3_c32_t *buffer32; /**< Buffer for 32-bit characters. */
+ FILE *of; /**< Output file. */
+ unsigned long lineno; /**< Line number. */
+ unsigned long nextobj; /**< Next object number. */
+ unsigned long npobjs; /**< Number of printable objects. */
+ size_t bs; /**< Buffer size. */
+ size_t spused; /**< Number elements used in special. */
+ size_t shipused; /**< Shipout buffer used. */
+ unsigned options; /**< Job options. */
+ int iecmd; /**< Input encoding from cmd args. */
+ int actsect; /**< Flag: Active section. */
+ int cmd; /**< Option processing result. */
+ int exv; /**< Exit status code. */
+ int cs; /**< Character set for HTML output. */
+ int secttype; /**< Section type. */
+ int non_url; /**< Flag: Non-URL characters found. */
+ int maxdepth; /**< Maximum depth of a node. */
+ int headlevels; /**< Maximum depth to print header. */
+ int coli; /**< Current code line number. */
+ int cols; /**< Code line state. */
+} hb_job_t;
+
+
+
+/** File processing help structure.
+*/
+typedef struct {
+ hb_job_t *job; /**< Job structure. */
+ hb_node_t *p; /**< Previous node. */
+ hb_node_t *n; /**< Next node. */
+ int in_template; /**< Flag: Processing template. */
+ int stm; /**< State machine. */
+} hb_file_processor_t;
+
+
+
+/** @defgroup hboptions Node options from project file. */
+/**@{*/
+
+/** Write page TOC.
+*/
+#define HB_NODE_OPT_PAGE_TOC 0x0001U
+
+/** Replace ampersand.
+*/
+#define HB_NODE_OPT_REPLACE_AMPERSAND 0x0002U
+
+/** Use tidy while copying.
+*/
+#define HB_NODE_OPT_USE_TIDY 0x0004U
+
+/** Write header chain.
+*/
+#define HB_NODE_OPT_HEADER_CHAIN 0x0008U
+
+/** Indicate the impressum node.
+*/
+#define HB_NODE_OPT_IMPRESSUM 0x0010U
+
+/** Stop inheritance of JS files at this node.
+*/
+#define HB_NODE_OPT_STOP_JS_INHERITANCE 0x0020U
+
+/**@}*/
+
+
+
+/** @defgroup hbjoboptions Job options. */
+/**@{*/
+
+/** Create index file.
+*/
+#define HB_JOB_OPT_CREATE_INDEX 0x0001U
+
+/** Create table of contents.
+*/
+#define HB_JOB_OPT_CREATE_TOC 0x0002U
+
+/** Currently processing code.
+*/
+#define HB_JOB_OPT_CODE 0x0004U
+
+/** Produce output for building a chm file.
+*/
+#define HB_JOB_OPT_CHM 0x0008U
+
+/** Use ln instead of cp for resource files.
+*/
+#define HB_JOB_OPT_LN 0x0010U
+
+/** Write section number in positions table.
+*/
+#define HB_JOB_OPT_NUM_IN_POS 0x0020U
+
+/** Write section number in keyword index.
+*/
+#define HB_JOB_OPT_NUM_IN_IDX 0x0040U
+
+/** Write section number in page header.
+*/
+#define HB_JOB_OPT_NUM_IN_PAGE_HEADER 0x0080U
+
+/** Enable full text search in chm output.
+*/
+#define HB_JOB_OPT_CHM_FULL_TEXT_SEARCH 0x0100U
+
+/** Print line numbers for code.
+*/
+#define HB_JOB_OPT_CODE_LINE_NUMBERS 0x0200U
+
+/**@}*/
+
+
+
+/** @defgroup hbcharsets Character sets used by htmlbook. */
+/**@{*/
+
+/** Character set us-ascii.
+*/
+#define HB_CS_ASCII 0
+
+/** Character set UTF-8.
+*/
+#define HB_CS_UTF_8 1
+
+/**@}*/
+
+
+
+/** @defgroup hbsections Section types. */
+/**@{*/
+
+/** Section type not yet known.
+*/
+#define HB_SECTION_UNKNOWN 0
+
+/** Options section.
+*/
+#define HB_SECTION_OPTIONS 1
+
+/** Files section.
+*/
+#define HB_SECTION_FILES 2
+
+/** Contents section.
+*/
+#define HB_SECTION_CONTENTS 3
+
+/**@}*/
+
+
+
+/** @defgroup hbtocstate Node state when creating TOC. */
+/**@{*/
+
+/** Work on this node is not yet in progress.
+*/
+#define HB_TOC_STATE_INIT 0
+
+/** Work on this node is in progress.
+*/
+#define HB_TOC_STATE_IN_PROGRESS 1
+
+/** Work on this node is finished.
+*/
+#define HB_TOC_STATE_FINISHED 2
+
+/**@}*/
+
+
+
+/** @defgroup hbcolist Code line states. */
+/**@{*/
+
+/** Directly after code special command.
+*/
+#define HB_COLIST_NONE 0
+
+/** In a new line, no contents yet thus no opened code tag.
+*/
+#define HB_COLIST_NOT_OPENED 1
+
+/** Code tag was opened and must be closed.
+*/
+#define HB_COLIST_OPENED 2
+
+/**@}*/
+
+
+
+/** Maximum line length.
+*/
+#define HB_LINE_LENGTH 16383
+
+
+#include "hbnode.h"
+#include "hbconf.h"
+#include "hbhtml.h"
+#include "hbtool.h"
+#include "hbcont.h"
+#include "hbindex.h"
+#include "hbimgdim.h"
+#include "hbchm.h"
+#include "dk3strkv.h"
+#include "dk3kv.h"
+#include "dk3se.h"
+
+
+
+%% module
+
+#include "dk3all.h"
+#if 0
+#include "dkt-version.h"
+#endif
+#include "dk4vers.h"
+#include "htmlbook.h"
+
+
+/* Synopsis:
+ htmlbook -h | --help
+ htmlbook -v | --version
+ htmlbook -L | --license
+ htmlbook [<options>] <project>
+
+ Options:
+*/
+
+
+$!trace-include
+
+
+
+/** @defgroup hbcmd Commands for htmlbook. */
+/**@{*/
+/** Print help.
+*/
+#define HB_CMD_HELP 1
+/** Print version number.
+*/
+#define HB_CMD_VERSION 2
+/** Print license terms.
+*/
+#define HB_CMD_LICENSE 4
+/**@}*/
+
+
+
+/** Version information.
+*/
+static dkChar const *hb_version[] = {
+ dkT("htmlbook "),
+ DKT_VERSION_DK
+};
+
+
+
+/** License conditions.
+*/
+static dkChar const * const hb_license[] = {
+$!text macro=dkT
+
+Copyright (c) 2013-2016, Dirk Krause
+All rights reserved.
+
+Redistribution and use in source and binary forms,
+with or without modification, are permitted provided
+that the following conditions are met:
+
+* Redistributions of source code must retain the above
+ copyright notice, this list of conditions and the
+ following disclaimer.
+* Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials
+ provided with the distribution.
+* Neither the name of the copyright holder(s) nor the names of
+ contributors may be used to endorse or promote
+ products derived from this software without specific
+ prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.
+IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+$!end
+};
+
+
+
+/** Help text shown if help file is not found.
+*/
+static dkChar const * const hb_help_text[] = {
+$!text macro=dkT
+
+NAME
+
+htmlbook - Create HTML book structure
+
+SYNOPSIS
+
+ htmlbook [<option>] <file>
+ htmlbook -h
+ htmlbook -v
+ htmlbook -L
+
+DESCRIPTION
+
+The program creates a HTML book structure in a specified output directory.
+Configuration is read from a project file specified on the command line.
+
+OPTIONS
+
+-i <encoding> | --input-encoding=<encoding>
+ Input encoding for project file to process.
+
+-o name[,name...]
+ Activate optional project file sections.
+
+-s name=value | --set=name=value
+ Set variables (overwrite variables from options section).
+
+-h | --help
+ Show help text.
+
+-v | --version
+ Show version information.
+
+-L | --license
+ Show license terms.
+
+EXIT STATUS
+
+0 on success, all other exit status codes indicate an error.
+
+FILES
+
+The project file contains project settings and information about the
+document structure (text files and used template files).
+
+Project file
+------------
+A project file consists of three sections: ``[options]'', ``[files]'', and
+``[contents]''. A project file can contain optional sections
+``[options:<name>]'', ``[files:<name>]'', and ``[contents:<name>]''. Optional
+sections are only processed when activated by the -o command line option.
+On Windows systems optional sections named ``windows'' are activated
+automatically, on non-Windows systems sections named ``non-windows'' are
+activated automatically.
+
+The options section contains ``key=value'' lines for the following keys:
+
+ output directory Name of output directory. This directory is
+ removed completely and created again each
+ time the output script is run.
+
+ output script Script to re-create the output directory and
+ copy files into it.
+
+ title Document or collection title.
+
+ url URL to access the document collection via web.
+
+ index file Name of file containing text for start page.
+
+ html charset Character set for output HTML files
+ (``us-ascii'', ``ascii'', or ``utf-8'').
+
+ template Name of default template file (``web.hbt'').
+
+ style Name of default style file (``style.css'').
+
+ page toc Flag: Create an intra-page table of contents.
+
+ create toc Flag: Create table of contents.
+
+ create index Flag: Create keyword index.
+
+ section numbers in index Flag: Write section numbers in index.
+
+ replace ampersand Flag: Replace ampersand in texts (no).
+
+ tidy Flag: Use tidy for inspection and correction
+ of HTML output files.
+
+ ln Flag: Use ln command instead of cp to save
+ disk space.
+
+ author Author name.
+
+ location Location of author.
+
+ write position Flag: Write position within the collection at
+ start of page.
+
+ section numbers in position Flag: Write section number in position.
+
+ shortcut icon URL to shortcut icon.
+
+ icon toc File names for icons in navigation bar.
+ icon previous
+ icon next
+ icon index
+
+ impressum link URL to impressum.
+
+ impressum page Name of text file for impressum (you can use
+ either impressum link or impressum page).
+
+ chm Flag: Create HTML to produce a CHM file later.
+
+ chm language Language setting for CHM project
+ (``0x409 English (USA)'').
+
+ js file File name of JavaScript file.
+
+ inherit js Flag: Inherit JavaScript files from parents.
+
+ var Set variable (the first text word on the
+ right side is the variable name, the
+ remainder of the line is the variable value).
+
+The ``[files]'' section lists the name of additional files to copy,
+one per line.
+
+The ``[contents]'' section contains the tree structure for navigation.
+Each subsection for a node is started by a title line.
+The indent level corresponds to the tree structure.
+Title lines with same indent level are neighbours (sub-nodes of the same
+parent node). A nodes parent node is the next node above the node with
+smaller indent.
+After the node title there are lines started by @ to configure the node:
+
+ file = <File> Text file for the nodes contents.
+ input encoding = <Encoding> Default encoding to use if no BOM is found.
+ suffix = <String> File name suffix for output file.
+ short = <Short title> Short title for use in the navigation menu.
+
+Additionally you can use the ``html charset'', ``template'', ``style'',
+``page toc'', ``write position'', ``replace ampersand'', ``tidy'', ``ln'',
+``author'', ``location'', ``js file'', ``inherit js'', ``var'',
+``icon toc'', ``icon previous'', ``icon next'', ``icon index'', and
+``shortcut icon'' settings as shown for the options section.
+
+Leafs (nodes without further subnodes) must have a text file configured,
+for other nodes it's optional.
+
+Template file
+-------------
+The template file specifies the text between <BODY> and </BODY>.
+Special commands %%command%% can be used to insert the text, the navigation
+menu, navigation blocks with clickable icons.
+The following special commands are available:
+
+ \%%contents%% Insert the text file contents.
+
+ \%%title%% Insert the node title.
+
+ \%%img <options>%% Insert an image. The following options
+ are available:
+ div[=bool] Create <div> around <img>
+ centered[=bool] Show image centered, not left-aligned.
+ src=file File name for image.
+ alt="text" Alternative text for image.
+ title[="text"] Title text (alt= is used as default).
+ caption[="text"] Image caption.
+ longdesc=URL File containing long description of image.
+ border=width Border width.
+ height=height Image height.
+ width=width Image width.
+ svg=file SVG version of image.
+ svgwh[=bool] Apply PNG/JPEG dimensions to SVG object.
+ object[=bool] Create object for SVG.
+ pdf=file PDF version of image.
+ larger=file Larger version of image.
+ ismap[=bool] Set ismap attribute.
+ usemap=file Image map file.
+ name=name Item name.
+ id=name ID for CSS styling.
+ class=name Class name for CSS styling.
+ align=name Alignment.
+ vspace=distance Vertical space.
+ hspace=distance Horizontal space.
+ downloads[=bool] Provide links to download vector graphics
+ cache Cache image dimensions for images used multiple
+ times. Image dimensions for images used in
+ a template are cached automatically.
+
+ \%%menu <options>%% Insert the navigation menu.
+ The following options are available:
+ style=... One from ``reverse'' (full menu in reverse
+ order), ``full'' (full menu), ``top'' (show
+ only first hierarchy level) or ``current''
+ (show only current hierarchy level).
+ sub[=bool] Flag: Show subnodes of current node.
+
+ \%%navigation <options>%% Insert a navigation block.
+ The following options are available:
+ itop=file Icon for table of contents (``toc.png'').
+ iprev=file Icon for previous section (``prev.png'').
+ inext=file Icon for next section (``next.png'').
+ ikind=file Icon for keyword index (``index.png'').
+
+ \%%author%% Insert the author name.
+
+ \%%location%% Insert the authors location.
+
+ \%%date <options>%% Insert the current node.
+ The following options are available:
+ style=name Date style, currently only ``german'' is
+ allowed to switch from the default
+ ``yyyy-mm-dd'' to ``dd.mm.yyyy''.
+
+ \%%var <name> <options>%% Insert a variable value.
+ The following options are available:
+ url[=bool] Flag: Encode as URL, not as text.
+
+ \%%code <options>%% Output encoding. By default the
+ ``<'', ``>'' are not replaced by ``&lt;'', and
+ ``&gt;'' as we expect to get correct HTML
+ from the text files. Replacement of ``&''
+ by ``&amp;'' is controlled by the
+ ``replace ampersand'' setting in the options
+ section.
+ In code mode our text comes from a source
+ code file, so we have to encode these
+ characters for HTML output.
+ The following options are available:
+ enable[=bool] Turn code mode on.
+ on[=bool] Turn code mode on.
+ disable[=bool] Turn code mode off.
+ off[=bool] Turn code mode off.
+ toggle Toggle code mode.
+
+ \%%a <options>%% Insert a named anchor or a hyperlink.
+ The following options are available:
+ name=name Anchor name.
+ href=URL Link destination.
+ title=``text'' Text to show when mouse is over link.
+ text=``text'' Text for hyperlink.
+ target=destination Destination windows or frame, i.e. ``_blank''.
+ type=text MIME type.
+ external[=bool] Override result of internal/external test.
+ id=text ID for CSS styling.
+ class=text Class name for CSS styling.
+ style=text Direct style information.
+ hreflang=text Language for href text.
+ charset=text Character set.
+ onblur=text Script to execute when link looses focus.
+ onfocus=text Script to execute when link gets focus.
+ accesskey=text Hotkey for link.
+ tabindex=number Tabulator index.
+ shape=text Link shape form.
+ coords=text Coordinates.
+ rel=text Information for link to next element.
+ rev=text Information for link to previous element.
+
+ \%%menuentry <options>%% Insert code to visualize a menu entry.
+ The following options are available:
+ item=``text'' Text of the menu entry, can be used
+ multiple times for hierarchical menus.
+
+ \%%sourcefile <options>%% Show a file contents in a <PRE></PRE>
+ environment and provide a download
+ hyperlink. The following options are available:
+ file=file File name.
+ type=text MIME type.
+ title=``text'' Text shown when mouse is over hyperlink.
+
+Text file
+---------
+Text files contain the page contents.
+You can use headings like
+ .1 @name@ Heading text
+for a structural document. Depths 1, 2, 3, 4, or 5 are converted to
+<h2>...<h6> headers. A <h1> header is used for the page title.
+The @name@ specification is optional, it results in a named anchor
+ <a name="name"></a>
+before the heading. If the name specification is omitted, an anchor name
+is generated automatically.
+
+Text files can use the special commands listed in ``Template file'', execpt
+\%%contents%%. Additionally the following special command can be used
+in text files:
+
+ \%%index <options>%% Add an entry to the keyword index.
+ The following options can be used:
+ text=``text'' Keyword.
+ name=``text'' Name of a named anchor.
+ reference[=bool] Flag: Use existing named anchor, do not
+ create an anchor.
+NOTES
+
+All text files, style files and images must be local files
+in the current working directory.
+
+AUTHOR
+
+Dirk krause
+
+COPYRIGHT AND LICENSE
+
+Run
+ htmlbook --license
+to see the license conditions.
+
+SEE ALSO
+
+tidy
+
+$!end
+};
+
+
+
+/** 8-bit character keywords.
+*/
+static char const * const hb_c8_kw[] = {
+$!string-table
+#
+# 0 1 Newline and space
+#
+\n
+
+#
+# 2 3 DOS command to remove directory
+#
+RD /S /Q "
+"\n
+#
+# 4 5 UNIX command to remove directory
+#
+rm -fr '
+'\n
+#
+# 6 DOS command to create a directory
+#
+MKDIR "
+#
+# 7 Unix command to create a directory
+#
+mkdir -p '
+#
+# 8 9
+#
+IF NOT EXIST "
+" ECHO ERROR File does not exist:
+#
+# 10 11 12 13
+#
+IF EXIST "
+" XCOPY "
+" "
+\\" /Y /Q\n
+#
+# 14 15 16 17 18
+#
+if [ -f '
+' ]\n
+then\n
+else\n
+fi\n
+#
+# 19 20 21
+#
+ln '
+cp '
+' '
+#
+# 22 23
+#
+echo 'ERROR: File
+ does not exist'\n
+#
+# 24 25 26
+#
+tidy -q -utf8 < "
+tidy -q -ascii < "
+" > "
+#
+# 27 28 29 30
+#
+tidy -q -utf8 < '
+tidy -q -ascii < '
+' > '
+/
+#
+# 31 32 33 34 35
+#
+@ECHO OFF\n
+\#! /bin/sh\n
+EXITCODE=0\n
+exit $EXITCODE\n
+EXITCODE=1\n
+#
+# 36
+#
+ECHO TIDY
+#
+# 37
+#
+echo TIDY
+#
+# 38 39
+#
+" DEL /Q "
+"\n
+#
+# 40 41 42
+#
+find '
+' -type d -exec chmod ugo+rx {} \\;\n
+' -type f -exec chmod ugo+r {} \\;\n
+$!end
+};
+
+
+
+/** Fixed keywords (not localized).
+*/
+static dkChar const * const hb_kwnl[] = {
+$!string-table macro=dkT
+#
+# 0: Program group name
+#
+dktools
+#
+# 1: String table file name
+#
+htmlbook.str
+#
+# 2: Help text file name.
+#
+htmlbook.txt
+#
+# 3: Configuration file name
+#
+htmlbook.conf
+#
+# 4: File name for TOC icon
+#
+toc.png
+#
+# 5: File name for previous section icon
+#
+prev.png
+#
+# 6: File name for next section icon
+#
+next.png
+#
+# 7: File name for index icon
+#
+index.png
+#
+# 8: Name of root node output file
+#
+index.html
+#
+# 9: Dot for file name suffix.
+#
+.
+#
+# 10: Default suffix.
+#
+html
+#
+# 11: Alternative date style
+#
+german
+#
+# 12: url keyword var special command
+#
+url
+#
+# 13: internal anchor for keyword index
+#
+\#hb_index
+#
+# 14 15 16 17 Icon file names for navigation
+#
+toc.png
+prev.png
+next.png
+index.png
+#
+# 18 19 Section names
+#
+windows
+non-windows
+#
+# 20 21 Protocols
+#
+http://
+ftp://
+#
+# 22 File open mode write
+#
+w
+#
+# 23 24
+#
+html
+htm
+#
+# 25 Switch back to standard encoding
+#
+none
+#
+# 26 Name of hhc.exe project file
+#
+project.hhp
+#
+# 27 Name of hhc.exe output file
+#
+index.chm
+#
+# 28 Name of hhc.exe contents file
+#
+contents.hhc
+#
+# 29 Name of hhc.exe index file
+#
+index.hhk
+#
+# 30 File open mode
+#
+wb
+#
+# 31 Anchor name for TOC
+#
+\#hb_toc
+#
+# 32 Long option to set variables
+#
+set
+#
+# 33 34
+#
+SVG
+PDF
+#
+# 35 (space)
+#
+
+#
+# 36 (index.xml file name for chmcmd)
+#
+project.xml
+#
+# 37 (icon file name for home button)
+#
+home.png
+$!end
+};
+
+
+
+/** Default message texts.
+*/
+static dkChar const * const hb_kw[] = {
+$!string-table macro=dkT
+#
+# 0: Title for impressum page
+#
+Impressum
+#
+# 1: Link title
+#
+Go to start page:
+#
+# 2: Link title
+#
+At start page.
+#
+# 3: Link title
+#
+Go to previous page:
+#
+# 4: Link title
+#
+At first page.
+#
+# 5: Link title
+#
+Go to next page:
+#
+# 6: Link title
+#
+At last page.
+#
+# 7: Link title
+#
+Go to keyword index.
+#
+# 8: Syntax error, missing =
+#
+Syntax error, missing "="!
+#
+# 9: Syntax error, empty value!
+#
+Syntax error, empty value!
+#
+# 10: Syntax error, only allowed in options section
+#
+Syntax error, setting only allowed in options section!
+#
+# 11: Syntax error, illegal character set
+#
+Syntax error, illegal character set!\nOnly "ascii" or "utf-8" allowed.
+#
+# 12: Syntax error, no path specification in file name allowed!
+#
+Syntax error, no path specification in file name allowed!
+#
+# 13: Missing project file name
+#
+Missing project file name!
+#
+# 14: Too many project files specified, just one allowed!
+#
+Too many project file specified, just one allowed!
+#
+# 15: No parent candidate found!
+#
+No parent candidate found (probably a bug)!
+#
+# 16
+#
+Syntax error, missing section name!
+#
+# 17
+#
+Syntax error, missing closing square bracket!
+#
+# 18
+#
+Syntax error, illegal section name!
+#
+# 19
+#
+No template for node!
+#
+# 20
+#
+Failed to obtain file name (probably a bug)!
+#
+# 21 22
+#
+String "
+" contains characters not usable in an URL!
+#
+# 23 Header External links
+#
+External links
+#
+# 24 Error: No source file
+#
+No source file specified!
+#
+# 25 26 Error: Illegal menu style
+#
+Syntax error, illegal menu style: "
+"!
+#
+# 27 ERROR: Illegal key
+#
+Syntax error, illegal key (attribute name): "
+#
+# 28 ERROR: Contents is allowed only in templates!
+#
+Syntax error, "%%contents%%" is only allowed in templates!
+#
+# 29 ERROR: Illegal special command
+#
+Syntax error, illegal special command: "
+#
+# 30 ERROR: Parsing failed
+#
+Syntax error, parsing special command failed near:\n"
+#
+# 31 ERROR: Line too long
+#
+Line too long:\n"
+#
+# 32
+#
+Syntax error, missing header text!
+#
+# 33
+#
+Syntax error, missing closing ``@''!
+#
+# 34
+#
+Syntax error, missing text after ``@''!
+#
+# 35
+#
+Syntax error, missing header level!
+#
+# 36
+#
+Syntax error, no text after leading ``.'' in line!
+#
+# 37
+#
+Header level corrected to allowed maximum 6!
+#
+# 38
+#
+Syntax error, ''url'' can be set in options section only!
+#
+# 39
+#
+Failed to process a special command!
+#
+# 40
+#
+Syntax error, parsing special command arguments failed!
+#
+# 41
+#
+Syntax error, too many items for menu entry!
+#
+# 42
+#
+Syntax error, no items for menu entry!
+#
+# 43 44
+#
+Syntax error, illegal configuration key: "
+"!
+#
+# 45
+#
+Table of contents
+#
+# 46
+#
+Keyword and key phrases index
+#
+# 47
+#
+No default topic found!
+#
+# 48
+#
+Missing ``text'' attribute!
+#
+# 49
+#
+Missing ``file'' attribute!
+#
+# 50
+#
+The ``index'' special command can not be used in template!
+#
+# 51
+#
+No destination file for link found!
+#
+# 52 53
+#
+No text node for title:\n"
+"!
+#
+# 54 55 56 57
+#
+Current position
+Page table of contents
+External links
+Table of contents
+#
+# 58 59
+#
+Large
+Image
+#
+# 60
+#
+Menu entry
+#
+# 61 Text "Impressum" used in the HTML head range link tag.
+#
+Impressum
+#
+# 62 Error message, unfinished command!
+#
+Unfinished ``%%'' command!
+#
+# 63 64
+#
+Not a backslash escape sequence: ``
+''!
+#
+# 65
+#
+Image
+#
+# 66
+#
+Overwriting ``div'' option by ``table''!
+#
+# 67 68
+#
+No output directory configured!
+No output script configured
+#
+# 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
+#
+Overwriting previous setting for ``author''!
+Overwriting previous setting for ``title''!
+Overwriting previous setting for ``output directory''!
+Overwriting previous setting for ``output script''!
+Overwriting previous setting for ``template''!
+Overwriting previous setting for ``style''!
+Overwriting previous setting for ``short''!
+Overwriting previous setting for ``file''!
+Overwriting previous setting for ``suffix''!
+Overwriting previous setting for ``icon toc''!
+Overwriting previous setting for ``icon previous''!
+Overwriting previous setting for ``icon next''!
+Overwriting previous setting for ``icon index''!
+Overwriting previous setting for ``shortcut icon''!
+Overwriting previous setting for ``var''!
+#
+# 84 85
+#
+File not found: "
+"!
+#
+# 86
+#
+Overwriting previous setting for ``file''!
+#
+# 87
+#
+Start page
+#
+# 88
+#
+Too many text lines, max. 999 allowed!
+#
+# 89 90
+#
+Syntax error, ignoring unexpected %%hint%% key \"
+"!
+#
+# 91
+#
+Syntax error, missing text for %%hint%%!
+#
+# 92
+#
+Syntax error, missing title for %%hint%%!
+#
+# 93 94
+#
+Go to table of contents:
+On start page.
+#
+# 95
+#
+Overwriting previous setting for ``icon home''!
+#
+# 96
+#
+Syntax error, value required!
+#
+# 97 98 99
+#
+Overwriting previous setting for ``meta description''!
+Overwriting previous setting for ``meta keywords''!
+Overwriting previous setting for ``location''!
+$!end
+};
+
+
+
+/** Section names in project files.
+*/
+static dkChar const * const hb_section_names[] = {
+$!string-table macro=dkT
+options
+files
+contents
+$!end
+};
+
+
+
+/** Accepted program options.
+*/
+static dk3_option_t const hb_options[] = {
+ { dkT('h'), dkT("help"), 0 },
+ { dkT('v'), dkT("version"), 0 },
+ { dkT('L'), dkT("license"), 0 },
+ { dkT('o'), dkT("optional-sections"), 1 },
+ { dkT('i'), dkT("input-encoding"), 1 }
+};
+
+/** Number of elements in the hb_options array.
+*/
+static size_t const hb_sz_options = sizeof(hb_options)/sizeof(dk3_option_t);
+
+
+
+/** Initialize job structure.
+ @param job Job structure to initialize.
+ @param app Application structure.
+ @param msg Localized keywords.
+ @param kwnl Keywords not localized.
+*/
+static
+void
+hb_job_init(
+ hb_job_t *job,
+ dk3_app_t *app,
+ dkChar const * const *msg,
+ dkChar const * const *kwnl
+)
+{
+ $? "+ hb_job_init"
+ job->app = app;
+ job->msg = msg;
+ job->kwnl = kwnl;
+ job->opt = NULL;
+ job->s_nodes = NULL;
+ job->i_nodes = NULL;
+ job->s_pnodes = NULL;
+ job->i_pnodes = NULL;
+ job->s_files = NULL;
+ job->i_files = NULL;
+ job->s_index = NULL;
+ job->i_index = NULL;
+ job->s_optsect = NULL;
+ job->i_optsect = NULL;
+ job->s_imgdim = NULL;
+ job->i_imgdim = NULL;
+ job->rootnode = NULL;
+ job->currentnode = NULL;
+ job->impressumnode = NULL;
+ job->firstnode = NULL;
+ job->lastnode = NULL;
+ job->infilename = NULL;
+ job->outputdir = NULL;
+ job->outputscript = NULL;
+ job->url = NULL;
+ job->indexfile = NULL;
+ job->impressumlink = NULL;
+ job->chmlang = NULL;
+ job->shipbuffer = NULL;
+ job->iltemplate = NULL;
+ job->ilfile = NULL;
+ job->special = NULL;
+ job->buffer32 = NULL;
+ job->of = NULL;
+ job->lineno = 0UL;
+ job->nextobj = 0UL;
+ job->npobjs = 0UL;
+ job->spused = 0;
+ job->shipused = 0;
+ job->options = HB_JOB_OPT_CREATE_TOC;
+ job->options |= HB_JOB_OPT_NUM_IN_POS;
+ job->options |= HB_JOB_OPT_NUM_IN_IDX;
+ job->options |= HB_JOB_OPT_NUM_IN_PAGE_HEADER;
+ job->options |= HB_JOB_OPT_CODE_LINE_NUMBERS;
+ job->actsect = 1;
+ job->iecmd = -1; /* No input encoding specified */
+ job->bs = 0;
+ job->cmd = 0;
+ job->exv = 1; $? ". INIT"
+ job->cs = HB_CS_ASCII;
+ job->secttype = HB_SECTION_UNKNOWN;
+ job->non_url = 0;
+ job->maxdepth = 0;
+ job->coli = 0;
+ job->cols = HB_COLIST_NONE;
+#if DK3_SIZEOF_INT > 2
+#if Dk3_SIZEOF_INT > 4
+ job->headlevels = 9223372036854775807;
+#else
+ job->headlevels = 2147483647;
+#endif
+#else
+ job->headlevels = 32767;
+#endif
+ $? "- hb_job_init"
+}
+
+
+
+/** Clean up job structure at end of program.
+ @param job Job structure to clean up.
+*/
+static
+void
+hb_job_end(hb_job_t *job)
+{
+ hb_img_dim_t *idptr; /* Current image dimension cache entry */
+ hb_index_entry_t *ie; /* Current index entry */
+ hb_node_t *cn; /* Current node */
+ dkChar *cfn; /* Current file name */
+ $? "+ hb_job_end"
+ /* Release options.
+ */
+ if(job->opt) {
+ dk3opt_close(job->opt); job->opt = NULL;
+ }
+
+ /* The s_nodes component contains a list of all nodes.
+ We traverse this container to release all nodes.
+ */
+ if(job->s_nodes) {
+ if(job->i_nodes) {
+ dk3sto_it_reset(job->i_nodes);
+ while(NULL != (cn = (hb_node_t *)dk3sto_it_next(job->i_nodes))) {
+ hb_node_delete(cn);
+ }
+ dk3sto_it_close(job->i_nodes); job->i_nodes = NULL;
+ }
+ dk3sto_close(job->s_nodes); job->s_nodes = NULL;
+ }
+
+ if(job->s_imgdim) {
+ if(job->i_imgdim) {
+ dk3sto_it_reset(job->i_imgdim);
+ while(NULL != (idptr = (hb_img_dim_t *)dk3sto_it_next(job->i_imgdim))) {
+ hbimgdim_delete(idptr);
+ }
+ dk3sto_it_close(job->i_imgdim);
+ }
+ dk3sto_close(job->s_imgdim);
+ } job->s_imgdim = NULL; job->i_imgdim = NULL;
+
+ if(job->s_optsect) {
+ if(job->i_optsect) {
+ dk3sto_it_reset(job->i_optsect);
+ while(NULL != (cfn = (dkChar *)dk3sto_it_next(job->i_optsect))) {
+ $? ". releasing optional section \"%!ds\"", TR_STR(cfn)
+ dk3_release(cfn);
+ }
+ dk3sto_it_close(job->i_optsect);
+ }
+ dk3sto_close(job->s_optsect);
+ }
+ job->s_optsect = NULL; job->i_optsect = NULL;
+
+ if(job->s_index) {
+ if(job->i_index) {
+ dk3sto_it_reset(job->i_index);
+ while(NULL != (ie = (hb_index_entry_t *)dk3sto_it_next(job->i_index))) {
+ hbindex_delete(ie);
+ }
+ dk3sto_it_close(job->i_index);
+ }
+ dk3sto_close(job->s_index);
+ }
+ job->s_index = NULL; job->i_index = NULL;
+
+ /* We must free the list of additional files.
+ */
+ if(job->s_files) {
+ if(job->i_files) {
+ dk3sto_it_reset(job->i_files);
+ while(NULL != (cfn = (dkChar *)dk3sto_it_next(job->i_files))) {
+ $? ". release file name \"%!ds\"", cfn
+ dk3_release(cfn);
+ }
+ dk3sto_it_close(job->i_files); job->i_files = NULL;
+ }
+ dk3sto_close(job->s_files); job->s_files = NULL;
+ }
+
+ /* The s_pnodes component contains a list of the leaf nodes
+ only (nodes to produce output for).
+ We already traversed s_nodes to release all the nodes, so
+ we can simply close s_pnodes and i_pnodes here.
+ */
+ if(job->s_pnodes) {
+ if(job->i_pnodes) {
+ dk3sto_it_close(job->i_pnodes);
+ }
+ dk3sto_close(job->s_pnodes); job->s_pnodes = NULL;
+ }
+
+ /* Release components allocated dynamically.
+ */
+ dk3_release(job->outputdir);
+ dk3_release(job->outputscript);
+ dk3_release(job->url);
+ dk3_release(job->impressumlink);
+ dk3_release(job->chmlang);
+ dk3_release(job->indexfile);
+ dk3_release(job->shipbuffer);
+ dk3_release(job->iltemplate);
+ dk3_release(job->ilfile);
+ dk3_release(job->special);
+ dk3_release(job->buffer32);
+
+ job->impressumnode = NULL;
+ $? "- hb_job_end"
+}
+
+
+
+/** Save names of optional sections to process.
+ @param job Job structure.
+ @param sections Section names.
+ @return 1 on success, 0 on errors.
+*/
+static
+int
+hb_save_optional_sections(hb_job_t *job, dkChar const *sections)
+{
+ dkChar bu[1024]; /* Private copy of sections */
+ dkChar *p1; /* Current section name */
+ dkChar *p2; /* Next section name */
+ dkChar *p3; /* Copy of current section for storage */
+ int back = 0; /* Result */
+ $? "+ hb_save_optional_sections \"%!ds\"", TR_STR(sections)
+ if((job) && (sections)) {
+ if(dk3str_len(sections) < DK3_SIZEOF(bu,dkChar)) {
+ dk3str_cpy(bu, sections);
+ back = 1; $? ". back = 1"
+ p1 = dk3str_start(bu, NULL);
+ while(p1) {
+ p2 = dk3str_chr(p1, dkT(','));
+ if(p2) {
+ *(p2++) = dkT('\0');
+ p2 = dk3str_start(p2, NULL);
+ }
+ dk3str_chomp(p1, NULL);
+ $? ". saving optional section \"%!ds\"", p1
+ p3 = dk3str_dup_app(p1, job->app);
+ if(p3) {
+ if(!dk3sto_add(job->s_optsect, p3)) {
+ dk3_release(p3);
+ back = 0; /* REPORTED */ $? ". back = 0"
+ }
+ } else {
+ back = 0; /* REPORTED */ $? ". back = 0"
+ }
+ p1 = p2;
+ }
+ } else {
+ dk3app_log_i3(job->app, DK3_LL_ERROR, 135, 136, sections);
+ }
+ } $? "- hb_save_optional_sections %d", back
+ return back;
+}
+
+
+
+/** Process command line options.
+ @param job Job structure.
+ @return 1 on success, 0 on error.
+*/
+static
+int
+hb_process_options(hb_job_t *job)
+{
+ dkChar const *optarg; /* Option argument */
+ int back = 0;
+ job->opt = dk3opt_open_from_app(
+ hb_options, hb_sz_options, dkT('s'), hb_kwnl[32], job->app
+ );
+ if(job->opt) {
+ if(0 == dk3opt_get_error_code(job->opt)) {
+ back = 1;
+ if(dk3opt_is_set(job->opt, dkT('h'))) {
+ job->cmd |= HB_CMD_HELP;
+ }
+ if(dk3opt_is_set(job->opt, dkT('v'))) {
+ job->cmd |= HB_CMD_VERSION;
+ }
+ if(dk3opt_is_set(job->opt, dkT('L'))) {
+ job->cmd |= HB_CMD_LICENSE;
+ }
+ if(0 == (job->cmd)) {
+ if(dk3opt_is_set(job->opt, dkT('i'))) {
+ optarg = dk3opt_get_short_arg(job->opt, dkT('i'));
+ if(optarg) {
+ job->iecmd = dk3enc_get_text_encoding_app(optarg, job->app);
+ if(0 > job->iecmd) { job->iecmd = -1; }
+ }
+ }
+ if(1 > dk3opt_get_num_args(job->opt)) { $? "! no project"
+ /* ERROR: No project file specified! */
+ dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 13);
+ back = 0;
+ } else {
+ if(1 < dk3opt_get_num_args(job->opt)) { $? "! too many"
+ /* WARNING: Too many project files, using just one! */
+ dk3app_log_1(job->app, DK3_LL_WARNING, job->msg, 14);
+ }
+ }
+ }
+ }
+ }
+ return back;
+}
+
+
+
+/** Print help text, version information or license terms.
+ @param job Job structure.
+*/
+static
+void
+hb_help_version_license(hb_job_t *job)
+{
+ dkChar const * const *ptr; /* Current line to print */
+ $? "+ hb_help_version_license"
+ /* Show version
+ */
+ dk3sf_initialize_stdout();
+ dk3sf_fputs(hb_version[0], stdout);
+ dk3sf_fputs(hb_version[1], stdout);
+ dk3sf_fputc(dkT('\n'), stdout);
+
+ if(HB_CMD_LICENSE & (job->cmd)) {
+ /* Show license
+ */
+ ptr = hb_license;
+ while(*ptr) {
+ dk3sf_fputs(*(ptr++), stdout); dk3sf_fputc(dkT('\n'), stdout);
+ }
+ }
+ if(HB_CMD_HELP & (job->cmd)) {
+ /* Show help
+ */
+ dk3app_help(job->app, hb_kwnl[2], hb_help_text);
+ }
+ job->exv = 0; $? ". SUCCESS"
+ $? "- hb_help_version_license"
+}
+
+
+
+/** Compare two file names.
+ @param l Left pointer.
+ @param r Right pointer.
+ @param cr Comparison criteria (ignored).
+ @return Comparison result.
+*/
+static
+int
+hb_file_name_compare(void const *l, void const *r, int cr)
+{
+ int back = 0;
+ $? "+ hb_file_name_compare PTR=%d PTR=%d", TR_IPTR(l), TR_IPTR(r)
+ if(l) {
+ if(r) {
+ back = dk3str_fncmp((dkChar const *)l, (dkChar const *)r);
+ if(-1 > back) { back = -1; }
+ if( 1 < back) { back = 1; }
+ } else {
+ back = 1;
+ }
+ } else {
+ if(r) {
+ back = -1;
+ }
+ } $? "- hb_file_name_compare %d", back
+ return back;
+}
+
+
+
+/** Compare two strings.
+ @param l Left string.
+ @param r Right string.
+ @param cr Comparison criteria (ignored).
+ @return Comparison result.
+*/
+static
+int
+hb_compare_strings(void const *l, void const *r, int cr)
+{
+ int back = 0;
+ $? "+ hb_compare_strings PTR=%d PTR=%d", TR_IPTR(l), TR_IPTR(r)
+ if(l) {
+ if(r) {
+ back = dk3str_cmp((dkChar const *)l, (dkChar const *)r);
+ if(-1 > back) { back = -1; }
+ if( 1 < back) { back = 1; }
+ } else back = 1;
+ } else {
+ if(r) back = -1;
+ } $? "- hb_compare_strings %d", back
+ return back;
+}
+
+
+
+/** Allocate memory for job structure.
+ @param job Job structure to initialize.
+ @return 1 on success, 0 on error.
+*/
+static
+int
+hb_job_allocate(hb_job_t *job)
+{
+ int back = 0;
+ $? "+ hb_job_allocate"
+ job->s_nodes = dk3sto_open_app(job->app);
+ if(job->s_nodes) {
+ dk3sto_set_comp(job->s_nodes, hb_node_compare, 0);
+ job->i_nodes = dk3sto_it_open(job->s_nodes);
+ if(job->i_nodes) {
+ job->s_pnodes = dk3sto_open_app(job->app);
+ if(job->s_pnodes) {
+ dk3sto_set_comp(job->s_pnodes, hb_node_compare, 0);
+ job->i_pnodes = dk3sto_it_open(job->s_pnodes);
+ if(job->i_pnodes) {
+ job->rootnode = hb_node_new(job, NULL, 0UL, 0UL, -1);
+ job->nextobj += 1UL;
+ if(job->rootnode) {
+ (job->rootnode)->depth = 0;
+ if(dk3sto_add(job->s_nodes, job->rootnode)) {
+ job->currentnode = job->rootnode;
+ job->shipbuffer = dk3_new_app(dkChar,HB_LINE_LENGTH,job->app);
+ job->iltemplate = dk3_new_app(dkChar,HB_LINE_LENGTH,job->app);
+ job->ilfile = dk3_new_app(dkChar,HB_LINE_LENGTH,job->app);
+ job->special = dk3_new_app(dkChar,HB_LINE_LENGTH,job->app);
+ job->buffer32 = dk3_new_app(dk3_c32_t,HB_LINE_LENGTH,job->app);
+ job->bs = HB_LINE_LENGTH;
+ job->spused = 0;
+ if(job->iltemplate) {
+ if(job->ilfile) {
+ if(job->special) {
+ if(job->buffer32) {
+ if(job->shipbuffer) {
+ job->s_files = dk3sto_open_app(job->app);
+ if(job->s_files) {
+ dk3sto_set_comp(job->s_files,hb_file_name_compare,0);
+ job->i_files = dk3sto_it_open(job->s_files);
+ if(job->i_files) {
+ if(dk3sto_add(job->s_pnodes, job->rootnode)) {
+ back = 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ } else {
+ hb_node_delete(job->rootnode);
+ job->rootnode = NULL;
+ }
+ }
+ }
+ }
+ }
+ }
+ if(back) {
+ back = 0;
+ job->s_index = dk3sto_open_app(job->app);
+ if(job->s_index) {
+ dk3sto_set_comp(job->s_index, hbindex_compare, 0);
+ job->i_index = dk3sto_it_open(job->s_index);
+ if(job->i_index) {
+ job->s_optsect = dk3sto_open_app(job->app);
+ if(job->s_optsect) {
+ dk3sto_set_comp(job->s_optsect, hb_compare_strings, 0);
+ job->i_optsect = dk3sto_it_open(job->s_optsect);
+ if(job->i_optsect) {
+ job->s_imgdim = dk3sto_open_app(job->app);
+ if(job->s_imgdim) {
+ dk3sto_set_comp(job->s_imgdim, hbimgdim_compare, 0);
+ job->i_imgdim = dk3sto_it_open(job->s_imgdim);
+ if(job->i_imgdim) {
+ back = 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ } $? "- hb_job_allocate %d", back
+ return back;
+}
+
+
+
+#if 0
+/** Add one file to file list.
+ @param job Job structure.
+ @param il Input line to process, contains file name.
+ @return 1 on success, -1 on error.
+*/
+static
+int
+hb_add_file_to_file_list(hb_job_t *job, dkChar *il)
+{
+#if VERSION_BEFORE_20131207
+ dkChar *p1; /* Start of line */
+ dkChar *p2; /* Allocated memory */
+ int back = 1;
+ p1 = dk3str_start(il, NULL);
+ if(p1) {
+ dk3str_chomp(p1, NULL);
+ if(!(dk3sto_it_find_like(job->i_files, (void const *)il, 0))) {
+ p2 = dk3str_dup_app(il,job->app);
+ if(p2) {
+ if(!(dk3sto_add(job->s_files, (void *)p2))) {
+ back = -1;
+ dk3_release(p2);
+ }
+ } else {
+ back = -1;
+ }
+ }
+ }
+ return back;
+#else
+ return(hbtool_add_file(job,il));
+#endif
+}
+#endif
+
+
+
+/** Find indent level.
+ @param il Input line to process.
+ @return Number of leading spaces.
+*/
+static
+int
+hb_find_indent(dkChar *il)
+{
+ dkChar *p1; /* Traverse text line */
+ int back = 0;
+ $? "+ hb_find_indent \"%!ds\"", TR_STR(il)
+ p1 = il;
+ while((dkT(' ') == *p1) || (dkT('\t') == *p1)) {
+ back++;
+ if(dkT('\t') == *p1) {
+ while(back % 8) { back++; }
+ }
+ p1++;
+ } $? "- hb_find_indent %d", back
+ return back;
+}
+
+
+
+/** Find parent candidate for new node.
+ @param current Current node to edit.
+ @param indent Indent of new node.
+ @return Pointer to node on success, NULL on error.
+*/
+static
+hb_node_t *
+hb_parent_candidate(hb_node_t *current, int indent)
+{
+ hb_node_t *back = NULL;
+ hb_node_t *ca; /* Candidate node */
+ int cc; /* Flag: Can continue */
+ $? "+ hb_parent_candidate"
+ ca = current;
+ cc = 1;
+ while(cc) {
+ if(ca) {
+ if((ca->indent) < indent) {
+ back = ca;
+ cc = 0;
+ } else {
+ ca = ca->parent;
+ }
+ } else {
+ cc = 0;
+ }
+ } $? "- hb_parent_candidate PTR=%d", TR_IPTR(back)
+ return back;
+}
+
+
+
+/** Process a line from the contents section.
+ @param job Job structure.
+ @param il Input line.
+ @return 1 on success, -1 on error.
+*/
+static
+int
+hb_add_contents(hb_job_t *job, dkChar *il)
+{
+ hb_node_t *pa; /* Parent node for new node */
+ hb_node_t *nn; /* New node */
+ dkChar *p1; /* Start of text line */
+ int indent; /* Indent level */
+ int back = 1;
+ $? "+ hb_add_contents \"%!ds\"", TR_STR(il)
+ p1 = dk3str_start(il, NULL);
+ if(p1) {
+ if(dkT('@') == *p1) {
+ p1++;
+ back = hbconf_process_line(job, p1, HB_SECTION_CONTENTS);
+ } else {
+ /* Create new node. */
+ indent = hb_find_indent(il);
+ pa = hb_parent_candidate(job->currentnode, indent);
+ if(pa) {
+ nn = hb_node_new(job, pa, job->lineno, job->nextobj, indent);
+ job->nextobj += 1UL;
+ if(nn) {
+ if(nn->depth > job->maxdepth) { job->maxdepth = nn->depth; }
+ if(dk3sto_add(job->s_nodes, (void *)nn)) {
+ if(dk3sto_add(pa->s_subnodes, (void *)nn)) {
+ job->currentnode = nn;
+ nn->title = dk3str_dup_app(p1,job->app);
+ if(!(nn->title)) {
+ back = -1; /* REPORTED */
+ }
+ } else {
+ back = -1; /* REPORTED */
+ }
+ } else {
+ back = -1; /* REPORTED */
+ hb_node_delete(nn);
+ }
+ } else {
+ back = -1; /* REPORTED */
+ }
+ } else {
+ back = -1;
+ /* ERROR: No parent candidate found! */
+ dk3app_log_1(job->app, DK3_LL_WARNING, job->msg, 15);
+ }
+ }
+ } $? "- hb_add_contents %d", back
+ return back;
+}
+
+
+
+/** Process one line from project file.
+ @param job Job structure.
+ @param il Input line to process.
+ @return 1 on success, 0 on minor errors, -1 on fatal errors.
+*/
+static
+int
+hb_process_line(hb_job_t *job, dkChar *il)
+{
+ dkChar *p1; /* Start of line */
+ dkChar *p2; /* Next pointer */
+ int back = 1; /* Result */
+ int newst = HB_SECTION_UNKNOWN; /* New section type */
+ $? "+ hb_process_line \"%!ds\"", TR_STR(il)
+ job->lineno += 1UL;
+ p1 = dk3str_start(il, NULL);
+ if(p1) {
+ dk3str_chomp(p1,NULL);
+ if(dkT('#') != *p1) {
+ if(dkT('[') == *p1) {
+ job->actsect = 1;
+ job->secttype = HB_SECTION_UNKNOWN;
+ p1++;
+ p1 = dk3str_start(p1, NULL);
+ if(p1) {
+ p2 = dk3str_chr(p1, dkT(']'));
+ if(p2) {
+ *p2 = dkT('\0');
+ dk3str_chomp(p1, NULL);
+ p2 = dk3str_chr(p1, dkT(':'));
+ if(p2) {
+ *(p2++) = dkT('\0');
+ p2 = dk3str_start(p2, NULL);
+ dk3str_chomp(p2, NULL);
+ dk3str_chomp(p1, NULL);
+ }
+ newst = dk3str_array_index(hb_section_names, p1, 0);
+ if(0 <= newst) {
+ job->secttype = 1 + newst;
+ } else {
+ /* ERROR: Syntax (unknown section name) */
+ dk3app_log_1(job->app, DK3_LL_WARNING, job->msg, 18);
+ }
+ if(p2) {
+ if(!dk3sto_it_find_like(job->i_optsect, p2, 0)) {
+ job->actsect = 0;
+#if DK3_ON_WINDOWS
+ if(0 == dk3str_cmp(p2, (job->kwnl)[18])) {
+ job->actsect = 1;
+ }
+#else
+ if(0 == dk3str_cmp(p2, (job->kwnl)[19])) {
+ job->actsect = 1;
+ }
+#endif
+ }
+ }
+ } else {
+ /* ERROR: Syntax (missing closing bracket) */
+ dk3app_log_1(job->app, DK3_LL_WARNING, job->msg, 17);
+ }
+ } else {
+ /* ERROR: Syntax (no text in bracket) */
+ back = -1;
+ dk3app_log_1(job->app, DK3_LL_WARNING, job->msg, 16);
+ }
+ } else {
+ if(job->actsect) {
+ switch(job->secttype) {
+ case HB_SECTION_OPTIONS: {
+ back = hbconf_process_line(job, il, HB_SECTION_OPTIONS);
+ } break;
+ case HB_SECTION_FILES: {
+ back = hbtool_add_file(job, il);
+ } break;
+ case HB_SECTION_CONTENTS: {
+ back = hb_add_contents(job, il);
+ } break;
+ }
+ }
+ }
+ }
+ } $? "- hb_process_line %d", back
+ return back;
+}
+
+
+
+/** Line handler to process one line from project file.
+ @param obj Object to save data.
+ @param il Input line to process.
+ @return 1 on success, 0 on minor errors, -1 on fatal errors.
+*/
+static
+int
+hb_line_reader_handler(void *obj, dkChar *il)
+{
+ int back;
+ $? "+ hb_line_reader_handler"
+ back = hb_process_line((hb_job_t *)obj, il);
+ $? "- hb_line_reader_handler %d", back
+ return back;
+}
+
+
+
+/** Process command line variables, overwrite settings from
+ options section in project file.
+ @param job Job structure.
+ @return 1 on success, 0 on error.
+*/
+static
+int
+hb_read_variables(hb_job_t *job)
+{
+ dkChar bu[1024]; /* Buffer for modification */
+ dk3_key_value_t *kvp; /* New key value pair */
+ dkChar const *optstr; /* Option string */
+ dkChar *p1; /* Start of option string (key) */
+ dkChar *p2; /* Start of value */
+ dkChar *p3; /* Copy of value */
+ int back = 1;
+ int nfo; /* Number of further arguments */
+ int i; /* Index of current argument */
+
+ if(0 < (nfo = dk3opt_get_num_fo(job->opt))) {
+ for(i = 0; i < nfo; i++) {
+ optstr = dk3opt_get_fo(job->opt, i);
+ if(optstr) {
+ if(dk3str_len(optstr) < DK3_SIZEOF(bu,dkChar)) {
+ dk3str_cpy(bu, optstr);
+ p1 = dk3str_start(bu, NULL);
+ if(p1) {
+ p2 = dk3str_chr(p1, dkT('='));
+ if(p2) {
+ *(p2++) = dkT('\0');
+ p2 = dk3str_start(p2, NULL);
+ }
+ if(p2) {
+ dk3str_chomp(p1, NULL);
+ dk3str_chomp(p2, NULL);
+ kvp = dk3sto_it_find_like(
+ (job->rootnode)->i_variables, p1, 1
+ );
+ if(kvp) {
+ p3 = dk3str_dup_app(p2, job->app);
+ if(p3) {
+ dk3_release(kvp->val);
+ kvp->val = p3;
+ } else {
+ back = 0;
+ }
+ } else {
+ kvp = dk3kv_new_app(p1, p2, job->app);
+ if(kvp) {
+ if(!dk3sto_add((job->rootnode)->s_variables, kvp)) {
+ dk3kv_delete(kvp);
+ back = 0;
+ }
+ } else {
+ back = 0;
+ }
+ }
+ } else {
+ kvp = dk3sto_it_find_like(
+ (job->rootnode)->i_variables, p1, 1
+ );
+ if(kvp) {
+ dk3sto_remove((job->rootnode)->s_variables, kvp);
+ dk3kv_delete(kvp);
+ }
+ }
+ } else {
+ /* Empty string is ok */
+ }
+ } else {
+ /* ERROR: String too long! */
+ dk3app_log_i3(job->app, DK3_LL_ERROR, 135, 136, optstr);
+ }
+ }
+ }
+ }
+ return back;
+}
+
+
+
+/** Read the project file.
+ @param job Job structure.
+ @return 1 on success, 0 on error.
+*/
+static
+int
+hb_read_project(hb_job_t *job)
+{
+ int back = 0;
+ int inenc; /* Input encoding */
+ $? "+ hb_read_project"
+ inenc = dk3app_get_input_file_encoding(job->app);
+ if(0 <= job->iecmd) { inenc = job->iecmd; }
+ back = dk3stream_process_filename_lines_app(
+ (void *)job, hb_line_reader_handler, job->infilename,
+ job->ilfile, job->bs,
+ dk3app_get_encoding(job->app),
+ inenc,
+ job->app
+ );
+ if(!hb_read_variables(job)) {
+ back = 0;
+ }
+ if((job->options) & HB_JOB_OPT_CHM) {
+ job->cs = HB_CS_ASCII;
+ }
+ if(1 != back) { back = 0; }
+ $? "- hb_read_project %d", back
+ return back;
+}
+
+
+
+/** Write all HTML files for the project.
+ @param job Job structure.
+*/
+static
+void
+hb_write_html_files(hb_job_t *job)
+{
+#if VERSION_BEFORE_20131206
+ hb_node_t *nptr;
+ $? "+ hb_write_html_files"
+ dk3sto_it_reset(job->i_pnodes);
+ while(NULL != (nptr = (hb_node_t *)dk3sto_it_next(job->i_pnodes))) {
+ $? ". node \"%!ds\"", TR_STR(nptr->title)
+ if(0UL != nptr->objno) { $? ". must write"
+ hbhtml_write_file(job, nptr);
+ }
+ } $? "- hb_write_html_files"
+#else
+ hb_node_t *c;
+ hb_node_t *p;
+ hb_node_t *n;
+ $? "+ hb_write_html_files"
+ p = c = n = NULL;
+ dk3sto_it_reset(job->i_pnodes);
+ c = dk3sto_it_next(job->i_pnodes);
+ while(c) {
+ n = dk3sto_it_next(job->i_pnodes);
+ if(0UL != c->objno) {
+ hbhtml_write_file(job, c, p, n);
+ }
+ p = c;
+ c = n;
+ }
+ $? "- hb_write_html_files"
+#endif
+}
+
+
+
+/** Write index html file.
+ @param job Job structure.
+*/
+static
+void
+hb_write_index(hb_job_t *job)
+{
+ hb_node_t *n; /* Current index item */
+ $? "+ hb_write_index"
+ dk3sto_it_reset(job->i_pnodes);
+ if(dk3sto_it_next(job->i_pnodes)) {
+ n = (hb_node_t *)dk3sto_it_next(job->i_pnodes);
+ if(n) {
+ hbhtml_write_file(job, job->rootnode, NULL, n);
+ } else {
+/* 2014/02/05 We now allow an empty contents section to
+ produce just one file index.html.
+*/
+#if VERSION_BEFORE_20140205
+ job->exv = 1; $? "! ERROR"
+#else
+ hbhtml_write_file(job, job->rootnode, NULL, n);
+#endif
+ }
+ } else {
+ job->exv = 1; $? "! ERROR"
+ } $? "- hb_write_index"
+}
+
+
+
+#if TRACE_DEBUG && (DK3_CHAR_SIZE == 1)
+/** Show document tree structure at a node recursively.
+ @param job Job structure.
+ @param nptr Current node to show.
+ @param l Indent level.
+*/
+static
+void
+hb_show_tree_node(hb_job_t *job, hb_node_t *nptr, int l)
+{
+ hb_node_t *hbptr;
+ int i;
+ if(dktrace_file()) {
+ fputs("> ", dktrace_file());
+ for(i = 0; i < l; i++) {
+ fputs(" ", dktrace_file());
+ }
+ fputs(nptr->title, dktrace_file());
+ if(nptr->shorttitle) {
+ fputs(" (", dktrace_file());
+ fputs(nptr->shorttitle, dktrace_file());
+ fputs(")", dktrace_file());
+ }
+ fprintf(dktrace_file(), " depth=%d", nptr->depth);
+ fputc('\n', dktrace_file());
+ dk3sto_it_reset(nptr->i_subnodes);
+ while(NULL != (hbptr = (hb_node_t *)dk3sto_it_next(nptr->i_subnodes))) {
+ hb_show_tree_node(job, hbptr, (l+1));
+ }
+ }
+}
+
+/** Show document tree structure.
+ @param job Job structure.
+*/
+static
+void
+hb_show_structure(hb_job_t *job)
+{
+ hb_show_tree_node(job, job->rootnode, 0);
+}
+#endif
+
+
+
+#if (DK3_ON_WINDOWS) || (DK3_CHAR_SIZE > 1)
+/** Write file name to output file, ANSI encoded.
+ Set exit status code on error.
+ @param job Job structure.
+ @param fn File name.
+*/
+static
+void
+hb_write_ansi_filename(hb_job_t *job, dkChar const *fn)
+{
+ $? "+ hb_write_ansi_filename \"%!ds\"", TR_STR(fn)
+ if(!dk3se_ansi_fputs(fn, dk3app_get_encoding(job->app), job->of, job->app)) {
+ job->exv = 1;
+ } $? "- hb_write_ansi_filename"
+}
+#endif
+
+
+#if !DK3_ON_WINDOWS
+/** Write a file name.
+ @param job Job structure.
+ @param fn File name to write.
+*/
+static
+void
+hb_write_filename(hb_job_t *job, dkChar const *fn)
+{
+#if DK3_CHAR_SIZE > 1
+ hb_write_ansi_filename(job, fn);
+#error "Not implemented!"
+#else
+ if(EOF == fputs(fn, job->of)) {
+ job->exv = 1;
+ /* ERROR: Write attempt failed! */
+ dk3app_log_i1(job->app, DK3_LL_ERROR, 120);
+ }
+#endif
+}
+#endif
+
+
+
+/** Check whether the output file for a node is a HTML file.
+ @param nptr Node to check.
+ @return 1 for HTML files, 0 otherwise.
+*/
+static
+int
+hb_htfile(hb_node_t *nptr)
+{
+ int back = 1;
+ $? "+ hb_htfile"
+ if(nptr->suffix) {
+ back = 0;
+ if(dk3str_fncmp(nptr->suffix, hb_kwnl[23]) == 0) { back = 1; }
+ if(dk3str_fncmp(nptr->suffix, hb_kwnl[24]) == 0) { back = 1; }
+ } $? "- hb_htfile %d", back
+ return back;
+}
+
+
+
+/** Write instruction to copy one file to script.
+ @param job Job structure.
+ @param fn File name.
+*/
+static
+void
+hb_write_script_copy_file(hb_job_t *job, dkChar const *fn)
+{
+#if DK3_ON_WINDOWS
+ fputs(hb_c8_kw[8], job->of);
+ hb_write_ansi_filename(job, fn);
+ fputs(hb_c8_kw[9], job->of);
+ hb_write_ansi_filename(job, fn);
+ fputs(hb_c8_kw[0], job->of);
+ fputs(hb_c8_kw[10], job->of);
+ hb_write_ansi_filename(job, fn);
+ fputs(hb_c8_kw[11], job->of);
+ hb_write_ansi_filename(job, fn);
+ fputs(hb_c8_kw[12], job->of);
+ hb_write_ansi_filename(job, job->outputdir);
+ fputs(hb_c8_kw[13], job->of);
+#else
+ fputs(hb_c8_kw[14], job->of); /* if */
+ hb_write_filename(job, fn);
+ fputs(hb_c8_kw[15], job->of); /* then */
+ fputs(hb_c8_kw[16], job->of); /* else */
+ if((job->options) & HB_JOB_OPT_LN) {
+ fputs(hb_c8_kw[19], job->of);
+ } else {
+ fputs(hb_c8_kw[20], job->of);
+ }
+ hb_write_filename(job, fn);
+ fputs(hb_c8_kw[21], job->of);
+ hb_write_filename(job, job->outputdir);
+ fputs(hb_c8_kw[5], job->of);
+ fputs(hb_c8_kw[17], job->of); /* fi */
+ fputs(hb_c8_kw[22], job->of);
+ hb_write_filename(job, fn);
+ fputs(hb_c8_kw[23], job->of);
+ fputs(hb_c8_kw[35], job->of);
+ fputs(hb_c8_kw[18], job->of);
+#endif
+}
+
+
+
+/** Write the output script.
+ Set exit status code on errors.
+ @param job Job structure.
+*/
+static
+void
+hb_write_script(hb_job_t *job)
+{
+ dkChar of[DK3_MAX_PATH]; /* Output file name */
+ hb_node_t *nptr; /* Current print node */
+ dkChar const *fn; /* Current resource file name */
+ $? "+ hb_write_script"
+ if(job->outputscript) {
+ if(job->outputdir) {
+ job->of = dk3sf_fopen_app(job->outputscript, hb_kwnl[22], job->app);
+ if(job->of) {
+ /* Start of file
+ */
+#if DK3_ON_WINDOWS
+ fputs(hb_c8_kw[31], job->of);
+#else
+ fputs(hb_c8_kw[32], job->of);
+ fputs(hb_c8_kw[33], job->of);
+#endif
+ /* Remove existing directory completely.
+ */
+#if DK3_ON_WINDOWS
+ fputs(hb_c8_kw[2], job->of);
+ hb_write_ansi_filename(job, job->outputdir);
+ fputs(hb_c8_kw[3], job->of);
+#else
+ fputs(hb_c8_kw[4], job->of);
+ hb_write_filename(job, job->outputdir);
+ fputs(hb_c8_kw[5], job->of);
+#endif
+ /* Create new directory.
+ */
+#if DK3_ON_WINDOWS
+ fputs(hb_c8_kw[6], job->of);
+ hb_write_ansi_filename(job, job->outputdir);
+ fputs(hb_c8_kw[5], job->of);
+#else
+ fputs(hb_c8_kw[7], job->of);
+ hb_write_filename(job, job->outputdir);
+ fputs(hb_c8_kw[5], job->of);
+#endif
+ /* Copy resource files.
+ */
+ dk3sto_it_reset(job->i_files);
+ while(NULL != (fn = (dkChar const *)dk3sto_it_next(job->i_files))) {
+ /* 2014-04-17
+ Writinig the file copy instruction is now in the
+ hb_write_script_copy_file() function.
+ */
+ hb_write_script_copy_file(job, fn);
+ }
+ /* For CHM projects copy index.hhp, index.hhc and index.hhk
+ */
+ if ((job->options) & HB_JOB_OPT_CHM) {
+ hb_write_script_copy_file(job, hb_kwnl[36]);
+ hb_write_script_copy_file(job, hb_kwnl[26]);
+ hb_write_script_copy_file(job, hb_kwnl[28]);
+ if ((job->options) & HB_JOB_OPT_CREATE_INDEX) {
+ if (hbchm_have_index_entries(job)) {
+ hb_write_script_copy_file(job, hb_kwnl[29]);
+ }
+ }
+ }
+ /* Copy HTML files, use tidy if available.
+ */
+ dk3sto_it_reset(job->i_pnodes);
+ while(NULL != (nptr = (hb_node_t *)dk3sto_it_next(job->i_pnodes))) {
+ if(hbhtml_create_output_filename(of,DK3_SIZEOF(of,dkChar),job,nptr))
+ {
+ fn = of;
+#if DK3_ON_WINDOWS
+ /* Remove existing file.
+ */
+ fputs(hb_c8_kw[10], job->of);
+ hb_write_ansi_filename(job, job->outputdir);
+ fputc('\\', job->of);
+ hb_write_ansi_filename(job, fn);
+ fputs(hb_c8_kw[38], job->of);
+ hb_write_ansi_filename(job, job->outputdir);
+ fputc('\\', job->of);
+ hb_write_ansi_filename(job, fn);
+ fputs(hb_c8_kw[39], job->of);
+ /* Use tidy or xcopy to bring new file in place.
+ */
+ fputs(hb_c8_kw[8], job->of);
+ hb_write_ansi_filename(job, fn);
+ fputs(hb_c8_kw[9], job->of);
+ hb_write_ansi_filename(job, fn);
+ fputs(hb_c8_kw[0], job->of);
+ if(((nptr->options) & HB_NODE_OPT_USE_TIDY) && (hb_htfile(nptr))) {
+ fputs(hb_c8_kw[36], job->of);
+ hb_write_ansi_filename(job, fn);
+ fputs(hb_c8_kw[0], job->of);
+ if(HB_CS_UTF_8 == job->cs) {
+ fputs(hb_c8_kw[24], job->of);
+ hb_write_ansi_filename(job, fn);
+ fputs(hb_c8_kw[26], job->of);
+ hb_write_ansi_filename(job, job->outputdir);
+ fputc('\\', job->of);
+ hb_write_ansi_filename(job, fn);
+ fputs(hb_c8_kw[3], job->of);
+ } else {
+ fputs(hb_c8_kw[25], job->of);
+ hb_write_ansi_filename(job, fn);
+ fputs(hb_c8_kw[26], job->of);
+ hb_write_ansi_filename(job, job->outputdir);
+ fputc('\\', job->of);
+ hb_write_ansi_filename(job, fn);
+ fputs(hb_c8_kw[3], job->of);
+ }
+ } else {
+ fputs(hb_c8_kw[10], job->of);
+ hb_write_ansi_filename(job, fn);
+ fputs(hb_c8_kw[11], job->of);
+ hb_write_ansi_filename(job, fn);
+ fputs(hb_c8_kw[12], job->of);
+ hb_write_ansi_filename(job, job->outputdir);
+ fputs(hb_c8_kw[13], job->of);
+ }
+#else
+ /* Remove existing file.
+ */
+ fputs(hb_c8_kw[14], job->of); /* if */
+ hb_write_filename(job, job->outputdir);
+ fputs(hb_c8_kw[30], job->of);
+ hb_write_filename(job, fn);
+ fputs(hb_c8_kw[15], job->of);
+ fputs(hb_c8_kw[16], job->of); /* then */
+ fputs(hb_c8_kw[4], job->of);
+ hb_write_filename(job, job->outputdir);
+ fputs(hb_c8_kw[30], job->of);
+ hb_write_filename(job, fn);
+ fputs(hb_c8_kw[5], job->of);
+ fputs(hb_c8_kw[18], job->of); /* fi */
+ /* Use tidy, cp or ln to bring new file in place.
+ */
+ fputs(hb_c8_kw[14], job->of);
+ hb_write_filename(job, fn);
+ fputs(hb_c8_kw[15], job->of);
+ fputs(hb_c8_kw[16], job->of);
+ if(((nptr->options) & HB_NODE_OPT_USE_TIDY) && (hb_htfile(nptr))) {
+ fputs(hb_c8_kw[37], job->of);
+ hb_write_filename(job, fn);
+ fputs(hb_c8_kw[0], job->of);
+ if(HB_CS_UTF_8 == job->cs) {
+ fputs(hb_c8_kw[27], job->of);
+ } else {
+ fputs(hb_c8_kw[28], job->of);
+ }
+ hb_write_filename(job, fn);
+ fputs(hb_c8_kw[29], job->of);
+ hb_write_filename(job, job->outputdir);
+ fputs(hb_c8_kw[30], job->of);
+ hb_write_filename(job, fn);
+ fputs(hb_c8_kw[5], job->of);
+ } else {
+ if((job->options) & HB_JOB_OPT_LN) {
+ fputs(hb_c8_kw[19], job->of);
+ } else {
+ fputs(hb_c8_kw[20], job->of);
+ }
+ hb_write_filename(job, fn);
+ fputs(hb_c8_kw[21], job->of);
+ hb_write_filename(job, job->outputdir);
+ fputs(hb_c8_kw[5], job->of);
+ }
+ fputs(hb_c8_kw[17], job->of);
+ fputs(hb_c8_kw[22], job->of);
+ hb_write_filename(job, fn);
+ fputs(hb_c8_kw[23], job->of);
+ fputs(hb_c8_kw[35], job->of);
+ fputs(hb_c8_kw[18], job->of);
+#endif
+ }
+ }
+ /* End of file.
+ */
+#if !DK3_ON_WINDOWS
+ /* find ... -type d -exec chmod ugo+rx {} \; */
+ fputs(hb_c8_kw[40], job->of);
+ hb_write_filename(job, job->outputdir);
+ fputs(hb_c8_kw[41], job->of);
+ /* find ... -type f -exec chmod ugo+r {} \; */
+ fputs(hb_c8_kw[40], job->of);
+ hb_write_filename(job, job->outputdir);
+ fputs(hb_c8_kw[42], job->of);
+ /* exit EXITCODE */
+ fputs(hb_c8_kw[34], job->of);
+#endif
+ /* Close file.
+ */
+ if(!dk3sf_fclose_fn_app(job->of, job->outputscript, job->app)) {
+ job->exv = 1;
+ }
+ } else {
+ job->exv = 1;
+ }
+ } else {
+ job->exv = 1;
+ /* ERROR: No output directory configured! */
+ dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 67);
+ }
+ } else {
+ job->exv = 1;
+ /* ERROR: No output script configured! */
+ dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 68);
+ } $? "- hb_write_script"
+}
+
+
+
+/** Write output files.
+ Set exit status code on errors.
+ @param job Job structure.
+*/
+static
+void
+hb_write_output(hb_job_t *job)
+{
+ $? "+ hb_write_output"
+#if DK3_CHAR_SIZE == 1
+ $!trace-code hb_show_structure(job);
+#endif
+ hb_write_html_files(job);
+ hb_write_index(job);
+ hb_write_script(job);
+ if((job->options) & HB_JOB_OPT_CHM) {
+ if(!hbchm_write_project(job)) { job->exv = 1; }
+ }
+#if DK3_CHAR_SIZE == 1
+ $!trace-code hb_show_structure(job);
+#endif
+ $? "- hb_write_output"
+}
+
+
+
+/** Check consistency of input data.
+ @param job Job structure.
+ @return 1 on success, 0 on error.
+*/
+static
+int
+hb_check_data(hb_job_t *job)
+{
+ hb_node_t *nptr; /* Current node */
+ int back = 1;
+ $? "+ hb_check_data"
+ /* All printable nodes must have a template.
+ */
+ job->npobjs = 0UL;
+ dk3sto_it_reset(job->i_pnodes);
+ while(NULL != (nptr = (hb_node_t *)dk3sto_it_next(job->i_pnodes))) {
+ if(!(job->firstnode)) { job->firstnode = nptr; }
+ job->lastnode = nptr;
+ nptr->pobjno = job->npobjs;
+ job->npobjs += 1UL;
+ if(!hbconf_node_template(job, nptr)) {
+ back = 0;
+ /* ERROR: No template for node! */
+ dk3app_set_source_line(job->app, nptr->lineno);
+ dk3app_log_1(job->app, DK3_LL_WARNING, job->msg, 19);
+ }
+ }
+ if(back) {
+ /* ##### Further tests. */
+ } $? "- hb_check_data %d", back
+ return back;
+}
+
+
+
+/** Do normal processing for one specified project file.
+ @param job Job structure.
+*/
+static
+void
+hb_run_with_input_filename(hb_job_t *job)
+{
+ int res = 1;
+ $? "+ hb_run_with_input_filename"
+ dk3app_set_source_file(job->app, job->infilename);
+ dk3app_set_source_line(job->app, 0UL);
+ if(hb_job_allocate(job)) { $? ". allocation ok"
+ if(dk3opt_is_set(job->opt, dkT('o'))) {
+ res = hb_save_optional_sections(
+ job, dk3opt_get_short_arg(job->opt, dkT('o'))
+ );
+ }
+ if(res) {
+ if(hbconf_read_files(job)) {
+ if(hb_read_project(job)) {
+ if(hb_check_data(job)) {
+ hbtool_enumerate(job);
+ job->exv = 0; $? ". SUCCESS"
+ hb_write_output(job);
+ }
+ }
+ }
+ }
+ } else { $? "! allocation failed"
+ }
+ $? "- hb_run_with_input_filename"
+}
+
+
+
+/** Run normally.
+ @param job Job structure.
+*/
+static
+void
+hb_run(hb_job_t *job)
+{
+ dkChar const *infilename; /* Input file name */
+ dk3_dir_t *fne; /* File name expander */
+ dk3_um_t numfiles; /* Number of files in expander */
+ $? "+ hb_run"
+ infilename = dk3opt_get_arg(job->opt, 0);
+ if(infilename) {
+ if(dk3sf_must_expand(infilename)) {
+ fne = dk3dir_fne_open_app(infilename, job->app);
+ if(fne) {
+ numfiles = dk3dir_get_number_of_files(fne);
+ if(DK3_UM_0 < numfiles) {
+ if(DK3_UM_1 < numfiles) {
+ /* ERROR: Too many file names match */
+ dk3app_log_i3(job->app, DK3_LL_ERROR, 168, 169, infilename);
+ } else {
+ if(dk3dir_get_next_file(fne)) {
+ job->infilename = dk3dir_get_fullname(fne);
+ if(job->infilename) {
+ hb_run_with_input_filename(job);
+ } else {
+ /* ERROR: Failed to obtain file name */
+ dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 20);
+ }
+ } else {
+ /* ERROR: Failed to obtain file name */
+ dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 20);
+ }
+ }
+ } else {
+ /* ERROR: No matching file name! */
+ dk3app_log_i3(job->app, DK3_LL_ERROR, 215, 216, infilename);
+ }
+ dk3dir_close(fne);
+ }
+ } else {
+ job->infilename = infilename;
+ hb_run_with_input_filename(job);
+ }
+ } else {
+ /* ERROR: Missing project file name! */
+ dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 13);
+ }
+ $? "- hb_run"
+}
+
+
+
+/** Main function of the htmlbook program.
+ @param argc Number of command line arguments.
+ @param argv Command line arguments array.
+ @return 0 on success, any other value indicates an error.
+*/
+DK3_MAIN
+{
+ hb_job_t job; /* Job structure */
+ dk3_app_t *app = NULL; /* Application structure */
+ dkChar const * const *msg = NULL; /* Localized message texts */
+ dk3_time_t timer; /* Current time */
+ int exv = 1; /* Exit status code */
+
+ $!trace-init htmlbook.deb
+ $? "+ main"
+#if DK3_HAVE_TZSET
+ tzset();
+#endif
+ app = dk3app_open_command(
+ argc, (dkChar const * const *)argv, hb_kwnl[0]
+ );
+ if(app) {
+ msg = dk3app_messages(app, hb_kwnl[1], (dkChar const **)hb_kw);
+ hb_job_init(&job, app, msg, hb_kwnl);
+ dk3sf_time(&timer);
+ dk3sf_localtime_app(&(job.starttime), &timer, app);
+ if(hb_process_options(&job)) {
+ if(job.cmd) {
+ hb_help_version_license(&job);
+ } else {
+ hb_run(&job);
+ }
+ }
+ exv = job.exv;
+ hb_job_end(&job);
+ dk3app_close(app); app = NULL;
+ } else {
+ fputs("htmlbook: ERROR: Not enough memory (RAM/swap)!\n", stderr);
+ fflush(stderr);
+ }
+ $? "- main %d", exv
+ $!trace-end
+ fflush(stdout);
+ exit(exv); return exv;
+}
+
+