From 6ae8d8153b5405a3f10a86e9a358662d86b26254 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Tue, 30 Jan 2018 21:02:04 +0100 Subject: [PATCH] Write Help as HTML files specific binary to generate HTML doc : bin/generatedoc see http://pulkomandy.tk/projects/GrafX2/ticket/8 --- Makefile | 7 +- src/Makefile | 15 ++- src/generatedoc.c | 302 ++++++++++++++++++++++++++++++++++++++++++++++ src/help.h | 1 - src/struct.h | 2 +- 5 files changed, 323 insertions(+), 4 deletions(-) create mode 100644 src/generatedoc.c diff --git a/Makefile b/Makefile index e76e3bbd..2ab7bc6c 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ OPT = WIN32CROSS=1 \ endif .PHONY: all tools grafx2 ziprelease 3rdparty win32installer \ - doc doxygen docarchive doxygenarchive + doc doxygen docarchive doxygenarchive htmldoc all: grafx2 tools @@ -27,8 +27,13 @@ tools: win32installer: $(MAKE) -C install/ +# generate Doxygen to doc/doxygen doxygen: $(MAKE) -C tools/ doxygen doxygenarchive: $(MAKE) -C tools/ doxygenarchive + +# generate HTML doc to doc/html +htmldoc: + $(MAKE) -C src/ htmldoc diff --git a/src/Makefile b/src/Makefile index 9e91e577..6da778a9 100644 --- a/src/Makefile +++ b/src/Makefile @@ -99,6 +99,7 @@ ifdef COMSPEC RMDIR = rmdir --ignore-fail-on-non-empty CP = cp BIN = ../bin/grafx2.exe + GENERATEDOCBIN = ../bin/generatedoc.exe COPT = -W -Wall -Wdeclaration-after-statement -O$(OPTIM) -g -ggdb `sdl-config --cflags` $(TTFCOPT) $(JOYCOPT) $(LUACOPT) LOPT = `sdl-config --libs` -lSDL_image $(TTFLOPT) -lpng -lz $(LUALOPT) LUALOPT = -llua @@ -112,6 +113,8 @@ ifdef COMSPEC ZIP = zip else +# default for GENERATEDOCBIN + GENERATEDOCBIN = ../bin/generatedoc #For all other platforms, we can rely on uname PLATFORM = $(shell uname) @@ -642,7 +645,7 @@ endif ### And now for the real build rules ### -.PHONY : all debug release clean depend force install uninstall valgrind doc doxygen +.PHONY : all debug release clean depend force install uninstall valgrind doc doxygen htmldoc # This is the list of the objects we want to build. Dependancies are built by "make depend" automatically. OBJS = main.o init.o graph.o $(APIOBJ) misc.o special.o \ @@ -662,6 +665,8 @@ OBJS += loadrecoil.o recoil.o endif OBJ = $(addprefix $(OBJDIR)/,$(OBJS)) +GENERATEDOCOBJ = $(addprefix $(OBJDIR)/,generatedoc.o hotkeys.o keyboard.o) + SKINS = skin_classic.png skin_modern.png skin_DPaint.png \ font_Classic.png font_Fun.png font_Fairlight.png \ font_Melon.png font_DPaint.png \ @@ -840,6 +845,10 @@ ifeq ($(PLATFORM),Haiku) mimeset -f $(BIN) endif +$(GENERATEDOCBIN): $(GENERATEDOCOBJ) + @test -d ../bin || $(MKDIR) ../bin + $(CC) $(GENERATEDOCOBJ) -o $(GENERATEDOCBIN) $(LOPT) $(LFLAGS) + # GIT revision number version.c: $(REVISION_CACHE) echo "const char SVN_revision[]=\"$(GIT_REVISION)\";" > version.c @@ -972,4 +981,8 @@ doc: doxygen doxygen: $(MAKE) -C ../tools doxygen +htmldoc: $(GENERATEDOCBIN) + $(MKDIR) ../doc/html + $(GENERATEDOCBIN) ../doc/html + -include Makefile.dep diff --git a/src/generatedoc.c b/src/generatedoc.c new file mode 100644 index 00000000..d359743a --- /dev/null +++ b/src/generatedoc.c @@ -0,0 +1,302 @@ +/* vim:expandtab:ts=2 sw=2: +*/ +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2018 Thomas Bernard + Copyright 2011 Pawel Góralski + Copyright 2009 Pasi Kallinen + Copyright 2008 Peter Gordon + Copyright 2008 Franck Charlet + Copyright 2007 Adrien Destugues + Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) + + Grafx2 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; version 2 + of the License. + + Grafx2 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 Grafx2; if not, see +*/ +/** + * @file generatedoc.c + * HTML doc generator + */ +#include +#include +#include "global.h" +#include "hotkeys.h" +#include "helpfile.h" +#include "keyboard.h" // for Key_Name() + +/// +/// Export the help to HTML files +static int Export_help(const char * path); + +int main(int argc,char * argv[]) +{ + int r; + const char * path = "."; + + if (argc > 1) { + if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0) { + printf("Usage: %s [directory]\n", argv[0]); + return 1; + } + path = argv[1]; + } + r = Export_help(path); + if (r < 0) + return -r; + return 0; +} + +/// similar to Shortcut() from help.c, but relying only on default shortcuts +static word * Find_default_shortcut(word shortcut_number) +{ + short order_index; + // Recherche dans hotkeys + order_index=0; + while (Ordering[order_index]!=shortcut_number) + { + order_index++; + if (order_index>=NB_SHORTCUTS) + { + return NULL; + } + } + return &(ConfigKey[order_index].Key); +} + +/// Similar to Keyboard_shortcut_value() from help.c, but relying only on default shortcuts +static const char * Keyboard_default_shortcut(word shortcut_number) +{ + static char shortcuts_name[80]; + word * pointer = Find_default_shortcut(shortcut_number); + if (pointer == NULL) + return "(Problem)"; + else + { + if (pointer[0] == 0 && pointer[1] == 0) + return "None"; + if (pointer[0] != 0 && pointer[1] == 0) + return Key_name(pointer[0]); + if (pointer[0] == 0 && pointer[1] != 0) + return Key_name(pointer[1]); + + strcpy(shortcuts_name, Key_name(pointer[0])); + strcat(shortcuts_name, " or "); + strcat(shortcuts_name, Key_name(pointer[1])); + return shortcuts_name; + } +} + +/// +static const char * Export_help_table(FILE * f, unsigned int page) +{ + int hlevel = 1; + static char title[256]; + word index; + + const T_Help_table * table = Help_section[page].Help_table; + word length = Help_section[page].Length; + + // Line_type : 'N' for normal line + // 'S' for a bold line + // 'K' for a line with keyboard shortcut + // 'T' and '-' for upper and lower titles. + + for (index = 0; index < length; index++) + { + if (table[index].Line_type == 'T') + { + strncpy(title, table[index].Text, sizeof(title)); + title[sizeof(title)-1] = '\0'; + while (index + 2 < length && table[index+2].Line_type == 'T') + { + size_t len = strlen(title); + index += 2; + if (table[index].Text[0] != ' ') + title[len++] = ' '; + if (len >= sizeof(title) - 1) + break; + strncpy(title + len, table[index].Text, sizeof(title)-len-1); + } + break; + } + } + + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "%s\n", title); + fprintf(f, "\n"); + fprintf(f, "\n"); + fprintf(f, "\n"); + + fprintf(f, "\n"); + + fprintf(f, "
"); + fprintf(f, "\n
"); + if (page > 0) + fprintf(f, "Previous\n", page - 1); + fprintf(f, "GrafX2 Help"); + if (page < sizeof(Help_section)/sizeof(Help_section[0]) - 1) + fprintf(f, "Next\n", page + 1); + fprintf(f, "
"); + fprintf(f, "
\n"); + fprintf(f, "
"); + for (index = 0; index < length; index++) + { + if (table[index].Line_type == '-') + continue; +// if (table[index].Line_type != 'N') printf("%c %s\n", table[index].Line_type, table[index].Text); + if (table[index].Line_type == 'S') + fprintf(f, ""); + else if (table[index].Line_type == 'T' && !(index > 1 && table[index-2].Line_type == 'T')) + fprintf(f, "", hlevel); + + if (table[index].Line_type == 'K') + { + char keytmp[64]; + snprintf(keytmp, sizeof(keytmp), "%s", Keyboard_default_shortcut(table[index].Line_parameter)); + fprintf(f, table[index].Text, keytmp); + } + else + { + const char * prefix = ""; + char * link = strstr(table[index].Text, "http://"); + if (link == NULL) + { + link = strstr(table[index].Text, "www."); + prefix = "http://"; + } + if (link != NULL) + { + char * link_end = strchr(link, ' '); + if (link_end == NULL) + { + link_end = strchr(link, ')'); + if (link_end == NULL) + link_end = link + strlen(link); + } + fprintf(f, "%.*s", (int)(link - table[index].Text), table[index].Text); + fprintf(f, "%.*s%s", prefix, + (int)(link_end - link), link, (int)(link_end - link), link, link_end); + } + else + { + // print the string and escape < and > characters + const char * text = table[index].Text; + while (text[0] != '\0') + { + size_t i = strcspn(text, "<>"); + if (text[i] == '\0') + { // no character to escape + fprintf(f, "%s", text); + break; + } + if (i > 0) + fprintf(f, "%.*s", (int)i, text); + switch(text[i]) + { + case '<': + fprintf(f, "<"); + break; + case '>': + fprintf(f, ">"); + break; + } + // continue with the remaining of the string + text += i + 1; + } + } + } + + if (table[index].Line_type == 'S') + fprintf(f, ""); + else if (table[index].Line_type == 'T') + { + if (index < length-2 && table[index+2].Line_type == 'T') + fprintf(f, " "); + else + { + fprintf(f, "", hlevel); + if (hlevel == 1) + hlevel++; + } + } + if (table[index].Line_type != 'T') + fprintf(f, "\n"); + // fprintf(f, "
\n"); + } + fprintf(f, "
"); + fprintf(f, "\n"); + fprintf(f, "\n"); + return title; +} + +/// +/// Export the help to HTML files +static int Export_help(const char * path) +{ + FILE * f; + FILE * findex; + char filename[MAX_PATH_CHARACTERS]; + unsigned int i; + + snprintf(filename, sizeof(filename), "%s/index.html", path); + //GFX2_Log(GFX2_INFO, "Creating %s\n", filename); + findex = fopen(filename, "w"); + if (findex == NULL) + { + fprintf(stderr, "Cannot save index HTML file %s\n", filename); + return -1; + } + fprintf(findex, "\n"); + fprintf(findex, "\n"); + fprintf(findex, "\n"); + fprintf(findex, "GrafX2 Help\n"); + fprintf(findex, "\n"); + fprintf(findex, "\n"); + fprintf(findex, "\n"); + + fprintf(findex, "\n"); + fprintf(findex, "
    \n"); + for (i = 0; i < sizeof(Help_section)/sizeof(Help_section[0]); i++) + { + const char * title; + snprintf(filename, sizeof(filename), "%s/grafx2_%02d.html", path, i); + f = fopen(filename, "w"); + if (f == NULL) + { + fprintf(stderr, "Cannot save HTML file %s\n", filename); + fclose(findex); + return -1; + } + //GFX2_Log(GFX2_INFO, "Saving %s\n", filename); + title = Export_help_table(f, i); + fclose(f); + fprintf(findex, "
  • %s
  • \n", i, title); + } + fprintf(findex, "
\n"); + fprintf(findex, "\n"); + fclose(findex); + + snprintf(filename, sizeof(filename), "%s/grafx2.css", path); + f = fopen(filename, "w"); + if (f != NULL) + { + fprintf(f, ".help {\n"); + fprintf(f, "font-family: %s;\n", "monospace"); + fprintf(f, "white-space: %s;\n", "pre"); + fprintf(f, "}\n"); + fclose(f); + } + return 0; +} diff --git a/src/help.h b/src/help.h index 390b9405..6fa1b730 100644 --- a/src/help.h +++ b/src/help.h @@ -63,4 +63,3 @@ const char * Keyboard_shortcut_value(word shortcut_number); void Remove_duplicate_shortcuts(void); #endif - diff --git a/src/struct.h b/src/struct.h index ef510bf3..9f461d47 100644 --- a/src/struct.h +++ b/src/struct.h @@ -248,7 +248,7 @@ typedef struct /// Data for one line of the "Help" screens. typedef struct { char Line_type; ///< Kind of line: 'N' for normal line, 'S' for a bold line, 'K' for a line with keyboard shortcut, 'T' and '-' for upper and lower titles. - char * Text; ///< Displayed string. + const char * Text; ///< Displayed string. int Line_parameter; ///< Generic parameter depending on line type. For 'K' lines: a shortcut identifier. For others: unused. } T_Help_table;