2002-11-01 18:22:40 +00:00
/*
* xhtml backend for Halibut
* ( initial implementation by James Aylett )
*
* Still to do :
*
* + + + doesn ' t handle non - breaking hyphens . Not sure how to yet .
* + + + entity names ( from a file - - ideally supply normal SGML files )
* + + + configuration directive to file split where the current layout
* code wouldn ' t . Needs changes to _ponder_layout ( ) and _do_paras ( ) ,
* perhaps others .
*
* Limitations :
*
* + + + biblio / index references target the nearest section marker , rather
* than having a dedicated target themselves . In large bibliographies
* this will cause problems . ( The solution is to fake up a response
* from xhtml_find_section ( ) , probably linking it into the sections
* chain just in case we need it again , and to make freeing it up
* easier . ) docsrc . pl used to work as we do , however , and SGT agrees that
* this is acceptable for now .
* + + + can ' t cope with leaf - level = = 0. It ' s all to do with the
* top - level file not being normal , probably not even having a valid
* section level , and stuff like that . I question whether this is an
* issue , frankly ; small manuals that fit on one page should probably
* not be written in halibut at all .
*/
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <assert.h>
# include "halibut.h"
2021-09-11 22:57:27 +00:00
enum outputtype { OT_XHTML = 0x01 , OT_CHM = 0x02 , OT_HTML4 = 0x04 , OT_HTML5 = 0x08 } ;
int g_outputtype = OT_XHTML ;
# define is_chm() ( (g_outputtype & OT_CHM) == OT_CHM )
# define is_xhtml() ( (g_outputtype & OT_XHTML) == OT_XHTML )
# define is_html5() ( (g_outputtype & OT_HTML5) == OT_HTML5 )
# define gettagtxt_br() ( is_xhtml() ? "<br / >" : "<br>" )
# define gettagtxt_hr() ( is_xhtml() ? "<hr / >" : "<hr>" )
2002-11-01 21:52:36 +00:00
struct xhtmlsection_Struct {
2003-04-04 14:43:36 +00:00
struct xhtmlsection_Struct * next ; /* next sibling (NULL if split across files) */
struct xhtmlsection_Struct * child ; /* NULL if split across files */
struct xhtmlsection_Struct * parent ; /* NULL if split across files */
struct xhtmlsection_Struct * chain ; /* single structure independent of weird trees */
paragraph * para ;
struct xhtmlfile_Struct * file ; /* which file is this a part of? */
char * fragment ; /* fragment id within the file */
int level ;
2002-11-01 18:22:40 +00:00
} ;
2002-11-01 21:52:36 +00:00
struct xhtmlfile_Struct {
2003-04-04 14:43:36 +00:00
struct xhtmlfile_Struct * next ;
struct xhtmlfile_Struct * child ;
struct xhtmlfile_Struct * parent ;
char * filename ;
struct xhtmlsection_Struct * sections ; /* sections within this file (only one for non-leaf) */
int is_leaf ; /* is this file a leaf file, ie does it not have any children? */
2002-11-01 18:22:40 +00:00
} ;
typedef struct xhtmlsection_Struct xhtmlsection ;
typedef struct xhtmlfile_Struct xhtmlfile ;
typedef struct xhtmlindex_Struct xhtmlindex ;
2002-11-01 21:52:36 +00:00
struct xhtmlindex_Struct {
2003-04-04 14:43:36 +00:00
int nsection ;
int size ;
xhtmlsection * * sections ;
2002-11-01 18:22:40 +00:00
} ;
2002-11-01 21:52:36 +00:00
typedef struct {
2003-04-04 14:43:36 +00:00
int just_numbers ;
wchar_t * number_suffix ;
2002-11-01 21:52:36 +00:00
} xhtmlheadfmt ;
typedef struct {
2003-04-04 14:43:36 +00:00
int contents_depth [ 6 ] ;
int leaf_contains_contents ;
int leaf_level ;
int leaf_smallest_contents ;
int include_version_id ;
wchar_t * author , * description ;
2021-09-11 22:57:27 +00:00
wchar_t * html_lang , * meta_charset ;
wchar_t * head_start , * head_middle , * head_end , * body , * body_start , * body_end ;
2021-09-13 23:21:37 +00:00
ustr_slist * meta_append ;
2021-09-11 22:57:27 +00:00
wchar_t * address_start , * address_end , * nav_attrs ;
2003-11-03 09:10:19 +00:00
wchar_t * rlink_prefix , * rlink_suffix ;
wchar_t * chm_toc_file , * chm_ind_file ;
2003-04-04 14:43:36 +00:00
int suppress_address ;
xhtmlheadfmt fchapter , * fsect ;
int nfsect ;
2011-11-30 22:17:17 +00:00
int keywordfragments ;
2002-11-01 21:52:36 +00:00
} xhtmlconfig ;
2002-11-01 18:22:40 +00:00
/*static void xhtml_level(paragraph *, int);
static void xhtml_level_0 ( paragraph * ) ;
static void xhtml_docontents ( FILE * , paragraph * , int ) ;
static void xhtml_dosections ( FILE * , paragraph * , int ) ;
static void xhtml_dobody ( FILE * , paragraph * , int ) ; */
2002-11-01 21:52:36 +00:00
static void xhtml_doheader ( FILE * , word * ) ;
static void xhtml_dofooter ( FILE * ) ;
static void xhtml_versionid ( FILE * , word * , int ) ;
2002-11-01 18:22:40 +00:00
2002-11-01 21:52:36 +00:00
static void xhtml_utostr ( wchar_t * , char * * ) ;
static int xhtml_para_level ( paragraph * ) ;
static int xhtml_reservedchar ( int ) ;
2002-11-01 18:22:40 +00:00
2002-11-01 21:52:36 +00:00
static int xhtml_convert ( wchar_t * , char * * , int ) ;
static void xhtml_rdaddwc ( rdstringc * , word * , word * ) ;
static void xhtml_para ( FILE * , word * ) ;
static void xhtml_codepara ( FILE * , word * ) ;
static void xhtml_heading ( FILE * , paragraph * ) ;
2002-11-01 18:22:40 +00:00
2003-11-03 09:10:19 +00:00
static void chm_doheader ( FILE * , word * ) ;
static void chm_dofooter ( FILE * ) ;
2002-11-01 18:22:40 +00:00
/* File-global variables are much easier than passing these things
* all over the place . Evil , but easier . We can replace this with a single
* structure at some point .
*/
static xhtmlconfig conf ;
static keywordlist * keywords ;
static indexdata * idx ;
static xhtmlfile * topfile ;
static xhtmlsection * topsection ;
static paragraph * sourceparas ;
static xhtmlfile * lastfile ;
static xhtmlfile * xhtml_last_file = NULL ;
static int last_level = - 1 ;
static xhtmlsection * currentsection ;
2003-11-03 09:10:19 +00:00
static FILE * chm_toc = NULL ;
static FILE * chm_ind = NULL ;
2021-09-11 22:57:27 +00:00
static const wchar_t * normalizehtmlkeywordprefix ( const wchar_t * s ) // [x]html... --> html...
{
return s & & utolower ( s [ 0 ] ) = = ' x ' & & utolower ( s [ 1 ] ) = = ' h ' & & utolower ( s [ 2 ] ) = = ' t ' ? s + 1 : s ;
}
static const wchar_t * ishtmlkeyword ( const wchar_t * a , const wchar_t * b )
{
return ! ustricmp ( normalizehtmlkeywordprefix ( a ) , normalizehtmlkeywordprefix ( b ) ) ? a : 0 ;
}
static wchar_t * configurekeyword ( wchar_t * * dst , const wchar_t * keyword , const paragraph * source )
{
if ( ishtmlkeyword ( source - > keyword , keyword ) )
return * dst = uadv ( source - > keyword ) ;
else
return 0 ;
}
2002-11-01 18:22:40 +00:00
2002-11-01 21:52:36 +00:00
static xhtmlconfig xhtml_configure ( paragraph * source )
2002-11-01 18:22:40 +00:00
{
2003-04-04 14:43:36 +00:00
xhtmlconfig ret ;
/*
* Defaults .
*/
ret . contents_depth [ 0 ] = 2 ;
ret . contents_depth [ 1 ] = 3 ;
ret . contents_depth [ 2 ] = 4 ;
ret . contents_depth [ 3 ] = 5 ;
ret . contents_depth [ 4 ] = 6 ;
ret . contents_depth [ 5 ] = 7 ;
ret . leaf_level = 2 ;
ret . leaf_smallest_contents = 4 ;
ret . leaf_contains_contents = FALSE ;
ret . include_version_id = TRUE ;
ret . author = NULL ;
ret . description = NULL ;
2021-09-11 22:57:27 +00:00
ret . html_lang = NULL ;
ret . meta_charset = NULL ;
ret . head_start = ret . head_middle = ret . head_end = NULL ;
2003-04-04 14:43:36 +00:00
ret . body = NULL ;
ret . body_start = NULL ;
ret . body_end = NULL ;
2021-09-13 23:21:37 +00:00
ret . meta_append = NULL ;
2003-04-04 14:43:36 +00:00
ret . address_start = NULL ;
ret . address_end = NULL ;
ret . nav_attrs = NULL ;
ret . suppress_address = FALSE ;
2003-11-03 09:10:19 +00:00
ret . chm_toc_file = NULL ;
ret . chm_ind_file = NULL ;
chm_toc = NULL ;
chm_ind = NULL ;
2003-04-04 14:43:36 +00:00
ret . fchapter . just_numbers = FALSE ;
ret . fchapter . number_suffix = ustrdup ( L " : " ) ;
ret . nfsect = 2 ;
ret . fsect = mknewa ( xhtmlheadfmt , ret . nfsect ) ;
ret . fsect [ 0 ] . just_numbers = FALSE ;
ret . fsect [ 0 ] . number_suffix = ustrdup ( L " : " ) ;
ret . fsect [ 1 ] . just_numbers = TRUE ;
ret . fsect [ 1 ] . number_suffix = ustrdup ( L " " ) ;
2003-11-03 09:10:19 +00:00
ret . rlink_prefix = NULL ;
ret . rlink_suffix = NULL ;
2011-11-30 22:17:17 +00:00
ret . keywordfragments = TRUE ;
2003-04-04 14:43:36 +00:00
for ( ; source ; source = source - > next )
{
if ( source - > type = = para_Config )
{
2021-09-11 22:57:27 +00:00
if ( ishtmlkeyword ( source - > keyword , L " html-version " ) )
{
const wchar_t * v = uadv ( source - > keyword ) ;
if ( ! ustricmp ( v , L " html4 " ) ) g_outputtype = OT_HTML4 ; // Note: Upstream treats this as "W3C HTML 4.01 Strict"
else if ( ! ustricmp ( v , L " html5 " ) ) g_outputtype = OT_HTML5 ;
else if ( ! ustricmp ( v , L " xhtml1.0transitional " ) ) g_outputtype = OT_XHTML ;
else error ( err_whatever , " %ls unknown %ls " , source - > keyword , v ) ;
} else if ( ishtmlkeyword ( source - > keyword , L " xhtml-contents-depth-0 " ) )
2003-04-04 14:43:36 +00:00
{
ret . contents_depth [ 0 ] = utoi ( uadv ( source - > keyword ) ) ;
2021-09-11 22:57:27 +00:00
} else if ( ishtmlkeyword ( source - > keyword , L " xhtml-contents-depth-1 " ) )
2003-04-04 14:43:36 +00:00
{
ret . contents_depth [ 1 ] = utoi ( uadv ( source - > keyword ) ) ;
2021-09-11 22:57:27 +00:00
} else if ( ishtmlkeyword ( source - > keyword , L " xhtml-contents-depth-2 " ) )
2003-04-04 14:43:36 +00:00
{
ret . contents_depth [ 2 ] = utoi ( uadv ( source - > keyword ) ) ;
2021-09-11 22:57:27 +00:00
} else if ( ishtmlkeyword ( source - > keyword , L " xhtml-contents-depth-3 " ) )
2003-04-04 14:43:36 +00:00
{
ret . contents_depth [ 3 ] = utoi ( uadv ( source - > keyword ) ) ;
2021-09-11 22:57:27 +00:00
} else if ( ishtmlkeyword ( source - > keyword , L " xhtml-contents-depth-4 " ) )
2003-04-04 14:43:36 +00:00
{
ret . contents_depth [ 4 ] = utoi ( uadv ( source - > keyword ) ) ;
2021-09-11 22:57:27 +00:00
} else if ( ishtmlkeyword ( source - > keyword , L " xhtml-contents-depth-5 " ) )
2003-04-04 14:43:36 +00:00
{
ret . contents_depth [ 5 ] = utoi ( uadv ( source - > keyword ) ) ;
2021-09-11 22:57:27 +00:00
} else if ( ishtmlkeyword ( source - > keyword , L " xhtml-leaf-level " ) )
2003-04-04 14:43:36 +00:00
{
ret . leaf_level = utoi ( uadv ( source - > keyword ) ) ;
} else
2021-09-11 22:57:27 +00:00
if ( ishtmlkeyword ( source - > keyword , L " xhtml-leaf-smallest-contents " ) )
2003-04-04 14:43:36 +00:00
{
ret . leaf_smallest_contents = utoi ( uadv ( source - > keyword ) ) ;
2021-09-11 22:57:27 +00:00
} else if ( ishtmlkeyword ( source - > keyword , L " xhtml-versionid " ) )
2003-04-04 14:43:36 +00:00
{
ret . include_version_id = utob ( uadv ( source - > keyword ) ) ;
2021-09-11 22:57:27 +00:00
} else if ( ishtmlkeyword ( source - > keyword , L " xhtml-leaf-contains-contents " ) )
2003-04-04 14:43:36 +00:00
{
ret . leaf_contains_contents = utob ( uadv ( source - > keyword ) ) ;
2021-09-11 22:57:27 +00:00
} else if ( ishtmlkeyword ( source - > keyword , L " xhtml-suppress-address " ) )
2003-04-04 14:43:36 +00:00
{
ret . suppress_address = utob ( uadv ( source - > keyword ) ) ;
2021-09-11 22:57:27 +00:00
} else if ( ishtmlkeyword ( source - > keyword , L " xhtml-author " ) )
2003-04-04 14:43:36 +00:00
{
ret . author = uadv ( source - > keyword ) ;
2003-11-03 09:10:19 +00:00
} else if ( ! ustricmp ( source - > keyword , L " chm-toc-file " ) )
{
ret . chm_toc_file = uadv ( source - > keyword ) ;
} else if ( ! ustricmp ( source - > keyword , L " chm-ind-file " ) )
{
ret . chm_ind_file = uadv ( source - > keyword ) ;
2021-09-11 22:57:27 +00:00
} else if ( ishtmlkeyword ( source - > keyword , L " xhtml-description " ) )
2003-04-04 14:43:36 +00:00
{
ret . description = uadv ( source - > keyword ) ;
2021-09-11 22:57:27 +00:00
} else if ( configurekeyword ( & ret . html_lang , L " xhtml-lang " , source ) ) {
} else if ( configurekeyword ( & ret . meta_charset , L " xhtml-meta-charset " , source ) ) {
} else if ( configurekeyword ( & ret . head_start , L " xhtml-head-start " , source ) ) {
} else if ( configurekeyword ( & ret . head_middle , L " xhtml-head-middle " , source ) ) {
} else if ( configurekeyword ( & ret . head_end , L " xhtml-head-end " , source ) ) {
} else if ( ishtmlkeyword ( source - > keyword , L " xhtml-body-start " ) )
2003-04-04 14:43:36 +00:00
{
ret . body_start = uadv ( source - > keyword ) ;
2021-09-11 22:57:27 +00:00
} else if ( ishtmlkeyword ( source - > keyword , L " xhtml-body-tag " ) )
2003-04-04 14:43:36 +00:00
{
ret . body = uadv ( source - > keyword ) ;
2021-09-11 22:57:27 +00:00
} else if ( ishtmlkeyword ( source - > keyword , L " xhtml-body-end " ) )
2003-04-04 14:43:36 +00:00
{
ret . body_end = uadv ( source - > keyword ) ;
2021-09-13 23:21:37 +00:00
} else if ( ishtmlkeyword ( source - > keyword , L " html-append-meta " ) )
{
ustr_slist_append ( & ret . meta_append , uadv ( source - > keyword ) ) ;
2021-09-11 22:57:27 +00:00
} else if ( ishtmlkeyword ( source - > keyword , L " xhtml-address-start " ) )
2003-04-04 14:43:36 +00:00
{
ret . address_start = uadv ( source - > keyword ) ;
2021-09-11 22:57:27 +00:00
} else if ( ishtmlkeyword ( source - > keyword , L " xhtml-address-end " ) )
2003-04-04 14:43:36 +00:00
{
ret . address_end = uadv ( source - > keyword ) ;
} else
2021-09-11 22:57:27 +00:00
if ( ishtmlkeyword ( source - > keyword , L " xhtml-navigation-attributes " ) )
2003-04-04 14:43:36 +00:00
{
ret . nav_attrs = uadv ( source - > keyword ) ;
2021-09-11 22:57:27 +00:00
} else if ( ishtmlkeyword ( source - > keyword , L " xhtml-chapter-numeric " ) )
2003-04-04 14:43:36 +00:00
{
ret . fchapter . just_numbers = utob ( uadv ( source - > keyword ) ) ;
2021-09-11 22:57:27 +00:00
} else if ( ishtmlkeyword ( source - > keyword , L " xhtml-chapter-suffix " ) )
2003-04-04 14:43:36 +00:00
{
2021-09-11 22:57:27 +00:00
ustrreplacedup ( & ret . fchapter . number_suffix , uadv ( source - > keyword ) ) ;
} else if ( ishtmlkeyword ( source - > keyword , L " xhtml-rlink-prefix " ) )
2003-11-03 09:10:19 +00:00
{
ret . rlink_prefix = uadv ( source - > keyword ) ;
2021-09-11 22:57:27 +00:00
} else if ( ishtmlkeyword ( source - > keyword , L " xhtml-rlink-suffix " ) )
2003-11-03 09:10:19 +00:00
{
ret . rlink_suffix = uadv ( source - > keyword ) ;
2021-09-11 22:57:27 +00:00
} else if ( ishtmlkeyword ( source - > keyword , L " xhtml-section-numeric " ) )
2003-04-04 14:43:36 +00:00
{
wchar_t * p = uadv ( source - > keyword ) ;
int n = 0 ;
if ( uisdigit ( * p ) )
{
n = utoi ( p ) ;
p = uadv ( p ) ;
}
if ( n > = ret . nfsect )
{
int i ;
ret . fsect = resize ( ret . fsect , n + 1 ) ;
for ( i = ret . nfsect ; i < = n ; i + + )
ret . fsect [ i ] = ret . fsect [ ret . nfsect - 1 ] ;
ret . nfsect = n + 1 ;
}
ret . fsect [ n ] . just_numbers = utob ( p ) ;
2021-09-11 22:57:27 +00:00
} else if ( ishtmlkeyword ( source - > keyword , L " xhtml-section-suffix " ) )
2003-04-04 14:43:36 +00:00
{
wchar_t * p = uadv ( source - > keyword ) ;
int n = 0 ;
if ( uisdigit ( * p ) )
{
n = utoi ( p ) ;
p = uadv ( p ) ;
}
if ( n > = ret . nfsect )
{
int i ;
ret . fsect = resize ( ret . fsect , n + 1 ) ;
for ( i = ret . nfsect ; i < = n ; i + + )
ret . fsect [ i ] = ret . fsect [ ret . nfsect - 1 ] ;
ret . nfsect = n + 1 ;
}
2021-09-11 22:57:27 +00:00
ustrreplacedup ( & ret . fsect [ n ] . number_suffix , p ) ;
} else if ( ishtmlkeyword ( source - > keyword , L " xhtml-keywordfragments " ) )
2011-11-30 22:17:17 +00:00
{
ret . keywordfragments = utob ( uadv ( source - > keyword ) ) ;
2003-04-04 14:43:36 +00:00
}
2002-11-01 18:22:40 +00:00
}
2003-04-04 14:43:36 +00:00
}
/* printf(" !!! leaf_level = %i\n", ret.leaf_level);
printf ( " !!! contentdepth-0 = %i \n " , ret . contents_depth [ 0 ] ) ;
printf ( " !!! contentdepth-1 = %i \n " , ret . contents_depth [ 1 ] ) ;
printf ( " !!! contentdepth-2 = %i \n " , ret . contents_depth [ 2 ] ) ;
printf ( " !!! contentdepth-3 = %i \n " , ret . contents_depth [ 3 ] ) ;
printf ( " !!! contentdepth-4 = %i \n " , ret . contents_depth [ 4 ] ) ;
printf ( " !!! contentdepth-5 = %i \n " , ret . contents_depth [ 5 ] ) ;
printf ( " !!! leaf_contains_contents = %i \n " , ret . leaf_contains_contents ) ; */
return ret ;
2002-11-01 18:22:40 +00:00
}
2002-11-01 21:52:36 +00:00
static xhtmlsection * xhtml_new_section ( xhtmlsection * last )
2002-11-01 18:22:40 +00:00
{
2003-04-04 14:43:36 +00:00
xhtmlsection * ret = mknew ( xhtmlsection ) ;
ret - > next = NULL ;
ret - > child = NULL ;
ret - > parent = NULL ;
ret - > chain = last ;
ret - > para = NULL ;
ret - > file = NULL ;
ret - > fragment = NULL ;
ret - > level = - 1 ; /* marker: end of chain */
return ret ;
2002-11-01 18:22:40 +00:00
}
/* Returns NULL or the section that marks that paragraph */
2002-11-01 21:52:36 +00:00
static xhtmlsection * xhtml_find_section ( paragraph * p )
2002-11-01 18:22:40 +00:00
{
2003-04-04 14:43:36 +00:00
xhtmlsection * ret = topsection ;
if ( xhtml_para_level ( p ) = = - 1 )
{ /* first, we back-track to a section paragraph */
paragraph * p2 = sourceparas ;
paragraph * p3 = NULL ;
while ( p2 & & p2 ! = p )
{
if ( xhtml_para_level ( p2 ) ! = - 1 )
{
p3 = p2 ;
}
p2 = p2 - > next ;
2002-11-01 18:22:40 +00:00
}
2003-04-04 14:43:36 +00:00
if ( p3 = = NULL )
{ /* for some reason, we couldn't find a section before this paragraph ... ? */
/* Note that this can happen, if you have a cross-reference to before the first chapter starts.
* So don ' t do that , then .
*/
return NULL ;
2002-11-01 18:22:40 +00:00
}
2003-04-04 14:43:36 +00:00
p = p3 ;
}
while ( ret & & ret - > para ! = p )
{
/* printf(" xhtml_find_section(): checking %s for para @ %p\n", ret->fragment, p);*/
ret = ret - > chain ;
}
return ret ;
2002-11-01 18:22:40 +00:00
}
2002-11-01 21:52:36 +00:00
static xhtmlfile * xhtml_new_file ( xhtmlsection * sect )
2002-11-01 18:22:40 +00:00
{
2003-04-04 14:43:36 +00:00
xhtmlfile * ret = mknew ( xhtmlfile ) ;
ret - > next = NULL ;
ret - > child = NULL ;
ret - > parent = NULL ;
ret - > filename = NULL ;
ret - > sections = sect ;
ret - > is_leaf = ( sect ! = NULL & & sect - > level = = conf . leaf_level ) ;
if ( sect = = NULL )
{
if ( conf . leaf_level = = 0 )
{ /* currently unused */
2002-11-01 18:22:40 +00:00
# define FILENAME_MANUAL "Manual.html"
# define FILENAME_CONTENTS "Contents.html"
2003-04-04 14:43:36 +00:00
ret - > filename = smalloc ( strlen ( FILENAME_MANUAL ) + 1 ) ;
sprintf ( ret - > filename , FILENAME_MANUAL ) ;
} else
{
ret - > filename = smalloc ( strlen ( FILENAME_CONTENTS ) + 1 ) ;
sprintf ( ret - > filename , FILENAME_CONTENTS ) ;
}
} else
{
paragraph * p = sect - > para ;
rdstringc fname_c = { 0 , 0 , NULL } ;
char * c ;
word * w ;
for ( w = ( p - > kwtext ) ? ( p - > kwtext ) : ( p - > words ) ; w ; w = w - > next )
{
switch ( removeattr ( w - > type ) )
{
case word_Normal :
/*case word_Emph:
case word_Code :
case word_WeakCode : */
xhtml_utostr ( w - > text , & c ) ;
rdaddsc ( & fname_c , c ) ;
sfree ( c ) ;
break ;
}
2002-11-01 18:22:40 +00:00
}
2003-04-04 14:43:36 +00:00
rdaddsc ( & fname_c , " .html " ) ;
ret - > filename = rdtrimc ( & fname_c ) ;
}
/* printf(" ! new file '%s', is_leaf == %s\n", ret->filename, (ret->is_leaf)?("true"):("false")); */
return ret ;
2002-11-01 18:22:40 +00:00
}
/*
* Walk the tree fixing up files which are actually leaf ( ie
* have no children ) but aren ' t at leaf level , so they have the
* leaf flag set .
*/
2002-11-01 21:52:36 +00:00
void xhtml_fixup_layout ( xhtmlfile * file )
2002-11-01 18:22:40 +00:00
{
2003-04-04 14:43:36 +00:00
if ( file - > child = = NULL )
{
file - > is_leaf = TRUE ;
} else
{
xhtml_fixup_layout ( file - > child ) ;
}
if ( file - > next )
xhtml_fixup_layout ( file - > next ) ;
2002-11-01 18:22:40 +00:00
}
/*
* Create the tree structure so we know where everything goes .
* Method :
*
* Ignoring file splitting , we have three choices with each new section :
*
* + - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - +
* | | |
* X + - - - - X - - - - + ( 1 )
* | |
* Y ( 2 )
* |
* ( 3 )
*
* Y is the last section we added ( currentsect ) .
* If sect is the section we want to add , then :
*
* ( 1 ) if sect - > level < currentsect - > level
* ( 2 ) if sect - > level = = currentsect - > level
* ( 3 ) if sect - > level > currentsect - > level
*
* This requires the constraint that you never skip section numbers
* ( so you can ' t have a . b . c . d without all of a , a . b and a . b . c existing ) .
*
* Note that you _can_ have 1.1 .1 .1 followed by 1.2 - you can change
* more than one level at a time . Lots of asserts , and probably part of
* the algorithm here , rely on this being true . ( It currently isn ' t
* enforced by halibut , however . )
*
* File splitting makes this harder . For instance , say we added at ( 3 )
* above and now need to add another section . We are splitting at level
* 2 , ie the level of Y . Z is the last section we added :
*
* + - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - +
* | | |
* X + - - - - X - - - - + ( 1 )
* | |
* + - - - - Y - - - - + ( 1 )
* | |
* Z ( 2 )
* |
* ( 3 )
*
* The ( 1 ) case is now split ; we need to search upwards to find where
* to actually link in . The other two cases remain the same ( and will
* always be like this ) .
*
* File splitting makes this harder , however . The decision of whether
* to split to a new file is always on the same condition , however ( is
* the level of this section higher than the leaf_level configuration
* value or not ) .
*
* Treating the cases backwards :
*
* ( 3 ) same file if sect - > level > conf . leaf_level , otherwise new file
*
* if in the same file , currentsect - > child points to sect
* otherwise the linking is done through the file tree ( which works
* in more or less the same way , ie currentfile - > child points to
* the new file )
*
* ( 2 ) same file if sect - > level > conf . leaf_level , otherwise new file
*
* if in the same file , currentsect - > next points to sect
* otherwise file linking and currentfile - > next points to the new
* file ( we know that Z must have caused a new file to be created )
*
* ( 1 ) same file if sect - > level > conf . leaf_level , otherwise new file
*
* this is actually effectively the same case as ( 2 ) here ,
* except that we first have to travel up the sections to figure
* out which section this new one will be a sibling of . In doing
* so , we may disappear off the top of a file and have to go up
* to its parent in the file tree .
*
*/
2002-11-01 21:52:36 +00:00
static void xhtml_ponder_layout ( paragraph * p )
2002-11-01 18:22:40 +00:00
{
2003-04-04 14:43:36 +00:00
xhtmlsection * lastsection ;
xhtmlsection * currentsect ;
xhtmlfile * currentfile ;
lastfile = NULL ;
topsection = xhtml_new_section ( NULL ) ;
topfile = xhtml_new_file ( NULL ) ;
lastsection = topsection ;
currentfile = topfile ;
currentsect = topsection ;
if ( conf . leaf_level = = 0 )
{
topfile - > is_leaf = 1 ;
topfile - > sections = topsection ;
topsection - > file = topfile ;
}
2002-11-01 18:22:40 +00:00
2003-04-04 14:43:36 +00:00
for ( ; p ; p = p - > next )
{
int level = xhtml_para_level ( p ) ;
if ( level > 0 )
{ /* actually a section */
xhtmlsection * sect ;
word * w ;
char * c ;
rdstringc fname_c = { 0 , 0 , NULL } ;
sect = xhtml_new_section ( lastsection ) ;
lastsection = sect ;
sect - > para = p ;
for ( w = ( p - > kwtext2 ) ? ( p - > kwtext2 ) : ( p - > words ) ; w ; w = w - > next )
{ /* kwtext2 because we want numbers only! */
switch ( removeattr ( w - > type ) )
{
case word_Normal :
/*case word_Emph:
case word_Code :
case word_WeakCode : */
xhtml_utostr ( w - > text , & c ) ;
rdaddsc ( & fname_c , c ) ;
sfree ( c ) ;
break ;
}
}
2002-11-01 18:22:40 +00:00
/* rdaddsc(&fname_c, ".html");*/
2003-04-04 14:43:36 +00:00
sect - > fragment = rdtrimc ( & fname_c ) ;
sect - > level = level ;
/* printf(" ! adding para @ %p as sect %s, level %i\n", sect->para, sect->fragment, level); */
if ( level > currentsect - > level )
{ /* case (3) */
if ( level > conf . leaf_level )
{ /* same file */
assert ( currentfile - > is_leaf ) ;
currentsect - > child = sect ;
sect - > parent = currentsect ;
sect - > file = currentfile ;
/* printf("connected '%s' to existing file '%s' [I]\n", sect->fragment, currentfile->filename); */
currentsect = sect ;
} else
{ /* new file */
xhtmlfile * file = xhtml_new_file ( sect ) ;
assert ( ! currentfile - > is_leaf ) ;
currentfile - > child = file ;
sect - > file = file ;
file - > parent = currentfile ;
/* printf("connected '%s' to new file '%s' [I]\n", sect->fragment, file->filename); */
currentfile = file ;
currentsect = sect ;
}
} else if ( level > = currentsect - > file - > sections - > level )
{
/* Case (1) or (2) *AND* still under the section that starts
* the current file .
*
* I ' m not convinced that this couldn ' t be rolled in with the
* final else { } leg further down . It seems a lot of effort
* this way .
*/
if ( level > conf . leaf_level )
{ /* stick within the same file */
assert ( currentfile - > is_leaf ) ;
sect - > file = currentfile ;
while ( currentsect & & currentsect - > level > level & &
currentsect - > file = = currentsect - > parent - > file )
{
currentsect = currentsect - > parent ;
}
assert ( currentsect ) ;
currentsect - > next = sect ;
assert ( currentsect - > level = = sect - > level ) ;
sect - > parent = currentsect - > parent ;
currentsect = sect ;
/* printf("connected '%s' to existing file '%s' [II]\n", sect->fragment, currentfile->filename); */
} else
{ /* new file */
xhtmlfile * file = xhtml_new_file ( sect ) ;
sect - > file = file ;
currentfile - > next = file ;
file - > parent = currentfile - > parent ;
file - > is_leaf = ( level = = conf . leaf_level ) ;
file - > sections = sect ;
/* printf("connected '%s' to new file '%s' [II]\n", sect->fragment, file->filename); */
currentfile = file ;
currentsect = sect ;
}
} else
{ /* Case (1) or (2) and we must move up the file tree first */
/* this loop is now probably irrelevant - we know we can't connect
* to anything in the current file */
while ( currentsect & & level < currentsect - > level )
{
currentsect = currentsect - > parent ;
if ( currentsect )
{
/* printf(" * up one level to '%s'\n", currentsect->fragment); */
} else
{
/* printf(" * up one level (off top of current file)\n"); */
}
}
if ( currentsect )
{
/* I'm pretty sure this can now never fire */
assert ( currentfile - > is_leaf ) ;
/* printf("connected '%s' to existing file '%s' [III]\n", sect->fragment, currentfile->filename); */
sect - > file = currentfile ;
currentsect - > next = sect ;
currentsect = sect ;
} else
{ /* find a file we can attach to */
while ( currentfile & & currentfile - > sections
& & level < currentfile - > sections - > level )
{
currentfile = currentfile - > parent ;
if ( currentfile )
{
/* printf(" * up one file level to '%s'\n", currentfile->filename); */
} else
{
/* printf(" * up one file level (off top of tree)\n"); */
}
}
if ( currentfile )
{ /* new file (we had to skip up a file to
get here , so we must be dealing with a
level no lower than the configured
leaf_level */
xhtmlfile * file = xhtml_new_file ( sect ) ;
currentfile - > next = file ;
sect - > file = file ;
file - > parent = currentfile - > parent ;
file - > is_leaf = ( level = = conf . leaf_level ) ;
file - > sections = sect ;
/* printf("connected '%s' to new file '%s' [III]\n", sect->fragment, file->filename); */
currentfile = file ;
currentsect = sect ;
} else
{
fatal ( err_whatever ,
" Ran off the top trying to connect sibling: strange document. " ) ;
}
}
}
2002-11-01 18:22:40 +00:00
}
2003-04-04 14:43:36 +00:00
}
topsection = lastsection ; /* get correct end of the chain */
xhtml_fixup_layout ( topfile ) ; /* leaf files not at leaf level marked as such */
2002-11-01 18:22:40 +00:00
}
2021-09-11 22:57:27 +00:00
static void xhtml_hack_xhtmlify ( word * words ) // "\" "<br" "\" ">" --> "\" "<br /" "\" ">"
{
int prevwasslash = 0 ;
if ( ! is_xhtml ( ) ) return ;
for ( ; words ; words = words - > next )
{
if ( ! words - > text ) continue ;
if ( prevwasslash )
{
if ( words - > text [ 0 ] = = ' < ' & & ! ustricmp ( words - > text , L " <br " ) & & words - > next & & words - > next - > text & & words - > next - > text [ 0 ] = = ' \\ ' )
ustrreplacedup ( & words - > text , L " <br / " ) ;
}
else
prevwasslash = words - > text [ 0 ] = = ' \\ ' & & ! words - > text [ 1 ] ;
}
}
2011-11-30 22:17:17 +00:00
# define NAMEDFRAGMENT_MAXLEN 200 /* More than enough for our usage */
/*
2016-02-04 20:14:06 +00:00
* Get formatted fragment name for html anchor .
2011-11-30 22:17:17 +00:00
* Uses para - > keyword if possible , falls back to the ? # . # . # default .
*/
static char *
xhtml_get_fragmentname ( const xhtmlsection * section , char * fragmentbuf )
{
if ( conf . keywordfragments )
{
paragraph * para = section - > para ;
if ( para & & para - > keyword & & * para - > keyword ) return ustrtoa ( para - > keyword , fragmentbuf , NAMEDFRAGMENT_MAXLEN ) ;
}
return section - > fragment ;
}
2002-11-01 21:52:36 +00:00
static void xhtml_do_index ( ) ;
static void xhtml_do_file ( xhtmlfile * file ) ;
static void xhtml_do_top_file ( xhtmlfile * file , paragraph * sourceform ) ;
static void xhtml_do_paras ( FILE * fp , paragraph * p ) ;
static int xhtml_do_contents_limit ( FILE * fp , xhtmlfile * file , int limit ) ;
2003-11-03 09:10:19 +00:00
static int xhtml_do_contents_section_limit ( FILE * fp , xhtmlsection * section , int limit ) ;
static int xhtml_add_contents_entry ( FILE * fp , xhtmlsection * section , int limit ) ;
2002-11-01 21:52:36 +00:00
static int xhtml_do_contents ( FILE * fp , xhtmlfile * file ) ;
static int xhtml_do_naked_contents ( FILE * fp , xhtmlfile * file ) ;
static void xhtml_do_sections ( FILE * fp , xhtmlsection * sections ) ;
2002-11-01 18:22:40 +00:00
/*
* Do all the files in this structure .
*/
2002-11-01 21:52:36 +00:00
static void xhtml_do_files ( xhtmlfile * file )
2002-11-01 18:22:40 +00:00
{
2003-04-04 14:43:36 +00:00
xhtml_do_file ( file ) ;
if ( file - > child )
xhtml_do_files ( file - > child ) ;
if ( file - > next )
xhtml_do_files ( file - > next ) ;
2002-11-01 18:22:40 +00:00
}
/*
* Free up all memory used by the file tree from ' xfile ' downwards
*/
2002-11-01 21:52:36 +00:00
static void xhtml_free_file ( xhtmlfile * xfile )
2002-11-01 18:22:40 +00:00
{
2003-04-04 14:43:36 +00:00
if ( xfile = = NULL )
{
return ;
}
2002-11-01 18:22:40 +00:00
2003-04-04 14:43:36 +00:00
if ( xfile - > filename )
{
sfree ( xfile - > filename ) ;
}
xhtml_free_file ( xfile - > child ) ;
xhtml_free_file ( xfile - > next ) ;
sfree ( xfile ) ;
2002-11-01 18:22:40 +00:00
}
/*
* Main function .
*/
void
2002-11-01 21:52:36 +00:00
xhtml_backend ( paragraph * sourceform , keywordlist * in_keywords ,
2003-04-04 14:43:36 +00:00
indexdata * in_idx )
2002-11-01 18:22:40 +00:00
{
/* int i;*/
2003-04-04 14:43:36 +00:00
indexentry * ientry ;
int ti ;
xhtmlsection * xsect ;
sourceparas = sourceform ;
conf = xhtml_configure ( sourceform ) ;
keywords = in_keywords ;
idx = in_idx ;
/* Clear up the index entries backend data pointers */
for ( ti = 0 ;
( ientry = ( indexentry * ) index234 ( idx - > entries , ti ) ) ! = NULL ; ti + + )
{
ientry - > backend_data = NULL ;
}
2002-11-01 18:22:40 +00:00
2003-04-04 14:43:36 +00:00
xhtml_ponder_layout ( sourceform ) ;
2002-11-01 18:22:40 +00:00
2003-04-04 14:43:36 +00:00
/* old system ... (writes to *.alt, but gets some stuff wrong and is ugly) */
2002-11-01 18:22:40 +00:00
/* xhtml_level_0(sourceform);
for ( i = 1 ; i < = conf . leaf_level ; i + + )
{
xhtml_level ( sourceform , i ) ;
} */
2003-04-04 14:43:36 +00:00
/* new system ... (writes to *.html, but isn't fully trusted) */
xhtml_do_top_file ( topfile , sourceform ) ;
assert ( ! topfile - > next ) ; /* shouldn't have a sibling at all */
if ( topfile - > child )
{
xhtml_do_files ( topfile - > child ) ;
xhtml_do_index ( ) ;
}
2002-11-01 18:22:40 +00:00
2003-04-04 14:43:36 +00:00
/* release file, section, index data structures */
xsect = topsection ;
while ( xsect )
{
xhtmlsection * tmp = xsect - > chain ;
if ( xsect - > fragment )
{
sfree ( xsect - > fragment ) ;
2002-11-01 18:22:40 +00:00
}
2003-04-04 14:43:36 +00:00
sfree ( xsect ) ;
xsect = tmp ;
}
xhtml_free_file ( topfile ) ;
for ( ti = 0 ;
( ientry = ( indexentry * ) index234 ( idx - > entries , ti ) ) ! = NULL ; ti + + )
{
if ( ientry - > backend_data ! = NULL )
2002-11-01 18:22:40 +00:00
{
2003-04-04 14:43:36 +00:00
xhtmlindex * xi = ( xhtmlindex * ) ientry - > backend_data ;
if ( xi - > sections ! = NULL )
{
sfree ( xi - > sections ) ;
}
sfree ( xi ) ;
2002-11-01 18:22:40 +00:00
}
2003-04-04 14:43:36 +00:00
ientry - > backend_data = NULL ;
}
{
int i ;
sfree ( conf . fchapter . number_suffix ) ;
for ( i = 0 ; i < conf . nfsect ; i + + )
sfree ( conf . fsect [ i ] . number_suffix ) ;
sfree ( conf . fsect ) ;
}
2021-09-14 22:42:37 +00:00
free_ustr_slist ( conf . meta_append ) ;
2002-11-01 18:22:40 +00:00
}
2002-11-01 21:52:36 +00:00
static int xhtml_para_level ( paragraph * p )
2002-11-01 18:22:40 +00:00
{
2003-04-04 14:43:36 +00:00
switch ( p - > type )
{
case para_Title :
return 0 ;
break ;
case para_UnnumberedChapter :
case para_Chapter :
case para_Appendix :
return 1 ;
break ;
2002-11-01 18:22:40 +00:00
/* case para_BiblioCited:
return 2 ;
break ; */
2003-04-04 14:43:36 +00:00
case para_Heading :
case para_Subsect :
return p - > aux + 2 ;
break ;
default :
return - 1 ;
break ;
}
2002-11-01 18:22:40 +00:00
}
static char * xhtml_index_filename = " IndexPage.html " ;
/* Output the nav links for the current file.
* file = = NULL means we ' re doing the index
*/
2002-11-01 21:52:36 +00:00
static void xhtml_donavlinks ( FILE * fp , xhtmlfile * file )
2002-11-01 18:22:40 +00:00
{
2003-04-04 14:43:36 +00:00
xhtmlfile * xhtml_next_file = NULL ;
fprintf ( fp , " <p " ) ;
if ( conf . nav_attrs ! = NULL )
{
fprintf ( fp , " %ls> " , conf . nav_attrs ) ;
} else
{
fprintf ( fp , " > " ) ;
}
if ( xhtml_last_file = = NULL )
{
fprintf ( fp , " Previous | " ) ;
} else
{
fprintf ( fp , " <a href='%s'>Previous</a> | " , xhtml_last_file - > filename ) ;
}
fprintf ( fp , " <a href='Contents.html'>Contents</a> | " ) ;
if ( file ! = NULL )
{ /* otherwise we're doing nav links for the index */
if ( xhtml_next_file = = NULL )
xhtml_next_file = file - > child ;
if ( xhtml_next_file = = NULL )
xhtml_next_file = file - > next ;
if ( xhtml_next_file = = NULL )
xhtml_next_file = file - > parent - > next ;
}
if ( xhtml_next_file = = NULL )
{
if ( file = = NULL )
{ /* index, so no next file */
fprintf ( fp , " Next " ) ;
} else
{
fprintf ( fp , " <a href='%s'>Next</a> " , xhtml_index_filename ) ;
2002-11-01 18:22:40 +00:00
}
2003-04-04 14:43:36 +00:00
} else
{
fprintf ( fp , " <a href='%s'>Next</a> " , xhtml_next_file - > filename ) ;
}
fprintf ( fp , " </p> \n " ) ;
2002-11-01 18:22:40 +00:00
}
/* Write out the index file */
2002-11-01 21:52:36 +00:00
static void xhtml_do_index_body ( FILE * fp )
2002-11-01 18:22:40 +00:00
{
2003-04-04 14:43:36 +00:00
indexentry * y ;
int ti ;
if ( count234 ( idx - > entries ) = = 0 )
return ; /* don't write anything at all */
fprintf ( fp , " <dl> \n " ) ;
/* iterate over idx->entries using the tree functions and display everything */
for ( ti = 0 ; ( y = ( indexentry * ) index234 ( idx - > entries , ti ) ) ! = NULL ;
ti + + )
{
if ( y - > backend_data )
{
int i ;
xhtmlindex * xi ;
fprintf ( fp , " <dt> " ) ;
xhtml_para ( fp , y - > text ) ;
fprintf ( fp , " </dt> \n <dd> " ) ;
xi = ( xhtmlindex * ) y - > backend_data ;
for ( i = 0 ; i < xi - > nsection ; i + + )
{
xhtmlsection * sect = xi - > sections [ i ] ;
if ( sect )
{
2011-11-30 22:17:17 +00:00
char fragmentbuf [ NAMEDFRAGMENT_MAXLEN ] ;
2011-12-03 19:50:02 +00:00
fprintf ( fp , " <a href='%s#%s'> " , conf . leaf_level ? sect - > file - > filename : " " ,
2011-11-30 22:17:17 +00:00
xhtml_get_fragmentname ( sect , fragmentbuf ) ) ;
2003-04-04 14:43:36 +00:00
if ( sect - > para - > kwtext )
{
xhtml_para ( fp , sect - > para - > kwtext ) ;
} else if ( sect - > para - > words )
{
xhtml_para ( fp , sect - > para - > words ) ;
}
fprintf ( fp , " </a> " ) ;
if ( i + 1 < xi - > nsection )
{
fprintf ( fp , " , " ) ;
}
}
}
fprintf ( fp , " </dd> \n " ) ;
2002-11-01 18:22:40 +00:00
}
2003-04-04 14:43:36 +00:00
}
fprintf ( fp , " </dl> \n " ) ;
2002-11-01 18:22:40 +00:00
}
2002-11-01 21:52:36 +00:00
static void xhtml_do_index ( )
2002-11-01 18:22:40 +00:00
{
2003-04-04 14:43:36 +00:00
word temp_word =
{ NULL , NULL , word_Normal , 0 , 0 , L " Index " , { NULL , 0 , 0 } } ;
FILE * fp = fopen ( xhtml_index_filename , " w " ) ;
2002-11-01 18:22:40 +00:00
2003-04-04 14:43:36 +00:00
if ( fp = = NULL )
fatal ( err_cantopenw , xhtml_index_filename ) ;
xhtml_doheader ( fp , & temp_word ) ;
xhtml_donavlinks ( fp , NULL ) ;
2002-11-01 18:22:40 +00:00
2003-04-04 14:43:36 +00:00
xhtml_do_index_body ( fp ) ;
2002-11-01 18:22:40 +00:00
2003-04-04 14:43:36 +00:00
xhtml_donavlinks ( fp , NULL ) ;
xhtml_dofooter ( fp ) ;
fclose ( fp ) ;
2002-11-01 18:22:40 +00:00
}
/* Output the given file. This includes whatever contents at beginning and end, etc. etc. */
2002-11-01 21:52:36 +00:00
static void xhtml_do_file ( xhtmlfile * file )
2002-11-01 18:22:40 +00:00
{
2003-04-04 14:43:36 +00:00
FILE * fp = fopen ( file - > filename , " w " ) ;
if ( fp = = NULL )
fatal ( err_cantopenw , file - > filename ) ;
if ( file - > sections - > para - > words )
{
xhtml_doheader ( fp , file - > sections - > para - > words ) ;
} else if ( file - > sections - > para - > kwtext )
{
xhtml_doheader ( fp , file - > sections - > para - > kwtext ) ;
} else
{
xhtml_doheader ( fp , NULL ) ;
}
2002-11-01 18:22:40 +00:00
2003-04-04 14:43:36 +00:00
xhtml_donavlinks ( fp , file ) ;
2002-11-01 18:22:40 +00:00
2003-04-04 14:43:36 +00:00
if ( file - > is_leaf & & conf . leaf_contains_contents & &
xhtml_do_contents ( NULL , file ) > = conf . leaf_smallest_contents )
xhtml_do_contents ( fp , file ) ;
xhtml_do_sections ( fp , file - > sections ) ;
if ( ! file - > is_leaf )
xhtml_do_naked_contents ( fp , file ) ;
2002-11-01 18:22:40 +00:00
2003-04-04 14:43:36 +00:00
xhtml_donavlinks ( fp , file ) ;
2002-11-01 18:22:40 +00:00
2003-04-04 14:43:36 +00:00
xhtml_dofooter ( fp ) ;
fclose ( fp ) ;
2002-11-01 18:22:40 +00:00
2003-04-04 14:43:36 +00:00
xhtml_last_file = file ;
2002-11-01 18:22:40 +00:00
}
/* Output the top-level file. */
2002-11-01 21:52:36 +00:00
static void xhtml_do_top_file ( xhtmlfile * file , paragraph * sourceform )
2002-11-01 18:22:40 +00:00
{
2003-04-04 14:43:36 +00:00
paragraph * p ;
2005-05-06 09:57:37 +00:00
char fname [ 4096 ] ;
2003-04-04 14:43:36 +00:00
int done = FALSE ;
2005-05-06 09:51:52 +00:00
2003-04-04 14:43:36 +00:00
FILE * fp = fopen ( file - > filename , " w " ) ;
2005-05-06 09:51:52 +00:00
if ( fp = = NULL )
fatal ( err_cantopenw , file - > filename ) ;
2021-09-11 22:57:27 +00:00
if ( conf . chm_toc_file | | conf . chm_ind_file ) g_outputtype = OT_CHM | ( g_outputtype & ( OT_XHTML | OT_HTML5 ) ) ;
2005-05-06 09:57:37 +00:00
ustrtoa ( conf . chm_toc_file , fname , 4096 ) ;
2003-11-03 09:10:19 +00:00
if ( * fname )
{
chm_toc = fopen ( fname , " w " ) ;
if ( chm_toc = = NULL )
2005-05-06 09:57:37 +00:00
fatal ( err_cantopenw , fname ) ;
2003-11-03 09:10:19 +00:00
}
else
chm_toc = NULL ;
2005-05-06 09:57:37 +00:00
ustrtoa ( conf . chm_ind_file , fname , 4096 ) ;
2003-11-03 09:10:19 +00:00
if ( * fname ) {
chm_ind = fopen ( fname , " w " ) ;
if ( chm_ind = = NULL )
2005-05-06 09:57:37 +00:00
fatal ( err_cantopenw , fname ) ;
2003-11-03 09:10:19 +00:00
}
else
chm_ind = NULL ;
2003-04-04 14:43:36 +00:00
/* Do the title -- only one allowed */
for ( p = sourceform ; p & & ! done ; p = p - > next )
{
if ( p - > type = = para_Title )
{
xhtml_doheader ( fp , p - > words ) ;
2003-11-03 09:10:19 +00:00
if ( chm_toc ) chm_doheader ( chm_toc , p - > words ) ;
if ( chm_ind ) chm_doheader ( chm_ind , p - > words ) ;
2003-04-04 14:43:36 +00:00
done = TRUE ;
2002-11-01 18:22:40 +00:00
}
2003-04-04 14:43:36 +00:00
}
if ( ! done )
xhtml_doheader ( fp , NULL /* Eek! */ ) ;
/*
* Display the title .
*/
for ( p = sourceform ; p ; p = p - > next )
{
if ( p - > type = = para_Title )
{
xhtml_heading ( fp , p ) ;
break ;
2002-11-01 18:22:40 +00:00
}
2003-04-04 14:43:36 +00:00
}
2002-11-01 18:22:40 +00:00
2003-04-04 14:43:36 +00:00
/* Do the preamble and copyright */
for ( p = sourceform ; p ; p = p - > next )
{
if ( p - > type = = para_Preamble )
{
fprintf ( fp , " <p> " ) ;
2021-09-11 22:57:27 +00:00
xhtml_hack_xhtmlify ( p - > words ) ;
2003-04-04 14:43:36 +00:00
xhtml_para ( fp , p - > words ) ;
fprintf ( fp , " </p> \n " ) ;
2002-11-01 18:22:40 +00:00
}
2003-04-04 14:43:36 +00:00
}
for ( p = sourceform ; p ; p = p - > next )
{
if ( p - > type = = para_Copyright )
{
fprintf ( fp , " <p> " ) ;
2021-09-11 22:57:27 +00:00
xhtml_hack_xhtmlify ( p - > words ) ;
2003-04-04 14:43:36 +00:00
xhtml_para ( fp , p - > words ) ;
fprintf ( fp , " </p> \n " ) ;
2002-11-01 18:22:40 +00:00
}
2003-04-04 14:43:36 +00:00
}
2002-11-01 18:22:40 +00:00
2003-04-04 14:43:36 +00:00
xhtml_do_contents ( fp , file ) ;
xhtml_do_sections ( fp , file - > sections ) ;
2002-11-01 18:22:40 +00:00
2003-04-04 14:43:36 +00:00
/*
* Put the index in the top file if we ' re in single - file mode
* ( leaf - level 0 ) .
*/
if ( conf . leaf_level = = 0 & & count234 ( idx - > entries ) > 0 )
{
fprintf ( fp , " <a name= \" index \" ></a><h1>Index</h1> \n " ) ;
xhtml_do_index_body ( fp ) ;
}
xhtml_dofooter ( fp ) ;
2003-11-03 09:10:19 +00:00
if ( chm_toc ) chm_dofooter ( chm_toc ) ;
if ( chm_ind ) chm_dofooter ( chm_ind ) ;
2003-04-04 14:43:36 +00:00
fclose ( fp ) ;
2005-05-10 20:30:01 +00:00
if ( chm_toc )
{
fclose ( chm_toc ) ;
chm_toc = NULL ;
}
if ( chm_ind )
{
fclose ( chm_ind ) ;
chm_ind = NULL ;
}
2002-11-01 18:22:40 +00:00
}
/* Convert a Unicode string to an ASCII one. '?' is
* used for unmappable characters .
*/
2002-11-01 21:52:36 +00:00
static void xhtml_utostr ( wchar_t * in , char * * out )
2002-11-01 18:22:40 +00:00
{
2003-04-04 14:43:36 +00:00
int l = ustrlen ( in ) ;
int i ;
* out = smalloc ( l + 1 ) ;
for ( i = 0 ; i < l ; i + + )
{
if ( in [ i ] > = 32 & & in [ i ] < = 126 )
( * out ) [ i ] = ( char ) in [ i ] ;
else
( * out ) [ i ] = ' ? ' ;
}
( * out ) [ i ] = 0 ;
2002-11-01 18:22:40 +00:00
}
/*
* Write contents for the given file , and subfiles , down to
* the appropriate contents depth . Returns the number of
* entries written .
*/
2002-11-01 21:52:36 +00:00
static int xhtml_do_contents ( FILE * fp , xhtmlfile * file )
2002-11-01 18:22:40 +00:00
{
2003-04-04 14:43:36 +00:00
int level , limit , start_level , count = 0 ;
if ( ! file )
return 0 ;
level = ( file - > sections ) ? ( file - > sections - > level ) : ( 0 ) ;
limit = conf . contents_depth [ ( level > 5 ) ? ( 5 ) : ( level ) ] ;
start_level = ( file - > is_leaf ) ? ( level - 1 ) : ( level ) ;
last_level = start_level ;
count + = xhtml_do_contents_section_limit ( fp , file - > sections , limit ) ;
count + = xhtml_do_contents_limit ( fp , file - > child , limit ) ;
if ( fp ! = NULL )
{
while ( last_level > start_level )
{
last_level - - ;
fprintf ( fp , " </ul> \n " ) ;
2003-11-03 09:10:19 +00:00
if ( chm_toc ) fprintf ( chm_toc , " </ul> \n " ) ;
2002-11-01 18:22:40 +00:00
}
2003-04-04 14:43:36 +00:00
}
return count ;
2002-11-01 18:22:40 +00:00
}
/* As above, but doesn't do anything in the current file */
2002-11-01 21:52:36 +00:00
static int xhtml_do_naked_contents ( FILE * fp , xhtmlfile * file )
2002-11-01 18:22:40 +00:00
{
2003-04-04 14:43:36 +00:00
int level , limit , start_level , count = 0 ;
if ( ! file )
return 0 ;
level = ( file - > sections ) ? ( file - > sections - > level ) : ( 0 ) ;
limit = conf . contents_depth [ ( level > 5 ) ? ( 5 ) : ( level ) ] ;
start_level = ( file - > is_leaf ) ? ( level - 1 ) : ( level ) ;
last_level = start_level ;
count = xhtml_do_contents_limit ( fp , file - > child , limit ) ;
if ( fp ! = NULL )
{
while ( last_level > start_level )
{
last_level - - ;
fprintf ( fp , " </ul> \n " ) ;
2003-11-03 09:10:19 +00:00
if ( chm_toc ) fprintf ( chm_toc , " </ul> \n " ) ;
2002-11-01 18:22:40 +00:00
}
2003-04-04 14:43:36 +00:00
}
return count ;
2002-11-01 18:22:40 +00:00
}
/*
* Write contents for the given file , children , and siblings , down to
* given limit contents depth .
*/
2002-11-01 21:52:36 +00:00
static int xhtml_do_contents_limit ( FILE * fp , xhtmlfile * file , int limit )
2002-11-01 18:22:40 +00:00
{
2003-04-04 14:43:36 +00:00
int count = 0 ;
while ( file )
{
count + = xhtml_do_contents_section_limit ( fp , file - > sections , limit ) ;
count + = xhtml_do_contents_limit ( fp , file - > child , limit ) ;
file = file - > next ;
}
return count ;
2002-11-01 18:22:40 +00:00
}
/*
* Write contents entries for the given section tree , down to the
* limit contents depth .
*/
static int
2002-11-01 21:52:36 +00:00
xhtml_do_contents_section_deep_limit ( FILE * fp , xhtmlsection * section ,
2003-04-04 14:43:36 +00:00
int limit )
2002-11-01 18:22:40 +00:00
{
2003-04-04 14:43:36 +00:00
int count = 0 ;
while ( section )
{
if ( ! xhtml_add_contents_entry ( fp , section , limit ) )
return 0 ;
else
count + + ;
count + =
xhtml_do_contents_section_deep_limit ( fp , section - > child , limit ) ;
section = section - > next ;
}
return count ;
2002-11-01 18:22:40 +00:00
}
/*
* Write contents entries for the given section tree , down to the
* limit contents depth .
*/
static int
2003-11-03 09:10:19 +00:00
xhtml_do_contents_section_limit ( FILE * fp , xhtmlsection * section , int limit )
2002-11-01 18:22:40 +00:00
{
2003-04-04 14:43:36 +00:00
int count = 0 ;
if ( ! section )
return 0 ;
xhtml_add_contents_entry ( fp , section , limit ) ;
count = 1 ;
count + = xhtml_do_contents_section_deep_limit ( fp , section - > child , limit ) ;
/* section=section->child;
while ( section & & xhtml_add_contents_entry ( fp , section , limit ) ) {
section = section - > next ;
} */
return count ;
2002-11-01 18:22:40 +00:00
}
/*
* Add a section entry , unless we ' re exceeding the limit , in which
* case return FALSE ( otherwise return TRUE ) .
*/
static int
2002-11-01 21:52:36 +00:00
xhtml_add_contents_entry ( FILE * fp , xhtmlsection * section , int limit )
2002-11-01 18:22:40 +00:00
{
2011-12-03 19:50:02 +00:00
char fragmentbuf [ NAMEDFRAGMENT_MAXLEN ] , * fragment , * filename ;
2003-04-04 14:43:36 +00:00
if ( ! section | | section - > level > limit )
return FALSE ;
if ( fp = = NULL | | section - > level < 0 )
2002-11-01 21:52:36 +00:00
return TRUE ;
2003-04-04 14:43:36 +00:00
while ( last_level > section - > level )
{
last_level - - ;
fprintf ( fp , " </ul> \n " ) ;
2003-11-03 09:10:19 +00:00
if ( chm_toc ) fprintf ( chm_toc , " </ul> \n " ) ;
2003-04-04 14:43:36 +00:00
}
while ( last_level < section - > level )
{
last_level + + ;
fprintf ( fp , " <ul> \n " ) ;
2003-11-03 09:10:19 +00:00
if ( chm_toc ) fprintf ( chm_toc , " <ul> \n " ) ;
2003-04-04 14:43:36 +00:00
}
2011-12-03 19:50:02 +00:00
filename = conf . leaf_level ? section - > file - > filename : " " ;
2011-12-03 20:07:28 +00:00
fragment = " " ;
if ( section - > para - > type ! = para_Chapter | | ! conf . leaf_level )
fragment = xhtml_get_fragmentname ( section , fragmentbuf ) ;
2003-04-04 14:43:36 +00:00
fprintf ( fp , " <li> " ) ;
fprintf ( fp , " <a %shref= \" %s#%s \" > " ,
2003-11-03 09:10:19 +00:00
( section - > para - > type = = para_Chapter | | section - > para - > type = = para_Appendix ) ? " class= \" btitle \" " : " " ,
2011-12-03 20:07:28 +00:00
filename , fragment ) ;
2003-11-03 09:10:19 +00:00
if ( chm_toc ) fprintf ( chm_toc , " <li><OBJECT type= \" text/sitemap \" ><param name= \" Local \" value= \" %s#%s \" ><param name= \" Name \" value= \" " ,
2011-12-03 20:07:28 +00:00
filename , fragment ) ;
2003-11-03 09:10:19 +00:00
if ( chm_ind ) fprintf ( chm_ind , " <li><OBJECT type= \" text/sitemap \" ><param name= \" Local \" value= \" %s#%s \" ><param name= \" Name \" value= \" " ,
2011-12-03 20:07:28 +00:00
filename , fragment ) ;
2003-11-03 09:10:19 +00:00
//%s
2003-04-04 14:43:36 +00:00
if ( section - > para - > type = = para_Chapter
| | section - > para - > type = = para_Appendix )
fprintf ( fp , " <b> " ) ;
if ( ( section - > para - > type ! = para_Heading
& & section - > para - > type ! = para_Subsect ) | | ( section - > para - > kwtext
& & ! section - > para - >
words ) )
{
xhtml_para ( fp , section - > para - > kwtext ) ;
2003-11-03 09:10:19 +00:00
if ( chm_toc ) xhtml_para ( chm_toc , section - > para - > kwtext ) ;
if ( section - > para - > words ) {
2003-04-04 14:43:36 +00:00
fprintf ( fp , " : " ) ;
2003-11-03 09:10:19 +00:00
if ( chm_toc ) fprintf ( chm_toc , " : " ) ;
}
2003-04-04 14:43:36 +00:00
}
if ( section - > para - > type = = para_Chapter
| | section - > para - > type = = para_Appendix )
fprintf ( fp , " </b> " ) ;
if ( section - > para - > words )
{
xhtml_para ( fp , section - > para - > words ) ;
2003-11-03 09:10:19 +00:00
if ( chm_toc ) xhtml_para ( chm_toc , section - > para - > words ) ;
if ( chm_ind ) xhtml_para ( chm_ind , section - > para - > words ) ;
2003-04-04 14:43:36 +00:00
}
fprintf ( fp , " </a></li> \n " ) ;
2003-11-03 09:10:19 +00:00
if ( chm_toc ) fprintf ( chm_toc , " \" ></OBJECT></li> \n " ) ;
if ( chm_ind ) fprintf ( chm_ind , " \" ></OBJECT></li> \n " ) ;
2003-04-04 14:43:36 +00:00
return TRUE ;
2002-11-01 18:22:40 +00:00
}
/*
* Write all the sections in this file . Do all paragraphs in this section , then all
* children ( recursively ) , then go on to the next one ( tail recursively ) .
*/
2002-11-01 21:52:36 +00:00
static void xhtml_do_sections ( FILE * fp , xhtmlsection * sections )
2002-11-01 18:22:40 +00:00
{
2003-04-04 14:43:36 +00:00
while ( sections )
{
currentsection = sections ;
xhtml_do_paras ( fp , sections - > para ) ;
xhtml_do_sections ( fp , sections - > child ) ;
sections = sections - > next ;
}
2002-11-01 18:22:40 +00:00
}
/* Write this list of paragraphs. Close off all lists at the end. */
2002-11-01 21:52:36 +00:00
static void xhtml_do_paras ( FILE * fp , paragraph * p )
2002-11-01 18:22:40 +00:00
{
2003-04-04 14:43:36 +00:00
int last_type = - 1 , first = TRUE ;
if ( ! p )
return ;
2002-11-01 18:22:40 +00:00
/* for (; p && (xhtml_para_level(p)>limit || xhtml_para_level(p)==-1 || first); p=p->next) {*/
2003-04-04 14:43:36 +00:00
for ( ; p & & ( xhtml_para_level ( p ) = = - 1 | | first ) ; p = p - > next )
{
first = FALSE ;
switch ( p - > type )
{
/*
* Things we ignore because we ' ve already processed them or
* aren ' t going to touch them in this pass .
*/
case para_IM :
case para_BR :
case para_Biblio : /* only touch BiblioCited */
case para_VersionID :
case para_Copyright :
case para_Preamble :
case para_NoCite :
case para_Title :
break ;
/*
* Chapter titles .
*/
case para_Chapter :
case para_Appendix :
case para_UnnumberedChapter :
xhtml_heading ( fp , p ) ;
break ;
case para_Heading :
case para_Subsect :
xhtml_heading ( fp , p ) ;
break ;
case para_Rule :
2021-09-11 22:57:27 +00:00
fprintf ( fp , " \n %s \n " , gettagtxt_hr ( ) ) ;
2003-04-04 14:43:36 +00:00
break ;
case para_Normal :
fprintf ( fp , " \n <p> " ) ;
xhtml_para ( fp , p - > words ) ;
fprintf ( fp , " </p> \n " ) ;
break ;
case para_Bullet :
case para_NumberedList :
case para_BiblioCited :
if ( last_type ! = p - > type )
{
/* start up list if necessary */
if ( p - > type = = para_Bullet )
{
fprintf ( fp , " <ul> \n " ) ;
} else if ( p - > type = = para_NumberedList )
{
fprintf ( fp , " <ol> \n " ) ;
} else if ( p - > type = = para_BiblioCited )
{
fprintf ( fp , " <dl> \n " ) ;
}
}
if ( p - > type = = para_Bullet | | p - > type = = para_NumberedList )
fprintf ( fp , " <li> " ) ;
else if ( p - > type = = para_BiblioCited )
{
fprintf ( fp , " <dt> " ) ;
xhtml_para ( fp , p - > kwtext ) ;
fprintf ( fp , " </dt> \n <dd> " ) ;
}
xhtml_para ( fp , p - > words ) ;
if ( p - > type = = para_BiblioCited )
{
fprintf ( fp , " </dd> \n " ) ;
} else if ( p - > type = = para_Bullet | | p - > type = = para_NumberedList )
{
fprintf ( fp , " </li> " ) ;
}
if ( p - > type = = para_Bullet | | p - > type = = para_NumberedList
| | p - > type = = para_BiblioCited )
/* close off list if necessary */
{
paragraph * p2 = p - > next ;
int close_off = FALSE ;
2002-11-01 18:22:40 +00:00
/* if (p2 && (xhtml_para_level(p2)>limit || xhtml_para_level(p2)==-1)) {*/
2003-04-04 14:43:36 +00:00
if ( p2 & & xhtml_para_level ( p2 ) = = - 1 )
{
if ( p2 - > type ! = p - > type )
close_off = TRUE ;
} else
{
close_off = TRUE ;
}
if ( close_off )
{
if ( p - > type = = para_Bullet )
{
fprintf ( fp , " </ul> \n " ) ;
} else if ( p - > type = = para_NumberedList )
{
fprintf ( fp , " </ol> \n " ) ;
} else if ( p - > type = = para_BiblioCited )
{
fprintf ( fp , " </dl> \n " ) ;
}
}
}
break ;
case para_Code :
xhtml_codepara ( fp , p - > words ) ;
break ;
2002-11-01 18:22:40 +00:00
}
2003-04-04 14:43:36 +00:00
last_type = p - > type ;
}
2002-11-01 18:22:40 +00:00
}
2021-09-11 22:57:27 +00:00
static void printoptstr ( FILE * fp , const char * prefix , const wchar_t * str , const char * suffix )
{
if ( str )
{
fprintf ( fp , " %s%ls%s " , prefix ? prefix : " " , str , suffix ? suffix : " " ) ;
}
}
2002-11-01 18:22:40 +00:00
/*
* Output a header for this XHTML file .
*/
2002-11-01 21:52:36 +00:00
static void xhtml_doheader ( FILE * fp , word * title )
2002-11-01 18:22:40 +00:00
{
2021-09-11 22:57:27 +00:00
const int xhtml = is_xhtml ( ) , html5 = is_html5 ( ) ;
const char * xhtmldoctype = " <!DOCTYPE html PUBLIC \" -//W3C//DTD XHTML 1.0 Transitional//EN \" \" http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd \" > \n " ;
2021-09-13 23:21:37 +00:00
const char * html4doctype = " <!DOCTYPE HTML PUBLIC \" -//W3C//DTD HTML 4.01 Transitional//EN \" \" http://www.w3.org/TR/html4/loose.dtd \" > \n " ;
const char * xhtmlxmlns = xhtml ? " xmlns= \" http://www.w3.org/1999/xhtml \" " : 0 ;
2021-09-11 22:57:27 +00:00
const char * voidend = xhtml ? " / " : " " ;
const wchar_t * tmpwstr ;
2021-09-13 23:21:37 +00:00
const ustr_slist * pussl ;
2021-09-11 22:57:27 +00:00
if ( xhtml & & html5 ) fatal ( err_whatever , " indeterminate format " ) ;
fprintf ( fp , html5 ? " <!DOCTYPE html> \n " : xhtml ? xhtmldoctype : html4doctype ) ;
2021-09-13 23:21:37 +00:00
fprintf ( fp , " <html%s " , xhtml ? xhtmlxmlns : " " ) ;
2021-09-11 22:57:27 +00:00
//www.w3.org/International/questions/qa-html-language-declarations
if ( * ( tmpwstr = ustrdef ( conf . html_lang , L " " ) ) )
fprintf ( fp , " %s%ls%s lang= \" %ls \" " , xhtml ? " xml:lang= \" " : " " , xhtml ? tmpwstr : L " " , xhtml ? " \" " : " " , tmpwstr ) ;
fprintf ( fp , " ><head> \n " ) ;
if ( ustricmp ( L " none " , ( tmpwstr = ustrdef ( conf . meta_charset , L " UTF-8 " ) ) ) )
fprintf ( fp , ( xhtml | | ! html5 ) ? " <meta http-equiv= \" Content-Type \" content= \" text/html; charset=%ls \" %s> " : " <meta charset= \" %ls \" > \n " , tmpwstr , voidend ) ;
printoptstr ( fp , " " , conf . head_start , " \n " ) ;
2021-09-13 23:21:37 +00:00
fprintf ( fp , " <title> " ) ;
2003-04-04 14:43:36 +00:00
if ( title = = NULL )
fprintf ( fp , " Documentation " ) ;
else
xhtml_para ( fp , title ) ;
fprintf ( fp , " </title> \n " ) ;
2021-09-13 23:21:37 +00:00
for ( pussl = conf . meta_append ; pussl ; pussl = pussl - > next )
fprintf ( fp , " <meta %ls%s> " , pussl - > string , voidend ) ;
2021-09-11 22:57:27 +00:00
printoptstr ( fp , " " , conf . head_middle , " \n " ) ;
fprintf ( fp , " <meta name= \" generator \" content= \" Halibut %s xhtml-backend \" %s> \n " , version , voidend ) ;
2003-04-04 14:43:36 +00:00
if ( conf . author )
2021-09-11 22:57:27 +00:00
fprintf ( fp , " <meta name= \" author \" content= \" %ls \" %s> \n " , conf . author , voidend ) ;
2003-04-04 14:43:36 +00:00
if ( conf . description )
2021-09-11 22:57:27 +00:00
fprintf ( fp , " <meta name= \" description \" content= \" %ls \" %s> \n " , conf . description , voidend ) ;
printoptstr ( fp , " " , conf . head_end , " \n " ) ;
fprintf ( fp , " </head> \n " ) ;
fprintf ( fp , " %ls \n " , conf . body ? conf . body : L " <body> " ) ;
2003-04-04 14:43:36 +00:00
if ( conf . body_start )
fprintf ( fp , " %ls \n " , conf . body_start ) ;
2002-11-01 18:22:40 +00:00
}
2003-11-03 09:10:19 +00:00
static void chm_doheader ( FILE * fp , word * title )
{
fprintf ( fp , " <HTML><BODY><UL><LI><OBJECT type= \" text/sitemap \" ><param name= \" Name \" value= \" " ) ;
xhtml_para ( fp , title ) ;
fprintf ( fp , " \" ><param name= \" Local \" value= \" Contents.html \" ></OBJECT></li> \n " ) ;
}
2002-11-01 18:22:40 +00:00
/*
* Output a footer for this XHTML file .
*/
2002-11-01 21:52:36 +00:00
static void xhtml_dofooter ( FILE * fp )
2002-11-01 18:22:40 +00:00
{
2021-09-13 23:21:37 +00:00
int hr = conf . body_end | | ! conf . suppress_address ;
if ( hr )
fprintf ( fp , " \n %s \n \n " , gettagtxt_hr ( ) ) ;
2003-04-04 14:43:36 +00:00
if ( conf . body_end )
fprintf ( fp , " %ls \n " , conf . body_end ) ;
if ( ! conf . suppress_address )
{
fprintf ( fp , " <address> \n " ) ;
if ( conf . address_start )
fprintf ( fp , " %ls \n " , conf . address_start ) ;
/* Do the version ID */
if ( conf . include_version_id )
{
paragraph * p ;
int started = 0 ;
for ( p = sourceparas ; p ; p = p - > next )
if ( p - > type = = para_VersionID )
{
xhtml_versionid ( fp , p - > words , started ) ;
started = 1 ;
}
2002-11-01 18:22:40 +00:00
}
2003-04-04 14:43:36 +00:00
if ( conf . address_end )
fprintf ( fp , " %ls \n " , conf . address_end ) ;
fprintf ( fp , " </address> \n " ) ;
}
2021-09-13 23:21:37 +00:00
fprintf ( fp , " </body></html> \n " ) ;
2002-11-01 18:22:40 +00:00
}
2003-11-03 09:10:19 +00:00
static void chm_dofooter ( FILE * fp )
{
fprintf ( fp , " </ul></BODY></HTML> \n " ) ;
}
2002-11-01 18:22:40 +00:00
/*
* Output the versionid paragraph . Typically this is a version control
* ID string ( such as $ Id . . . $ in RCS ) .
*/
2002-11-01 21:52:36 +00:00
static void xhtml_versionid ( FILE * fp , word * text , int started )
2002-11-01 18:22:40 +00:00
{
2003-04-04 14:43:36 +00:00
rdstringc t = { 0 , 0 , NULL } ;
2002-11-01 18:22:40 +00:00
2003-04-04 14:43:36 +00:00
rdaddc ( & t , ' [ ' ) ; /* FIXME: configurability */
xhtml_rdaddwc ( & t , text , NULL ) ;
rdaddc ( & t , ' ] ' ) ; /* FIXME: configurability */
2002-11-01 18:22:40 +00:00
2003-04-04 14:43:36 +00:00
if ( started )
2021-09-11 22:57:27 +00:00
fprintf ( fp , " %s \n " , gettagtxt_br ( ) ) ;
2003-04-04 14:43:36 +00:00
fprintf ( fp , " %s \n " , t . text ) ;
sfree ( t . text ) ;
2002-11-01 18:22:40 +00:00
}
/* Is this an XHTML reserved character? */
2002-11-01 21:52:36 +00:00
static int xhtml_reservedchar ( int c )
2002-11-01 18:22:40 +00:00
{
2003-04-04 14:43:36 +00:00
if ( c = = ' & ' | | c = = ' < ' | | c = = ' > ' | | c = = ' " ' )
return TRUE ;
else
return FALSE ;
2002-11-01 18:22:40 +00:00
}
/*
* Convert a wide string into valid XHTML : Anything outside ASCII will
* be fixed up as an entity . Currently we don ' t worry about constraining the
* encoded character set , which we should probably do at some point ( we can
* still fix up and return FALSE - see the last comment here ) . We also don ' t
* currently
*
* Because this is only used for words , spaces are HARD spaces ( any other
* spaces will be word_Whitespace not word_Normal ) . So they become & nbsp ;
* Unless hard_spaces is FALSE , of course ( code paragraphs break the above
* rule ) .
*
* If ` result ' is non - NULL , mallocs the resulting string and stores a pointer to
* it in ` * result ' . If ` result ' is NULL , merely checks whether all
* characters in the string are feasible .
*
* Return is nonzero if all characters are OK . If not all
* characters are OK but ` result ' is non - NULL , a result _will_
* still be generated !
*/
2002-11-01 21:52:36 +00:00
static int xhtml_convert ( wchar_t * s , char * * result , int hard_spaces )
2002-11-01 18:22:40 +00:00
{
2003-04-04 14:43:36 +00:00
int doing = ( result ! = 0 ) ;
int ok = TRUE ;
char * p = NULL ;
int plen = 0 , psize = 0 ;
2002-11-01 18:22:40 +00:00
2003-04-04 14:43:36 +00:00
for ( ; * s ; s + + )
{
wchar_t c = * s ;
2002-11-01 18:22:40 +00:00
# define ensure_size(i) if (i>=psize) { psize = i+256; p = resize(p, psize); }
2003-04-04 14:43:36 +00:00
if ( ( ( c = = 32 & & ! hard_spaces )
| | ( c > 32 & & c < = 126 & & ! xhtml_reservedchar ( c ) ) ) )
{
/* Char is OK. */
if ( doing )
{
ensure_size ( plen ) ;
p [ plen + + ] = ( char ) c ;
}
} else
{
/* Char needs fixing up. */
/* ok = FALSE; -- currently we never return FALSE; we
* might want to when considering a character set for the
* encoded document .
*/
if ( doing )
{
if ( c = = 32 )
{ /* a space in a word is a hard space */
ensure_size ( plen + 7 ) ; /* includes space for the NUL, which is subsequently stomped on */
sprintf ( p + plen , " " ) ;
plen + = 6 ;
} else
{
switch ( c )
{
case ' & ' :
ensure_size ( plen + 6 ) ; /* includes space for the NUL, which is subsequently stomped on */
plen + = sprintf ( p + plen , " & " ) ;
break ;
case ' " ' :
ensure_size ( plen + 7 ) ; /* includes space for the NUL, which is subsequently stomped on */
plen + = sprintf ( p + plen , " " " ) ;
break ;
case ' < ' :
if ( plen > 1 & & * ( s - 1 ) = = ' \\ ' & & * ( s - 2 ) = = ' \\ ' )
{
ensure_size ( - - plen ) ;
p [ plen - 1 ] = ( char ) c ;
p [ plen ] = 0 ;
} else
{
ensure_size ( plen + 5 ) ; /* includes space for the NUL, which is subsequently stomped on */
plen + = sprintf ( p + plen , " < " ) ;
}
break ;
case ' > ' :
if ( plen > 1 & & * ( s - 1 ) = = ' \\ ' & & * ( s - 2 ) = = ' \\ ' )
{
ensure_size ( - - plen ) ;
p [ plen - 1 ] = ( char ) c ;
p [ plen ] = 0 ;
} else
{
ensure_size ( plen + 5 ) ; /* includes space for the NUL, which is subsequently stomped on */
plen + = sprintf ( p + plen , " > " ) ;
}
break ;
default :
ensure_size ( plen + 8 ) ; /* includes space for the NUL, which is subsequently stomped on */
plen + = sprintf ( p + plen , " &#%04i; " , ( int ) c ) ;
break ;
}
}
}
2002-11-01 18:22:40 +00:00
}
2003-04-04 14:43:36 +00:00
}
if ( doing )
{
p = resize ( p , plen + 1 ) ;
p [ plen ] = ' \0 ' ;
* result = p ;
}
2002-11-01 18:22:40 +00:00
2003-04-04 14:43:36 +00:00
return ok ;
2002-11-01 18:22:40 +00:00
}
/*
* This formats the given words as XHTML .
*/
2002-11-01 21:52:36 +00:00
static void xhtml_rdaddwc ( rdstringc * rs , word * text , word * end )
2002-11-01 18:22:40 +00:00
{
2003-04-04 14:43:36 +00:00
char * c ;
keyword * kwl ;
xhtmlsection * sect ;
indextag * itag ;
int ti ;
2003-11-03 09:10:19 +00:00
wchar_t * s ;
2003-04-04 14:43:36 +00:00
for ( ; text & & text ! = end ; text = text - > next )
{
switch ( text - > type )
{
case word_HyperLink :
xhtml_utostr ( text - > text , & c ) ;
rdaddsc ( rs , " <a href= \" " ) ;
2003-11-03 09:10:19 +00:00
if ( chm_toc & & * c = = ' . ' & & * ( c + 1 ) = = ' . ' )
rdaddsc ( rs , c + 1 ) ;
else
2021-09-11 22:57:27 +00:00
rdaddsc ( rs , c ) ;
2003-11-03 09:10:19 +00:00
rdaddsc ( rs , " \" > " ) ;
sfree ( c ) ;
break ;
case word_LocalHyperLink :
xhtml_utostr ( text - > text , & c ) ;
rdaddsc ( rs , " <a href= \" " ) ;
if ( conf . rlink_prefix )
{
char * c2 ;
xhtml_utostr ( conf . rlink_prefix , & c2 ) ;
rdaddsc ( rs , c2 ) ;
sfree ( c2 ) ;
}
2021-09-11 22:57:27 +00:00
rdaddsc ( rs , c ) ;
2003-11-03 09:10:19 +00:00
if ( conf . rlink_suffix )
{
char * c2 ;
xhtml_utostr ( conf . rlink_suffix , & c2 ) ;
rdaddsc ( rs , c2 ) ;
sfree ( c2 ) ;
}
2003-04-04 14:43:36 +00:00
rdaddsc ( rs , " \" > " ) ;
sfree ( c ) ;
break ;
case word_UpperXref :
case word_LowerXref :
case word_FreeTextXref :
kwl = kw_lookup ( keywords , text - > text ) ;
if ( kwl )
{
sect = xhtml_find_section ( kwl - > para ) ;
if ( sect )
{
2011-11-30 22:17:17 +00:00
char fragmentbuf [ NAMEDFRAGMENT_MAXLEN ] ;
2003-04-04 14:43:36 +00:00
rdaddsc ( rs , " <a href= \" " ) ;
2011-12-03 19:50:02 +00:00
rdaddsc ( rs , conf . leaf_level ? sect - > file - > filename : " " ) ;
2003-04-04 14:43:36 +00:00
rdaddc ( rs , ' # ' ) ;
2011-11-30 22:17:17 +00:00
rdaddsc ( rs , xhtml_get_fragmentname ( sect , fragmentbuf ) ) ;
2003-04-04 14:43:36 +00:00
rdaddsc ( rs , " \" > " ) ;
} else
{
rdaddsc ( rs ,
" <a href= \" Apologies.html \" ><!-- probably a bibliography cross reference --> " ) ;
error ( err_whatever ,
" Couldn't locate cross-reference! (Probably a bibliography entry.) " ) ;
}
} else
{
rdaddsc ( rs ,
" <a href= \" Apologies.html \" ><!-- unknown cross-reference --> " ) ;
error ( err_whatever ,
" Couldn't locate cross-reference! (Wasn't in source file.) " ) ;
}
break ;
case word_IndexRef : /* in theory we could make an index target here */
2002-11-01 18:22:40 +00:00
/* rdaddsc(rs, "<a name=\"idx-");
xhtml_utostr ( text - > text , & c ) ;
rdaddsc ( rs , c ) ;
sfree ( c ) ;
rdaddsc ( rs , " \" ></a> " ) ; */
2003-04-04 14:43:36 +00:00
/* what we _do_ need to do is to fix up the backend data
* for any indexentry this points to .
*/
for ( ti = 0 ;
( itag = ( indextag * ) index234 ( idx - > tags , ti ) ) ! = NULL ; ti + + )
{
/* FIXME: really ustricmp() and not ustrcmp()? */
if ( ustricmp ( itag - > name , text - > text ) = = 0 )
{
break ;
}
}
if ( itag ! = NULL )
{
if ( itag - > refs ! = NULL )
{
int i ;
for ( i = 0 ; i < itag - > nrefs ; i + + )
{
xhtmlindex * idx_ref ;
indexentry * ientry ;
ientry = itag - > refs [ i ] ;
if ( ientry - > backend_data = = NULL )
{
idx_ref = ( xhtmlindex * ) smalloc ( sizeof ( xhtmlindex ) ) ;
if ( idx_ref = = NULL )
fatal ( err_nomemory ) ;
idx_ref - > nsection = 0 ;
idx_ref - > size = 4 ;
idx_ref - > sections =
( xhtmlsection * * ) smalloc ( idx_ref - > size *
sizeof ( xhtmlsection * ) ) ;
if ( idx_ref - > sections = = NULL )
fatal ( err_nomemory ) ;
ientry - > backend_data = idx_ref ;
} else
{
idx_ref = ientry - > backend_data ;
if ( idx_ref - > nsection + 1 > idx_ref - > size )
{
int new_size = idx_ref - > size * 2 ;
idx_ref - > sections =
srealloc ( idx_ref - > sections ,
new_size * sizeof ( xhtmlsection ) ) ;
if ( idx_ref - > sections = = NULL )
{
fatal ( err_nomemory ) ;
}
idx_ref - > size = new_size ;
}
}
idx_ref - > sections [ idx_ref - > nsection + + ] = currentsection ;
2002-11-01 18:22:40 +00:00
#if 0
# endif
2003-04-04 14:43:36 +00:00
}
} else
{
fatal ( err_whatever , " Index tag had no entries! " ) ;
}
} else
{
fprintf ( stderr , " Looking for index entry '%ls' \n " , text - > text ) ;
fatal ( err_whatever ,
" Couldn't locate index entry! (Wasn't in index.) " ) ;
}
break ;
case word_HyperEnd :
case word_XrefEnd :
rdaddsc ( rs , " </a> " ) ;
break ;
case word_Normal :
case word_Emph :
case word_Code :
case word_WeakCode :
case word_WhiteSpace :
case word_EmphSpace :
case word_CodeSpace :
case word_WkCodeSpace :
case word_Quote :
case word_EmphQuote :
case word_CodeQuote :
case word_WkCodeQuote :
assert ( text - > type ! = word_CodeQuote & &
text - > type ! = word_WkCodeQuote ) ;
if ( towordstyle ( text - > type ) = = word_Emph & &
( attraux ( text - > aux ) = = attr_First | |
attraux ( text - > aux ) = = attr_Only ) )
rdaddsc ( rs , " <em> " ) ;
else if ( ( towordstyle ( text - > type ) = = word_Code
| | towordstyle ( text - > type ) = = word_WeakCode )
& & ( attraux ( text - > aux ) = = attr_First
| | attraux ( text - > aux ) = = attr_Only ) )
rdaddsc ( rs , " <code> " ) ;
if ( removeattr ( text - > type ) = = word_Normal )
{
static int dont_convert = 0 ;
if ( dont_convert )
{
char buf [ 2 ] = " " ;
dont_convert = 0 ;
2003-11-03 09:10:19 +00:00
s = text - > text ;
2003-04-04 14:43:36 +00:00
for ( ; * s ; s + + )
{
buf [ 0 ] = ( char ) * s ;
rdaddsc ( rs , buf ) ;
}
buf [ 0 ] = 0 ;
rdaddsc ( rs , buf ) ;
} else
{
if ( * text - > text = = ' \\ ' & & text - > next
& & text - > next - > text & & ( * text - > next - > text = = ' & '
| | * text - > next - > text = = ' < '
| | * text - > next - > text = = ' > '
| | * text - > next - > text = = ' " ' ) )
dont_convert = 1 ;
else
{
if ( xhtml_convert ( text - > text , & c , TRUE ) ) /* spaces in the word are hard */
rdaddsc ( rs , c ) ;
else
xhtml_rdaddwc ( rs , text - > alt , NULL ) ;
sfree ( c ) ;
}
}
} else if ( removeattr ( text - > type ) = = word_WhiteSpace )
{
rdaddc ( rs , ' ' ) ;
} else if ( removeattr ( text - > type ) = = word_Quote )
{
rdaddsc ( rs , " " " ) ;
}
if ( towordstyle ( text - > type ) = = word_Emph & &
( attraux ( text - > aux ) = = attr_Last | |
attraux ( text - > aux ) = = attr_Only ) )
rdaddsc ( rs , " </em> " ) ;
else if ( ( towordstyle ( text - > type ) = = word_Code
| | towordstyle ( text - > type ) = = word_WeakCode )
& & ( attraux ( text - > aux ) = = attr_Last
| | attraux ( text - > aux ) = = attr_Only ) )
rdaddsc ( rs , " </code> " ) ;
break ;
2002-11-01 18:22:40 +00:00
}
2003-04-04 14:43:36 +00:00
}
2002-11-01 18:22:40 +00:00
}
/* Output a heading, formatted as XHTML.
*/
2002-11-01 21:52:36 +00:00
static void xhtml_heading ( FILE * fp , paragraph * p )
2002-11-01 18:22:40 +00:00
{
2003-04-04 14:43:36 +00:00
rdstringc t = { 0 , 0 , NULL } ;
word * tprefix = p - > kwtext ;
word * nprefix = p - > kwtext2 ;
word * text = p - > words ;
int level = xhtml_para_level ( p ) ;
xhtmlsection * sect = xhtml_find_section ( p ) ;
xhtmlheadfmt * fmt ;
2011-11-30 22:17:17 +00:00
char fragmentbuf [ NAMEDFRAGMENT_MAXLEN ] , * fragment ;
2003-04-04 14:43:36 +00:00
if ( sect )
{
2011-11-30 22:17:17 +00:00
fragment = xhtml_get_fragmentname ( sect , fragmentbuf ) ;
2003-04-04 14:43:36 +00:00
} else
{
2002-11-01 21:52:36 +00:00
if ( p - > type = = para_Title )
2003-04-04 14:43:36 +00:00
fragment = " title " ;
2002-11-01 21:52:36 +00:00
else
2003-04-04 14:43:36 +00:00
{
fragment = " " ; /* FIXME: what else can we do? */
error ( err_whatever , " Couldn't locate heading cross-reference! " ) ;
2002-11-01 18:22:40 +00:00
}
2003-04-04 14:43:36 +00:00
}
if ( p - > type = = para_Title )
fmt = NULL ;
else if ( level = = 1 )
fmt = & conf . fchapter ;
else if ( level - 1 < conf . nfsect )
fmt = & conf . fsect [ level - 1 ] ;
else
fmt = & conf . fsect [ conf . nfsect - 1 ] ;
if ( fmt & & fmt - > just_numbers & & nprefix )
{
xhtml_rdaddwc ( & t , nprefix , NULL ) ;
if ( fmt )
{
char * c ;
if ( xhtml_convert ( fmt - > number_suffix , & c , FALSE ) )
{
rdaddsc ( & t , c ) ;
sfree ( c ) ;
}
}
} else if ( fmt & & ! fmt - > just_numbers & & tprefix )
{
xhtml_rdaddwc ( & t , tprefix , NULL ) ;
if ( fmt )
{
char * c ;
if ( xhtml_convert ( fmt - > number_suffix , & c , FALSE ) )
{
rdaddsc ( & t , c ) ;
sfree ( c ) ;
}
}
}
xhtml_rdaddwc ( & t , text , NULL ) ;
/*
* If we ' re outputting in single - file mode , we need to lower
* the level of each heading by one , because the overall
* document title will be sitting right at the top as an < h1 >
* and so chapters and sections should start at < h2 > .
*
* Even if not , the document title will come back from
* xhtml_para_level ( ) as level zero , so we must increment that
* no matter what leaf_level is set to .
*/
if ( conf . leaf_level = = 0 | | level = = 0 )
level + + ;
fprintf ( fp , " <a name= \" %s \" ></a><h%i>%s</h%i> \n " , fragment , level ,
t . text , level ) ;
sfree ( t . text ) ;
2002-11-01 18:22:40 +00:00
}
/* Output a paragraph. Styles are handled by xhtml_rdaddwc().
* This looks pretty simple ; I may have missed something . . .
*/
2002-11-01 21:52:36 +00:00
static void xhtml_para ( FILE * fp , word * text )
2002-11-01 18:22:40 +00:00
{
2003-04-04 14:43:36 +00:00
rdstringc out = { 0 , 0 , NULL } ;
xhtml_rdaddwc ( & out , text , NULL ) ;
fprintf ( fp , " %s " , out . text ) ;
sfree ( out . text ) ;
2002-11-01 18:22:40 +00:00
}
/* Output a code paragraph. I'm treating this as preformatted, which
* may not be entirely correct . See xhtml_para ( ) for my worries about
* this being overly - simple ; however I think that most of the complexity
* of the text backend came entirely out of word wrapping anyway .
*/
2002-11-01 21:52:36 +00:00
static void xhtml_codepara ( FILE * fp , word * text )
2002-11-01 18:22:40 +00:00
{
2003-04-04 14:43:36 +00:00
fprintf ( fp , " <pre> " ) ;
for ( ; text ; text = text - > next )
if ( text - > type = = word_WeakCode )
{
char * c ;
xhtml_convert ( text - > text , & c , FALSE ) ;
fprintf ( fp , " %s \n " , c ) ;
sfree ( c ) ;
}
fprintf ( fp , " </pre> \n " ) ;
2002-11-01 18:22:40 +00:00
}