/*
Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen,
Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner,
Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai.
This file is part of ROBODoc
ROBODoc is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
/****h* ROBODoc/HTML_Generator
* FUNCTION
* The generator for HTML output.
*
* The generator supports sections upto 7 levels deep. It supports
* a Table of Contents based on all headers. A masterindex for
* all headertypes and seperate masterindexes for each headertype.
*
* MODIFICATION HISTORY
* 2003-02-03 Frans Slothouber Refactoring
* ????-??-?? Frans Slothouber V1.0
*******
* $Id: html_generator.c,v 1.91 2007/07/10 19:13:51 gumpu Exp $
*/
#include
#include
#include
#include
#include
#include "html_generator.h"
#include "util.h"
#include "globals.h"
#include "robodoc.h"
#include "links.h"
#include "headers.h"
#include "headertypes.h"
#include "generator.h"
#include "items.h"
#include "string.h"
#include "document.h"
#include "directory.h"
#include "path.h"
#include "part.h"
#include "roboconfig.h"
#ifdef DMALLOC
#include
#endif
static char *css_name = NULL;
static int in_linecomment = 0; // are we in a line comment?
static void RB_HTML_Generate_String(
FILE *dest_doc,
const char *a_string );
/* TODO Documentation */
static void HTML_Generate_Div(
FILE *dest_doc,
char *id )
{
fprintf( dest_doc, "
\n", id );
}
/* TODO Documentation */
static void HTML_Generate_Div_End(
FILE *dest_doc,
char *id )
{
fprintf( dest_doc, "
\n" );
}
/* TODO Documentation */
void RB_HTML_Generate_Source_Tree(
FILE *dest_doc,
char *dest_name,
struct RB_Document *document )
{
struct RB_Directory *srctree;
srctree = document->srctree;
RB_HTML_Generate_Source_Tree_Entry( dest_doc, dest_name, NULL, srctree,
document );
}
/****if* HTML_Generator/RB_HTML_Generate_String
* FUNCTION
* Write a string to the destination document, escaping
* characters where necessary.
* SYNOPSIS
*/
static void RB_HTML_Generate_String(
FILE *dest_doc,
const char *a_string )
/*
* INPUTS
* o dest_doc -- the file the characters are written too
* o a_string -- a nul terminated string.
* SEE ALSO
* RB_HTML_Generate_Char()
* SOURCE
*/
{
int i;
int l = strlen( a_string );
unsigned char c;
for ( i = 0; i < l; ++i )
{
c = a_string[i];
RB_HTML_Generate_Char( dest_doc, c );
}
}
/*******/
/****if* HTML_Generator/RB_HTML_Generate_False_Link
* FUNCTION
* Create a representation for a link that links an word in
* a header to the header itself.
* SYNOPSIS
*/
void RB_HTML_Generate_False_Link(
FILE *dest_doc,
char *name )
/*
* INPUTS
* * dest_doc -- the file the representation is written to.
* * name -- the word.
* SOURCE
*/
{
fprintf( dest_doc, "" );
RB_HTML_Generate_String( dest_doc, name );
fprintf( dest_doc, "" );
}
/*******/
/****f* HTML_Generator/RB_HTML_Color_String
* FUNCTION
* Generates various colored strings
* SOURCE
*/
static void RB_HTML_Color_String(
FILE *dest_doc,
int open,
const char *class,
const char *string )
{
switch ( open )
{
// string, closing
case 0:
RB_HTML_Generate_String( dest_doc, string );
fprintf( dest_doc, "" );
break;
// opening, string
case 1:
fprintf( dest_doc, "", class );
RB_HTML_Generate_String( dest_doc, string );
break;
// opening, string, closing
case 2:
fprintf( dest_doc, "", class );
RB_HTML_Generate_String( dest_doc, string );
fprintf( dest_doc, "" );
break;
// opening, char, closing
case 3:
fprintf( dest_doc, "", class );
RB_HTML_Generate_Char( dest_doc, *string );
fprintf( dest_doc, "" );
break;
// Bug
default:
assert( 0 );
}
}
/*******/
/****f* HTML_Generator/RB_HTML_Generate_Line_Comment_End
* FUNCTION
* Check if a line comment is active and generate ending sequence for it.
* Should be called at the end of each SOURCE line.
* SYNOPSIS
*/
void RB_HTML_Generate_Line_Comment_End(
FILE *dest_doc )
{
// Check if we are in a line comment
if ( in_linecomment )
{
// and end the line comment
in_linecomment = 0;
RB_HTML_Color_String( dest_doc, in_linecomment, COMMENT_CLASS, "" );
}
}
/*******/
/****f* HTML_Generator/RB_HTML_Generate_Extra
* FUNCTION
* Do some additional processing to detect HTML extra's like
* file references and other kind of links for the documentation
* body of an item.
* SYNOPSIS
*/
int RB_HTML_Generate_Extra(
FILE *dest_doc,
enum ItemType item_type,
char *cur_char,
char prev_char )
/*
* INPUTS
* o dest_doc -- the file to write to.
* o item_type -- the kind of item the body belongs to.
* o cur_char -- pointer to a substring of the item's body
* o prev_char -- the character just before cur char (zero if none)
* RESULTS
* Number of characters produced.
* SOURCE
*/
{
char link[1024], *str;
int res = -1;
unsigned int i;
static int incomment = 0; /* are we in comment? */
static int quote = 0; /* double quote */
static int squote = 0; /* single quote */
// Reset comment and quote state machine if not source item
if ( !Works_Like_SourceItem( item_type ) )
{
quote = 0;
squote = 0;
incomment = 0;
in_linecomment = 0;
}
// else check for quotations and string literals
else if ( !( incomment || in_linecomment ) )
{
switch ( *cur_char )
{
// Check for quoted string literals ("string")
case '\"':
if ( !squote && course_of_action.do_quotes )
{
if ( prev_char != '\\' )
{
quote = !quote;
RB_HTML_Color_String( dest_doc, quote,
QUOTE_CLASS, "\"" );
return 0;
}
else if ( quote && *( ( char * ) ( cur_char - 2 ) ) == '\\' )
{
quote = !quote; /* case "... \\" */
RB_HTML_Color_String( dest_doc, quote,
QUOTE_CLASS, "\"" );
return 0;
}
}
break;
// Check for single quoted string literals ('string')
case '\'':
if ( !quote && course_of_action.do_squotes )
{
if ( prev_char != '\\' )
{
squote = !squote;
RB_HTML_Color_String( dest_doc, squote,
SQUOTE_CLASS, "\'" );
return 0;
}
else if ( squote && *( ( char * ) ( cur_char - 2 ) ) == '\\' )
{
squote = !squote; /* case '\\' */
RB_HTML_Color_String( dest_doc, squote,
SQUOTE_CLASS, "\'" );
return 0;
}
}
break;
default:
break;
}
}
// Recognise line comments
if ( Works_Like_SourceItem( item_type ) && !incomment && !quote
&& !squote && course_of_action.do_line_comments )
{
// check for line comment start
if ( !in_linecomment )
{
str =
Find_Parameter_Partial( &
( configuration.
source_line_comments ), cur_char );
if ( str )
{
in_linecomment = 1;
RB_HTML_Color_String( dest_doc, in_linecomment,
COMMENT_CLASS, str );
// We found it, so exit
return strlen( str ) - 1;
}
}
// The end of line comments are generated in
// RB_HTML_Generate_Line_Comment_End()
}
// Recognise block comments
if ( Works_Like_SourceItem( item_type ) && !in_linecomment && !quote
&& !squote && course_of_action.do_block_comments )
{
// Check for block comment start
if ( !incomment )
{
str =
Find_Parameter_Partial( &
( configuration.
remark_begin_markers ), cur_char );
if ( str )
{
incomment = 1;
RB_HTML_Color_String( dest_doc, incomment,
COMMENT_CLASS, str );
// We found it, so exit
return strlen( str ) - 1;
}
}
// Check for block comment end
else
{
str =
Find_Parameter_Partial( &( configuration.remark_end_markers ),
cur_char );
if ( str )
{
incomment = 0;
RB_HTML_Color_String( dest_doc, incomment,
COMMENT_CLASS, str );
// We found it, so exit
return strlen( str ) - 1;
}
}
}
// Do further source formating
if ( Works_Like_SourceItem( item_type ) &&
!in_linecomment && !incomment && !quote && !squote )
{
// Check for keywords
if ( configuration.keywords.number && course_of_action.do_keywords )
{
char *keyword;
// Check if we are at the beginning of a word
if ( !utf8_isalnum( prev_char ) && ( prev_char != '_' ) )
{
// Count word length
for ( i = 1; // A word should have at least one character...
utf8_isalnum( cur_char[i] ) || ( cur_char[i] == '_' );
i++ );
// Check if it is a keyword
if ( ( keyword = Find_Keyword( cur_char, i ) ) )
{
RB_HTML_Color_String( dest_doc, 2, KEYWORD_CLASS,
keyword );
// Exit function
return i - 1;
}
}
}
// Do some fancy coloration for non-alphanumeric chars
if ( !utf8_isalnum( *cur_char ) && *cur_char != '_'
&& *cur_char != ' ' && course_of_action.do_non_alpha )
{
RB_HTML_Color_String( dest_doc, 3, SIGN_CLASS, cur_char );
return 0;
}
}
// Check for links, etc...
if ( incomment || in_linecomment || !Works_Like_SourceItem( item_type ) )
{
if ( strncmp( "http://", cur_char, 7 ) == 0 )
{
sscanf( cur_char, "%s", link );
RB_Say( "found link %s\n", SAY_DEBUG, link );
res = ( strlen( link ) - 1 );
/* [ 697247 ] http://body. does not skip the '.' */
if ( link[( strlen( link ) - 1 )] == '.' )
{
link[( strlen( link ) - 1 )] = '\0';
fprintf( dest_doc, "%s.", link, link );
}
else
{
fprintf( dest_doc, "%s", link, link );
}
}
else if ( strncmp( "href:", cur_char, 5 ) == 0 )
{
/*
* handy in relative hyperlink paths, e.g.
* href:../../modulex/
*/
sscanf( ( cur_char + 5 ), "%s", link );
RB_Say( "found link %s\n", SAY_DEBUG, link );
res = ( strlen( link ) + 4 );
fprintf( dest_doc, "%s", link, link );
}
else if ( strncmp( "file:/", cur_char, strlen( "file:/" ) ) == 0 )
{
sscanf( cur_char, "%s", link );
RB_Say( "found link %s\n", SAY_DEBUG, link );
res = ( strlen( link ) - 1 );
fprintf( dest_doc, "%s", link, link );
}
else if ( strncmp( "mailto:", cur_char, 7 ) == 0 )
{
sscanf( ( cur_char + 7 ), "%s", link );
RB_Say( "found mail to %s\n", SAY_DEBUG, link );
res = ( strlen( link ) + 6 );
fprintf( dest_doc, "%s", link, link );
}
else if ( strncmp( "image:", cur_char, 6 ) == 0 )
{
sscanf( ( cur_char + 6 ), "%s", link );
RB_Say( "found image %s\n", SAY_DEBUG, link );
res = ( strlen( link ) + 5 );
fprintf( dest_doc, "", link );
}
}
return res;
}
/******/
void RB_HTML_Generate_Item_Name(
FILE *dest_doc,
char *name )
{
fprintf( dest_doc, "
" );
RB_HTML_Generate_String( dest_doc, name );
fprintf( dest_doc, "
\n" );
}
void RB_HTML_Generate_Item_Begin(
FILE *dest_doc,
char *name )
{
USE( dest_doc );
USE( name );
/* empty */
}
void RB_HTML_Generate_Item_End(
FILE *dest_doc,
char *name )
{
USE( dest_doc );
USE( name );
/* empty */
}
int sectiontoc_counters[MAX_SECTION_DEPTH];
/****f* HTML_Generator/RB_HTML_Generate_TOC_Section
* FUNCTION
* Create a table of contents based on the hierarchy of
* the headers starting for a particular point in this
* hierarchy (the parent).
* SYNOPSIS
*/
void RB_HTML_Generate_TOC_Section(
FILE *dest_doc,
char *dest_name,
struct RB_header *parent,
struct RB_header **headers,
int count,
int depth )
/*
* INPUTS
* o dest_doc -- the file to write to.
* o dest_name -- the name of this file.
* o parent -- the parent of the headers for which the the
* current level(depth) of TOC is created.
* o headers -- an array of headers for which the TOC is created
* o count -- the number of headers in this array
* o depth -- the current depth of the TOC
* NOTES
* This is a recursive function and tricky stuff.
* SOURCE
*/
{
struct RB_header *header;
int i, n, once = 0;
++sectiontoc_counters[depth];
for ( i = depth + 1; i < MAX_SECTION_DEPTH; ++i )
{
sectiontoc_counters[i] = 0;
}
// List item start
fprintf( dest_doc, "
" );
// Do not generate section numbers if sectionnameonly
if ( !( course_of_action.do_sectionnameonly ) )
{
for ( i = 1; i <= depth; ++i )
{
fprintf( dest_doc, "%d.", sectiontoc_counters[i] );
}
fprintf( dest_doc, " " );
}
// Generate Link to first reference name
RB_HTML_Generate_Link( dest_doc, dest_name, parent->file_name,
parent->unique_name,
// only generate function name if sectionnameonly
( course_of_action.do_sectionnameonly ) ?
parent->function_name : parent->name, 0 );
// Generate links to further reference names
for ( n = 1; n < parent->no_names; n++ )
{
RB_HTML_Generate_String( dest_doc, ", " );
RB_HTML_Generate_Link( dest_doc, dest_name, parent->file_name,
parent->unique_name, parent->names[n], 0 );
}
// List item end
fprintf( dest_doc, "
\n" );
for ( i = 0; i < count; ++i )
{
header = headers[i];
if ( header->parent == parent )
{
// Generate better TOC level hiearchy (Thuffir)
// We only generate
once for a level
if ( !once )
{
once = 1;
fprintf( dest_doc, "
\n" );
}
RB_HTML_Generate_TOC_Section( dest_doc, dest_name, header,
headers, count, depth + 1 );
}
else
{
/* Empty */
}
}
// If we have generated an
before, generate the closing one too.
if ( once )
fprintf( dest_doc, "
\n" );
}
void RB_HTML_Generate_TOC_2(
FILE *dest_doc,
struct RB_header **headers,
int count,
struct RB_Part *owner,
char *dest_name )
{
struct RB_header *header;
int i, j;
int depth = 1;
for ( i = 0; i < MAX_SECTION_DEPTH; ++i )
{
sectiontoc_counters[i] = 0;
}
fprintf( dest_doc, "
TABLE OF CONTENTS
\n" );
if ( course_of_action.do_sections )
{
/* --sections was specified, create a TOC based on the
* hierarchy of the headers.
*/
fprintf( dest_doc, "
\n" );
for ( i = 0; i < count; ++i )
{
header = headers[i];
if ( owner == NULL )
{
if ( header->parent )
{
/* Will be done in the subfunction */
}
else
{
RB_HTML_Generate_TOC_Section( dest_doc, dest_name, header,
headers, count, depth );
}
}
else
{
/* This is the TOC for a specific RB_Part (MultiDoc
* documentation). We only include the headers that
* are part of the subtree. That is, headers that are
* parth the RB_Part, or that are childern of the
* headers in the RB_Part.
*/
if ( header->owner == owner )
{
/* BUG 721690 */
/* Any of the parents of this header should not
* have the same owner as this header, otherwise
* this header will be part of the TOC multiple times.
*/
int no_bad_parent = TRUE;
struct RB_header *parent = header->parent;
for ( ; parent; parent = parent->parent )
{
if ( parent->owner == owner )
{
no_bad_parent = FALSE;
break;
}
}
if ( no_bad_parent )
{
RB_HTML_Generate_TOC_Section( dest_doc, dest_name,
header, headers, count,
depth );
}
}
}
}
fprintf( dest_doc, "
\n" );
}
else
{
/* No --section option, generate a plain, one-level
* TOC
*/
fprintf( dest_doc, "
\n" );
}
}
/****if* HTML_Generator/RB_HTML_Generate_Index_Shortcuts
* NAME
* RB_HTML_Generate_Index_Shortcuts
* FUNCTION
* Generates alphabetic shortcuts to index entries.
* SYNOPSIS
*/
static void RB_HTML_Generate_Index_Shortcuts(
FILE *dest )
/*
* INPUTS
* o dest -- the file to write to
* TODO
* - Only list used letters.
* - List all letters (accented, signs, etc), not just the common ones.
* - Should be better to implement it as a
\n" );
}
/********/
/****if* HTML_Generator/RB_HTML_Generate_Index_Table
* NAME
* RB_HTML_Generate_Index_Table --
* FUNCTION
* Create a HTML TABLE containing links to headers of a particular
* type. This creates two tables, a table for normal headers as
* well as one for internal headers.
* SYNOPSIS
*/
void RB_HTML_Generate_Index_Table(
FILE *dest,
char *dest_name,
struct RB_HeaderType *type,
char *title )
/*
* INPUTS
* o dest -- the file in which to write the table
* o dest_name -- the name of this file
* o type -- the type of header for which to generate
* the table
* o title -- the title of the table.
* SOURCE
*/
{
/* Compute the number of columns we need for
* this type of header.
*/
// Generate Index Title
fprintf( dest, "
" );
RB_HTML_Generate_String( dest, title );
fprintf( dest, "
\n" );
// Generate Shortcuts at the begining
RB_HTML_Generate_Index_Shortcuts( dest );
if ( RB_Number_Of_Links( type, NULL, FALSE ) )
{
if ( RB_Number_Of_Links( type, NULL, TRUE ) )
{
/* only print a title if there are two tables. */
fprintf( dest, "
Normal
" );
}
RB_HTML_Generate_Table_Body( dest, dest_name, type, FALSE );
}
if ( RB_Number_Of_Links( type, NULL, TRUE ) )
{
/* Always print the Internal title, since
* these headers are special and the user should know
* he is looking at something special.
*/
fprintf( dest, "
Internal
" );
RB_HTML_Generate_Table_Body( dest, dest_name, type, TRUE );
}
// Generate Shortcuts at the end
RB_HTML_Generate_Index_Shortcuts( dest );
}
/********/
/* TODO */
/*x**if* HTML_Generator/RB_HTML_Generate_Empty_Item
* NAME
* RB_HTML_Generate_Empty_Item --
******
*/
void RB_HTML_Generate_Empty_Item(
FILE *dest_doc )
{
fprintf( dest_doc, " \n" );
}
/****f* HTML_Generator/RB_HTML_Generate_Link
* NAME
* RB_HTML_Generate_Link --
* SYNOPSIS
*/
void RB_HTML_Generate_Link(
FILE *cur_doc,
char *cur_name,
char *filename,
char *labelname,
char *linkname,
char *classname )
/*
* INPUTS
* cur_doc -- the file to which the text is written
* cur_name -- the name of the destination file
* (the file from which we link)
* filename -- the name of the file that contains the link
* (the file we link to)
* labelname-- the name of the unique label of the link.
* linkname -- the name of the link as shown to the user.
* SOURCE
*/
{
if ( classname )
{
fprintf( cur_doc, "", r, labelname );
RB_HTML_Generate_String( cur_doc, linkname );
fprintf( cur_doc, "" );
}
else if (labelname)
{
fprintf( cur_doc, "href=\"#%s\">", labelname );
RB_HTML_Generate_String( cur_doc, linkname );
fprintf( cur_doc, "" );
}
else
{
fprintf( cur_doc, "href=\"%s\">", filename);
RB_HTML_Generate_String( cur_doc, linkname );
fprintf( cur_doc, "" );
}
}
/******/
/****f* HTML_Generator/RB_HTML_RelativeAddress
* FUNCTION
* Link to 'that' from 'this' computing the relative path. Here
* 'this' and 'that' are both paths. This function is used to
* create links from one document to another document that might be
* in a completely different directory.
* SYNOPSIS
*/
char *RB_HTML_RelativeAddress(
char *thisname,
char *thatname )
/*
* EXAMPLE
* The following two
* this /sub1/sub2/sub3/f.html
* that /sub1/sub2/g.html
* result in
* ../g.html
*
* this /sub1/f.html
* that /sub1/sub2/g.html
* ==
* ./sub2/g.html
*
* this /sub1/f.html
* that /sub1/g.html
* ==
* ./g.html
*
* this /sub1/doc3/doc1/tt.html
* that /sub1/doc5/doc2/qq.html
* ==
* ../../doc5/doc2/qq.html
*
* NOTES
* Notice the execelent docmentation.
* SOURCE
*/
#define MAX_RELATIVE_SIZE 1024
{
static char relative[MAX_RELATIVE_SIZE + 1];
char *i_this;
char *i_that;
char *i_this_slash = NULL;
char *i_that_slash = NULL;
relative[0] = '\0';
assert( thisname );
assert( thatname );
for ( i_this = thisname, i_that = thatname;
( *i_this && *i_that ) && ( *i_this == *i_that );
++i_this, ++i_that )
{
if ( *i_this == '/' )
{
i_this_slash = i_this;
}
if ( *i_that == '/' )
{
i_that_slash = i_that;
}
}
if ( i_this_slash && i_that_slash )
{
int this_slashes_left = 0;
int that_slashes_left = 0;
char *i_c;
for ( i_c = i_this_slash + 1; *i_c; ++i_c )
{
if ( *i_c == '/' )
{
++this_slashes_left;
}
}
for ( i_c = i_that_slash + 1; *i_c; ++i_c )
{
if ( *i_c == '/' )
{
++that_slashes_left;
}
}
if ( this_slashes_left )
{
int i;
for ( i = 0; i < this_slashes_left; ++i )
{
strcat( relative, "../" );
}
strcat( relative, i_that_slash + 1 );
}
else if ( that_slashes_left )
{
/* !this_slashes_left && that_slashes_left */
strcat( relative, "./" );
strcat( relative, i_that_slash + 1 );
}
else
{
/* !this_slashes_left && !that_slashes_left */
strcat( relative, "./" );
strcat( relative, i_that_slash + 1 );
}
}
return relative;
}
/******/
/****f* HTML_Generator/RB_HTML_Generate_Char
* NAME
* RB_HTML_Generate_Char -- generate a single character for an item.
* SYNOPSIS
*/
void RB_HTML_Generate_Char(
FILE *dest_doc,
int c )
/*
* FUNCTION
* This function is called for every character that goes
* into an item's body. This escapes all the reserved
* HTML characters such as '&', '<', '>', '"'.
* SOURCE
*/
{
switch ( c )
{
case '\n':
assert( 0 );
break;
case '\t':
assert( 0 );
break;
case '<':
fprintf( dest_doc, "<" );
break;
case '>':
fprintf( dest_doc, ">" );
break;
case '&':
fprintf( dest_doc, "&" );
break;
default:
// All others are printed literally
fputc( c, dest_doc );
}
}
/*******/
void HTML_Generate_Begin_Content(
FILE *dest_doc )
{
HTML_Generate_Div( dest_doc, "content" );
}
void HTML_Generate_End_Content(
FILE *dest_doc )
{
HTML_Generate_Div_End( dest_doc, "content" );
}
void HTML_Generate_Begin_Navigation(
FILE *dest_doc )
{
HTML_Generate_Div( dest_doc, "navigation" );
}
void HTML_Generate_End_Navigation(
FILE *dest_doc )
{
HTML_Generate_Div_End( dest_doc, "navigation" );
}
void HTML_Generate_Begin_Extra(
FILE *dest_doc )
{
HTML_Generate_Div( dest_doc, "extra" );
}
void HTML_Generate_End_Extra(
FILE *dest_doc )
{
HTML_Generate_Div_End( dest_doc, "extra" );
}
/****f* HTML_Generator/RB_Create_CSS
* FUNCTION
* Create the .css file. Unless the user specified it's own css
* file robodoc creates a default one.
*
* For multidoc mode the name of the .css file is
* robodoc.css
* For singledoc mode the name of the .css file is equal
* to the name of the documentation file.
* SYNOPSIS
*/
void RB_Create_CSS(
struct RB_Document *document )
/*
* INPUTS
* o document -- the document for which to create the file.
* SOURCE
*/
{
size_t l = 0;
FILE *css_file;
/* compute the complete path to the css file */
if ( ( document->actions.do_singledoc ) ||
( document->actions.do_singlefile ) )
{
char *extension = ".css";
l += strlen( document->singledoc_name );
l += strlen( extension );
++l;
css_name = malloc( l );
strcpy( css_name, document->singledoc_name );
strcat( css_name, extension );
}
else
{
struct RB_Path *docroot = document->docroot;
char *docrootname = docroot->name;
char *filename = "robodoc.css";
l = strlen( filename );
l += strlen( docrootname );
++l;
css_name = malloc( l );
strcpy( css_name, docrootname );
strcat( css_name, filename );
}
RB_Say( "Creating CSS file %s\n", SAY_DEBUG, css_name );
if ( document->css )
{
/* The user specified its own css file,
* so we use the content of that.
*/
RB_CopyFile( document->css, css_name );
}
else
{
css_file = fopen( css_name, "w" );
if ( css_file )
{
/** BEGIN BEGIN BEGIN Don't remove */
fprintf( css_file,
"/****h* ROBODoc/ROBODoc Cascading Style Sheet\n"
" * FUNCTION\n"
" * This is the default cascading style sheet for documentation\n"
" * generated with ROBODoc.\n"
" * You can edit this file to your own liking and then use\n"
" * it with the option\n"
" * --css \n"
" *\n"
" * This style-sheet defines the following layout\n"
" * +----------------------------------------+\n"
" * | logo |\n"
" * +----------------------------------------+\n"
" * | extra |\n"
" * +----------------------------------------+\n"
" * | | navi- |\n"
" * | | gation |\n"
" * | content | |\n"
" * | | |\n"
" * +----------------------------------------+\n"
" * | footer |\n"
" * +----------------------------------------+\n"
" *\n"
" * This style-sheet is based on a style-sheet that was automatically\n"
" * generated with the Strange Banana stylesheet generator.\n"
" * See http://www.strangebanana.com/generator.aspx\n"
" *\n"
" ******\n"
" * $Id: html_generator.c,v 1.91 2007/07/10 19:13:51 gumpu Exp $\n"
" */\n"
"\n"
"body\n"
"{\n"
" background-color: rgb(255,255,255);\n"
" color: rgb(98,84,55);\n"
" font-family: Arial, serif;\n"
" border-color: rgb(226,199,143);\n"
"}\n"
"\n"
"pre\n"
"{\n"
" font-family: monospace;\n"
" margin: 15px;\n"
" padding: 5px;\n"
" white-space: pre;\n"
" color: #000;\n"
"}\n"
"\n"
"pre.source\n"
"{\n"
" background-color: #ffe;\n"
" border: dashed #aa9 1px;\n"
"}\n"
"\n"
"p\n"
"{\n"
" margin:15px;\n"
"}\n"
"\n"
"p.item_name \n"
"{\n"
" font-weight: bolder;\n"
" margin:5px;\n"
" font-size: 120%%;\n"
"}\n"
"\n"
"#content\n" "{\n" " font-size: 100%%;\n" );
fprintf( css_file,
" color: rgb(0,0,0);\n"
" background-color: rgb(255,255,255);\n"
" border-left-width: 0px; \n"
" border-right-width: 0px; \n"
" border-top-width: 0px; \n"
" border-bottom-width: 0px;\n"
" border-left-style: none; \n"
" border-right-style: none; \n"
" border-top-style: none; \n"
" border-bottom-style: none;\n"
" padding: 40px 31px 14px 17px;\n"
" border-color: rgb(0,0,0);\n"
" text-align: justify;\n"
"}\n"
"\n"
"#navigation\n"
"{\n"
" background-color: rgb(98,84,55);\n"
" color: rgb(230,221,202);\n"
" font-family: \"Times New Roman\", serif;\n"
" font-style: normal;\n"
" border-color: rgb(0,0,0);\n"
"}\n"
"\n"
"a.menuitem\n"
"{\n"
" font-size: 120%%;\n"
" background-color: rgb(0,0,0);\n"
" color: rgb(195,165,100);\n"
" font-variant: normal;\n"
" text-transform: none;\n"
" font-weight: normal;\n"
" padding: 1px 8px 3px 1px;\n"
" margin-left: 5px; \n"
" margin-right: 5px; \n"
" margin-top: 5px; \n"
" margin-bottom: 5px;\n"
" border-color: rgb(159,126,57);\n"
" text-align: right;\n"
"}\n"
"\n"
"#logo, #logo a\n"
"{\n"
" font-size: 130%%;\n"
" background-color: rgb(198,178,135);\n"
" color: rgb(98,84,55);\n"
" font-family: Georgia, serif;\n"
" font-style: normal;\n"
" font-variant: normal;\n"
" text-transform: none;\n"
" font-weight: bold;\n"
" padding: 20px 18px 20px 18px;\n"
" border-color: rgb(255,255,255);\n"
" text-align: right;\n"
"}\n"
"\n"
"#extra, #extra a\n"
"{\n"
" font-size: 128%%;\n"
" background-color: rgb(0,0,0);\n"
" color: rgb(230,221,202);\n"
" font-style: normal;\n"
" font-variant: normal;\n"
" text-transform: none;\n"
" font-weight: normal;\n" );
fprintf( css_file,
" border-left-width: 0px; \n"
" border-right-width: 0px; \n"
" border-top-width: 0px; \n"
" border-bottom-width: 0px;\n"
" border-left-style: none; \n"
" border-right-style: none; \n"
" border-top-style: none; \n"
" border-bottom-style: none;\n"
" padding: 12px 12px 12px 12px;\n"
" border-color: rgb(195,165,100);\n"
" text-align: center;\n"
"}\n"
"\n"
"#content a\n"
"{\n"
" color: rgb(159,126,57);\n"
" text-decoration: none;\n"
"}\n"
"\n"
"#content a:hover, #content a:active\n"
"{\n"
" color: rgb(255,255,255);\n"
" background-color: rgb(159,126,57);\n"
"}\n"
"\n"
"a.indexitem\n"
"{\n"
" display: block;\n"
"}\n"
"\n"
"h1, h2, h3, h4, h5, h6\n"
"{\n"
" background-color: rgb(221,221,221);\n"
" font-family: Arial, serif;\n"
" font-style: normal;\n"
" font-variant: normal;\n"
" text-transform: none;\n"
" font-weight: normal;\n"
"}\n"
"\n"
"h1\n"
"{\n"
" font-size: 151%%;\n"
"}\n"
"\n"
"h2\n"
"{\n"
" font-size: 142%%;\n"
"}\n"
"\n"
"h3\n"
"{\n"
" font-size: 133%%;\n"
"}\n"
"\n"
"h4\n"
"{\n"
" font-size: 124%%;\n"
"}\n"
"\n"
"h5\n"
"{\n"
" font-size: 115%%;\n"
"}\n"
"\n"
"h6\n"
"{\n"
" font-size: 106%%;\n"
"}\n"
"\n"
"#navigation a\n"
"{\n"
" text-decoration: none;\n"
"}\n"
"\n"
".menuitem:hover\n"
"{\n"
" background-color: rgb(195,165,100);\n"
" color: rgb(0,0,0);\n"
"}\n"
"\n"
"#extra a\n"
"{\n"
" text-decoration: none;\n"
"}\n"
"\n"
"#logo a\n"
"{\n"
" text-decoration: none;\n"
"}\n"
"\n"
"#extra a:hover\n"
"{\n"
"}\n"
"\n"
"/* layout */\n"
"#navigation\n"
"{\n"
" width: 22%%; \n"
" position: relative; \n"
" top: 0; \n"
" right: 0; \n"
" float: right; \n"
" text-align: center;\n"
" margin-left: 10px;\n"
"}\n"
"\n"
".menuitem {width: auto;}\n"
"#content {width: auto;}\n"
".menuitem {display: block;}\n" "\n" "\n" );
fprintf( css_file,
"div#footer\n"
"{\n"
" background-color: rgb(198,178,135);\n"
" color: rgb(98,84,55);\n"
" clear: left;\n"
" width: 100%%;\n"
" font-size: 71%%;\n"
"}\n"
"\n"
"div#footer a\n"
"{\n"
" background-color: rgb(198,178,135);\n"
" color: rgb(98,84,55);\n"
"}\n"
"\n"
"div#footer p\n"
"{\n"
" margin:0;\n"
" padding:5px 10px\n"
"}\n"
"\n"
"span.keyword\n"
"{\n"
" color: #00F;\n"
"}\n"
"\n"
"span.comment\n"
"{\n"
" color: #080;\n"
"}\n"
"\n"
"span.quote\n"
"{\n"
" color: #F00;\n"
"}\n"
"\n"
"span.squote\n"
"{\n"
" color: #F0F;\n"
"}\n"
"\n"
"span.sign\n"
"{\n"
" color: #008B8B;\n"
"}\n"
"\n"
"\n"
"@media print\n"
"{\n"
" #navigation {display: none;}\n"
" #content {padding: 0px;}\n"
" #content a {text-decoration: underline;}\n"
"}\n" );
/** END END END Don't remove */
fclose( css_file );
}
else
{
RB_Panic( "Can't open %s for writing\n", css_name );
}
}
}
/*******/
void RB_InsertCSS(
FILE *dest_doc,
char *filename )
{
if ( css_name )
{
char *r = RB_HTML_RelativeAddress( filename, css_name );
assert( r );
assert( strlen( r ) );
fprintf( dest_doc,
"\n",
r );
}
}
void HTML_Generate_Begin_Paragraph(
FILE *dest_doc )
{
fprintf( dest_doc, "
\n" );
}
void HTML_Generate_Begin_Preformatted(
FILE *dest_doc,
int source )
{
// Check if we are preformatting a SOURCE item
if ( source )
{
// SOURCE items have their own class in the CSS
fprintf( dest_doc, "