Logo Search packages:      
Sourcecode: xorg-server version File versions  Download package

help.c

/*
 * 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.7tsi 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);
    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);
      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);
    }
}

/*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;
    unsigned int entity : 1;  /* it changes the type of the text */
    unsigned int nest   : 1;  /* does not close tags automatically */
    unsigned int end    : 1;  /* need a close markup */
    unsigned int adnl   : 1;  /* add newline before/after tag contents */
    unsigned 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);

    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);

    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);
    XawTextSourceReplace(src, 0, info->last, &info->block);
    XtVaSetValues(src, XtNeditType, XawtextRead, NULL);

    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 = 0xe1; break;    case 'e': idx = 0xe9; break;
                case 'i': idx = 0xed; break;    case 'o': idx = 0xf3; break;
                case 'u': idx = 0xfa; break;    case 'A': idx = 0xc1; break;
                case 'E': idx = 0xc9; break;    case 'I': idx = 0xcd; break;
                case 'O': idx = 0xd3; break;    case 'U': idx = 0xda; break;
                case 'y': idx = 0xfd; break;    case 'Y': idx = 0xdd; break;
            }
          }
          else if (strcmp(buf + 1, "grave") == 0) {
            switch (*buf) {
                case 'a': idx = 0xe0; break;    case 'e': idx = 0xe8; break;
                case 'i': idx = 0xec; break;    case 'o': idx = 0xf2; break;
                case 'u': idx = 0xf9; break;    case 'A': idx = 0xc0; break;
                case 'E': idx = 0xc8; break;    case 'I': idx = 0xcc; break;
                case 'O': idx = 0xd2; break;    case 'U': idx = 0xd9; break;
            }
          }
          else if (strcmp(buf + 1, "tilde") == 0) {
            switch (*buf) {
                case 'a': idx = 0xe3; break;    case 'o': idx = 0xf5; break;
                case 'n': idx = 0xf1; break;    case 'A': idx = 0xc3; break;
                case 'O': idx = 0xd5; break;    case 'N': idx = 0xd1; break;
            }
          }
          else if (strcmp(buf + 1, "circ") == 0) {
            switch (*buf) {
                case 'a': idx = 0xe2; break;    case 'e': idx = 0xea; break;
                case 'i': idx = 0xee; break;    case 'o': idx = 0xf4; break;
                case 'u': idx = 0xfb; break;    case 'A': idx = 0xc2; break;
                case 'E': idx = 0xca; break;    case 'I': idx = 0xce; break;
                case 'O': idx = 0xd4; break;    case 'U': idx = 0xdb; 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 = 0xfc; break;    case 'A': idx = 0xc4; break;
                case 'E': idx = 0xcb; break;    case 'I': idx = 0xfc; break;
                case 'O': idx = 0xd6; break;    case 'U': idx = 0xdc; break;
                case 'y': idx = 0xff; break;
            }
          }
          else if (strcmp(buf + 1, "cedil") == 0) {
            switch (*buf) {
                case 'c': idx = 0xe7; break;    case 'C': idx = 0xc7; 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 = 0xaa;
          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 = 0xb0;
          else if (strcasecmp(buf, "plusmn") == 0)
            idx = 0xb1;
          else if (strcasecmp(buf, "sup2") == 0)
            idx = 0xb2;
          else if (strcasecmp(buf, "sup3") == 0)
            idx = 0xb3;
          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 = 0xb9;
          else if (strcasecmp(buf, "ordm") == 0)
            idx = 0xba;
          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);
      }
    }
}

Generated by  Doxygen 1.6.0   Back to index