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