summaryrefslogtreecommitdiff
path: root/hw/xfree86/utils/xorgcfg/help.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/xfree86/utils/xorgcfg/help.c')
-rw-r--r--hw/xfree86/utils/xorgcfg/help.c1786
1 files changed, 1786 insertions, 0 deletions
diff --git a/hw/xfree86/utils/xorgcfg/help.c b/hw/xfree86/utils/xorgcfg/help.c
new file mode 100644
index 000000000..2b25e8ede
--- /dev/null
+++ b/hw/xfree86/utils/xorgcfg/help.c
@@ -0,0 +1,1786 @@
+/*
+ * Copyright (c) 2000 by Conectiva S.A. (http://www.conectiva.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * CONECTIVA LINUX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Conectiva Linux shall
+ * not be used in advertising or otherwise to promote the sale, use or other
+ * dealings in this Software without prior written authorization from
+ * Conectiva Linux.
+ *
+ * Author: Paulo César Pereira de Andrade <pcpa@conectiva.com.br>
+ *
+ * $XFree86: xc/programs/Xserver/hw/xfree86/xf86cfg/help.c,v 1.7 2002/06/06 21:03:32 paulo Exp $
+ */
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <X11/Shell.h>
+#include <X11/Xaw/AsciiText.h>
+#include <X11/Xaw/Command.h>
+#include <X11/Xaw/Form.h>
+#include <X11/Xaw/Paned.h>
+
+#include <X11/Xaw/Text.h>
+#include <X11/Xaw/TextSinkP.h>
+#include <X11/Xaw/TextSrcP.h>
+#include <X11/Xmu/SysUtil.h>
+#include <X11/Xmu/Xmu.h>
+#include <stdlib.h> /* for bsearch() */
+#include <ctype.h>
+#include "help.h"
+#include "options.h"
+
+/*
+ * Prototypes
+ */
+static void CloseCallback(Widget, XtPointer, XtPointer);
+static void StartHelp(void);
+void Html_ModeStart(Widget);
+
+/*
+ * Initialization
+ */
+static Widget shell, text;
+static Bool popped_up = False;
+
+/*
+ * Implementation
+ */
+void
+Help(char *topic)
+{
+ Widget source;
+ char *str = NULL;
+ Bool error = False;
+ static char *def_text = "<h2>Help Error</h2>"
+ "No help available for the topic <b>%s</b>.";
+ XtResource resource = {
+ NULL, "HelpMessage", XtRString, sizeof(char*),
+ 0, XtRString, NULL
+ };
+
+ StartHelp();
+ source = XawTextGetSource(text);
+ XawTextSourceClearEntities(source, 0,
+ XawTextSourceScan(source, 0, XawstAll,
+ XawsdRight, 1, True));
+ if (topic != NULL) {
+ resource.resource_name = topic;
+ XtGetApplicationResources(shell, (XtPointer)&str,
+ &resource, 1, NULL, 0);
+ }
+ if (str == NULL) {
+ int len;
+
+ error = True;
+ if (topic == NULL)
+ topic = "(null argument)";
+ str = XtMalloc(len = strlen(topic) + strlen(def_text) + 1);
+ XmuSnprintf(str, len, def_text, topic);
+ }
+ XtVaSetValues(text, XtNstring, str, NULL, 0);
+ if (error)
+ XtFree(str);
+
+ Html_ModeStart(source);
+ _XawTextBuildLineTable((TextWidget)text,
+ XawTextTopPosition(text), True);
+ XawTextDisplay(text);
+ if (popped_up == False) {
+ popped_up = True;
+ XtPopup(shell, XtGrabNone);
+ XtSetKeyboardFocus(shell, text);
+ }
+}
+
+static void
+StartHelp(void)
+{
+ static XtResource resource = {
+ "properties", "Properties", XtRString, sizeof(char*),
+ 0, XtRString, NULL
+ };
+
+ if (shell == NULL) {
+ Widget pane, commands, close;
+ char *props;
+ XawTextPropertyList *propl;
+
+ shell = XtCreatePopupShell("help", transientShellWidgetClass,
+ toplevel, NULL, 0);
+ pane = XtCreateManagedWidget("pane", panedWidgetClass,
+ shell, NULL, 0);
+ text = XtVaCreateManagedWidget("text", asciiTextWidgetClass,
+ pane, XtNeditType, XawtextRead, NULL, 0);
+ commands = XtCreateManagedWidget("commands", formWidgetClass, pane,
+ NULL, 0);
+ close = XtCreateManagedWidget("close", commandWidgetClass,
+ commands, NULL, 0);
+ XtAddCallback(close, XtNcallback, CloseCallback, NULL);
+ XtRealizeWidget(shell);
+ XSetWMProtocols(DPY, XtWindow(shell), &wm_delete_window, 1);
+ XtGetApplicationResources(text, (XtPointer)&props,
+ &resource, 1, NULL, 0);
+ propl = XawTextSinkConvertPropertyList("html", props,
+ toplevel->core.screen,
+ toplevel->core.colormap,
+ toplevel->core.depth);
+ XtVaSetValues(XawTextGetSink(text), XawNtextProperties, propl, NULL, 0);
+ }
+}
+
+/*ARGSUSED*/
+static void
+CloseCallback(Widget w, XtPointer user_data, XtPointer call_data)
+{
+ XtPopdown(shell);
+ popped_up = False;
+}
+
+/*ARGSUSED*/
+void
+HelpCancelAction(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ CloseCallback(w, NULL, NULL);
+}
+
+
+/* bellow is a modified version of the html-mode.c I wrote for xedit
+ * (at least) temporarily dead.
+ */
+
+/*
+ * Copyright (c) 1999 by The XFree86 Project, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of the XFree86 Project shall
+ * not be used in advertising or otherwise to promote the sale, use or other
+ * dealings in this Software without prior written authorization from the
+ * XFree86 Project.
+ *
+ * Author: Paulo César Pereira de Andrade
+ */
+
+#define Html_Peek(parser) ((parser)->next)
+
+/*
+ * Types
+ */
+typedef struct _Html_Parser Html_Parser;
+typedef struct _Html_Item Html_Item;
+
+typedef struct _Html_TagInfo {
+ char *name;
+ int entity : 1; /* it changes the type of the text */
+ int nest : 1; /* does not close tags automatically */
+ int end : 1; /* need a close markup */
+ int adnl : 1; /* add newline before/after tag contents */
+ int para : 1; /* changes the paragraph formatting */
+ unsigned long mask; /* enforce use of attributes of this tag-info */
+ unsigned long xlfd_mask;
+ void (*parse_args)(Html_Parser*, Html_Item*);
+ XawTextProperty *override;
+ XrmQuark ident;
+} Html_TagInfo;
+
+struct _Html_Item {
+ XrmQuark ident;
+ XawTextPosition start, end;
+ Html_TagInfo *info;
+
+ XawTextProperty *combine;
+ Bool override;
+ int li;
+
+ XtPointer replace;
+
+ Html_Item *parent, *child, *next;
+};
+
+struct _Html_Parser {
+ Widget source;
+ XawTextBlock block, replace;
+ XawTextPosition position, offset, start, end, last;
+ XrmQuark quark;
+ int i, ch, next;
+ Html_Item *item, *head;
+ XmuScanline *mask;
+ int space, pre, adnl, list, desc, column;
+ Bool spc;
+ XawTextBlock *entity;
+
+ Pixel alink;
+};
+
+typedef struct _Html_SourceInfo Html_SourceInfo;
+struct _Html_SourceInfo {
+ Widget source;
+ XawTextBlock block;
+ XawTextPosition last;
+ Html_SourceInfo *next;
+};
+
+/*
+ * Proptotypes
+ */
+void Html_ModeEnd(Widget);
+static void Html_ModeInit(void);
+static void Html_ParseCallback(Widget, XtPointer, XtPointer);
+static Html_TagInfo *Html_GetInfo(char*);
+static int Html_Get(Html_Parser*);
+static int Html_Parse1(Html_Parser*);
+static int Html_Parse2(Html_Parser*);
+static void Html_ParseTag(Html_Parser*);
+static void Html_Commit(Html_Parser*);
+static void Html_AddEntities(Html_Parser*, Html_Item*);
+
+static int Html_Put(Html_Parser*, int);
+static void Html_Puts(Html_Parser*, char*);
+static int Html_Format1(Html_Parser*);
+static int Html_Format2(Html_Parser*);
+static int Html_Format3(Html_Parser*);
+static void Html_FormatTag(Html_Parser*);
+
+static void Html_AArgs(Html_Parser*, Html_Item*);
+static void Html_FontArgs(Html_Parser*, Html_Item*);
+
+/*
+ * Initialization
+ */
+static XrmQuark
+ Qbr,
+ Qdefault,
+ Qdd,
+ Qdl,
+ Qdt,
+ Qentity,
+ Qetag,
+ Qhide,
+ Qli,
+ Qol,
+ Qp,
+ Qpre,
+ Qspace,
+ Qtag,
+ Qul;
+
+static Html_TagInfo tag_info[] = {
+ {"a", 1, 0, 1, 0, 0,
+ 0, 0,
+ Html_AArgs},
+ {"address", 1, 0, 1, 0, 0,
+ 0, XAW_TPROP_SLANT,
+ },
+ {"b", 1, 0, 1, 0, 0,
+ 0, XAW_TPROP_WEIGHT,
+ },
+ {"blockquote", 0, 1, 1, 1, 1,
+ 0, 0,
+ },
+ {"body", 0, 0, 1, 0, 0,
+ 0, 0,
+ },
+ {"br", 0, 0, 0, 0, 0,
+ },
+ {"code", 1, 0, 1, 0, 0,
+ 0, XAW_TPROP_FAMILY | XAW_TPROP_PIXELSIZE,
+ },
+ {"dd", 0, 1, 1, 0, 1,
+ 0, 0},
+ {"dl", 0, 1, 1, 0, 0,
+ 0, 0,
+ },
+ {"dt", 0, 0, 1, 0, 0,
+ 0, 0},
+ {"em", 1, 0, 1, 0, 0,
+ 0, XAW_TPROP_SLANT,
+ },
+ {"font", 1, 1, 1, 0, 0,
+ 0, 0,
+ Html_FontArgs},
+ {"h1", 1, 0, 1, 1, 0,
+ 0, XAW_TPROP_WEIGHT | XAW_TPROP_PIXELSIZE,
+ },
+ {"h2", 1, 0, 1, 1, 0,
+ 0, XAW_TPROP_WEIGHT | XAW_TPROP_PIXELSIZE,
+ },
+ {"h3", 1, 0, 1, 1, 0,
+ 0, XAW_TPROP_WEIGHT | XAW_TPROP_PIXELSIZE,
+ },
+ {"h4", 1, 0, 1, 1, 0,
+ 0, XAW_TPROP_WEIGHT | XAW_TPROP_PIXELSIZE,
+ },
+ {"h5", 1, 0, 1, 1, 0,
+ 0, XAW_TPROP_WEIGHT | XAW_TPROP_PIXELSIZE,
+ },
+ {"h6", 1, 0, 1, 1, 0,
+ 0, XAW_TPROP_WEIGHT | XAW_TPROP_PIXELSIZE,
+ },
+ {"head", 0, 0, 1, 0, 0,
+ 0, 0,
+ },
+ {"html", 0, 0, 1, 0, 0,
+ 0, 0,
+ },
+ {"i", 1, 0, 1, 0, 0,
+ 0, XAW_TPROP_SLANT,
+ },
+ {"kbd", 1, 0, 1, 0, 0,
+ 0, XAW_TPROP_FAMILY | XAW_TPROP_PIXELSIZE,
+ },
+ {"li", 0, 0, 0, 0, 0,
+ 0, 0},
+ {"ol", 0, 1, 1, 0, 1,
+ 0, 0,
+ },
+ {"p", 0, 0, 0, 1, 0,
+ },
+ {"pre", 1, 0, 1, 1, 0,
+ 0, XAW_TPROP_FAMILY | XAW_TPROP_PIXELSIZE,
+ },
+ {"samp", 1, 0, 1, 0, 0,
+ 0, XAW_TPROP_FAMILY | XAW_TPROP_PIXELSIZE,
+ },
+ {"strong", 1, 0, 1, 0, 0,
+ 0, XAW_TPROP_WEIGHT,
+ },
+ {"tt", 1, 0, 1, 0, 0,
+ 0, XAW_TPROP_FAMILY | XAW_TPROP_PIXELSIZE,
+ },
+ {"ul", 0, 1, 1, 0, 1,
+ 0, 0,
+ },
+};
+
+static char *pnl = "<p>\n", *nlpnl = "\n<p>\n";
+static Html_SourceInfo *source_info;
+
+/*
+ * Implementation
+ */
+static char *
+Html_GetText(Widget src, XawTextPosition position)
+{
+ char *result, *tempResult;
+ XawTextPosition offset = 0;
+ XawTextBlock text;
+
+ tempResult = result = XtMalloc((unsigned)(position + 1));
+
+ while (offset < position) {
+ offset = XawTextSourceRead(src, offset, &text, position - offset);
+ if (!text.length)
+ break;
+ memcpy(tempResult, text.ptr, (unsigned)text.length);
+ tempResult += text.length;
+ }
+
+ *tempResult = '\0';
+
+ return (result);
+}
+
+void
+Html_ModeStart(Widget src)
+{
+ Html_Parser *parser = XtNew(Html_Parser);
+ Html_Item *next, *item;
+ XColor color, exact;
+ Html_SourceInfo *info = XtNew(Html_SourceInfo);
+
+ if (XAllocNamedColor(XtDisplay(toplevel), toplevel->core.colormap,
+ "blue", &color, &exact))
+ parser->alink = color.pixel;
+ else
+ parser->alink = 0L;
+
+ XtVaSetValues(src, XtNeditType, XawtextEdit, NULL, 0);
+
+ Html_ModeInit();
+
+ /* initialize parser state */
+ parser->source = src;
+ parser->position = XawTextSourceRead(parser->source, 0,
+ &parser->block, 4096);
+ parser->replace.ptr = NULL;
+ parser->replace.firstPos = 0;
+ parser->replace.length = 0;
+ parser->replace.format = FMT8BIT;
+ parser->offset = -1;
+ parser->quark = NULLQUARK;
+ parser->i = 0;
+ parser->i = parser->ch = parser->next = 0;
+ parser->last = XawTextSourceScan(src, 0, XawstAll, XawsdRight, 1, 1);
+ if (parser->block.length == 0)
+ parser->ch = parser->next = EOF;
+ else
+ (void)Html_Get(parser);
+ parser->pre = 0;
+ parser->adnl = 1;
+ parser->list = parser->desc = parser->column = 0;
+ parser->spc = True;
+
+ info->source = src;
+ info->block.ptr = Html_GetText(src, parser->last);
+ info->block.length = parser->last;
+ info->block.format = FMT8BIT;
+ info->block.firstPos = 0;
+ info->next = NULL;
+ if (source_info == NULL)
+ source_info = info;
+ else {
+ Html_SourceInfo *tmp = source_info;
+
+ while (tmp->next)
+ tmp = tmp->next;
+ tmp->next = info;
+ }
+
+ while (Html_Format1(parser) != EOF)
+ ;
+ XawTextSourceReplace(parser->source, 0, parser->last, &parser->replace);
+ XtFree(parser->replace.ptr);
+
+ /* re-initialize parser state */
+ parser->position = XawTextSourceRead(parser->source, 0,
+ &parser->block, 4096);
+ parser->offset = -1;
+ parser->quark = NULLQUARK;
+ parser->i = parser->ch = parser->next = 0;
+ parser->last = XawTextSourceScan(src, 0, XawstAll, XawsdRight, 1, 1);
+ info->last = parser->last;
+ if (parser->block.length == 0)
+ parser->ch = parser->next = EOF;
+ else
+ (void)Html_Get(parser);
+ parser->adnl = 1;
+ parser->list = parser->desc = parser->column = 0;
+ parser->spc = True;
+ parser->head = parser->item = NULL;
+
+ parser->mask = XmuNewScanline(0, 0, 0);
+
+ /* build html structure information */
+ while (Html_Parse1(parser) != EOF)
+ ;
+
+ /* create top level entity mask */
+ (void)XmuScanlineNot(parser->mask, 0, parser->last);
+
+ item = parser->item;
+ while (item) {
+ next = item->next;
+ Html_AddEntities(parser, item);
+ if (item->combine)
+ XtFree((XtPointer)item->combine);
+ XtFree((XtPointer)item);
+ item = next;
+ }
+ XmuDestroyScanline(parser->mask);
+
+ XtVaSetValues(src, XtNeditType, XawtextRead, NULL, 0);
+
+ XtFree((XtPointer)parser);
+
+ /* add callbacks for interactive changes */
+ XtAddCallback(src, XtNpropertyCallback, Html_ParseCallback, NULL);
+}
+
+void
+Html_ModeEnd(Widget src)
+{
+ Html_SourceInfo *info, *pinfo;
+
+ XtRemoveCallback(src, XtNpropertyCallback, Html_ParseCallback, NULL);
+ for (pinfo = info = source_info; info; pinfo = info, info = info->next)
+ if (info->source == src)
+ break;
+
+ if (info == NULL)
+ return;
+
+ XawTextSourceClearEntities(src, 0, info->last);
+ XtVaSetValues(src, XtNeditType, XawtextEdit, NULL, 0);
+ XawTextSourceReplace(src, 0, info->last, &info->block);
+ XtVaSetValues(src, XtNeditType, XawtextRead, NULL, 0);
+
+ if (info == source_info)
+ source_info = source_info->next;
+ else
+ pinfo->next = info->next;
+ XtFree(info->block.ptr);
+ XtFree((XtPointer)info);
+}
+
+static void
+Html_ParseCallback(Widget w, XtPointer client_data, XtPointer call_data)
+{
+}
+
+static int
+bcmp_tag_info(_Xconst void *left, _Xconst void *right)
+{
+ return (strcmp((char*)left, ((Html_TagInfo*)right)->name));
+}
+
+static Html_TagInfo *
+Html_GetInfo(char *name)
+{
+ return (bsearch(name, tag_info, sizeof(tag_info) / sizeof(tag_info[0]),
+ sizeof(Html_TagInfo), bcmp_tag_info));
+}
+
+static int
+Html_Get(Html_Parser *parser)
+{
+ if (parser->ch == EOF)
+ return (EOF);
+ if (parser->i >= parser->block.length) {
+ parser->i = 0;
+ parser->position = XawTextSourceRead(parser->source, parser->position,
+ &parser->block, 4096);
+ }
+ parser->ch = parser->next;
+ if (parser->block.length == 0)
+ parser->next = EOF;
+ else
+ parser->next = (unsigned char)parser->block.ptr[parser->i++];
+ parser->offset++;
+
+ return (parser->ch);
+}
+
+static void
+Html_ModeInit(void)
+{
+ static int initialized;
+ int i;
+
+ if (initialized)
+ return;
+
+ Qbr = XrmPermStringToQuark("br");
+ Qdd = XrmPermStringToQuark("dd");
+ Qdefault = XrmPermStringToQuark("default");
+ Qdl = XrmPermStringToQuark("dl");
+ Qdt = XrmPermStringToQuark("dt");
+ Qentity = XrmPermStringToQuark("entity");
+ Qetag = XrmPermStringToQuark("/tag");
+ Qhide = XrmPermStringToQuark("hide");
+ Qli = XrmPermStringToQuark("li");
+ Qol = XrmPermStringToQuark("ol");
+ Qp = XrmPermStringToQuark("p");
+ Qpre = XrmPermStringToQuark("pre");
+ Qspace = XrmPermStringToQuark("space");
+ Qtag = XrmPermStringToQuark("tag");
+ Qul = XrmPermStringToQuark("ul");
+
+ for (i = 0; i < sizeof(tag_info) / sizeof(tag_info[0]); i++)
+ tag_info[i].ident = XrmPermStringToQuark(tag_info[i].name);
+
+ initialized = True;
+}
+
+/************************************************************************/
+/* PARSE */
+/************************************************************************/
+static void
+Html_AddEntities(Html_Parser *parser, Html_Item *item)
+{
+ Html_Item *parent, *next, *child = item->child;
+ XmuSegment segment, *ent;
+ XmuScanline *mask = XmuNewScanline(0, 0, 0);
+ XawTextProperty *tprop, *property = NULL;
+ Widget sink;
+ Bool changed = False;
+
+ /* combine properties */
+ if (item->info &&
+ (item->info->entity ||
+ (item->parent && item->parent->ident != item->parent->info->ident))) {
+ sink = XawTextGetSink(text);
+ parent = item->parent;
+ property = XawTextSinkCopyProperty(sink, item->ident);
+ property->mask = item->info->mask;
+ property->xlfd_mask = item->info->xlfd_mask;
+ if (parent) {
+ (void)XawTextSinkCombineProperty(sink, property,
+ XawTextSinkGetProperty(sink, parent->ident), False);
+ if (item->combine && parent->combine)
+ (void)XawTextSinkCombineProperty(sink, item->combine,
+ parent->combine,
+ item->override);
+ }
+ if (item->combine)
+ XawTextSinkCombineProperty(sink, property, item->combine, True);
+ tprop = property;
+ property = XawTextSinkAddProperty(sink, property);
+ XtFree((XtPointer)tprop);
+ if (property && item->ident != property->identifier) {
+ item->ident = property->identifier;
+ changed = True;
+ }
+ }
+
+ if (item->end < 0) {
+ if (item->next)
+ item->end = item->next->start;
+ else if (item->parent)
+ item->end = item->parent->end;
+ else
+ item->end = parser->last;
+ }
+
+ while (child) {
+ next = child->next;
+ segment.x1 = child->start;
+ segment.x2 = child->end;
+ (void)XmuScanlineOrSegment(mask, &segment);
+ Html_AddEntities(parser, child);
+ if (child->combine)
+ XtFree((XtPointer)child->combine);
+ XtFree((XtPointer)child);
+ child = next;
+ }
+
+ /* build entity mask */
+ (void)XmuScanlineNot(mask, item->start, item->end);
+ (void)XmuScanlineAnd(mask, parser->mask);
+
+ /* add entities */
+ if (item->info && changed) {
+ for (ent = mask->segment; ent; ent = ent->next)
+ (void)XawTextSourceAddEntity(parser->source, 0, 0, NULL, ent->x1,
+ ent->x2 - ent->x1, item->ident);
+ }
+ else if (item->info == NULL)
+ (void)XawTextSourceAddEntity(parser->source, 0,
+ XAW_TENTF_READ | XAW_TENTF_REPLACE,
+ item->replace, item->start,
+ item->end - item->start,
+ item->parent->ident);
+
+ /* set mask for parent entities */
+ (void)XmuScanlineOr(parser->mask, mask);
+ XmuDestroyScanline(mask);
+
+#if 0
+ if (item->info && item->info->para) {
+ XawTextSourceSetParagraph(parser->source, item->start, item->end,
+ 40, /* arbitrary value, for testing */
+ 0, 0);
+ }
+#endif
+}
+
+static void
+Html_Commit(Html_Parser *parser)
+{
+ XawTextPosition position;
+ int length;
+
+ position = parser->start;
+ length = parser->end - parser->start;
+ if (position < 0) {
+ length += position;
+ position = 0;
+ }
+ if (position + length > parser->last + 1)
+ length -= (position + length) - parser->last + 1;
+
+ if (parser->quark != Qdefault && parser->quark != NULLQUARK && length > 0) {
+ XmuSegment segment;
+ Html_Item *head = parser->head;
+ XrmQuark quark = parser->quark;
+
+ parser->quark = Qdefault;
+
+ if (quark == Qli && head &&
+ (head->info->ident == Qol || head->info->ident == Qul)) {
+ if (parser->head == NULL || head->info->ident != Qol)
+ XawTextSourceAddEntity(parser->source, 0, /*XAW_TENT_BULLET,*/
+ XAW_TENTF_HIDE, NULL,
+ position, length, Qli);
+ else
+ XawTextSourceAddEntity(parser->source, 0, /*XAW_TENT_LITEM,*/
+ XAW_TENTF_HIDE,
+ (XtPointer)(long)head->li++,
+ position, length, Qli);
+ }
+ else if (quark == Qhide)
+ XawTextSourceAddEntity(parser->source, 0, XAW_TENTF_HIDE, NULL,
+ position, length, quark);
+ else if (quark == Qentity) {
+ if (head && head->end == -1) {
+ Html_Item *item, *it;
+
+ item = XtNew(Html_Item);
+ item->ident = Qentity;
+ item->start = position;
+ item->end = position + length;
+ item->info = NULL;
+ item->combine = NULL;
+ item->override = False;
+ item->replace = (XtPointer)parser->entity;
+ item->child = item->next = NULL;
+
+ it = head->child;
+
+ item->parent = head;
+ if (it == NULL)
+ head->child = item;
+ else {
+ while (it->next)
+ it = it->next;
+ it->next = item;
+ }
+
+ return;
+ }
+ XawTextSourceAddEntity(parser->source, 0,
+ XAW_TENTF_READ | XAW_TENTF_REPLACE,
+ (XtPointer)parser->entity,
+ position, length, Qentity);
+ }
+
+ segment.x1 = position;
+ segment.x2 = position + length;
+ (void)XmuScanlineOrSegment(parser->mask, &segment);
+ }
+}
+
+static void
+Html_ParseTag(Html_Parser *parser)
+{
+ int ch, sz;
+ char buf[32];
+ Html_TagInfo *info;
+ Html_Item *item = NULL;
+ XawTextPosition offset = parser->offset - 1;
+
+ switch (Html_Peek(parser)) {
+ case '!':
+ (void)Html_Get(parser); /* eat `!' */
+ if (Html_Peek(parser) == '-') {
+ /* comment */
+ (void)Html_Get(parser); /* eat `-' */
+ if (Html_Peek(parser) == '-') {
+ int count = 0;
+
+ (void)Html_Get(parser);
+ while ((ch = Html_Peek(parser)) != EOF) {
+ if (ch == '>' && count >= 2)
+ break;
+ else if (ch == '-')
+ ++count;
+ else
+ count = 0;
+ (void)Html_Get(parser);
+ }
+ }
+ }
+ break;
+ case '?':
+ break;
+ case '/':
+ (void)Html_Get(parser); /* eat `/' */
+ sz = 0;
+ while (isalnum(Html_Peek(parser)) &&
+ sz <= sizeof(buf) + 1)
+ buf[sz++] = tolower(Html_Get(parser));
+ buf[sz] = '\0';
+ if ((info = Html_GetInfo(buf)) != NULL) {
+ if (parser->head) {
+ Html_Item *it = parser->head;
+
+ while (it) {
+ if (it->info == info)
+ break;
+ it = it->parent;
+ }
+
+ if (it) {
+ if (it == parser->head)
+ parser->head->end = offset;
+ else {
+ it->end = offset;
+ do {
+ parser->head->end = offset;
+ parser->head = parser->head->parent;
+ } while (parser->head != it);
+ }
+ if (parser->head->parent)
+ parser->head = parser->head->parent;
+ else
+ parser->head = parser->item;
+ }
+ }
+ }
+ break;
+ default:
+ sz = 0;
+ while (isalnum(Html_Peek(parser)) &&
+ sz <= sizeof(buf) + 1)
+ buf[sz++] = tolower(Html_Get(parser));
+ buf[sz] = '\0';
+ if ((info = Html_GetInfo(buf)) != NULL) {
+ if (info->end == False) {
+ if (info->ident == Qli)
+ parser->quark = Qli;
+ if (!info->para)
+ break; /* no more processing required */
+ }
+ item = XtNew(Html_Item);
+ item->info = info;
+ item->ident = item->info->ident;
+ item->combine = NULL;
+ item->override = False;
+ item->start = item->end = -1;
+ if (info->ident == Qol)
+ item->li = 1;
+ else
+ item->li = 0;
+ item->parent = item->child = item->next = NULL;
+ if (parser->item == NULL)
+ parser->item = parser->head = item;
+ else if (parser->head->end == -1) {
+ if (parser->head->info != item->info || info->nest) {
+ Html_Item *it = parser->head;
+
+ /* first, see if we need to close a long list of tags */
+ if (info->ident == Qdd) {
+ if (parser->head &&
+ parser->head->info->ident == Qdt) {
+ parser->head->end = offset;
+ parser->head = parser->head->parent;
+ }
+ }
+ else if (info->ident == Qdt) {
+ if (parser->head &&
+ parser->head->info->ident == Qdd) {
+ parser->head->end = offset;
+ parser->head = parser->head->parent;
+ }
+ }
+ else if (!info->nest) {
+ while (it) {
+ if (it->info == info || it->info->end)
+ break;
+ it = it->parent;
+ }
+ if (it) {
+ /* close the items */
+ while (parser->head != it) {
+ if (parser->head->info->ident == Qpre)
+ --parser->pre;
+ parser->head->end = offset;
+ parser->head = parser->head->parent;
+ }
+ }
+ }
+
+ /* add child item */
+ it = parser->head->child;
+
+ item->parent = parser->head;
+ if (it == NULL)
+ parser->head->child = item;
+ else {
+ while (it->next)
+ it = it->next;
+ it->next = item;
+ }
+ parser->head = item;
+ }
+ else {
+ /* close the `head' item and start a new one */
+ Html_Item *it;
+
+ parser->head->end = offset;
+ if (parser->head->parent)
+ parser->head = parser->head->parent;
+ else
+ parser->head = parser->item;
+
+ if ((it = parser->head->child) != NULL) {
+ item->parent = parser->head;
+ while (it->next)
+ it = it->next;
+ it->next = item;
+ parser->head = item;
+ }
+ else {
+ parser->head->child = item;
+ parser->head = item;
+ }
+ }
+ }
+ else {
+ /* this is not common, but handle it */
+ Html_Item *it = parser->item;
+
+ while (it->next)
+ it = it->next;
+ it->next = item;
+ parser->head = item;
+ }
+ if (info->parse_args)
+ (info->parse_args)(parser, item);
+ }
+ break;
+ }
+
+ /* skip anything not processed */
+ while ((ch = Html_Peek(parser)) != '>' && ch != EOF)
+ (void)Html_Get(parser);
+ if (item && item->start == -1)
+ item->start = parser->offset + 1;
+}
+
+/* tags */
+static int
+Html_Parse2(Html_Parser *parser)
+{
+ int ch;
+
+ for (;;) {
+ if ((ch = Html_Get(parser)) == '<') {
+ parser->end = parser->offset - 1;
+ Html_Commit(parser);
+ parser->quark = Qhide;
+ parser->start = parser->end;
+
+ Html_ParseTag(parser);
+
+ (void)Html_Get(parser); /* eat `>' */
+ parser->end = parser->offset;
+ Html_Commit(parser);
+ }
+ else
+ return (ch);
+ }
+ /*NOTREACHED*/
+}
+
+/* entities */
+static int
+Html_Parse1(Html_Parser *parser)
+{
+ static XawTextBlock *entities[256];
+ static char chars[256];
+ int ch;
+
+ for (;;) {
+ if ((ch = Html_Parse2(parser)) == EOF)
+ return (EOF);
+
+ if (ch == '&') {
+ unsigned char idx = '?';
+ char buf[32];
+ int sz = 0;
+
+ /* the string comparisons need a big optmization! */
+ parser->end = parser->offset - 1;
+ Html_Commit(parser);
+ parser->start = parser->end;
+ while ((ch = Html_Peek(parser)) != ';'
+ && ch != EOF && !isspace(ch)) {
+ ch = Html_Get(parser);
+ if (sz + 1 <= sizeof(buf))
+ buf[sz++] = ch;
+ }
+ buf[sz] = '\0';
+ if (ch == ';')
+ (void)Html_Get(parser);
+ if (sz == 0)
+ idx = '&';
+ else if (strcasecmp(buf, "lt") == 0)
+ idx = '<';
+ else if (strcasecmp(buf, "gt") == 0)
+ idx = '>';
+ else if (strcasecmp(buf, "nbsp") == 0)
+ idx = ' ';
+ else if (strcasecmp(buf, "amp") == 0)
+ idx = '&';
+ else if (strcasecmp(buf, "quot") == 0)
+ idx = '"';
+ else if (*buf == '#') {
+ if (sz == 1)
+ idx = '#';
+ else {
+ char *tmp;
+
+ idx = strtol(buf + 1, &tmp, 10);
+ if (*tmp)
+ idx = '?';
+ }
+ }
+ else if (strcmp(buf + 1, "acute") == 0) {
+ switch (*buf) {
+ case 'a': idx = 'á'; break; case 'e': idx = 'é'; break;
+ case 'i': idx = 'í'; break; case 'o': idx = 'ó'; break;
+ case 'u': idx = 'ú'; break; case 'A': idx = 'Á'; break;
+ case 'E': idx = 'É'; break; case 'I': idx = 'Í'; break;
+ case 'O': idx = 'Ó'; break; case 'U': idx = 'Ú'; break;
+ case 'y': idx = 'ý'; break; case 'Y': idx = 'Ý'; break;
+ }
+ }
+ else if (strcmp(buf + 1, "grave") == 0) {
+ switch (*buf) {
+ case 'a': idx = 'à'; break; case 'e': idx = 'è'; break;
+ case 'i': idx = 'ì'; break; case 'o': idx = 'ò'; break;
+ case 'u': idx = 'ù'; break; case 'A': idx = 'À'; break;
+ case 'E': idx = 'È'; break; case 'I': idx = 'Ì'; break;
+ case 'O': idx = 'Ò'; break; case 'U': idx = 'Ù'; break;
+ }
+ }
+ else if (strcmp(buf + 1, "tilde") == 0) {
+ switch (*buf) {
+ case 'a': idx = 'ã'; break; case 'o': idx = 'õ'; break;
+ case 'n': idx = 'ñ'; break; case 'A': idx = 'Ã'; break;
+ case 'O': idx = 'Õ'; break; case 'N': idx = 'Ñ'; break;
+ }
+ }
+ else if (strcmp(buf + 1, "circ") == 0) {
+ switch (*buf) {
+ case 'a': idx = 'â'; break; case 'e': idx = 'ê'; break;
+ case 'i': idx = 'î'; break; case 'o': idx = 'ô'; break;
+ case 'u': idx = 'û'; break; case 'A': idx = 'Â'; break;
+ case 'E': idx = 'Ê'; break; case 'I': idx = 'Î'; break;
+ case 'O': idx = 'Ô'; break; case 'U': idx = 'Û'; break;
+ }
+ }
+ else if (strcmp(buf + 1, "uml") == 0) {
+ switch (*buf) {
+ case 'a': idx = 0xe4;break; case 'e': idx = 0xeb;break;
+ case 'i': idx = 0xef;break; case 'o': idx = 0xf6;break;
+ case 'u': idx = 'ü'; break; case 'A': idx = 0xc4;break;
+ case 'E': idx = 0xcb;break; case 'I': idx = 0xfc;break;
+ case 'O': idx = 0xd6;break; case 'U': idx = 'Ü'; break;
+ case 'y': idx = 0xff;break;
+ }
+ }
+ else if (strcmp(buf + 1, "cedil") == 0) {
+ switch (*buf) {
+ case 'c': idx = 'ç'; break; case 'C': idx = 'Ç'; break;
+ }
+ }
+ else if (strcmp(buf + 1, "slash") == 0) {
+ switch (*buf) {
+ case 'o': idx = 0xf8; break;case 'O': idx = 0xd8; break;
+ }
+ }
+ else if (strcmp(buf + 1, "ring") == 0) {
+ switch (*buf) {
+ case 'a': idx = 0xe5; break;case 'A': idx = 0xc5; break;
+ }
+ }
+ else if (strcasecmp(buf, "iexcl") == 0)
+ idx = 0xa1;
+ else if (strcasecmp(buf, "cent") == 0)
+ idx = 0xa2;
+ else if (strcasecmp(buf, "pound") == 0)
+ idx = 0xa3;
+ else if (strcasecmp(buf, "curren") == 0)
+ idx = 0xa4;
+ else if (strcasecmp(buf, "yen") == 0)
+ idx = 0xa5;
+ else if (strcasecmp(buf, "brvbar") == 0)
+ idx = 0xa6;
+ else if (strcasecmp(buf, "sect") == 0)
+ idx = 0xa7;
+ else if (strcasecmp(buf, "uml") == 0)
+ idx = 0xa8;
+ else if (strcasecmp(buf, "copy") == 0)
+ idx = 0xa9;
+ else if (strcasecmp(buf, "ordf") == 0)
+ idx = 'ª';
+ else if (strcasecmp(buf, "laquo") == 0)
+ idx = 0xab;
+ else if (strcasecmp(buf, "not") == 0)
+ idx = 0xac;
+ else if (strcasecmp(buf, "shy") == 0)
+ idx = 0xad;
+ else if (strcasecmp(buf, "reg") == 0)
+ idx = 0xae;
+ else if (strcasecmp(buf, "macr") == 0)
+ idx = 0xaf;
+ else if (strcasecmp(buf, "deg") == 0)
+ idx = '°';
+ else if (strcasecmp(buf, "plusmn") == 0)
+ idx = 0xb1;
+ else if (strcasecmp(buf, "sup2") == 0)
+ idx = '²';
+ else if (strcasecmp(buf, "sup3") == 0)
+ idx = '³';
+ else if (strcasecmp(buf, "acute") == 0)
+ idx = 0xb4;
+ else if (strcasecmp(buf, "micro") == 0)
+ idx = 0xb5;
+ else if (strcasecmp(buf, "para") == 0)
+ idx = 0xb6;
+ else if (strcasecmp(buf, "middot") == 0)
+ idx = 0xb7;
+ else if (strcasecmp(buf, "cedil") == 0)
+ idx = 0xb8;
+ else if (strcasecmp(buf, "supl") == 0)
+ idx = '¹';
+ else if (strcasecmp(buf, "ordm") == 0)
+ idx = 'º';
+ else if (strcasecmp(buf, "raquo") == 0)
+ idx = 0xbb;
+ else if (strcasecmp(buf, "frac14") == 0)
+ idx = 0xbc;
+ else if (strcasecmp(buf, "frac12") == 0)
+ idx = 0xbd;
+ else if (strcasecmp(buf, "frac34") == 0)
+ idx = 0xbe;
+ else if (strcasecmp(buf, "iquest") == 0)
+ idx = 0xbf;
+ else if (strcasecmp(buf, "AElig") == 0)
+ idx = 0xc6;
+ else if (strcasecmp(buf, "ETH") == 0)
+ idx = 0xd0;
+ else if (strcasecmp(buf, "THORN") == 0)
+ idx = 0xde;
+ else if (strcasecmp(buf, "szlig") == 0)
+ idx = 0xdf;
+ else if (strcasecmp(buf, "aelig") == 0)
+ idx = 0xe6;
+ else if (strcasecmp(buf, "eth") == 0)
+ idx = 0xf0;
+ else if (strcasecmp(buf, "thorn") == 0)
+ idx = 0xfe;
+
+ parser->quark = Qentity;
+ if (entities[idx] == NULL) {
+ entities[idx] = XtNew(XawTextBlock);
+ entities[idx]->firstPos = 0;
+ entities[idx]->length = 1;
+ entities[idx]->ptr = chars + idx;
+ entities[idx]->format = FMT8BIT;
+ chars[idx] = idx;
+ }
+ parser->entity = entities[idx];
+ parser->end = parser->offset;
+ Html_Commit(parser);
+ parser->start = parser->end;
+ }
+ }
+ /*NOTREACHED*/
+}
+
+/************************************************************************/
+/* FORMAT */
+/************************************************************************/
+static int
+Html_Put(Html_Parser *parser, int ch)
+{
+ if (ch != '\r') {
+ if (parser->replace.length % 4096 == 0)
+ parser->replace.ptr = XtRealloc(parser->replace.ptr,
+ parser->replace.length + 4096);
+ parser->replace.ptr[parser->replace.length++] = ch;
+ }
+
+ return (ch);
+}
+
+static void
+Html_Puts(Html_Parser *parser, char *str)
+{
+ int len = strlen(str);
+
+ if (parser->replace.length % 4096 == 0 ||
+ parser->replace.length + len > parser->replace.length +
+ (4096 - (parser->replace.length % 4096)))
+ parser->replace.ptr = XtRealloc(parser->replace.ptr,
+ parser->replace.length + 4096);
+ memcpy(parser->replace.ptr + parser->replace.length, str, len);
+ parser->replace.length += len;
+}
+
+static void
+Html_FormatTag(Html_Parser *parser)
+{
+ int ch = 0, sz = 0;
+ char buf[32];
+ Html_TagInfo *info = NULL;
+
+ switch (Html_Peek(parser)) {
+ case '!':
+ Html_Put(parser, '<');
+ Html_Put(parser, Html_Get(parser)); /* eat `!' */
+ if (Html_Peek(parser) == '-') {
+ /* comment */
+ Html_Put(parser, Html_Get(parser)); /* eat `-' */
+ if (Html_Peek(parser) == '-') {
+ int count = 0;
+
+ Html_Put(parser, Html_Get(parser));
+ while ((ch = Html_Peek(parser)) != EOF) {
+ if (ch == '>' && count >= 2)
+ break;
+ else if (ch == '-')
+ ++count;
+ else
+ count = 0;
+ Html_Put(parser, Html_Get(parser));
+ }
+ (void)Html_Get(parser); /* eat `>' */
+ Html_Put(parser, '>');
+ return;
+ }
+ }
+ break;
+ case '?':
+ Html_Put(parser, '<');
+ break;
+ case '/':
+ (void)Html_Get(parser); /* eat `/' */
+ while (isalnum(Html_Peek(parser)) &&
+ sz <= sizeof(buf) + 1)
+ buf[sz++] = ch = tolower(Html_Get(parser));
+ buf[sz] = '\0';
+ if ((info = Html_GetInfo(buf)) != NULL && info->adnl) {
+ if (info->ident == Qpre && parser->pre) {
+ if (--parser->pre == 0)
+ parser->column = 0;
+ }
+ parser->quark = Qetag;
+ parser->spc = True;
+ if (info->ident == Qp) {
+ while ((ch = Html_Peek(parser) != '>' && ch != EOF))
+ (void)Html_Get(parser);
+ (void)Html_Get(parser); /* eat '>' */
+ return;
+ }
+ }
+ else if (info) {
+ if (info->ident == Qol || info->ident == Qul) {
+ if (parser->list && --parser->list == 0 &&
+ parser->desc == 0) {
+ parser->quark = Qetag;
+ Html_Put(parser, '\n');
+ ++parser->adnl;
+ parser->column = 0;
+ }
+ }
+ else if (info->ident == Qdl) {
+ if (parser->desc && --parser->desc == 0 &&
+ parser->list == 0) {
+ parser->quark = Qetag;
+ Html_Put(parser, '\n');
+ ++parser->adnl;
+ parser->column = 0;
+ }
+ }
+ }
+ Html_Puts(parser, "</");
+ Html_Puts(parser, buf);
+ break;
+ default:
+ while (isalnum(Html_Peek(parser)) &&
+ sz <= sizeof(buf) + 1)
+ buf[sz++] = tolower(Html_Get(parser));
+ buf[sz] = '\0';
+ if ((info = Html_GetInfo(buf)) != NULL && info->adnl) {
+ if (info->ident == Qpre)
+ ++parser->pre;
+ if (parser->quark != Qtag) {
+ if (parser->adnl < 2) {
+ Html_Puts(parser, parser->adnl ? pnl : nlpnl);
+ parser->adnl = 2;
+ parser->spc = True;
+ parser->column = 0;
+ }
+ }
+ parser->quark = Qtag;
+ if (info->ident == Qp) {
+ while ((ch = Html_Peek(parser) != '>' && ch != EOF))
+ (void)Html_Get(parser);
+ (void)Html_Get(parser); /* eat '>' */
+ return;
+ }
+ }
+ else if (info) {
+ if (info->ident == Qol || info->ident == Qul) {
+ if (++parser->list == 1 && !parser->desc) {
+ if (parser->adnl < 2) {
+ Html_Puts(parser, parser->adnl ? pnl : nlpnl);
+ parser->adnl = 2;
+ parser->column = 0;
+ }
+ }
+ else if (parser->adnl == 0) {
+ Html_Put(parser, '\n');
+ parser->adnl = 1;
+ parser->column = 0;
+ }
+ parser->spc = True;
+ }
+ else if (info->ident == Qli) {
+ if (parser->adnl == 0) {
+ Html_Put(parser, '\n');
+ parser->adnl = 1;
+ parser->column = 0;
+ }
+ }
+
+ else if (info->ident == Qdl) {
+ if (++parser->desc == 1 && !parser->list) {
+ if (parser->adnl < 2) {
+ Html_Puts(parser, parser->adnl ? pnl : nlpnl);
+ parser->adnl = 2;
+ parser->column = 0;
+ }
+ }
+ else if (parser->adnl == 0) {
+ Html_Put(parser, '\n');
+ parser->adnl = 1;
+ parser->column = 0;
+ }
+ parser->spc = True;
+ }
+ else if (info->ident == Qdd) {
+ if (parser->desc == 0) {
+ if (parser->adnl < 2) {
+ Html_Puts(parser, parser->adnl ? pnl : nlpnl);
+ parser->adnl = 2;
+ parser->column = 0;
+ }
+ }
+ else if (parser->adnl == 0) {
+ Html_Put(parser, '\n');
+ parser->adnl = 1;
+ parser->column = 0;
+ }
+ parser->spc = True;
+ }
+ else if (info->ident == Qdt) {
+ if (parser->adnl == 0) {
+ Html_Put(parser, '\n');
+ parser->adnl = 1;
+ parser->spc = True;
+ parser->column = 0;
+ }
+ }
+ }
+ Html_Put(parser, '<');
+ Html_Puts(parser, buf);
+ break;
+ }
+
+ sz = 0;
+ while ((ch = Html_Peek(parser)) != '>' && ch != EOF) {
+ if (isspace(ch)) {
+ (void)Html_Get(parser);
+ ++sz;
+ continue;
+ }
+ else if (sz) {
+ Html_Put(parser, ' ');
+ sz = 0;
+ }
+ Html_Put(parser, Html_Get(parser));
+ }
+ Html_Put(parser, Html_Get(parser)); /* eat `>' */
+ if (info && info->ident == Qbr) {
+ ++parser->adnl;
+ parser->spc = True;
+ Html_Put(parser, '\n');
+ parser->quark = info->ident;
+ parser->column = 0;
+ }
+}
+
+/* tags */
+static int
+Html_Format3(Html_Parser *parser)
+{
+ int ch;
+
+ for (;;) {
+ if ((ch = Html_Get(parser)) == '<') {
+ if (parser->quark == Qspace && parser->spc == False) {
+ Html_Put(parser, ' ');
+ parser->spc = True;
+ }
+
+/* parser->quark = Qhide;*/
+ Html_FormatTag(parser);
+ }
+ else
+ return (ch);
+ }
+ /*NOTREACHED*/
+}
+
+/* entities */
+static int
+Html_Format2(Html_Parser *parser)
+{
+ int ch;
+
+ for (ch = Html_Format3(parser); ch == '&'; ch = Html_Format3(parser)) {
+ Html_Put(parser, '&');
+ while ((ch = Html_Peek(parser)) != ';') {
+ if (isspace(ch) || ch == EOF)
+ break;
+ Html_Put(parser, Html_Get(parser));
+ }
+ if (ch != EOF)
+ Html_Put(parser, Html_Get(parser));
+ else
+ break;
+ if (parser->pre)
+ ++parser->column;
+ }
+
+ return (ch);
+}
+
+/* spaces */
+static int
+Html_Format1(Html_Parser *parser)
+{
+ int ch;
+
+ for (;;) {
+ if ((ch = Html_Format2(parser)) == EOF)
+ return (ch);
+
+ if (parser->quark == Qetag) {
+ if (parser->adnl < 2) {
+ Html_Puts(parser, parser->adnl ? pnl : nlpnl);
+ parser->adnl = 2;
+ parser->spc = True;
+ }
+ }
+ else if (parser->quark == Qspace && parser->spc == False) {
+ Html_Put(parser, ' ');
+ parser->spc = True;
+ }
+
+ if (!parser->pre && isspace(ch))
+ parser->quark = Qspace;
+ else {
+ if (parser->pre) {
+ if (parser->spc) {
+ /* did not yet see any non space character */
+ if (isspace(ch)) {
+ if (ch == '\n') {
+ parser->column = 0;
+ parser->spc = False;
+ parser->adnl = 1;
+ }
+ else if (ch == '\t')
+ parser->column += 8 - (parser->column % 8);
+ else
+ ++parser->column;
+ continue;
+ }
+ else {
+ int column = parser->column;
+
+ while (column-- > 0)
+ Html_Put(parser, ' ');
+ parser->spc = False;
+ parser->adnl = 0;
+ }
+ }
+ else if (ch == '\n') {
+ ++parser->adnl;
+ parser->column = 0;
+ }
+ else if (ch == '\t') {
+ int column = parser->column + (8 - (parser->column % 8));
+
+ parser->adnl = 0;
+ while (parser->column < column) {
+ Html_Put(parser, ' ');
+ ++parser->column;
+ }
+ continue;
+ }
+ else {
+ parser->adnl = 0;
+ ++parser->column;
+ }
+ }
+ else
+ parser->adnl = 0;
+ Html_Put(parser, ch);
+ parser->quark = Qdefault;
+ parser->spc = False;
+ }
+ }
+}
+
+/************************************************************************/
+/* ARGUMENTS */
+/************************************************************************/
+static void
+Html_AArgs(Html_Parser *parser, Html_Item *item)
+{
+ int ch, sz;
+ char buf[32];
+
+ /*CONSTCOND*/
+ while (True) {
+ sz = 0;
+ while ((ch = Html_Peek(parser)) != '>' && ch != EOF) {
+ if (isalnum(ch))
+ break;
+ else
+ (void)Html_Get(parser);
+ }
+
+ if (ch == '>' || ch == EOF)
+ return;
+ buf[sz++] = tolower(Html_Get(parser));
+ while ((ch = Html_Peek(parser)) != '>' && ch != EOF)
+ if (isalnum(ch))
+ buf[sz++] = tolower(Html_Get(parser));
+ else
+ break;
+ buf[sz] = '\0';
+ if (strcmp(buf, "href") == 0) {
+ item->combine = XawTextSinkCopyProperty(XawTextGetSink(text),
+ item->info->ident);
+ item->override = True;
+ item->combine->xlfd_mask = 0L;
+ item->combine->mask = XAW_TPROP_UNDERLINE | XAW_TPROP_FOREGROUND;
+ item->combine->foreground = parser->alink;
+ return;
+ }
+ while ((ch = Html_Peek(parser)) != '>' && ch != EOF) {
+ if (isspace(ch))
+ break;
+ else
+ (void)Html_Get(parser);
+ }
+ }
+}
+
+static void
+Html_FontArgs(Html_Parser *parser, Html_Item *item)
+{
+ int ch, sz;
+ char name[32], value[256], xlfd[128];
+
+ item->combine = XawTextSinkCopyProperty(XawTextGetSink(text),
+ Qdefault);
+ item->override = True;
+ item->combine->mask = item->combine->xlfd_mask = 0L;
+
+ /*CONSTCOND*/
+ while (True) {
+ /* skip white spaces */
+ while ((ch = Html_Peek(parser)) != '>' && ch != EOF) {
+ if (isalnum(ch))
+ break;
+ else
+ (void)Html_Get(parser);
+ }
+
+ if (ch == '>' || ch == EOF)
+ return;
+
+ /* read option name */
+ sz = 0;
+ name[sz++] = tolower(Html_Get(parser));
+ while ((ch = Html_Peek(parser)) != '>' && ch != EOF)
+ if (isalnum(ch) && sz + 1 <= sizeof(name))
+ name[sz++] = tolower(Html_Get(parser));
+ else
+ break;
+ name[sz] = '\0';
+
+ if (ch != '=')
+ continue;
+ (void)Html_Get(parser); /* skip `=' */
+ if (Html_Peek(parser) == '"')
+ (void)Html_Get(parser);
+
+ sz = 0;
+ while ((ch = Html_Peek(parser)) != '>' && ch != EOF) {
+ if (!isspace(ch) && sz + 1 <= sizeof(value))
+ value[sz++] = Html_Get(parser);
+ else
+ break;
+ }
+ value[sz] = '\0';
+ if (sz > 0 && value[sz - 1] == '"')
+ value[--sz] = '\0';
+
+ if (strcmp(name, "color") == 0) {
+ XColor color, exact;
+
+ if (XAllocNamedColor(XtDisplay(toplevel), toplevel->core.colormap,
+ value, &color, &exact)) {
+ item->combine->mask |= XAW_TPROP_FOREGROUND;
+ item->combine->foreground = color.pixel;
+ }
+ }
+ else if (strcmp(name, "face") == 0) {
+ int count = 0;
+ char *ptr, *family, **font_list;
+
+ ptr = value;
+ do {
+ family = ptr;
+ ptr = strchr(ptr, ',');
+ if (ptr)
+ *ptr++ = '\0';
+ XmuSnprintf(xlfd, sizeof(xlfd), "-*-%s-*-*-*-*-*-*-*-*-*-*-*-*",
+ family);
+ font_list = XListFonts(XtDisplay(toplevel), xlfd, 1, &count);
+ if (font_list)
+ XFreeFontNames(font_list);
+ if (count)
+ break;
+ } while (ptr);
+ if (count) {
+ item->combine->xlfd_mask |= XAW_TPROP_FAMILY;
+ item->combine->family = XrmStringToQuark(family);
+ }
+ }
+ else if (strcmp(name, "size") == 0) {
+ int size, sign = 0;
+
+ if (isalnum(*value)) {
+ size = atoi(value);
+ sign = 0;
+ }
+ else {
+ char *str = XrmQuarkToString(item->combine->pixel_size);
+
+ size = str ? atoi(str) : 12;
+ if (*value == '+') {
+ size += atoi(value + 1);
+ sign = 1;
+ }
+ else if (*value == '-') {
+ size -= atoi(value + 1);
+ sign = -1;
+ }
+ }
+
+ if (item->combine->xlfd != NULLQUARK) {
+ int count, ucount, dcount, usize, dsize;
+ char **current, **result, **up, **down;
+
+ current = result = up = down = NULL;
+ /* try to load an appropriate font */
+ XmuSnprintf(value, sizeof(value),
+ "-*-%s-%s-%s-*--%%d-*-*-*-*-*-%s-%s",
+ XrmQuarkToString(item->combine->family),
+ XrmQuarkToString(item->combine->weight),
+ XrmQuarkToString(item->combine->slant),
+ XrmQuarkToString(item->combine->registry),
+ XrmQuarkToString(item->combine->encoding));
+ XmuSnprintf(xlfd, sizeof(xlfd), value,
+ atoi(XrmQuarkToString(item->combine->pixel_size)));
+ current = XListFonts(XtDisplay(toplevel), xlfd, 1, &count);
+ if (count) {
+ ucount = dcount = usize = dsize = 0;
+
+ XmuSnprintf(xlfd, sizeof(xlfd), value, size);
+ result = XListFonts(XtDisplay(toplevel), xlfd, 1, &count);
+ if (count == 0 || strstr(*result, "-0-")) {
+ if (sign <= 0) {
+ sz = dsize = size;
+ while (dcount == 0 && --sz > size - 8 && sz > 1) {
+ XmuSnprintf(xlfd, sizeof(xlfd), value, sz);
+ down = XListFonts(XtDisplay(toplevel), xlfd,
+ 1, &dcount);
+ if (dcount && strstr(*down, "-0-") != NULL) {
+ XFreeFontNames(down);
+ down = NULL;
+ dcount = 0;
+ }
+ }
+ if (dcount)
+ dsize = sz;
+ }
+ if (sign >= 0) {
+ sz = usize = size;
+ while (ucount == 0 && ++sz < size + 8) {
+ XmuSnprintf(xlfd, sizeof(xlfd), value, sz);
+ up = XListFonts(XtDisplay(toplevel), xlfd,
+ 1, &ucount);
+ if (ucount && strstr(*up, "-0-") != NULL) {
+ XFreeFontNames(up);
+ up = NULL;
+ ucount = 0;
+ }
+ }
+ if (ucount)
+ usize = sz;
+ }
+ if (ucount && dcount)
+ size = size - dsize < usize - size ? dsize : usize;
+ else if (ucount)
+ size = usize;
+ else if (dcount)
+ size = dsize;
+ }
+ if (current)
+ XFreeFontNames(current);
+ if (result)
+ XFreeFontNames(result);
+ if (up)
+ XFreeFontNames(up);
+ if (down)
+ XFreeFontNames(down);
+ }
+ }
+
+ XmuSnprintf(value, sizeof(value), "%d", size);
+ item->combine->xlfd_mask |= XAW_TPROP_PIXELSIZE;
+ item->combine->pixel_size = XrmStringToQuark(value);
+ }
+
+ while ((ch = Html_Peek(parser)) != '>' && ch != EOF) {
+ if (isspace(ch))
+ break;
+ else
+ (void)Html_Get(parser);
+ }
+ }
+}