earlybrowserreborn - Blame information for rev 3

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 roytam 1 /*==================================================================*/
2 /*                                                                  */
3 /* SGMLHyperWidget                                                  */
4 /*                                                                  */
5 /* B.Raoult (mab@ecmwf.co.uk)                              Oct.91   */
6 /* T.Johnson - added SGML facilities                      June.92   */
7 /*             (Tony Johnson)                                       */
8 /*                                                                  */
9 /* Hyper text like widget.                                          */
10 /*                                                                  */
11 /*==================================================================*/
12  
13 #include <stdio.h>
14 #include <errno.h>
15 #include <ctype.h>
16 #include <string.h>
17 #include <X11/IntrinsicP.h>
18 #include <X11/StringDefs.h>
19 #include <X11/CoreP.h>
20 #include <X11/cursorfont.h>
21 #include <Xm/Xm.h>
22 #include <Xm/ScrolledW.h>
23 #include <X11/Xatom.h>
24  
25 #ifdef VMS
26 #include <Xmu/Atoms.h>
27 #ifdef UCX
28 #define bcopy(a, b, c) (void) memmove ((void *) (b), (void *) (a), (size_t) (c))
29 #endif
30 #else
31 #include <X11/Xmu/Atoms.h>
32 #endif
33  
34 #include "SGMLText.h"
35 #include "SGMLPlainText.h"
36 #include "SGMLFormattedText.h"
37 #include "SGMLFormText.h"
38 #include "SGMLCaptionText.h"
39 #include "SGMLTableText.h"
40 #include "SGMLCompositeText.h"
41 #include "SGMLContainerTextP.h"
42 #include "SGMLAnchorText.h"
43 #include "SGMLMarkerText.h"
44 #include "SGMLRuleText.h"
45 #include "SGMLInputText.h"
46 #include "SGMLListText.h"
47 #include "SGMLHyperP.h"
48  
49 #ifndef ABS
50 #define ABS(a)           ((a)>=0?(a):-(a))
51 #endif
52 #ifndef MIN
53 #define MIN(a,b)         ((a)>(b)?(b):(a))
54 #endif
55 #define MAX_LINE_SIZE    1024
56  
57 /*      Entity Names
58 **      ------------
59 **
60 **      This table must be matched exactly the table below
61 */
62 static char* entities[] = {
63   "AElig",      /* capital AE diphthong (ligature) */
64   "Aacute",     /* capital A, acute accent */
65   "Acirc",      /* capital A, circumflex accent */
66   "Agrave",     /* capital A, grave accent */
67   "Aring",      /* capital A, ring */
68   "Atilde",     /* capital A, tilde */
69   "Auml",       /* capital A, dieresis or umlaut mark */
70   "Ccedil",     /* capital C, cedilla */
71   "ETH",        /* capital Eth, Icelandic */
72   "Eacute",     /* capital E, acute accent */
73   "Ecirc",      /* capital E, circumflex accent */
74   "Egrave",     /* capital E, grave accent */
75   "Euml",       /* capital E, dieresis or umlaut mark */
76   "Iacute",     /* capital I, acute accent */
77   "Icirc",      /* capital I, circumflex accent */
78   "Igrave",     /* capital I, grave accent */
79   "Iuml",       /* capital I, dieresis or umlaut mark */
80   "Ntilde",     /* capital N, tilde */
81   "Oacute",     /* capital O, acute accent */
82   "Ocirc",      /* capital O, circumflex accent */
83   "Ograve",     /* capital O, grave accent */
84   "Oslash",     /* capital O, slash */
85   "Otilde",     /* capital O, tilde */
86   "Ouml",       /* capital O, dieresis or umlaut mark */
87   "THORN",      /* capital THORN, Icelandic */
88   "Uacute",     /* capital U, acute accent */
89   "Ucirc",      /* capital U, circumflex accent */
90   "Ugrave",     /* capital U, grave accent */
91   "Uuml",       /* capital U, dieresis or umlaut mark */
92   "Yacute",     /* capital Y, acute accent */
93   "aacute",     /* small a, acute accent */
94   "acirc",      /* small a, circumflex accent */
95   "aelig",      /* small ae diphthong (ligature) */
96   "agrave",     /* small a, grave accent */
97   "amp",        /* ampersand */
98   "aring",      /* small a, ring */
99   "atilde",     /* small a, tilde */
100   "auml",       /* small a, dieresis or umlaut mark */
101   "ccedil",     /* small c, cedilla */
102   "eacute",     /* small e, acute accent */
103   "ecirc",      /* small e, circumflex accent */
104   "egrave",     /* small e, grave accent */
105   "eth",        /* small eth, Icelandic */
106   "euml",       /* small e, dieresis or umlaut mark */
107   "gt",         /* greater than */
108   "iacute",     /* small i, acute accent */
109   "icirc",      /* small i, circumflex accent */
110   "igrave",     /* small i, grave accent */
111   "iuml",       /* small i, dieresis or umlaut mark */
112   "lt",         /* less than */
113   "ntilde",     /* small n, tilde */
114   "oacute",     /* small o, acute accent */
115   "ocirc",      /* small o, circumflex accent */
116   "ograve",     /* small o, grave accent */
117   "oslash",     /* small o, slash */
118   "otilde",     /* small o, tilde */
119   "ouml",       /* small o, dieresis or umlaut mark */
120   "szlig",      /* small sharp s, German (sz ligature) */
121   "thorn",      /* small thorn, Icelandic */
122   "uacute",     /* small u, acute accent */
123   "ucirc",      /* small u, circumflex accent */
124   "ugrave",     /* small u, grave accent */
125   "uuml",       /* small u, dieresis or umlaut mark */
126   "yacute",     /* small y, acute accent */
127   "yuml",       /* small y, dieresis or umlaut mark */
128 };
129 /*      Entity values -- for ISO Latin 1 local representation
130 **
131 **      This MUST match exactly the table above!
132 */
133 static int ISO_Latin1[] = {
134         0306,   /* capital AE diphthong (ligature) */
135         0301,   /* capital A, acute accent */
136         0302,   /* capital A, circumflex accent */
137         0300,   /* capital A, grave accent */
138         0305,   /* capital A, ring */
139         0303,   /* capital A, tilde */
140         0304,   /* capital A, dieresis or umlaut mark */
141         0307,   /* capital C, cedilla */
142         0320,   /* capital Eth, Icelandic */
143         0311,   /* capital E, acute accent */
144         0312,   /* capital E, circumflex accent */
145         0310,   /* capital E, grave accent */
146         0313,   /* capital E, dieresis or umlaut mark */
147         0315,   /* capital I, acute accent */
148         0316,   /* capital I, circumflex accent */
149         0314,   /* capital I, grave accent */
150         0317,   /* capital I, dieresis or umlaut mark */
151         0321,   /* capital N, tilde */
152         0323,   /* capital O, acute accent */
153         0324,   /* capital O, circumflex accent */
154         0322,   /* capital O, grave accent */
155         0330,   /* capital O, slash */
156         0325,   /* capital O, tilde */
157         0326,   /* capital O, dieresis or umlaut mark */
158         0336,   /* capital THORN, Icelandic */
159         0332,   /* capital U, acute accent */
160         0333,   /* capital U, circumflex accent */
161         0331,   /* capital U, grave accent */
162         0334,   /* capital U, dieresis or umlaut mark */
163         0335,   /* capital Y, acute accent */
164         0341,   /* small a, acute accent */
165         0342,   /* small a, circumflex accent */
166         0346,   /* small ae diphthong (ligature) */
167         0340,   /* small a, grave accent */
168         0046,   /* ampersand */
169         0345,   /* small a, ring */
170         0343,   /* small a, tilde */
171         0344,   /* small a, dieresis or umlaut mark */
172         0347,   /* small c, cedilla */
173         0351,   /* small e, acute accent */
174         0352,   /* small e, circumflex accent */
175         0350,   /* small e, grave accent */
176         0360,   /* small eth, Icelandic */
177         0353,   /* small e, dieresis or umlaut mark */
178         0076,   /* greater than */
179         0355,   /* small i, acute accent */
180         0356,   /* small i, circumflex accent */
181         0354,   /* small i, grave accent */
182         0357,   /* small i, dieresis or umlaut mark */
183         0074,   /* less than */
184         0361,   /* small n, tilde */
185         0363,   /* small o, acute accent */
186         0364,   /* small o, circumflex accent */
187         0362,   /* small o, grave accent */
188         0370,   /* small o, slash */
189         0365,   /* small o, tilde */
190         0366,   /* small o, dieresis or umlaut mark */
191         0337,   /* small sharp s, German (sz ligature) */
192         0376,   /* small thorn, Icelandic */
193         0372,   /* small u, acute accent */
194         0373,   /* small u, circumflex accent */
195         0371,   /* small u, grave accent */
196         0374,   /* small u, dieresis or umlaut mark */
197         0375,   /* small y, acute accent */
198         0377,   /* small y, dieresis or umlaut mark */
199 };
200  
201 #define SGML_ENTITIES 65
202 /*
203   Private functions
204 */
205  
206 static void    create_gcs();
207 static void    selectt();
208 static void    cursor();
209 static void    activate();
210 static Widget  add_to_text();
211 static void    set_tag();
212 static void    calc_new_size ();
213 static void    show_selection();
214 static void    lowcase();
215 static void    SelectWord();
216 static void    SelectLine();
217 static void    SelectRegion();
218 static void    SelectAll();
219 static void    SelectStart();
220 static void    SelectExtend();
221 static void    SelectEnd();
222 static Boolean Convert();
223 static void    LoseOwnership();
224 static void    SelectionDone();
225 static Boolean GetSelection();
226 static void    _OwnSelection();
227  
228 static int              NumberOfClasses = 0;
229 static WidgetClass     *ClassList = NULL;
230 static XrmName          NullQuark;
231  
232 /*
233   Widget class methods
234 */
235  
236 static void    DeleteChild();
237 static void    InsertChild();
238 static void    ClassInitialize();
239 static void    Initialize();
240 static void    Redisplay();
241 static void    Resize();
242 static void    Destroy();
243 static Boolean SetValues();
244 static XtGeometryResult GeometryManager();
245  
246 static XrmName dl_quark;
247 static XrmName dlc_quark;
248  
249 static char defaultTranslations[] =
250 "!<Btn1Down>: selectstart()          \n\
251 !<Btn1Motion>: selectextend()       \n\
252 !<Btn1Up>: selectend(PRIMARY, CUT_BUFFER0)              \n\
253 !Ctrl <Btn3Up>: selectall(PRIMARY, CUT_BUFFER0)         \n\
254 <Motion>:cursor()                   ";
255  
256 static XtActionsRec actionsList[] = {
257     { "selectstart",   (XtActionProc) SelectStart},
258     { "selectextend",  (XtActionProc) SelectExtend},
259     { "selectend",  (XtActionProc) SelectEnd},
260     { "selectall",  (XtActionProc) SelectAll},
261     { "cursor",   (XtActionProc) cursor},
262 };
263  
264 #define Offset(field) XtOffsetOf(SGMLHyperRec, sgml_hyper.field)
265  
266 static XtResource resources[] = {
267  
268     {SGMLNactivateCallback,SGMLCCallback,XtRCallback,sizeof(caddr_t),
269     Offset (activate),XtRCallback,NULL},
270  
271     {SGMLNcaseSensitiveTags,SGMLCCaseSensitiveTags,XtRBoolean,sizeof(Boolean),
272     Offset (case_sensitive_tags),XtRImmediate,(XtPointer)FALSE},
273  
274     {SGMLNcacheSize,SGMLCCacheSize,XtRInt,sizeof(int),
275     Offset (cache_size),XtRImmediate,(XtPointer)0},
276  
277     {SGMLNopenTag,SGMLCTagChar,XtRUnsignedChar,sizeof(unsigned char),
278     Offset(open_tag),XtRImmediate,(XtPointer)'<'},
279  
280     {SGMLNcloseTag,SGMLCTagChar,XtRUnsignedChar,sizeof(unsigned char),
281     Offset(close_tag),XtRImmediate,(XtPointer)'>'},
282  
283     {SGMLNendTag,SGMLCTagChar,XtRUnsignedChar,sizeof(unsigned char),
284     Offset(end_tag),XtRImmediate,(XtPointer)'/'},
285  
286     {SGMLNparameterTag,SGMLCTagChar,XtRUnsignedChar,sizeof(unsigned char),
287     Offset(parameter_tag),XtRImmediate,(XtPointer)' '},
288  
289     {SGMLNentityTag,SGMLCTagChar,XtRUnsignedChar,sizeof(unsigned char),
290     Offset(entity_tag),XtRImmediate,(XtPointer)'&'},
291  
292     {SGMLNentityEndTag,SGMLCTagChar,XtRUnsignedChar,sizeof(unsigned char),
293     Offset(entity_end_tag),XtRImmediate,(XtPointer)';'},
294  
295     {SGMLNmargin,SGMLCMargin,XtRDimension,sizeof(Dimension),
296     Offset (margin),XtRImmediate,(XtPointer)10},
297  
298     {SGMLNnaturalWidth,SGMLCWidth,XtRDimension,sizeof(Dimension),
299     Offset (natural_width),XtRImmediate,(XtPointer)500},
300 };
301  
302 #undef Offset
303  
304 /* stack pointer */
305  
306 static int sp = 0;
307  
308 /*---------------------------------------------------------------*/
309 /* Static initialisation of the class record                     */
310 /*---------------------------------------------------------------*/
311  
312 static CompositeClassExtensionRec compositeExtension = {
313     NULL,                                 /* next_extension   */
314     NULLQUARK,                            /* record_type      */
315     XtCompositeExtensionVersion,          /* version          */
316     sizeof(CompositeClassExtensionRec),   /* record_size      */
317     TRUE                                  /* accepts_objects  */  
318 };
319  
320 SGMLHyperClassRec  sGMLHyperClassRec = {
321     {
322 #ifdef MOTIF
323     (WidgetClass) &xmManagerClassRec,    /* superclass            */
324 #else
325     (WidgetClass) &compositeClassRec,    /* superclass            */
326 #endif
327     "SGMLHyper",                         /* class_name            */
328     sizeof(SGMLHyperRec),                /* widget_size           */
329     ClassInitialize,                     /* class_initialize      */
330     NULL,                                /* class_part_initialize */
331     FALSE,                               /* class_inited          */
332     Initialize,                          /* initialize            */
333     NULL,                                /* initialize_hook       */
334     XtInheritRealize,                    /* realize               */
335     actionsList,                         /* actions               */
336     XtNumber(actionsList),               /* num_actions           */
337     resources,                           /* resources             */
338     XtNumber(resources),                 /* num_resources         */
339     NULLQUARK,                           /* xrm_class             */
340     TRUE,                                /* compress_motion       */
341     TRUE,                                /* compress_exposure     */
342     TRUE,                                /* compress_enterleave   */
343     TRUE,                                /* visible_interest      */
344     Destroy,                             /* destroy               */
345     Resize,                              /* resize                */
346     Redisplay,                           /* expose                */
347     SetValues,                           /* set_values            */
348     NULL,                                /* set_values_hook       */
349     XtInheritSetValuesAlmost,            /* set_values_almost     */
350     NULL,                                /* get_values_hook       */
351     NULL,                                /* accept_focus          */
352     XtVersion,                           /* version               */
353     NULL,                                /* callback private      */
354     defaultTranslations,                 /* tm_table              */
355     NULL,                                /* query_geometry        */
356     NULL,                                /* display_accelerator   */
357     NULL,                                /* extension             */
358     },
359     {
360     GeometryManager,                     /* geometry manager      */
361     NULL,                                /* change_managed        */
362     InsertChild,                         /* insert_child          */
363     DeleteChild,                         /* delete_child          */
364     (XtPointer) &compositeExtension      /* extension             */
365     },
366 #ifdef MOTIF
367    {            /* constraint_class fields */
368       NULL,                                     /* resource list        */  
369       0,                                        /* num resources        */  
370       0,                                        /* constraint size      */  
371       NULL,                                     /* init proc            */  
372       NULL,                                     /* destroy proc         */  
373       NULL,                                     /* set values proc      */  
374       NULL,                                     /* extension            */
375    },    
376  
377    {
378     XtInheritTranslations,                /* translations                  */
379     NULL,                                 /* syn_resources                 */
380     0,                                    /* num_syn_resources             */
381     NULL,                                 /* syn_constraint_resources      */
382     0,                                    /* num_syn_constraint_resources  */
383     NULL,                                 /* parent_process                */
384     NULL,                                 /* extension                     */
385     },
386 #endif
387     {
388     0,                                    /* ignore                */
389     }
390 };
391  
392 static int EntityToIsoLatin1(entity)
393 char *entity;
394 {
395   int high, low, i, diff;
396  
397   for (low = 0, high = SGML_ENTITIES ; high > low ;
398        diff < 0 ? (low = i+1) : (high = i))     /* Binary search */
399     {
400         i = (low + (high-low)/2);
401         diff = strcmp(entities[i], entity);     /* Case sensitive! */
402         if (diff==0) {                          /* success: found it */
403             return ISO_Latin1[i];
404         }
405     }
406   return '\0';
407 }
408 static Boolean IsSubClass(sub,class)
409 WidgetClass sub, class;
410 {
411   for (; sub != NULL; sub = sub->core_class.superclass)
412     if (sub == class) return TRUE;
413  
414   return FALSE;
415 }
416  
417 WidgetClass sGMLHyperWidgetClass = (WidgetClass) &sGMLHyperClassRec;
418  
419  
420 static void CvtStringToClass (args, num_args, fromVal, toVal)
421     XrmValuePtr args;
422     Cardinal    *num_args;
423     XrmValuePtr fromVal;
424     XrmValuePtr toVal;
425 {
426     char *s;
427     int p;
428  
429     if (*num_args != 0)
430         XtWarningMsg("wrongParameters","cvtStringToClass","XtToolkitError",
431                   "String to Class conversion needs no extra arguments",
432                   (String *) NULL, (Cardinal *)NULL);
433  
434     s = (char *) fromVal->addr;
435  
436     for (p=0; p<NumberOfClasses; p++)
437       if (!strcmp(s,ClassList[p]->core_class.class_name))
438         {
439           toVal->size = sizeof(WidgetClass);
440           toVal->addr = (XtPointer) &ClassList[p];
441           return;
442         }    
443     XtStringConversionWarning((char *) fromVal->addr, SGMLRClass);
444 }
445 static void CvtStringToTagList (args, num_args, fromVal, toVal)
446     XrmValuePtr args;
447     Cardinal    *num_args;
448     XrmValuePtr fromVal;
449     XrmValuePtr toVal;
450 {
451     int polarity;
452     char *s, *t, *p;
453     WidgetClass current_class = NULL;
454  
455     Cardinal num_slots = 10;
456     Cardinal num_used = 0;
457     static SGMLTagList *list;
458  
459     list = (SGMLTagList *) XtMalloc(sizeof(SGMLTagList) * num_slots);
460  
461     if (*num_args != 0)
462         XtWarningMsg("wrongParameters","cvtStringToTagList","XtToolkitError",
463                   "String to Tag List conversion needs no extra arguments",
464                   (String *) NULL, (Cardinal *)NULL);
465  
466     s = XtNewString((char *) fromVal->addr);
467  
468     t = strtok(s," \t");
469     if (t && !strcmp(t,"*"))
470       {
471         polarity = 1;        
472         t = strtok(NULL," \t");
473       }
474     else polarity = 0;  
475  
476     for (; t != NULL; t = strtok(NULL," \t"))
477       {
478         if ((p = strchr(t,':')) == NULL)
479           {
480             XrmName tag;
481             int sign = 1, match = 1;
482  
483             if      (*t == '+') { sign =  1; t++; }
484             else if (*t == '-') { sign = -1; t++; }
485  
486             if      (*t == '%') { match = 0; t++; }
487  
488             tag = XrmStringToQuark(t);
489             if (num_used == num_slots)
490               list = (SGMLTagList *) XtRealloc((XtPointer) list, sizeof(SGMLTagList) * (num_slots *= 2));
491  
492             list[num_used].name = tag;
493             list[num_used].class = current_class;  
494             list[num_used].polarity = polarity * sign;
495             list[num_used].matched = match;
496             num_used++;
497           }
498         else  
499           {
500              int i;
501  
502              *p = '\0';
503              current_class = NULL;
504  
505              for (i=0; i<NumberOfClasses; i++)
506                if (!strcmp(t,ClassList[i]->core_class.class_name))
507                  current_class = ClassList[i];
508  
509              if (current_class == NULL)
510                XtStringConversionWarning(t, SGMLRClass);
511           }
512       }
513     if (num_used == num_slots)
514        list = (SGMLTagList *) XtRealloc((XtPointer) list, sizeof(SGMLTagList) * (++num_slots));
515  
516     list[num_used].name = 0;
517     list[num_used].class = NULL;
518     list[num_used].polarity = 0;  
519     num_used++;
520     toVal->addr = (XtPointer) &list;
521     toVal->size = sizeof(XtPointer);
522  
523     XtFree(s);
524 }
525  
526 static Boolean ConvertStringToString(display,args,nargs,from,to,converter_data)
527     Display    *display;
528     XrmValue   *args;
529     Cardinal   *nargs;
530     XrmValue   *from;
531     XrmValue   *to;
532     XtPointer  *converter_data;
533 {
534     int size = sizeof(from->addr);
535     if (to->addr == 0)
536       {
537          to->addr = (XtPointer) &from->addr;
538          to->size = size;
539          return TRUE;
540       }
541     else if  (to->size >= size)
542       {
543          memcpy(to->addr,&from->addr,size);
544          to->size = size;
545          return TRUE;
546       }
547     else
548       {
549          to->size = size;
550          return FALSE;
551       }
552 }
553  
554 /*--------------------------------------------------------------*/
555 /* ClassInitialize: Register the standard text classes          */
556 /*--------------------------------------------------------------*/
557 static void ClassInitialize()
558 {
559     XtAddConverter (XtRString, SGMLRTagList, CvtStringToTagList,
560                        (XtConvertArgList) NULL, (Cardinal) 0);
561  
562     XtAddConverter (XtRString, SGMLRClass, CvtStringToClass,
563                         (XtConvertArgList) NULL, (Cardinal) 0);
564  
565 /*
566  *  Intrinsics bug ... trys to convert STRING to STRING
567  */
568  
569    XtSetTypeConverter(XtRString,XtRString,ConvertStringToString,
570                       NULL,0,XtCacheNone,NULL);
571  
572  
573    SGMLHyperDeclareClass(sGMLTextObjectClass);
574    SGMLHyperDeclareClass(sGMLPlainTextObjectClass);
575    SGMLHyperDeclareClass(sGMLFormattedTextObjectClass);
576    SGMLHyperDeclareClass(sGMLFormTextObjectClass);
577    SGMLHyperDeclareClass(sGMLAnchorTextObjectClass);
578    SGMLHyperDeclareClass(sGMLMarkerTextObjectClass);
579    SGMLHyperDeclareClass(sGMLRuleTextObjectClass);
580    SGMLHyperDeclareClass(sGMLCompositeTextObjectClass);
581    SGMLHyperDeclareClass(sGMLInputTextObjectClass);
582    SGMLHyperDeclareClass(sGMLListTextObjectClass);
583    SGMLHyperDeclareClass(sGMLCaptionTextObjectClass);
584    SGMLHyperDeclareClass(sGMLTableTextObjectClass);
585  
586    NullQuark = XrmStringToQuark(NULL);
587    dlc_quark = XrmStringToQuark("dl_compact");
588    dl_quark  = XrmStringToQuark("dl");
589 }
590  
591 /*--------------------------------------------------------------*/
592 /* Initialize:                                                  */
593 /*--------------------------------------------------------------*/
594  
595 static void Initialize (request, new)
596 SGMLHyperWidget request, new;
597 {
598     Arg arglist[10];
599     int n = 0;
600  
601     /* Check the size of the widget */
602  
603     if (request->core.width  == 0) new->core.width = 100;
604     if (request->core.height == 0) new->core.height = 100;
605  
606     new->sgml_hyper.hand = XCreateFontCursor(XtDisplay(new),XC_hand2);
607  
608     new->sgml_hyper.grep_txt = NULL;
609     new->sgml_hyper.grep_len = 0;
610     new->sgml_hyper.grep_off = 0;
611  
612     new->sgml_hyper.managed = NULL;
613     new->sgml_hyper.search_widget = NULL;
614     new->sgml_hyper.sw_flag = NULL;
615     new->sgml_hyper.contains = NULL;
616     new->sgml_hyper.contain_slots = 0;
617     new->sgml_hyper.contain_used = 0;
618  
619     new->sgml_hyper.last_time = CurrentTime;
620     new->sgml_hyper.select_index = 0;
621     new->sgml_hyper.copy_text = NULL;
622  
623     new->sgml_hyper.copy_info.last_x = 0;
624     new->sgml_hyper.copy_info.last_y = 0;
625     new->sgml_hyper.copy_info.first_char = NULL;
626     new->sgml_hyper.copy_info.last_widget = NULL;
627     new->sgml_hyper.copy_info.flag = 0;
628  
629     new->sgml_hyper.cache_list = NULL;
630     new->sgml_hyper.cache_slots = 0;
631     new->sgml_hyper.cache_used = 0;
632 }
633  
634  
635 /*--------------------------------------------------------------*/
636 /* Destroy the widget: release all memory allocated             */
637 /*--------------------------------------------------------------*/
638  
639 static void Destroy (w)
640 SGMLHyperWidget w;
641 {
642     XtRemoveAllCallbacks ((Widget) w,SGMLNactivateCallback);
643     XtFree((char *) w->sgml_hyper.cache_list);
644     XFreeCursor(XtDisplay(w),w->sgml_hyper.hand);
645 }
646  
647 /*--------------------------------------------------------------*/
648 /* DeleteChild : deal with the case where this is managed       */
649 /*--------------------------------------------------------------*/
650  
651 static void DeleteChild(w)
652 Widget w;
653 {
654    int i;
655    SGMLHyperWidget parent = (SGMLHyperWidget) XtParent(w);
656  
657    if (parent->sgml_hyper.managed == w) parent->sgml_hyper.managed = NULL;
658  
659    if (XtIsWidget(w))
660      {
661         WidgetList contains = parent->sgml_hyper.contains;
662         int i;
663         int last = 2*parent->sgml_hyper.contain_used;
664  
665         for (i=0; i < last; i += 2)
666           if (contains[i] == w)
667             {
668               contains[i]   = contains[last-2];
669               contains[i+1] = contains[last-1];  
670               parent->sgml_hyper.contain_used--;
671               break;
672             }
673      }
674  
675    /* If the child was on the cache list we had better remove it */
676  
677    for (i = 0 ; i < parent->sgml_hyper.cache_used ; i++)
678      if (w == parent->sgml_hyper.cache_list[i])
679        {
680          parent->sgml_hyper.cache_list[i] =
681            parent->sgml_hyper.cache_list[--parent->sgml_hyper.cache_used];
682        }
683  
684    /* Invoke the superclass's delete_child method  (see note under InsertChild below) */  
685  
686    (*compositeClassRec.composite_class.delete_child)(w);
687 }
688  
689 /*--------------------------------------------------------------*/
690 /* InsertChild : Only accept SGMLTextObject as child            */
691 /*               (or any widget)                                */
692 /*--------------------------------------------------------------*/
693  
694 static void InsertChild(w)
695 Widget w;
696 {
697    String params[2];
698    Cardinal num_params;
699    SGMLHyperWidget parent = (SGMLHyperWidget) XtParent(w);
700  
701    if (SGMLIsText(w))
702      {
703        /*
704         * We have added a new SGMLText child, so we need to think about
705         * removing a cached child. For now we simply remove the oldest cached
706         * widget
707         */
708  
709        int j , i = parent->sgml_hyper.cache_used;
710        Widget *cache = parent->sgml_hyper.cache_list;
711  
712        for (; i > 0 && i >=  parent->sgml_hyper.cache_size ; )
713          {
714            /* Warning, delete child from cache list before calling destroy, to prevent DeleteChild
715             * method from itself messing with the cache list
716             */
717            Widget old = cache[0];
718  
719            parent->sgml_hyper.cache_used = --i;
720            for (j = 0 ; j < i ; j++)  cache[j] = cache[j+1];  
721  
722            XtDestroyWidget(old);
723          }
724  
725        /* Add new widget to end of cache list, making sure there is room */
726  
727        if (i == parent->sgml_hyper.cache_slots)
728          {
729            parent->sgml_hyper.cache_slots += 10;
730            parent->sgml_hyper.cache_list = cache = (WidgetList) XtRealloc((XtPointer) cache,
731                                  (unsigned) parent->sgml_hyper.cache_slots * sizeof(Widget));
732          }
733        cache[i++] = w;
734        parent->sgml_hyper.cache_used = i;      
735      }
736    else if (XtIsWidget(w))
737      {
738         WidgetList contains = parent->sgml_hyper.contains;
739  
740         Widget container = NULL; /* needed in case w has no userdata resource */
741         int i = parent->composite.num_children;
742         Widget curr;
743         Arg arglist[10];
744         int n=0;
745  
746         XtSetArg(arglist[n],XmNuserData,&container); n++;
747         XtGetValues(w,arglist,n); n = 0;
748  
749         if (!container)
750           {  
751             for (;curr = parent->composite.children[--i];)
752               if (SGMLIsCompositeText(curr)) break;/* bug */
753  
754             XtSetArg(arglist[n],SGMLNchild,w); n++;
755             container = XtCreateWidget("container",sGMLContainerTextObjectClass,curr,arglist,n);
756             SGMLCompositeTextInsertChild(container);
757           }
758         if (parent->sgml_hyper.contain_used == parent->sgml_hyper.contain_slots)
759           {
760             parent->sgml_hyper.contain_slots += 10;
761             parent->sgml_hyper.contains = contains = (WidgetList) XtRealloc((XtPointer) contains,
762                                  (unsigned) parent->sgml_hyper.contain_slots * sizeof(Widget) * 2);
763           }
764         contains += 2*( parent->sgml_hyper.contain_used++ );
765         contains[0] = w;
766         contains[1] = container;
767      }
768    else
769      {  
770        params[0] = XtClass(w)->core_class.class_name;
771        params[1] = XtClass(parent)->core_class.class_name;
772        num_params = 2;
773        XtAppErrorMsg(XtWidgetToApplicationContext(w),
774                      "childError","class","WidgetError",
775                      "Children of class %s cannot be added to %s widgets",
776                      params, &num_params);
777      }
778  
779 /* Invoke the superclass's insert_child method
780    NB Actually we skip out superclasses insert_child since the
781       Motif widgets treat non-widget children in some incompatible
782       way... instead we go straight to the composite widget's insert_child
783       method, but will this cause problems with XmManager functionality?  */  
784  
785    (*compositeClassRec.composite_class.insert_child)(w);
786  
787 }
788 /*--------------------------------------------------------------*/
789 /* Resize : not implemented                                     */
790 /*--------------------------------------------------------------*/
791  
792 static void Resize (w)
793 SGMLHyperWidget w;
794 {
795 }
796 /*--------------------------------------------------------------*/
797 /* GeometryManager:                                             */
798 /* Only real widgets can make geometry requests, so pass the    */
799 /* request on to the corresponding container widget             */
800 /*--------------------------------------------------------------*/
801  
802  
803 static XtGeometryResult GeometryManager(w,desired,allowed)
804 Widget w;
805 XtWidgetGeometry *desired, *allowed;
806 {
807    SGMLHyperWidget parent = (SGMLHyperWidget) XtParent(w);
808    WidgetList contains = parent->sgml_hyper.contains;
809    int i;
810    int last = 2*parent->sgml_hyper.contain_used;
811  
812    for (i=0; i < last; i += 2)
813      if (contains[i] == w)
814        {
815           Widget container = contains[i+1];
816           SGMLContainerTextObjectClass class = (SGMLContainerTextObjectClass) XtClass(container);
817           return (*class->sgml_container_text_class.geometry_manager)(container,desired,allowed);
818        }
819    return XtGeometryNo;
820 }
821  
822 /*--------------------------------------------------------------*/
823 /* Redisplay : redraw the text                                  */
824 /*--------------------------------------------------------------*/
825  
826 static void Redisplay (w, event, region)
827 SGMLHyperWidget  w;
828 XEvent       *event;
829 Region        region;
830 {
831     if(w->core.visible && w->sgml_hyper.managed)
832     {
833       SGMLTextObjectClass childClass = (SGMLTextObjectClass) XtClass(w->sgml_hyper.managed);
834       (*childClass->sgml_text_class.expose)(w->sgml_hyper.managed,event,region,0);
835     }  
836 }
837  
838 /*------------------------------------------------------------------*/
839 /* SetValues : redraw only for font or color changes                */
840 /*------------------------------------------------------------------*/
841  
842 static Boolean SetValues (current, request, new)
843 SGMLHyperWidget current, request, new;
844 {
845     Boolean    redraw = FALSE;
846  
847 #define HAS_CHANGED(a)    (new->a != current->a)
848  
849     if(
850         HAS_CHANGED(sgml_hyper.natural_width)
851       )
852     {
853  
854         /* invalidate size of all text widget children */
855  
856         int n = new->composite.num_children;
857         SGMLTextObject *children = (SGMLTextObject *) new->composite.children;
858  
859         for (; n-- > 0; children++)
860           if (SGMLIsText( (Widget) *children)) (*children)->sgml_text.size_valid = FALSE;
861  
862         /* rebuild text */
863  
864         calc_new_size(new);
865         redraw = TRUE;
866     }
867  
868     return (redraw);
869  
870 #undef HAS_CHANGED
871  
872 }
873  
874 /*------------------------------------------------------------------*/
875 /* Adjust the size of a child                                       */
876 /*------------------------------------------------------------------*/
877  
878 static void adjust_size(child,y,ascent,descent)
879 Widget child;
880 Position y;
881 Dimension ascent, descent;
882 {
883 }
884 /*------------------------------------------------------------------*/
885 /* Calculate the size of the widget                                 */
886 /*------------------------------------------------------------------*/
887  
888 static void calc_new_size(w)
889 SGMLHyperWidget  w;
890 {
891     XtGeometryResult    result;
892     SGMLDimension       width=0, height=0;
893     SGMLGeometry        geom;
894     Dimension requestWidth, requestHeight;
895  
896     geom.coord.x = 0;
897     geom.coord.y = w->sgml_hyper.margin;
898     geom.coord.descent = 0;
899     geom.coord.ascent = 0;
900     geom.broken = TRUE;
901     geom.leave_space = FALSE;
902     geom.space = 99999;
903     geom.actual_width = 2 * w->sgml_hyper.margin;
904     geom.natural_width = w->sgml_hyper.natural_width;
905  
906     /* Loop over all of the text segments, getting each to
907        tell us how much space it needs                     */
908  
909     if (w->sgml_hyper.managed)
910       {
911         SGMLTextObject t = (SGMLTextObject) w->sgml_hyper.managed;
912  
913         if (t->sgml_text.size_valid)
914           {
915             width =  t->sgml_text.width;
916             height = geom.coord.y + t->sgml_text.height;
917           }
918         else
919           {
920             SGMLTextObjectClass childClass = (SGMLTextObjectClass) XtClass((Widget) t);
921             (*childClass->sgml_text_class.compute_size)(t,&geom,adjust_size,w->sgml_hyper.managed);
922  
923             t->sgml_text.size_valid = TRUE;
924             width = geom.actual_width;
925             height = geom.coord.y + geom.coord.descent + geom.coord.ascent;
926           }
927       }
928     width  += w->sgml_hyper.margin;
929     height += w->sgml_hyper.margin;
930  
931     /*
932     Tell our parent we want a new size
933     */
934  
935     requestWidth = width > 32767 ? 32767 : width;
936     requestHeight = height > 32767 ? 32767 : height;      
937  
938     /* Temporarily until something better comes along */
939  
940     if (requestHeight != height) MidasQueueCommand(w,"Popup .^^^WWWMain###WWWTruncate");
941  
942     if(w->core.width != width || w->core.height != height)
943     {
944         Dimension replyWidth = 0, replyHeight = 0;
945  
946         result = XtMakeResizeRequest((Widget) w,requestWidth,requestHeight,
947             &replyWidth, &replyHeight) ;
948  
949         if (result == XtGeometryAlmost)
950             XtMakeResizeRequest ((Widget) w, replyWidth, replyHeight,NULL, NULL);
951     }
952  
953     /*
954     Redraw the window
955     */
956  
957     if (XtIsRealized((Widget) w)) XClearArea(XtDisplay((Widget)w),XtWindow((Widget)w),0,0,0,0,True);
958  
959 }
960  
961 /*-----------------------------------------------------------------------*/
962 /* Find the "visible" part of a widget as the intersection of all the    */
963 /* windows of it's parents' windows                                      */
964 /*-----------------------------------------------------------------------*/
965  
966 static void find_visible_part(w,x,y,width,height)
967 Widget    w;
968 Position  *x;
969 Position  *y;
970 Dimension *width;
971 Dimension *height;
972 {
973     Position root_x,root_y;
974     Widget   p = w;
975  
976     *width  = w->core.width;
977     *height = w->core.height;
978     XtTranslateCoords(w,0,0,&root_x,&root_y);
979  
980     *x = 0;
981     *y = 0;
982  
983     while(p = XtParent(p))
984     {
985         Position  rx,ry;
986         Dimension w,h;
987  
988         /*
989            make all computations in the root's
990            coordinate system
991         */
992  
993         XtTranslateCoords(p,0,0,&rx,&ry);
994  
995         w = p->core.width;
996         h = p->core.height;
997  
998         /*
999             use the smallest rectangle
1000         */
1001  
1002         if(w < *width)  *width  = w;
1003         if(h < *height) *height = h;
1004  
1005         if(rx>root_x) root_x = rx;
1006         if(ry>root_y) root_y = ry;
1007  
1008         /* stop when reach a shell,
1009           don't go to top level shell */
1010         if(XtIsShell(p)) break;
1011     }
1012  
1013     /* Back to the widget's coordinate system */
1014  
1015     XtTranslateCoords(w,0,0,x,y);
1016     *x = root_x - *x;
1017     *y = root_y - *y;
1018  
1019  
1020 }
1021  
1022  
1023 /*----------------------------------------------------------------------*/
1024 /* Find the Widget (Gadget) at point (x,y)                              */
1025 /*----------------------------------------------------------------------*/
1026 SGMLTextObject find_segment(w,x,y,mode)
1027 SGMLHyperWidget w;
1028 int x,y;
1029 Boolean mode;
1030 {
1031    if (w->sgml_hyper.managed)
1032       {
1033          SGMLTextObjectClass childClass = (SGMLTextObjectClass) XtClass(w->sgml_hyper.managed);
1034          Widget result = (*childClass->sgml_text_class.contains)(w->sgml_hyper.managed,x,y,mode);
1035          return (SGMLTextObject) result;  
1036       }        
1037  
1038     return NULL;
1039 }
1040 /*-----------------------------------------------------------------------*/
1041 /* Check for mouse down                                                  */
1042 /*-----------------------------------------------------------------------*/
1043  
1044 /* This function is never used and is replaced by SelectStart            */
1045  
1046 static void selectt (w, event, args, n_args)
1047 SGMLHyperWidget   w;
1048 XEvent        *event;
1049 char          *args[];
1050 int            n_args;
1051 {
1052     /*
1053        Find if the user clicked in a (sensitive) text object
1054     */
1055  
1056     SGMLTextObject s = find_segment(w,event->xbutton.x,event->xbutton.y,FALSE);
1057     w->sgml_hyper.last_selected = s;
1058  
1059     if (s != NULL)
1060       {
1061          SGMLTextObjectClass childClass = (SGMLTextObjectClass) XtClass((Widget) s);
1062          (*childClass->sgml_text_class.hilite)(s,SGMLSELECT_WIDGET);  
1063       }
1064 }
1065  
1066 /*-----------------------------------------------------------------------*/
1067 /* Check for mouse up                                                    */
1068 /*-----------------------------------------------------------------------*/
1069  
1070 /* This function is never used and is replaced by SelectEnd              */
1071  
1072 static void activate (w, event, args, n_args)
1073 SGMLHyperWidget   w;
1074 XEvent        *event;
1075 char          *args[];
1076 int            n_args;
1077 {
1078     SGMLTextObject s = find_segment(w,event->xbutton.x,event->xbutton.y,FALSE);
1079  
1080     /*
1081        Find if the user clicked in a highlighted text
1082     */
1083  
1084     if(s != NULL && s == w->sgml_hyper.last_selected)
1085     {
1086          SGMLTextObjectClass childClass = (SGMLTextObjectClass) XtClass((Widget) s);
1087  
1088          (*childClass->sgml_text_class.hilite)(s,SGMLSELECT_WIDGET);  
1089          (*childClass->sgml_text_class.activate)(s,event);  
1090  
1091     }
1092     w->sgml_hyper.last_selected = NULL;
1093 }
1094  
1095 /*-----------------------------------------------------------------------*/
1096 /* Check for mouse moves                                                 */
1097 /*-----------------------------------------------------------------------*/
1098  
1099 static void cursor (w, event, args, n_args)
1100 SGMLHyperWidget   w;
1101 XEvent        *event;
1102 char          *args[];
1103 int            n_args;
1104 {
1105     SGMLTextObject s = find_segment(w,event->xbutton.x,event->xbutton.y,FALSE);
1106     SGMLTextObject l = w->sgml_hyper.last_selected;
1107  
1108     if(s != w->sgml_hyper.last_cursor)
1109     {
1110         if ( l != NULL && (s == l || l == w->sgml_hyper.last_cursor))
1111           {
1112             SGMLTextObjectClass childClass = (SGMLTextObjectClass) XtClass((Widget) l);
1113             (*childClass->sgml_text_class.hilite)(l,SGMLSELECT_WIDGET);
1114           }
1115  
1116         if(s) XDefineCursor(XtDisplay(w),XtWindow(w),w->sgml_hyper.hand);
1117         else  XUndefineCursor(XtDisplay(w),XtWindow(w));
1118  
1119         w->sgml_hyper.last_cursor = s;
1120     }
1121 }
1122  
1123 /*-----------------------------------------------------------------------*/
1124 /* select a word by double clicks                                        */
1125 /*-----------------------------------------------------------------------*/
1126 static void SelectWord (w, event)
1127 SGMLHyperWidget   w;
1128 XEvent        *event;
1129 {
1130     Widget selection;
1131     int x = event->xbutton.x;
1132     int y = event->xbutton.y;
1133     char *pos = NULL;
1134     SGMLTextObject s = find_segment(w,event->xbutton.x,event->xbutton.y,TRUE);
1135  
1136     /* No other widgets except text widgets ONLY are allowed */
1137     if (!s || !s->sgml_text.text || *(s->sgml_text.text) == '\0') return;
1138  
1139     /* race condition with motion? */
1140     if (w->sgml_hyper.race) return;
1141     else w->sgml_hyper.race = TRUE;
1142  
1143     if(s != NULL)
1144     {
1145       SGMLTextObjectClass class = (SGMLTextObjectClass) XtClass((Widget) s);
1146  
1147       w->sgml_hyper.copy_info.current_x = x;
1148       w->sgml_hyper.copy_info.current_y = y;
1149       w->sgml_hyper.copy_info.current_widget = (Widget)s;
1150  
1151       selection = (*class->sgml_text_class.hilite_selection)(s,SGMLSELECT_WORD,&w->sgml_hyper.copy_info);  
1152     }
1153  
1154 }
1155  
1156 /*-----------------------------------------------------------------------*/
1157 /* select a line by triple clicks                                        */
1158 /*-----------------------------------------------------------------------*/
1159 static void SelectLine (w, event)
1160 SGMLHyperWidget   w;
1161 XEvent        *event;
1162 {
1163     Widget selection;
1164     int x = event->xbutton.x;
1165     int y = event->xbutton.y;
1166     char *pos = NULL;
1167     SGMLTextObject lasts = NULL;
1168     SGMLTextObject s = find_segment(w,event->xbutton.x,event->xbutton.y,TRUE);
1169  
1170     /* No other widgets except text widgets ONLY are allowed */
1171     if (s == NULL || s->sgml_text.text == NULL || *(s->sgml_text.text) == '\0') return;
1172  
1173     /* race condition with motion? */
1174     if (w->sgml_hyper.race) return;
1175     else w->sgml_hyper.race = TRUE;
1176  
1177     if(s != NULL)
1178     {
1179       SGMLTextObjectClass class = (SGMLTextObjectClass) XtClass((Widget) s);
1180  
1181       for (x=10;x < w->core.width; x += 10)
1182         {
1183           s = find_segment(w,x,y,TRUE);
1184  
1185           if (s == lasts || s == NULL) continue;
1186  
1187           /* No other widgets except text widgets ONLY are allowed */
1188           if (s->sgml_text.text == NULL || *(s->sgml_text.text) == '\0')
1189             continue;
1190  
1191           w->sgml_hyper.copy_info.current_x = x;
1192           w->sgml_hyper.copy_info.current_y = y;
1193           w->sgml_hyper.copy_info.current_widget = (Widget) s;
1194           selection = (*class->sgml_text_class.hilite_selection)(s,SGMLSELECT_LINE,&w->sgml_hyper.copy_info);  
1195           lasts = s;
1196  
1197         }
1198  
1199       if (selection)
1200         {
1201           w->sgml_hyper.copy_info.sw_flag = TRUE;
1202           w->sgml_hyper.copy_info.last_widget = selection;
1203           w->sgml_hyper.copy_info.last_mode = FALSE;
1204         }
1205      }
1206  
1207 }
1208  
1209  
1210 /*-----------------------------------------------------------------------*/
1211 /* select whole document by Ctrl-click                                   */
1212 /*-----------------------------------------------------------------------*/
1213 static void SelectAll (w, event, args, n_args)
1214 SGMLHyperWidget   w;
1215 XEvent        *event;
1216 String        *args;
1217 Cardinal      *n_args;
1218 {
1219   SGMLTextObjectClass childClass = (SGMLTextObjectClass) XtClass(w->sgml_hyper.managed);
1220   Widget selection;
1221  
1222   w->sgml_hyper.selection_time = event->xbutton.time;
1223  
1224   if (w->sgml_hyper.search_widget || w->sgml_hyper.sw_flag)
1225     {
1226       (*childClass->sgml_text_class.clear_select)(w->sgml_hyper.managed,w->sgml_hyper.sw_flag,TRUE);
1227       w->sgml_hyper.search_widget = NULL;
1228       w->sgml_hyper.sw_flag = NULL;
1229     }
1230  
1231   w->sgml_hyper.copy_info.sw_flag = FALSE;
1232   w->sgml_hyper.copy_info.last_widget = NULL;
1233  
1234   selection =  (*childClass->sgml_text_class.hilite_selection)(w->sgml_hyper.managed,SGMLSELECT_ALL,&w->sgml_hyper.copy_info);
1235  
1236   if (w->sgml_hyper.copy_text)
1237     {
1238       XtFree(w->sgml_hyper.copy_text);
1239       w->sgml_hyper.copy_text = NULL;
1240     }
1241  
1242   if (w->sgml_hyper.copy_info.sw_flag)
1243     {
1244       w->sgml_hyper.search_widget = w->sgml_hyper.copy_info.last_widget;
1245       w->sgml_hyper.sw_flag = w->sgml_hyper.search_widget;
1246     }
1247  
1248   _OwnSelection(w, event, args, n_args);
1249  
1250 }
1251  
1252 /*-----------------------------------------------------------------------*/
1253 /* select a region of text by button + motion                            */
1254 /*-----------------------------------------------------------------------*/
1255 static void SelectRegion(w,event)
1256 SGMLHyperWidget w;
1257 XEvent *event;
1258 {
1259    SGMLTextObject s = find_segment(w,event->xbutton.x,event->xbutton.y,TRUE);
1260  
1261    if(s != NULL)
1262      {
1263        Widget selection;
1264        int x = event->xbutton.x;
1265        int y = event->xbutton.y;
1266        char *pos;
1267        SGMLTextObjectClass class = (SGMLTextObjectClass) XtClass((Widget) s);
1268  
1269        /* No other widgets except text widgets ONLY are allowed */
1270        if (s->sgml_text.text == NULL || *(s->sgml_text.text) == '\0') return;
1271  
1272        (*class->sgml_text_class.xy_to_pos)(s,&x,&y,&pos);
1273        w->sgml_hyper.copy_info.current_widget = (Widget)s;
1274        w->sgml_hyper.copy_info.last_widget = (Widget) s;
1275        w->sgml_hyper.copy_info.first_char = pos;
1276        w->sgml_hyper.copy_info.first_x = x;
1277        w->sgml_hyper.copy_info.first_y = y;
1278        w->sgml_hyper.copy_info.current_x = x;
1279        w->sgml_hyper.copy_info.current_y = y;
1280        w->sgml_hyper.copy_info.last_x = x;
1281        w->sgml_hyper.copy_info.last_y = y;
1282        w->sgml_hyper.copy_info.flag = FALSE;
1283        w->sgml_hyper.copy_info.sw_flag = FALSE;
1284        w->sgml_hyper.copy_info.first_widget = (Widget)s;
1285        w->sgml_hyper.copy_info.current_mode = FALSE;
1286        w->sgml_hyper.copy_info.last_mode = FALSE;
1287        w->sgml_hyper.copy_info.cw = w->sgml_hyper.managed;
1288      }
1289    else
1290      w->sgml_hyper.select_start = FALSE;
1291 }
1292  
1293 /*-----------------------------------------------------------------------*/
1294 /* Selection start                                                       */
1295 /*-----------------------------------------------------------------------*/
1296 static void SelectStart (w, event, args, n_args)
1297 SGMLHyperWidget   w;
1298 XEvent        *event;
1299 String        *args;
1300 Cardinal      *n_args;
1301 {
1302   Time mct = XtGetMultiClickTime(XtDisplay(w));
1303   Time sel_time = event->xbutton.time;
1304   SGMLTextObjectClass childClass = (SGMLTextObjectClass) XtClass(w->sgml_hyper.managed);
1305   SGMLTextObject s = find_segment(w,event->xbutton.x,event->xbutton.y,FALSE);
1306  
1307  
1308   /* clear the selection whenever button click */
1309   if (w->sgml_hyper.search_widget || w->sgml_hyper.sw_flag)
1310     {
1311       (*childClass->sgml_text_class.clear_select)(w->sgml_hyper.managed,w->sgml_hyper.sw_flag,TRUE);
1312       w->sgml_hyper.search_widget = NULL;
1313       w->sgml_hyper.sw_flag = NULL;
1314     }
1315  
1316   if (w->sgml_hyper.copy_text)
1317     {
1318       XtFree(w->sgml_hyper.copy_text);
1319       w->sgml_hyper.copy_text = NULL;
1320     }
1321  
1322   w->sgml_hyper.last_selected = s;
1323   if (s != NULL)
1324     {
1325        SGMLTextObjectClass class = (SGMLTextObjectClass) XtClass((Widget) s);
1326        (*class->sgml_text_class.hilite)(s,SGMLSELECT_WIDGET);  
1327        w->sgml_hyper.select_start = FALSE;
1328        return;
1329     }
1330  
1331   w->sgml_hyper.select_start = TRUE;
1332   if (sel_time > w->sgml_hyper.last_time &&
1333       sel_time - w->sgml_hyper.last_time < mct)
1334     {
1335       if (w->sgml_hyper.select_index < SGMLSELECT_LINE)
1336         w->sgml_hyper.select_index++;
1337       else w->sgml_hyper.select_index = SGMLSELECT_REGION;
1338     }
1339   else w->sgml_hyper.select_index = SGMLSELECT_REGION;
1340  
1341   w->sgml_hyper.last_time = sel_time;
1342  
1343   if (w->sgml_hyper.select_index)
1344     {
1345       w->sgml_hyper.race = FALSE;
1346       if (w->sgml_hyper.select_index == SGMLSELECT_WORD)
1347         SelectWord(w,event);
1348       else if (w->sgml_hyper.select_index == SGMLSELECT_LINE)
1349         SelectLine(w,event);
1350       else
1351         SelectRegion(w,event);
1352     }
1353  
1354 }
1355  
1356 /*-----------------------------------------------------------------------*/
1357 /* Selection extend                                                      */
1358 /*-----------------------------------------------------------------------*/
1359 static void SelectExtend (w, event, args, n_args)
1360 SGMLHyperWidget   w;
1361 XEvent        *event;
1362 String        *args;
1363 Cardinal      *n_args;
1364 {
1365     Widget selection;
1366     int x = event->xbutton.x;
1367     int y = event->xbutton.y;
1368     char *pos = NULL;
1369     SGMLTextObject s = find_segment(w,event->xbutton.x,event->xbutton.y,TRUE);
1370     SGMLTextObject ss = find_segment(w,event->xbutton.x,event->xbutton.y,FALSE);
1371     SGMLTextObject l = w->sgml_hyper.last_selected;
1372  
1373     if (ss != w->sgml_hyper.last_cursor)
1374     {
1375       if ( l != NULL && (s == l || l == w->sgml_hyper.last_cursor))
1376         {
1377           SGMLTextObjectClass childClass = (SGMLTextObjectClass) XtClass((Widget) l);
1378           (*childClass->sgml_text_class.hilite)(l,SGMLSELECT_WIDGET);
1379         }
1380       if (ss) XDefineCursor(XtDisplay(w),XtWindow(w),w->sgml_hyper.hand);
1381       else XUndefineCursor(XtDisplay(w),XtWindow(w));
1382       w->sgml_hyper.last_cursor = ss;
1383     }
1384  
1385     if (!w->sgml_hyper.select_start) return;
1386  
1387     /* race condition with button down? */
1388     if (w->sgml_hyper.race) return;
1389  
1390     if (w->sgml_hyper.select_index != SGMLSELECT_REGION &&
1391         w->sgml_hyper.copy_info.last_widget == NULL ) return;
1392  
1393     if (s != NULL)
1394     {
1395       SGMLTextObjectClass class = (SGMLTextObjectClass) XtClass((Widget) s);
1396       SGMLTextObjectClass childClass = (SGMLTextObjectClass) XtClass(w->sgml_hyper.managed);
1397       SGMLTextObject last_widget = (SGMLTextObject)w->sgml_hyper.copy_info.last_widget;
1398  
1399       /* No other widgets except text widgets ONLY are allowed */
1400       if (s->sgml_text.text == NULL || *(s->sgml_text.text) == '\0') return;
1401  
1402       (*class->sgml_text_class.xy_to_pos)(s,&x,&y,&pos);
1403       w->sgml_hyper.copy_info.current_x = x;
1404       w->sgml_hyper.copy_info.current_y = y;
1405       w->sgml_hyper.copy_info.current_widget = (Widget)s;
1406       if ((w->sgml_hyper.copy_info.current_x == w->sgml_hyper.copy_info.last_x &&
1407           w->sgml_hyper.copy_info.current_y == w->sgml_hyper.copy_info.current_y) ||
1408           w->sgml_hyper.copy_info.last_pos == pos )
1409         return;
1410  
1411       w->sgml_hyper.copy_info.last_pos = pos;
1412       if (s == last_widget)
1413         selection =  (*class->sgml_text_class.hilite_selection)(s,SGMLSELECT_REGION,&w->sgml_hyper.copy_info);
1414       else
1415         selection =  (*childClass->sgml_text_class.hilite_selection)(w->sgml_hyper.managed,SGMLSELECT_REGION,&w->sgml_hyper.copy_info);
1416  
1417       w->sgml_hyper.copy_info.last_mode = w->sgml_hyper.copy_info.current_mode;
1418       w->sgml_hyper.copy_info.last_widget = w->sgml_hyper.copy_info.current_widget;
1419       w->sgml_hyper.copy_info.last_x = w->sgml_hyper.copy_info.current_x;
1420       w->sgml_hyper.copy_info.last_y = w->sgml_hyper.copy_info.current_y;
1421  
1422     }
1423 }
1424  
1425 /*-----------------------------------------------------------------------*/
1426 /* Selection end                                                         */
1427 /*-----------------------------------------------------------------------*/
1428 static void SelectEnd (w, event, args, n_args)
1429 SGMLHyperWidget   w;
1430 XEvent        *event;
1431 String        *args;
1432 Cardinal      *n_args;
1433 {
1434     SGMLTextObject s = find_segment(w,event->xbutton.x,event->xbutton.y,FALSE);
1435  
1436     if(s != NULL && s == w->sgml_hyper.last_selected)
1437     {
1438          SGMLTextObjectClass childClass = (SGMLTextObjectClass) XtClass((Widget) s);
1439  
1440          (*childClass->sgml_text_class.hilite)(s,SGMLSELECT_WIDGET);
1441          (*childClass->sgml_text_class.activate)(s,event);
1442          w->sgml_hyper.last_selected = NULL;
1443          return;
1444     }
1445     w->sgml_hyper.last_selected = NULL;
1446  
1447     if (!w->sgml_hyper.search_widget && !w->sgml_hyper.sw_flag)
1448       {
1449         Boolean sw = w->sgml_hyper.copy_info.sw_flag;
1450  
1451         if (sw)
1452           {
1453             if (w->sgml_hyper.copy_info.last_mode)
1454               w->sgml_hyper.search_widget = w->sgml_hyper.copy_info.first_widget;
1455             else
1456               w->sgml_hyper.search_widget = w->sgml_hyper.copy_info.last_widget;
1457             w->sgml_hyper.sw_flag = w->sgml_hyper.search_widget;
1458  
1459             if (w->sgml_hyper.copy_text)
1460               {
1461                 XtFree(w->sgml_hyper.copy_text);
1462                 w->sgml_hyper.copy_text = NULL;
1463               }
1464           }
1465  
1466         w->sgml_hyper.selection_time = event->xbutton.time;
1467  
1468         if (w->sgml_hyper.search_widget)
1469           _OwnSelection(w,event,args,n_args);
1470       }
1471 }
1472  
1473 static void _OwnSelection(w, event, args, n_args)
1474 SGMLHyperWidget w;
1475 XEvent        *event;
1476 String        *args;
1477 Cardinal      *n_args;
1478 {
1479    int i, buffer;
1480    Atom *atoms;
1481  
1482    atoms = (Atom *)malloc(*n_args * sizeof(Atom));
1483    if (atoms == NULL)
1484      {
1485         fprintf(stderr, "cannot allocate atom list\n");
1486         return;
1487      }
1488    XmuInternStrings(XtDisplay((Widget)w), args, *n_args, atoms);
1489    w->sgml_hyper.selection_time = event->xbutton.time;
1490    for (i=0; i< *n_args; i++)
1491      {
1492        switch (atoms[i])
1493        {
1494          case XA_CUT_BUFFER0: buffer = 0; break;
1495          case XA_CUT_BUFFER1: buffer = 1; break;
1496          case XA_CUT_BUFFER2: buffer = 2; break;
1497          case XA_CUT_BUFFER3: buffer = 3; break;
1498          case XA_CUT_BUFFER4: buffer = 4; break;
1499          case XA_CUT_BUFFER5: buffer = 5; break;
1500          case XA_CUT_BUFFER6: buffer = 6; break;
1501          case XA_CUT_BUFFER7: buffer = 7; break;
1502          default: buffer = -1; break;
1503        }
1504        if (buffer >= 0)
1505          {
1506            if (GetSelection(w,SGMLDUMP_ASCII))
1507              XStoreBuffer(XtDisplay((Widget)w), w->sgml_hyper.copy_text,
1508                           strlen(w->sgml_hyper.copy_text), buffer);
1509          }
1510        else
1511          {
1512            Boolean result = XtOwnSelection((Widget)w, atoms[i],
1513                                            event->xbutton.time,Convert,
1514                                            LoseOwnership,SelectionDone);
1515            if (!result)
1516              printf ("Warning: Fail to become selection owner\n");
1517          }
1518      }
1519    free ((char *)atoms);
1520  
1521 }
1522  
1523 /*-----------------------------------------------------------------------*/
1524 /* Add text to a text segment                                            */
1525 /*-----------------------------------------------------------------------*/
1526  
1527 static Widget add_to_text(name,parent,class,text,param,matched)
1528 Widget parent;
1529 SGMLTextObjectClass class;
1530 char *text, *param, *name;
1531 int matched;
1532 {
1533     Widget new;
1534  
1535 /*    
1536  *  Scan the param string looking for possible parameters (maximum 5 at present)
1537  */
1538  
1539     if (param && *param)
1540       {
1541         char *copy;
1542         char *Type[5];
1543         char *Res[5];
1544         char *Val[5];
1545         int  Len[5];
1546         char *whiteSpace = " \t\n\r";
1547         char *whiteSpaceOrEqual = " \t=\n\r";
1548         int i, l;        
1549         char *p, *q, *r;
1550  
1551         copy = XtNewString(param);
1552         r = copy;
1553  
1554         for (i=0; i<5; )
1555           {
1556             Boolean done, equal;
1557  
1558             p = r + strspn(r,whiteSpace);           /* skip leading whitespace */
1559             if (*p=='\0') break;
1560             q = p + strcspn(p,whiteSpaceOrEqual);   /* Skip until white or equal */
1561             r = q + strspn(q,whiteSpace);           /* Skip any whitespace */
1562  
1563             done  =  (*r == '\0');
1564             equal =  (*r == '=' );
1565             *q = '\0';
1566  
1567             if (*p != '"') lowcase(p);
1568             else
1569               {
1570                 p++;
1571                 if (*(q-1)=='"') *(q-1) = '\0';
1572               }  
1573  
1574             /*
1575              * For security reasons we mustn't let any Callbacks
1576              * be set using tag parameters
1577              */
1578  
1579             if (strstr(p,"Callback")) continue;
1580  
1581             Type[i] = XtVaTypedArg;
1582             Res[i]  = p;
1583  
1584             if (equal)
1585               {
1586                 r++;
1587                 r +=  strspn(r,whiteSpace);
1588                 if (*r == '"')
1589                   {
1590                     r++;
1591                     l = strcspn(r,"\"");
1592                   }    
1593                 else
1594                   {
1595                     l = strcspn(r,whiteSpace);
1596                   }
1597                 p = r + l;
1598                 done = (*p == '\0');
1599                 if (!done) *p = '\0';
1600  
1601                 Val[i] = r;
1602                 Len[i] = l + 1;
1603                 r = p + 1;  
1604                 i++;
1605               }
1606             else
1607               {
1608                 Val[i] = "TRUE";
1609                 Len[i] = 5;
1610                 i++;
1611               }
1612             if (done) break;
1613           }
1614         if (i < 5) Type[i] = NULL;
1615         new = XtVaCreateWidget(name,(WidgetClass) class,parent,
1616               SGMLNtext,      (XtArgVal) text,
1617               SGMLNparam,     (XtArgVal) param,
1618               SGMLNmatched,   (XtArgVal) matched,  
1619               Type[0], Res[0], XtRString, Val[0], Len[0],
1620               Type[1], Res[1], XtRString, Val[1], Len[1],
1621               Type[2], Res[2], XtRString, Val[2], Len[2],
1622               Type[3], Res[3], XtRString, Val[3], Len[3],
1623               Type[4], Res[4], XtRString, Val[4], Len[4], NULL);
1624  
1625         XtFree(copy);
1626       }          
1627     else
1628       {
1629         Arg arglist[10];
1630         int n=0;
1631  
1632         XtSetArg(arglist[n],SGMLNtext ,   (XtArgVal) text   ); n++;
1633         XtSetArg(arglist[n],SGMLNparam,   (XtArgVal) param  ); n++;
1634         XtSetArg(arglist[n],SGMLNmatched, (XtArgVal) matched); n++;
1635  
1636         new = XtCreateWidget(name,(WidgetClass) class, parent, arglist, n);
1637       }
1638  
1639     if (SGMLIsCompositeText(parent)) SGMLCompositeTextInsertChild(new);
1640  
1641     /*
1642      *  Invoke the CreateCallback
1643      */  
1644  
1645     (*class->sgml_text_class.call_create_callback)(new,NULL);
1646  
1647     return new;
1648 }    
1649  
1650 /*-----------------------------------------------------------------------*/
1651 /* check a tag: returns TRUE if tag accepted                             */    
1652 /*                      FALSE if tag rejected                            */
1653 /* if the tag is accepted then NewClass gives its type (or null if it    */
1654 /* was a terminator)                                                     */
1655 /*-----------------------------------------------------------------------*/
1656  
1657 static Boolean check_tag(w,intag,Text,Name,NewClass,tagQuark,exactTerminator,matched)
1658 SGMLHyperWidget w;
1659 char *intag;
1660 XrmName Name;
1661 Widget Text;
1662 WidgetClass *NewClass;
1663 XrmName *tagQuark;
1664 Boolean exactTerminator;
1665 int *matched;
1666 {
1667   char *tag = XtNewString(intag);
1668   char *oldtag = tag;
1669   char et = w->sgml_hyper.end_tag;
1670   Arg arglist[10];
1671   int n = 0;
1672   int i;
1673   SGMLTagList *tagList;
1674   Boolean end = (*tag == et);
1675   if (end) tag++;  
1676  
1677   *NewClass = NULL;
1678  
1679   if (!w->sgml_hyper.case_sensitive_tags) lowcase(tag);
1680   *tagQuark = XrmStringToQuark(tag);  
1681   XtFree(oldtag);
1682  
1683   if (Name != NullQuark)
1684     if (end) return (!exactTerminator || *tagQuark == Name );
1685     else     return FALSE;
1686  
1687   if (end)
1688     {
1689       int d = 0;
1690  
1691       if (XtParent(Text) == (Widget) w) return FALSE; /* nothing to end */
1692       if (!exactTerminator) return TRUE;
1693       for (; XtParent(Text) != (Widget) w ; Text = XtParent(Text))
1694         {
1695           d++;
1696           if (*tagQuark == Text->core.xrm_name ||  /* dlc kludge */
1697              (*tagQuark == dl_quark && dlc_quark == Text->core.xrm_name)) return TRUE;
1698         }  
1699       return FALSE;
1700     }
1701  
1702   XtSetArg(arglist[n],SGMLNtagList,&tagList); n++;
1703   XtGetValues(Text,arglist,n);
1704  
1705   if (tagList)
1706     for (i=0; tagList[i].class != NULL; i++)
1707       if (tagList[i].name == *tagQuark)
1708         {
1709           *NewClass = tagList[i].class;
1710           *matched = tagList[i].matched;
1711           return TRUE;
1712         }
1713  
1714   return FALSE;  
1715 }
1716  
1717 /*-----------------------------------------------------------------------*/
1718 /* set a new tag: the tag must previously have been accepted by          */    
1719 /* check tag                                                             */
1720 /*-----------------------------------------------------------------------*/
1721  
1722  
1723 static void set_tag(w,inoutText,inoutName,inoutClass,param,NewClass,tagQuark,matched)
1724 SGMLHyperWidget w;
1725 char *param;
1726 XrmName *inoutName;
1727 Widget *inoutText;
1728 WidgetClass *inoutClass;
1729 WidgetClass NewClass;  
1730 XrmName tagQuark;
1731 int matched;
1732 {
1733   Widget text = *inoutText;
1734   XrmName name = *inoutName;
1735  
1736   /* temporary kludge to support dl compact */
1737  
1738   if (tagQuark == dl_quark && param && strstr(param,"compact")) tagQuark = dlc_quark;
1739  
1740   if (name != NullQuark)
1741     {
1742        Arg arglist[10];
1743        int n = 0;
1744  
1745        *inoutName = NullQuark;
1746  
1747        XtSetArg(arglist[n],SGMLNdefaultClass,inoutClass); n++;
1748        XtGetValues(text,arglist,n);
1749        return;
1750     }  
1751  
1752   if (NewClass == NULL)
1753     {
1754       for (; tagQuark != text->core.xrm_name && (tagQuark != dl_quark || dlc_quark != text->core.xrm_name); text = XtParent(text));
1755       text = XtParent(text);  
1756     }
1757   else
1758     {
1759     if (!matched)
1760       {
1761         add_to_text(XrmQuarkToString(tagQuark),text,NewClass,NULL,param,matched);
1762       }
1763     else if (IsSubClass(NewClass,sGMLCompositeTextObjectClass))
1764       {
1765         text = add_to_text(XrmQuarkToString(tagQuark),text,NewClass,NULL,param,matched);
1766       }  
1767     else
1768       {
1769         *inoutName = tagQuark;
1770         *inoutClass = NewClass;
1771       }
1772     }    
1773   if (text != *inoutText)
1774   {
1775     Arg arglist[10];
1776     int n = 0;
1777  
1778     XtSetArg(arglist[n],SGMLNdefaultClass,inoutClass); n++;
1779     XtGetValues(text,arglist,n);
1780   }
1781   *inoutText = text;
1782 }
1783 /*-----------------------------------------------------------------------*/
1784 /* Rebuild the text structure. Called when the font changes              */
1785 /*-----------------------------------------------------------------------*/
1786  
1787 void SGMLHyperManageChild(w)
1788 Widget w;
1789 {
1790     SGMLHyperWidget parent = (SGMLHyperWidget) XtParent(w);
1791     SGMLTextObjectClass class = (SGMLTextObjectClass) XtClass(w);
1792     Widget old = parent->sgml_hyper.managed;
1793     Widget sw = parent->sgml_hyper.sw_flag;
1794     int i;
1795  
1796     if (XtIsRealized((Widget) parent)) XUndefineCursor(XtDisplay((Widget) parent),XtWindow((Widget) parent)); /* In case cursor was set */
1797  
1798     if (old == w) return;
1799  
1800     if (old)
1801       {
1802         SGMLTextObjectClass oldclass = (SGMLTextObjectClass) XtClass(old);
1803         (*oldclass->sgml_text_class.call_map_callback)(old,NULL,FALSE);
1804         if (sw) {
1805           (*oldclass->sgml_text_class.clear_select)(old,sw,FALSE);
1806           parent->sgml_hyper.sw_flag = NULL;
1807           if (parent->sgml_hyper.copy_text)
1808             {
1809               XtFree(parent->sgml_hyper.copy_text);
1810               parent->sgml_hyper.copy_text = NULL;
1811             }
1812           }
1813       }
1814     parent->sgml_hyper.managed = w;
1815     parent->sgml_hyper.search_widget = NULL;
1816  
1817     calc_new_size(parent);
1818  
1819     /*
1820      * Each time a widget is managed we put it back at the top of the cache
1821      * list, thus making it less likely to be removed from the cache as other
1822      * children are created
1823      */
1824  
1825     for (i=0 ; i < parent->sgml_hyper.cache_used - 1; i++)
1826       if (w == parent->sgml_hyper.cache_list[i])
1827         {
1828           Widget swap = parent->sgml_hyper.cache_list[parent->sgml_hyper.cache_used - 1] ;
1829           parent->sgml_hyper.cache_list[parent->sgml_hyper.cache_used - 1] =
1830             parent->sgml_hyper.cache_list[i];
1831           parent->sgml_hyper.cache_list[i] = swap;
1832         }
1833  
1834     (*class->sgml_text_class.call_map_callback)(w,NULL,TRUE);
1835 }
1836 /*-----------------------------------------------------------------------*/
1837 /* Build the text. Gets the chars from the funtion "get_next_char"       */
1838 /* using "data" as a parameter                                           */
1839 /*-----------------------------------------------------------------------*/
1840  
1841 #define NORMAL 0
1842 #define TAG    1
1843 #define PARAM  2
1844 #define ENTITY 4
1845 #define PARAMILLEGAL  3
1846  
1847 typedef struct {
1848  
1849     SGMLHyperWidget w;
1850     Widget      parentText;
1851     Widget      topText;
1852     char        *word;
1853     char        *saveParam;
1854  
1855     int         mode;
1856     int         tag;
1857     int         param;
1858     int         wordsize;
1859     int         i;
1860  
1861     WidgetClass currentClass;
1862     WidgetClass NewClass;
1863     XrmName     currentName;
1864     XrmName     tagQuark;
1865     Boolean     exactTerminator;
1866     Boolean     supportsEntities;
1867     Boolean     hideIllegalTags;
1868     int         matched;
1869  
1870     Arg arglist[10];
1871     int n;
1872  
1873 } ParseState;
1874  
1875 static ParseState *CreateState(inW)
1876 Widget inW;
1877 {  
1878     ParseState *state = XtNew(ParseState);
1879  
1880     state->i = 0;
1881     state->mode = NORMAL;
1882     state->currentName = NullQuark;
1883     state->saveParam = NULL;
1884  
1885     /* Create the base text object */
1886  
1887     state->topText = state->parentText = XtCreateWidget("default",sGMLCompositeTextObjectClass,inW,NULL,0);
1888  
1889     state->n = 0;
1890     XtSetArg(state->arglist[state->n],SGMLNdefaultClass,&state->currentClass); state->n++;
1891     XtGetValues(state->parentText,state->arglist,state->n);
1892  
1893     state->n = 0;
1894     XtSetArg(state->arglist[state->n],SGMLNexactTerminator,&state->exactTerminator); state->n++;
1895     XtSetArg(state->arglist[state->n],SGMLNsupportsEntities,&state->supportsEntities); state->n++;
1896     XtSetArg(state->arglist[state->n],SGMLNhideIllegalTags,&state->hideIllegalTags); state->n++;
1897     XtGetValues(state->parentText,state->arglist,state->n);
1898  
1899     state->wordsize = MAX_LINE_SIZE;
1900     state->word = XtMalloc(state->wordsize);
1901  
1902     for (; !SGMLIsHyper(inW);) inW = XtParent(inW);
1903     state->w = (SGMLHyperWidget) inW;
1904  
1905     return state;    
1906 }
1907 static Widget DestroyState(state)
1908 ParseState *state;
1909 {
1910     Widget result;
1911  
1912     /* flush .. */
1913  
1914     if(state->i)
1915     {
1916       state->word[state->i] = '\0';
1917       if (state->i) add_to_text(XrmQuarkToString(state->currentName),state->parentText,
1918                                 state->currentClass,state->word,state->saveParam,1);
1919     }
1920  
1921     XtFree(state->saveParam);  
1922     XtFree(state->word);
1923  
1924     result = state->topText;
1925     XtFree((char *)state);
1926     return result;
1927 }
1928  
1929 static void munge_text(state,get_next_char,data)
1930 ParseState *state;
1931 int (*get_next_char)();
1932 XtPointer data;
1933 {
1934     int c;
1935     int i = state->i;
1936     int mode = state->mode;
1937     char *word = state->word;
1938     int wordsize = state->wordsize;
1939  
1940     int ot  = state->w->sgml_hyper.open_tag;
1941     int ct  = state->w->sgml_hyper.close_tag;
1942     int pt  = state->w->sgml_hyper.parameter_tag;
1943     int est = state->w->sgml_hyper.entity_tag;
1944     int eet = state->w->sgml_hyper.entity_end_tag;
1945  
1946     while((c = (get_next_char)(data)) != EOF)  
1947     {
1948         /* kludge */
1949  
1950         if (mode == TAG && (c == '\n' || c == '\t')) c = ' ';
1951  
1952         /* Open Tag */
1953  
1954         if (mode == NORMAL && c == ot)
1955         {
1956             word[i++] = c;
1957             if(i == wordsize) word = XtRealloc(word, (wordsize *= 2));
1958             state->tag = i;    
1959             mode = TAG;
1960         }
1961  
1962         /* Entity */
1963  
1964         else if (state->supportsEntities && mode == NORMAL && c == est)
1965         {
1966             word[i++] = c;
1967             if(i == wordsize) word = XtRealloc(word, (wordsize *= 2));
1968             state->tag = i;
1969             mode = ENTITY;
1970         }
1971  
1972         /* Parameter */
1973  
1974         else if (mode == TAG && c == pt)
1975         {
1976             word[i] = '\0';
1977             if (check_tag(state->w,word+state->tag,state->parentText,state->currentName,
1978                           &state->NewClass,&state->tagQuark,state->exactTerminator,&state->matched))
1979             {
1980               word[state->tag-1] = '\0';
1981               if (*word) add_to_text(XrmQuarkToString(state->currentName),state->parentText,
1982                                      state->currentClass,word,state->saveParam,1);
1983               i++;
1984               if(i == wordsize) word = XtRealloc(word, (wordsize *= 2));
1985               XtFree(state->saveParam);
1986               state->saveParam = NULL;
1987               state->param = i;
1988               mode = PARAM;
1989             }
1990             else if (state->hideIllegalTags)
1991             {
1992               word[state->tag-1] = '\0';
1993               if (*word) add_to_text(XrmQuarkToString(state->currentName),state->parentText,
1994                                      state->currentClass,word,state->saveParam,1);
1995               word[i++] = pt;
1996               if (i == wordsize) word = XtRealloc(word, (wordsize *= 2));
1997               XtFree(state->saveParam);
1998               state->saveParam = NULL;
1999               mode = PARAMILLEGAL;
2000             }    
2001             else
2002             {
2003               word[i++] = pt;
2004               if(i == wordsize) word = XtRealloc(word, (wordsize *= 2));
2005               mode = NORMAL;
2006             }
2007         }
2008  
2009         /* Close Tag */
2010  
2011         else if (mode == TAG && c == ct)
2012         {
2013             word[i] = '\0';
2014             if (check_tag(state->w,word+state->tag,state->parentText,state->currentName,
2015                           &state->NewClass,&state->tagQuark,state->exactTerminator,&state->matched))
2016             {
2017               word[state->tag-1] = '\0';
2018               add_to_text(XrmQuarkToString(state->currentName),state->parentText,
2019                                      state->currentClass,word,state->saveParam,1);
2020               set_tag(state->w,&state->parentText,&state->currentName,&state->currentClass,
2021                       state->saveParam,state->NewClass,state->tagQuark,state->matched);
2022               XtGetValues(state->parentText,state->arglist,state->n);
2023  
2024               i = 0;    
2025               mode = NORMAL;
2026               XtFree(state->saveParam);
2027               state->saveParam = NULL;  
2028             }
2029             else if (state->hideIllegalTags)
2030             {
2031               word[state->tag-1] = '\0';
2032               if (*word) add_to_text(XrmQuarkToString(state->currentName),state->parentText,
2033                                      state->currentClass,word,state->saveParam,1);
2034  
2035               word[state->tag-1] = ot;
2036               word[i++] = ct;
2037               if (i == wordsize) word = XtRealloc(word, (wordsize *= 2));
2038               word[i++] = '\0';
2039               add_to_text("hidden",state->parentText,sGMLFormattedTextObjectClass,word+state->tag-1,NULL,1);
2040  
2041               i = 0;    
2042               mode = NORMAL;
2043               XtFree(state->saveParam);
2044               state->saveParam = NULL;  
2045             }    
2046             else
2047             {
2048               word[i++] = ct;
2049               if(i == wordsize) word = XtRealloc(word, (wordsize *= 2));
2050               mode = NORMAL;
2051             }
2052         }
2053  
2054         else if (mode == PARAM && c == ct)
2055         {
2056             word[i] = '\0';
2057             set_tag(state->w,&state->parentText,&state->currentName,&state->currentClass,
2058                     word+state->param,state->NewClass,state->tagQuark,state->matched);
2059             XtGetValues(state->parentText,state->arglist,state->n);
2060  
2061             if (state->NewClass && state->matched)
2062                state->saveParam = XtNewString(word+state->param);
2063             mode = NORMAL;
2064             i = 0;    
2065         }
2066         else if (mode == PARAMILLEGAL && c == ct)
2067         {
2068             word[state->tag-1] = ot;
2069             word[i++] = ct;
2070             if (i == wordsize) word = XtRealloc(word, (wordsize *= 2));
2071             word[i++] = '\0';
2072             add_to_text("hidden",state->parentText,sGMLFormattedTextObjectClass,word+state->tag-1,NULL,1);
2073  
2074             mode = NORMAL;
2075             i = 0;    
2076         }
2077         else if (mode == ENTITY && c == eet)
2078         {
2079             char entity[32];
2080             char *e = entity;
2081             int j;
2082  
2083             for (j = state->tag ; j<i ; j++) *e++ = word[j];
2084  
2085             if (c == eet)
2086              {
2087                *e = '\0';
2088  
2089                if      (isdigit(*entity)) c = (char) atoi(entity);
2090                else if (*entity == '#')   c = (char) atoi(entity+1);
2091                else if ((c = EntityToIsoLatin1(entity)) == '\0') c = '?';
2092  
2093                i = state->tag;
2094                word[i-1] = c;
2095              }
2096             mode = NORMAL;
2097         }
2098         else if (mode == ENTITY && (i-state->tag > 30 || (c != '#' && !isalnum(c))))
2099         {
2100             mode = NORMAL;
2101         }
2102         else
2103         {
2104             word[i++] = c;
2105             if(i == wordsize) word = XtRealloc(word, (wordsize *= 2));
2106         }
2107     }
2108  
2109     state->i = i;
2110     state->mode = mode;
2111     state->word = word;
2112     state->wordsize = wordsize;
2113     return;
2114 }
2115  
2116 static Widget set_text(inW,get_next_char,data)
2117 Widget inW;
2118 int (*get_next_char)();
2119 XtPointer data;
2120 {    
2121    ParseState *state = CreateState(inW);
2122    munge_text(state,get_next_char,data);
2123    return DestroyState(state);
2124 }
2125  
2126  
2127 /*-----------------------------------------------------------------------*/
2128 /* Declare a Widget class for the converter                              */
2129 /*-----------------------------------------------------------------------*/
2130  
2131 void SGMLHyperDeclareClass(class)
2132 WidgetClass class;
2133 {
2134    static int MaxClasses = 0;  
2135    if (NumberOfClasses == MaxClasses)
2136      ClassList = (WidgetClass *)  XtRealloc((XtPointer) ClassList, (MaxClasses += 10) * sizeof(WidgetClass));
2137    ClassList[NumberOfClasses++] = class;
2138 }
2139  
2140 /*-----------------------------------------------------------------------*/
2141 /* Create a new HyperWidget                                              */
2142 /*-----------------------------------------------------------------------*/
2143  
2144 Widget SGMLCreateHyper(parent,name,al,ac)
2145 Widget parent;
2146 char   *name;
2147 ArgList al;
2148 int     ac;
2149 {
2150     return XtCreateWidget(name,sGMLHyperWidgetClass,parent,al,ac);
2151 }
2152  
2153 /*-----------------------------------------------------------------------*/
2154 /* Redisplay HyperWidget                                                 */
2155 /*-----------------------------------------------------------------------*/
2156  
2157 void SGMLHyperRedisplay(w)
2158 Widget w;
2159 {
2160    SGMLHyperWidget h = (SGMLHyperWidget) w;
2161    if (h->sgml_hyper.managed) calc_new_size(h);
2162 }
2163 /*-----------------------------------------------------------------------*/
2164 /* Load the text from a file                                             */
2165 /*-----------------------------------------------------------------------*/
2166  
2167 /* provides chars to "set_text" routine */
2168  
2169 static int get_from_file(f)
2170 FILE **f;
2171 {
2172     int n =  getc(*f);
2173     return n;
2174 }
2175  
2176 /* Public routine */
2177  
2178 Widget SGMLHyperLoadFile(widget,fname)
2179 Widget widget;
2180 char   *fname;
2181 {
3 roytam 2182 //    extern char *sys_errlist[];
1 roytam 2183     Widget result = NULL;
2184  
2185     FILE *f = fopen(fname,"r");
2186     if(f)
2187     {
2188         result = set_text(widget,get_from_file,&f);
2189         fclose(f);
2190     }
2191     else
2192     {
2193         char msg[1024];
2194         sprintf(msg,"%s: %s",fname,sys_errlist[errno]);
2195         XtWarning(msg);
2196     }
2197     return result;  
2198 }
2199  
2200 /*-----------------------------------------------------------------------*/
2201 /* Load text using a getchar like routine                                */
2202 /*-----------------------------------------------------------------------*/
2203  
2204 Widget SGMLHyperLoadText(widget,get_character,closure)
2205 Widget widget;
2206 int (*get_character)();
2207 XtPointer closure;
2208 {
2209    return set_text(widget,get_character,closure);
2210 }
2211  
2212 /*-----------------------------------------------------------------------*/
2213 /* Load text from memory buffer                                          */
2214 /*-----------------------------------------------------------------------*/
2215  
2216 /* provides chars to "set_text" routine */
2217  
2218 static int get_from_buffer(buffer)
2219 char **buffer;
2220 {
2221     char c = **buffer;
2222     (*buffer)++;
2223     return c?c:EOF;
2224 }
2225  
2226 /* Public routines */
2227  
2228 Widget SGMLHyperSetText(widget,text)
2229 Widget  widget;
2230 char *text;
2231 {
2232     return set_text(widget,get_from_buffer,&text);
2233 }
2234  
2235 XtPointer SGMLHyperOpen(widget)
2236 Widget widget;
2237 {
2238   return (XtPointer) CreateState(widget);
2239 }
2240 void SGMLHyperWrite(state,text)
2241 XtPointer state;
2242 char *text;
2243 {
2244   munge_text((ParseState *) state, get_from_buffer, &text);
2245 }
2246 void SGMLHyperWriteData(state,get_character,closure)
2247 XtPointer state;
2248 int (*get_character)();
2249 XtPointer closure;
2250 {
2251   munge_text((ParseState *) state, get_character, closure);
2252 }
2253 Widget SGMLHyperClose(state)
2254 XtPointer state;
2255 {
2256   return DestroyState((ParseState *) state);
2257 }
2258  
2259 /*-----------------------------------------------------------------------*/
2260 /* SGMLHyperSearch: Public routine                                       */
2261 /*-----------------------------------------------------------------------*/
2262 Widget SGMLHyperSearch(w,exp,sens,cont)
2263 SGMLHyperWidget w;
2264 char *exp;
2265 Boolean sens;
2266 Boolean cont;
2267 {
2268    Widget result = NULL;
2269  
2270  
2271    if (w->sgml_hyper.managed)
2272      {
2273        SGMLTextObjectClass childClass = (SGMLTextObjectClass) XtClass(w->sgml_hyper.managed);
2274  
2275        if (!cont && w->sgml_hyper.search_widget)
2276          {
2277            (*childClass->sgml_text_class.clear_select)(w->sgml_hyper.managed,w->sgml_hyper.sw_flag,TRUE);
2278            w->sgml_hyper.search_widget = NULL;
2279          }
2280  
2281        /* clear the already hilite widget */        
2282        if (w->sgml_hyper.search_widget)
2283          (*childClass->sgml_text_class.hilite)(w->sgml_hyper.managed,SGMLSELECT_WORD);
2284  
2285        result = (*childClass->sgml_text_class.search)(exp,sens,w->sgml_hyper.managed,TRUE,NULL,NULL,&w->sgml_hyper.search_widget);
2286        if (result)
2287          (*childClass->sgml_text_class.hilite)(w->sgml_hyper.managed,SGMLSELECT_WORD);
2288      }
2289  
2290    /* clear the last search widget */
2291    if (w->sgml_hyper.sw_flag && !result)
2292      {
2293        XClearArea(XtDisplay((Widget)w),XtWindow((Widget)w),0,0,0,0,True);
2294        w->sgml_hyper.sw_flag = NULL;
2295      }
2296  
2297    w->sgml_hyper.search_widget = result;
2298    w->sgml_hyper.sw_flag = w->sgml_hyper.search_widget;
2299    return result;        
2300 }
2301  
2302 /*-----------------------------------------------------------------------*/
2303 /* Specifies start and end of highlignt chars                            */
2304 /*-----------------------------------------------------------------------*/
2305  
2306  
2307 void SGMLHyperSetTags(widget,open_tag,close_tag,end_tag,parameter_tag)
2308 Widget widget;
2309 unsigned char open_tag;
2310 unsigned char close_tag;
2311 unsigned char end_tag;
2312 unsigned char parameter_tag;
2313 {
2314     ((SGMLHyperWidget)widget)->sgml_hyper.open_tag      = open_tag;
2315     ((SGMLHyperWidget)widget)->sgml_hyper.close_tag     = close_tag;
2316     ((SGMLHyperWidget)widget)->sgml_hyper.end_tag       = end_tag;
2317     ((SGMLHyperWidget)widget)->sgml_hyper.parameter_tag = parameter_tag;
2318 }
2319  
2320  
2321 /*-----------------------------------------------------------------------*/
2322 /* convert a string to lower case                                        */
2323 /*-----------------------------------------------------------------------*/
2324  
2325 static void lowcase(p)
2326 register char *p;
2327 {
2328     while(*p)
2329     {
2330         *p = tolower(*p);
2331         p++;
2332     }
2333 }
2334  
2335 /*-----------------------------------------------------------------------*/
2336 /* Returns the text of the widget                                        */
2337 /* the memory is allocated. It must be freed by the application          */
2338 /* If include_tags is FALSE, the special characters are not returned     */
2339 /*-----------------------------------------------------------------------*/
2340  
2341 static void dump_text(hyper,w,include_tags,calc_len,pp)
2342 SGMLHyperWidget hyper;
2343 SGMLTextObject w;
2344 Boolean include_tags, calc_len;
2345 char **pp;
2346 {
2347   char *special = "<>&\"";
2348   char ot = hyper->sgml_hyper.open_tag;
2349   char ct = hyper->sgml_hyper.close_tag;
2350   char et = hyper->sgml_hyper.end_tag;
2351   char pt = hyper->sgml_hyper.parameter_tag;
2352   char est = hyper->sgml_hyper.entity_tag;
2353   char eet = hyper->sgml_hyper.entity_end_tag;
2354   Boolean supportsEntities;
2355  
2356   char *p;
2357   int len, matched;
2358   char *name = XtName((Widget)w);
2359  
2360   Arg arglist[10];
2361   int n = 0;
2362  
2363   XtSetArg(arglist[n],SGMLNsupportsEntities,&supportsEntities); n++;
2364   XtSetArg(arglist[n],SGMLNmatched,&matched); n++;
2365   XtGetValues((Widget)w,arglist,n);
2366  
2367   if (w->object.being_destroyed) return;
2368  
2369   if (calc_len) len = (int) *pp;
2370   else          p   = *pp;  
2371  
2372   if (!strcmp(name,"default")) name = "";
2373   if (!strcmp(name,"hidden"))  { name = ""; supportsEntities = FALSE; }
2374  
2375   if (*name && include_tags)
2376   {
2377     char *q = name;
2378     if (calc_len) len++;
2379     else          *p++ = ot;
2380     if (calc_len) len += strlen(q);
2381     else          for (; *q != '\0' && *q != '_'; ) *p++ = *q++;
2382     if (w->sgml_text.param_length)
2383       {  
2384         char *param = w->sgml_text.param;
2385         if (calc_len) len++;
2386         else          *p++ = pt;
2387         if (calc_len) len += strlen(param);
2388         else          for (; *param != '\0';) *p++ = *param++;
2389       }              
2390     if (calc_len) len++;
2391     else          *p++ = ct;
2392   }  
2393   if (w->sgml_text.text)
2394   {
2395     if (supportsEntities)
2396       {
2397         char *text = w->sgml_text.text;
2398         if (calc_len)
2399           {
2400             for (; *text != '\0';)
2401               if (strchr(special,*text++)) len += 6;
2402               else len++;
2403           }
2404         else
2405           {
2406             for (; *text != '\0';)
2407               if (strchr(special,*text)) { sprintf(p,"%c#%03d%c",est,(int)*text++,eet); p += 6; }
2408               else  *p++ = *text++;
2409           }
2410       }
2411     else
2412       {
2413         char *text = w->sgml_text.text;
2414         if (calc_len) len += strlen(text);
2415         else          for (; *text != '\0';) *p++ = *text++;
2416       }
2417   }
2418   if (SGMLIsCompositeText((Widget)w))
2419   {
2420     int n;
2421     WidgetList children;
2422     int nn = 0;
2423     Arg arglist[10];
2424  
2425     XtSetArg(arglist[nn],XtNnumChildren,&n); nn++;
2426     XtSetArg(arglist[nn],XtNchildren,&children); nn++;
2427     XtGetValues((Widget)w,arglist,nn);
2428  
2429     if (calc_len) for (; n-- > 0; children++) dump_text(hyper,*children,include_tags,calc_len,&len);
2430     else          for (; n-- > 0; children++) dump_text(hyper,*children,include_tags,calc_len,&p);  
2431   }
2432   if (matched && include_tags && *name)
2433   {
2434     char *q = name;
2435     if (calc_len) len ++;
2436     else          *p++ = ot;
2437     if (calc_len) len ++;
2438     else          *p++ = et;
2439     if (calc_len) len += strlen(q);
2440     else          for (; *q != '\0' && *q != '_'; ) *p++ = *q++;
2441     if (calc_len) len ++;
2442     else          *p++ = ct;
2443   }  
2444   if (calc_len) *pp = (char *) len;
2445   else          *pp = p;
2446 }
2447  
2448 char *SGMLHyperGetText(widget, include_tags)
2449 Widget  widget;
2450 Boolean include_tags;
2451 {
2452  
2453     SGMLHyperWidget w = (SGMLHyperWidget)widget;
2454     char  *result, *p;
2455     int   len = 1;
2456  
2457     if (w->sgml_hyper.managed)
2458       {
2459         dump_text(w,w->sgml_hyper.managed,include_tags,TRUE,&len);
2460         result = p = XtMalloc(len);
2461         dump_text(w,w->sgml_hyper.managed,include_tags,FALSE,&p);
2462  
2463         *p++ = '\0';
2464         return result;
2465       }
2466     else return NULL;
2467 }
2468  
2469 /*-----------------------------------------------------------------------*/
2470 /* Only for Motif                                                        */
2471 /* If the widget is in a XmScrolledWindow, scroll it so the selection is */
2472 /* visible                                                               */
2473 /*-----------------------------------------------------------------------*/
2474  
2475 void SGMLHyperShowObject(h,object,sel)
2476 SGMLHyperWidget h;
2477 SGMLTextObject object;
2478 Boolean sel;
2479 {
2480 #define SetArg(a,b)  XtSetArg(al[ac],a,b);ac++
2481 #define GetValues(w) XtGetValues(w,al,ac);ac=0
2482 #define SetValues(w) XtSetValues(w,al,ac);ac=0
2483  
2484     Widget clip = XtParent(h);
2485     Widget swin;
2486  
2487     Widget h_scroll;
2488     Widget v_scroll;
2489  
2490     int ac = 0;
2491  
2492     Position    x_parent,y_parent;
2493     Position    x_grep,y_grep;
2494     Dimension   h_grep,w_grep;
2495     Position    x_clip,y_clip;
2496     Dimension   h_clip,w_clip;
2497     Position    dv=0,dh=0;
2498     int min,max;
2499     int v_val,v_size,v_inc,v_page;
2500     int h_val,h_size,h_inc,h_page;
2501     Position x,y;
2502  
2503     Arg al[5];
2504  
2505     /* check if selection exists */
2506  
2507     /* check if the widget is in a scrolled window */
2508     /* the XmScrolledWindow creates a clip window  */
2509     /* The widget's parent is the clip window      */
2510  
2511  
2512     if(!clip) return;
2513     swin = XtParent(clip);
2514  
2515     if(!swin || !XmIsScrolledWindow(swin)) return;
2516  
2517  
2518     /* Get window scroll bars */
2519  
2520     SetArg(XmNhorizontalScrollBar, &h_scroll);
2521     SetArg(XmNverticalScrollBar  , &v_scroll);
2522     GetValues(swin);
2523  
2524     /* Get size of clip window and selection rect */
2525  
2526     w_clip = clip->core.width;
2527     h_clip = clip->core.height;
2528  
2529     /* If no object specified then position at top */
2530  
2531     if (!object)
2532     {
2533         SetArg(XmNminimum,&min);
2534         GetValues(v_scroll);
2535         XmScrollBarGetValues(v_scroll,&v_val,&v_size,&v_inc,&v_page);
2536         dv = min - v_val;
2537  
2538         SetArg(XmNminimum,&min);
2539         GetValues(h_scroll);
2540         XmScrollBarGetValues(h_scroll,&h_val,&h_size,&h_inc,&h_page);
2541         dh = min - h_val;
2542     }
2543     else
2544     {
2545       w_grep = object->sgml_text.width;
2546       h_grep = object->sgml_text.height;
2547  
2548       /* Get global coordinates of clip and selection rect */
2549  
2550       XtTranslateCoords(clip,0,0,&x_clip,&y_clip);
2551       if (sel && object->sgml_text.begin_select)
2552         {
2553           Position sx, sy;
2554           char *sb = object->sgml_text.begin_select;
2555           SGMLTextObjectClass class = (SGMLTextObjectClass) XtClass((Widget)object);
2556           sx = object->sgml_text.margin;
2557           sy = object->sgml_text.begin.y;
2558           /* deliberately make object small */
2559           w_grep = 2;
2560           h_grep = 2;
2561           (*class->sgml_text_class.pos_to_xy)(object,&sx,&sy,sb,FALSE);
2562           XtTranslateCoords((Widget)h,sx,sy,&x_grep,&y_grep);
2563         }
2564       else
2565         XtTranslateCoords((Widget)h,object->sgml_text.margin,object->sgml_text.begin.y,&x_grep,&y_grep);
2566  
2567       /* offset of selection within clip window */
2568  
2569       x = x_grep - x_clip;
2570       y = y_grep - y_clip;
2571  
2572  
2573       /* selection y coordinate is not visible */
2574  
2575       if( y < 0 || y + h_grep > h_clip)
2576       {
2577           /* the widget must be moved verticaly by dv pixels */
2578  
2579           dv = (y + h_grep / 2)  - h_clip / 2;
2580  
2581           SetArg(XmNminimum,&min);
2582           SetArg(XmNmaximum,&max);
2583  
2584           GetValues(v_scroll);
2585  
2586           XmScrollBarGetValues(v_scroll,&v_val,&v_size,&v_inc,&v_page);
2587  
2588           max -= v_size;
2589  
2590           if( dv + v_val > max ) dv = max - v_val;
2591           if( dv + v_val < min ) dv = min - v_val;
2592  
2593  
2594       }
2595  
2596       /* selection x coordinate is not visible */
2597  
2598       if( x < 0 || x + w_grep > w_clip)
2599       {
2600           /* the widget must be moved horizontaly by dh pixels */
2601  
2602           dh = (x + w_grep / 2)  - w_clip / 2;
2603  
2604           SetArg(XmNminimum,&min);
2605           SetArg(XmNmaximum,&max);
2606           GetValues(h_scroll);
2607  
2608           XmScrollBarGetValues(h_scroll,&h_val,&h_size,&h_inc,&h_page);
2609  
2610           max -= h_size;
2611  
2612           if( dh + h_val > max ) dh = max - h_val;
2613           if( dh + h_val < min ) dh = min - h_val;
2614  
2615       }
2616  
2617     }
2618     /* if the widget must be moved */
2619  
2620     if(dv || dh)
2621     {
2622         Position x = h->core.x-dh;
2623         Position y = h->core.y-dv;
2624  
2625         /* move it */
2626  
2627         SetArg(XmNx,x);
2628         SetArg(XmNy,y);
2629         SetValues((Widget) h);
2630  
2631         /* update scroll bars */
2632  
2633         if(dv) XmScrollBarSetValues(v_scroll,v_val+dv,v_size,v_inc,
2634             v_page,TRUE);
2635         if(dh) XmScrollBarSetValues(h_scroll,h_val+dh,h_size,h_inc,
2636             h_page,TRUE);
2637  
2638  
2639     }
2640  
2641 }
2642  
2643 /*-----------------------------------------------------------------------*/
2644 /* Clear previous selection                                              */
2645 /*-----------------------------------------------------------------------*/
2646  
2647 static void clear_selection(w)
2648 SGMLHyperWidget w;
2649 {
2650 /*
2651     if(w->sgml_hyper.grep_seg)
2652     {
2653         if(XtIsRealized(w))
2654 */
2655             /* force a redraw */
2656 /*
2657             XClearArea(XtDisplay(w),XtWindow(w),
2658                 w->sgml_hyper.grep_x,
2659                 w->sgml_hyper.grep_y,
2660                 w->sgml_hyper.grep_width,
2661                 w->sgml_hyper.grep_height,
2662                 TRUE);
2663  
2664     }
2665     w->sgml_hyper.grep_seg = NULL;
2666 */
2667 }
2668  
2669 /*-----------------------------------------------------------------------*/
2670 /* Set the new selection                                                 */
2671 /*-----------------------------------------------------------------------*/
2672  
2673 static void set_selection(w)
2674 SGMLHyperWidget w;
2675 {
2676 /*
2677     if(w->sgml_hyper.grep_seg)
2678     {
2679         text_segment *s = w->sgml_hyper.grep_seg;
2680         char *p = s->text;
2681         XCharStruct   char_info;
2682         int dir,ascent,desc;
2683 */
2684         /* get size of the begining of
2685            the segment, up to the found string */
2686 /*
2687         XTextExtents(
2688             s->style->sgml_style.font,
2689             s->text,
2690             w->sgml_hyper.grep_off,
2691             &dir,&ascent,&desc,&char_info);
2692  
2693         w->sgml_hyper.grep_x      = s->x + char_info.width;
2694         w->sgml_hyper.grep_y      = s->y + desc;
2695         w->sgml_hyper.grep_height = s->height;
2696 */
2697         /* Get size of the selection */
2698 /*
2699         XTextExtents(
2700             s->style->sgml_style.font,
2701             w->sgml_hyper.grep_txt,
2702             w->sgml_hyper.grep_len,
2703             &dir,&ascent,&desc,&char_info);
2704  
2705  
2706         w->sgml_hyper.grep_width  = char_info.width;
2707 */
2708         /* force update */
2709 /*
2710         if(XtIsRealized(w))
2711             XClearArea(XtDisplay(w),XtWindow(w),
2712                 w->sgml_hyper.grep_x,
2713                 w->sgml_hyper.grep_y,
2714                 w->sgml_hyper.grep_width,
2715                 w->sgml_hyper.grep_height,
2716                 TRUE);
2717     }
2718 */
2719 }
2720  
2721 /* size of regexp buffer */
2722  
2723 #define ESIZE 1024
2724  
2725 /*-----------------------------------------------------------------------*/
2726 /* if you have regexp, define USE_REGEXP                                 */
2727 /* NOTE : since regexp variables and functions are not static            */
2728 /* you can have some problems if you use the same names or include       */
2729 /* regexp somewhere else                                                 */
2730 /*-----------------------------------------------------------------------*/
2731 #ifdef USE_REGEXP
2732  
2733 /* regexp macros ... see "man regexp" */
2734  
2735 #define INIT        register char *sp = instring;
2736 #define GETC()      (*sp++)
2737 #define PEEKC()     (*sp)
2738 #define UNGETC(c)   (--sp)
2739 #define RETURN(c)   return;
2740 #define ERROR(c)    fprintf(stderr,"Warning regexp error %d\n",c)
2741  
2742  
2743 #include <regexp.h>
2744  
2745  
2746 #else
2747  
2748 /*-----------------------------------------------------------------------*/
2749 /* If we don't have regexp mimic it.                                     */
2750 /* Just find plain text using strncmp. no regular expression matching    */
2751 /*-----------------------------------------------------------------------*/
2752  
2753 static char *loc1,*loc2;
2754 static int len;
2755  
2756 static compile(w,buf,end,dummy)
2757 char *w,*buf;
2758 int end;
2759 int dummy;
2760 {
2761     strcpy(buf,w);
2762     len = strlen(w);
2763 }
2764  
2765 static step(w,buf)
2766 char *w;
2767 char *buf;
2768 {
2769     loc1 = w;
2770     while(*loc1)
2771     {
2772         if(strncmp(loc1,buf,len) == 0)
2773         {
2774             loc2 = loc1+len;
2775             return TRUE;
2776         }
2777         loc1++;
2778     }
2779     return FALSE;
2780 }
2781  
2782  
2783 #endif
2784  
2785 /*-----------------------------------------------------------------------*/
2786 /* Select a word in the hyper widget                                     */
2787 /* word : word to find ( or regular expression if USE_REGEX is defined)  */
2788 /* ignore_case : if TRUE ignore case in comparaison                      */
2789 /* from_start : if TRUE search from start of text, else search from      */
2790 /* current selection                                                     */
2791 /* wrap: if TRUE, continue search from the begining of text if the end   */
2792 /* is reached                                                            */
2793 /*-----------------------------------------------------------------------*/
2794  
2795 #ifdef _NO_PROTO
2796  
2797 Boolean SGMLHyperGrep(widget,word,ignore_case,from_start,wrap)
2798 Widget   widget;
2799 char     *word;
2800 Boolean  ignore_case;
2801 Boolean  from_start;
2802 Boolean  wrap;
2803  
2804 #else
2805  
2806 Boolean SGMLHyperGrep(Widget widget,
2807                       char *word,
2808                       Boolean ignore_case,
2809                       Boolean from_start,
2810                       Boolean wrap)
2811  
2812 #endif
2813  
2814 {
2815 #ifdef dummy
2816     SGMLHyperWidget  h = (SGMLHyperWidget)widget;
2817     char         *w = word;
2818     char         *p;
2819     int          offset,from,to;
2820     text_segment *s;
2821     char          expbuf[ESIZE];
2822  
2823     if(!h->sgml_hyper.first_seg) return;
2824  
2825     if(ignore_case)
2826     {
2827         /* if ignore case, change word to lower case */
2828         w = XtNewString(word);
2829         lowcase(w);
2830     }
2831  
2832     /* compile the regular expression */
2833     compile(w,expbuf,&expbuf[ESIZE],'\0');
2834  
2835  
2836     if(ignore_case) XtFree(w);
2837  
2838     /* if from_start or no previous selection,
2839        start from first segment */
2840  
2841     if(from_start || h->sgml_hyper.grep_seg == NULL)
2842     {
2843         offset=0;
2844         wrap = FALSE;
2845         s = h->sgml_hyper.first_seg;
2846     }
2847     else
2848     {
2849         /* start from last selection */
2850  
2851         offset = h->sgml_hyper.grep_off + h->sgml_hyper.grep_len;
2852         s = h->sgml_hyper.grep_seg;
2853     }
2854  
2855     for(;;)
2856     {
2857         if(s->text)
2858         {
2859             if(ignore_case)
2860             {
2861                 /* if ignore case, change segment to lower case */
2862                 p = XtNewString(s->text);
2863                 lowcase(p);
2864             }
2865  
2866             /* search the string */
2867  
2868             if(step(p+offset,expbuf))
2869             {
2870                 /* if found ...*/
2871  
2872                 /* clear previous selection */
2873                 clear_selection(h);
2874  
2875                 h->sgml_hyper.grep_seg = s;
2876                 h->sgml_hyper.grep_off = offset + (loc1-(p+offset));
2877                 h->sgml_hyper.grep_txt = s->text + h->sgml_hyper.grep_off;
2878                 h->sgml_hyper.grep_len = loc2-loc1;
2879  
2880                 /* set new selection */
2881  
2882                 set_selection(h);
2883  
2884                 /* make it visible */
2885  
2886                 show_selection(h);
2887  
2888                 if(ignore_case) XtFree(p);
2889  
2890                 return TRUE;
2891             }
2892  
2893             if(ignore_case) XtFree(p);
2894         }
2895  
2896         offset = 0;
2897         s = s->next;
2898  
2899         /* if end of text and wrap mode, go to start of text */
2900         if(!s)
2901             if(wrap)
2902             {
2903                 wrap = FALSE;
2904                 s = h->sgml_hyper.first_seg;
2905             }
2906             else break;
2907  
2908     }
2909  
2910  
2911 #endif
2912     return FALSE;
2913 }
2914  
2915 static Boolean Convert(w, selection, target, type, value, length, format)
2916 Widget w;
2917 Atom *selection, *target, *type;
2918 XtPointer *value;
2919 unsigned long *length;
2920 int *format;
2921 {
2922   Display *d = XtDisplay(w);
2923   SGMLHyperWidget hw = (SGMLHyperWidget)w;
2924  
2925   if (*selection != XA_PRIMARY) return False;
2926  
2927   /*
2928    * XA_TARGETS identifies what targets the text widget can
2929    * provide data for.
2930    */
2931   if (*target == XA_TARGETS(d))
2932      {
2933        Atom* targetP;
2934        Atom* std_targets;
2935        unsigned long std_length;
2936        XmuConvertStandardSelection(
2937                     w, hw->sgml_hyper.selection_time, selection,
2938                     target, type, (caddr_t*)&std_targets, &std_length, format
2939                    );
2940        *length = std_length + 5;
2941        *value = (XtPointer)XtMalloc(sizeof(Atom)*(*length));
2942        targetP = *(Atom**)value;
2943        *targetP++ = XA_STRING;
2944        *targetP++ = XA_TEXT(d);
2945        *targetP++ = XA_COMPOUND_TEXT(d);
2946        *targetP++ = XA_LIST_LENGTH(d);
2947        *targetP++ = XA_LENGTH(d);
2948        bcopy((char*)std_targets, (char*)targetP, sizeof(Atom)*std_length);
2949        XtFree((char*)std_targets);
2950        *type = XA_ATOM;
2951        *format = 32;
2952        return TRUE;
2953      }
2954  
2955    if (*target == XA_STRING ||
2956        *target == XA_TEXT(d)||
2957        *target == XA_COMPOUND_TEXT(d) )
2958      {
2959        Boolean result = TRUE;
2960  
2961        if (*target == XA_COMPOUND_TEXT(d))
2962          *type = *target;
2963        else
2964          *type = XA_STRING;
2965  
2966        if (hw == NULL) return FALSE;
2967  
2968        if (hw->sgml_hyper.copy_text == NULL && hw->sgml_hyper.search_widget)
2969          result = GetSelection(hw,SGMLDUMP_ASCII);  
2970  
2971       *format = 8;
2972       if (result && hw->sgml_hyper.copy_text)
2973         {
2974           *length = (unsigned long) strlen(hw->sgml_hyper.copy_text);
2975           *value = hw->sgml_hyper.copy_text;
2976         }
2977       else
2978         {
2979           *length = 0;
2980           *value = NULL;
2981         }
2982  
2983        return TRUE;
2984      }
2985  
2986    if (*target == XA_LIST_LENGTH(d))
2987      {
2988        *value = XtMalloc(4);
2989         if (sizeof(long) == 4)
2990           {
2991             *(long*)*value = 1;
2992           }
2993         else
2994           {
2995             long temp = 1;
2996             bcopy( ((char*)&temp)+sizeof(long)-4, (char*)*value, 4);
2997           }
2998         *type = XA_INTEGER;
2999         *length = 1;
3000         *format = 32;
3001         return TRUE;
3002      }
3003  
3004    if (*target == XA_LENGTH(d))
3005      {
3006         *value = XtMalloc(4);
3007         if (sizeof(long) == 4)
3008             *(long*)*value = strlen(hw->sgml_hyper.copy_text);
3009         else {
3010             long temp = strlen(hw->sgml_hyper.copy_text);
3011             bcopy( ((char*)&temp)+sizeof(long)-4, (char*)*value, 4);
3012         }
3013         *type = XA_INTEGER;
3014         *length = 1;
3015         *format = 32;
3016         return True;
3017      }
3018  
3019    if (XmuConvertStandardSelection(w, hw->sgml_hyper.selection_time, selection,
3020                                    target, type,
3021                                    (caddr_t *)value, length, format))
3022      return TRUE;
3023  
3024    /* else */
3025    return FALSE;
3026  
3027 }
3028  
3029 static void LoseOwnership(w, selection)
3030 Widget w;
3031 Atom *selection;
3032 {
3033    SGMLHyperWidget hw = (SGMLHyperWidget)w;
3034    SGMLTextObjectClass childClass = (SGMLTextObjectClass) XtClass(hw->sgml_hyper.managed);
3035  
3036    if (hw->sgml_hyper.copy_text)
3037      {
3038        XtFree(hw->sgml_hyper.copy_text);
3039        hw->sgml_hyper.copy_text = NULL;
3040      }
3041  
3042    if (hw->sgml_hyper.sw_flag || hw->sgml_hyper.search_widget)
3043      {
3044        (*childClass->sgml_text_class.clear_select)(hw->sgml_hyper.managed,hw->sgml_hyper.sw_flag,TRUE);
3045         hw->sgml_hyper.search_widget = NULL;
3046         hw->sgml_hyper.sw_flag = NULL;
3047       }
3048 }
3049  
3050 static void SelectionDone(w, selection, target)
3051 Widget w;
3052 Atom *selection, *target;
3053 {
3054         /* empty proc so Intrinsics know we want to keep storage */
3055 }
3056  
3057 static Boolean GetSelection(hw,type)
3058 SGMLHyperWidget hw;
3059 int type;
3060 {
3061    Display *d = XtDisplay((Widget)hw);
3062    SGMLTextObjectClass childClass = (SGMLTextObjectClass) XtClass(hw->sgml_hyper.managed);
3063    int len = 0;
3064    char *p;
3065    SGMLDumpTextInfo dp;
3066  
3067    dp.sw = hw->sgml_hyper.search_widget;
3068    dp.begin_sw = FALSE;
3069    dp.calc_len = TRUE;
3070    dp.format_type = type;
3071    dp.copy_type = hw->sgml_hyper.select_index;
3072    dp.current_pos = NULL;
3073    dp.last_pos = NULL;
3074    dp.line_spacing = 0;
3075    dp.spacing = 0;
3076    dp.last_len = 0;
3077    (*childClass->sgml_text_class.dump_text)(hw->sgml_hyper.managed,&dp,&len);
3078  
3079    if (!len) return FALSE;
3080  
3081    dp.calc_len = FALSE;
3082    dp.begin_sw = FALSE;
3083    dp.line_spacing = 0;
3084    dp.spacing = 0;
3085    hw->sgml_hyper.copy_text = p = XtMalloc((unsigned)len+1);
3086    dp.current_pos = dp.last_pos = hw->sgml_hyper.copy_text;
3087    (*childClass->sgml_text_class.dump_text)(hw->sgml_hyper.managed,&dp,&p);
3088    *p = '\0';
3089  
3090    return TRUE;
3091 }