From 649487fac17bfdd0bc9ef39c6e0852802669b1e6 Mon Sep 17 00:00:00 2001 From: Slava Zanko Date: Wed, 7 Apr 2010 11:54:16 +0300 Subject: [PATCH 01/11] Ticket #45: Build system does not allow cross compiling The man2hlp program is build using the target compiler. The resulting executable therefore does not work on the build host. Since the man2hlp program is needed during compile time, the build will fail. Moved man2hlp into separate subdir Signed-off-by: Slava Zanko --- configure.ac | 1 + doc/hlp/Makefile.am | 4 ++-- doc/hlp/es/Makefile.am | 5 +++-- doc/hlp/hu/Makefile.am | 5 +++-- doc/hlp/it/Makefile.am | 5 +++-- doc/hlp/pl/Makefile.am | 5 +++-- doc/hlp/ru/Makefile.am | 5 +++-- doc/hlp/sr/Makefile.am | 5 +++-- src/Makefile.am | 24 +++++++++--------------- src/man2hlp/Makefile.am | 6 ++++++ src/{ => man2hlp}/man2hlp.c | 2 +- 11 files changed, 37 insertions(+), 30 deletions(-) create mode 100644 src/man2hlp/Makefile.am rename src/{ => man2hlp}/man2hlp.c (99%) diff --git a/configure.ac b/configure.ac index ed415fbec..7175e76e5 100644 --- a/configure.ac +++ b/configure.ac @@ -589,6 +589,7 @@ misc/mc.ext src/Makefile src/consaver/Makefile src/editor/Makefile +src/man2hlp/Makefile src/viewer/Makefile src/diffviewer/Makefile diff --git a/doc/hlp/Makefile.am b/doc/hlp/Makefile.am index 2d58db7da..a84d35ab4 100644 --- a/doc/hlp/Makefile.am +++ b/doc/hlp/Makefile.am @@ -6,5 +6,5 @@ pkgdata_DATA = mc.hlp EXTRA_DIST = xnc.hlp CLEANFILES = $(pkgdata_DATA) -mc.hlp: $(top_builddir)/doc/man/mc.1 $(srcdir)/xnc.hlp $(top_builddir)/src/man2hlp - - $(top_builddir)/src/man2hlp $(top_builddir)/doc/man/mc.1 $(srcdir)/xnc.hlp mc.hlp +mc.hlp: $(top_builddir)/doc/man/mc.1 $(srcdir)/xnc.hlp $(top_builddir)/src/man2hlp/man2hlp + - $(top_builddir)/src/man2hlp/man2hlp $(top_builddir)/doc/man/mc.1 $(srcdir)/xnc.hlp mc.hlp diff --git a/doc/hlp/es/Makefile.am b/doc/hlp/es/Makefile.am index 6aaa8ef07..d9865db3e 100644 --- a/doc/hlp/es/Makefile.am +++ b/doc/hlp/es/Makefile.am @@ -1,8 +1,9 @@ LANG=es +MAN2HLP=$(top_builddir)/src/man2hlp/man2hlp pkgdata_DATA = mc.hlp.$(LANG) EXTRA_DIST = xnc.hlp CLEANFILES = $(pkgdata_DATA) -mc.hlp.$(LANG): $(top_builddir)/doc/man/$(LANG)/mc.1 $(srcdir)/xnc.hlp $(top_builddir)/src/man2hlp - - $(top_builddir)/src/man2hlp $(top_builddir)/doc/man/$(LANG)/mc.1 $(srcdir)/xnc.hlp mc.hlp.$(LANG) +mc.hlp.$(LANG): $(top_builddir)/doc/man/$(LANG)/mc.1 $(srcdir)/xnc.hlp $(MAN2HLP) + - $(MAN2HLP) $(top_builddir)/doc/man/$(LANG)/mc.1 $(srcdir)/xnc.hlp mc.hlp.$(LANG) diff --git a/doc/hlp/hu/Makefile.am b/doc/hlp/hu/Makefile.am index efccca4f3..557fd6624 100644 --- a/doc/hlp/hu/Makefile.am +++ b/doc/hlp/hu/Makefile.am @@ -1,8 +1,9 @@ LANG=hu +MAN2HLP=$(top_builddir)/src/man2hlp/man2hlp pkgdata_DATA = mc.hlp.$(LANG) EXTRA_DIST = xnc.hlp CLEANFILES = $(pkgdata_DATA) -mc.hlp.$(LANG): $(top_builddir)/doc/man/$(LANG)/mc.1 $(srcdir)/xnc.hlp $(top_builddir)/src/man2hlp - - $(top_builddir)/src/man2hlp $(top_builddir)/doc/man/$(LANG)/mc.1 $(srcdir)/xnc.hlp mc.hlp.$(LANG) +mc.hlp.$(LANG): $(top_builddir)/doc/man/$(LANG)/mc.1 $(srcdir)/xnc.hlp $(MAN2HLP) + - $(MAN2HLP) $(top_builddir)/doc/man/$(LANG)/mc.1 $(srcdir)/xnc.hlp mc.hlp.$(LANG) diff --git a/doc/hlp/it/Makefile.am b/doc/hlp/it/Makefile.am index d64b2b564..c9639a41e 100644 --- a/doc/hlp/it/Makefile.am +++ b/doc/hlp/it/Makefile.am @@ -1,8 +1,9 @@ LANG=it +MAN2HLP=$(top_builddir)/src/man2hlp/man2hlp pkgdata_DATA = mc.hlp.$(LANG) EXTRA_DIST = xnc.hlp CLEANFILES = $(pkgdata_DATA) -mc.hlp.$(LANG): $(top_builddir)/doc/man/$(LANG)/mc.1 $(srcdir)/xnc.hlp $(top_builddir)/src/man2hlp - - $(top_builddir)/src/man2hlp $(top_builddir)/doc/man/$(LANG)/mc.1 $(srcdir)/xnc.hlp mc.hlp.$(LANG) +mc.hlp.$(LANG): $(top_builddir)/doc/man/$(LANG)/mc.1 $(srcdir)/xnc.hlp $(MAN2HLP) + - $(MAN2HLP) $(top_builddir)/doc/man/$(LANG)/mc.1 $(srcdir)/xnc.hlp mc.hlp.$(LANG) diff --git a/doc/hlp/pl/Makefile.am b/doc/hlp/pl/Makefile.am index c9526c5a0..e0251a152 100644 --- a/doc/hlp/pl/Makefile.am +++ b/doc/hlp/pl/Makefile.am @@ -1,8 +1,9 @@ LANG=pl +MAN2HLP=$(top_builddir)/src/man2hlp/man2hlp pkgdata_DATA = mc.hlp.$(LANG) EXTRA_DIST = xnc.hlp CLEANFILES = $(pkgdata_DATA) -mc.hlp.$(LANG): $(top_builddir)/doc/man/$(LANG)/mc.1 $(srcdir)/xnc.hlp $(top_builddir)/src/man2hlp - - $(top_builddir)/src/man2hlp $(top_builddir)/doc/man/$(LANG)/mc.1 $(srcdir)/xnc.hlp mc.hlp.$(LANG) +mc.hlp.$(LANG): $(top_builddir)/doc/man/$(LANG)/mc.1 $(srcdir)/xnc.hlp $(MAN2HLP) + - $(MAN2HLP) $(top_builddir)/doc/man/$(LANG)/mc.1 $(srcdir)/xnc.hlp mc.hlp.$(LANG) diff --git a/doc/hlp/ru/Makefile.am b/doc/hlp/ru/Makefile.am index 52e236dec..60c141dd2 100644 --- a/doc/hlp/ru/Makefile.am +++ b/doc/hlp/ru/Makefile.am @@ -1,8 +1,9 @@ LANG=ru +MAN2HLP=$(top_builddir)/src/man2hlp/man2hlp pkgdata_DATA = mc.hlp.$(LANG) EXTRA_DIST = xnc.hlp CLEANFILES = $(pkgdata_DATA) -mc.hlp.$(LANG): $(top_builddir)/doc/man/$(LANG)/mc.1 $(srcdir)/xnc.hlp $(top_builddir)/src/man2hlp - - $(top_builddir)/src/man2hlp $(top_builddir)/doc/man/$(LANG)/mc.1 $(srcdir)/xnc.hlp mc.hlp.$(LANG) +mc.hlp.$(LANG): $(top_builddir)/doc/man/$(LANG)/mc.1 $(srcdir)/xnc.hlp $(MAN2HLP) + - $(MAN2HLP) $(top_builddir)/doc/man/$(LANG)/mc.1 $(srcdir)/xnc.hlp mc.hlp.$(LANG) diff --git a/doc/hlp/sr/Makefile.am b/doc/hlp/sr/Makefile.am index 4204457dc..04b4277ae 100644 --- a/doc/hlp/sr/Makefile.am +++ b/doc/hlp/sr/Makefile.am @@ -1,8 +1,9 @@ LANG=sr +MAN2HLP=$(top_builddir)/src/man2hlp/man2hlp pkgdata_DATA = mc.hlp.$(LANG) EXTRA_DIST = xnc.hlp CLEANFILES = $(pkgdata_DATA) -mc.hlp.$(LANG): $(top_builddir)/doc/man/$(LANG)/mc.1 $(srcdir)/xnc.hlp $(top_builddir)/src/man2hlp - - $(top_builddir)/src/man2hlp $(top_builddir)/doc/man/$(LANG)/mc.1 $(srcdir)/xnc.hlp mc.hlp.$(LANG) +mc.hlp.$(LANG): $(top_builddir)/doc/man/$(LANG)/mc.1 $(srcdir)/xnc.hlp $(MAN2HLP) + - $(MAN2HLP) $(top_builddir)/doc/man/$(LANG)/mc.1 $(srcdir)/xnc.hlp mc.hlp.$(LANG) diff --git a/src/Makefile.am b/src/Makefile.am index 9c6657cce..3b44027f2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = viewer +SUBDIRS = man2hlp viewer if USE_EDIT SUBDIRS += editor @@ -25,16 +25,8 @@ pkglibexecdir = $(libexecdir)/@PACKAGE@ bin_PROGRAMS = mc mcmfmt -noinst_PROGRAMS = man2hlp - mcmfmt_SOURCES = mfmt.c -man2hlp_SOURCES = man2hlp.c - -man2hlp_LDADD = \ - ../lib/libmc.la \ - $(GLIB_LIBS) $(PCRE_LIBS) - if USE_EDIT EDITLIB = editor/libedit.la endif @@ -53,10 +45,9 @@ endif mc_LDADD = \ ../lib/libmc.la \ viewer/libmcviewer.la \ - $(EDITLIB) \ - $(DIFFLIB) \ - $(INTLLIBS) $(MCLIBS) $(SLANGLIB) $(LIBICONV) \ - $(GLIB_LIBS) $(PCRE_LIBS) + $(MCLIBS) $(DIFFLIB) $(EDITLIB) $(SLANGLIB) \ + $(GLIB_LIBS) $(PCRE_LIBS) \ + $(LIBICONV) $(INTLLIBS) if USE_SAMBA_FS # this is a hack for linking with own samba library in simple way @@ -115,14 +106,17 @@ mc_SOURCES = \ listmode.c listmode.h \ main.c main.h \ main-widgets.h \ - mountlist.c mountlist.h \ panelize.c panelize.h \ subshell.c subshell.h \ textconf.c textconf.h \ treestore.c treestore.h \ user.c user.h -EXTRA_DIST = man2hlp.c $(SRC_maintainer) $(SRC_charset) +#if USE_MOUNTLIST +mc_SOURCES += mountlist.c mountlist.h +#endif + +EXTRA_DIST = $(SRC_maintainer) $(SRC_charset) # end of automated testing diff --git a/src/man2hlp/Makefile.am b/src/man2hlp/Makefile.am new file mode 100644 index 000000000..7fe483604 --- /dev/null +++ b/src/man2hlp/Makefile.am @@ -0,0 +1,6 @@ +noinst_PROGRAMS = man2hlp + +man2hlp_SOURCES = man2hlp.c +man2hlp_LDADD = \ + ../../lib/libmc.la \ + $(GLIB_LIBS) $(PCRE_LIBS) diff --git a/src/man2hlp.c b/src/man2hlp/man2hlp.c similarity index 99% rename from src/man2hlp.c rename to src/man2hlp/man2hlp.c index e7066fbc7..ab8a7ebac 100644 --- a/src/man2hlp.c +++ b/src/man2hlp/man2hlp.c @@ -32,7 +32,7 @@ #include -#include "help.h" +#include "../help.h" #define BUFFER_SIZE 256 From d523d6e531f061cb9fbe8de4724f6579c8086dc3 Mon Sep 17 00:00:00 2001 From: Slava Zanko Date: Tue, 11 May 2010 17:24:25 +0300 Subject: [PATCH 02/11] Replace man2hlp (from C to perl) Signed-off-by: Slava Zanko --- configure.ac | 8 + src/man2hlp/Makefile.am | 7 +- src/man2hlp/man2hlp.c | 1029 --------------------------------------- src/man2hlp/man2hlp.in | 911 ++++++++++++++++++++++++++++++++++ 4 files changed, 920 insertions(+), 1035 deletions(-) delete mode 100644 src/man2hlp/man2hlp.c create mode 100644 src/man2hlp/man2hlp.in diff --git a/configure.ac b/configure.ac index 7175e76e5..c600ae161 100644 --- a/configure.ac +++ b/configure.ac @@ -569,6 +569,14 @@ AM_CONDITIONAL(ENABLE_MCSERVER, [test x"$enable_mcserver" = "xyes"]) AM_CONDITIONAL(CHARSET, [test -n "$have_charset"]) AM_CONDITIONAL(CONS_SAVER, [test -n "$cons_saver"]) +AC_CONFIG_FILES( +[ +src/man2hlp/man2hlp +], +[ +chmod +x src/man2hlp/man2hlp +]) + AC_CONFIG_FILES([ Makefile diff --git a/src/man2hlp/Makefile.am b/src/man2hlp/Makefile.am index 7fe483604..4ed83c63a 100644 --- a/src/man2hlp/Makefile.am +++ b/src/man2hlp/Makefile.am @@ -1,6 +1 @@ -noinst_PROGRAMS = man2hlp - -man2hlp_SOURCES = man2hlp.c -man2hlp_LDADD = \ - ../../lib/libmc.la \ - $(GLIB_LIBS) $(PCRE_LIBS) +noinst_SCRIPTS = man2hlp diff --git a/src/man2hlp/man2hlp.c b/src/man2hlp/man2hlp.c deleted file mode 100644 index ab8a7ebac..000000000 --- a/src/man2hlp/man2hlp.c +++ /dev/null @@ -1,1029 +0,0 @@ -/* Man page to help file converter - Copyright (C) 1994, 1995, 1998, 2000, 2001, 2002, 2003, 2004, 2005, - 2007 Free Software Foundation, Inc. - 2002 Andrew V. Samoilov - 2002 Pavel Roskin - 2010 Andrew Borodin - - This program 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 2 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ - -/** \file man2hlp.c - * \brief Source: man page to help file converter - */ - -#include - -#include -#include -#include -#include - -#include - -#include "../help.h" - -#define BUFFER_SIZE 256 - -static int col = 0; /* Current output column */ -static int out_row = 1; /* Current output row */ -static int in_row = 0; /* Current input row */ -static int no_split_flag = 0; /* Flag: Don't split section on next ".SH" */ -static int skip_flag = 0; /* Flag: Skip this section. - 0 = don't skip, - 1 = skipping title, - 2 = title skipped, skipping text */ -static int link_flag = 0; /* Flag: Next line is a link */ -static int verbatim_flag = 0; /* Flag: Copy input to output verbatim */ -static int node = 0; /* Flag: This line is an original ".SH" */ - -static const char *c_out; /* Output filename */ -static FILE *f_out; /* Output file */ - -static const char *c_in; /* Current input filename */ - -static int indentation; /* Indentation level, n spaces */ -static int tp_flag; /* Flag: .TP paragraph - 1 = this line is .TP label, - 2 = first line of label description. */ -static char *topics = NULL; - -struct node -{ - char *node; /* Section name */ - char *lname; /* Translated .SH, NULL if not translated */ - struct node *next; - int heading_level; -}; - -static struct node nodes; -static struct node *cnode; /* Current node */ - -#define MAX_STREAM_BLOCK 8192 - -/* - * Read in blocks of reasonable size and make sure we read everything. - * Failure to read everything is an error, indicated by returning 0. - */ -static size_t -persistent_fread (void *data, size_t len, FILE * stream) -{ - size_t count; - size_t bytes_done = 0; - char *ptr = (char *) data; - - if (len <= 0) - return 0; - - while (bytes_done < len) - { - count = len - bytes_done; - if (count > MAX_STREAM_BLOCK) - count = MAX_STREAM_BLOCK; - - count = fread (ptr, 1, count, stream); - - if (count <= 0) - return 0; - - bytes_done += count; - ptr += count; - } - - return bytes_done; -} - -/* - * Write in blocks of reasonable size and make sure we write everything. - * Failure to write everything is an error, indicated by returning 0. - */ -static size_t -persistent_fwrite (const void *data, size_t len, FILE * stream) -{ - size_t count; - size_t bytes_done = 0; - const char *ptr = (const char *) data; - - if (len <= 0) - return 0; - - while (bytes_done < len) - { - count = len - bytes_done; - if (count > MAX_STREAM_BLOCK) - count = MAX_STREAM_BLOCK; - - count = fwrite (ptr, 1, count, stream); - - if (count <= 0) - return 0; - - bytes_done += count; - ptr += count; - } - - return bytes_done; -} - -/* Report error in input */ -static void -print_error (const char *message) -{ - fprintf (stderr, "man2hlp: %s in file \"%s\" on line %d\n", message, c_in, in_row); -} - -/* Do fopen(), exit if it fails */ -static FILE * -fopen_check (const char *filename, const char *flags) -{ - char tmp[BUFFER_SIZE]; - FILE *f; - - f = fopen (filename, flags); - if (f == NULL) - { - g_snprintf (tmp, sizeof (tmp), "man2hlp: Cannot open file \"%s\"", filename); - perror (tmp); - exit (3); - } - - return f; -} - -/* Do fclose(), exit if it fails */ -static void -fclose_check (FILE * f) -{ - if (ferror (f)) - { - perror ("man2hlp: File error"); - exit (3); - } - - if (fclose (f)) - { - perror ("man2hlp: Cannot close file"); - exit (3); - } -} - -/* Change output line */ -static void -newline (void) -{ - out_row++; - col = 0; - fprintf (f_out, "\n"); -} - -/* Calculate the length of string */ -static int -string_len (const char *buffer) -{ - static int anchor_flag = 0; /* Flag: Inside hypertext anchor name */ - static int lc_link_flag = 0; /* Flag: Inside hypertext link target name */ - int backslash_flag = 0; /* Flag: Backslash quoting */ - int c; /* Current character */ - int len = 0; /* Result: the length of the string */ - - while (*(buffer)) - { - c = *buffer++; - if (c == CHAR_LINK_POINTER) - lc_link_flag = 1; /* Link target name starts */ - else if (c == CHAR_LINK_END) - lc_link_flag = 0; /* Link target name ends */ - else if (c == CHAR_NODE_END) - { - /* Node anchor name starts */ - anchor_flag = 1; - /* Ugly hack to prevent loss of one space */ - len++; - } - /* Don't add control characters to the length */ - if (c >= 0 && c < 32) - continue; - /* Attempt to handle backslash quoting */ - if (c == '\\' && !backslash_flag) - { - backslash_flag = 1; - continue; - } - backslash_flag = 0; - /* Increase length if not inside anchor name or link target name */ - if (!anchor_flag && !lc_link_flag) - len++; - if (anchor_flag && c == ']') - { - /* Node anchor name ends */ - anchor_flag = 0; - } - } - return len; -} - -/* Output the string */ -static void -print_string (char *buffer) -{ - int len; /* The length of current word */ - int c; /* Current character */ - int backslash_flag = 0; - - /* Skipping lines? */ - if (skip_flag) - return; - /* Copying verbatim? */ - if (verbatim_flag) - { - /* Attempt to handle backslash quoting */ - while (*(buffer)) - { - c = *buffer++; - if (c == '\\' && !backslash_flag) - { - backslash_flag = 1; - continue; - } - backslash_flag = 0; - fputc (c, f_out); - } - } - else - { - /* Split into words */ - buffer = strtok (buffer, " \t\n"); - /* Repeat for each word */ - while (buffer) - { - /* Skip empty strings */ - if (*(buffer)) - { - len = string_len (buffer); - /* Words are separated by spaces */ - if (col > 0) - { - fputc (' ', f_out); - col++; - } - else if (indentation) - { - while (col++ < indentation) - fputc (' ', f_out); - } - /* Attempt to handle backslash quoting */ - while (*(buffer)) - { - c = *buffer++; - if (c == '\\' && !backslash_flag) - { - backslash_flag = 1; - continue; - } - backslash_flag = 0; - fputc (c, f_out); - } - /* Increase column */ - col += len; - } - /* Get the next word */ - buffer = strtok (NULL, " \t\n"); - } /* while */ - } -} - -/* Like print_string but with printf-like syntax */ -static void -printf_string (const char *format, ...) -{ - va_list args; - char buffer[BUFFER_SIZE]; - - va_start (args, format); - g_vsnprintf (buffer, sizeof (buffer), format, args); - va_end (args); - print_string (buffer); -} - -/* Handle NODE and .SH commands. is_sh is 1 for .SH, 0 for NODE */ -static void -handle_node (char *buffer, int is_sh) -{ - int len, heading_level; - - /* If we already skipped a section, don't skip another */ - if (skip_flag == 2) - { - skip_flag = 0; - } - /* Get the command parameters */ - buffer = strtok (NULL, ""); - if (buffer == NULL) - { - print_error ("Syntax error: .SH: no title"); - return; - } - else - { - /* Remove quotes */ - if (buffer[0] == '"') - { - buffer++; - len = strlen (buffer); - if (buffer[len - 1] == '"') - { - len--; - buffer[len] = 0; - } - } - /* Calculate heading level */ - heading_level = 0; - while (buffer[heading_level] == ' ') - heading_level++; - /* Heading level must be even */ - if (heading_level & 1) - print_error ("Syntax error: .SH: odd heading level"); - if (no_split_flag) - { - /* Don't start a new section */ - newline (); - print_string (buffer); - newline (); - newline (); - no_split_flag = 0; - } - else if (skip_flag) - { - /* Skipping title and marking text for skipping */ - skip_flag = 2; - } - else - { - buffer += heading_level; - if (!is_sh || !node) - { - /* Start a new section, but omit empty section names */ - if (*buffer) - { - fprintf (f_out, "%c[%s]", CHAR_NODE_END, buffer); - newline (); - } - - /* Add section to the linked list */ - if (!cnode) - { - cnode = &nodes; - } - else - { - cnode->next = malloc (sizeof (nodes)); - cnode = cnode->next; - } - cnode->node = strdup (buffer); - cnode->lname = NULL; - cnode->next = NULL; - cnode->heading_level = heading_level; - } - if (is_sh) - { - /* print_string() strtok()es buffer, so */ - cnode->lname = strdup (buffer); - print_string (buffer); - newline (); - newline (); - } - } /* Start new section */ - } /* Has parameters */ - node = !is_sh; -} - -/* Convert character from the macro name to the font marker */ -static inline char -char_to_font (char c) -{ - switch (c) - { - case 'R': - return CHAR_FONT_NORMAL; - case 'B': - return CHAR_FONT_BOLD; - case 'I': - return CHAR_FONT_ITALIC; - default: - return 0; - } -} - -/* - * Handle alternate font commands (.BR, .IR, .RB, .RI, .BI, .IB) - * Return 0 if the command wasn't recognized, 1 otherwise - */ -static int -handle_alt_font (char *buffer) -{ - char *p; - char *w; - char font[2]; - int in_quotes = 0; - int alt_state = 0; - - if (strlen (buffer) != 3) - return 0; - - if (buffer[0] != '.') - return 0; - - font[0] = char_to_font (buffer[1]); - font[1] = char_to_font (buffer[2]); - - /* Exclude names with unknown characters, .BB, .II and .RR */ - if (font[0] == 0 || font[1] == 0 || font[0] == font[1]) - return 0; - - p = strtok (NULL, ""); - if (p == NULL) - { - return 1; - } - - w = buffer; - *w++ = font[0]; - - while (*p) - { - - if (*p == '"') - { - in_quotes = !in_quotes; - p++; - continue; - } - - if (*p == ' ' && !in_quotes) - { - p++; - /* Don't change font if we are at the end */ - if (*p != 0) - { - alt_state = !alt_state; - *w++ = font[alt_state]; - } - - /* Skip more spaces */ - while (*p == ' ') - p++; - - continue; - } - - *w++ = *p++; - } - - /* Turn off attributes if necessary */ - if (font[alt_state] != CHAR_FONT_NORMAL) - *w++ = CHAR_FONT_NORMAL; - - *w = 0; - print_string (buffer); - - return 1; -} - -/* Handle .IP and .TP commands. is_tp is 1 for .TP, 0 for .IP */ -static void -handle_tp_ip (int is_tp) -{ - if (col > 0) - newline (); - newline (); - if (is_tp) - { - tp_flag = 1; - indentation = 0; - } - else - indentation = 8; -} - -/* Handle all the roff dot commands. See man groff_man for details */ -static void -handle_command (char *buffer) -{ - int len; - - /* Get the command name */ - strtok (buffer, " \t"); - - if (strcmp (buffer, ".SH") == 0) - { - indentation = 0; - handle_node (buffer, 1); - } - else if (strcmp (buffer, ".\\\"NODE") == 0) - { - handle_node (buffer, 0); - } - else if (strcmp (buffer, ".\\\"DONT_SPLIT\"") == 0) - { - no_split_flag = 1; - } - else if (strcmp (buffer, ".\\\"SKIP_SECTION\"") == 0) - { - skip_flag = 1; - } - else if (strcmp (buffer, ".\\\"LINK2\"") == 0) - { - /* Next two input lines form a link */ - link_flag = 2; - } - else if ((strcmp (buffer, ".PP") == 0) - || (strcmp (buffer, ".P") == 0) || (strcmp (buffer, ".LP") == 0)) - { - indentation = 0; - /* End of paragraph */ - if (col > 0) - newline (); - newline (); - } - else if (strcmp (buffer, ".nf") == 0) - { - /* Following input lines are to be handled verbatim */ - verbatim_flag = 1; - if (col > 0) - newline (); - } - else if (strcmp (buffer, ".I") == 0 || strcmp (buffer, ".B") == 0 - || strcmp (buffer, ".SB") == 0) - { - /* Bold text or italics text */ - char *p; - char *w; - int backslash_flag = 0; - - /* .SB [text] - * Causes the text on the same line or the text on the - * next line to appear in boldface font, one point - * size smaller than the default font. - */ - - /* FIXME: text is optional, so there is no error */ - p = strtok (NULL, ""); - if (p == NULL) - { - print_error ("Syntax error: .I | .B | .SB : no text"); - return; - } - - *buffer = (buffer[1] == 'I') ? CHAR_FONT_ITALIC : CHAR_FONT_BOLD; - - /* Attempt to handle backslash quoting */ - for (w = &buffer[1]; *p; p++) - { - if (*p == '\\' && !backslash_flag) - { - backslash_flag = 1; - continue; - } - backslash_flag = 0; - *w++ = *p; - } - - *w++ = CHAR_FONT_NORMAL; - *w = 0; - print_string (buffer); - } - else if (strcmp (buffer, ".TP") == 0) - { - handle_tp_ip (1); - } - else if (strcmp (buffer, ".IP") == 0) - { - handle_tp_ip (0); - } - else if (strcmp (buffer, ".\\\"TOPICS") == 0) - { - if (out_row > 1) - { - print_error ("Syntax error: .\\\"TOPICS must be first command"); - return; - } - buffer = strtok (NULL, ""); - if (buffer == NULL) - { - print_error ("Syntax error: .\\\"TOPICS: no text"); - return; - } - /* Remove quotes */ - if (buffer[0] == '"') - { - buffer++; - len = strlen (buffer); - if (buffer[len - 1] == '"') - { - len--; - buffer[len] = 0; - } - } - topics = strdup (buffer); - } - else if (strcmp (buffer, ".br") == 0) - { - if (col) - newline (); - } - else if (strncmp (buffer, ".\\\"", 3) == 0) - { - /* Comment */ - } - else if (strcmp (buffer, ".TH") == 0) - { - /* Title header */ - } - else if (strcmp (buffer, ".SM") == 0) - { - /* Causes the text on the same line or the text on the - * next line to appear in a font that is one point - * size smaller than the default font. */ - buffer = strtok (NULL, ""); - if (buffer) - print_string (buffer); - } - else if (handle_alt_font (buffer) == 1) - { - return; - } - else - { - /* Other commands are ignored */ - char warn_str[BUFFER_SIZE]; - g_snprintf (warn_str, sizeof (warn_str), "Warning: unsupported command %s", buffer); - print_error (warn_str); - return; - } -} - -static struct links -{ - char *linkname; /* Section name */ - int line; /* Input line in ... */ - const char *filename; - struct links *next; -} links, *current_link; - -static void -handle_link (char *buffer) -{ - static char old[80]; - int len; - char *amp; - const char *amp_arg; - - switch (link_flag) - { - case 1: - /* Old format link, not supported */ - break; - case 2: - /* First part of new format link */ - /* Bold text or italics text */ - if (buffer[0] == '.' && (buffer[1] == 'I' || buffer[1] == 'B')) - for (buffer += 2; *buffer == ' ' || *buffer == '\t'; buffer++); - g_strlcpy (old, buffer, sizeof (old)); - link_flag = 3; - break; - case 3: - /* Second part of new format link */ - if (buffer[0] == '.') - buffer++; - if (buffer[0] == '\\') - buffer++; - if (buffer[0] == '"') - buffer++; - len = strlen (buffer); - if (len && buffer[len - 1] == '"') - { - buffer[--len] = 0; - } - - /* "Layout\&)," -- "Layout" should be highlighted, but not ")," */ - amp = strstr (old, "\\&"); - if (amp) - { - *amp = 0; - amp += 2; - amp_arg = amp; - } - else - { - amp_arg = ""; - } - - printf_string ("%c%s%c%s%c%s\n", CHAR_LINK_START, old, - CHAR_LINK_POINTER, buffer, CHAR_LINK_END, amp_arg); - link_flag = 0; - /* Add to the linked list */ - if (current_link) - { - current_link->next = malloc (sizeof (links)); - current_link = current_link->next; - current_link->next = NULL; - } - else - { - current_link = &links; - } - current_link->linkname = strdup (buffer); - current_link->filename = c_in; - current_link->line = in_row; - break; - } -} - -int -main (int argc, char **argv) -{ - int len; /* Length of input line */ - const char *c_man; /* Manual filename */ - const char *c_tmpl; /* Template filename */ - FILE *f_man; /* Manual file */ - FILE *f_tmpl; /* Template file */ - char buffer[BUFFER_SIZE]; /* Full input line */ - char *lc_node = NULL; - char *outfile_buffer; /* Large buffer to keep the output file */ - long cont_start; /* Start of [Contents] */ - long file_end; /* Length of the output file */ - - /* Validity check for arguments */ - if (argc != 4) - { - fprintf (stderr, "Usage: man2hlp file.man template_file helpfile\n"); - return 3; - } - - c_man = argv[1]; - c_tmpl = argv[2]; - c_out = argv[3]; - - /* First stage - process the manual, write to the output file */ - f_man = fopen_check (c_man, "r"); - f_out = fopen_check (c_out, "w"); - c_in = c_man; - - /* Repeat for each input line */ - while (fgets (buffer, BUFFER_SIZE, f_man)) - { - char *input_line; /* Input line without initial "\&" */ - - if (buffer[0] == '\\' && buffer[1] == '&') - input_line = buffer + 2; - else - input_line = buffer; - - in_row++; - len = strlen (input_line); - /* Remove terminating newline */ - if (input_line[len - 1] == '\n') - { - len--; - input_line[len] = 0; - } - - if (verbatim_flag) - { - /* Copy the line verbatim */ - if (strcmp (input_line, ".fi") == 0) - { - verbatim_flag = 0; - } - else - { - print_string (input_line); - newline (); - } - } - else if (link_flag) - { - /* The line is a link */ - handle_link (input_line); - } - else if (buffer[0] == '.') - { - /* The line is a roff command */ - handle_command (input_line); - } - else - { - /* A normal line, just output it */ - print_string (input_line); - } - /* .TP label processed as usual line */ - if (tp_flag) - { - if (tp_flag == 1) - { - tp_flag = 2; - } - else - { - tp_flag = 0; - indentation = 8; - if (col >= indentation) - newline (); - else - while (++col < indentation) - fputc (' ', f_out); - } - } - } - - newline (); - fclose_check (f_man); - /* First stage ends here, closing the manual */ - - /* Second stage - process the template file */ - f_tmpl = fopen_check (c_tmpl, "r"); - c_in = c_tmpl; - - /* Repeat for each input line */ - /* Read a line */ - while (fgets (buffer, BUFFER_SIZE, f_tmpl)) - { - if (lc_node) - { - if (*buffer && *buffer != '\n') - { - cnode->lname = strdup (buffer); - lc_node = strchr (cnode->lname, '\n'); - if (lc_node) - *lc_node = 0; - } - lc_node = NULL; - } - else - { - lc_node = strchr (buffer, CHAR_NODE_END); - if (lc_node && (lc_node[1] == '[')) - { - char *p = strchr (lc_node, ']'); - if (p) - { - if (strncmp (lc_node + 1, "[main]", 6) == 0) - { - lc_node = NULL; - } - else - { - if (!cnode) - { - cnode = &nodes; - } - else - { - cnode->next = malloc (sizeof (nodes)); - cnode = cnode->next; - } - cnode->node = strdup (lc_node + 2); - cnode->node[p - lc_node - 2] = 0; - cnode->lname = NULL; - cnode->next = NULL; - cnode->heading_level = 0; - } - } - else - lc_node = NULL; - } - else - lc_node = NULL; - } - fputs (buffer, f_out); - } - - cont_start = ftell (f_out); - if (cont_start <= 0) - { - perror (c_out); - return 1; - } - - if (topics) - fprintf (f_out, "\004[Contents]\n%s\n\n", topics); - else - fprintf (f_out, "\004[Contents]\n"); - - for (current_link = &links; current_link && current_link->linkname;) - { - int found = 0; - struct links *next = current_link->next; - - if (strcmp (current_link->linkname, "Contents") == 0) - { - found = 1; - } - else - { - for (cnode = &nodes; cnode && cnode->node; cnode = cnode->next) - { - if (strcmp (cnode->node, current_link->linkname) == 0) - { - found = 1; - break; - } - } - } - if (!found) - { - g_snprintf (buffer, sizeof (buffer), "Stale link \"%s\"", current_link->linkname); - c_in = current_link->filename; - in_row = current_link->line; - print_error (buffer); - } - free (current_link->linkname); - if (current_link != &links) - free (current_link); - current_link = next; - } - - for (cnode = &nodes; cnode && cnode->node;) - { - struct node *next = cnode->next; - lc_node = cnode->node; - - if (*lc_node) - fprintf (f_out, " %*s\001%s\002%s\003", cnode->heading_level, - "", cnode->lname ? cnode->lname : lc_node, lc_node); - fprintf (f_out, "\n"); - - free (cnode->node); - if (cnode->lname) - free (cnode->lname); - if (cnode != &nodes) - free (cnode); - cnode = next; - } - - file_end = ftell (f_out); - - /* Sanity check */ - if ((file_end <= 0) || (file_end - cont_start <= 0)) - { - perror (c_out); - return 1; - } - - fclose_check (f_out); - fclose_check (f_tmpl); - /* Second stage ends here, closing all files, note the end of output */ - - /* - * Third stage - swap two parts of the output file. - * First, open the output file for reading and load it into the memory. - */ - f_out = fopen_check (c_out, "r"); - - outfile_buffer = malloc (file_end); - if (!outfile_buffer) - return 1; - - if (!persistent_fread (outfile_buffer, file_end, f_out)) - { - perror (c_out); - return 1; - } - - fclose_check (f_out); - /* Now the output file is in the memory */ - - /* Again open output file for writing */ - f_out = fopen_check (c_out, "w"); - - /* Write part after the "Contents" node */ - if (!persistent_fwrite (outfile_buffer + cont_start, file_end - cont_start, f_out)) - { - perror (c_out); - return 1; - } - - /* Write part before the "Contents" node */ - if (!persistent_fwrite (outfile_buffer, cont_start, f_out)) - { - perror (c_out); - return 1; - } - - free (outfile_buffer); - fclose_check (f_out); - /* Closing everything */ - - return 0; -} diff --git a/src/man2hlp/man2hlp.in b/src/man2hlp/man2hlp.in new file mode 100644 index 000000000..7652ba8d6 --- /dev/null +++ b/src/man2hlp/man2hlp.in @@ -0,0 +1,911 @@ +#! @PERL@ -w +# +# Man page to help file converter +# Copyright (C) 1994, 1995, 1998, 2000, 2001, 2002, 2003, 2004, 2005, +# 2007, 2010 Free Software Foundation, Inc. +# +# Originally written by: +# 2002 Andrew V. Samoilov +# 2002 Pavel Roskin +# 2010 Andrew Borodin +# Completely rewriten on perl by: +# 2010 Alexandr Prenko +# +# This program 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 2 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, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +# +# \file man2hlp.c +# \brief Source: man page to help file converter + +# include "help.h" +# end of include "help.h" + +use strict; +use warnings; + +# Perl have no static variables, so this hash emulates them +my %static = ( + "string_len anchor_flag" => 0, + "string_len lc_link_flag" => 0, + "handle_link old" => undef +); + +# Imported constants +my $CHAR_LINK_START = chr(01); # Ctrl-A +my $CHAR_LINK_POINTER = chr(02); # Ctrl-B +my $CHAR_LINK_END = chr(03); # Ctrl-C +my $CHAR_NODE_END = chr(04); # Ctrl-D +my $CHAR_ALTERNATE = chr(05); # Ctrl-E +my $CHAR_NORMAL = chr(06); # Ctrl-F +my $CHAR_VERSION = chr(07); # Ctrl-G +my $CHAR_FONT_BOLD = chr(010); # Ctrl-H +my $CHAR_FONT_NORMAL = chr(013); # Ctrl-K +my $CHAR_FONT_ITALIC = chr(024); # Ctrl-T +# end of import + +my $col = 0; # Current output column +my $out_row = 1; # Current output row +my $in_row = 0; # Current input row +my $no_split_flag = 0; # Flag: Don't split section on next ".SH" +my $skip_flag = 0; # Flag: Skip this section. + # 0 = don't skip, + # 1 = skipping title, + # 2 = title skipped, skipping text +my $link_flag = 0; # Flag: Next line is a link +my $verbatim_flag = 0; # Flag: Copy input to output verbatim +my $node = 0; # Flag: This line is an original ".SH" + +my $c_out; # Output filename +my $f_out; # Output file + +my $c_in; # Current input filename + +my $indentation; # Indentation level, n spaces +my $tp_flag; # Flag: .TP paragraph + # 1 = this line is .TP label, + # 2 = first line of label description. +my $topics = undef; + +# Emulate C strtok() +my $strtok; + +sub strtok($$) { + my ($str, $chars) = @_; + + if (! defined $chars || $chars eq "") + { + my $result = $strtok; + $strtok = undef; + return $result; + } + + $str = $strtok unless defined $str; + return undef unless defined $str; + + my $result; + $str =~ s/^[$chars]+//; + ($result, $strtok) = split /[$chars]+/, $str, 2; + ($result, $strtok) = split /[$chars]+/, $strtok, 2 if defined $result && $result eq ""; + $strtok = undef if ! defined $strtok || $strtok eq ""; + return $result; +} + +# Attempt to handle backslash quoting +sub handle_backslash($) +{ + my ($s) = @_; + my $backslash_flag = 0; + my $result = ''; + foreach my $c (split //, $s) + { + if ($c eq '\\' && ! $backslash_flag) + { + $backslash_flag = 1; + next; + } + $backslash_flag = 0; + $result .= $c; + } + return $result; +} + +sub struct_node() { + return { + "node" => undef, # Section name + "lname" => undef, # Translated .SH, undef if not translated + "next" => undef, + "heading_level" => undef + } +} + +my $nodes = struct_node(); +my $cnode; # Current node + +# Report error in input +sub print_error($) +{ + my ($message) = @_; + warn sprintf "man2hlp: %s in file \"%s\" on line %d\n", $message, $c_in, $in_row; +} + +# Do open, exit if it fails +sub fopen_check ($$) +{ + my ($mode, $filename) = @_; + my $f; + + unless (open $f, $mode, $filename) + { + warn sprintf("man2hlp: Cannot open file \"%s\" ($!)\n", $filename); + exit 3; + } + return $f; +} + +# Do close, exit if it fails +sub fclose_check($) +{ + my ($f) = @_; + unless (close $f) + { + warn "man2hlp: Cannot close file ($!)\n"; + exit 3; + } +} + +# Change output line +sub newline() +{ + $out_row++; + $col = 0; + print $f_out "\n"; +} + +# Calculate the length of string +sub string_len +{ + my ($buffer) = @_; + my $anchor_flag = \$static{"string_len anchor_flag"}; # Flag: Inside hypertext anchor name ho4u_v_Ariom + my $lc_link_flag = \$static{"string_len lc_link_flag"}; # Flag: Inside hypertext link target name + my $backslash_flag = 0; # Flag: Backslash quoting + my $len = 0; # Result: the length of the string + + + foreach my $c (split //, $buffer) + { + if ($c eq $CHAR_LINK_POINTER) + { + $$lc_link_flag = 1; # Link target name starts + } + elsif ($c eq $CHAR_LINK_END) + { + $$lc_link_flag = 0; # Link target name ends + } + elsif ($c eq $CHAR_NODE_END) + { + # Node anchor name starts + $$anchor_flag = 1; + # Ugly hack to prevent loss of one space + $len++; + } + # Don't add control characters to the length + next if ord($c) >= 0 && ord($c) < 32; + # Attempt to handle backslash quoting + if ($c eq '\\' && !$backslash_flag) + { + $backslash_flag = 1; + next; + } + $backslash_flag = 0; + # Increase length if not inside anchor name or link target name + $len++ if !$$anchor_flag && !$$lc_link_flag; + if ($$anchor_flag && $c eq ']') + { + # Node anchor name ends + $$anchor_flag = 0; + } + } + return $len; +} + +# Output the string +sub print_string($) +{ + my ($buffer) = @_; + my $len; # The length of current word + my $c; # Current character + my $backslash_flag = 0; + + # Skipping lines? + return if $skip_flag; + # Copying verbatim? + if ($verbatim_flag) + { + # Attempt to handle backslash quoting + $buffer = handle_backslash $buffer; + print $f_out $buffer; + } + else + { + # Split into words + $buffer = strtok($buffer, " \t\n"); + # Repeat for each word + while (defined $buffer) + { + # Skip empty strings + if ($buffer ne '') + { + $len = length($buffer); + # Words are separated by spaces + if ($col > 0) + { + print $f_out ' '; + $col++; + } + elsif ($indentation) + { + print $f_out ' ' while $col++ < $indentation; + } + # Attempt to handle backslash quoting + $buffer = handle_backslash $buffer; + print $f_out $buffer; + # Increase column + $col += $len; + } + # Get the next word + $buffer = strtok(undef, " \t\n"); + } # while + } +} + +# Like print_string but with printf-like syntax +sub printf_string +{ + print_string sprintf shift, @_; +} + +# Handle NODE and .SH commands. is_sh is 1 for .SH, 0 for NODE +# FIXME: Consider to remove first parameter +sub handle_node($$) +{ + my ($buffer, $is_sh) = @_; + my ($len, $heading_level); + + # If we already skipped a section, don't skip another + $skip_flag = 0 if $skip_flag == 2; + + # Get the command parameters + $buffer = strtok(undef, ""); + if (! defined $buffer) + { + print_error "Syntax error: .SH: no title"; + return; + } + else + { + # Remove quotes + $buffer =~ s/^"// and $buffer =~ s/"$//; + # Calculate heading level + $heading_level = 0; + $heading_level++ while substr($buffer, $heading_level, 1) eq ' '; + # Heading level must be even + unless ($heading_level % 2) + { + print_error "Syntax error: .SH: odd heading level"; + } + if ($no_split_flag) + { + # Don't start a new section + newline; + print_string $buffer; + newline; + newline; + $no_split_flag = 0; + } + elsif ($skip_flag) + { + # Skipping title and marking text for skipping + $skip_flag = 2; + } + else + { + $buffer = substr($buffer, $heading_level); + if (! $is_sh || ! $node) + { + # Start a new section, but omit empty section names + if ($buffer ne '') + { + printf $f_out "%s[%s]", $CHAR_NODE_END, $buffer; + newline; + } + + # Add section to the linked list + if (! defined $cnode) + { + $cnode = $nodes; + } + else + { + $cnode->{'next'} = struct_node(); + $cnode = $cnode->{'next'}; + } + $cnode->{'node'} = $buffer; + $cnode->{'lname'} = undef; + $cnode->{'next'} = undef; + $cnode->{'heading_level'} = $heading_level; + } + if ($is_sh) + { + $cnode->{'lname'} = $buffer; + print_string $buffer; + newline; + newline; + } + } # Start new section + } # Has parameters + $node = ! $is_sh; +} + +# Convert character from the macro name to the font marker +sub char_to_font($) +{ + my ($c) = @_; + my %font = ( + 'R' => $CHAR_FONT_NORMAL, + 'B' => $CHAR_FONT_BOLD, + 'I' => $CHAR_FONT_ITALIC + ); + return exists $font{$c} ? $font{$c} : chr(0); +} + +# +# Handle alternate font commands (.BR, .IR, .RB, .RI, .BI, .IB) +# Return 0 if the command wasn't recognized, 1 otherwise +# +sub handle_alt_font($) +{ + my ($buffer) = @_; + my $in_quotes = 0; + my $alt_state = 0; + + return 0 if length($buffer) != 3; + return 0 if substr($buffer, 0, 1) ne '.'; + + my @font = ( + char_to_font substr($buffer, 1, 1), + char_to_font substr($buffer, 2, 1) + ); + + # Exclude names with unknown characters, .BB, .II and .RR + if ($font[0] eq chr(0) || $font[1] eq chr(0) || $font[0] eq $font[1]) + { + return 0; + } + + my $p = strtok(undef, ""); + return 1 unless defined $p; + + $buffer = $font[0]; + + my @p = split //, $p; + while (@p) + { + + if ($p[0] eq '"') + { + $in_quotes = !$in_quotes; + shift @p; + next; + } + + if ($p[0] eq ' ' && !$in_quotes) + { + shift @p; + # Don't change font if we are at the end + if ($#p) + { + $alt_state = $alt_state ? 0 : 1; + $buffer .= $font[$alt_state]; + } + + # Skip more spaces + shift @p while $p[0] eq ' '; + + next; + } + + $buffer .= shift @p; + } + + # Turn off attributes if necessary + if ($font[$alt_state] ne $CHAR_FONT_NORMAL) + { + $buffer .= $CHAR_FONT_NORMAL; + } + + print_string $buffer; + + return 1; +} + +# Handle .IP and .TP commands. is_tp is 1 for .TP, 0 for .IP */ +sub handle_tp_ip($) +{ + my ($is_tp) = @_; + newline if $col > 0; + newline; + if ($is_tp) + { + $tp_flag = 1; + $indentation = 0; + } + else + { + $indentation = 8; + } +} + +# Handle all the roff dot commands. See man groff_man for details +sub handle_command($) +{ + my ($buffer) = @_; + my $len; + + # Get the command name + $buffer = strtok($buffer, " \t"); + + if ($buffer eq ".SH") + { + $indentation = 0; + handle_node $buffer, 1; + } + elsif ($buffer eq ".\\\"NODE") + { + handle_node $buffer, 0; + } + elsif ($buffer eq ".\\\"DONT_SPLIT\"") + { + $no_split_flag = 1; + } + elsif ($buffer eq ".\\\"SKIP_SECTION\"") + { + $skip_flag = 1; + } + elsif ($buffer eq ".\\\"LINK2\"") + { + # Next two input lines form a link + $link_flag = 2; + } + elsif ($buffer eq ".PP" || $buffer eq ".P" || $buffer eq ".LP") + { + $indentation = 0; + # End of paragraph + newline if $col > 0; + newline; + } + elsif ($buffer eq ".nf") + { + # Following input lines are to be handled verbatim + $verbatim_flag = 1; + newline if $col > 0; + } + elsif ($buffer eq ".I" || $buffer eq ".B" || $buffer eq ".SB") + { + # Bold text or italics text + + # .SB [text] + # Causes the text on the same line or the text on the + # next line to appear in boldface font, one point + # size smaller than the default font. + # + + # FIXME: text is optional, so there is no error + my $p = strtok(undef, ""); + if (! defined $p) + { + print_error "Syntax error: .I | .B | .SB : no text"; + return; + } + + $buffer = substr($buffer, 1, 1) eq 'I' ? $CHAR_FONT_ITALIC : $CHAR_FONT_BOLD; + + # Attempt to handle backslash quoting + $p = handle_backslash $p; + print_string $buffer . $p . $CHAR_FONT_NORMAL; + } + elsif ($buffer eq ".TP") + { + handle_tp_ip 1; + } + elsif ($buffer eq ".IP") + { + handle_tp_ip 0; + } + elsif ($buffer eq ".\\\"TOPICS") + { + if ($out_row > 1) + { + print_error "Syntax error: .\\\"TOPICS must be first command"; + return; + } + $buffer = strtok(undef, ""); + if (! defined $buffer) + { + print_error "Syntax error: .\\\"TOPICS: no text"; + return; + } + # Remove quotes + $buffer =~ s/^"// and $buffer =~ s/"$//; + $topics = $buffer; + } + elsif ($buffer eq ".br") + { + newline if $col; + } + elsif ($buffer =~ /^\.\\"/) + { + # Comment { Hello from K.O. ;-) } + } + elsif ($buffer eq ".TH") + { + # Title header + } + elsif ($buffer eq ".SM") + { + # Causes the text on the same line or the text on the + # next line to appear in a font that is one point + # size smaller than the default font. + $buffer = strtok(undef, ""); + print_string $buffer if defined $buffer; + } + elsif (handle_alt_font($buffer) == 1) + { + return; + } + else + { + # Other commands are ignored + print_error sprintf "Warning: unsupported command %s", $buffer; + return; + } +} + +sub struct_links() +{ + return { + 'linkname' => undef, # Section name + 'line' => undef, # Input line in ... + 'filename' => undef, + 'next' => undef + } +} + +my $links = struct_links(); +my $current_link; + + +sub handle_link($) +{ + my ($buffer) = @_; + my $old = \$static{"handle_link old"}; + my $len; + my $amp; + my $amp_arg; + + if ($link_flag == 1) + { + # Old format link, not supported + } + elsif ($link_flag == 2) + { + # First part of new format link + # Bold text or italics text + if (substr($buffer, 0, 2) eq '.I' || substr($buffer, 0, 2) eq '.B') + { + $buffer =~ s/^..[\s\t]*//; + } + $$old = $buffer; + $link_flag = 3; + + } + elsif ($link_flag == 3) + { + # Second part of new format link + $buffer =~ s/^\.//; + $buffer =~ s/^\\//; + $buffer =~ s/^"//; + $buffer =~ s/"$//; + + # "Layout\&)," -- "Layout" should be highlighted, but not ")," + ($$old, $amp_arg) = split /\\&/, $$old, 2; + printf_string "%s%s%s%s%s%s\n", $CHAR_LINK_START, $$old, + $CHAR_LINK_POINTER, $buffer, $CHAR_LINK_END, $amp_arg; + $link_flag = 0; + # Add to the linked list + if (defined $current_link) + { + $current_link->{'next'} = struct_links(); + $current_link = $current_link->{'next'}; + $current_link->{'next'} = undef; + } + else + { + $current_link = $links; + } + $current_link->{'linkname'} = $buffer; + $current_link->{'filename'} = $c_in; + $current_link->{'line'} = $in_row; + } +} + +sub main +{ + my $len; # Length of input line + my $c_man; # Manual filename + my $c_tmpl; # Template filename + my $f_man; # Manual file + my $f_tmpl; # Template file + my $buffer; # Full input line + my $lc_node = undef; + my $outfile_buffer; # Large buffer to keep the output file + my $cont_start; # Start of [Contents] + my $file_end; # Length of the output file + + # Validity check for arguments + if (@ARGV != 3) + { + warn "Usage: man2hlp file.man template_file helpfile\n"; + return 3; + } + + $c_man = $ARGV[0]; + $c_tmpl = $ARGV[1]; + $c_out = $ARGV[2]; + + # First stage - process the manual, write to the output file + + $f_man = fopen_check "<", $c_man; + $f_out = fopen_check ">", $c_out; + $c_in = $c_man; + + # Repeat for each input line + while (<$f_man>) + { + # Remove terminating newline + chomp; + $buffer = $_; + my $input_line; # Input line without initial "\&" + + if (substr($buffer, 0, 2) eq '\\&') + { + $input_line = substr($buffer, 2); + } + else + { + $input_line = $buffer; + } + + $in_row++; + $len = length($input_line); + + if ($verbatim_flag) + { + # Copy the line verbatim + if ($input_line eq ".fi") + { + $verbatim_flag = 0; + } + else + { + print_string $input_line; + newline; + } + } + elsif ($link_flag) + { + # The line is a link + handle_link $input_line; + } + elsif (substr($buffer, 0, 1) eq '.') + { + # The line is a roff command + handle_command $input_line; + } + else + { + #A normal line, just output it + print_string $input_line; + } + # .TP label processed as usual line + if ($tp_flag) + { + if ($tp_flag == 1) + { + $tp_flag = 2; + } + else + { + $tp_flag = 0; + $indentation = 8; + if ($col >= $indentation) + { + newline; + } + else + { + print $f_out " " while ++$col < $indentation; + } + } + } + } + + newline; + fclose_check $f_man; + # First stage ends here, closing the manual + + # Second stage - process the template file + $f_tmpl = fopen_check "<", $c_tmpl; + $c_in = $c_tmpl; + + # Repeat for each input line + # Read a line + while (<$f_tmpl>) + { + $buffer = $_; + if (defined $lc_node) + { + chomp $buffer; + $lc_node = undef; + } + else + { + my $char_node_end = index($buffer, $CHAR_NODE_END); + $lc_node = $char_node_end < 0 ? undef : substr($buffer, $char_node_end); + + if (defined $lc_node && substr($lc_node, 1, 1) eq '[') + { + my $p = index($lc_node, ']'); + if ($p >= 0) { + if (substr($lc_node, 1, 6) eq '[main]') + { + $lc_node = undef; + } + else + { + if (! defined $cnode) + { + $cnode = $nodes; + } + else + { + $cnode->{'next'} = struct_node(); + $cnode = $cnode->{'next'}; + } + $cnode->{'$node'} = substr($lc_node, 1, $p-1); + $cnode->{'lname'} = undef; + $cnode->{'next'} = undef; + $cnode->{'heading_level'} = 0; + } + } + else + { + $lc_node = undef; + } + } + else + { + $lc_node = undef; + } + } + print $f_out $buffer; + } + + $cont_start = tell $f_out; + if ($cont_start <= 0) + { + perror $c_out; + return 1; + } + + if ($topics) + { + printf $f_out "\004[Contents]\n%s\n\n", $topics; + } + else + { + print $f_out "\004[Contents]\n"; + } + + for ($current_link = $links; defined $current_link && defined $current_link->{'linkname'};) + { + my $found = 0; + my $next = $current_link->{'next'}; + + if ($current_link->{'linkname'} eq "Contents") + { + $found = 1; + } + else + { + for ($cnode = $nodes; defined $cnode && defined $cnode->{'node'}; $cnode = $cnode->{'next'}) + { + if ($cnode->{'node'} eq $current_link->{'linkname'}) + { + $found = 1; + last; + } + } + } + if (! $found) + { + $buffer = sprintf "Stale link \"%s\"", $current_link->{'linkname'}; + $c_in = $current_link->{'filename'}; + $in_row = $current_link->{'line'}; + print_error $buffer; + } + + $current_link = $next; + } + + for ($cnode = $nodes; defined $cnode && defined $cnode->{'node'};) + { + my $next = $cnode->{'next'}; + $lc_node = $cnode->{'node'}; + + if (defined $lc_node && $lc_node ne '') { + printf $f_out " %*s\001%s\002%s\003", $cnode->{'heading_level'}, + "", $cnode->{'lname'} ? $cnode->{'lname'} : $lc_node, $lc_node; + } + print $f_out "\n"; + $cnode = $next; + } + + $file_end = tell $f_out; + + # Sanity check + if (($file_end <= 0) || ($file_end - $cont_start <= 0)) + { + warn $c_out ."\n"; + return 1; + } + + fclose_check $f_out; + fclose_check $f_tmpl; + # Second stage ends here, closing all files, note the end of output + + # + # Third stage - swap two parts of the output file. + # First, open the output file for reading and load it into the memory. + # + ## TODO: replace writing to f_out by writing to a string + $outfile_buffer = ''; + $f_out = fopen_check '<', $c_out; + $outfile_buffer .= $_ while <$f_out>; + fclose_check $f_out; + # Now the output file is in the memory + + # Again open output file for writing + $f_out = fopen_check '>', $c_out; + + # Write part after the "Contents" node + print $f_out substr($outfile_buffer, $cont_start, $file_end - $cont_start); + + # Write part before the "Contents" node + print $f_out substr($outfile_buffer, 0, $cont_start-1); + fclose_check $f_out; + + return 0; +} + +exit main(); From fd3dd57078ae2a1a0a81a1203eb26e6066c2c186 Mon Sep 17 00:00:00 2001 From: Alexandr Prenko Date: Thu, 20 May 2010 08:58:41 +0300 Subject: [PATCH 03/11] Bug fix: Invalid content generation --- src/man2hlp/man2hlp.in | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/man2hlp/man2hlp.in b/src/man2hlp/man2hlp.in index 7652ba8d6..8b10c1f2f 100644 --- a/src/man2hlp/man2hlp.in +++ b/src/man2hlp/man2hlp.in @@ -765,7 +765,11 @@ sub main $buffer = $_; if (defined $lc_node) { - chomp $buffer; + if ($buffer ne "\n") + { + $cnode->{'lname'} = $buffer; + chomp $cnode->{'lname'}; + } $lc_node = undef; } else @@ -792,7 +796,7 @@ sub main $cnode->{'next'} = struct_node(); $cnode = $cnode->{'next'}; } - $cnode->{'$node'} = substr($lc_node, 1, $p-1); + $cnode->{'node'} = substr($lc_node, 2, $p-2); $cnode->{'lname'} = undef; $cnode->{'next'} = undef; $cnode->{'heading_level'} = 0; From 8a46e405649ee446722026049945a53946b6974d Mon Sep 17 00:00:00 2001 From: Alexandr Prenko Date: Fri, 21 May 2010 21:30:38 +0300 Subject: [PATCH 04/11] Fixed backslash handling --- src/man2hlp/man2hlp.in | 59 ++++++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/src/man2hlp/man2hlp.in b/src/man2hlp/man2hlp.in index 8b10c1f2f..9a7575a76 100644 --- a/src/man2hlp/man2hlp.in +++ b/src/man2hlp/man2hlp.in @@ -101,25 +101,6 @@ sub strtok($$) { return $result; } -# Attempt to handle backslash quoting -sub handle_backslash($) -{ - my ($s) = @_; - my $backslash_flag = 0; - my $result = ''; - foreach my $c (split //, $s) - { - if ($c eq '\\' && ! $backslash_flag) - { - $backslash_flag = 1; - next; - } - $backslash_flag = 0; - $result .= $c; - } - return $result; -} - sub struct_node() { return { "node" => undef, # Section name @@ -224,7 +205,6 @@ sub print_string($) { my ($buffer) = @_; my $len; # The length of current word - my $c; # Current character my $backslash_flag = 0; # Skipping lines? @@ -233,8 +213,16 @@ sub print_string($) if ($verbatim_flag) { # Attempt to handle backslash quoting - $buffer = handle_backslash $buffer; - print $f_out $buffer; + foreach (split //, $buffer) + { + if ($_ eq '\\' && !$backslash_flag) + { + $backslash_flag = 1; + next; + } + $backslash_flag = 0; + print $f_out $_; + } } else { @@ -258,8 +246,16 @@ sub print_string($) print $f_out ' ' while $col++ < $indentation; } # Attempt to handle backslash quoting - $buffer = handle_backslash $buffer; - print $f_out $buffer; + foreach (split //, $buffer) + { + if ($_ eq '\\' && !$backslash_flag) + { + $backslash_flag = 1; + next; + } + $backslash_flag = 0; + print $f_out $_; + } # Increase column $col += $len; } @@ -503,6 +499,7 @@ sub handle_command($) elsif ($buffer eq ".I" || $buffer eq ".B" || $buffer eq ".SB") { # Bold text or italics text + my $backslash_flag = 0; # .SB [text] # Causes the text on the same line or the text on the @@ -511,6 +508,7 @@ sub handle_command($) # # FIXME: text is optional, so there is no error + my $p = strtok(undef, ""); if (! defined $p) { @@ -521,7 +519,18 @@ sub handle_command($) $buffer = substr($buffer, 1, 1) eq 'I' ? $CHAR_FONT_ITALIC : $CHAR_FONT_BOLD; # Attempt to handle backslash quoting - $p = handle_backslash $p; + my @p = split //, $p; + $p = ''; + foreach (@p) + { + if ($_ eq '\\' && !$backslash_flag) + { + $backslash_flag = 1; + next; + } + $backslash_flag = 0; + $p .= $_; + } print_string $buffer . $p . $CHAR_FONT_NORMAL; } elsif ($buffer eq ".TP") From 84c1f750c4736597a320ca3c07a8dd83ec8f5792 Mon Sep 17 00:00:00 2001 From: Alexandr Prenko Date: Fri, 21 May 2010 22:33:00 +0300 Subject: [PATCH 05/11] Fixed string splitting by '\&' bug --- src/man2hlp/man2hlp.in | 1 + 1 file changed, 1 insertion(+) diff --git a/src/man2hlp/man2hlp.in b/src/man2hlp/man2hlp.in index 9a7575a76..1fe76c14e 100644 --- a/src/man2hlp/man2hlp.in +++ b/src/man2hlp/man2hlp.in @@ -638,6 +638,7 @@ sub handle_link($) # "Layout\&)," -- "Layout" should be highlighted, but not ")," ($$old, $amp_arg) = split /\\&/, $$old, 2; + $amp_arg = "" unless defined $amp_arg; printf_string "%s%s%s%s%s%s\n", $CHAR_LINK_START, $$old, $CHAR_LINK_POINTER, $buffer, $CHAR_LINK_END, $amp_arg; $link_flag = 0; From fc0a3ebe93694eff988551d191909770ddfa702c Mon Sep 17 00:00:00 2001 From: Alexandr Prenko Date: Fri, 21 May 2010 22:39:39 +0300 Subject: [PATCH 06/11] Fixed bug: Wrong odd SH warning --- src/man2hlp/man2hlp.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/man2hlp/man2hlp.in b/src/man2hlp/man2hlp.in index 1fe76c14e..d9e6218e0 100644 --- a/src/man2hlp/man2hlp.in +++ b/src/man2hlp/man2hlp.in @@ -296,7 +296,7 @@ sub handle_node($$) $heading_level = 0; $heading_level++ while substr($buffer, $heading_level, 1) eq ' '; # Heading level must be even - unless ($heading_level % 2) + if ($heading_level % 2) { print_error "Syntax error: .SH: odd heading level"; } From 738fed4ffb1a2bb0def6a0a238dff0eda84d3bb0 Mon Sep 17 00:00:00 2001 From: Alexandr Prenko Date: Sat, 22 May 2010 00:32:48 +0300 Subject: [PATCH 07/11] Fixed bug: Wrong string length calculation --- src/man2hlp/man2hlp.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/man2hlp/man2hlp.in b/src/man2hlp/man2hlp.in index d9e6218e0..387533835 100644 --- a/src/man2hlp/man2hlp.in +++ b/src/man2hlp/man2hlp.in @@ -234,7 +234,7 @@ sub print_string($) # Skip empty strings if ($buffer ne '') { - $len = length($buffer); + $len = string_len($buffer); # Words are separated by spaces if ($col > 0) { From 9722a476e658f7c2e38baf72e567c181e949d7ac Mon Sep 17 00:00:00 2001 From: Alexandr Prenko Date: Sat, 22 May 2010 01:17:50 +0300 Subject: [PATCH 08/11] Fixed bug: Wrong last char processing in handle_alt_font --- src/man2hlp/man2hlp.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/man2hlp/man2hlp.in b/src/man2hlp/man2hlp.in index 387533835..7a2ac3275 100644 --- a/src/man2hlp/man2hlp.in +++ b/src/man2hlp/man2hlp.in @@ -409,7 +409,7 @@ sub handle_alt_font($) { shift @p; # Don't change font if we are at the end - if ($#p) + if (@p) { $alt_state = $alt_state ? 0 : 1; $buffer .= $font[$alt_state]; From 4c008486411b0eddbaddc9b4f490c1cd707a3eeb Mon Sep 17 00:00:00 2001 From: Alexandr Prenko Date: Sat, 22 May 2010 01:42:37 +0300 Subject: [PATCH 09/11] Minor code cleanups --- src/man2hlp/man2hlp.in | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/man2hlp/man2hlp.in b/src/man2hlp/man2hlp.in index 7a2ac3275..e8c44f22b 100644 --- a/src/man2hlp/man2hlp.in +++ b/src/man2hlp/man2hlp.in @@ -23,14 +23,11 @@ # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # -# \file man2hlp.c +# \file man2hlp # \brief Source: man page to help file converter -# include "help.h" -# end of include "help.h" - use strict; use warnings; @@ -435,7 +432,7 @@ sub handle_alt_font($) return 1; } -# Handle .IP and .TP commands. is_tp is 1 for .TP, 0 for .IP */ +# Handle .IP and .TP commands. is_tp is 1 for .TP, 0 for .IP sub handle_tp_ip($) { my ($is_tp) = @_; @@ -519,9 +516,7 @@ sub handle_command($) $buffer = substr($buffer, 1, 1) eq 'I' ? $CHAR_FONT_ITALIC : $CHAR_FONT_BOLD; # Attempt to handle backslash quoting - my @p = split //, $p; - $p = ''; - foreach (@p) + foreach (split //, $p) { if ($_ eq '\\' && !$backslash_flag) { @@ -529,9 +524,9 @@ sub handle_command($) next; } $backslash_flag = 0; - $p .= $_; + $buffer .= $_; } - print_string $buffer . $p . $CHAR_FONT_NORMAL; + print_string $buffer . $CHAR_FONT_NORMAL; } elsif ($buffer eq ".TP") { @@ -902,7 +897,6 @@ sub main # Third stage - swap two parts of the output file. # First, open the output file for reading and load it into the memory. # - ## TODO: replace writing to f_out by writing to a string $outfile_buffer = ''; $f_out = fopen_check '<', $c_out; $outfile_buffer .= $_ while <$f_out>; From aefd218a3285151e605f2b91928263a668c7d89c Mon Sep 17 00:00:00 2001 From: Alexandr Prenko Date: Mon, 24 May 2010 09:22:40 +0300 Subject: [PATCH 10/11] Fixed bug: No newline at the end of file --- src/man2hlp/man2hlp.in | 1 + 1 file changed, 1 insertion(+) diff --git a/src/man2hlp/man2hlp.in b/src/man2hlp/man2hlp.in index e8c44f22b..18d9226fc 100644 --- a/src/man2hlp/man2hlp.in +++ b/src/man2hlp/man2hlp.in @@ -911,6 +911,7 @@ sub main # Write part before the "Contents" node print $f_out substr($outfile_buffer, 0, $cont_start-1); + print $f_out "\n"; fclose_check $f_out; return 0; From 878a0fdc85e063f594fa622bb08717eece2a48e6 Mon Sep 17 00:00:00 2001 From: Slava Zanko Date: Mon, 24 May 2010 10:40:25 +0300 Subject: [PATCH 11/11] mc.spec: Added perl in build requires Signed-off-by: Slava Zanko --- contrib/dist/redhat/mc.spec.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/dist/redhat/mc.spec.in b/contrib/dist/redhat/mc.spec.in index 5b0cc4b12..041b0665c 100644 --- a/contrib/dist/redhat/mc.spec.in +++ b/contrib/dist/redhat/mc.spec.in @@ -31,7 +31,7 @@ Patch0: glib2-CVE-2008-4316.patch URL: http://www.midnight-commander.org/ BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) -BuildRequires: e2fsprogs-devel gpm-devel +BuildRequires: e2fsprogs-devel gpm-devel perl %if %{legacy_rhel}%{?el5} BuildRequires: pcre-devel