home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Leser 15 / Amiga Plus Leser CD 15.iso / Tools / Development / MosaicSRC / src / HTML.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-03-13  |  60.7 KB  |  2,873 lines

  1. // MDF - PORT FROM NCSA VERSION 2.1
  2.  
  3. /****************************************************************************
  4.  * NCSA Mosaic for the X Window System                                      *
  5.  * Software Development Group                                               *
  6.  * National Center for Supercomputing Applications                          *
  7.  * University of Illinois at Urbana-Champaign                               *
  8.  * 605 E. Springfield, Champaign IL 61820                                   *
  9.  * mosaic@ncsa.uiuc.edu                                                     *
  10.  *                                                                          *
  11.  * Copyright (C) 1993, Board of Trustees of the University of Illinois      *
  12.  *                                                                          *
  13.  * NCSA Mosaic software, both binary and source (hereafter, Software) is    *
  14.  * copyrighted by The Board of Trustees of the University of Illinois       *
  15.  * (UI), and ownership remains with the UI.                                 *
  16.  *                                                                          *
  17.  * The UI grants you (hereafter, Licensee) a license to use the Software    *
  18.  * for academic, research and internal business purposes only, without a    *
  19.  * fee.  Licensee may distribute the binary and source code (if released)   *
  20.  * to third parties provided that the copyright notice and this statement   *
  21.  * appears on all copies and that no charge is associated with such         *
  22.  * copies.                                                                  *
  23.  *                                                                          *
  24.  * Licensee may make derivative works.  However, if Licensee distributes    *
  25.  * any derivative work based on or derived from the Software, then          *
  26.  * Licensee will (1) notify NCSA regarding its distribution of the          *
  27.  * derivative work, and (2) clearly notify users that such derivative       *
  28.  * work is a modified version and not the original NCSA Mosaic              *
  29.  * distributed by the UI.                                                   *
  30.  *                                                                          *
  31.  * Any Licensee wishing to make commercial use of the Software should       *
  32.  * contact the UI, c/o NCSA, to negotiate an appropriate license for such   *
  33.  * commercial use.  Commercial use includes (1) integration of all or       *
  34.  * part of the source code into a product for sale or license by or on      *
  35.  * behalf of Licensee to third parties, or (2) distribution of the binary   *
  36.  * code or source code to third parties that need it to utilize a           *
  37.  * commercial product sold or licensed by or on behalf of Licensee.         *
  38.  *                                                                          *
  39.  * UI MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR   *
  40.  * ANY PURPOSE.  IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED          *
  41.  * WARRANTY.  THE UI SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY THE    *
  42.  * USERS OF THIS SOFTWARE.                                                  *
  43.  *                                                                          *
  44.  * By using or copying this Software, Licensee agrees to abide by the       *
  45.  * copyright law and all other applicable laws of the U.S. including, but   *
  46.  * not limited to, export control laws, and the terms of this license.      *
  47.  * UI shall have the right to terminate this license immediately by         *
  48.  * written notice upon Licensee's breach of, or non-compliance with, any    *
  49.  * of its terms.  Licensee may be held legally responsible for any          *
  50.  * copyright infringement that is caused or encouraged by Licensee's        *
  51.  * failure to abide by the terms of this license.                           *
  52.  *                                                                          *
  53.  * Comments and questions are welcome and can be sent to                    *
  54.  * mosaic-x@ncsa.uiuc.edu.                                                  *
  55.  ****************************************************************************/
  56.  
  57. #ifdef _AMIGA
  58. #include "includes.h"
  59. #include <exec/types.h>
  60. #include <stdlib.h>
  61. #include <string.h>
  62. #include <ctype.h>
  63. #include <intuition/intuitionbase.h>
  64. #include <clib/graphics_protos.h>
  65. #include <graphics/gfxmacros.h>
  66. #include "XtoI.h"
  67. #include "globals.h"
  68. #include "htmlgad.h"
  69. #endif /* _AMIGA */
  70.  
  71. #include <stdio.h>
  72. /* nothing in here can be used outside the widget */
  73. #include "HTMLP.h"
  74.  
  75. /*
  76. #ifdef MOTIF
  77. #include <Xm/DrawingA.h>
  78. #include <Xm/ScrollBar.h>
  79. #else
  80. #include "DrawingArea.h"
  81. #include <X11/Xaw/Scrollbar.h>
  82. #endif
  83. #include <X11/cursorfont.h>
  84. */
  85.  
  86. #define    MARGIN_DEFAULT        20
  87. #define    CLICK_TIME        500
  88. #define    SELECT_THRESHOLD    3
  89. #define    MAX_UNDERLINES        3
  90. #define DEFAULT_INCREMENT       18
  91.  
  92. #ifndef ABS
  93. #define ABS(x)  (((x) > 0) ? (x) : ((x) * -1))
  94. #endif
  95.  
  96. #define    W_TEXTFIELD    0
  97. #define    W_CHECKBOX    1
  98. #define    W_RADIOBOX    2
  99. #define    W_PUSHBUTTON    3
  100. #define    W_PASSWORD    4
  101. #define    W_OPTIONMENU    5
  102.  
  103.  
  104. extern struct Region *installClipRegion(struct Window *, struct Layer *,
  105.                     struct Region *);
  106. extern int FormatAll(HTMLGadClData *, int *);
  107. extern int DocumentWidth(HTMLGadClData *, struct mark_up *);
  108. extern void PlaceLine(HTMLGadClData *, int);
  109. extern void TextRefresh(HTMLGadClData *, struct ele_rec *, int, int);
  110. extern void ImageRefresh(HTMLGadClData *, struct ele_rec *);
  111. extern void LinefeedRefresh(HTMLGadClData *, struct ele_rec *);
  112. extern void BulletRefresh(HTMLGadClData *, struct ele_rec *);
  113. extern void RefreshTextRange(HTMLGadClData *, struct ele_rec *, struct ele_rec *);
  114. extern void FreeColors(void *, void *);
  115. extern void FreeImages(HTMLGadClData *);
  116. extern void HideWidgets();
  117. extern void MapWidgets();
  118. extern int SwapElements(struct ele_rec *, struct ele_rec *, int, int);
  119. extern int ElementLessThan(struct ele_rec *, struct ele_rec *, int, int);
  120. extern int IsDelayedHRef(HTMLGadClData *, char *);
  121. extern int IsIsMapForm(HTMLGadClData *, char *);
  122. extern int AnchoredHeight(HTMLGadClData *);
  123. extern char *ParseMarkTag(char *, char *, char *);
  124. extern char *ParseTextToString(struct ele_rec *, struct ele_rec *,
  125.                    struct ele_rec *, int, int, int, int);
  126. extern char *ParseTextToPrettyString(HTMLGadClData *, struct ele_rec *,
  127.                      struct ele_rec *, struct ele_rec *,
  128.                      int, int, int, int);
  129. extern char *ParseTextToPSString();
  130. extern struct mark_up *HTMLParse(struct mark_up *, char *);
  131. extern struct ele_rec *LocateElement(HTMLGadClData *, int, int, int *);
  132. extern struct ele_rec **MakeLineList(struct ele_rec *, int);
  133. extern void FreeHRefs(struct ref_rec *);
  134. extern struct ref_rec *AddHRef();
  135. extern void FreeDelayedImages(struct delay_rec *);
  136. extern struct delay_rec *AddDelayedImage();
  137. extern ImageInfo *NoImageData();
  138. extern void ImageSubmitForm();
  139. extern void AddNewWidgets(HTMLGadClData *);
  140. extern void HideWidgets(HTMLGadClData *);
  141. static void CallLinkCallbacks(HTMLGadClData *);
  142. void ViewRedisplay(HTMLGadClData *, int, int, int, int);
  143.  
  144.  
  145. //static Cursor in_anchor_cursor = NULL;
  146. static void *in_anchor_cursor = NULL;
  147.  
  148. /*
  149.  * Either the vertical or hortizontal scrollbar has been moved
  150.  */
  151. void
  152. ScrollToPos(HTMLGadClData * HTML_Data, int bar, int value)
  153. //ScrollToPos(Widget w, HTMLGadClData * HTML_Data, int value)
  154. {
  155.     /*
  156.      * If we've moved the vertical scrollbar
  157.      */
  158.     if (bar == 0)
  159.     {
  160.         /*
  161.          * We've scrolled down. Copy up the untouched part of the
  162.          * window.  Then Clear and redraw the new area
  163.          * exposed.
  164.          */
  165.         if (value > HTML_Data->scroll_y)
  166.         {
  167.             int dy;
  168.         
  169.             dy = value - HTML_Data->scroll_y;
  170.             if (dy > HTML_Data->view_height){
  171.                 HTML_Data->scroll_y = value;
  172.                 XClearArea(XtDisplay(HTML_Data->view),XtWindow(HTML_Data->view),0, 0,HTML_Data->view_width,HTML_Data->view_height, False);
  173.                 ViewRedisplay(HTML_Data,0, 0,HTML_Data->view_width,HTML_Data->view_height);
  174.             }
  175.             else{
  176.                 XCopyArea(XtDisplay(HTML_Data->view),XtWindow(HTML_Data->view),XtWindow(HTML_Data->view),HTML_Data->drawGC, 0, dy,HTML_Data->view_width,HTML_Data->view_height - dy,0, 0);
  177.                 HTML_Data->scroll_y = value;
  178.                 XClearArea(XtDisplay(HTML_Data->view),XtWindow(HTML_Data->view),0, (int)HTML_Data->view_height - dy,HTML_Data->view_width, dy, False);
  179.                 ViewRedisplay(HTML_Data,0, (int)HTML_Data->view_height - dy,HTML_Data->view_width, dy);
  180.             }
  181.         }
  182.         /*
  183.          * We've scrolled up. Copy down the untouched part of the
  184.          * window.  Then Clear and redraw the new area
  185.          * exposed.
  186.          */
  187.         else if (value < HTML_Data->scroll_y)
  188.         {
  189.             int dy;
  190.         
  191.             dy = HTML_Data->scroll_y - value;
  192.             if (dy > HTML_Data->view_height){
  193.                 HTML_Data->scroll_y = value;
  194.                 XClearArea(XtDisplay(HTML_Data->view),XtWindow(HTML_Data->view),0, 0,HTML_Data->view_width,HTML_Data->view_height, False);
  195.                 ViewRedisplay(HTML_Data,0, 0,HTML_Data->view_width,HTML_Data->view_height);
  196.             }
  197.             else{
  198.                 XCopyArea(XtDisplay(HTML_Data->view),XtWindow(HTML_Data->view),XtWindow(HTML_Data->view),HTML_Data->drawGC, 0, 0,HTML_Data->view_width,HTML_Data->view_height - dy,0, dy);
  199.                 HTML_Data->scroll_y = value;
  200.                 XClearArea(XtDisplay(HTML_Data->view),XtWindow(HTML_Data->view),0, 0,HTML_Data->view_width, dy, False);
  201.                 ViewRedisplay(HTML_Data,0, 0,HTML_Data->view_width, dy);
  202.             }
  203.         }
  204.     }
  205.     /*
  206.      * Else we've moved the horizontal scrollbar
  207.      */
  208.     else if (bar == 1)
  209.     {
  210.         /*
  211.          * We've scrolled right. Copy left the untouched part of the
  212.          * window.  Then Clear and redraw the new area
  213.          * exposed.
  214.          */
  215.         if (value > HTML_Data->scroll_x){
  216.             int dx;
  217.         
  218.             dx = value - HTML_Data->scroll_x;
  219.             if (dx > HTML_Data->view_width){
  220.                 HTML_Data->scroll_x = value;
  221.                 XClearArea(XtDisplay(HTML_Data->view),XtWindow(HTML_Data->view),0, 0,HTML_Data->view_width,HTML_Data->view_height, False);
  222.                 ViewRedisplay(HTML_Data,0, 0,HTML_Data->view_width,HTML_Data->view_height);
  223.             }
  224.             else{
  225.                 XCopyArea(XtDisplay(HTML_Data->view),XtWindow(HTML_Data->view),XtWindow(HTML_Data->view),HTML_Data->drawGC, dx, 0,HTML_Data->view_width - dx,HTML_Data->view_height,0, 0);
  226.                 HTML_Data->scroll_x = value;
  227.                 XClearArea(XtDisplay(HTML_Data->view),XtWindow(HTML_Data->view),(int)HTML_Data->view_width - dx, 0,dx, HTML_Data->view_height, False);
  228.                 ViewRedisplay(HTML_Data,(int)HTML_Data->view_width - dx, 0,dx, HTML_Data->view_height);
  229.             }
  230.         }
  231.         /*
  232.          * We've scrolled left. Copy right the untouched part of the
  233.          * window.  Then Clear and redraw the new area
  234.          * exposed.
  235.          */
  236.         else if (value < HTML_Data->scroll_x)
  237.         {
  238.             int dx;
  239.         
  240.             dx = HTML_Data->scroll_x - value;
  241.             if (dx > HTML_Data->view_width){
  242.                 HTML_Data->scroll_x = value;
  243.                 XClearArea(XtDisplay(HTML_Data->view),XtWindow(HTML_Data->view),0, 0,HTML_Data->view_width,HTML_Data->view_height, False);
  244.                 ViewRedisplay(HTML_Data,0, 0,HTML_Data->view_width,HTML_Data->view_height);
  245.             }
  246.             else{
  247.                 XCopyArea(XtDisplay(HTML_Data->view),XtWindow(HTML_Data->view),XtWindow(HTML_Data->view),HTML_Data->drawGC, 0, 0,HTML_Data->view_width - dx,HTML_Data->view_height,dx, 0);
  248.                 HTML_Data->scroll_x = value;
  249.                 XClearArea(XtDisplay(HTML_Data->view),XtWindow(HTML_Data->view),0, 0,dx, HTML_Data->view_height, False);
  250.                 ViewRedisplay(HTML_Data,0, 0,dx, HTML_Data->view_height);
  251.             }
  252.         }
  253.     }
  254.  
  255. }
  256.  
  257. /*
  258.  * Reformat the window and ( scrollbars ).
  259.  * May be called because of a changed document, or because of a changed
  260.  * window size.
  261.  */
  262. void
  263. ReformatWindow(HTMLGadClData * HTML_Data)
  264. {
  265.     int temp;
  266.     int new_width;
  267. //    Dimension swidth, sheight;
  268. //    Dimension st;
  269.  
  270.     /*
  271.      * Find the current scrollbar sizes, and shadow thickness and format
  272.      * the document to the current window width
  273.      * (assume a vertical scrollbar)
  274.      */
  275.     new_width = HTML_Data->view_width;
  276.     temp = FormatAll(HTML_Data, &new_width);
  277.  
  278.     /*
  279.      * If we need the vertical scrollbar, place and manage it,
  280.      * and store the current viewing area width.
  281.      */
  282.  
  283.     /*
  284.      * Calculate the actual max width and height of the complete
  285.      * formatted document.
  286.      * The max width may exceed the preformatted width due to special
  287.      * factors in the formatting of the widget.
  288.      * Use the max of the 2 here, but leave max_pre_width unchanged
  289.      * for future formatting calls.
  290.      */
  291.     /*
  292.      * new_width includes the margins, and HTML_Data->max_pre_width
  293.      * does not, fix that here.
  294.      */
  295.     new_width = new_width - (2 * HTML_Data->margin_width);
  296.     if (HTML_Data->max_pre_width > new_width)
  297.     {
  298.         new_width = HTML_Data->max_pre_width;
  299.     }
  300.     /*
  301.      * If the maximum width derives from a formatted, as opposed to
  302.      * unformatted piece of text, allow a 20% of margin width slop
  303.      * over into the margin to cover up a minor glick with terminaing
  304.      * punctuation after anchors at the end of the line.
  305.      */
  306.     else
  307.     {
  308.         new_width = new_width - (20 * HTML_Data->margin_width / 100);
  309.     }
  310.  
  311.     HTML_Data->doc_height = temp;
  312.     HTML_Data->doc_width = new_width + (2 * HTML_Data->margin_width);
  313.     if (HTML_Data->view_width > HTML_Data->doc_width)
  314.     {
  315.         HTML_Data->doc_width = HTML_Data->view_width;
  316.     }
  317.  
  318. }
  319.  
  320.  
  321. /*
  322.  * Initialize is called when the widget is first initialized.
  323.  * Check to see that all the starting resources are valid.
  324.  */
  325. static void
  326. Initialize(HTMLGadClData * request, HTMLGadClData * new)
  327. {
  328.     /*
  329.      *    Make sure the underline numbers are within bounds.
  330.      */
  331.     if (new->num_anchor_underlines < 0)
  332.     {
  333.         new->num_anchor_underlines = 0;
  334.     } 
  335.     if (new->num_anchor_underlines > MAX_UNDERLINES)
  336.     {
  337.         new->num_anchor_underlines = MAX_UNDERLINES;
  338.     } 
  339.     if (new->num_visitedAnchor_underlines < 0)
  340.     {
  341.         new->num_visitedAnchor_underlines = 0;
  342.     } 
  343.     if (new->num_visitedAnchor_underlines > MAX_UNDERLINES)
  344.     {
  345.         new->num_visitedAnchor_underlines = MAX_UNDERLINES;
  346.     } 
  347.  
  348.     /*
  349.      * Parse the raw text with the HTML parser.  And set the formatted 
  350.      * element list to NULL.
  351.      */
  352.     new->html_objects = HTMLParse(NULL, request->raw_text);
  353.     CallLinkCallbacks(new);
  354.     new->html_header_objects =
  355.         HTMLParse(NULL, request->header_text);
  356.     new->html_footer_objects =
  357.         HTMLParse(NULL, request->footer_text);
  358.     new->formatted_elements = NULL;
  359.     new->my_visited_hrefs = NULL;
  360.     new->my_delayed_images = NULL;
  361.     new->widget_list = NULL;
  362.     new->form_list = NULL;
  363.  
  364.     /*
  365.      * Blank document
  366.      */
  367.     new->line_array = NULL;
  368.     new->line_count = 0;
  369.  
  370.     /*
  371.      * Find the max width of a preformatted
  372.      * line in this document.
  373.      */
  374.     new->max_pre_width = DocumentWidth(new, new->html_objects);
  375.  
  376.     /*
  377.      * Create the scrollbars.
  378.      * Find their dimensions and then decide which scrollbars you
  379.      * will need, and what the dimensions of the viewing area are.
  380.      * Start assuming a vertical scrollbar and a horizontal one.
  381.      * The remove vertical if short enough, and remove horizontal
  382.      * if narrow enough.
  383.      */
  384. //    CreateScrollbars(new);
  385.     new->scroll_x = 0;
  386.     new->scroll_y = 0;
  387.     ReformatWindow(new);
  388.  
  389.     /*
  390.      * Initialize private widget resources
  391.      */
  392.     new->drawGC = NULL;
  393.     new->select_start = NULL;
  394.     new->select_end = NULL;
  395.     new->sel_start_pos = 0;
  396.     new->sel_end_pos = 0;
  397.     new->new_start = NULL;
  398.     new->new_end = NULL;
  399.     new->new_start_pos = 0;
  400.     new->new_end_pos = 0;
  401.     new->active_anchor = NULL;
  402.     new->press_x = 0;
  403.     new->press_y = 0;
  404.  
  405.         new->cached_tracked_ele = NULL;
  406.  
  407.         /* Initialize cursor used when pointer is inside anchor. */
  408. //        if (in_anchor_cursor == NULL)
  409. //          in_anchor_cursor = XCreateFontCursor (XtDisplay (new), XC_hand2);
  410.  
  411.         return;
  412. }
  413.  
  414.  
  415. #ifdef DEBUG
  416. void
  417. DebugHook(x, y, width, height)
  418.     int x, y, width, height;
  419. {
  420. fprintf(stderr, "Redrawing (%d,%d) %dx%d\n", x, y, width, height);
  421. }
  422. #endif
  423.  
  424.  
  425. /*
  426.  * This is called by redisplay.  It is passed a rectangle
  427.  * in the viewing area, and it redisplays that portion of the
  428.  * underlying document area.
  429.  */
  430. void
  431. ViewRedisplay(
  432.             HTMLGadClData * HTML_Data,
  433.             int x,
  434.             int y,
  435.             int width,
  436.             int height)
  437. {
  438.     int sx, sy;
  439. //mjw    int doc_x;
  440.     int doc_y;
  441.     int i, start, end, guess;
  442.  
  443.     struct Region *new, *old;
  444.     struct Rectangle rect;
  445.  
  446.     /*
  447.      * Use scrollbar values to map from view space to document space.
  448.      */
  449.     sx = sy = 0;
  450.     if (HTML_Data->use_vbar == True)
  451.     {
  452.         sy += HTML_Data->scroll_y;
  453.     }
  454.     if (HTML_Data->use_hbar == True)
  455.     {
  456.         sx += HTML_Data->scroll_x;
  457.     }
  458.  
  459. //mjw    doc_x = x + sx;
  460.     doc_y = y + sy;
  461.  
  462.     /*
  463.      * Find the lines that overlap the exposed area.
  464.      */
  465.     start = 0;
  466.     end = HTML_Data->line_count - 1;
  467.  
  468.     /*
  469.      * Heuristic to speed up redraws by guessing at the starting line.
  470.      */
  471.     guess = doc_y / (HTML_Data->font->tf_YSize);
  472.     if (guess > end)
  473.     {
  474.         guess = end;
  475.     }
  476.     while (guess > 0)
  477.     {
  478.         if ((HTML_Data->line_array[guess] != NULL)&&
  479.             (HTML_Data->line_array[guess]->y < doc_y))
  480.         {
  481.             break;
  482.         }
  483.         guess--;
  484.     }
  485.     if (guess < start)
  486.     {
  487.         guess = start;
  488.     }
  489.  
  490.     for (i=guess; i<HTML_Data->line_count; i++)
  491.     {
  492.         if (HTML_Data->line_array[i] == NULL)
  493.         {
  494.             continue;
  495.         }
  496.  
  497.         if (HTML_Data->line_array[i]->y < doc_y)
  498.         {
  499.             start = i;
  500.         }
  501.         if (HTML_Data->line_array[i]->y > (doc_y + height))
  502.         {
  503.             end = i;
  504.             break;
  505.         }
  506.     }
  507.  
  508.     if (HTML_Data->rp != NULL){
  509.         /*
  510.          * If we have a GC draw the lines that overlap the exposed area.
  511.          */
  512.         if(!HTML_Data->have_forms){
  513.             rect.MinX = HTML_Data->view_left;
  514.             rect.MinY = HTML_Data->view_top;
  515.             rect.MaxX = HTML_Data->view_left + HTML_Data->view_width;
  516.             rect.MaxY = HTML_Data->view_top  + HTML_Data->view_height - 1;
  517.  
  518. /* sb: VERY ugly! Will rewrite it, later */
  519.  
  520.             new = NewRegion();
  521.             OrRectRegion(new, &rect);
  522.  
  523.             old = installClipRegion(HTML_Data->win, HTML_Data->win->WLayer, new);
  524.         }
  525.         for (i=start; i<=end; i++)
  526.         {
  527.             PlaceLine(HTML_Data, i);
  528.         }
  529.  
  530.         if(!HTML_Data->have_forms){
  531.             new = installClipRegion(HTML_Data->win, HTML_Data->win->WLayer, old);
  532.             DisposeRegion(new);
  533.             }
  534.       SetDrPt(HTML_Data->rp, 0xFFFF);
  535.     }
  536. }
  537.  
  538.  
  539. void
  540. ViewClearAndRefresh(HTMLGadClData * HTML_Data)
  541. {
  542.     /*
  543.      * Only refresh if we have a window already.
  544.      * (if we have a GC we have a window)
  545.      */
  546.     if (HTML_Data->rp != NULL){
  547.         SetAPen(HTML_Data->rp, 0);
  548.         RectFill(HTML_Data->rp, HTML_Data->view_left, HTML_Data->view_top,HTML_Data->view_left + HTML_Data->view_width,HTML_Data->view_top + HTML_Data->view_height);
  549.         SetAPen(HTML_Data->rp, 1);
  550.         ViewRedisplay(HTML_Data, 0, 0,
  551.             HTML_Data->view_width, HTML_Data->view_height);
  552.     }
  553. }
  554.  
  555. /*
  556.  * Find the complete text for this the anchor that aptr is a part of
  557.  * and set it into the selection.
  558.  */
  559. static void
  560. FindSelectAnchor(HTMLGadClData * HTML_Data, struct ele_rec *aptr)
  561. {
  562.     struct ele_rec *eptr;
  563.  
  564.     eptr = aptr;
  565.     while ((eptr->prev != NULL)&&
  566.         (eptr->prev->anchorHRef != NULL)&&
  567.         (strcmp(eptr->prev->anchorHRef, eptr->anchorHRef) == 0))
  568.     {
  569.         eptr = eptr->prev;
  570.     }
  571.     HTML_Data->select_start = eptr;
  572.     HTML_Data->sel_start_pos = 0;
  573.  
  574.     eptr = aptr;
  575.     while ((eptr->next != NULL)&&
  576.         (eptr->next->anchorHRef != NULL)&&
  577.         (strcmp(eptr->next->anchorHRef, eptr->anchorHRef) == 0))
  578.     {
  579.         eptr = eptr->next;
  580.     }
  581.     HTML_Data->select_end = eptr;
  582.     HTML_Data->sel_end_pos = eptr->edata_len - 2;
  583. }
  584.  
  585.  
  586. /*
  587.  * Set as active all elements in the widget that are part of the anchor
  588.  * in the widget's start ptr.
  589.  */
  590. void
  591. SetAnchor(HTMLGadClData * HTML_Data)
  592. {
  593.     struct ele_rec *eptr;
  594.     struct ele_rec *start;
  595.     struct ele_rec *end;
  596.     unsigned long fg, bg;
  597.     unsigned long old_fg, old_bg;
  598.     struct Region *new, *old;
  599.     struct Rectangle rect;
  600.  
  601.     eptr = HTML_Data->active_anchor;
  602.     if ((eptr == NULL)||(eptr->anchorHRef == NULL))
  603.     {
  604.         return;
  605.     }
  606.     fg = HTML_Data->activeAnchor_fg;
  607.     bg = HTML_Data->activeAnchor_bg;
  608.  
  609.     FindSelectAnchor(HTML_Data, eptr);
  610.  
  611.     start = HTML_Data->select_start;
  612.     end = HTML_Data->select_end;
  613.  
  614.     /* install amiga clipping region */
  615.     rect.MinX = HTML_Data->view_left;
  616.     rect.MinY = HTML_Data->view_top;
  617.     rect.MaxX = HTML_Data->view_left + HTML_Data->view_width;
  618.     rect.MaxY = HTML_Data->view_top  + HTML_Data->view_height - 1;
  619.     new = NewRegion();
  620.     OrRectRegion(new, &rect);
  621.     old = installClipRegion(HTML_Data->win, HTML_Data->win->WLayer, new);
  622.     /* end clipping */
  623.  
  624.     eptr = start;
  625.     while ((eptr != NULL)&&(eptr != end))
  626.     {
  627.         if (eptr->type == E_TEXT)
  628.         {
  629.             old_fg = eptr->fg;
  630.             old_bg = eptr->bg;
  631.             eptr->fg = fg;
  632.             eptr->bg = bg;
  633.             TextRefresh(HTML_Data, eptr,
  634.                 0, (eptr->edata_len - 2));
  635.             eptr->fg = old_fg;
  636.             eptr->bg = old_bg;
  637.         }
  638.         else if (eptr->type == E_IMAGE)
  639.         {
  640.             old_fg = eptr->fg;
  641.             old_bg = eptr->bg;
  642.             eptr->fg = fg;
  643.             eptr->bg = bg;
  644.             ImageRefresh(HTML_Data, eptr);
  645.             eptr->fg = old_fg;
  646.             eptr->bg = old_bg;
  647.         }
  648.     /*
  649.      * Linefeeds in anchor spanning multiple lines should NOT
  650.      * be highlighted!
  651.         else if (eptr->type == E_LINEFEED)
  652.         {
  653.             old_fg = eptr->fg;
  654.             old_bg = eptr->bg;
  655.             eptr->fg = fg;
  656.             eptr->bg = bg;
  657.             LinefeedRefresh(HTML_Data, eptr);
  658.             eptr->fg = old_fg;
  659.             eptr->bg = old_bg;
  660.         }
  661.     */
  662.         eptr = eptr->next;
  663.     }
  664.     if (eptr != NULL)
  665.     {
  666.         if (eptr->type == E_TEXT)
  667.         {
  668.             old_fg = eptr->fg;
  669.             old_bg = eptr->bg;
  670.             eptr->fg = fg;
  671.             eptr->bg = bg;
  672.             TextRefresh(HTML_Data, eptr,
  673.                 0, (eptr->edata_len - 2));
  674.             eptr->fg = old_fg;
  675.             eptr->bg = old_bg;
  676.         }
  677.         else if (eptr->type == E_IMAGE)
  678.         {
  679.             old_fg = eptr->fg;
  680.             old_bg = eptr->bg;
  681.             eptr->fg = fg;
  682.             eptr->bg = bg;
  683.             ImageRefresh(HTML_Data, eptr);
  684.             eptr->fg = old_fg;
  685.             eptr->bg = old_bg;
  686.         }
  687.     /*
  688.      * Linefeeds in anchor spanning multiple lines should NOT
  689.      * be highlighted!
  690.         else if (eptr->type == E_LINEFEED)
  691.         {
  692.             old_fg = eptr->fg;
  693.             old_bg = eptr->bg;
  694.             eptr->fg = fg;
  695.             eptr->bg = bg;
  696.             LinefeedRefresh(HTML_Data, eptr);
  697.             eptr->fg = old_fg;
  698.             eptr->bg = old_bg;
  699.         }
  700.     */
  701.     }
  702.     new = installClipRegion(HTML_Data->win, HTML_Data->win->WLayer, old);
  703.     DisposeRegion(new);
  704. }
  705.  
  706.  
  707. /*
  708.  * Draw selection for all elements in the widget
  709.  * from start to end.
  710.  */
  711. static void
  712. DrawSelection(HTMLGadClData * HTML_Data, struct ele_rec *start, struct ele_rec *end,
  713.           int start_pos, int end_pos)
  714. {
  715.     struct ele_rec *eptr;
  716.     int epos;
  717.  
  718.     if ((start == NULL)||(end == NULL))
  719.     {
  720.         return;
  721.     }
  722.  
  723.     /*
  724.      * Keep positions within bounds (allows us to be sloppy elsewhere)
  725.      */
  726.     if (start_pos < 0)
  727.     {
  728.         start_pos = 0;
  729.     }
  730.     if (start_pos >= start->edata_len - 1)
  731.     {
  732.         start_pos = start->edata_len - 2;
  733.     }
  734.     if (end_pos < 0)
  735.     {
  736.         end_pos = 0;
  737.     }
  738.     if (end_pos >= end->edata_len - 1)
  739.     {
  740.         end_pos = end->edata_len - 2;
  741.     }
  742.  
  743.     if (SwapElements(start, end, start_pos, end_pos))
  744.     {
  745.         eptr = start;
  746.         start = end;
  747.         end = eptr;
  748.         epos = start_pos;
  749.         start_pos = end_pos;
  750.         end_pos = epos;
  751.     }
  752.  
  753.     eptr = start;
  754.     while ((eptr != NULL)&&(eptr != end))
  755.     {
  756.         int p1, p2;
  757.  
  758.         if (eptr == start)
  759.         {
  760.             p1 = start_pos;
  761.         }
  762.         else
  763.         {
  764.             p1 = 0;
  765.         }
  766.         p2 = eptr->edata_len - 2;
  767.  
  768.         if (eptr->type == E_TEXT)
  769.         {
  770.             eptr->selected = True;
  771.             eptr->start_pos = p1;
  772.             eptr->end_pos = p2;
  773.             TextRefresh(HTML_Data, eptr, p1, p2);
  774.         }
  775.         else if (eptr->type == E_LINEFEED)
  776.         {
  777.             eptr->selected = True;
  778.             LinefeedRefresh(HTML_Data, eptr);
  779.         }
  780.         eptr = eptr->next;
  781.     }
  782.     if (eptr != NULL)
  783.     {
  784.         int p1, p2;
  785.  
  786.         if (eptr == start)
  787.         {
  788.             p1 = start_pos;
  789.         }
  790.         else
  791.         {
  792.             p1 = 0;
  793.         }
  794.  
  795.         if (eptr == end)
  796.         {
  797.             p2 = end_pos;
  798.         }
  799.         else
  800.         {
  801.             p2 = eptr->edata_len - 2;
  802.         }
  803.  
  804.         if (eptr->type == E_TEXT)
  805.         {
  806.             eptr->selected = True;
  807.             eptr->start_pos = p1;
  808.             eptr->end_pos = p2;
  809.             TextRefresh(HTML_Data, eptr, p1, p2);
  810.         }
  811.         else if (eptr->type == E_LINEFEED)
  812.         {
  813.             eptr->selected = True;
  814.             LinefeedRefresh(HTML_Data, eptr);
  815.         }
  816.     }
  817. }
  818.  
  819.  
  820. /*
  821.  * Set selection for all elements in the widget's
  822.  * start to end list.
  823.  */
  824. static void
  825. SetSelection(HTMLGadClData * HTML_Data)
  826. {
  827.     struct ele_rec *start;
  828.     struct ele_rec *end;
  829.     int start_pos, end_pos;
  830.  
  831.     start = HTML_Data->select_start;
  832.     end = HTML_Data->select_end;
  833.     start_pos = HTML_Data->sel_start_pos;
  834.     end_pos = HTML_Data->sel_end_pos;
  835.     DrawSelection(HTML_Data, start, end, start_pos, end_pos);
  836. }
  837.  
  838.  
  839. /*
  840.  * Erase the selection from start to end
  841.  */
  842. static void
  843. EraseSelection(HTMLGadClData * HTML_Data, struct ele_rec *start, struct ele_rec *end,
  844.            int start_pos, int end_pos)
  845. {
  846.     struct ele_rec *eptr;
  847.     int epos;
  848.  
  849.     if ((start == NULL)||(end == NULL))
  850.     {
  851.         return;
  852.     }
  853.  
  854.     /*
  855.      * Keep positoins within bounds (allows us to be sloppy elsewhere)
  856.      */
  857.     if (start_pos < 0)
  858.     {
  859.         start_pos = 0;
  860.     }
  861.     if (start_pos >= start->edata_len - 1)
  862.     {
  863.         start_pos = start->edata_len - 2;
  864.     }
  865.     if (end_pos < 0)
  866.     {
  867.         end_pos = 0;
  868.     }
  869.     if (end_pos >= end->edata_len - 1)
  870.     {
  871.         end_pos = end->edata_len - 2;
  872.     }
  873.  
  874.     if (SwapElements(start, end, start_pos, end_pos))
  875.     {
  876.         eptr = start;
  877.         start = end;
  878.         end = eptr;
  879.         epos = start_pos;
  880.         start_pos = end_pos;
  881.         end_pos = epos;
  882.     }
  883.  
  884.     eptr = start;
  885.     while ((eptr != NULL)&&(eptr != end))
  886.     {
  887.         int p1, p2;
  888.  
  889.         if (eptr == start)
  890.         {
  891.             p1 = start_pos;
  892.         }
  893.         else
  894.         {
  895.             p1 = 0;
  896.         }
  897.         p2 = eptr->edata_len - 2;
  898.  
  899.         if (eptr->type == E_TEXT)
  900.         {
  901.             eptr->selected = False;
  902.             TextRefresh(HTML_Data, eptr, p1, p2);
  903.         }
  904.         else if (eptr->type == E_LINEFEED)
  905.         {
  906.             eptr->selected = False;
  907.             LinefeedRefresh(HTML_Data, eptr);
  908.         }
  909.         eptr = eptr->next;
  910.     }
  911.     if (eptr != NULL)
  912.     {
  913.         int p1, p2;
  914.  
  915.         if (eptr == start)
  916.         {
  917.             p1 = start_pos;
  918.         }
  919.         else
  920.         {
  921.             p1 = 0;
  922.         }
  923.  
  924.         if (eptr == end)
  925.         {
  926.             p2 = end_pos;
  927.         }
  928.         else
  929.         {
  930.             p2 = eptr->edata_len - 2;
  931.         }
  932.  
  933.         if (eptr->type == E_TEXT)
  934.         {
  935.             eptr->selected = False;
  936.             TextRefresh(HTML_Data, eptr, p1, p2);
  937.         }
  938.         else if (eptr->type == E_LINEFEED)
  939.         {
  940.             eptr->selected = False;
  941.             LinefeedRefresh(HTML_Data, eptr);
  942.         }
  943.     }
  944. }
  945.  
  946.  
  947. /*
  948.  * Clear the current selection (if there is one)
  949.  */
  950. static void
  951. ClearSelection(HTMLGadClData * HTML_Data)
  952. {
  953.     struct ele_rec *start;
  954.     struct ele_rec *end;
  955.     int start_pos, end_pos;
  956.  
  957.     start = HTML_Data->select_start;
  958.     end = HTML_Data->select_end;
  959.     start_pos = HTML_Data->sel_start_pos;
  960.     end_pos = HTML_Data->sel_end_pos;
  961.     EraseSelection(HTML_Data, start, end, start_pos, end_pos);
  962.  
  963.     if ((start == NULL)||(end == NULL))
  964.     {
  965.         HTML_Data->select_start = NULL;
  966.         HTML_Data->select_end = NULL;
  967.         HTML_Data->sel_start_pos = 0;
  968.         HTML_Data->sel_end_pos = 0;
  969.         HTML_Data->active_anchor = NULL;
  970.         return;
  971.     }
  972.  
  973.     HTML_Data->select_start = NULL;
  974.     HTML_Data->select_end = NULL;
  975.     HTML_Data->sel_start_pos = 0;
  976.     HTML_Data->sel_end_pos = 0;
  977.     HTML_Data->active_anchor = NULL;
  978. }
  979.  
  980.  
  981. /*
  982.  * clear from active all elements in the widget that are part of the anchor.
  983.  * (These have already been previously set into the start and end of the
  984.  * selection.
  985.  */
  986. void
  987. UnsetAnchor(HTMLGadClData * HTML_Data)
  988. {
  989.     struct ele_rec *eptr;
  990.     struct Region *new, *old;
  991.     struct Rectangle rect;
  992.  
  993.     if(eptr = HTML_Data->select_start){
  994.  
  995.         /* Amiga clipping stuff */
  996.         rect.MinX = HTML_Data->view_left;
  997.         rect.MinY = HTML_Data->view_top;
  998.         rect.MaxX = HTML_Data->view_left + HTML_Data->view_width;
  999.         rect.MaxY = HTML_Data->view_top  + HTML_Data->view_height - 1;
  1000.         new = NewRegion();
  1001.         OrRectRegion(new, &rect);
  1002.         old = installClipRegion(HTML_Data->win, HTML_Data->win->WLayer, new);
  1003.         /* end clipping */
  1004.  
  1005.         /*
  1006.          * Clear any activated images
  1007.          */
  1008.  
  1009.         while ((eptr != NULL)&&(eptr != HTML_Data->select_end)){
  1010.             if (eptr->type == E_IMAGE){
  1011.                 ImageRefresh(HTML_Data, eptr);}
  1012.             eptr = eptr->next;
  1013.             }
  1014.         if ((eptr != NULL)&&(eptr->type == E_IMAGE)){
  1015.             ImageRefresh(HTML_Data, eptr);}
  1016.  
  1017.         /*
  1018.          * Clear the activated anchor
  1019.          */
  1020.         ClearSelection(HTML_Data); /* Selection doesn't work for AMosaic */
  1021.  
  1022.         new = installClipRegion(HTML_Data->win, HTML_Data->win->WLayer, old);
  1023.         DisposeRegion(new);
  1024.     }
  1025. }
  1026.  
  1027.  
  1028. /*
  1029.  * Erase the old selection, and draw the new one in such a way
  1030.  * that advantage is taken of overlap, and there is no obnoxious
  1031.  * flashing.
  1032.  */
  1033. static void
  1034. ChangeSelection(HTMLGadClData * HTML_Data, struct ele_rec *start, struct ele_rec *end,
  1035.         int start_pos, int end_pos)
  1036. {
  1037.     struct ele_rec *old_start;
  1038.     struct ele_rec *old_end;
  1039.     struct ele_rec *new_start;
  1040.     struct ele_rec *new_end;
  1041.     struct ele_rec *eptr;
  1042.     int epos;
  1043.     int new_start_pos, new_end_pos;
  1044.     int old_start_pos, old_end_pos;
  1045.  
  1046.     old_start = HTML_Data->new_start;
  1047.     old_end = HTML_Data->new_end;
  1048.     old_start_pos = HTML_Data->new_start_pos;
  1049.     old_end_pos = HTML_Data->new_end_pos;
  1050.     new_start = start;
  1051.     new_end = end;
  1052.     new_start_pos = start_pos;
  1053.     new_end_pos = end_pos;
  1054.  
  1055.     if ((new_start == NULL)||(new_end == NULL))
  1056.     {
  1057.         return;
  1058.     }
  1059.  
  1060.     if ((old_start == NULL)||(old_end == NULL))
  1061.     {
  1062.         DrawSelection(HTML_Data, new_start, new_end,
  1063.             new_start_pos, new_end_pos);
  1064.         return;
  1065.     }
  1066.  
  1067.     if (SwapElements(old_start, old_end, old_start_pos, old_end_pos))
  1068.     {
  1069.         eptr = old_start;
  1070.         old_start = old_end;
  1071.         old_end = eptr;
  1072.         epos = old_start_pos;
  1073.         old_start_pos = old_end_pos;
  1074.         old_end_pos = epos;
  1075.     }
  1076.  
  1077.     if (SwapElements(new_start, new_end, new_start_pos, new_end_pos))
  1078.     {
  1079.         eptr = new_start;
  1080.         new_start = new_end;
  1081.         new_end = eptr;
  1082.         epos = new_start_pos;
  1083.         new_start_pos = new_end_pos;
  1084.         new_end_pos = epos;
  1085.     }
  1086.  
  1087.     /*
  1088.      * Deal with all possible intersections of the 2 selection sets.
  1089.      *
  1090.      ********************************************************
  1091.      *            *                *
  1092.      *      |--        *         |--        *
  1093.      * old--|        *    new--|            *
  1094.      *      |--        *         |--        *
  1095.      *            *                *
  1096.      *      |--        *         |--        *
  1097.      * new--|        *    old--|            *
  1098.      *      |--        *         |--        *
  1099.      *            *                *
  1100.      ********************************************************
  1101.      *            *                *
  1102.      *      |----        *           |--        *
  1103.      * old--|        *      new--|        *
  1104.      *      | |--        *           |        *
  1105.      *      |-+--        *         |-+--        *
  1106.      *        |        *         | |--        *
  1107.      *   new--|        *    old--|            *
  1108.      *        |--        *         |----        *
  1109.      *            *                *
  1110.      ********************************************************
  1111.      *            *                *
  1112.      *      |---------    *         |---------        *
  1113.      *      |        *         |            *
  1114.      *      |      |--    *         |      |--        *
  1115.      * new--| old--|    *    old--| new--|        *
  1116.      *      |      |--    *         |      |--        *
  1117.      *      |        *         |            *
  1118.      *      |---------    *         |---------        *
  1119.      *            *                *
  1120.      ********************************************************
  1121.      *
  1122.      */
  1123.     if ((ElementLessThan(old_end, new_start, old_end_pos, new_start_pos))||
  1124.         (ElementLessThan(new_end, old_start, new_end_pos, old_start_pos)))
  1125.     {
  1126.         EraseSelection(HTML_Data, old_start, old_end,
  1127.             old_start_pos, old_end_pos);
  1128.         DrawSelection(HTML_Data, new_start, new_end,
  1129.             new_start_pos, new_end_pos);
  1130.     }
  1131.     else if ((ElementLessThan(old_start, new_start,
  1132.             old_start_pos, new_start_pos))&&
  1133.          (ElementLessThan(old_end, new_end, old_end_pos, new_end_pos)))
  1134.     {
  1135.         if (new_start_pos != 0)
  1136.         {
  1137.             EraseSelection(HTML_Data, old_start, new_start,
  1138.                 old_start_pos, new_start_pos - 1);
  1139.         }
  1140.         else
  1141.         {
  1142.             EraseSelection(HTML_Data, old_start, new_start->prev,
  1143.                 old_start_pos, new_start->prev->edata_len - 2);
  1144.         }
  1145.         if (old_end_pos < (old_end->edata_len - 2))
  1146.         {
  1147.             DrawSelection(HTML_Data, old_end, new_end,
  1148.                 old_end_pos + 1, new_end_pos);
  1149.         }
  1150.         else
  1151.         {
  1152.             DrawSelection(HTML_Data, old_end->next, new_end,
  1153.                 0, new_end_pos);
  1154.         }
  1155.     }
  1156.     else if ((ElementLessThan(new_start, old_start,
  1157.             new_start_pos, old_start_pos))&&
  1158.          (ElementLessThan(new_end, old_end, new_end_pos, old_end_pos)))
  1159.     {
  1160.         if (old_start_pos != 0)
  1161.         {
  1162.             DrawSelection(HTML_Data, new_start, old_start,
  1163.                 new_start_pos, old_start_pos - 1);
  1164.         }
  1165.         else
  1166.         {
  1167.             DrawSelection(HTML_Data, new_start, old_start->prev,
  1168.                 new_start_pos, old_start->prev->edata_len - 2);
  1169.         }
  1170.         if (new_end_pos < (new_end->edata_len - 2))
  1171.         {
  1172.             EraseSelection(HTML_Data, new_end, old_end,
  1173.                 new_end_pos + 1, old_end_pos);
  1174.         }
  1175.         else
  1176.         {
  1177.             EraseSelection(HTML_Data, new_end->next, old_end,
  1178.                 0, old_end_pos);
  1179.         }
  1180.     }
  1181.     else if ((ElementLessThan(new_start, old_start,
  1182.             new_start_pos, old_start_pos))||
  1183.          (ElementLessThan(old_end, new_end, old_end_pos, new_end_pos)))
  1184.     {
  1185.         if ((new_start != old_start)||(new_start_pos != old_start_pos))
  1186.         {
  1187.             if (old_start_pos != 0)
  1188.             {
  1189.                 DrawSelection(HTML_Data, new_start, old_start,
  1190.                     new_start_pos, old_start_pos - 1);
  1191.             }
  1192.             else
  1193.             {
  1194.                 DrawSelection(HTML_Data, new_start, old_start->prev,
  1195.                     new_start_pos,
  1196.                     old_start->prev->edata_len - 2);
  1197.             }
  1198.         }
  1199.         if ((old_end != new_end)||(old_end_pos != new_end_pos))
  1200.         {
  1201.             if (old_end_pos < (old_end->edata_len - 2))
  1202.             {
  1203.                 DrawSelection(HTML_Data, old_end, new_end,
  1204.                     old_end_pos + 1, new_end_pos);
  1205.             }
  1206.             else
  1207.             {
  1208.                 DrawSelection(HTML_Data, old_end->next, new_end,
  1209.                     0, new_end_pos);
  1210.             }
  1211.         }
  1212.     }
  1213.     else
  1214.     {
  1215.         if ((old_start != new_start)||(old_start_pos != new_start_pos))
  1216.         {
  1217.             if (new_start_pos != 0)
  1218.             {
  1219.                 EraseSelection(HTML_Data, old_start, new_start,
  1220.                     old_start_pos, new_start_pos - 1);
  1221.             }
  1222.             else
  1223.             {
  1224.                 EraseSelection(HTML_Data, old_start, new_start->prev,
  1225.                     old_start_pos,
  1226.                     new_start->prev->edata_len - 2);
  1227.             }
  1228.         }
  1229.         if ((new_end != old_end)||(new_end_pos != old_end_pos))
  1230.         {
  1231.             if (new_end_pos < (new_end->edata_len - 2))
  1232.             {
  1233.                 EraseSelection(HTML_Data, new_end, old_end,
  1234.                     new_end_pos + 1, old_end_pos);
  1235.             }
  1236.             else
  1237.             {
  1238.                 EraseSelection(HTML_Data, new_end->next, old_end,
  1239.                     0, old_end_pos);
  1240.             }
  1241.         }
  1242.     }
  1243. }
  1244.  
  1245.  
  1246.  
  1247. /* MDF - I should port this!! */
  1248.  
  1249. /*
  1250.  * Go through the parsed marks and for all the <LINK> tags in the document
  1251.  * call the LinkCallback.
  1252.  */
  1253. static void
  1254. CallLinkCallbacks(HTMLGadClData * HTML_Data)
  1255. {
  1256.     struct mark_up *mptr;
  1257.     LinkInfo l_info;
  1258.  
  1259.     mptr = HTML_Data->html_objects;
  1260.     while (mptr != NULL)
  1261.     {
  1262.         if (mptr->type == M_BASE)
  1263.         {
  1264.             l_info.href = ParseMarkTag(mptr->start, MT_BASE,
  1265.                 "HREF");
  1266.             l_info.role = ParseMarkTag(mptr->start, MT_BASE,
  1267.                 "ROLE");
  1268. //            XtCallCallbackList ((Widget)HTML_Data, HTML_Data->link_callback,
  1269. //                (XtPointer)&l_info);
  1270.             if (l_info.href != NULL)
  1271.             {
  1272.                 free(l_info.href);
  1273.             }
  1274.             if (l_info.role != NULL)
  1275.             {
  1276.                 free(l_info.role);
  1277.             }
  1278.         }
  1279.         mptr = mptr->next;
  1280.     }
  1281. }
  1282.  
  1283.  
  1284. /*
  1285.  * Search through the whole document, and recolor the internal elements with
  1286.  * the passed HREF.
  1287.  */
  1288. static void
  1289. RecolorInternalHRefs(HTMLGadClData * HTML_Data, char *href)
  1290. {
  1291.     struct ele_rec *start;
  1292.     unsigned long fg;
  1293.  
  1294.     fg = HTML_Data->visitedAnchor_fg;
  1295.     start = HTML_Data->formatted_elements;
  1296.     while (start != NULL)
  1297.     {
  1298.         /*
  1299.          * This one is internal
  1300.          * This one has an href
  1301.          * This is the href we want
  1302.          */
  1303.         if ((start->internal == True)&&
  1304.             (start->anchorHRef != NULL)&&
  1305.             (strcmp(start->anchorHRef, href) == 0))
  1306.         {
  1307.             start->fg = fg;
  1308.             start->underline_number =
  1309.                 HTML_Data->num_visitedAnchor_underlines;
  1310.             start->dashed_underline =
  1311.                 HTML_Data->dashed_visitedAnchor_lines;
  1312.         }
  1313.         start = start->next;
  1314.     }
  1315. }
  1316.  
  1317. /*
  1318.  *************************************************************************
  1319.  ******************************* PUBLIC FUNCTIONS ************************
  1320.  *************************************************************************
  1321.  */
  1322.  
  1323.  
  1324. /*
  1325.  * Convenience function to return the text of the HTML document as a plain
  1326.  * ascii text string.
  1327.  * This function allocates memory for the returned string, that it is up
  1328.  * to the user to free.
  1329.  * Extra option flags "pretty" text to be returned.
  1330.  */
  1331. char *
  1332. HTMLGetText(HTMLGadClData *w, int pretty)
  1333. {
  1334.     HTMLGadClData * HTML_Data = w;
  1335.     char *text;
  1336.     char *tptr, *buf;
  1337.     struct ele_rec *start;
  1338.     struct ele_rec *end;
  1339.  
  1340.     text = NULL;
  1341.     start = HTML_Data->formatted_elements;
  1342.     end = start;
  1343.     while (end != NULL)
  1344.     {
  1345.         end = end->next;
  1346.     }
  1347.  
  1348.     if (pretty == 2)
  1349.     {
  1350. /*
  1351.         tptr = ParseTextToPSString(HTML_Data, start, start, end,
  1352.                 0, 0,
  1353.                 HTML_Data->font->max_bounds.width,
  1354.                 HTML_Data->margin_width);
  1355. */
  1356.     }
  1357.     else if (pretty)
  1358.     {
  1359.         int width;
  1360.  
  1361.         SetFont(HTML_Data->rp, HTML_Data->font);
  1362.         width = TextLength(HTML_Data->rp, "n", 1); /* average character? */
  1363.         tptr = ParseTextToPrettyString(HTML_Data, start, start, end,
  1364.                 0, 0,
  1365.                 width,
  1366.                 HTML_Data->margin_width);
  1367.     }
  1368.     else
  1369.     {
  1370.         int width;
  1371.  
  1372.         SetFont(HTML_Data->rp, HTML_Data->font);
  1373.         width = TextLength(HTML_Data->rp, "n", 1); /* average character? */
  1374.         tptr = ParseTextToString(start, start, end,
  1375.                 0, 0,
  1376.                 width,
  1377.                 HTML_Data->margin_width);
  1378.     }
  1379.     if (tptr != NULL)
  1380.     {
  1381.         if (text == NULL)
  1382.         {
  1383.             text = tptr;
  1384.         }
  1385.         else
  1386.         {
  1387.             buf = (char *)malloc(strlen(text) +
  1388.                 strlen(tptr) + 1);
  1389.             strcpy(buf, text);
  1390.             strcat(buf, tptr);
  1391.             free(text);
  1392.             free(tptr);
  1393.             text = buf;
  1394.         }
  1395.     }
  1396.     return(text);
  1397. }
  1398.  
  1399.  
  1400. /*
  1401.  * Convenience function to return the element id of the element
  1402.  * nearest to the x,y coordinates passed in.
  1403.  * If there is no element there, return the first element in the
  1404.  * line we are on.  If there we are on no line, either return the
  1405.  * beginning, or the end of the document.
  1406.  */
  1407. int
  1408. HTMLPositionToId(HTMLGadClData *w, int x, int y)
  1409. {
  1410.     HTMLGadClData * HTML_Data = w;
  1411.     int i;
  1412.     int epos;
  1413.     struct ele_rec *eptr;
  1414.  
  1415.     eptr = LocateElement(HTML_Data, x, y, &epos);
  1416.     if (eptr == NULL)
  1417.     {
  1418. //mjw        x = x + HTML_Data->scroll_x;
  1419. //sb        y = y + HTML_Data->scroll_y; /* This look stupid! */
  1420.         eptr = HTML_Data->line_array[0];
  1421.         for (i=0; i<HTML_Data->line_count; i++)
  1422.         {
  1423.             if (HTML_Data->line_array[i] == NULL)
  1424.             {
  1425.                 continue;
  1426.             }
  1427.             else if (HTML_Data->line_array[i]->y <= y)
  1428.             {
  1429.                 eptr = HTML_Data->line_array[i];
  1430.                 continue;
  1431.             }
  1432.             else
  1433.             {
  1434.                 break;
  1435.             }
  1436.         }
  1437.     }
  1438.  
  1439.     /*
  1440.      * 0 means the very top of the document.  We put you there for
  1441.      * unfound elements.
  1442.      * We also special case for when the scrollbar is at the
  1443.      * absolute top.
  1444.      */
  1445.     if ((eptr == NULL)||(HTML_Data->scroll_y == 0))
  1446.     {
  1447.         return(0);
  1448.     }
  1449.     else
  1450.     {
  1451.         return(eptr->ele_id);
  1452.     }
  1453. }
  1454.  
  1455.  
  1456. /*
  1457.  * Convenience function to return the position of the element
  1458.  * based on the element id passed in.
  1459.  * Function returns 1 on success and fills in x,y pixel values.
  1460.  * If there is no such element, x=0, y=0 and -1 is returned.
  1461.  */
  1462. int
  1463. HTMLIdToPosition(Widget w, int element_id, int *x, int *y)
  1464. {
  1465.     HTMLGadClData * HTML_Data = (HTMLGadClData *)w;
  1466.     struct ele_rec *start;
  1467.     struct ele_rec *eptr;
  1468.  
  1469.     eptr = NULL;
  1470.     start = HTML_Data->formatted_elements;
  1471.     while (start != NULL)
  1472.     {
  1473.         if (start->ele_id == element_id)
  1474.         {
  1475.             eptr = start;
  1476.             break;
  1477.         }
  1478.         start = start->next;
  1479.     }
  1480.  
  1481.     if (eptr == NULL)
  1482.     {
  1483.         *x = 0;
  1484.         *y = 0;
  1485.         return(-1);
  1486.     }
  1487.     else
  1488.     {
  1489.         *x = eptr->x;
  1490.         *y = eptr->y;
  1491.         return(1);
  1492.     }
  1493. }
  1494.  
  1495.  
  1496. /*
  1497.  * Convenience function to position the element
  1498.  * based on the element id passed at the top of the viewing area.
  1499.  * A passed in id of 0 means goto the top.
  1500.  */
  1501. void
  1502. HTMLGotoId(HTMLGadClData *w, int element_id)
  1503. {
  1504.     HTMLGadClData * HTML_Data = w;
  1505.     struct ele_rec *start;
  1506.     struct ele_rec *eptr;
  1507.     int newy;
  1508. #ifdef MOTIF
  1509.     int val, size, inc, pageinc;
  1510. #endif
  1511.  
  1512.     /*
  1513.      * If we have no scrollbar, just return.
  1514.      */
  1515.     if (HTML_Data->use_vbar == False)
  1516.     {
  1517.         return;
  1518.     }
  1519.  
  1520.     /*
  1521.      * Find the element corrsponding to the id passed in.
  1522.      */
  1523.     eptr = NULL;
  1524.     start = HTML_Data->formatted_elements;
  1525.     while (start != NULL)
  1526.     {
  1527.         if (start->ele_id == element_id)
  1528.         {
  1529.             eptr = start;
  1530.             break;
  1531.         }
  1532.         start = start->next;
  1533.     }
  1534.  
  1535.     /*
  1536.      * No such element, do nothing.
  1537.      */
  1538.     if ((element_id != 0)&&(eptr == NULL))
  1539.     {
  1540.         return;
  1541.     }
  1542.  
  1543.     if (element_id == 0)
  1544.     {
  1545.         newy = 0;
  1546.     }
  1547.     else
  1548.     {
  1549.         newy = eptr->y - 2;
  1550.     }
  1551.     if (newy < 0)
  1552.     {
  1553.         newy = 0;
  1554.     }
  1555.     if (newy > (HTML_Data->doc_height - (int)HTML_Data->view_height))
  1556.     {
  1557.         newy = HTML_Data->doc_height - (int)HTML_Data->view_height;
  1558.     }
  1559.     if (newy < 0)
  1560.     {
  1561.         newy = 0;
  1562.     }
  1563.     set(HTML_Gad,HTMLA_scroll_y,newy);
  1564.     set(HTML_Gad,HTMLA_scroll_x,0);
  1565. //    ScrollToPos(HTML_Data, 0, newy);
  1566. //    ScrollToPos(HTML_Data, 1, 0);
  1567. //    ScrollToPos(HTML_Data->vbar, HTML_Data, newy);
  1568. //    ScrollToPos(HTML_Data->hbar, HTML_Data, 0);
  1569. //    setScrollBar(HTML_Data->vbar, newy, 
  1570. //             HTML_Data->doc_height,
  1571. //             HTML_Data->view_height);
  1572. #endif
  1573. }
  1574.  
  1575.  
  1576. /*
  1577.  * Convenience function to return the position of the anchor
  1578.  * based on the anchor NAME passed.
  1579.  * Function returns 1 on success and fills in x,y pixel values.
  1580.  * If there is no such element, x=0, y=0 and -1 is returned.
  1581.  */
  1582. int
  1583. HTMLAnchorToPosition(Widget w, char *name, int *x, int *y)
  1584. {
  1585.     HTMLGadClData * HTML_Data = (HTMLGadClData *)w;
  1586.     struct ele_rec *start;
  1587.     struct ele_rec *eptr;
  1588.  
  1589.     eptr = NULL;
  1590.     start = HTML_Data->formatted_elements;
  1591.     while (start != NULL)
  1592.     {
  1593.         if ((start->anchorName)&&
  1594.             (strcmp(start->anchorName, name) == 0))
  1595.         {
  1596.             eptr = start;
  1597.             break;
  1598.         }
  1599.         start = start->next;
  1600.     }
  1601.  
  1602.     if (eptr == NULL)
  1603.     {
  1604.         *x = 0;
  1605.         *y = 0;
  1606.         return(-1);
  1607.     }
  1608.     else
  1609.     {
  1610.         *x = eptr->x;
  1611.         *y = eptr->y;
  1612.         return(1);
  1613.     }
  1614. }
  1615.  
  1616.  
  1617. /*
  1618.  * Convenience function to return the element id of the anchor
  1619.  * based on the anchor NAME passed.
  1620.  * Function returns id on success.
  1621.  * If there is no such element, 0 is returned.
  1622.  */
  1623. int
  1624. HTMLAnchorToId(Object *HTML_Gad, char *name)
  1625. {
  1626.     HTMLGadClData * HTML_Data = INST_DATA(HTMLGadClass,HTML_Gad);
  1627.     struct ele_rec *start;
  1628.     struct ele_rec *eptr;
  1629.  
  1630.     /*
  1631.      * Find the passed anchor name
  1632.      */
  1633.     eptr = NULL;
  1634.     start = HTML_Data->formatted_elements;
  1635.     while (start != NULL)
  1636.     {
  1637.         if ((start->anchorName)&&
  1638.             (strcmp(start->anchorName, name) == 0))
  1639.         {
  1640.             eptr = start;
  1641.             break;
  1642.         }
  1643.         start = start->next;
  1644.     }
  1645.  
  1646.     if (eptr == NULL)
  1647.     {
  1648.         return(0);
  1649.     }
  1650.     else
  1651.     {
  1652.         return(eptr->ele_id);
  1653.     }
  1654. }
  1655.  
  1656.  
  1657. /*
  1658.  * Convenience function to return the HREFs of all active anchors in the
  1659.  * document.
  1660.  * Function returns an array of strings and fills num_hrefs passed.
  1661.  * If there are no HREFs NULL returned.
  1662.  */
  1663. char **
  1664. HTMLGetHRefs(Object *HTML_Gad, int *num_hrefs)
  1665. {
  1666.     HTMLGadClData * HTML_Data = INST_DATA(HTMLGadClass,HTML_Gad);
  1667.     int cnt;
  1668.     struct ele_rec *start;
  1669.     struct ele_rec *list;
  1670.     struct ele_rec *eptr;
  1671.     char **harray;
  1672.  
  1673.     list = NULL;
  1674.     cnt = 0;
  1675.     /*
  1676.      * Construct a linked list of all the diffeent hrefs, counting
  1677.      * then as we go.
  1678.      */
  1679.     start = HTML_Data->formatted_elements;
  1680.     while (start != NULL)
  1681.     {
  1682.         /*
  1683.          * This one has an HREF
  1684.          */
  1685.         if (start->anchorHRef != NULL)
  1686.         {
  1687.             /*
  1688.              * Check to see if we already have
  1689.              * this HREF in our list.
  1690.              */
  1691.             eptr = list;
  1692.             while (eptr != NULL)
  1693.             {
  1694.                 if (strcmp(eptr->anchorHRef,
  1695.                     start->anchorHRef) == 0)
  1696.                 {
  1697.                     break;
  1698.                 }
  1699.                 eptr = eptr->next;
  1700.             }
  1701.             /*
  1702.              * This HREF is not, in our list.  Add it.
  1703.              * That is, if it's not an internal reference.
  1704.              */
  1705.             if ((eptr == NULL)&&(start->internal == False))
  1706.             {
  1707.                 eptr = (struct ele_rec *)
  1708.                     malloc(sizeof(struct ele_rec));
  1709.                 eptr->anchorHRef = start->anchorHRef;
  1710.                 eptr->next = list;
  1711.                 list = eptr;
  1712.                 cnt++;
  1713.             }
  1714.         }
  1715.         start = start->next;
  1716.     }
  1717.  
  1718.     if (cnt == 0)
  1719.     {
  1720.         *num_hrefs = 0;
  1721.         return(NULL);
  1722.     }
  1723.     else
  1724.     {
  1725.         *num_hrefs = cnt;
  1726.         harray = (char **)malloc(sizeof(char *) * cnt);
  1727.         eptr = list;
  1728.         cnt--;
  1729.         while (eptr != NULL)
  1730.         {
  1731.             harray[cnt] = (char *)
  1732.                 malloc(strlen(eptr->anchorHRef) + 1);
  1733.             strcpy(harray[cnt], eptr->anchorHRef);
  1734.             start = eptr;
  1735.             eptr = eptr->next;
  1736.             free((char *)start);
  1737.             cnt--;
  1738.         }
  1739.         return(harray);
  1740.     }
  1741. }
  1742.  
  1743.  
  1744. /*
  1745.  * Convenience function to return the SRCs of all images in the
  1746.  * document.
  1747.  * Function returns an array of strings and fills num_srcs passed.
  1748.  * If there are no SRCs NULL returned.
  1749.  */
  1750. char **
  1751. HTMLGetImageSrcs(HTMLGadClData *w, int *num_srcs)
  1752. {
  1753.     HTMLGadClData * HTML_Data = w;
  1754.     struct mark_up *mptr;
  1755.     int cnt;
  1756.     char *tptr;
  1757.     char **harray;
  1758.  
  1759.     cnt = 0;
  1760.     mptr = HTML_Data->html_objects;
  1761.     while (mptr != NULL)
  1762.     {
  1763.         if (mptr->type == M_IMAGE)
  1764.         {
  1765.             tptr = ParseMarkTag(mptr->start, MT_IMAGE, "SRC");
  1766.             if ((tptr != NULL)&&(*tptr != '\0'))
  1767.             {
  1768.                 cnt++;
  1769.                 free(tptr);
  1770.             }
  1771.         }
  1772.         else if (mptr->type == M_INPUT)
  1773.         {
  1774.             tptr = ParseMarkTag(mptr->start, MT_INPUT, "TYPE");
  1775.             if (tptr && !stricmp(tptr,"image"))
  1776.             {
  1777.                 free(tptr);
  1778.                 tptr = ParseMarkTag(mptr->start, MT_IMAGE, "SRC");
  1779.                 if ((tptr != NULL)&&(*tptr != '\0'))
  1780.                     {
  1781.                     cnt++;
  1782.                     free(tptr);
  1783.                     }
  1784.             }
  1785.             else
  1786.                 free(tptr);
  1787.  
  1788.         }
  1789.  
  1790.         mptr = mptr->next;
  1791.     }
  1792.  
  1793.     if (cnt == 0)
  1794.     {
  1795.         *num_srcs = 0;
  1796.         return(NULL);
  1797.     }
  1798.     else
  1799.     {
  1800.         *num_srcs = cnt;
  1801.         harray = (char **)malloc(sizeof(char *) * cnt);
  1802.         mptr = HTML_Data->html_objects;
  1803.         cnt = 0;
  1804.         while (mptr != NULL)
  1805.         {
  1806.             if (mptr->type == M_IMAGE)
  1807.             {
  1808.                 tptr = ParseMarkTag(mptr->start,MT_IMAGE,"SRC");
  1809.                 if ((tptr != NULL)&&(*tptr != '\0'))
  1810.                 {
  1811.                     harray[cnt] = tptr;
  1812.                     cnt++;
  1813.                 }
  1814.             }
  1815.             else if (mptr->type == M_INPUT){
  1816.                 tptr = ParseMarkTag(mptr->start, MT_INPUT, "TYPE");
  1817.                 if (tptr && !stricmp(tptr,"image")){
  1818.                     free(tptr);
  1819.                     tptr = ParseMarkTag(mptr->start, MT_IMAGE, "SRC");
  1820.                     if ((tptr != NULL)&&(*tptr != '\0')){
  1821.                         harray[cnt] = tptr;
  1822.                         cnt++;
  1823.                         }
  1824.                 }
  1825.                 else
  1826.                     free(tptr);
  1827.                 }
  1828.  
  1829.             mptr = mptr->next;
  1830.         }
  1831.         return(harray);
  1832.     }
  1833. }
  1834.  
  1835.  
  1836. /*
  1837.  * Convenience function to return the link information
  1838.  * for all the <LINK> tags in the document.
  1839.  * Function returns an array of LinkInfo structures and fills
  1840.  * num_links passed.
  1841.  * If there are no LINKs NULL returned.
  1842.  */
  1843. LinkInfo *
  1844. HTMLGetLinks(Widget w, int *num_links)
  1845. {
  1846.     HTMLGadClData * HTML_Data = (HTMLGadClData *)w;
  1847.     struct mark_up *mptr;
  1848.     int cnt;
  1849.     char *tptr;
  1850.     LinkInfo *larray;
  1851.  
  1852.     cnt = 0;
  1853.     mptr = HTML_Data->html_objects;
  1854.     while (mptr != NULL)
  1855.     {
  1856.         if (mptr->type == M_BASE)
  1857.         {
  1858.             cnt++;
  1859.         }
  1860.         mptr = mptr->next;
  1861.     }
  1862.  
  1863.     if (cnt == 0)
  1864.     {
  1865.         *num_links = 0;
  1866.         return(NULL);
  1867.     }
  1868.     else
  1869.     {
  1870.         *num_links = cnt;
  1871.         larray = (LinkInfo *)malloc(sizeof(LinkInfo) * cnt);
  1872.         mptr = HTML_Data->html_objects;
  1873.         cnt = 0;
  1874.         while (mptr != NULL)
  1875.         {
  1876.             if (mptr->type == M_BASE)
  1877.             {
  1878.                 tptr = ParseMarkTag(mptr->start,
  1879.                     MT_BASE, "HREF");
  1880.                 larray[cnt].href = tptr;
  1881.                 tptr = ParseMarkTag(mptr->start,
  1882.                     MT_BASE, "ROLE");
  1883.                 larray[cnt].role = tptr;
  1884.                 cnt++;
  1885.             }
  1886.             mptr = mptr->next;
  1887.         }
  1888.         return(larray);
  1889.     }
  1890. }
  1891.  
  1892.  
  1893.  
  1894. void *
  1895. HTMLGetWidgetInfo(HTMLGadClData *w)
  1896. {
  1897.     HTMLGadClData * HTML_Data = w;
  1898.  
  1899.     return((void *)HTML_Data->widget_list);
  1900. }
  1901.  
  1902.  
  1903. void
  1904. HTMLFreeImageInfo(Widget w)
  1905. {
  1906.     HTMLGadClData * HTML_Data = (HTMLGadClData *)w;
  1907.  
  1908. //    FreeColors(XtDisplay(w), DefaultColormapOfScreen(XtScreen(w)));
  1909.     FreeImages(HTML_Data);
  1910. }
  1911.  
  1912.  
  1913. void
  1914. HTMLFreeWidgetInfo(void *ptr)
  1915. {
  1916.     WidgetInfo *wptr = (WidgetInfo *)ptr;
  1917.     WidgetInfo *tptr;
  1918.  
  1919.     while (wptr != NULL)
  1920.     {
  1921.         tptr = wptr;
  1922.         wptr = wptr->next;
  1923.         if (tptr->w != NULL)
  1924.         {
  1925. //            XtDestroyWidget(tptr->w);
  1926.         }
  1927.         if (tptr->name != NULL)
  1928.         {
  1929.             free(tptr->name);
  1930.         }
  1931.         if ((tptr->value != NULL)&&(tptr->type != W_OPTIONMENU))
  1932.         {
  1933.             free(tptr->value);
  1934.         }
  1935.         free((char *)tptr);
  1936.     }
  1937. }
  1938.  
  1939.  
  1940. /*
  1941.  * Convenience function to redraw all active anchors in the
  1942.  * document.
  1943.  * Can also pass a new predicate function to check visited
  1944.  * anchors.  If NULL passed for function, uses default predicate
  1945.  * function.
  1946.  */
  1947. void
  1948. HTMLRetestAnchors(Widget w, visitTestProc testFunc)
  1949. {
  1950.     HTMLGadClData * HTML_Data = (HTMLGadClData *)w;
  1951.     struct ele_rec *start;
  1952.  
  1953.     if (testFunc == NULL)
  1954.     {
  1955.         testFunc = (visitTestProc)HTML_Data->previously_visited_test;
  1956.     }
  1957.  
  1958.     /*
  1959.      * Search all elements
  1960.      */
  1961.     start = HTML_Data->formatted_elements;
  1962.     while (start != NULL)
  1963.     {
  1964.         if ((start->internal == True)||
  1965.             (start->anchorHRef == NULL))
  1966.         {
  1967.             start = start->next;
  1968.             continue;
  1969.         }
  1970.  
  1971.         if (testFunc != NULL)
  1972.         {
  1973.             if ((*testFunc)(HTML_Data, start->anchorHRef))
  1974.             {
  1975.                 start->fg = HTML_Data->visitedAnchor_fg;
  1976.                 start->underline_number =
  1977.                 HTML_Data->num_visitedAnchor_underlines;
  1978.                 start->dashed_underline =
  1979.                 HTML_Data->dashed_visitedAnchor_lines;
  1980.             }
  1981.             else
  1982.             {
  1983.                 start->fg = HTML_Data->anchor_fg;
  1984.                 start->underline_number =
  1985.                 HTML_Data->num_anchor_underlines;
  1986.                 start->dashed_underline =
  1987.                 HTML_Data->dashed_anchor_lines;
  1988.             }
  1989.         }
  1990.         else
  1991.         {
  1992.             start->fg = HTML_Data->anchor_fg;
  1993.             start->underline_number =
  1994.                 HTML_Data->num_anchor_underlines;
  1995.             start->dashed_underline =
  1996.                 HTML_Data->dashed_anchor_lines;
  1997.         }
  1998.  
  1999.         /*
  2000.          * Since the element may have changed, redraw it
  2001.          */
  2002.         switch(start->type)
  2003.         {
  2004.             case E_TEXT:
  2005.                 TextRefresh(HTML_Data, start,
  2006.                      0, (start->edata_len - 2));
  2007.                 break;
  2008.             case E_IMAGE:
  2009.                 ImageRefresh(HTML_Data, start);
  2010.                 break;
  2011.             case E_BULLET:
  2012.                 BulletRefresh(HTML_Data, start);
  2013.                 break;
  2014.             case E_LINEFEED:
  2015.                 LinefeedRefresh(HTML_Data, start);
  2016.                 break;
  2017.         }
  2018.  
  2019.         start = start->next;
  2020.     }
  2021. }
  2022.  
  2023.  
  2024. void
  2025. HTMLClearSelection(Widget w)
  2026. {
  2027. //    LoseSelection (w, NULL);
  2028. }
  2029.  
  2030.  
  2031. /*
  2032.  * Convenience function to return the text of the HTML document as a single
  2033.  * white space separated string, with pointers to the various start and
  2034.  * end points of selections.
  2035.  * This function allocates memory for the returned string, that it is up
  2036.  * to the user to free.
  2037.  */
  2038. char *
  2039. HTMLGetTextAndSelection(Widget w, char **startp, char **endp, char **insertp)
  2040. {
  2041.     HTMLGadClData * HTML_Data = (HTMLGadClData *)w;
  2042.     int length;
  2043.     char *text;
  2044.     char *tptr;
  2045.     struct ele_rec *eptr;
  2046.     struct ele_rec *sel_start;
  2047.     struct ele_rec *sel_end;
  2048.     struct ele_rec *insert_start;
  2049.     int start_pos, end_pos, insert_pos;
  2050.  
  2051.     if (SwapElements(HTML_Data->select_start, HTML_Data->select_end,
  2052.         HTML_Data->sel_start_pos, HTML_Data->sel_end_pos))
  2053.     {
  2054.         sel_end = HTML_Data->select_start;
  2055.         end_pos = HTML_Data->sel_start_pos;
  2056.         sel_start = HTML_Data->select_end;
  2057.         start_pos = HTML_Data->sel_end_pos;
  2058.     }
  2059.     else
  2060.     {
  2061.         sel_start = HTML_Data->select_start;
  2062.         start_pos = HTML_Data->sel_start_pos;
  2063.         sel_end = HTML_Data->select_end;
  2064.         end_pos = HTML_Data->sel_end_pos;
  2065.     }
  2066.  
  2067.     insert_start = HTML_Data->new_start;
  2068.     insert_pos = HTML_Data->new_start_pos;
  2069.     *startp = NULL;
  2070.     *endp = NULL;
  2071.     *insertp = NULL;
  2072.  
  2073.     length = 0;
  2074.  
  2075.     eptr = HTML_Data->formatted_elements;
  2076.     while (eptr != NULL)
  2077.     {
  2078.         /*
  2079.          * Skip the special internal text
  2080.          */
  2081.         if (eptr->internal == True)
  2082.         {
  2083.             eptr = eptr->next;
  2084.             continue;
  2085.         }
  2086.  
  2087.         if (eptr->type == E_TEXT)
  2088.         {
  2089.             length = length + eptr->edata_len - 1;
  2090.         }
  2091.         else if (eptr->type == E_LINEFEED)
  2092.         {
  2093.             length = length + 1;
  2094.         }
  2095.         eptr = eptr->next;
  2096.     }
  2097.  
  2098.     text = (char *)malloc(length + 1);
  2099.     if (text == NULL)
  2100.     {
  2101.         fprintf(stderr, "No space for return string\n");
  2102.         return(NULL);
  2103.     }
  2104.     strcpy(text, "");
  2105.  
  2106.     tptr = text;
  2107.  
  2108.     eptr = HTML_Data->formatted_elements;
  2109.     while (eptr != NULL)
  2110.     {
  2111.         /*
  2112.          * Skip the special internal text
  2113.          */
  2114.         if (eptr->internal == True)
  2115.         {
  2116.             eptr = eptr->next;
  2117.             continue;
  2118.         }
  2119.  
  2120.         if (eptr->type == E_TEXT)
  2121.         {
  2122.             if (eptr == sel_start)
  2123.             {
  2124.                 *startp = (char *)(tptr + start_pos);
  2125.             }
  2126.  
  2127.             if (eptr == sel_end)
  2128.             {
  2129.                 *endp = (char *)(tptr + end_pos);
  2130.             }
  2131.  
  2132.             if (eptr == insert_start)
  2133.             {
  2134.                 *insertp = (char *)(tptr + insert_pos);
  2135.             }
  2136.  
  2137.             strcat(text, (char *)eptr->edata);
  2138.             tptr = tptr + eptr->edata_len - 1;
  2139.         }
  2140.         else if (eptr->type == E_LINEFEED)
  2141.         {
  2142.             if (eptr == sel_start)
  2143.             {
  2144.                 *startp = tptr;
  2145.             }
  2146.  
  2147.             if (eptr == sel_end)
  2148.             {
  2149.                 *endp = tptr;
  2150.             }
  2151.  
  2152.             if (eptr == insert_start)
  2153.             {
  2154.                 *insertp = tptr;
  2155.             }
  2156.  
  2157.             strcat(text, " ");
  2158.             tptr = tptr + 1;
  2159.         }
  2160.         eptr = eptr->next;
  2161.     }
  2162.     return(text);
  2163. }
  2164.  
  2165.  
  2166. /*
  2167.  * Convenience function to set the raw text into the widget.
  2168.  * Forces a reparse and a reformat.
  2169.  * If any pointer is passed in as NULL that text is unchanged,
  2170.  * if a pointer points to an empty string, that text is set to NULL;
  2171.  * Also pass an element ID to set the view area to that section of the new
  2172.  * text.  Finally pass an anchor NAME to set position of the new text
  2173.  * to that anchor.
  2174.  */
  2175. void
  2176. HTMLSetText(HTMLGadClData *HTML_Data, char *text, char *header_text, char *footer_text, int element_id, char *target_anchor, void *ptr)
  2177. {
  2178. //    HTMLGadClData *HTML_Data = INST_DATA(HTMLGadClass,HTML_Gad);
  2179.     WidgetInfo *wptr = (WidgetInfo *)ptr;
  2180.     struct ele_rec *start;
  2181.     struct ele_rec *eptr;
  2182.     int newy;
  2183.  
  2184.     if ((text == NULL)&&(header_text == NULL)&&(footer_text == NULL))
  2185.     {
  2186.         return;
  2187.     }
  2188.  
  2189.     /*
  2190.      * Free up the old visited href list.
  2191.      */
  2192.     FreeHRefs(HTML_Data->my_visited_hrefs);
  2193.     HTML_Data->my_visited_hrefs = NULL;
  2194.  
  2195.     /*
  2196.      * Free up the old visited delayed images list.
  2197.      */
  2198.     FreeDelayedImages(HTML_Data->my_delayed_images);
  2199.     HTML_Data->my_delayed_images = NULL;
  2200.  
  2201.     /*
  2202.      * Hide any old widgets
  2203.      */
  2204.  
  2205.     if(!(HTML_Data->object_flags&Object_Reparsing)){
  2206.         HideWidgets(HTML_Data);
  2207.         DisposeForms(HTML_Data->form_list);
  2208.         }
  2209. /*    HTML_Data->widget_list = wptr; */
  2210.     HTML_Data->form_list = NULL;
  2211.  
  2212.     if (text != NULL)
  2213.     {
  2214.         if (*text == '\0')
  2215.         {
  2216.             text = NULL;
  2217.         }
  2218.         HTML_Data->raw_text = text;
  2219.  
  2220.         /*
  2221.          * Free any old colors and pixmaps
  2222.          */
  2223. //        FreeColors(XtDisplay(HTML_Data),DefaultColormapOfScreen(XtScreen(HTML_Data)));
  2224. //        FreeImages(HTML_Data);
  2225.  
  2226.         /*
  2227.          * Parse the raw text with the HTML parser
  2228.          */
  2229.         HTML_Data->html_objects = HTMLParse(HTML_Data->html_objects,
  2230.             HTML_Data->raw_text);
  2231.         CallLinkCallbacks(HTML_Data);
  2232.     }
  2233.     if (header_text != NULL)
  2234.     {
  2235.         if (*header_text == '\0')
  2236.         {
  2237.             header_text = NULL;
  2238.         }
  2239.         HTML_Data->header_text = header_text;
  2240.  
  2241.         /*
  2242.          * Parse the header text with the HTML parser
  2243.          */
  2244.         HTML_Data->html_header_objects =
  2245.             HTMLParse(HTML_Data->html_header_objects,
  2246.             HTML_Data->header_text);
  2247.     }
  2248.     if (footer_text != NULL)
  2249.     {
  2250.         if (*footer_text == '\0')
  2251.         {
  2252.             footer_text = NULL;
  2253.         }
  2254.         HTML_Data->footer_text = footer_text;
  2255.  
  2256.         /*
  2257.          * Parse the footer text with the HTML parser
  2258.          */
  2259.         HTML_Data->html_footer_objects =
  2260.             HTMLParse(HTML_Data->html_footer_objects,
  2261.             HTML_Data->footer_text);
  2262.     }
  2263.  
  2264.     /*
  2265.      * Reformat the new text
  2266.      */
  2267.     if(HTML_Data->win){
  2268.         HTML_Data->max_pre_width = DocumentWidth(HTML_Data, HTML_Data->html_objects);
  2269.         ReformatWindow(HTML_Data);
  2270.         }
  2271.  
  2272.     /*
  2273.      * If a target anchor is passed, override the element id
  2274.      * with the id of that anchor.
  2275.      */
  2276.     if (target_anchor != NULL)
  2277.     {
  2278.         int id;
  2279.  
  2280.         id = HTMLAnchorToId(HTML_Gad, target_anchor);
  2281.         if (id != 0)
  2282.         {
  2283.             element_id = id;
  2284.         }
  2285.     }
  2286.  
  2287.     /*
  2288.      * Position text at id specified, or at top if no position
  2289.      * specified.
  2290.      * Find the element corrsponding to the id passed in.
  2291.      */
  2292.     eptr = NULL;
  2293.     if (element_id != 0)
  2294.     {
  2295.         start = HTML_Data->formatted_elements;
  2296.         while (start != NULL)
  2297.         {
  2298.             if (start->ele_id == element_id)
  2299.             {
  2300.                 eptr = start;
  2301.                 break;
  2302.             }
  2303.             start = start->next;
  2304.         }
  2305.     }
  2306.     if (eptr == NULL)
  2307.     {
  2308.         newy = 0;
  2309.     }
  2310.     else
  2311.     {
  2312.         newy = eptr->y - 2;
  2313.     }
  2314.     if (newy < 0)
  2315.     {
  2316.         newy = 0;
  2317.     }
  2318.     if (newy > (HTML_Data->doc_height - (int)HTML_Data->view_height))
  2319.     {
  2320.         newy = HTML_Data->doc_height - (int)HTML_Data->view_height;
  2321.     }
  2322.     if (newy < 0)
  2323.     {
  2324.         newy = 0;
  2325.     }
  2326.     HTML_Data->scroll_x = 0;
  2327.     HTML_Data->scroll_y = 0;
  2328.     HTML_Data->new_scroll_y = newy;
  2329.  
  2330. #ifdef DEBUG
  2331. fprintf (stderr, "calling in HTMLSetText\n");
  2332. #endif
  2333.  
  2334. //    ConfigScrollBars(HTML_Data);
  2335. //    ScrollWidgets(HTML_Data);
  2336.  
  2337.     /*
  2338.      * Display the new text
  2339.      */
  2340.     AddNewWidgets(HTML_Data);
  2341.  
  2342. /*    MUI_Redraw(HTML_Gad,MADF_DRAWOBJECT); */
  2343.  
  2344.     /*
  2345.      * Clear any previous selection
  2346.      */
  2347.     HTML_Data->select_start = NULL;
  2348.     HTML_Data->select_end = NULL;
  2349.     HTML_Data->sel_start_pos = 0;
  2350.     HTML_Data->sel_end_pos = 0;
  2351.     HTML_Data->new_start = NULL;
  2352.     HTML_Data->new_end = NULL;
  2353.     HTML_Data->new_start_pos = 0;
  2354.     HTML_Data->new_end_pos = 0;
  2355.     HTML_Data->active_anchor = NULL;
  2356.  
  2357.     HTML_Data->cached_tracked_ele = NULL;
  2358. }
  2359.  
  2360.  
  2361. /*
  2362.  * To use faster TOLOWER as set up in HTMLparse.c
  2363.  */
  2364. #ifdef NOT_ASCII
  2365. #define TOLOWER(x)      (tolower(x))
  2366. #else
  2367. extern char map_table[];
  2368. #define TOLOWER(x)      (map_table[x])
  2369. #endif /* NOT_ASCII */
  2370.  
  2371.  
  2372. /*
  2373.  * Convenience function to search the text of the HTML document as a single
  2374.  * white space separated string. Linefeeds are converted into spaces.
  2375.  *
  2376.  * Takes a pattern, pointers to the start and end blocks to store the
  2377.  * start and end of the match into.  Start is also used as the location to
  2378.  * start the search from for incremental searching.  If start is an invalid
  2379.  * position (id = 0).  Default start is the beginning of the document for
  2380.  * forward searching, and the end of the document for backwards searching.
  2381.  * The backward and caseless parameters I hope are self-explanatory.
  2382.  *
  2383.  * returns 1 on success
  2384.  *      (and the start and end positions of the match).
  2385.  * returns -1 otherwise (and start and end are unchanged).
  2386.  */
  2387. int
  2388. HTMLSearchText (HTMLGadClData *HTML_Data, char *pattern, ElementRef *m_start, ElementRef *m_end,
  2389.         int backward, int caseless)
  2390. {
  2391.     int found, equal;
  2392.     char *match;
  2393.     char *tptr;
  2394.     char *mptr;
  2395.     char cval;
  2396.     struct ele_rec *eptr;
  2397.     int s_pos;
  2398.     struct ele_rec *s_eptr;
  2399.     ElementRef s_ref, e_ref;
  2400.     ElementRef *start, *end;
  2401.  
  2402.     /*
  2403.      * If bad parameters are passed, just fail the search
  2404.      */
  2405.     if ((pattern == NULL)||(*pattern == '\0')||
  2406.         (m_start == NULL)||(m_end == NULL))
  2407.     {
  2408.         return(-1);
  2409.     }
  2410.  
  2411.     /*
  2412.      * If we are caseless, make a lower case copy of the pattern to
  2413.      * match to use in compares.
  2414.      *
  2415.      * remember to free this before returning
  2416.      */
  2417.     if (caseless)
  2418.     {
  2419.         match = (char *)malloc(strlen(pattern) + 1);
  2420.         tptr = pattern;
  2421.         mptr = match;
  2422.         while (*tptr != '\0')
  2423.         {
  2424.             *mptr = (char)TOLOWER((int)*tptr);
  2425.             mptr++;
  2426.             tptr++;
  2427.         }
  2428.         *mptr = '\0';
  2429.     }
  2430.     else
  2431.     {
  2432.         match = pattern;
  2433.     }
  2434.  
  2435.     /*
  2436.      * Slimy coding.  I later decided I didn't want to change start and
  2437.      * end if the search failed.  Rather than changing all the code,
  2438.      * I just copy it into locals here, and copy it out again if a match
  2439.      * is found.
  2440.      */
  2441.     start = &s_ref;
  2442.     end = &e_ref;
  2443.     start->id = m_start->id;
  2444.     start->pos = m_start->pos;
  2445.     end->id = m_end->id;
  2446.     end->pos = m_end->pos;
  2447.  
  2448.     /*
  2449.      * Find the user specified start position.
  2450.      */
  2451.     if (start->id > 0)
  2452.     {
  2453.         found = 0;
  2454.         eptr = HTML_Data->formatted_elements;
  2455.  
  2456.         while (eptr != NULL)
  2457.         {
  2458.             if (eptr->ele_id == start->id)
  2459.             {
  2460.                 s_eptr = eptr;
  2461.                 found = 1;
  2462.                 break;
  2463.             }
  2464.             eptr = eptr->next;
  2465.         }
  2466.         /*
  2467.          * Bad start position, fail them out.
  2468.          */
  2469.         if (!found)
  2470.         {
  2471.             if (caseless)
  2472.             {
  2473.                 free(match);
  2474.             }
  2475.             return(-1);
  2476.         }
  2477.         /*
  2478.          * Sanify the start position
  2479.          */
  2480.         s_pos = start->pos;
  2481.         if (s_pos >= s_eptr->edata_len - 1)
  2482.         {
  2483.             s_pos = s_eptr->edata_len - 2;
  2484.         }
  2485.         if (s_pos < 0)
  2486.         {
  2487.             s_pos = 0;
  2488.         }
  2489.     }
  2490.     else
  2491.     {
  2492.         /*
  2493.          * Default search starts at end for backward, and
  2494.          * beginning for forwards.
  2495.          */
  2496.         if (backward)
  2497.         {
  2498.             s_eptr = HTML_Data->formatted_elements;
  2499.             while (s_eptr->next != NULL)
  2500.             {
  2501.                 s_eptr = s_eptr->next;
  2502.             }
  2503.             s_pos = s_eptr->edata_len - 2;
  2504.         }
  2505.         else
  2506.         {
  2507.             s_eptr = HTML_Data->formatted_elements;
  2508.             s_pos = 0;
  2509.         }
  2510.     }
  2511.  
  2512.     if (backward)
  2513.     {
  2514.         char *mend;
  2515.  
  2516.         /*
  2517.          * Save the end of match here for easy end to start searching
  2518.          */
  2519.         mend = match;
  2520.         while (*mend != '\0')
  2521.         {
  2522.             mend++;
  2523.         }
  2524.         if (mend > match)
  2525.         {
  2526.             mend--;
  2527.         }
  2528.         found = 0;
  2529.         equal = 0;
  2530.         mptr = mend;
  2531.  
  2532.         if (s_eptr != NULL)
  2533.         {
  2534.             eptr = s_eptr;
  2535.         }
  2536.         else
  2537.         {
  2538.             eptr = HTML_Data->formatted_elements;
  2539.             while (eptr->next != NULL)
  2540.             {
  2541.                 eptr = eptr->next;
  2542.             }
  2543.         }
  2544.  
  2545.         while (eptr != NULL)
  2546.         {
  2547.             /*
  2548.              * Skip the special internal text
  2549.              */
  2550.             if (eptr->internal == True)
  2551.             {
  2552.                 eptr = eptr->prev;
  2553.                 continue;
  2554.             }
  2555.  
  2556.             if (eptr->type == E_TEXT)
  2557.             {
  2558.                 tptr = (char *)(eptr->edata + eptr->edata_len - 2);
  2559.                 if (eptr == s_eptr)
  2560.                 {
  2561.                 tptr = (char *)(eptr->edata + s_pos);
  2562.                 }
  2563.                 while (tptr >= eptr->edata)
  2564.                 {
  2565.                 if (equal)
  2566.                 {
  2567.                     if (caseless)
  2568.                     {
  2569.                         cval =(char)TOLOWER((int)*tptr);
  2570.                     }
  2571.                     else
  2572.                     {
  2573.                         cval = *tptr;
  2574.                     }
  2575.                     while ((mptr >= match)&&
  2576.                         (tptr >= eptr->edata)&&
  2577.                         (cval == *mptr))
  2578.                     {
  2579.                         tptr--;
  2580.                         mptr--;
  2581.                         if (tptr >= eptr->edata)
  2582.                         {
  2583.                         if (caseless)
  2584.                         {
  2585.                         cval =(char)TOLOWER((int)*tptr);
  2586.                         }
  2587.                         else
  2588.                         {
  2589.                             cval = *tptr;
  2590.                         }
  2591.                         }
  2592.                     }
  2593.                     if (mptr < match)
  2594.                     {
  2595.                         found = 1;
  2596.                         start->id = eptr->ele_id;
  2597.                         start->pos = (int)
  2598.                             (tptr - eptr->edata + 1);
  2599.                         break;
  2600.                     }
  2601.                     else if (tptr < eptr->edata)
  2602.                     {
  2603.                         break;
  2604.                     }
  2605.                     else
  2606.                     {
  2607.                         equal = 0;
  2608.                     }
  2609.                 }
  2610.                 else
  2611.                 {
  2612.                     mptr = mend;
  2613.                     if (caseless)
  2614.                     {
  2615.                         cval =(char)TOLOWER((int)*tptr);
  2616.                     }
  2617.                     else
  2618.                     {
  2619.                         cval = *tptr;
  2620.                     }
  2621.                     while ((tptr >= eptr->edata)&&
  2622.                         (cval != *mptr))
  2623.                     {
  2624.                         tptr--;
  2625.                         if (tptr >= eptr->edata)
  2626.                         {
  2627.                         if (caseless)
  2628.                         {
  2629.                         cval =(char)TOLOWER((int)*tptr);
  2630.                         }
  2631.                         else
  2632.                         {
  2633.                             cval = *tptr;
  2634.                         }
  2635.                         }
  2636.                     }
  2637.                     if ((tptr >= eptr->edata)&&
  2638.                         (cval == *mptr))
  2639.                     {
  2640.                         equal = 1;
  2641.                         end->id = eptr->ele_id;
  2642.                         end->pos = (int)
  2643.                             (tptr - eptr->edata + 1);
  2644.                     }
  2645.                 }
  2646.                 }
  2647.             }
  2648.             /*
  2649.              * Linefeeds match to single space characters.
  2650.              */
  2651.             else if (eptr->type == E_LINEFEED)
  2652.             {
  2653.                 if (equal)
  2654.                 {
  2655.                     if (*mptr == ' ')
  2656.                     {
  2657.                         mptr--;
  2658.                         if (mptr < match)
  2659.                         {
  2660.                             found = 1;
  2661.                             start->id =eptr->ele_id;
  2662.                             start->pos = 0;
  2663.                         }
  2664.                     }
  2665.                     else
  2666.                     {
  2667.                         equal = 0;
  2668.                     }
  2669.                 }
  2670.                 else
  2671.                 {
  2672.                     mptr = mend;
  2673.                     if (*mptr == ' ')
  2674.                     {
  2675.                         equal = 1;
  2676.                         end->id = eptr->ele_id;
  2677.                         end->pos = 0;
  2678.                         mptr--;
  2679.                         if (mptr < match)
  2680.                         {
  2681.                             found = 1;
  2682.                             start->id =eptr->ele_id;
  2683.                             start->pos = 0;
  2684.                         }
  2685.                     }
  2686.                 }
  2687.             }
  2688.             if (found)
  2689.             {
  2690.                 break;
  2691.             }
  2692.             eptr = eptr->prev;
  2693.         }
  2694.     }
  2695.     else /* forward */
  2696.     {
  2697.         found = 0;
  2698.         equal = 0;
  2699.         mptr = match;
  2700.  
  2701.         if (s_eptr != NULL)
  2702.         {
  2703.             eptr = s_eptr;
  2704.         }
  2705.         else
  2706.         {
  2707.             eptr = HTML_Data->formatted_elements;
  2708.         }
  2709.  
  2710.         while (eptr != NULL)
  2711.         {
  2712.             /*
  2713.              * Skip the special internal text
  2714.              */
  2715.             if (eptr->internal == True)
  2716.             {
  2717.                 eptr = eptr->next;
  2718.                 continue;
  2719.             }
  2720.  
  2721.             if (eptr->type == E_TEXT)
  2722.             {
  2723.                 tptr = eptr->edata;
  2724.                 if (eptr == s_eptr)
  2725.                 {
  2726.                 tptr = (char *)(tptr + s_pos);
  2727.                 }
  2728.                 while (*tptr != '\0')
  2729.                 {
  2730.                 if (equal)
  2731.                 {
  2732.                     if (caseless)
  2733.                     {
  2734.                         cval =(char)TOLOWER((int)*tptr);
  2735.                     }
  2736.                     else
  2737.                     {
  2738.                         cval = *tptr;
  2739.                     }
  2740.                     while ((*mptr != '\0')&&
  2741.                         (cval == *mptr))
  2742.                     {
  2743.                         tptr++;
  2744.                         mptr++;
  2745.                         if (caseless)
  2746.                         {
  2747.                         cval =(char)TOLOWER((int)*tptr);
  2748.                         }
  2749.                         else
  2750.                         {
  2751.                             cval = *tptr;
  2752.                         }
  2753.                     }
  2754.                     if (*mptr == '\0')
  2755.                     {
  2756.                         found = 1;
  2757.                         end->id = eptr->ele_id;
  2758.                         end->pos = (int)
  2759.                             (tptr - eptr->edata);
  2760.                         break;
  2761.                     }
  2762.                     else if (*tptr == '\0')
  2763.                     {
  2764.                         break;
  2765.                     }
  2766.                     else
  2767.                     {
  2768.                         equal = 0;
  2769.                     }
  2770.                 }
  2771.                 else
  2772.                 {
  2773.                     mptr = match;
  2774.                     if (caseless)
  2775.                     {
  2776.                         cval =(char)TOLOWER((int)*tptr);
  2777.                     }
  2778.                     else
  2779.                     {
  2780.                         cval = *tptr;
  2781.                     }
  2782.                     while ((*tptr != '\0')&&
  2783.                         (cval != *mptr))
  2784.                     {
  2785.                         tptr++;
  2786.                         if (caseless)
  2787.                         {
  2788.                         cval =(char)TOLOWER((int)*tptr);
  2789.                         }
  2790.                         else
  2791.                         {
  2792.                             cval = *tptr;
  2793.                         }
  2794.                     }
  2795.                     if (cval == *mptr)
  2796.                     {
  2797.                         equal = 1;
  2798.                         start->id = eptr->ele_id;
  2799.                         start->pos = (int)
  2800.                             (tptr - eptr->edata);
  2801.                     }
  2802.                 }
  2803.                 }
  2804.             }
  2805.             else if (eptr->type == E_LINEFEED)
  2806.             {
  2807.                 if (equal)
  2808.                 {
  2809.                     if (*mptr == ' ')
  2810.                     {
  2811.                         mptr++;
  2812.                         if (*mptr == '\0')
  2813.                         {
  2814.                             found = 1;
  2815.                             end->id = eptr->ele_id;
  2816.                             end->pos = 0;
  2817.                         }
  2818.                     }
  2819.                     else
  2820.                     {
  2821.                         equal = 0;
  2822.                     }
  2823.                 }
  2824.                 else
  2825.                 {
  2826.                     mptr = match;
  2827.                     if (*mptr == ' ')
  2828.                     {
  2829.                         equal = 1;
  2830.                         start->id = eptr->ele_id;
  2831.                         start->pos = 0;
  2832.                         mptr++;
  2833.                         if (*mptr == '\0')
  2834.                         {
  2835.                             found = 1;
  2836.                             end->id = eptr->ele_id;
  2837.                             end->pos = 0;
  2838.                         }
  2839.                     }
  2840.                 }
  2841.             }
  2842.             if (found)
  2843.             {
  2844.                 break;
  2845.             }
  2846.             eptr = eptr->next;
  2847.         }
  2848.     }
  2849.  
  2850.     if (found)
  2851.     {
  2852.         m_start->id = start->id;
  2853.         m_start->pos = start->pos;
  2854.         m_end->id = end->id;
  2855.         m_end->pos = end->pos;
  2856.     }
  2857.  
  2858.     if (caseless)
  2859.     {
  2860.         free(match);
  2861.     }
  2862.  
  2863.     if (found)
  2864.     {
  2865.         return(1);
  2866.     }
  2867.     else
  2868.     {
  2869.         return(-1);
  2870.     }
  2871. }
  2872.  
  2873.