/* 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/LaTeX_Generator * FUNCTION * Generator for LaTeX output. Supports singledoc mode. * ******* * TODO More documentation. */ #include #include #include #include #include "generator.h" #include "util.h" #include "links.h" #include "latex_generator.h" #include "globals.h" #include "robodoc.h" #ifdef DMALLOC #include #endif static int verbatim = FALSE; /****f* LaTeX_Generator/RB_LaTeX_Generate_String * FUNCTION * Write a string to the destination document, escaping * characters where necessary. ****** */ void RB_LaTeX_Generate_String( FILE *dest_doc, char *a_string ) { int i; int l = strlen( a_string ); unsigned char c; for ( i = 0; i < l; i++ ) { c = a_string[i]; RB_LaTeX_Generate_Char( dest_doc, c ); } } void RB_LaTeX_Generate_False_Link( FILE *dest_doc, char *name ) { RB_LaTeX_Generate_String( dest_doc, name ); } void RB_LaTeX_Generate_Item_Begin( FILE *dest_doc ) { USE( dest_doc ); /* Empty */ } void RB_LaTeX_Generate_Item_End( FILE *dest_doc ) { USE( dest_doc ); /* Empty */ } /* void */ /* RB_LaTeX_Generate_Item_Name( FILE* dest_doc, char *name ) */ /* { */ /* RB_LaTeX_Generate_String( dest_doc, name ); */ /* fprintf( dest_doc, "\n" ); */ /* } */ /* Lowtexx 21.09.2005 11:02 */ /* I think it looks better like this. This wastes less space in pdf-document. */ void RB_LaTeX_Generate_Item_Name( FILE *dest_doc, char *name ) { fprintf( dest_doc, "\\textbf{" ); RB_LaTeX_Generate_String( dest_doc, name ); // In alternate format, item names stand alone (Thuffir) if ( course_of_action.do_altlatex ) fprintf( dest_doc, "}\n" ); else fprintf( dest_doc, ":}\\hspace{0.08in}" ); } void RB_LaTeX_Generate_BeginSection( FILE *dest_doc, int depth, char *name, struct RB_header *header ) { int i; // Generate a new page for every section in alternate format if ( course_of_action.do_altlatex ) fprintf( dest_doc, "\\newpage\n" ); // If \part enabled, we have a level deeper // So enable the level '0' if ( course_of_action.do_latexparts ) depth--; switch ( depth ) { case 0: fprintf( dest_doc, "\\part{" ); break; case 1: fprintf( dest_doc, "\\section{" ); break; case 2: fprintf( dest_doc, "\\subsection{" ); break; case 3: fprintf( dest_doc, "\\subsubsection{" ); break; default: /* Too deep so just make it a subsubsection */ fprintf( dest_doc, "\\subsubsection{" ); } // Print Header "First" name RB_LaTeX_Generate_String( dest_doc, name ); // Print other names for ( i = 1; i < header->no_names; i++ ) { RB_LaTeX_Generate_String( dest_doc, ", " ); RB_LaTeX_Generate_String( dest_doc, header->names[i] ); } fprintf( dest_doc, "}\n" ); // Print Parent if any if ( header->parent ) { fprintf( dest_doc, "\\textsl{[ " ); RB_LaTeX_Generate_String( dest_doc, header->parent->function_name ); fprintf( dest_doc, " ]}\n" ); } // Print Header Type fprintf( dest_doc, "\\textsl{[ " ); RB_LaTeX_Generate_String( dest_doc, header->htype->indexName ); fprintf( dest_doc, " ]}\n\n" ); } void RB_LaTeX_Generate_EndSection( FILE *dest_doc, int depth, char *name ) { USE( dest_doc ); USE( depth ); USE( name ); /* Empty */ } char *RB_LaTeX_Get_Default_Extension( void ) { return ".tex"; } /****f* LaTeX_Generator/RB_LaTeX_Generate_Doc_Start * NAME * RB_LaTeX_Generate_Doc_Start -- ***** */ void RB_LaTeX_Generate_Doc_Start( FILE *dest_doc, char *src_name, char *name, char *charset ) { fprintf( dest_doc, "%% Document: %s\n", name ); fprintf( dest_doc, "%% Source: %s\n", src_name ); if ( course_of_action.do_nogenwith ) { } else { fprintf( dest_doc, "%% " COMMENT_ROBODOC ); /* Documentation is the users not ours fprintf( dest_doc, "%% " COMMENT_COPYRIGHT ); */ } if ( course_of_action.do_headless ) { /* The user wants a headless document, so we skip all * initialization. It is up to the user to put this in. */ } else { fprintf( dest_doc, "\\documentclass{article}\n" ); fprintf( dest_doc, "\\usepackage{makeidx}\n" ); fprintf( dest_doc, "\\usepackage{graphicx}\n" ); // Check if we have to use the inputenc package if ( charset ) { fprintf( dest_doc, "\\usepackage[%s]{inputenc}\n", charset ); } // Alternate mode, works better with pdflatex and DIN A4 sheets // At least for me :) (Thuffir) if ( course_of_action.do_altlatex ) { fprintf( dest_doc, "\\oddsidemargin 0 cm\n" ); fprintf( dest_doc, "\\evensidemargin 0 cm\n" ); fprintf( dest_doc, "\\topmargin 0 cm\n" ); fprintf( dest_doc, "\\textwidth 16 cm\n" ); fprintf( dest_doc, "\\textheight 22 cm\n" ); } else { /* I guess this is unecessarry (same definitions twice ?) fprintf( dest_doc, "\\oddsidemargin 0.15 in\n" ); fprintf( dest_doc, "\\evensidemargin 0.35 in\n" ); fprintf( dest_doc, "\\marginparwidth 1 in \n" ); */ fprintf( dest_doc, "\\oddsidemargin 0.25 in \n" ); fprintf( dest_doc, "\\evensidemargin 0.25 in\n" ); fprintf( dest_doc, "\\marginparwidth 0.75 in\n" ); fprintf( dest_doc, "\\textwidth 5.875 in\n" ); } fprintf( dest_doc, "\\setlength{\\parindent}{0in}\n" ); fprintf( dest_doc, "\\setlength{\\parskip}{.08in}\n\n" ); /* changed default header to use boldface (vs slant) */ fprintf( dest_doc, "\\pagestyle{headings}\n" ); // Set document title fprintf( dest_doc, "\\title{%s}\n", document_title ? document_title : DEFAULT_DOCTITILE ); if ( course_of_action.do_nogenwith ) { fprintf( dest_doc, "\\author{Documentation Generator}\n" ); } else { fprintf( dest_doc, "\\author{%s}\n", COMMENT_ROBODOC ); } fprintf( dest_doc, "\\makeindex\n" ); fprintf( dest_doc, "\\begin{document}\n" ); fprintf( dest_doc, "\\maketitle\n" ); // In alternate mode, we generate INDEX at the end of document if ( course_of_action.do_altlatex ) { fprintf( dest_doc, "\\newpage\n" ); } else { fprintf( dest_doc, "\\printindex\n" ); } /* autogenerate table of contents! */ fprintf( dest_doc, "\\tableofcontents\n" ); // We don't need this in alternate format, since every section begins // with a \newpage (Thuffir) if ( !( course_of_action.do_altlatex ) ) fprintf( dest_doc, "\\newpage\n" ); /* trick to disable the autogenerated \newpage */ fprintf( dest_doc, "\n" ); } } /****f* LaTeX_Generator/RB_LaTeX_Generate_Doc_End * NAME * RB_LaTeX_Generate_Doc_End -- ***** */ void RB_LaTeX_Generate_Doc_End( FILE *dest_doc, char *name ) { USE( name ); // In alternate mode, we generate INDEX at the end of document if ( course_of_action.do_altlatex ) { fprintf( dest_doc, "\\printindex\n" ); } if ( course_of_action.do_footless ) { /* The user does not want the foot of the * document */ } else { fprintf( dest_doc, "\\end{document}\n" ); } } /****f* LaTeX_Generator/RB_LaTeX_Generate_Index_Entry * FUNCTION * Creates a entry for the index. * ******* */ void RB_LaTeX_Generate_Index_Entry( FILE *dest_doc, struct RB_header *cur_header ) { assert( cur_header->function_name ); fprintf( dest_doc, "\\index{unsorted!" ); RB_LaTeX_Generate_String( dest_doc, cur_header->function_name ); if ( cur_header->is_internal ) { fprintf( dest_doc, "}\\index{internal\\_%s!", cur_header->htype->indexName ); } else { fprintf( dest_doc, "}\\index{%s!", cur_header->htype->indexName ); } RB_LaTeX_Generate_String( dest_doc, cur_header->function_name ); fprintf( dest_doc, "}\n" ); } /****f* LaTeX_Generator/RB_LaTeX_Generate_Header_Start * NAME * RB_LaTeX_Generate_Header_Start -- ***** */ void RB_LaTeX_Generate_Header_Start( FILE *dest_doc, struct RB_header *cur_header ) { fprintf( dest_doc, "\\subsection{" ); RB_LaTeX_Generate_String( dest_doc, cur_header->name ); fprintf( dest_doc, "}\n" ); } /****f* LaTeX_Generator/RB_LaTeX_Generate_Header_End * NAME * RB_LaTeX_Generate_Header_End -- ***** */ void RB_LaTeX_Generate_Header_End( FILE *dest_doc, struct RB_header *cur_header ) { USE( cur_header ); fputc( '\n', dest_doc ); } /*x**f* LaTeX_Generator/RB_LaTeX_Generate_Index * NAME * RB_LaTeX_Generate_Index -- ***** */ void RB_LaTeX_Generate_Index( FILE *dest, char *source ) { /* TODO REMOVE */ USE( dest ); USE( source ); assert( 0 ); #if 0 RB_Generate_Doc_Start( dest, source, "Master File", 0 ); RB_Generate_LaTeX_Includes( dest ); RB_Generate_Doc_End( dest, source ); #endif } /****f* LaTeX_Generator/RB_LaTeX_Generate_Index_Table * NAME * RB_LaTeX_Generate_Index_Table -- ***** */ void RB_LaTeX_Generate_Index_Table( FILE *dest, int type, char *title ) { USE( dest ); USE( type ); USE( title ); /* Empty */ } /****f* LaTeX_Generator/Generate_LaTeX_Includes * NAME * Generate_LaTeX_Includes -- generate include commands * SYNOPSIS * void RB_Generate_LaTeX_Includes (FILE *dest) * FUNCTION * Generates a series of \include commands to include the * documentation generated for each source file into one * big file. **** */ void RB_Generate_LaTeX_Includes( FILE *dest ) { USE( dest ); /* TODO REMOVE ?? */ #if 0 struct RB_link *cur_link; for ( cur_link = first_link; cur_link; cur_link = cur_link->next_link ) { { if ( cur_link->type == NO_HEADER ) fprintf( dest, "\\include{%s}\n", cur_link->label_name ); } } #endif } /****f* LaTeX_Generator/RB_LaTeX_Generate_Empty_Item * NAME * RB_LaTeX_Generate_Empty_Item -- ***** */ void RB_LaTeX_Generate_Empty_Item( FILE *dest_doc ) { fprintf( dest_doc, "\\\\\n" ); } /****f* LaTeX_Generator/RB_LaTeX_Generate_EscapedChar * FUNCTION * Generate a single character. These characters are outside * a begin{verbatim} end{verbatim} block. So we need to escape is * special characters. * These are * _ => \_ * % => \% * $ => \$ * < => \textless * > => \textgreater * \ => $\backslash$ * SYNOPSIS * void RB_LaTeX_Generate_EscapedChar( FILE* dest_doc, int c ) * SEE ALSO * RB_LaTeX_Generate_Char() ***** */ void RB_LaTeX_Generate_EscapedChar( FILE *dest_doc, int c ) { switch ( c ) { case '&': case '~': case '_': case '%': case '^': case '{': case '}': case '$': case '#': fputc( '\\', dest_doc ); fputc( c, dest_doc ); break; /* lowtexx 21.09.2005 11:12 */ /* Replace these characters by the correct latex-code */ case '\\': fprintf( dest_doc, "$\\backslash$" ); break; case '<': fprintf( dest_doc, "\\textless " ); break; case '>': fprintf( dest_doc, "\\textgreater " ); break; /* --- */ default: fputc( c, dest_doc ); break; } } /****f* LaTeX_Generator/RB_LaTeX_Generate_Char * FUNCTION * Generate a single character. These characters are generated * within a begin{verbatim} end{verbatim} block So no escaping is * necessary. * SYNOPSIS * void RB_LaTeX_Generate_Char( FILE* dest_doc, int c ) ***** */ void RB_LaTeX_Generate_Char( FILE *dest_doc, int c ) { if ( verbatim ) { switch ( c ) { case '\n': assert( 0 ); break; case '\t': assert( 0 ); break; default: fputc( c, dest_doc ); } } else { RB_LaTeX_Generate_EscapedChar( dest_doc, c ); } } void LaTeX_Generate_Begin_Paragraph( FILE *dest_doc ) { fprintf( dest_doc, "\n" ); } void LaTeX_Generate_End_Paragraph( FILE *dest_doc ) { fprintf( dest_doc, "\n" ); } void LaTeX_Generate_Begin_Preformatted( FILE *dest_doc ) { fprintf( dest_doc, "\\begin{verbatim}\n" ); verbatim = TRUE; } void LaTeX_Generate_End_Preformatted( FILE *dest_doc ) { verbatim = FALSE; fprintf( dest_doc, "\\end{verbatim}\n" ); } void LaTeX_Generate_Begin_List( FILE *dest_doc ) { fprintf( dest_doc, "\\begin{itemize}\n" ); } void LaTeX_Generate_End_List( FILE *dest_doc ) { fprintf( dest_doc, "\\end{itemize}\n" ); } void LaTeX_Generate_Begin_List_Item( FILE *dest_doc ) { fprintf( dest_doc, " \\item " ); } void LaTeX_Generate_End_List_Item( FILE *dest_doc ) { USE( dest_doc ); // fprintf( dest_doc, "" ); } /* lowtexx 21.09.2005 11:23 */ /* added some functions to create links in latex documents */ /****f* LaTeX_Generator/RB_LaTeX_Generate_Label * NAME * RB_LaTeX_Generate_Label -- * SYNOPSIS * void RB_LaTeX_Generate_Label( FILE* dest_doc, char* name) * INPUTS * dest_doc -- the file to which the text is written * name -- the unique name of the label to create * SOURCE */ void RB_LaTeX_Generate_Label( FILE *dest_doc, char *name ) { int i; int l = strlen( name ); unsigned char c; fprintf( dest_doc, "\\label{ch:" ); for ( i = 0; i < l; ++i ) { c = name[i]; if ( utf8_isalnum( c ) ) { RB_LaTeX_Generate_Char( dest_doc, c ); } else { // think about this // replaced by underscore fputc( '_', dest_doc ); } } fprintf( dest_doc, "}\n" ); } /******/ /****f* LaTeX_Generator/RB_LaTeX_Generate_Link * NAME * RB_LaTeX_Generate_Link -- * SYNOPSIS * void RB_LaTeX_Generate_Link( FILE *cur_doc, char *cur_name, * char *filename, char *labelname, * char *linkname ) * INPUTS * cur_doc -- the file to which the text is written * cur_name -- the name of the destination file (unused) * (the file from which we link) * filename -- the name of the file that contains the link * (the file we link to) (unused) * labelname-- the name of the unique label of the link. * linkname -- the name of the link as shown to the user (unused). * SOURCE */ void RB_LaTeX_Generate_Link( FILE *cur_doc, char *cur_name, char *filename, char *labelname, char *linkname ) { USE( cur_name ); USE( filename ); USE( linkname ); // Only generate links outside the verbatim sections // LaTeX does not seem to recognise them inside (Thuffir) if ( verbatim == FALSE ) fprintf( cur_doc, " (\\ref{ch:%s})", labelname ); } /******/