#include #include #include #include #include "robodoc.h" #include "headers.h" #include "items.h" #include "folds.h" #include "util.h" #include "links.h" #include "generator.h" #include "analyser.h" /****f* ROBODoc/RB_Generate_Documentation [3.0h] * NAME * RB_Generate_Documentation * SYNOPSIS * RB_Generate_Documentation (dest_doc, name, name) * * RB_Generate_Documentation (FILE *, char *, char *) * FUNCTION * Generates the autodoc documentation from the list of * function headers that has been created by * RB_Analyse_Document. * INPUTS * dest_doc - Pointer to the file to which the output will be written. * src_name - The name of the source file. * dest_name - The name of this file. * BUGS * There might be plenty. * SEE ALSO * RB_Generate_Doc_Start, * RB_Generate_Doc_End, * RB_Generate_Header_Start, * RB_Generate_Header_End, * RB_Generate_Header_Name, * RB_Generate_Item_Name, * RB_Generate_Item_Doc, * RB_Generate_Item_Body . * SOURCE */ void RB_Generate_Documentation ( FILE * dest_doc, char *src_name, char *dest_name) { struct RB_header *cur_header; int expc = 0; char fname[256]; FILE *orig_doc = dest_doc; RB_Make_Index_Tables (); RB_Generate_Doc_Start (dest_doc, src_name, dest_name, 1); for (cur_header = first_header; cur_header; cur_header = cur_header->next_header) { int item_type; char *next_line, *item_line = NULL; RB_Say ("generating documentation for \"%s\"\n", cur_header->name); if (output_mode == HTML) { sprintf(fname, "%s_exp_%d.html", doc_base, expc++); dest_doc = fopen(fname, "w"); } RB_Generate_Header_Start (dest_doc, cur_header); next_line = cur_header->contents; item_type = RB_Find_Item (&next_line, &item_line); if (item_type != NO_ITEM) { int old_item_type; char *old_next_line; do { if (course_of_action & DO_TELL) printf ("[%s] ", item_names[item_type]); if (!((item_type == SOURCE_ITEM) && (course_of_action & DO_NOSOURCE))) RB_Generate_Item_Name (dest_doc, item_type); old_next_line = next_line; old_item_type = item_type; item_type = RB_Find_Item (&next_line, &item_line); if (!((old_item_type == SOURCE_ITEM) && (course_of_action & DO_NOSOURCE))) RB_Generate_Item_Doc (dest_doc, dest_name, old_next_line, item_line, cur_header->function_name, old_item_type); } while (item_type != NO_ITEM); if (course_of_action & DO_TELL) putchar ('\n'); } else printf ("%s: WARNING, header \"%s\" has no items\n", whoami, cur_header->name); RB_Generate_Header_End (dest_doc, cur_header); } dest_doc = orig_doc; RB_Generate_Doc_End (dest_doc, dest_name); } /***** RB_Generate_Documentation ***/ /****f* ROBODoc/RB_Generate_Doc_Start [3.0j] * NAME * RB_Generate_Doc_Start -- Generate document header. * SYNOPSIS * RB_Generate_Doc_Start (dest_doc, src_name, name, toc) * * RB_Generate_Doc_Start (FILE *, char *, char *, char) * FUNCTION * Generates for depending on the output_mode the text that * will be at the start of a document. * Including the table of contents. * INPUTS * dest_doc - pointer to the file to which the output will * be written. * src_name - the name of the source file. * name - the name of this file. * output_mode - global variable that indicates the output * mode. * toc - generate table of contens * SEE ALSO * RB_Generate_Doc_End * SOURCE */ void RB_Generate_Doc_Start ( FILE * dest_doc, char *src_name, char *name, char toc) { struct RB_header *cur_header; int cur_len, max_len, header_nr; switch (output_mode) { case AMIGAGUIDE: if (strstr (name + 1, ".guide") == NULL) fprintf (dest_doc, "@database %s.guide\n", name); else fprintf (dest_doc, "@database %s\n", name); fprintf (dest_doc, "@rem Source: %s\n", src_name); fprintf (dest_doc, "@rem " COMMENT_ROBODOC); fprintf (dest_doc, "@rem " COMMENT_COPYRIGHT); fprintf (dest_doc, "@node Main %s\n", name); fprintf (dest_doc, "@{jcenter}\n"); fprintf (dest_doc, "@{fg highlight}@{b}TABLE OF CONTENTS@{ub}@{fg text}\n\n"); max_len = 0; for (cur_header = first_header; cur_header; cur_header = cur_header->next_header) { if (cur_header->name) { cur_len = strlen (cur_header->name); if (cur_len > max_len) max_len = cur_len; } } for (cur_header = first_header; cur_header; cur_header = cur_header->next_header) { if (cur_header->name && cur_header->function_name) { fprintf (dest_doc, "@{\"%s", cur_header->name); for (cur_len = strlen (cur_header->name); cur_len < max_len; ++cur_len) fputc (' ', dest_doc); fprintf (dest_doc, "\" Link \"%s\"}\n", cur_header->function_name); } } fprintf (dest_doc, "@{jleft}\n"); fprintf (dest_doc, "@endnode\n"); break; case HTML: /* Append document type and title */ fprintf (dest_doc, "\n"); fprintf (dest_doc, "\n%s\n", name); /* append SGML-comment with document- and copyright-info. This code * ensures that every line has an own comment to avoid problems with * buggy browsers */ fprintf (dest_doc, "\n", src_name); { static const char copyright_text[] = COMMENT_ROBODOC COMMENT_COPYRIGHT; size_t i = 0; char previous_char = '\n'; char current_char = copyright_text[i]; while (current_char) { if (previous_char == '\n') { fprintf (dest_doc, ""); } else if ((current_char == '-') && (previous_char == '-')) { /* avoid "--" inside SGML-comment, and use "-_" instead; this * looks a bit strange, but one should still be able to figure * out what is meant when reading the output */ current_char = '_'; } fputc (current_char, dest_doc); i += 1; previous_char = current_char; current_char = copyright_text[i]; } } /* append heading and start list of links to functions */ fprintf (dest_doc, "\n"); #if 0 fprintf (dest_doc, "Generated from %s with ROBODoc v" VERSION " on ", src_name, src_name); RB_TimeStamp (dest_doc); #endif fprintf (dest_doc, "
\n"); if (toc) { int expc = 0; char iname[256]; FILE *index; /* do toc if not in fold */ #if 0 fprintf (dest_doc, "

TABLE OF CONTENTS

\n"); #endif fprintf (dest_doc, "
    \n"); /* Generate quick index file, for fast referencing */ sprintf(iname, "%s_index.html", doc_base); index = fopen(iname, "w"); for (cur_header = first_header; cur_header; cur_header = cur_header->next_header) { char fname[256]; sprintf(fname, "%s_exp_%d.html", doc_base, expc); if (cur_header->name && cur_header->function_name) { if (expc == 0) { int item_type; char *next_line, *item_line = NULL; RB_Generate_Header_Start (dest_doc, cur_header); next_line = cur_header->contents; item_type = RB_Find_Item (&next_line, &item_line); if (item_type != NO_ITEM) { int old_item_type; char *old_next_line; do { if (course_of_action & DO_TELL) printf ("[%s] ", item_names[item_type]); if (!((item_type == SOURCE_ITEM) && (course_of_action & DO_NOSOURCE))) RB_Generate_Item_Name (dest_doc, item_type); old_next_line = next_line; old_item_type = item_type; item_type = RB_Find_Item (&next_line, &item_line); if (!((old_item_type == SOURCE_ITEM) && (course_of_action & DO_NOSOURCE))) RB_Generate_Item_Doc(dest_doc, name, old_next_line, item_line, cur_header->function_name, old_item_type); } while (item_type != NO_ITEM); if (course_of_action & DO_TELL) putchar ('\n'); } if (index) { fprintf (index, "%s
    \n", name, cur_header->function_name); } } else { fprintf (dest_doc, "
  1. %s\n", fname, cur_header->name); if (index) fprintf (index, "%s
    \n", fname, cur_header->function_name); } expc++; } } fprintf (dest_doc, "
\n"); if (index) fclose(index); } break; case LATEX: fprintf (dest_doc, "%% Document: %s\n", name); fprintf (dest_doc, "%% Source: %s\n", src_name); fprintf (dest_doc, "%% " COMMENT_ROBODOC); fprintf (dest_doc, "%% " COMMENT_COPYRIGHT); if (course_of_action & DO_SINGLEDOC) { fprintf (dest_doc, "\\section{%s}\n", src_name); } else { fprintf (dest_doc, "\\documentclass{article}\n"); fprintf (dest_doc, "\\usepackage{makeidx}\n"); 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"); if (document_title) { fprintf (dest_doc, "\\title{%s}\n", document_title); } else { fprintf (dest_doc, "\\title{API Reference}\n"); } fprintf (dest_doc, "\\author{%s}\n", COMMENT_ROBODOC); fprintf (dest_doc, "\\makeindex\n"); fprintf (dest_doc, "\\begin{document}\n"); fprintf (dest_doc, "\\maketitle\n"); /* autogenerate table of contents! */ fprintf (dest_doc, "\\printindex\n"); fprintf (dest_doc, "\\tableofcontents\n"); fprintf (dest_doc, "\\newpage\n"); /* trick to disable the autogenerated \newpage */ fprintf (dest_doc, "\n"); } break; case RTF: { char *cook_link; /* RTF header */ fprintf (dest_doc, "{\\rtf1\\ansi \\deff0" "{\\fonttbl;" "\\f0\\fswiss MS Sans Serif;" "\\f1\\fmodern Courier New;" "\\f2\\ftech Symbol;" "}" "{\\colortbl;" "\\red255\\green255\\blue255;" "\\red0\\green0\\blue0;" "\\red0\\green0\\blue255;" "}"); /* RTF document info */ fprintf (dest_doc, "{\\info" "{\\title %s}" "{\\comment\n" " Source: %s\n" " " COMMENT_ROBODOC " " COMMENT_COPYRIGHT "}" "}", name, src_name); /* RTF document format */ fprintf (dest_doc, "{\\margl1440\\margr1440}\n"); /* RTF document section */ fprintf (dest_doc, "\\f0\\cb1\\cf3\\fs28\\b1\\qc" "{\\super #{\\footnote{\\super #}%s_TOC}}" "{\\super ${\\footnote{\\super $}Contents}}" "{TABLE OF CONTENTS}\\ql\\b0\\fs20\\cf2\\par\n", src_name); for (cur_header = first_header; cur_header; cur_header = cur_header->next_header) { if (cur_header->name && cur_header->function_name) { cook_link = RB_CookStr (cur_header->function_name); fprintf (dest_doc, "{\\uldb %s}{\\v %s}\\line\n", cur_header->name, cook_link); free (cook_link); } } fprintf (dest_doc, "\\par\n"); } break; case ASCII: if (course_of_action & DO_TOC) { fprintf (dest_doc, "TABLE OF CONTENTS\n"); for (cur_header = first_header, header_nr = 1; cur_header; cur_header = cur_header->next_header, header_nr++) { if (cur_header->name && cur_header->function_name) { fprintf (dest_doc, "%4.4d %s\n", header_nr, cur_header->name); } } fputc ('\f', dest_doc); } default: break; } } /***************/ /****f* ROBODoc/RB_Generate_Doc_End [3.0h] * NAME * RB_Generate_Doc_End -- generate document trailer. * SYNOPSIS * RB_Generate_Doc_End (dest_doc, name) * * RB_Generate_Doc_End (FILE *, char *) * FUNCTION * Generates for depending on the output_mode the text that * will be at the end of a document. * INPUTS * dest_doc - pointer to the file to which the output will * be written. * name - the name of this file. * output_mode - global variable that indicates the output * mode. * NOTES * Doesn't do anything with its arguments, but that might * change in the future. * BUGS * SOURCE */ void RB_Generate_Doc_End (FILE * dest_doc, char *name) { switch (output_mode) { case AMIGAGUIDE: fputc ('\n', dest_doc); break; case HTML: fprintf (dest_doc, "\n"); break; case LATEX: if (!(course_of_action & DO_SINGLEDOC)) { fprintf (dest_doc, "\\end{document}\n"); } break; case RTF: fputc ('}', dest_doc); break; case ASCII: break; } } /************/ /****f* ROBODoc/RB_Generate_Header_Start [3.0h] * NAME * RB_Generate_Header_Start -- generate header start text. * SYNOPSIS * void RB_Generate_Header_Start (dest_doc, cur_header) * * void RB_Generate_Header_Start (FILE *, struct RB_header *) * FUNCTION * Generates depending on the output_mode the text that * will be at the end of each header. * INPUTS * dest_doc - pointer to the file to which the output will * be written. * cur_header - pointer to a RB_header structure. * SEE ALSO * RB_Generate_Header_End * SOURCE */ void RB_Generate_Header_Start (FILE * dest_doc, struct RB_header *cur_header) { char *cook_link; switch (output_mode) { /* switch by *koessi */ case AMIGAGUIDE: if (cur_header->name && cur_header->function_name) { fprintf (dest_doc, "@Node \"%s\" \"%s\"\n", cur_header->function_name, cur_header->name); fprintf (dest_doc, "%s", att_start_command[MAKE_SHINE][output_mode]); fprintf (dest_doc, "%s", cur_header->name); fprintf (dest_doc, "%s", att_stop_command[MAKE_SHINE][output_mode]); fprintf (dest_doc, "\n\n"); } break; case HTML: if (cur_header->name && cur_header->function_name) { #if 0 fprintf (dest_doc, "
\n"); #endif if (cur_header->type == FUNCTION_HEADER) fprintf (dest_doc, "\n" "Function %s" "

\n\n", cur_header->function_name, cur_header->function_name); else if (cur_header->type == STRUCT_HEADER) fprintf (dest_doc, "\n" "Structure %s" "

\n\n", cur_header->function_name, cur_header->function_name); else if (cur_header->type == VARIABLE_HEADER) fprintf (dest_doc, "\n" "Variable %s" "

\n\n", cur_header->function_name, cur_header->function_name); else fprintf (dest_doc, "\n" "%s" "

\n\n", cur_header->function_name, cur_header->function_name); } break; case LATEX: cook_link = RB_CookStr (cur_header->name); if (!(course_of_action & DO_SINGLEDOC)) { fprintf (dest_doc, "\\newpage\n"); } fprintf (dest_doc, "\\subsection{%s}\n", cook_link); free (cook_link); if (cur_header->function_name) { cook_link = RB_CookStr (cur_header->function_name); fprintf (dest_doc, "\\index{unsorted!%s}\\index{%s!%s}\n", cook_link, RB_header_type_names[cur_header->type], cook_link); free (cook_link); } break; case RTF: if (cur_header->name && cur_header->function_name) { cook_link = RB_CookStr (cur_header->function_name); fprintf (dest_doc, "\\page" "{\\super #{\\footnote{\\super #}%s}}" "{\\super ${\\footnote{\\super $}%s}}" "\\cf3 %s\\cf2\\line\n", cur_header->function_name, cur_header->name, cur_header->name); free (cook_link); } break; case ASCII: { fprintf (dest_doc, "%s", att_start_command[MAKE_SHINE][output_mode]); fprintf (dest_doc, "%s", cur_header->name); fprintf (dest_doc, "%s", att_stop_command[MAKE_SHINE][output_mode]); fprintf (dest_doc, "\n\n"); } break; } } /******/ /****f* ROBODoc/RB_Generate_Header_End [3.0h] * NAME * RB_Generate_Header_End * SYNOPSIS * void RB_Generate_Header_End (dest_doc, cur_header) * * void RB_Generate_Header_End (FILE *, struct RB_header *) * FUNCTION * Generates for depending on the output_mode the text that * will be at the end of a header. * INPUTS * dest_doc - pointer to the file to which the output will * be written. * cur_header - pointer to a RB_header structure. * SEE ALSO * RB_Generate_Header_Start * SOURCE */ void RB_Generate_Header_End (FILE * dest_doc, struct RB_header *cur_header) { switch (output_mode) { /* switch by *koessi */ case AMIGAGUIDE: if (cur_header->name && cur_header->function_name) fprintf (dest_doc, "@endnode\n"); break; case HTML: case LATEX: fputc ('\n', dest_doc); break; case RTF: fprintf (dest_doc, "\\par\n"); break; case ASCII: fputc ('\f', dest_doc); default: break; } } /*****/ /****f* ROBODoc/RB_Generate_Header_Name [3.0c] * NAME * RB_Generate_Header_Name * SYNOPSIS * RB_Generate_Header_Name (dest_doc, name) * * RB_Generate_Header_Name (FILE *, char *) * INPUTS * dest_doc - pointer to the file to which the output will * be written. * name - pointer to the header name. * SOURCE */ void RB_Generate_Header_Name (FILE * dest_doc, char *name) { char format_str[] = "%s"; fprintf (dest_doc, format_str, att_start_command[MAKE_SHINE][output_mode]); fprintf (dest_doc, format_str, name); fprintf (dest_doc, format_str, att_stop_command[MAKE_SHINE][output_mode]); fprintf (dest_doc, "\n\n"); } /*** RB_Generate_Header_Name ***/ /****** ROBODoc/RB_Generate_Item_Name [2.01] * NAME * RB_Generate_Item_Name -- fast&easy * SYNOPSIS * void RB_Generate_Item_Name( FILE * dest_doc, int item_type ) * FUNCTION * write the items name to the doc * INPUTS * FILE * dest_doc -- document in progress * int item_type -- this leads to the name and makes colors * AUTHOR * Koessi * NOTES * uses globals: output_mode, item_names[] * SOURCE */ void RB_Generate_Item_Name (FILE * dest_doc, int item_type) { char format_str[] = "%s"; if (item_attributes[item_type] & ITEM_NAME_LARGE_FONT) { fprintf (dest_doc, format_str, att_start_command[MAKE_LARGE][output_mode]); fprintf (dest_doc, format_str, att_start_command[MAKE_BOLD][output_mode]); if (output_mode == HTML) fprintf (dest_doc, "\n"); fprintf (dest_doc, format_str, item_names[item_type]); if (output_mode == HTML) fprintf (dest_doc, "\n"); fprintf (dest_doc, format_str, att_stop_command[MAKE_BOLD][output_mode]); fprintf (dest_doc, format_str, att_stop_command[MAKE_LARGE][output_mode]); } else fprintf (dest_doc, format_str, item_names[item_type]); fputc ('\n', dest_doc); } /*****/ /****f* ROBODoc/RB_Generate_Item_Doc [3.0j] * NAME * RB_Generate_Item_Doc * SYNOPSIS * void RB_Generate_Item_Doc(FILE * dest_doc, char *dest_name, * char *begin_of_item, * char *end_of_item, * char *function_name, * int item_type) * FUNCTION * Generates the body text of an item, applying predefined attributes * to the text. * NOTES * Body text is always non-proportional for several reasons: * 1) text is rarely written with prop spacing and text wrapping * in mind -- e.g., see SYNOPSIS above * 2) source code looks better * 3) it simplifies LaTeX handling * SOURCE */ void RB_Generate_Item_Doc (FILE * dest_doc, char *dest_name, char *begin_of_item, char *end_of_item, char *function_name, int item_type) { char format_str[] = "%s"; if (begin_of_item == end_of_item) { switch (output_mode) { case HTML: fprintf (dest_doc, "
\n"); break; case LATEX: fprintf (dest_doc, "\\\\\n"); break; case RTF: fprintf (dest_doc, "\n"); break; default: break; } return; } /* For text body in HTML, change to non-prop _before_ changing font * style. * To conform to DTD, this avoids
 and instead uses
   * 
 */
  if (output_mode == HTML)
    {
      fprintf (dest_doc, "
");
    }
  /* change font style */
  if (item_attributes[item_type] & TEXT_BODY_LARGE_FONT)
    fprintf (dest_doc, format_str,
	     att_start_command[MAKE_LARGE][output_mode]);
  if (item_attributes[item_type] & TEXT_BODY_ITALICS)
    fprintf (dest_doc, format_str,
	     att_start_command[MAKE_ITALICS][output_mode]);
  if (item_attributes[item_type] & TEXT_BODY_NON_PROP)
    fprintf (dest_doc, format_str,
	     att_start_command[MAKE_NON_PROP][output_mode]);
  if (item_attributes[item_type] & TEXT_BODY_SMALL_FONT)
    fprintf (dest_doc, format_str,
	     att_start_command[MAKE_SMALL][output_mode]);
  if (item_attributes[item_type] & TEXT_BODY_BOLD)
    fprintf (dest_doc, format_str,
	     att_start_command[MAKE_BOLD][output_mode]);
  if (item_attributes[item_type] & TEXT_BODY_UNDERLINE)
    fprintf (dest_doc, format_str,
	     att_start_command[MAKE_UNDERLINE][output_mode]);
  if (item_attributes[item_type] & TEXT_BODY_SHINE)
    fprintf (dest_doc, format_str,
	     att_start_command[MAKE_SHINE][output_mode]);

  /* 
   * For some modes, the text body is always non-prop
   */
  switch (output_mode)
    {
    case LATEX:
      fprintf (dest_doc, "\\begin{verbatim}\n");
      break;
    case RTF:
      fprintf (dest_doc, "{\\f1{}");
      break;
    default:
      break;
    }

  RB_Generate_Item_Body (dest_doc, dest_name, begin_of_item, end_of_item,
			 function_name, item_type, 0);

  switch (output_mode)
    {
    case LATEX:
      /* split the text so LaTeX doesn't get confused ;) */
      fprintf (dest_doc, "\\" "end{verbatim}\n");
      break;
    case RTF:
      fputc ('}', dest_doc);
    default:
      break;
    }

  /* restore font style */
  if (item_attributes[item_type] & TEXT_BODY_SHINE)
    fprintf (dest_doc, format_str,
	     att_stop_command[MAKE_SHINE][output_mode]);
  if (item_attributes[item_type] & TEXT_BODY_UNDERLINE)
    fprintf (dest_doc, format_str,
	     att_stop_command[MAKE_UNDERLINE][output_mode]);
  if (item_attributes[item_type] & TEXT_BODY_BOLD)
    fprintf (dest_doc, format_str,
	     att_stop_command[MAKE_BOLD][output_mode]);
  if (item_attributes[item_type] & TEXT_BODY_SMALL_FONT)
    fprintf (dest_doc, format_str,
	     att_stop_command[MAKE_SMALL][output_mode]);
  if (item_attributes[item_type] & TEXT_BODY_NON_PROP)
    fprintf (dest_doc, format_str,
	     att_stop_command[MAKE_NON_PROP][output_mode]);
  if (item_attributes[item_type] & TEXT_BODY_ITALICS)
    fprintf (dest_doc, format_str,
	     att_stop_command[MAKE_ITALICS][output_mode]);
  if (item_attributes[item_type] & TEXT_BODY_LARGE_FONT)
    fprintf (dest_doc, format_str,
	     att_stop_command[MAKE_LARGE][output_mode]);

  if (output_mode != HTML)
    {
      fputc ('\n', dest_doc);
    }
  /* for HTML, switch back to prop-font after restoring font style */
  if (output_mode == HTML)
    {
      fprintf (dest_doc, "
"); } } /******/ /****f* ROBODoc/RB_Generate_Item_Body [3.0h] * NAME * RB_Generate_Item_Body * SYNOPSIS * char * RB_Generate_Item_Body(FILE * dest_doc, char *dest_name, * char *begin_of_item, char *end_of_item, * char *function_name, * int item_type, int tabs_to_skip) * * FUNCTION * Generates body of an item in output-specific form * INPUTS * dest_doc - pointer to the file to which * the output will be written. * dest_name - the name of this file. * begin_of_item - * end_of_item - * function_name - * item_type - * tabs_to_skip - how many tabs to skip in this fold. * BUGS * o Unbalanced fold marks lead to crash. * NOTES * o Almost completely rewritten by koessi * o Almost completely Re-Rewritten by Slothouber :) * o Folding mode by PetteriK. * o Linking fixed inside folds / PetteriK 08.04.2000 * SOURCE */ char * RB_Generate_Item_Body (FILE * dest_doc, char *dest_name, char *begin_of_item, char *end_of_item, char *function_name, int item_type, int tabs_to_skip) { char *cur_char, old_char, c; int html_incr; char fname[128], foldname[128]; static int in_fold = 0; /* PetteriK 08.04.2000 */ cur_char = begin_of_item; if (item_type == SOURCE_ITEM) { /* skip end_comment_marker */ for (; *cur_char && *cur_char != '\n'; cur_char++); /* skip blank lines leading up to source code */ while (*cur_char == '\n') cur_char++; /* trim blanks following source code */ do { end_of_item--; } while (end_of_item > cur_char && isspace (*end_of_item)); end_of_item++; /* advance 1 for placement of the NUL */ } old_char = *end_of_item; *end_of_item = '\0'; for (; *cur_char; cur_char++) { int tb = tab_size; int do_search = TRUE; int was_link = FALSE; int tabs = 0; if (item_type != SOURCE_ITEM) { /* Skip empty lines */ while (*cur_char == '\n') { cur_char++; } cur_char = RB_Skip_Remark_Marker (cur_char); } else { /* indent source */ switch (output_mode) { case RTF: fprintf (dest_doc, "\\tab "); break; case AMIGAGUIDE: case HTML: case LATEX: default: fprintf (dest_doc, " "); } } while (((c = *cur_char) != '\0') && (c != '\n')) { char *label_name, *file_name; char found = 0; int tmp; if (!do_search) { if (!isalnum (c) && (c != '_')) { do_search = TRUE; } } else { if (isalpha (c) || (c == '_')) { if (((was_link = RB_Find_Link (cur_char, &label_name, &file_name)) == FALSE)) { do_search = FALSE; } } else was_link = FALSE; } if (!was_link) { switch (output_mode) { case AMIGAGUIDE: switch (c) { case '\n': --cur_char; break; case '\t': for (tb %= tab_size; tb < tab_size; ++tb) fputc (' ', dest_doc); break; case '@': fprintf (dest_doc, "\\@"); tb++; break; case '\\': fprintf (dest_doc, "\\\\"); tb++; break; default: fputc (c, dest_doc); tb++; } break; case HTML: /* PetteriK 26.07.1999 */ if (extra_flags & FOLD) { cur_char = RB_Check_Fold_Start (cur_char, foldname, &found); } if ((extra_flags & FOLD) && found) { FILE *fp; RB_Say ("fold name %s\n", foldname); RB_Say ("fold begin %d\n", ++fold); RB_Say ("tabs %d\n", tabs); sprintf (fname, "%s_fold_%d.html", doc_base, fold); RB_Say ("opening file %s\n", fname); fp = fopen (fname, "w"); RB_Generate_Doc_Start (fp, foldname, foldname, 0); fprintf (fp, "
\n");
		      fprintf (dest_doc, "... %s",
			       fname, foldname);
		      in_fold++;	/* PetteriK 08.04.2000 */
		      cur_char = RB_Generate_Item_Body (fp, dest_name,
						      cur_char, end_of_item,
							function_name,
							item_type, tabs);
		      in_fold--;	/* PetteriK 08.04.2000 */
		      /* skip chars until newline */
		      while (*cur_char != '\n')
			{
			  cur_char++;
			}
		      cur_char--;
		      fprintf (fp, "\n
\n"); RB_Generate_Doc_End (fp, foldname); fclose (fp); } else if ((extra_flags & FOLD) && RB_Check_Fold_End (cur_char)) { RB_Say ("fold end found\n"); return cur_char; } else if ((html_incr = RB_HTML_Extra (dest_doc, item_type, cur_char))) { cur_char += html_incr; } else { switch (c) { case '\n': --cur_char; break; case '\t': if (extra_flags & FOLD) { if (tabs >= tabs_to_skip) { for (tb %= tab_size; tb < tab_size; ++tb) { fputc (' ', dest_doc); } } tabs++; } else { for (tb %= tab_size; tb < tab_size; ++tb) { fputc (' ', dest_doc); } } break; case '<': fprintf (dest_doc, "<"); tb++; break; case '>': fprintf (dest_doc, ">"); tb++; break; case '&': fprintf (dest_doc, "&"); tb++; break; default: fputc (c, dest_doc); tb++; } } break; /* end case HTML */ case LATEX: switch (c) { case '\n': --cur_char; break; case '\t': for (tb %= tab_size; tb < tab_size; ++tb) fputc (' ', dest_doc); break; #if 0 /* not used in LaTeX's verbatim environment */ case '$': case '&': case '%': case '#': case '_': case '{': case '}': fputc ('\\', dest_doc); fputc (c, dest_doc); tb++; break; case '\\': fprintf (dest_doc, "$\\backslash$"); tb++; break; case '~': fprintf (dest_doc, "$\\tilde$"); tb++; break; case '^': fprintf (dest_doc, "$\\,\\!^{\\sim}$"); tb++; break; #endif default: fputc (c, dest_doc); tb++; } break; case RTF: switch (c) { case '\n': --cur_char; break; case '\t': for (tb %= tab_size; tb < tab_size; ++tb) fputc (' ', dest_doc); break; case '\\': case '{': case '}': fputc ('\\', dest_doc); fputc (c, dest_doc); tb++; break; default: fputc (c, dest_doc); tb++; } break; default: fputc (c, dest_doc); tb++; } cur_char++; } else { switch (output_mode) { case AMIGAGUIDE: if (file_name && strcmp (file_name, dest_name)) fprintf (dest_doc, "@{\"%s\" Link \"%s/%s\"}", label_name, file_name, label_name); else { if (strcmp (label_name, function_name)) fprintf (dest_doc, "@{\"%s\" Link \"%s\"}", label_name, label_name); else { fprintf (dest_doc, "%s", att_start_command[MAKE_BOLD][output_mode]); fprintf (dest_doc, "%s", label_name); fprintf (dest_doc, "%s", att_stop_command[MAKE_BOLD][output_mode]); } } break; case HTML: /* Include the file name in the link if we are in fold * PetteriK 08.04.2000 */ if (in_fold) { /* We are in fold, always use the file name in the link, * in file_name == NULL (i.e. the label is in the current file * that we are processing), refer to value in dest_name. * This also makes sure that we link correctly if function_name * is the same as label_name. */ fprintf (dest_doc, "%s", (file_name ? file_name : dest_name), label_name, label_name); } else if (file_name && strcmp (file_name, dest_name)) { fprintf (dest_doc, "%s", file_name, label_name, label_name); } else { if (strcmp (label_name, function_name)) { fprintf (dest_doc, "%s", label_name, label_name); } else { fprintf (dest_doc, "%s", att_start_command[MAKE_BOLD][output_mode]); fprintf (dest_doc, "%s", label_name); fprintf (dest_doc, "%s", att_stop_command[MAKE_BOLD][output_mode]); } } break; case RTF: if (strcmp (label_name, function_name)) { char *cook_link; cook_link = RB_CookStr (label_name); fprintf (dest_doc, "{\\uldb %s}{\\v %s}", label_name, cook_link); free (cook_link); } else { fprintf (dest_doc, "%s", att_start_command[MAKE_BOLD][output_mode]); fprintf (dest_doc, "%s", label_name); fprintf (dest_doc, "%s", att_stop_command[MAKE_BOLD][output_mode]); } break; default: fprintf (dest_doc, "%s", label_name); } tmp = strlen (label_name); cur_char += tmp; tb += tmp; } /* end if */ } if (*cur_char) { if (output_mode == RTF) fprintf (dest_doc, "\\line"); fputc ('\n', dest_doc); tabs = 0; } } *end_of_item = old_char; return (char *) 0; } /***************/ /****f* ROBODoc/RB_HTML_Extra * NAME * RB_HTML_Extra * AUTHOR * PetteriK * HISTORY * 05/15/2000 Added mailto: support (Guillaume Etorre) * FUNCTION * Check and process embedded hyperlinks. * RETURN VAL* FUNCTION * Check and process embedded hyperlinks. * RETURN VALUE * Number of chars processed from *cur_char * TODO * Flag for C and other grammars. * BUGS * As the documentation generated for this functions shows, if * the C source code contains a string with " / * " in it, this * function fails :) * SOURCE */ int RB_HTML_Extra (FILE * dest_doc, int item_type, char *cur_char) { int res = 0; char link[1024]; if (strncmp ("http://", cur_char, strlen ("http://")) == 0) { sscanf (cur_char, "%s", link); RB_Say ("found link %s\n", link); res = (strlen (link) - 1); fprintf (dest_doc, "%s", link, link); } else if (strncmp ("href:", cur_char, strlen ("href:")) == 0) { /* handy in relative hyperlink paths, e.g. href:../../modulex/ */ sscanf ((cur_char + strlen ("href:")), "%s", link); RB_Say ("found link %s\n", link); res = (strlen (link) + strlen ("href:") - 1); fprintf (dest_doc, "%s", link, link); } else if (strncmp ("mailto:", cur_char, strlen ("mailto:")) == 0) { sscanf ((cur_char + strlen ("mailto:")), "%s", link); RB_Say ("found mail to %s\n", link); res = (strlen (link) + strlen ("mailto:") - 1); fprintf (dest_doc, "%s", link, link); } else if ((extra_flags & C_MODE) && (item_type == SOURCE_ITEM) && (strncmp ("/*", cur_char, 2) == 0)) { /* start of C comment */ fprintf (dest_doc, "/*"); res = 1; } else if ((extra_flags & C_MODE) && (item_type == SOURCE_ITEM) && (strncmp ("*/", cur_char, 2) == 0)) { /* end of C comment */ fprintf (dest_doc, "*/"); res = 1; } return res; } /**********/ /****f* ROBODoc/RB_Generate_Index * NAME * RB_Generate_Index -- generate index file based on xref files. * SYNOPSIS * void RB_Generate_Index(FILE *dest, char *name) * FUNCTION * Create a master index file. It contains pointers to the * documentation generated for each source file, as well as all * "objects" found in the source files. ******** */ void RB_Generate_Index (FILE * dest, char *source) { RB_Slow_Sort_Links (); switch (output_mode) { case HTML: { if (document_title) { RB_Generate_Doc_Start (dest, source, document_title, 0); fprintf (dest, "

%s

\n", document_title); } else { RB_Generate_Doc_Start (dest, source, "Master Index File", 0); fprintf (dest, "

Master Index File

\n"); } if (RB_Number_Of_Links (MAIN_HEADER, NULL)) RB_Generate_Index_Table (dest, MAIN_HEADER, "Project Modules"); RB_Generate_Index_Table (dest, NO_HEADER, "Source Files"); if (RB_Number_Of_Links (CLASS_HEADER, NULL)) RB_Generate_Index_Table (dest, CLASS_HEADER, "Classes"); if (RB_Number_Of_Links (METHOD_HEADER, NULL)) RB_Generate_Index_Table (dest, METHOD_HEADER, "Methods"); if (RB_Number_Of_Links (STRUCT_HEADER, NULL)) RB_Generate_Index_Table (dest, STRUCT_HEADER, "Structures"); if (RB_Number_Of_Links (FUNCTION_HEADER, NULL)) RB_Generate_Index_Table (dest, FUNCTION_HEADER, "Functions"); if (RB_Number_Of_Links (VARIABLE_HEADER, NULL)) RB_Generate_Index_Table (dest, VARIABLE_HEADER, "Variables"); if (RB_Number_Of_Links (CONSTANT_HEADER, NULL)) RB_Generate_Index_Table (dest, CONSTANT_HEADER, "Constants"); if (RB_Number_Of_Links (GENERIC_HEADER, NULL)) RB_Generate_Index_Table (dest, GENERIC_HEADER, "Generic"); if (RB_Number_Of_Links (INTERNAL_HEADER, NULL)) RB_Generate_Index_Table (dest, INTERNAL_HEADER, "Internal"); RB_Generate_Doc_End (dest, source); } break; case LATEX: { RB_Generate_Doc_Start (dest, source, "Master File", 0); RB_Generate_LaTeX_Includes (dest); RB_Generate_Doc_End (dest, source); } } } /****f* ROBODoc/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) { 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); } } } /****f* ROBODoc/RB_Generate_Index_Table * NAME * RB_Generate_Index -- * SYNOPSIS * void RB_Generate_Index_Table(FILE *, int type, char *title) * RB_Generate_Index_Table(dest, type, title) * FUNCTION * Creates a table with index items of a particular type. * If the type is NO_HEADER, then the table is a table of * source files. In this case no link is added if the * source file did not contain any documentation. * INPUTS * dest -- output file * type -- kind of header index. * title -- title for the table * SOURCE */ void RB_Generate_Index_Table (FILE * dest, int type, char *title) { struct RB_link *cur_link; int number_of_columns; int cur_column; number_of_columns = 60 / RB_Max_Name_Length (type, NULL); fprintf (dest, "

%s

\n", title); fprintf (dest, "\n"); cur_column = 0; for (cur_link = first_link; cur_link; cur_link = cur_link->next_link) { if (cur_link->type == type) { if (cur_column == 0) { fprintf (dest, "\n"); } if (type == NO_HEADER) { if (RB_Number_Of_Links (NO_HEADER, cur_link->file_name) > 1) { fprintf (dest, "\n", cur_link->file_name, cur_link->label_name, cur_link->label_name); } else { fprintf (dest, "\n", cur_link->label_name); } } else { fprintf (dest, "\n", cur_link->file_name, cur_link->label_name, cur_link->label_name); }; cur_column++; if (cur_column > number_of_columns) { fprintf (dest, "\n"); cur_column = 0; } } } for (; cur_column <= number_of_columns;) { if (cur_column == 0) { fprintf (dest, "\n"); } fprintf (dest, "\n"); cur_column++; } fprintf (dest, "\n"); fprintf (dest, "
%s%s%s
\n"); } /******* END RB_Generate_Index_Table *****/ /****f* ROBODoc/RB_Number_Of_Links * NAME * RB_Number_Of_Links -- Count the number of links. * FUNCTION * Counts the number of links that are of a particular type * and that can be found in a particular file. * INPUTS * type -- the header type of the header the link is pointing to. * If NO_HEADER, all header types are counted. * file_name -- name of the file the link comes from, can be NULL, in * which case only the type is checked. * RESULT * number of links. ****** */ int RB_Number_Of_Links (int type, char *file_name) { struct RB_link *cur_link; int n = 0; for (cur_link = first_link; cur_link; cur_link = cur_link->next_link) { if (cur_link->type == type || (type == NO_HEADER)) { if (file_name) { if (strcmp (file_name, cur_link->file_name) == 0) { n++; } } else { n++; } } } return n; } /****f* ROBODoc/RB_Max_Name_Length * NAME * RB_Max_Name_Length -- find longest label name. * FUNCTION * Find the length of the longest label name in a sub list * of the list with links. This is used to determine how * many columns can be displayed in a table. * The sublist is specified by the type of header the link * should point to, as well as by the name of the documentation * file. * EXAMPLE * RB_Max_Name_Length(CLASS_HEADER, "muppets.c.html") * longest label name in the list of links to class headers * in muppets.c.html. * RB_Max_Name_Length(CLASS_HEADER, NULL) * longest label name in the list of links to class headers. * INPUTS * type -- type of header * file_name -- file the header come from, can be NULL. * In which links from all files are used. * SOURCE */ int RB_Max_Name_Length (int type, char *file_name) { struct RB_link *cur_link; int n = 1; for (cur_link = first_link; cur_link; cur_link = cur_link->next_link) { if (cur_link->type == type) { if (file_name) { if (strcmp (file_name, cur_link->file_name) == 0) { if (strlen (cur_link->label_name) > n) { n = strlen (cur_link->label_name); } } } else { if (strlen (cur_link->label_name) > n) { n = strlen (cur_link->label_name); } } } } return n; } /*********/