c37674ea21af8102ece821d6012a88123bc8530c
[oweals/cde.git] / cde / lib / DtHelp / LinkMgr.c
1 /* $XConsortium: LinkMgr.c /main/10 1996/11/01 10:10:59 drk $ */
2 /************************************<+>*************************************
3  ****************************************************************************
4  **
5  **   File:        LinkMgr.c
6  **
7  **   Project:     Cde Help System
8  **
9  **   Description: Hypertext manager for the core engine of the help
10  **                system.  Processes requests from the UI to move, turn
11  **                on, or turn off the traversal indicator, to return
12  **                information about a hypertext link and to determine
13  **                if a spot selected contains a hypertext link.
14  **
15  **  (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992 Hewlett-Packard Company
16  **
17  **  (c) Copyright 1993, 1994 Hewlett-Packard Company
18  **  (c) Copyright 1993, 1994 International Business Machines Corp.
19  **  (c) Copyright 1993, 1994 Sun Microsystems, Inc.
20  **  (c) Copyright 1993, 1994 Novell, Inc.
21  **
22  ****************************************************************************
23  ************************************<+>*************************************/
24
25 /*
26  * system includes
27  */
28 #include <errno.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include <X11/Xos.h>
34 #ifdef X_NOT_STDC_ENV
35 extern int errno;
36 #endif
37
38 /*
39  * Canvas Engine Includes
40  */
41 #include "CanvasP.h"
42
43 /*
44  * private includes
45  */
46 #include "CanvasOsI.h"
47 #include "CvStringI.h"
48 #include "LinkMgrI.h"
49 #include "LinkMgrP.h"
50
51
52 #ifdef NLS16
53 #endif
54
55 /********    Private Function Declarations    ********/
56 /********    End Private Function Declarations    ********/
57
58 /*****************************************************************************
59  *              Private Defines
60  *****************************************************************************/
61 #define GROW_SIZE       3
62
63 /*****************************************************************************
64  *              Private Variables
65  *****************************************************************************/
66 const static struct _dtCvLinkDb DefLinkDb = { 0, NULL };
67
68 /*****************************************************************************
69  *              Private Functions
70  *****************************************************************************/
71 /*****************************************************************************
72  * Function: FindLink (
73  *
74  * Purpose:
75  *****************************************************************************/
76 static  int
77 FindLink (
78     _DtCvLinkDb  link_db,
79     char        *id,
80     int         *ret_no,
81     int         *ret_hint)
82 {
83     int result = -1;
84     int i;
85
86     for (i = 0; -1 == result && i < link_db->max; i++)
87       {
88         if (_DtLinkTypeNone != link_db->list[i].type
89                         && NULL != link_db->list[i].id
90                         && 0 == _DtCvStrCaseCmpLatin1(link_db->list[i].id, id))
91           {
92             /*
93              * return a valid index
94              */
95             *ret_no = i;
96
97              /*
98               * check to see if the hint changes
99               */
100              if (_DtLinkTypeLink == link_db->list[i].type &&
101                 _DtCvWindowHint_Original != link_db->list[i].info.link.hint)
102                 *ret_hint = link_db->list[i].info.link.hint;
103
104              /*
105               * clear the error return
106               */
107              result = 0;
108           }
109       }
110
111     return result;
112 }
113
114 /*****************************************************************************
115  * Function: ResolveSwitch (_DtCvLinkDb link_db, int *ret_link)
116  *
117  * Purpose:
118  *****************************************************************************/
119 static  int
120 ResolveSwitch (
121     _DtCvLinkDb  link_db,
122     int          link_no,
123     int          iterations,
124     int         (*filter)(),
125     void        *client_data,
126     int         *ret_link,
127     int         *ret_hint)
128 {
129     int          result = -1;
130     char        *valueData = NULL;
131
132     if (iterations < 100)
133       {
134         result = _DtCvRunInterp(filter, client_data,
135                                 link_db->list[link_no].info.swtch.interp,
136                                 link_db->list[link_no].info.swtch.cmd,
137                                 &valueData);
138
139         if (result == 0)
140           {
141             int   value = atoi(valueData);
142             char *idRefs = link_db->list[link_no].info.swtch.branches;
143             char *rid;
144
145             iterations++;
146
147             while (value > 0 && *idRefs != '\0')
148               {
149                 /*
150                  * skip this id.
151                  */
152                 while(*idRefs != ' ' && *idRefs != '\0')
153                     idRefs++;
154
155                 /*
156                  * skip the spaces
157                  */
158                 while(*idRefs == ' ')
159                     idRefs++;
160
161                 /*
162                  * decrement the index.
163                  */
164                 value--;
165               }
166
167             /*
168              * if the value returned is more than the id list or we hit
169              * the end, back up to the first idref
170              */
171             if (value > 0 || *idRefs == '\0')
172                 idRefs = link_db->list[link_no].info.swtch.branches;
173
174             /*
175              * duplicate the id and null out the
176              * extraneous ids.
177              */
178             rid    = strdup (idRefs);
179             idRefs = rid;
180             while(*idRefs != ' ' && *idRefs != '\0')
181                 idRefs++;
182             *idRefs = '\0';
183
184             result = FindLink(link_db, rid, &link_no, ret_hint);
185             if (0 == result && _DtLinkTypeSwitch == link_db->list[link_no].type)
186                 result = ResolveSwitch (link_db,  link_no, iterations, filter,
187                                         client_data, &link_no, ret_hint);
188             free (rid);
189           }
190
191         if (valueData != NULL)
192             free(valueData);
193       }
194
195     *ret_link = link_no;
196     return result;
197 }
198
199 /*****************************************************************************
200  * Function: GetNextEntry (
201  *
202  * Purpose:
203  *****************************************************************************/
204 static  int
205 GetNextEntry (
206     _DtCvLinkDb link_db)
207 {
208     int    i = 0;
209
210     while (i < link_db->max && _DtLinkTypeNone != link_db->list[i].type)
211         i++;
212
213     if (i >= link_db->max)
214       {
215         link_db->max += GROW_SIZE;
216         if (link_db->list != NULL)
217             link_db->list = (_DtCvLinkEntry *) realloc(link_db->list,
218                                 (sizeof (_DtCvLinkEntry) * link_db->max));
219         else
220             link_db->list = (_DtCvLinkEntry *) malloc(
221                                 sizeof (_DtCvLinkEntry) * link_db->max);
222
223         if (link_db->list == NULL)
224             return -1;
225
226         while (i < link_db->max)
227           {
228             link_db->list[i  ].id   = NULL;
229             link_db->list[i++].type = _DtLinkTypeNone;
230           }
231
232         i -= GROW_SIZE;
233       }
234
235     return i;
236 }
237
238 /*****************************************************************************
239  *              Semi-Public Functions
240  *****************************************************************************/
241 /******************************************************************************
242  * Function:    int _DtLinkDbGetLinkType (link_index)
243  *
244  * Parameters:
245  *
246  * Returns:
247  *
248  * errno Values:
249  *
250  * Purpose:     Return the hypertext link type.
251  *
252  *****************************************************************************/
253 int
254 _DtLinkDbGetLinkType (
255     _DtCvLinkDb link_db,
256     int         link_index )
257 {
258     int  value = -1;
259
260     if (link_index < link_db->max &&
261                         _DtLinkTypeNone != link_db->list[link_index].type)
262         value = link_db->list[link_index].info.link.lnk_type;
263
264     return value;
265 }
266
267 /******************************************************************************
268  * Function:    int _DtLinkDbGetHint (link_index)
269  *
270  * Parameters:
271  *
272  * Returns:
273  *
274  * errno Values:
275  *
276  * Purpose:     Return the hypertext link type.
277  *
278  *****************************************************************************/
279 int
280 _DtLinkDbGetHint (
281     _DtCvLinkDb link_db,
282     int          link_index )
283 {
284     int  value = -1;
285
286     if (link_index < link_db->max &&
287                         _DtLinkTypeNone != link_db->list[link_index].type)
288         value = link_db->list[link_index].info.link.hint;
289
290     return value;
291 }
292
293 /******************************************************************************
294  * Function:    char *_DtLinkDbGetLinkSpec (link_index)
295  *
296  * Parameters:
297  *
298  * Returns:
299  *
300  * errno Values:
301  *
302  * Purpose:     Return the hypertext link type.
303  *
304  *****************************************************************************/
305 char *
306 _DtLinkDbGetLinkSpec (
307     _DtCvLinkDb link_db,
308     int          link_index )
309 {
310     char  *ptr = NULL;
311
312     if (link_index < link_db->max &&
313                         _DtLinkTypeNone != link_db->list[link_index].type)
314         ptr = link_db->list[link_index].info.link.spec;
315
316     return ptr;
317 }
318
319 /******************************************************************************
320  * Function:    int _DtLinkDbGetLinkInfo (link_index, ret_info)
321  *
322  * Parameters:
323  *
324  * Returns:
325  *
326  * errno Values:
327  *
328  * Purpose:     Return the hypertext link type.
329  *
330  *****************************************************************************/
331 int
332 _DtLinkDbGetLinkInfo (
333     _DtCvLinkDb          link_db,
334     int                  link_index,
335     int                 (*filter)(),
336     void                *client_data,
337     _DtCvLinkInfo       *ret_info)
338 {
339     int    hint;
340     int    result = -1;
341     char  *spec;
342
343     if (link_index < link_db->max &&
344                         _DtLinkTypeNone != link_db->list[link_index].type)
345       {
346         result = 0;
347
348         spec = link_db->list[link_index].info.link.spec;
349         hint = link_db->list[link_index].info.link.hint;
350
351         /*
352          * is this a link to a switch? Check the switches for
353          * the spec (id) and resolve to another link if so.
354          */
355         if (_DtLinkTypeSwitch == link_db->list[link_index].type ||
356                 (0 == FindLink(link_db, spec, &link_index, &hint)
357                         && _DtLinkTypeSwitch == link_db->list[link_index].type))
358             result = ResolveSwitch(link_db, link_index, 0, filter, client_data,
359                                                         &link_index, &hint);
360
361         if (0 == result)
362           {
363             ret_info->win_hint   = hint;
364             ret_info->hyper_type =
365                                 link_db->list[link_index].info.link.lnk_type;
366             ret_info->specification =
367                                 link_db->list[link_index].info.link.spec;
368             ret_info->description =
369                                 link_db->list[link_index].info.link.descrip;
370           }
371       }
372
373     return result;
374 }
375
376 /*****************************************************************************
377  *              Public Functions
378  *****************************************************************************/
379 /*****************************************************************************
380  * Function:    _DtCvLinkDb _DtLinkDbCreate ()
381  *
382  * Parameters:
383  *
384  * Returns:     A link data base handle.
385  *
386  * Purpose:     Create a link data base.
387  *
388  *****************************************************************************/
389 _DtCvLinkDb
390 _DtLinkDbCreate (void)
391 {
392     _DtCvLinkDb newDb = (_DtCvLinkDb) malloc (sizeof(struct _dtCvLinkDb));
393
394     if (NULL != newDb)
395         *newDb = DefLinkDb;
396
397     return (newDb);
398 }
399
400 /*****************************************************************************
401  * Function:    void _DtLinkDbDestroy (_DtCvLinkDb link_db)
402  *
403  * Parameters:
404  *              canvas          Specifies the handle for the canvas.
405  *
406  * Returns:     A handle to the canvas or NULL if an error occurs.
407  *
408  * Purpose:
409  *
410  *****************************************************************************/
411 void
412 _DtLinkDbDestroy (
413     _DtCvLinkDb link_db)
414 {
415     int i;
416
417     if (NULL != link_db)
418       {
419         for (i = 0; i < link_db->max; i++)
420           {
421             if (_DtLinkTypeLink == link_db->list[i].type)
422               {
423                 if (NULL != link_db->list[i].id)
424                     free(link_db->list[i].id);
425                 free(link_db->list[i].info.link.spec);
426                 if (NULL != link_db->list[i].info.link.descrip)
427                     free(link_db->list[i].info.link.descrip);
428               }
429             else if (_DtLinkTypeSwitch == link_db->list[i].type)
430               {
431                 free(link_db->list[i].id);
432                 free(link_db->list[i].info.swtch.interp);
433                 free(link_db->list[i].info.swtch.cmd);
434                 free(link_db->list[i].info.swtch.branches);
435               }
436           }
437         if (NULL != link_db->list)
438             free(link_db->list);
439
440         free(link_db);
441       }
442 }
443
444 /******************************************************************************
445  * Function:    int _DtLinkDbAddLink (link_data, char *link, int type,
446  *                                                      char *description)
447  *
448  * Parameters:
449  *              link    Specifies the hypertext link specification.
450  *              type    Specifies the type of hypertext link.
451  *              link    Specifies the hypertext link description.
452  *
453  * Returns      The index into the list of hypertext links.
454  *              -1 for errors.
455  *
456  * errno Values:
457  *              DtErrorMalloc
458  *
459  * Purpose:     Place a hypertext link into an array.
460  *
461  * Note:        The link and description pointers are hereafter owned by
462  *              the hypertext list. The caller should not free or realloc
463  *              these pointers.
464  *
465  *****************************************************************************/
466 int
467 _DtLinkDbAddLink (
468     _DtCvLinkDb link_db,
469     char         *id,
470     char        *spec,
471     int          type,
472     int          hint,
473     char        *description)
474 {
475     int    i = GetNextEntry(link_db);
476
477     if (spec == NULL || 0 > i)
478         return -1;
479
480     /*
481      * copy the information
482      */
483     if (NULL != id)
484       {
485         id = strdup(id);
486         if (NULL == id)
487             return -1;
488       }
489
490     spec = strdup(spec);
491     if (NULL == spec)
492       {
493         if (NULL != id) free (id);
494         return -1;
495       }
496
497     if (NULL != description)
498       {
499         description = strdup(description);
500         if (NULL == description)
501           {
502             if (NULL != id) free (id);
503             free(spec);
504             return -1;
505           }
506       }
507
508     /*
509      * assign the link
510      */
511     link_db->list[i].type = _DtLinkTypeLink;
512     link_db->list[i].id   = id;
513
514     link_db->list[i].info.link.spec     = spec;
515     link_db->list[i].info.link.lnk_type = type;
516     link_db->list[i].info.link.hint     = hint;
517     link_db->list[i].info.link.descrip  = description;
518
519     return i;
520 }
521
522 /******************************************************************************
523  * Function:    void _DtLinkDbRemoveLink (link_index)
524  *
525  * Parameters:
526  *
527  * Returns:
528  *
529  * errno Values:
530  *
531  * Purpose:     Remove a hypertext link from the array.
532  *
533  *****************************************************************************/
534 void
535 _DtLinkDbRemoveLink (
536     _DtCvLinkDb link_db,
537     int         link_index )
538 {
539     if (link_index < link_db->max &&
540                         _DtLinkTypeNone != link_db->list[link_index].type)
541       {
542         if (NULL != link_db->list[link_index].id)
543             free(link_db->list[link_index].id);
544
545         if (_DtLinkTypeLink == link_db->list[link_index].type)
546           {
547             free(link_db->list[link_index].info.link.spec);
548             if (NULL != link_db->list[link_index].info.link.descrip)
549                 free(link_db->list[link_index].info.link.descrip);
550           }
551         else if (_DtLinkTypeSwitch == link_db->list[link_index].type)
552           {
553             free(link_db->list[link_index].info.swtch.interp);
554             free(link_db->list[link_index].info.swtch.cmd);
555             free(link_db->list[link_index].info.swtch.branches);
556           }
557
558         link_db->list[link_index].type = _DtLinkTypeNone;
559         link_db->list[link_index].id   = NULL;
560       }
561 }
562
563 /******************************************************************************
564  * Function:    int _DtLinkDbAddSwitch (
565  *
566  * Parameters:
567  *
568  * Returns:
569  *
570  * errno Values:
571  *
572  * Purpose:     Add a switch to the link database
573  *
574  *****************************************************************************/
575 int
576 _DtLinkDbAddSwitch (
577     _DtCvLinkDb link_db,
578     char        *id,
579     char        *interp,
580     char        *cmd,
581     char        *branches)
582 {
583     int    i = GetNextEntry(link_db);
584
585     if (NULL == id || NULL == interp || NULL == cmd
586                                                 || NULL == branches || 0 > i)
587         return -1;
588
589     /*
590      * copy the information
591      */
592     id     = strdup(id);
593     interp = strdup(interp);
594     cmd    = strdup(cmd);
595     branches = strdup(branches);
596
597     if (NULL == id || NULL == interp || NULL == cmd || NULL == branches)
598       {
599         if (NULL != id)       free(id);
600         if (NULL != interp)   free(interp);
601         if (NULL != cmd)      free(cmd);
602         if (NULL != branches) free(branches);
603         return -1;
604       }
605
606     link_db->list[i].type = _DtLinkTypeSwitch;
607     link_db->list[i].id   = id;
608
609     link_db->list[i].info.swtch.interp   = interp;
610     link_db->list[i].info.swtch.cmd      = cmd;
611     link_db->list[i].info.swtch.branches = branches;
612
613     return i;
614 }