From 0731ad5e60e69fffae55a77e5b92b4867236ee3b Mon Sep 17 00:00:00 2001 From: Andrew Borodin Date: Thu, 1 Apr 2010 13:14:00 +0400 Subject: [PATCH] Applied MC indentation policy. Signed-off-by: Andrew Borodin --- src/help.c | 955 ++++++++++++++-------------- src/help.h | 22 +- src/man2hlp.c | 1925 ++++++++++++++++++++++++++++++--------------------------- 3 files changed, 1538 insertions(+), 1364 deletions(-) rewrite src/man2hlp.c (69%) diff --git a/src/help.c b/src/help.c index e8a77417..b9efcebd 100644 --- a/src/help.c +++ b/src/help.c @@ -1,12 +1,12 @@ /* Hypertext file browser. Copyright (C) 1994, 1995, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. - + 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 @@ -15,7 +15,7 @@ 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 help.c @@ -59,9 +59,9 @@ #include "lib/tty/key.h" #include "lib/strutil.h" -#include "dialog.h" /* For Dlg_head */ -#include "widget.h" /* For Widget */ -#include "wtools.h" /* For common_dialog_repaint() */ +#include "dialog.h" /* For Dlg_head */ +#include "widget.h" /* For Widget */ +#include "wtools.h" /* For common_dialog_repaint() */ #include "cmddef.h" #include "keybind.h" #include "help.h" @@ -73,31 +73,33 @@ const global_keymap_t *help_map; #define HISTORY_SIZE 20 #define HELP_WINDOW_WIDTH (COLS - 16) -#define STRING_LINK_START "\01" -#define STRING_LINK_POINTER "\02" -#define STRING_LINK_END "\03" -#define STRING_NODE_END "\04" +#define STRING_LINK_START "\01" +#define STRING_LINK_POINTER "\02" +#define STRING_LINK_END "\03" +#define STRING_NODE_END "\04" -static char *fdata = NULL; /* Pointer to the loaded data file */ -static int help_lines; /* Lines in help viewer */ -static int history_ptr; /* For the history queue */ -static const char *main_node; /* The main node */ -static const char *last_shown = NULL; /* Last byte shown in a screen */ -static gboolean end_of_node = FALSE; /* Flag: the last character of the node shown? */ +static char *fdata = NULL; /* Pointer to the loaded data file */ +static int help_lines; /* Lines in help viewer */ +static int history_ptr; /* For the history queue */ +static const char *main_node; /* The main node */ +static const char *last_shown = NULL; /* Last byte shown in a screen */ +static gboolean end_of_node = FALSE; /* Flag: the last character of the node shown? */ static const char *currentpoint; static const char *selected_item; /* The widget variables */ static Dlg_head *whelp; -static struct { - const char *page; /* Pointer to the selected page */ - const char *link; /* Pointer to the selected link */ -} history [HISTORY_SIZE]; +static struct +{ + const char *page; /* Pointer to the selected page */ + const char *link; /* Pointer to the selected link */ +} history[HISTORY_SIZE]; /* Link areas for the mouse */ -typedef struct Link_Area { +typedef struct Link_Area +{ int x1, y1, x2, y2; const char *link_name; } Link_Area; @@ -105,8 +107,7 @@ typedef struct Link_Area { static GSList *link_area = NULL; static gboolean inside_link_area = FALSE; -static cb_ret_t help_callback (Dlg_head *h, Widget *sender, - dlg_msg_t msg, int parm, void *data); +static cb_ret_t help_callback (Dlg_head * h, Widget * sender, dlg_msg_t msg, int parm, void *data); /* returns the position where text was found in the start buffer */ /* or 0 if not found */ @@ -120,22 +121,25 @@ search_string (const char *start, const char *text) /* fmt sometimes replaces a space with a newline in the help file */ /* Replace the newlines in the link name with spaces to correct the situation */ - while (*d != '\0') { - if (*d == '\n') - *d = ' '; - str_next_char (&d); + while (*d != '\0') + { + if (*d == '\n') + *d = ' '; + str_next_char (&d); } /* Do search */ - for (d = local_text; *e; e++){ - if (*d == *e) - d++; - else - d = local_text; - if (*d == '\0') { - result = e + 1; - break; - } + for (d = local_text; *e; e++) + { + if (*d == *e) + d++; + else + d = local_text; + if (*d == '\0') + { + result = e + 1; + break; + } } g_free (local_text); @@ -151,14 +155,15 @@ search_string_node (const char *start, const char *text) const char *e = start; if (start != NULL) - for (; *e && *e != CHAR_NODE_END; e++) { - if (*d == *e) - d++; - else - d = text; - if (*d == '\0') - return e + 1; - } + for (; *e && *e != CHAR_NODE_END; e++) + { + if (*d == *e) + d++; + else + d = text; + if (*d == '\0') + return e + 1; + } return NULL; } @@ -171,8 +176,8 @@ search_char_node (const char *start, char the_char, int direction) const char *e; for (e = start; (*e != '\0') && (*e != CHAR_NODE_END); e += direction) - if (*e == the_char) - return e; + if (*e == the_char) + return e; return NULL; } @@ -185,13 +190,13 @@ move_forward2 (const char *c, int lines) int line; currentpoint = c; - for (line = 0, p = currentpoint; (*p != '\0') && (*p != CHAR_NODE_END); - str_cnext_char (&p)) { - if (line == lines) - return currentpoint = p; + for (line = 0, p = currentpoint; (*p != '\0') && (*p != CHAR_NODE_END); str_cnext_char (&p)) + { + if (line == lines) + return currentpoint = p; - if (*p == '\n') - line++; + if (*p == '\n') + line++; } return currentpoint = c; } @@ -203,20 +208,21 @@ move_backward2 (const char *c, int lines) int line; currentpoint = c; - for (line = 0, p = currentpoint; (*p != '\0') && ((int) (p - fdata) >= 0); - str_cprev_char (&p)) { - if (*p == CHAR_NODE_END) { - /* We reached the beginning of the node */ - /* Skip the node headers */ - while (*p != ']') - str_cnext_char (&p); - return currentpoint = p + 2; /* Skip the newline following the start of the node */ - } - - if (*(p - 1) == '\n') - line++; - if (line == lines) - return currentpoint = p; + for (line = 0, p = currentpoint; (*p != '\0') && ((int) (p - fdata) >= 0); str_cprev_char (&p)) + { + if (*p == CHAR_NODE_END) + { + /* We reached the beginning of the node */ + /* Skip the node headers */ + while (*p != ']') + str_cnext_char (&p); + return currentpoint = p + 2; /* Skip the newline following the start of the node */ + } + + if (*(p - 1) == '\n') + line++; + if (line == lines) + return currentpoint = p; } return currentpoint = c; } @@ -225,7 +231,7 @@ static void move_forward (int i) { if (!end_of_node) - currentpoint = move_forward2 (currentpoint, i); + currentpoint = move_forward2 (currentpoint, i); } static void @@ -238,11 +244,11 @@ static void move_to_top (void) { while (((int) (currentpoint > fdata) > 0) && (*currentpoint != CHAR_NODE_END)) - currentpoint--; + currentpoint--; while (*currentpoint != ']') - currentpoint++; - currentpoint = currentpoint + 2; /* Skip the newline following the start of the node */ + currentpoint++; + currentpoint = currentpoint + 2; /* Skip the newline following the start of the node */ selected_item = NULL; } @@ -250,7 +256,7 @@ static void move_to_bottom (void) { while ((*currentpoint != '\0') && (*currentpoint != CHAR_NODE_END)) - currentpoint++; + currentpoint++; currentpoint--; move_backward (1); } @@ -258,26 +264,28 @@ move_to_bottom (void) static const char * help_follow_link (const char *start, const char *lc_selected_item) { - char link_name [MAXLINKNAME]; + char link_name[MAXLINKNAME]; const char *p; int i = 0; if (lc_selected_item == NULL) - return start; + return start; for (p = lc_selected_item; *p && *p != CHAR_NODE_END && *p != CHAR_LINK_POINTER; p++) - ; - if (*p == CHAR_LINK_POINTER){ - link_name [0] = '['; - for (i = 1; *p != CHAR_LINK_END && *p && *p != CHAR_NODE_END && i < MAXLINKNAME-3; ) - link_name [i++] = *++p; - link_name [i - 1] = ']'; - link_name [i] = '\0'; - p = search_string (fdata, link_name); - if (p != NULL) { - p += 1; /* Skip the newline following the start of the node */ - return p; - } + ; + if (*p == CHAR_LINK_POINTER) + { + link_name[0] = '['; + for (i = 1; *p != CHAR_LINK_END && *p && *p != CHAR_NODE_END && i < MAXLINKNAME - 3;) + link_name[i++] = *++p; + link_name[i - 1] = ']'; + link_name[i] = '\0'; + p = search_string (fdata, link_name); + if (p != NULL) + { + p += 1; /* Skip the newline following the start of the node */ + return p; + } } /* Create a replacement page with the error message */ @@ -290,23 +298,21 @@ select_next_link (const char *current_link) const char *p; if (current_link == NULL) - return NULL; + return NULL; p = search_string_node (current_link, STRING_LINK_END); if (p == NULL) - return NULL; + return NULL; p = search_string_node (p, STRING_LINK_START); if (p == NULL) - return NULL; + return NULL; return p - 1; } static const char * select_prev_link (const char *current_link) { - return current_link == NULL - ? NULL - : search_char_node (current_link - 1, CHAR_LINK_START, -1); + return current_link == NULL ? NULL : search_char_node (current_link - 1, CHAR_LINK_START, -1); } static void @@ -315,7 +321,7 @@ start_link_area (int x, int y, const char *link_name) Link_Area *la; if (inside_link_area) - message (D_NORMAL, _("Warning"), _(" Internal bug: Double start of link area ")); + message (D_NORMAL, _("Warning"), _(" Internal bug: Double start of link area ")); /* Allocate memory for a new link area */ la = g_new (Link_Area, 1); @@ -332,12 +338,13 @@ start_link_area (int x, int y, const char *link_name) static void end_link_area (int x, int y) { - if (inside_link_area) { - Link_Area *la = (Link_Area *) link_area->data; - /* Save the end coordinates of the link area */ - la->x2 = x; - la->y2 = y; - inside_link_area = FALSE; + if (inside_link_area) + { + Link_Area *la = (Link_Area *) link_area->data; + /* Save the end coordinates of the link area */ + la->x2 = x; + la->y2 = y; + inside_link_area = FALSE; } } @@ -351,244 +358,264 @@ clear_link_areas (void) } static void -help_print_word (Dlg_head *h, GString *word, int *col, int *line, gboolean add_space) +help_print_word (Dlg_head * h, GString * word, int *col, int *line, gboolean add_space) { if (*line >= help_lines) - g_string_set_size (word, 0); - else { - int w; - - w = str_term_width1 (word->str); - if (*col + w >= HELP_WINDOW_WIDTH) { - *col = 0; - (*line)++; - } - - if (*line >= help_lines) - g_string_set_size (word, 0); - else { - dlg_move (h, *line + 2, *col + 2); - tty_print_string (word->str); - g_string_set_size (word, 0); - *col += w; - } + g_string_set_size (word, 0); + else + { + int w; + + w = str_term_width1 (word->str); + if (*col + w >= HELP_WINDOW_WIDTH) + { + *col = 0; + (*line)++; + } + + if (*line >= help_lines) + g_string_set_size (word, 0); + else + { + dlg_move (h, *line + 2, *col + 2); + tty_print_string (word->str); + g_string_set_size (word, 0); + *col += w; + } } - if (add_space) { - if (*col < HELP_WINDOW_WIDTH - 1) { - tty_print_char (' '); - (*col)++; - } else { - *col = 0; - (*line)++; - } + if (add_space) + { + if (*col < HELP_WINDOW_WIDTH - 1) + { + tty_print_char (' '); + (*col)++; + } + else + { + *col = 0; + (*line)++; + } } } static void -help_show (Dlg_head *h, const char *paint_start) +help_show (Dlg_head * h, const char *paint_start) { const char *p, *n; int col, line, c; gboolean painting = TRUE; - gboolean acs; /* Flag: Alternate character set active? */ + gboolean acs; /* Flag: Alternate character set active? */ gboolean repeat_paint; - int active_col, active_line; /* Active link position */ + int active_col, active_line; /* Active link position */ char buff[MB_LEN_MAX + 1]; GString *word; word = g_string_sized_new (32); tty_setcolor (HELP_NORMAL_COLOR); - do { - line = col = active_col = active_line = 0; - repeat_paint = FALSE; - acs = FALSE; - - clear_link_areas (); - if ((int) (selected_item - paint_start) < 0) - selected_item = NULL; - + do + { + line = col = active_col = active_line = 0; + repeat_paint = FALSE; + acs = FALSE; + + clear_link_areas (); + if ((int) (selected_item - paint_start) < 0) + selected_item = NULL; + p = paint_start; n = paint_start; - while ((n[0] != '\0') && (n[0] != CHAR_NODE_END) && (line < help_lines)) { + while ((n[0] != '\0') && (n[0] != CHAR_NODE_END) && (line < help_lines)) + { p = n; n = str_cget_next_char (p); memcpy (buff, p, n - p); buff[n - p] = '\0'; - c = (unsigned char) buff[0]; - switch (c){ - case CHAR_LINK_START: - if (selected_item == NULL) - selected_item = p; - if (p != selected_item) - tty_setcolor (HELP_LINK_COLOR); - else { - tty_setcolor (HELP_SLINK_COLOR); - - /* Store the coordinates of the link */ - active_col = col + 2; - active_line = line + 2; - } - start_link_area (col, line, p); - break; - case CHAR_LINK_POINTER: - painting = FALSE; - end_link_area (col - 1, line); - break; - case CHAR_LINK_END: - painting = TRUE; - help_print_word (h, word, &col, &line, FALSE); - tty_setcolor (HELP_NORMAL_COLOR); - break; - case CHAR_ALTERNATE: - acs = TRUE; - break; - case CHAR_NORMAL: - acs = FALSE; - break; - case CHAR_VERSION: - dlg_move (h, line + 2, col + 2); - tty_print_string (VERSION); - col += str_term_width1 (VERSION); - break; - case CHAR_FONT_BOLD: - tty_setcolor (HELP_BOLD_COLOR); - break; - case CHAR_FONT_ITALIC: - tty_setcolor (HELP_ITALIC_COLOR); - break; - case CHAR_FONT_NORMAL: - help_print_word (h, word, &col, &line, FALSE); - tty_setcolor (HELP_NORMAL_COLOR); - break; - case '\n': - if (painting) - help_print_word (h, word, &col, &line, FALSE); - line++; - col = 0; - break; - case '\t': - col = (col / 8 + 1) * 8; - if (col >= HELP_WINDOW_WIDTH) { - line++; - col = 8; - } - break; - case ' ': - /* word delimeter */ - if (painting) - help_print_word (h, word, &col, &line, TRUE); - break; - default: - if (painting && (line < help_lines)) { - if (!acs) - /* accumulate symbols in a word */ - g_string_append (word, buff); - else if (col < HELP_WINDOW_WIDTH) { - dlg_move (h, line + 2, col + 2); - - if ((c == ' ') || (c == '.')) - tty_print_char (c); - else + c = (unsigned char) buff[0]; + switch (c) + { + case CHAR_LINK_START: + if (selected_item == NULL) + selected_item = p; + if (p != selected_item) + tty_setcolor (HELP_LINK_COLOR); + else + { + tty_setcolor (HELP_SLINK_COLOR); + + /* Store the coordinates of the link */ + active_col = col + 2; + active_line = line + 2; + } + start_link_area (col, line, p); + break; + case CHAR_LINK_POINTER: + painting = FALSE; + end_link_area (col - 1, line); + break; + case CHAR_LINK_END: + painting = TRUE; + help_print_word (h, word, &col, &line, FALSE); + tty_setcolor (HELP_NORMAL_COLOR); + break; + case CHAR_ALTERNATE: + acs = TRUE; + break; + case CHAR_NORMAL: + acs = FALSE; + break; + case CHAR_VERSION: + dlg_move (h, line + 2, col + 2); + tty_print_string (VERSION); + col += str_term_width1 (VERSION); + break; + case CHAR_FONT_BOLD: + tty_setcolor (HELP_BOLD_COLOR); + break; + case CHAR_FONT_ITALIC: + tty_setcolor (HELP_ITALIC_COLOR); + break; + case CHAR_FONT_NORMAL: + help_print_word (h, word, &col, &line, FALSE); + tty_setcolor (HELP_NORMAL_COLOR); + break; + case '\n': + if (painting) + help_print_word (h, word, &col, &line, FALSE); + line++; + col = 0; + break; + case '\t': + col = (col / 8 + 1) * 8; + if (col >= HELP_WINDOW_WIDTH) + { + line++; + col = 8; + } + break; + case ' ': + /* word delimeter */ + if (painting) + help_print_word (h, word, &col, &line, TRUE); + break; + default: + if (painting && (line < help_lines)) + { + if (!acs) + /* accumulate symbols in a word */ + g_string_append (word, buff); + else if (col < HELP_WINDOW_WIDTH) + { + dlg_move (h, line + 2, col + 2); + + if ((c == ' ') || (c == '.')) + tty_print_char (c); + else #ifndef HAVE_SLANG - tty_print_char (acs_map [c]); + tty_print_char (acs_map[c]); #else - SLsmg_draw_object (h->y + line + 2, h->x + col + 2, c); + SLsmg_draw_object (h->y + line + 2, h->x + col + 2, c); #endif - col++; - } - } - } - } - - /* print last word */ - if (n[0] == CHAR_NODE_END) - help_print_word (h, word, &col, &line, FALSE); - - last_shown = p; - end_of_node = line < help_lines; - tty_setcolor (HELP_NORMAL_COLOR); - if ((int) (selected_item - last_shown) >= 0) { - if ((link_area == NULL) || (link_area->data == NULL)) - selected_item = NULL; - else { - selected_item = ((Link_Area *) link_area->data)->link_name; - repeat_paint = TRUE; - } - } - } while (repeat_paint); + col++; + } + } + } + } + + /* print last word */ + if (n[0] == CHAR_NODE_END) + help_print_word (h, word, &col, &line, FALSE); + + last_shown = p; + end_of_node = line < help_lines; + tty_setcolor (HELP_NORMAL_COLOR); + if ((int) (selected_item - last_shown) >= 0) + { + if ((link_area == NULL) || (link_area->data == NULL)) + selected_item = NULL; + else + { + selected_item = ((Link_Area *) link_area->data)->link_name; + repeat_paint = TRUE; + } + } + } + while (repeat_paint); g_string_free (word, TRUE); /* Position the cursor over a nice link */ if (active_col) - dlg_move (h, active_line, active_col); + dlg_move (h, active_line, active_col); } static int -help_event (Gpm_Event *event, void *vp) +help_event (Gpm_Event * event, void *vp) { Widget *w = vp; GSList *current_area; if ((event->type & GPM_UP) == 0) - return 0; + return 0; /* The event is relative to the dialog window, adjust it: */ event->x -= 2; event->y -= 2; - if (event->buttons & GPM_B_RIGHT){ - currentpoint = history [history_ptr].page; - selected_item = history [history_ptr].link; - history_ptr--; - if (history_ptr < 0) - history_ptr = HISTORY_SIZE-1; - - help_callback (w->parent, NULL, DLG_DRAW, 0, NULL); - return 0; + if (event->buttons & GPM_B_RIGHT) + { + currentpoint = history[history_ptr].page; + selected_item = history[history_ptr].link; + history_ptr--; + if (history_ptr < 0) + history_ptr = HISTORY_SIZE - 1; + + help_callback (w->parent, NULL, DLG_DRAW, 0, NULL); + return 0; } /* Test whether the mouse click is inside one of the link areas */ for (current_area = link_area; current_area != NULL; current_area = g_slist_next (current_area)) { - Link_Area *la = (Link_Area *) current_area->data; - /* Test one line link area */ - if (event->y == la->y1 && event->x >= la->x1 && - event->y == la->y2 && event->x <= la->x2) - break; - /* Test two line link area */ - if (la->y1 + 1 == la->y2) { - /* The first line */ - if (event->y == la->y1 && event->x >= la->x1) - break; - /* The second line */ - if (event->y == la->y2 && event->x <= la->x2) - break; - } - /* Mouse will not work with link areas of more than two lines */ + Link_Area *la = (Link_Area *) current_area->data; + /* Test one line link area */ + if (event->y == la->y1 && event->x >= la->x1 && event->y == la->y2 && event->x <= la->x2) + break; + /* Test two line link area */ + if (la->y1 + 1 == la->y2) + { + /* The first line */ + if (event->y == la->y1 && event->x >= la->x1) + break; + /* The second line */ + if (event->y == la->y2 && event->x <= la->x2) + break; + } + /* Mouse will not work with link areas of more than two lines */ } /* Test whether a link area was found */ - if (current_area != NULL) { - Link_Area *la = (Link_Area *) current_area->data; - - /* The click was inside a link area -> follow the link */ - history_ptr = (history_ptr+1) % HISTORY_SIZE; - history [history_ptr].page = currentpoint; - history [history_ptr].link = la->link_name; - currentpoint = help_follow_link (currentpoint, la->link_name); - selected_item = NULL; - } else if (event->y < 0) - move_backward (help_lines - 1); + if (current_area != NULL) + { + Link_Area *la = (Link_Area *) current_area->data; + + /* The click was inside a link area -> follow the link */ + history_ptr = (history_ptr + 1) % HISTORY_SIZE; + history[history_ptr].page = currentpoint; + history[history_ptr].link = la->link_name; + currentpoint = help_follow_link (currentpoint, la->link_name); + selected_item = NULL; + } + else if (event->y < 0) + move_backward (help_lines - 1); else if (event->y >= help_lines) - move_forward (help_lines - 1); - else if (event->y < help_lines/2) - move_backward (1); + move_forward (help_lines - 1); + else if (event->y < help_lines / 2) + move_backward (1); else - move_forward (1); + move_forward (1); /* Show the new node */ help_callback (w->parent, NULL, DLG_DRAW, 0, NULL); @@ -598,71 +625,72 @@ help_event (Gpm_Event *event, void *vp) /* show help */ static void -help_help (Dlg_head *h) +help_help (Dlg_head * h) { const char *p; history_ptr = (history_ptr + 1) % HISTORY_SIZE; - history [history_ptr].page = currentpoint; - history [history_ptr].link = selected_item; + history[history_ptr].page = currentpoint; + history[history_ptr].link = selected_item; p = search_string (fdata, "[How to use help]"); - if (p != NULL) { - currentpoint = p + 1; /* Skip the newline following the start of the node */ - selected_item = NULL; - help_callback (h, NULL, DLG_DRAW, 0, NULL); + if (p != NULL) + { + currentpoint = p + 1; /* Skip the newline following the start of the node */ + selected_item = NULL; + help_callback (h, NULL, DLG_DRAW, 0, NULL); } } static void -help_index (Dlg_head *h) +help_index (Dlg_head * h) { const char *new_item; new_item = search_string (fdata, "[Contents]"); if (new_item == NULL) - message (D_ERROR, MSG_ERROR, _(" Cannot find node %s in help file "), - "[Contents]"); - else { - history_ptr = (history_ptr + 1) % HISTORY_SIZE; - history[history_ptr].page = currentpoint; - history[history_ptr].link = selected_item; - - currentpoint = new_item + 1; /* Skip the newline following the start of the node */ - selected_item = NULL; - help_callback (h, NULL, DLG_DRAW, 0, NULL); + message (D_ERROR, MSG_ERROR, _(" Cannot find node %s in help file "), "[Contents]"); + else + { + history_ptr = (history_ptr + 1) % HISTORY_SIZE; + history[history_ptr].page = currentpoint; + history[history_ptr].link = selected_item; + + currentpoint = new_item + 1; /* Skip the newline following the start of the node */ + selected_item = NULL; + help_callback (h, NULL, DLG_DRAW, 0, NULL); } } static void -help_back (Dlg_head *h) +help_back (Dlg_head * h) { - currentpoint = history [history_ptr].page; - selected_item = history [history_ptr].link; + currentpoint = history[history_ptr].page; + selected_item = history[history_ptr].link; history_ptr--; if (history_ptr < 0) - history_ptr = HISTORY_SIZE - 1; + history_ptr = HISTORY_SIZE - 1; - help_callback (h, NULL, DLG_DRAW, 0, NULL); /* FIXME: unneeded? */ + help_callback (h, NULL, DLG_DRAW, 0, NULL); /* FIXME: unneeded? */ } static void -help_cmk_move_backward(void *vp, int lines) +help_cmk_move_backward (void *vp, int lines) { (void) &vp; move_backward (lines); } static void -help_cmk_move_forward(void *vp, int lines) +help_cmk_move_forward (void *vp, int lines) { (void) &vp; move_forward (lines); } static void -help_cmk_moveto_top(void *vp, int lines) +help_cmk_moveto_top (void *vp, int lines) { (void) &vp; (void) &lines; @@ -670,7 +698,7 @@ help_cmk_moveto_top(void *vp, int lines) } static void -help_cmk_moveto_bottom(void *vp, int lines) +help_cmk_moveto_bottom (void *vp, int lines) { (void) &vp; (void) &lines; @@ -679,22 +707,25 @@ help_cmk_moveto_bottom(void *vp, int lines) static void help_next_link (gboolean move_down) - { +{ const char *new_item; new_item = select_next_link (selected_item); - if (new_item != NULL) { - selected_item = new_item; - if ((int) (selected_item - last_shown) >= 0) { - if (move_down) - move_forward (1); - else - selected_item = NULL; - } - } else if (move_down) - move_forward (1); + if (new_item != NULL) + { + selected_item = new_item; + if ((int) (selected_item - last_shown) >= 0) + { + if (move_down) + move_forward (1); + else + selected_item = NULL; + } + } + else if (move_down) + move_forward (1); else - selected_item = NULL; + selected_item = NULL; } static void @@ -704,13 +735,14 @@ help_prev_link (gboolean move_up) new_item = select_prev_link (selected_item); selected_item = new_item; - if ((selected_item == NULL) || (selected_item < currentpoint)) { - if (move_up) - move_backward (1); - else if ((link_area != NULL) && (link_area->data != NULL)) - selected_item = ((Link_Area *) link_area->data)->link_name; - else - selected_item = NULL; + if ((selected_item == NULL) || (selected_item < currentpoint)) + { + if (move_up) + move_backward (1); + else if ((link_area != NULL) && (link_area->data != NULL)) + selected_item = ((Link_Area *) link_area->data)->link_name; + else + selected_item = NULL; } } @@ -721,16 +753,16 @@ help_next_node (void) new_item = currentpoint; while ((*new_item != '\0') && (*new_item != CHAR_NODE_END)) - new_item++; + new_item++; if (*++new_item == '[') - while (*++new_item != '\0') - if ((*new_item == ']') && (*++new_item != '\0') - && (*++new_item != '\0')) { - currentpoint = new_item; - selected_item = NULL; - break; - } + while (*++new_item != '\0') + if ((*new_item == ']') && (*++new_item != '\0') && (*++new_item != '\0')) + { + currentpoint = new_item; + selected_item = NULL; + break; + } } static void @@ -740,12 +772,12 @@ help_prev_node (void) new_item = currentpoint; while (((int) (new_item - fdata) > 1) && (*new_item != CHAR_NODE_END)) - new_item--; + new_item--; new_item--; while (((int) (new_item - fdata) > 0) && (*new_item != CHAR_NODE_END)) - new_item--; + new_item--; while (*new_item != ']') - new_item++; + new_item++; currentpoint = new_item + 2; selected_item = NULL; } @@ -754,25 +786,28 @@ static void help_select_link (void) { /* follow link */ - if (selected_item == NULL) { + if (selected_item == NULL) + { #ifdef WE_WANT_TO_GO_BACKWARD_ON_KEY_RIGHT - /* Is there any reason why the right key would take us - * backward if there are no links selected?, I agree - * with Torben than doing nothing in this case is better - */ - /* If there are no links, go backward in history */ - history_ptr--; - if (history_ptr < 0) - history_ptr = HISTORY_SIZE-1; - - currentpoint = history [history_ptr].page; - selected_item = history [history_ptr].link; + /* Is there any reason why the right key would take us + * backward if there are no links selected?, I agree + * with Torben than doing nothing in this case is better + */ + /* If there are no links, go backward in history */ + history_ptr--; + if (history_ptr < 0) + history_ptr = HISTORY_SIZE - 1; + + currentpoint = history[history_ptr].page; + selected_item = history[history_ptr].link; #endif - } else { - history_ptr = (history_ptr + 1) % HISTORY_SIZE; - history [history_ptr].page = currentpoint; - history [history_ptr].link = selected_item; - currentpoint = help_follow_link (currentpoint, selected_item); + } + else + { + history_ptr = (history_ptr + 1) % HISTORY_SIZE; + history[history_ptr].page = currentpoint; + history[history_ptr].link = selected_item; + currentpoint = help_follow_link (currentpoint, selected_item); } selected_item = NULL; @@ -783,64 +818,66 @@ help_execute_cmd (unsigned long command) { cb_ret_t ret = MSG_HANDLED; - switch (command) { + switch (command) + { case CK_HelpHelp: - help_help (whelp); - break; + help_help (whelp); + break; case CK_HelpIndex: - help_index (whelp); - break; + help_index (whelp); + break; case CK_HelpBack: - help_back (whelp); - break; + help_back (whelp); + break; case CK_HelpMoveUp: - help_prev_link (TRUE); - break; + help_prev_link (TRUE); + break; case CK_HelpMoveDown: - help_next_link (TRUE); - break; + help_next_link (TRUE); + break; case CK_HelpSelectLink: - help_select_link (); - break; + help_select_link (); + break; case CK_HelpNextLink: - help_next_link (FALSE); - break; + help_next_link (FALSE); + break; case CK_HelpPrevLink: - help_prev_link (FALSE); - break; + help_prev_link (FALSE); + break; case CK_HelpNextNode: - help_next_node (); - break; + help_next_node (); + break; case CK_HelpPrevNode: - help_prev_node (); - break; + help_prev_node (); + break; case CK_HelpQuit: - dlg_stop (whelp); - break; + dlg_stop (whelp); + break; default: - ret = MSG_NOT_HANDLED; + ret = MSG_NOT_HANDLED; } return ret; } static cb_ret_t -help_handle_key (Dlg_head *h, int c) +help_handle_key (Dlg_head * h, int c) { if (c != KEY_UP && c != KEY_DOWN && - check_movement_keys (c, help_lines, NULL, - help_cmk_move_backward, - help_cmk_move_forward, - help_cmk_moveto_top, - help_cmk_moveto_bottom) == MSG_HANDLED) { - /* Nothing */; - } else { - unsigned long command; - - command = lookup_keymap_command (help_map, c); - if ((command == CK_Ignore_Key) - || (help_execute_cmd (command) == MSG_NOT_HANDLED)) - return MSG_NOT_HANDLED; + check_movement_keys (c, help_lines, NULL, + help_cmk_move_backward, + help_cmk_move_forward, + help_cmk_moveto_top, help_cmk_moveto_bottom) == MSG_HANDLED) + { + /* Nothing */ ; + } + else + { + unsigned long command; + + command = lookup_keymap_command (help_map, c); + if ((command == CK_Ignore_Key) || (help_execute_cmd (command) == MSG_NOT_HANDLED)) + return MSG_NOT_HANDLED; } help_callback (h, NULL, DLG_DRAW, 0, NULL); @@ -848,33 +885,33 @@ help_handle_key (Dlg_head *h, int c) } static cb_ret_t -help_callback (Dlg_head *h, Widget *sender, - dlg_msg_t msg, int parm, void *data) +help_callback (Dlg_head * h, Widget * sender, dlg_msg_t msg, int parm, void *data) { WButtonBar *bb; - switch (msg) { + switch (msg) + { case DLG_RESIZE: - help_lines = min (LINES - 4, max (2 * LINES / 3, 18)); - dlg_set_size (h, help_lines + 4, HELP_WINDOW_WIDTH + 4); - bb = find_buttonbar (h); - widget_set_size (&bb->widget, LINES - 1, 0, 1, COLS); - return MSG_HANDLED; + help_lines = min (LINES - 4, max (2 * LINES / 3, 18)); + dlg_set_size (h, help_lines + 4, HELP_WINDOW_WIDTH + 4); + bb = find_buttonbar (h); + widget_set_size (&bb->widget, LINES - 1, 0, 1, COLS); + return MSG_HANDLED; case DLG_DRAW: - common_dialog_repaint (h); - help_show (h, currentpoint); - return MSG_HANDLED; + common_dialog_repaint (h); + help_show (h, currentpoint); + return MSG_HANDLED; case DLG_KEY: - return help_handle_key (h, parm); + return help_handle_key (h, parm); case DLG_ACTION: - /* command from buttonbar */ - return help_execute_cmd (parm); + /* command from buttonbar */ + return help_execute_cmd (parm); default: - return default_dlg_callback (h, sender, msg, parm, data); + return default_dlg_callback (h, sender, msg, parm, data); } } @@ -897,30 +934,33 @@ translate_file (char *filedata) conv = str_crt_conv_from ("UTF-8"); if (conv == INVALID_CONV) - g_string_free (translated_data, TRUE); - else { - g_free (fdata); - - if (str_convert (conv, filedata, translated_data) != ESTR_FAILURE) - fdata = g_string_free (translated_data, FALSE); - else { - fdata = NULL; - g_string_free (translated_data, TRUE); - } - str_close_conv (conv); + g_string_free (translated_data, TRUE); + else + { + g_free (fdata); + + if (str_convert (conv, filedata, translated_data) != ESTR_FAILURE) + fdata = g_string_free (translated_data, FALSE); + else + { + fdata = NULL; + g_string_free (translated_data, TRUE); + } + str_close_conv (conv); } } static cb_ret_t -md_callback (Widget *w, widget_msg_t msg, int parm) +md_callback (Widget * w, widget_msg_t msg, int parm) { - switch (msg) { + switch (msg) + { case WIDGET_RESIZED: - w->lines = help_lines; - return MSG_HANDLED; + w->lines = help_lines; + return MSG_HANDLED; default: - return default_proc (msg, parm); + return default_proc (msg, parm); } } @@ -935,12 +975,11 @@ mousedispatch_new (int y, int x, int yl, int xl) void interactive_display (const char *filename, const char *node) { - const int help_colors[DLG_COLOR_NUM] = - { - HELP_NORMAL_COLOR, /* common text color */ - 0, /* unused in help */ - HELP_BOLD_COLOR, /* title color */ - 0 /* unused in help */ + const int help_colors[DLG_COLOR_NUM] = { + HELP_NORMAL_COLOR, /* common text color */ + 0, /* unused in help */ + HELP_BOLD_COLOR, /* title color */ + 0 /* unused in help */ }; WButtonBar *help_bar; @@ -949,57 +988,59 @@ interactive_display (const char *filename, const char *node) char *filedata; if (filename != NULL) - filedata = load_file (filename); + filedata = load_file (filename); else - filedata = load_mc_home_file (mc_home, mc_home_alt, "mc.hlp", &hlpfile); + filedata = load_mc_home_file (mc_home, mc_home_alt, "mc.hlp", &hlpfile); if (filedata == NULL) - message (D_ERROR, MSG_ERROR, _(" Cannot open file %s \n %s "), filename ? filename : hlpfile, - unix_error_string (errno)); + message (D_ERROR, MSG_ERROR, _(" Cannot open file %s \n %s "), + filename ? filename : hlpfile, unix_error_string (errno)); g_free (hlpfile); if (filedata == NULL) - return; + return; translate_file (filedata); g_free (filedata); if (fdata == NULL) - return; + return; if ((node == NULL) || (*node == '\0')) - node = "[main]"; + node = "[main]"; main_node = search_string (fdata, node); - if (main_node == NULL) { - message (D_ERROR, MSG_ERROR, _(" Cannot find node %s in help file "), - node); - - /* Fallback to [main], return if it also cannot be found */ - main_node = search_string (fdata, "[main]"); - if (main_node == NULL) { - interactive_display_finish (); - return; - } + if (main_node == NULL) + { + message (D_ERROR, MSG_ERROR, _(" Cannot find node %s in help file "), node); + + /* Fallback to [main], return if it also cannot be found */ + main_node = search_string (fdata, "[main]"); + if (main_node == NULL) + { + interactive_display_finish (); + return; + } } help_lines = min (LINES - 4, max (2 * LINES / 3, 18)); whelp = - create_dlg (0, 0, help_lines + 4, HELP_WINDOW_WIDTH + 4, - help_colors, help_callback, "[Help]", _("Help"), - DLG_TRYUP | DLG_CENTER | DLG_WANT_TAB); + create_dlg (0, 0, help_lines + 4, HELP_WINDOW_WIDTH + 4, + help_colors, help_callback, "[Help]", _("Help"), + DLG_TRYUP | DLG_CENTER | DLG_WANT_TAB); selected_item = search_string_node (main_node, STRING_LINK_START) - 1; - currentpoint = main_node + 1; /* Skip the newline following the start of the node */ + currentpoint = main_node + 1; /* Skip the newline following the start of the node */ - for (history_ptr = HISTORY_SIZE; history_ptr;) { - history_ptr--; - history[history_ptr].page = currentpoint; - history[history_ptr].link = selected_item; + for (history_ptr = HISTORY_SIZE; history_ptr;) + { + history_ptr--; + history[history_ptr].page = currentpoint; + history[history_ptr].link = selected_item; } help_bar = buttonbar_new (TRUE); @@ -1011,16 +1052,16 @@ interactive_display (const char *filename, const char *node) add_widget (whelp, md); add_widget (whelp, help_bar); - buttonbar_set_label (help_bar, 1, Q_("ButtonBar|Help"), help_map, NULL); - buttonbar_set_label (help_bar, 2, Q_("ButtonBar|Index"), help_map, NULL); - buttonbar_set_label (help_bar, 3, Q_("ButtonBar|Prev"), help_map, NULL); + buttonbar_set_label (help_bar, 1, Q_ ("ButtonBar|Help"), help_map, NULL); + buttonbar_set_label (help_bar, 2, Q_ ("ButtonBar|Index"), help_map, NULL); + buttonbar_set_label (help_bar, 3, Q_ ("ButtonBar|Prev"), help_map, NULL); buttonbar_set_label (help_bar, 4, "", help_map, NULL); buttonbar_set_label (help_bar, 5, "", help_map, NULL); buttonbar_set_label (help_bar, 6, "", help_map, NULL); buttonbar_set_label (help_bar, 7, "", help_map, NULL); buttonbar_set_label (help_bar, 8, "", help_map, NULL); buttonbar_set_label (help_bar, 9, "", help_map, NULL); - buttonbar_set_label (help_bar, 10, Q_("ButtonBar|Quit"), help_map, NULL); + buttonbar_set_label (help_bar, 10, Q_ ("ButtonBar|Quit"), help_map, NULL); run_dlg (whelp); interactive_display_finish (); diff --git a/src/help.h b/src/help.h index e0ca3319..3d7bbc21 100644 --- a/src/help.h +++ b/src/help.h @@ -30,17 +30,17 @@ #define MC_HELP_H /* Markers used in the help files */ -#define CHAR_LINK_START '\01' /* Ctrl-A */ -#define CHAR_LINK_POINTER '\02' /* Ctrl-B */ -#define CHAR_LINK_END '\03' /* Ctrl-C */ -#define CHAR_NODE_END '\04' /* Ctrl-D */ -#define CHAR_ALTERNATE '\05' /* Ctrl-E */ -#define CHAR_NORMAL '\06' /* Ctrl-F */ -#define CHAR_VERSION '\07' /* Ctrl-G */ -#define CHAR_FONT_BOLD '\010' /* Ctrl-H */ -#define CHAR_FONT_NORMAL '\013' /* Ctrl-K */ -#define CHAR_FONT_ITALIC '\024' /* Ctrl-T */ +#define CHAR_LINK_START '\01' /* Ctrl-A */ +#define CHAR_LINK_POINTER '\02' /* Ctrl-B */ +#define CHAR_LINK_END '\03' /* Ctrl-C */ +#define CHAR_NODE_END '\04' /* Ctrl-D */ +#define CHAR_ALTERNATE '\05' /* Ctrl-E */ +#define CHAR_NORMAL '\06' /* Ctrl-F */ +#define CHAR_VERSION '\07' /* Ctrl-G */ +#define CHAR_FONT_BOLD '\010' /* Ctrl-H */ +#define CHAR_FONT_NORMAL '\013' /* Ctrl-K */ +#define CHAR_FONT_ITALIC '\024' /* Ctrl-T */ void interactive_display (const char *filename, const char *node); -#endif +#endif /* MC_HELP_H */ diff --git a/src/man2hlp.c b/src/man2hlp.c dissimilarity index 69% index 80f7776d..e7066fbc 100644 --- a/src/man2hlp.c +++ b/src/man2hlp.c @@ -1,896 +1,1029 @@ -/* 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; -} +/* 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; +} -- 2.11.4.GIT