Skip to content

Instantly share code, notes, and snippets.

@deton
Last active May 29, 2022 01:35
Show Gist options
  • Save deton/ebc9d4b4af6c216bd49cdb656a9b0ebc to your computer and use it in GitHub Desktop.
Save deton/ebc9d4b4af6c216bd49cdb656a9b0ebc to your computer and use it in GitHub Desktop.
lynx patch for <p> style white-space:pre
diff --git a/WWW/Library/Implementation/HTStyle.h b/WWW/Library/Implementation/HTStyle.h
index 79ba003..efaeaed 100644
--- a/WWW/Library/Implementation/HTStyle.h
+++ b/WWW/Library/Implementation/HTStyle.h
@@ -221,6 +221,8 @@ extern "C" {
ST_GlossaryCompact6,
ST_Example,
ST_Preformatted,
+ ST_PreformattedDiv,
+ ST_PreformattedP,
ST_Listing,
ST_Address,
ST_Note,
diff --git a/lynx.cfg b/lynx.cfg
index b6224f1..9ba4dd2 100644
--- a/lynx.cfg
+++ b/lynx.cfg
@@ -3034,6 +3034,14 @@ COLOR:6:brightred:black
#COLOR_STYLE: mild-colors.lss
#COLOR_STYLE: opaque.lss
+.h2 PARAGRAPH_STYLE
+# Pre-format <P> or <DIV> class names feature
+# for <p class="xxx"> or <div class="xxx"> with CSS ".xxx{white-space:pre}".
+# PARAGRAPH_STYLE:ppre <url> .<classname>[,.<classname>]*
+.ex 2
+# PARAGRAPH_STYLE:ppre https://nitter.net .media-body,.quote-text
+# PARAGRAPH_STYLE:ppre https://togetter.com .tweet
+
.h2 NESTED_TABLES
# This is an experimental feature for improving table layout.
# It is enabled by default when the COLOR_STYLE configuration is used,
diff --git a/src/DefaultStyle.c b/src/DefaultStyle.c
index 3dc17f7..ebb5a46 100644
--- a/src/DefaultStyle.c
+++ b/src/DefaultStyle.c
@@ -346,9 +346,27 @@ HTStyleInit(
NO, NO, 0, 0, 0
);
+static HTStyle HTStylePreformattedDiv =
+HTStyleInit( /* <div style="white-space: pre;"> */
+ &HTStylePreformatted,
+ PreformattedDiv, "DIVPRE",
+ HT_FONT, 1, HT_BLACK, 0, 0,
+ 3, 3, 6, HT_LEFT, 1, 0, tabs_8,
+ YES, NO, 0, 0, 0
+);
+
+static HTStyle HTStylePreformattedP =
+HTStyleInit( /* <p style="white-space: pre;"> */
+ &HTStylePreformattedDiv,
+ PreformattedP, "PPRE",
+ HT_FONT, 1, HT_BLACK, 0, 0,
+ 3, 3, 6, HT_LEFT, 1, 0, tabs_8,
+ YES, NO, 0, 0, 0
+);
+
static HTStyle HTStyleListing =
HTStyleInit(
- &HTStylePreformatted, Listing, "LISTING",
+ &HTStylePreformattedP, Listing, "LISTING",
HT_FONT, 1, HT_BLACK, 0, 0,
0, 0, 0, HT_LEFT, 1, 0, tabs_8,
NO, NO, 0, 0, 0);
diff --git a/src/HTML.c b/src/HTML.c
index cf2e18b..9121881 100644
--- a/src/HTML.c
+++ b/src/HTML.c
@@ -62,10 +62,12 @@
#include <SGML.h>
#include <AttrList.h>
#include <LYHash.h>
+#endif /* USE_COLOR_STYLE */
+#if defined(USE_COLOR_STYLE) || defined(EXP_PPRE)
#include <LYStyle.h>
#undef SELECTED_STYLES
#define pHText_changeStyle(X,Y,Z) {}
-#endif /* USE_COLOR_STYLE */
+#endif
#ifdef USE_SOURCE_CACHE
#include <HTAccess.h>
@@ -112,7 +114,7 @@ static HTStyleSheet *styleSheet = NULL; /* Application-wide */
/* Module-wide style cache
*/
-static HTStyle *styles[HTML_ELEMENTS + LYNX_HTML_EXTRA_ELEMENTS];
+static HTStyle *styles[HTML_ELEMENTS + LYNX_HTML_EXTRA_ELEMENTS + 1];
/* adding 24 nested list styles */
/* and 3 header alignment styles */
@@ -429,7 +431,12 @@ void HTML_put_character(HTStructured * me, int c)
/*
* Free format text.
*/
- if (me->sp->style->id == ST_Preformatted) {
+ if (me->sp->style->id == ST_Preformatted
+#ifdef EXP_PPRE
+ || me->sp->style->id == ST_PreformattedP
+ || me->sp->style->id == ST_PreformattedDiv
+#endif
+ ) {
if (c != '\r' &&
!(c == '\n' && me->inLABEL && !me->inP) &&
!(c == '\n' && !me->inPRE)) {
@@ -1725,6 +1732,13 @@ static int HTML_start_element(HTStructured * me, int element_number,
me->sp[0].tag_number == HTML_LH ||
me->sp[0].tag_number == HTML_DD)
me->current_default_alignment = HT_LEFT;
+#ifdef EXP_PPRE
+ if (present && present[HTML_DIV_CLASS] &&
+ LYParaStyle_match(me->ppre_style, value[HTML_DIV_CLASS])) {
+ change_paragraph_style(me, styles[HTML_DIVPRE]);
+ me->current_default_alignment = styles[HTML_DIVPRE]->alignment;;
+ }
+#endif
LYHandlePlike(me, present, value, include, HTML_DIV_ALIGN, TRUE);
me->DivisionAlignments[me->Division_Level] = (short)
me->current_default_alignment;
@@ -1742,15 +1756,27 @@ static int HTML_start_element(HTStructured * me, int element_number,
me->current_default_alignment = styles[HTML_DRIGHT]->alignment;
} else {
me->DivisionAlignments[me->Division_Level] = HT_LEFT;
- change_paragraph_style(me, styles[HTML_DLEFT]);
+#ifdef EXP_PPRE
+ if (present && present[HTML_DIV_CLASS] &&
+ LYParaStyle_match(me->ppre_style, value[HTML_DIV_CLASS]))
+ change_paragraph_style(me, styles[HTML_DIVPRE]);
+ else
+#endif
+ change_paragraph_style(me, styles[HTML_DLEFT]);
UPDATE_STYLE;
- me->current_default_alignment = styles[HTML_DLEFT]->alignment;
+ me->current_default_alignment = me->new_style->alignment;
}
} else {
me->DivisionAlignments[me->Division_Level] = HT_LEFT;
- change_paragraph_style(me, styles[HTML_DLEFT]);
+#ifdef EXP_PPRE
+ if (present && present[HTML_DIV_CLASS] &&
+ LYParaStyle_match(me->ppre_style, value[HTML_DIV_CLASS]))
+ change_paragraph_style(me, styles[HTML_DIVPRE]);
+ else
+#endif
+ change_paragraph_style(me, styles[HTML_DLEFT]);
UPDATE_STYLE;
- me->current_default_alignment = styles[HTML_DLEFT]->alignment;
+ me->current_default_alignment = me->new_style->alignment;
}
CHECK_ID(HTML_DIV_ID);
break;
@@ -1846,6 +1872,11 @@ static int HTML_start_element(HTStructured * me, int element_number,
break;
case HTML_P:
+#ifdef EXP_PPRE
+ if (present && present[HTML_P_CLASS] &&
+ LYParaStyle_match(me->ppre_style, value[HTML_P_CLASS]))
+ change_paragraph_style(me, styles[HTML_PPRE]);
+#endif
LYHandlePlike(me, present, value, include, HTML_P_ALIGN, TRUE);
CHECK_ID(HTML_P_ID);
break;
@@ -5293,6 +5324,10 @@ static int HTML_start_element(HTStructured * me, int element_number,
} else if (me->List_Nesting_Level >= 0 ||
((me->Division_Level < 0) &&
(me->sp->style->id == ST_Normal ||
+#ifdef EXP_PPRE
+ me->sp->style->id == ST_PreformattedP ||
+ me->sp->style->id == ST_PreformattedDiv ||
+#endif
me->sp->style->id == ST_Preformatted))) {
me->sp->style->alignment = HT_LEFT;
} else {
@@ -5926,6 +5961,9 @@ static int HTML_end_element(HTStructured * me, int element_number,
break;
case HTML_P:
+#ifdef EXP_PPRE /* HTML_PPRE style end */
+ change_paragraph_style(me, me->sp->style);
+#endif
LYHandlePlike(me,
(const BOOL *) 0, (STRING2PTR) 0,
include, 0,
@@ -7414,6 +7452,7 @@ static void get_styles(void)
styles[HTML_DCENTER] = st[ST_DivCenter];
styles[HTML_DLEFT] = st[ST_DivLeft];
styles[HTML_DRIGHT] = st[ST_DivRight];
+ styles[HTML_DIVPRE] = st[ST_PreformattedDiv];
styles[HTML_DL] = st[ST_Glossary];
/* nested list styles */
@@ -7462,6 +7501,7 @@ static void get_styles(void)
styles[HTML_PLAINTEXT] =
styles[HTML_XMP] = st[ST_Example];
styles[HTML_PRE] = st[ST_Preformatted];
+ styles[HTML_PPRE] = st[ST_PreformattedP];
styles[HTML_LISTING] = st[ST_Listing];
}
@@ -7590,6 +7630,9 @@ HTStructured *HTML_new(HTParentAnchor *anchor,
me->sp->style = default_style; /* INVALID */
me->sp->style->alignment = HT_LEFT;
me->stack_overrun = FALSE;
+#ifdef EXP_PPRE
+ me->ppre_style = LYParaStyle_for_url(anchor->address);
+#endif
me->Division_Level = -1;
me->Underline_Level = 0;
diff --git a/src/HTML.h b/src/HTML.h
index 9f5d1d5..e2ea634 100644
--- a/src/HTML.h
+++ b/src/HTML.h
@@ -141,6 +141,9 @@ extern "C" {
stack_element *sp; /* Style stack pointer */
BOOL stack_overrun; /* Was MAX_NESTING exceeded? */
int skip_stack; /* flag to skip next style stack operation */
+#ifdef EXP_PPRE
+ int ppre_style; /* Pre-format <p> and <div> style index */
+#endif
/*
* Track if we are in an anchor, paragraph, address, base, etc.
diff --git a/src/HTNestedList.h b/src/HTNestedList.h
index 5a5f103..7f44924 100644
--- a/src/HTNestedList.h
+++ b/src/HTNestedList.h
@@ -39,6 +39,9 @@
#define HTML_OBJECT_M (HTML_ELEMENTS+31)
-#define LYNX_HTML_EXTRA_ELEMENTS 31
+#define HTML_DIVPRE (HTML_ELEMENTS+32)
+#define HTML_PPRE (HTML_ELEMENTS+33)
+
+#define LYNX_HTML_EXTRA_ELEMENTS 33
#endif /* HTNESTEDLIST_H */
diff --git a/src/LYCharUtils.c b/src/LYCharUtils.c
index 0013989..03b2e81 100644
--- a/src/LYCharUtils.c
+++ b/src/LYCharUtils.c
@@ -2635,6 +2635,10 @@ void LYHandlePlike(HTStructured * me, const BOOL *present,
me->sp->style->id == ST_DivRight)) ||
((me->Division_Level < 0) &&
(me->sp->style->id == ST_Normal ||
+#ifdef EXP_PPRE
+ me->sp->style->id == ST_PreformattedP ||
+ me->sp->style->id == ST_PreformattedDiv ||
+#endif
me->sp->style->id == ST_Preformatted))) {
me->sp->style->alignment = HT_LEFT;
} else {
@@ -3213,6 +3217,10 @@ void LYResetParagraphAlignment(HTStructured * me)
if (me->List_Nesting_Level >= 0 ||
((me->Division_Level < 0) &&
(me->sp->style->id == ST_Normal ||
+#ifdef EXP_PPRE
+ me->sp->style->id == ST_PreformattedP ||
+ me->sp->style->id == ST_PreformattedDiv ||
+#endif
me->sp->style->id == ST_Preformatted))) {
me->sp->style->alignment = HT_LEFT;
} else {
diff --git a/src/LYMain.c b/src/LYMain.c
index af78ef7..0c248ad 100644
--- a/src/LYMain.c
+++ b/src/LYMain.c
@@ -876,6 +876,9 @@ static void free_lynx_globals(void)
FREE(nonoption);
#endif
LYFreeStringList(positionable_editor);
+#ifdef EXP_PPRE
+ LYParaStyle_free();
+#endif
return;
}
diff --git a/src/LYReadCFG.c b/src/LYReadCFG.c
index 18bc34c..935f04c 100644
--- a/src/LYReadCFG.c
+++ b/src/LYReadCFG.c
@@ -42,6 +42,10 @@
#include <HTNews.h>
#endif
+#ifdef EXP_PPRE
+#include <LYStyle.h>
+#endif
+
BOOLEAN have_read_cfg = FALSE;
BOOLEAN LYUseNoviceLineTwo = TRUE;
@@ -1659,6 +1663,9 @@ static Config_Type Config_Table [] =
PARSE_SET(RC_UPDATE_TERM_TITLE, update_term_title),
PARSE_FUN(RC_NONRESTARTING_SIGWINCH, nonrest_sigwinch_fun),
PARSE_FUN(RC_OUTGOING_MAIL_CHARSET, outgoing_mail_charset_fun),
+#ifdef EXP_PPRE
+ PARSE_FUN(RC_PARAGRAPH_STYLE, LYParaStyle_add),
+#endif
#ifdef DISP_PARTIAL
PARSE_SET(RC_PARTIAL, display_partial_flag),
PARSE_INT(RC_PARTIAL_THRES, partial_threshold),
diff --git a/src/LYStyle.c b/src/LYStyle.c
index 77be188..ebc8b22 100644
--- a/src/LYStyle.c
+++ b/src/LYStyle.c
@@ -968,3 +968,123 @@ void reinit_color_styles(void)
}
#endif /* USE_COLOR_STYLE */
+
+#ifdef EXP_PPRE
+static HTList *paragraph_styles = NULL;
+
+typedef struct _paragraph_style_item {
+ char *url;
+ HTList *classnames;
+} paragraph_style_item;
+
+int LYParaStyle_add(char *config)
+{
+ char *style;
+ char *url;
+ char *selector;
+ char *p;
+ HTList *classnames;
+ paragraph_style_item *item = NULL;
+
+ style = HTNextField(&config);
+ if (!style)
+ return 0;
+ if (strcmp(style, "ppre")) {
+ CTRACE((tfp, "Unknown PARAGRAPH_STYLE:%s ignored.\n", style));
+ return 0;
+ }
+ url = HTNextField(&config);
+ if (!url)
+ return 0;
+ /* '.' prefixed class names separated by comma. ".name3,.name4" */
+ selector = HTNextField(&config);
+ if (!selector)
+ return 0;
+ classnames = HTList_new();
+ while ((p = LYstrsep(&selector, ",")) != NULL) {
+ if (*p != '.') {
+ CTRACE((tfp, "Unsupported PARAGRAPH_STYLE selector:%s ignored.\n", p));
+ continue;
+ }
+ p++;
+ if (isEmpty(p))
+ continue;
+ char *classname = NULL;
+ StrAllocCopy(classname, p);
+ HTList_addObject(classnames, classname);
+ }
+
+ if (paragraph_styles == NULL)
+ paragraph_styles = HTList_new();
+ item = typecalloc(paragraph_style_item);
+ if (item == NULL)
+ outofmem(__FILE__, "LYParaStyle_add");
+ StrAllocCopy(item->url, url);
+ item->classnames = classnames;
+ HTList_addObject(paragraph_styles, item);
+ return 0;
+}
+
+void LYParaStyle_free()
+{
+ paragraph_style_item *item;
+ HTList *cur = paragraph_styles;
+
+ while ((item = (paragraph_style_item *) HTList_nextObject(cur)) != NULL) {
+ FREE(item->url);
+ LYFreeStringList(item->classnames);
+ }
+ HTList_delete(paragraph_styles);
+ paragraph_styles = NULL;
+}
+
+int LYParaStyle_for_url(const char *url)
+{
+ int pos;
+ paragraph_style_item *item;
+ HTList *cur = paragraph_styles;
+
+ for (pos = 0;
+ (item = (paragraph_style_item *) HTList_nextObject(cur)) != NULL;
+ pos++) {
+ if (StrNCmp(item->url, url, strlen(item->url)) == 0) {
+ CTRACE((tfp, "LYParaStyle_for_url style %d for:%s\n", pos, url));
+ return pos;
+ }
+ }
+ return -1;
+}
+
+/*
+ * Check whether 'attr' matches class names for styleIndex.
+ * attr: class names separated by space. "name1 name2"
+ */
+BOOL LYParaStyle_match(int styleIndex, const char *attr)
+{
+ char *tmpbuf = 0;
+ char *anext;
+ char *a;
+ paragraph_style_item *style;
+
+ if (styleIndex < 0 || isEmpty(attr))
+ return FALSE;
+ style = HTList_objectAt(paragraph_styles, styleIndex);
+ if (style == NULL)
+ return FALSE;
+
+ StrAllocCopy(tmpbuf, attr);
+ anext = tmpbuf;
+ while ((a = LYstrsep(&anext, " ")) != 0) {
+ char *name;
+ HTList *cur = style->classnames;
+ while ((name = (char *) HTList_nextObject(cur)) != NULL) {
+ if (STREQ(name, a)) {
+ FREE(tmpbuf);
+ return TRUE;
+ }
+ }
+ }
+ FREE(tmpbuf);
+ return FALSE;
+}
+#endif /* EXP_PPRE */
diff --git a/src/LYStyle.h b/src/LYStyle.h
index a7e5e81..8e8da70 100644
--- a/src/LYStyle.h
+++ b/src/LYStyle.h
@@ -85,4 +85,19 @@ extern "C" {
#endif /* USE_COLOR_STYLE */
extern int lynx_has_color;
+#ifdef EXP_PPRE
+#ifdef __cplusplus
+extern "C" {
+#endif
+ /* Functions for paragraph style */
+ extern int LYParaStyle_add(char *config);
+ extern void LYParaStyle_free();
+ extern int LYParaStyle_for_url(const char *url);
+ extern BOOL LYParaStyle_match(int styleIndex, const char *attr);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* EXP_PPRE */
+
#endif /* LYSTYLE_H */
diff --git a/src/LYrcFile.h b/src/LYrcFile.h
index f23c87f..14c18b0 100644
--- a/src/LYrcFile.h
+++ b/src/LYrcFile.h
@@ -183,6 +183,7 @@
#define RC_NUMBER_FIELDS_ON_LEFT "number_fields_on_left"
#define RC_NUMBER_LINKS_ON_LEFT "number_links_on_left"
#define RC_OUTGOING_MAIL_CHARSET "outgoing_mail_charset"
+#define RC_PARAGRAPH_STYLE "paragraph_style"
#define RC_PARTIAL "partial"
#define RC_PARTIAL_THRES "partial_thres"
#define RC_PERSISTENT_COOKIES "persistent_cookies"
diff --git a/userdefs.h b/userdefs.h
index a1d370a..35f1c06 100644
--- a/userdefs.h
+++ b/userdefs.h
@@ -1677,6 +1677,13 @@
*/
#define SSL_CERT_FILE NULL
+/**************************
+ * Pre-format <P> class names feature.
+ * for <p class="xxx"> or <div class="xxx">
+ * with CSS ".xxx{white-space:pre}"
+ */
+#define EXP_PPRE
+
/****************************************************************
* Section 4. Things you MUST check only if you plan to use Lynx
* in an anonymous account (allow public access to Lynx).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment