1 /*----------------------------------------------------------------------------
2 //
3 //  Module:           xmubCustUtil
4 //
5 //  Project:          <>
6 //  System:           <>
7 //    Subsystem:      <>
8 //    Function block: <>
9 //
10 //  Description:
11 //    <>
12 //
13 //  Contents:
14 //    <>
15 //
16 //  Filename:         xmubCustUtil.c
17 //
18 //  Author:           Ulrika Bornetun
19 //  Creation date:    13.10.1994
20 //
21 //  Modifications:
22 //
23 //  Version / When / Who
24 //  What
25 //  --------------------------------------------
26 //  %StartLog%
27 //  %EndLog%
28 //
29 //
30 //  Copyright 1994 by Union Bank of Switzerland.
31 //
32 //  Permission to use, copy, modify, and distribute this software and its
33 //  documentation for any purpose and without fee is hereby granted,
34 //  provided that the above copyright notice appear in all copies.
35 //  Union Bank of Switzerland makes no representations about the usability
36 //  of this software for any purpose. It is provided "as is" without express
37 //  or implied warranty.
38 //--------------------------------------------------------------------------*/
39 
40 /* SCCS module identifier. */
41 #ifndef lint
42 static char SCCSID[] = "@(#) Module: xmubCustUtil.c, Version: 1.1, Date: 95/02/18 15:10:53";
43 #endif
44 
45 /*----------------------------------------------------------------------------
46 //  Include files
47 ----------------------------------------------------------------------------*/
48 
49 #ifdef VMS
50 #include ctype
51 #include stdlib
52 #include stdio
53 #include string
54 #include "xmubCustUtil.h"
55 
56 #else
57 #include <sys/types.h>
58 #include <unistd.h>
59 #include <stdlib.h>
60 #include <stdio.h>
61 #include <string.h>
62 #include <ctype.h>
63 
64 #include <xmubCustUtil.h>
65 
66 #endif
67 
68 
69 #include <X11/Shell.h>
70 
71 /* TEST */
72 /* #undef XlibSpecificationRelease */
73 /* #define XlibSpecificationRelease 4 */
74 
75 /*----------------------------------------------------------------------------
76 //  Macro definitions
77 ----------------------------------------------------------------------------*/
78 
79 /* Definitions used for the mapping file. */
80 #define RESMAP_FILE_NAME       "xresource.map"
81 #define MAP_FILE_NAME          "xresource"
82 #define MAP_FILE_SUFFIX        ".map"
83 #define MAP_FILE_DIRTYPE       "app-defaults"
84 #define XRESOURCE_MAP_FILE     "XRESOURCE_MAP_FILE"
85 
86 /* Defaults. */
87 #define DEFAULT_DELIMITERS     " "
88 
89 /* "Functions" */
90 #define Max( a, b )  ( ( a ) > ( b ) ? ( a ) : ( b ) )
91 
92 #ifdef VMS
93 #define unlink( filename )  delete( filename )
94 #endif
95 
96 #define BUFFER_LENGTH   200
97 
98 #if XlibSpecificationRelease < 5
99 #define XrmEnumAllLevels 0
100 #define XrmEnumOneLevel  1
101 #endif
102 
103 /*----------------------------------------------------------------------------
104 //  Type declarations
105 ----------------------------------------------------------------------------*/
106 
107 typedef struct
108 {
109   xmubResourceMappingInfoRef  info;
110   XrmQuark                    keyword_quark;
111   XrmQuark                    *sets;
112   int                         num_sets;
113   int                         set_list_length;
114 
115 } ListClassesInfo;
116 
117 #if XlibSpecificationRelease < 5
118 typedef void* XPointer;
119 #endif
120 
121 typedef Bool (*LoopDatabaseProc)
122 ( XrmDatabase*, XrmBindingList, XrmQuarkList, XrmRepresentation*,
123   XrmValue*, XPointer );
124 
125 /*
126 // The parameters for the LoopDatabaseProc function are the same as for
127 // the function called by XrmEnumerateDatabase in X11R5.
128 */
129 
130 
131 /*----------------------------------------------------------------------------
132 //  Global definitions
133 ----------------------------------------------------------------------------*/
134 
135 XrmOptionDescRec  xmub_options[] = {
136   { "-palette", "*palette", XrmoptionSepArg, NULL },
137   { "-fmap",    "*fmap",    XrmoptionSepArg, NULL },
138 };
139 
140 Cardinal  xmub_num_options = XtNumber( xmub_options );
141 
142 xmubAppResDesc  xmub_resource_sets[] = {
143   {  "palette", "Palette" },
144   {  "fmap",    "Fmap" } };
145 
146 Cardinal  xmub_num_resource_sets = XtNumber( xmub_resource_sets );
147 
148 /*----------------------------------------------------------------------------
149 //  Function prototypes
150 ----------------------------------------------------------------------------*/
151 
152 
153 static Bool
154   ExtractKeywordClass( XrmDatabase        *db,
155                        XrmBindingList     bindings,
156                        XrmQuarkList       quarks,
157                        XrmRepresentation  *type,
158                        XrmValue           *value,
159                        XPointer           closure );
160 
161 static Boolean
162   FileReadAccess( char*  file_name );
163 
164 static void
165   GetResourceValues( xmubResourceMappingInfoRef  info,
166                      xmubAppResDesc              resource_sets[],
167                      Cardinal                    num_resource_sets,
168                      char**                      values );
169 
170 static Bool
171   InsertGeneralMappingResources( XrmDatabase        *db,
172                                  XrmBindingList     bindings,
173                                  XrmQuarkList       quarks,
174                                  XrmRepresentation  *type,
175                                  XrmValue           *value,
176                                  XPointer           closure );
177 
178 static Bool
179   InsertSpecificMappingResources( XrmDatabase        *db,
180                                   XrmBindingList     bindings,
181                                   XrmQuarkList       quarks,
182                                   XrmRepresentation  *type,
183                                   XrmValue           *value,
184                                   XPointer           closure );
185 
186 static Bool
187   LoopThroughDatabase( XrmDatabase       db,
188                        XrmNameList       name_prefix,
189                        XrmClassList      class_prefix,
190                        int               unsupported,
191                        LoopDatabaseProc  proc,
192                        XPointer          client_data );
193   /*
194   // LoopThroughDatabase provides a simple XrmEnumerateDatabase
195   // functionality for X11R4.
196   // name_list and class_list only support lists of length 1.
197   */
198 
199 static Bool
200   ModifyKeywordResource( XrmDatabase        *db,
201                          XrmBindingList     bindings,
202                          XrmQuarkList       quarks,
203                          XrmRepresentation  *type,
204                          XrmValue           *value,
205                          XPointer           closure );
206 
207 static Bool
208   ModifySubstringResource( XrmDatabase        *db,
209                            XrmBindingList     bindings,
210                            XrmQuarkList       quarks,
211                            XrmRepresentation  *type,
212                            XrmValue           *value,
213                            XPointer           closure );
214 
215 static int
216   StringComp( const void  *s1,
217               const void  *s2 );
218 
219 
220 
221 /*----------------------------------------------------------------------------
222 //  Functions
223 ----------------------------------------------------------------------------*/
224 
225 static Bool
ExtractKeywordClass(XrmDatabase * db,XrmBindingList bindings,XrmQuarkList quarks,XrmRepresentation * type,XrmValue * value,XPointer closure)226   ExtractKeywordClass( XrmDatabase        *db,
227                        XrmBindingList     bindings,
228                        XrmQuarkList       quarks,
229                        XrmRepresentation  *type,
230                        XrmValue           *value,
231                        XPointer           closure )
232 {
233 
234   int              index;
235   int              length;
236   ListClassesInfo  *listinfo;
237 
238   /* Code. */
239 
240   listinfo = (ListClassesInfo *) closure;
241 
242   /* To be valid, we must have 2 quarks, and the 2nd must match our keyword.
243      In that case, the 1st is our candidate. */
244   for( length = 0; quarks[ length ] != NULLQUARK; length ++ );
245   if( length != 2 )
246     return( False );
247 
248   if( quarks[ 1 ] == listinfo -> keyword_quark ){
249     /* Insert the first one in the list. */
250 
251     /* Check for duplicates. */
252     for( index = 0; index < listinfo -> num_sets; index ++ ){
253       if( quarks[ 0 ] == listinfo -> sets[ index ] )
254         return( False );
255     }
256 
257     /* We can insert it. */
258     if( listinfo -> num_sets == listinfo -> set_list_length ){
259       ( listinfo -> set_list_length ) += 5;
260 
261       if( listinfo -> sets == NULL )
262         listinfo -> sets = (XrmQuark *) XtMalloc(
263           sizeof( XrmQuark ) * listinfo -> set_list_length );
264 
265       else
266         listinfo -> sets = (XrmQuark *) XtRealloc(
267           (char *) listinfo -> sets,
268           sizeof( XrmQuark ) * listinfo -> set_list_length );
269     }
270 
271     listinfo -> sets[ listinfo -> num_sets ] = quarks[ 0 ];
272     ( listinfo -> num_sets ) ++;
273 
274   }
275 
276 
277   return( False );
278 
279 }
280 
281 
282 /*----------------------------------------------------------------------*/
283 
284 static Boolean
FileReadAccess(char * file_name)285   FileReadAccess( char*  file_name )
286 {
287   /* This function is a replacement for the POSIX function access. */
288   FILE*  file;
289 
290   file = fopen( file_name, "r" );
291 
292   if( file == NULL )
293     return False;
294 
295   fclose( file );
296 
297   return True;
298 
299 }
300 
301 
302 /*----------------------------------------------------------------------*/
303 
304 static void
GetResourceValues(xmubResourceMappingInfoRef info,xmubAppResDesc resource_sets[],Cardinal num_resource_sets,char ** values)305   GetResourceValues( xmubResourceMappingInfoRef  info,
306                      xmubAppResDesc              resource_sets[],
307                      Cardinal                    num_resource_sets,
308                      char**                      values )
309 {
310   int       index;
311   int       length;
312   int       max_length;
313   Bool      ok;
314   char*     res_class;
315   char*     res_name;
316   char*     str_type_return;
317   XrmValue  value_return;
318 
319   /* Code. */
320 
321   /* Check max length of strings. */
322   for( index = 0, max_length = 0; index < num_resource_sets; index ++ ){
323 
324     /* Name. */
325     if( resource_sets[ index ].res_name != NULL )
326       length = strlen( resource_sets[ index ].res_name );
327     else
328       length = 0;
329 
330     max_length = Max( max_length, length );
331 
332     if( resource_sets[ index ].res_class != NULL )
333       length = strlen( resource_sets[ index ].res_class );
334     else
335       length = 0;
336 
337     max_length = Max( max_length, length );
338 
339   }
340 
341   res_name  = XtMalloc( max_length + strlen( info -> app_name ) + 5 );
342   res_class = XtMalloc( max_length + strlen( info -> app_class ) + 5 );
343 
344 
345   for( index = 0; index < num_resource_sets; index ++ ){
346     sprintf( res_name, "%s.%s", info -> app_name,
347              resource_sets[ index ].res_name );
348     sprintf( res_class, "%s.%s", info -> app_class,
349              resource_sets[ index ].res_class );
350 
351     ok = XrmGetResource( XtDatabase( info -> display ), res_name, res_class,
352                          &str_type_return, &value_return );
353 
354    if( ok )
355      values[ index ] = XtNewString( value_return.addr );
356    else
357      values[ index ] = NULL;
358 
359   }
360 
361   XtFree( res_name );
362   XtFree( res_class );
363 
364 }
365 
366 
367 /*----------------------------------------------------------------------*/
368 
369 static Bool
InsertGeneralMappingResources(XrmDatabase * db,XrmBindingList bindings,XrmQuarkList quarks,XrmRepresentation * type,XrmValue * value,XPointer closure)370   InsertGeneralMappingResources( XrmDatabase        *db,
371                                  XrmBindingList     bindings,
372                                  XrmQuarkList       quarks,
373                                  XrmRepresentation  *type,
374                                  XrmValue           *value,
375                                  XPointer           closure )
376 {
377 
378   xmubResourceMappingInfoRef  info;
379 
380   /* Code. */
381 
382   info = (xmubResourceMappingInfoRef) closure;
383 
384   /* The resource should just be inserted in the translation database. */
385   XrmQPutResource( &( info -> translation_db ), bindings,
386                    quarks, *type, value );
387 
388 
389   info -> selected = True;
390 
391 
392   return( False );
393 
394 }
395 
396 
397 /*----------------------------------------------------------------------*/
398 
399 static Bool
InsertSpecificMappingResources(XrmDatabase * db,XrmBindingList bindings,XrmQuarkList quarks,XrmRepresentation * type,XrmValue * value,XPointer closure)400   InsertSpecificMappingResources( XrmDatabase        *db,
401                                   XrmBindingList     bindings,
402                                   XrmQuarkList       quarks,
403                                   XrmRepresentation  *type,
404                                   XrmValue           *value,
405                                   XPointer           closure )
406 {
407 
408   xmubResourceMappingInfoRef  info;
409   int                         length;
410 
411   /* Code. */
412 
413   info = (xmubResourceMappingInfoRef) closure;
414 
415   /* Here we will get both general and specific resources. Select just
416      the ones that are specific. */
417   /* For specific resources, the quark list is longer than one item. */
418   for( length = 0; quarks[ length ] != NULLQUARK; length ++ );
419 
420   if( length > 1 ){
421 
422     char  *qs;
423     char  *res_spec;
424 
425     /* For the specific ones, we have to construct a string name. */
426     qs = XrmQuarkToString( quarks[ 1 ] );
427 
428     res_spec = (char *) XtMalloc( strlen( qs ) + 5 );
429     sprintf( res_spec, "*%s", qs );
430 
431     XrmPutResource( &( info -> translation_db ), res_spec,
432                     XrmRepresentationToString( *type ), value );
433     XtFree( res_spec );
434 
435     info -> selected = True;
436 
437   }
438 
439 
440   return( False );
441 
442 }
443 
444 
445 /*----------------------------------------------------------------------*/
446 
447 static Bool
LoopThroughDatabase(XrmDatabase db,XrmNameList name_prefix,XrmClassList class_prefix,int unsupported,LoopDatabaseProc proc,XPointer client_data)448   LoopThroughDatabase( XrmDatabase       db,
449                        XrmNameList       name_prefix,
450                        XrmClassList      class_prefix,
451                        int               unsupported,
452                        LoopDatabaseProc  proc,
453                        XPointer          client_data )
454 {
455 
456   XrmBindingList  binding_list;
457   char            buffer[ BUFFER_LENGTH ];
458   FILE            *db_file;
459   char            db_filename[ L_tmpnam + 1 ];
460   int             index;
461   int             length;
462   int             num_bindings;
463   XrmQuarkList    quark_list;
464   Boolean         selected;
465   int             start_index;
466   XrmQuark        string_rep;
467   Bool            terminate = False;
468   XrmValue        value;
469   XrmQuark        wildcard_quark;
470 
471   /* Code. */
472 
473   /* Dump the database to a file. */
474   (void) tmpnam( db_filename );
475   XrmPutFileDatabase( db, db_filename );
476 
477   db_file = fopen( db_filename, "r" );
478 
479   string_rep     = XrmStringToRepresentation( "String" );
480   wildcard_quark = XrmStringToQuark( "*" );
481 
482 
483   /* Read the resource specifications. */
484   while( fgets( buffer, BUFFER_LENGTH, db_file ) != NULL ){
485 
486     /* Split resource definition from value. */
487     length = strcspn( buffer, ":" );
488 
489     if( length == 0 )
490       continue;
491 
492     buffer[ length ] = '\0';
493 
494     for( num_bindings = 0, index = 0; buffer[ index ] != '\0'; index ++ ){
495       if( ( buffer[ index ] == '*' ) || ( buffer[ index ] == '.' ) )
496         num_bindings ++;
497     }
498 
499 
500     binding_list =
501       (XrmBindingList) XtMalloc( ( num_bindings + 3 ) * sizeof( XrmBinding ) );
502     quark_list =
503       (XrmQuarkList) XtMalloc( ( num_bindings + 3 ) * sizeof( XrmQuark ) );
504 
505     XrmStringToBindingQuarkList( buffer, binding_list, quark_list );
506 
507     /* Find the start of the value. */
508     for( start_index = length + 1;
509          ( buffer[ start_index ] != '\0' ) && isspace( buffer[ start_index ] );
510          start_index ++ );
511 
512     value.addr = (XPointer) &( buffer[ start_index ] );
513     value.size = strlen( &( buffer[ start_index ] ) );
514 
515     /* Mask away trailing newline and spaces. */
516     while( ( value.size > 0 ) &&
517            isspace( *( (char *) value.addr + value.size - 1 ) ) )
518       value.size --;
519     *( (char *) value.addr + value.size ) = '\0';
520     value.size ++;
521 
522     /* Check if selected. */
523     selected = False;
524 
525     if( ( name_prefix == NULL ) || ( class_prefix == NULL ) )
526       selected = True;
527     else if( ( name_prefix[ 0 ] == wildcard_quark ) ||
528              ( class_prefix[ 0 ] == wildcard_quark ) ){
529       /* Select if specification starts with "*". */
530       if( buffer[ 0 ] == '*' )
531         selected = True;
532 
533     } else {
534       /* The first quark must match name or class quark, or we must start
535          with '*'. */
536       if( buffer[ 0 ] == '*' )
537         selected = True;
538 
539       else {
540         if( ( name_prefix[ 0 ] == quark_list[ 0 ] ) ||
541             ( class_prefix[ 0 ] == quark_list[ 0 ] ) )
542           selected = True;
543       }
544     }
545 
546     if( selected )
547       terminate = (* ( proc ) ) ( &db, binding_list, quark_list, &string_rep,
548                                   &value, client_data );
549 
550 
551     XtFree( (char *) binding_list );
552     XtFree( (char *) quark_list );
553 
554     if( terminate )
555       break;
556 
557   }
558 
559   fclose( db_file );
560   unlink( db_filename );
561 
562 
563   return terminate;
564 
565 }
566 
567 
568 /*----------------------------------------------------------------------*/
569 
570 static Bool
ModifyKeywordResource(XrmDatabase * db,XrmBindingList bindings,XrmQuarkList quarks,XrmRepresentation * type,XrmValue * value,XPointer closure)571   ModifyKeywordResource( XrmDatabase        *db,
572                          XrmBindingList     bindings,
573                          XrmQuarkList       quarks,
574                          XrmRepresentation  *type,
575                          XrmValue           *value,
576                          XPointer           closure )
577 {
578 
579   Bool                        bok;
580   Boolean                     found;
581   int                         index;
582   xmubResourceMappingInfoRef  info;
583   int                         length;
584   Bool                        ok;
585   String                      res_class;
586   String                      res_name;
587   char                        *str_type_return;
588   XrmValue                    value_return;
589 
590   /* Code. */
591 
592   info = (xmubResourceMappingInfoRef) closure;
593 
594 
595   /* If the value is a token that has a mapping, it should be replaced
596      with the mapping. */
597 
598   /* Only for string resources. */
599   if( *type == info -> string_quark ){
600 
601     /* Check number of quarks. */
602     for( length = 0; quarks[ length ] != NULLQUARK; length ++ );
603 
604     if( info -> specific && ( length == 1 ) )
605       /* This is a general specification. */
606       return( False );
607 
608     /* If a resource selection has been defined, pick the ones we need. */
609     if( info -> num_selections > 0 ){
610 
611       found = False;
612 
613       for( index = 0; index < info -> num_selections; index ++ ){
614         if( info -> selection[ index ] == quarks[ length - 1 ] ){
615           found = True;
616           break;
617         }
618       }
619 
620       if( ( found && !info -> inclusive_selection ) ||
621           ( !found && info -> inclusive_selection ) )
622         return( False );
623     }
624 
625 
626 
627     /* Allocate storage for keyword search. */
628     res_name  = (char *) XtMalloc( strlen( info -> app_name ) +
629                                    value -> size + 5 );
630     res_class = (char *) XtMalloc( strlen( info -> app_class ) +
631                                    value -> size + 5 );
632 
633     /* Check if the token has a mapping. */
634     sprintf( res_name, "%s.", info -> app_name );
635     strncat( res_name, (char *) value -> addr, value -> size );
636     res_name[ strlen( info -> app_name ) + value -> size + 1 ] = '\0';
637 
638     sprintf( res_class, "%s.", info -> app_class );
639     strncat( res_class, (char *) value -> addr, value -> size );
640     res_class[ strlen( info -> app_class ) + value -> size + 1 ] = '\0';
641 
642     ok = XrmGetResource( info -> translation_db, res_name, res_class,
643                          &str_type_return, &value_return );
644 
645     if( ok ){
646       /* We have a translation. */
647 
648       XrmQPutResource( &( info -> merge_db ), bindings, quarks,
649                        XrmStringToRepresentation( str_type_return ),
650                        &value_return );
651 
652       /* Save original string if required. */
653       if( info -> save_in_orig )
654         XrmQPutResource( &( info -> orig_db ), bindings, quarks,
655                          *type, value );
656 
657     } else if( info -> replace_substrings ){
658       /* No match for whole keyword, but check if substring matches. */
659 
660       XrmQuark  class_list[ 3 ];
661       XrmQuark  name_list[ 3 ];
662 
663       name_list[ 0 ] = XrmStringToQuark( info -> app_name );
664       name_list[ 1 ] = XrmStringToQuark( "_FontLists_" );
665       name_list[ 2 ] = NULLQUARK;
666 
667       class_list[ 0 ] = XrmStringToQuark( info -> app_class );
668       class_list[ 1 ] = XrmStringToQuark( "_FontLists_" );
669       class_list[ 2 ] = NULLQUARK;
670 
671       info -> replaced = False;
672       info -> value    = XtMalloc( value -> size + 1 );
673       strncpy( info -> value, (char *) value -> addr, value -> size );
674       info -> value[ value -> size ] = '\0';
675 
676 #if XlibSpecificationRelease > 4
677       bok = XrmEnumerateDatabase(
678 #else
679       bok = LoopThroughDatabase(
680 #endif
681         info -> translation_db, name_list, class_list,
682         XrmEnumAllLevels, ModifySubstringResource, (XPointer) info );
683 
684       if( info -> replaced ){
685         XrmQPutStringResource( &( info -> merge_db ), bindings, quarks,
686                                info -> value );
687 
688         /* Save original string if required. */
689         if( info -> save_in_orig )
690           XrmQPutResource( &( info -> orig_db ), bindings, quarks,
691                            *type, value );
692       }
693 
694       XtFree( info -> value );
695 
696     }
697 
698     XtFree( res_name );
699     XtFree( res_class );
700   }
701 
702 
703   return( False );
704 
705 } /* ModifyKeywordResource */
706 
707 
708 /*----------------------------------------------------------------------*/
709 
710 static Bool
ModifySubstringResource(XrmDatabase * db,XrmBindingList bindings,XrmQuarkList quarks,XrmRepresentation * type,XrmValue * value,XPointer closure)711   ModifySubstringResource( XrmDatabase        *db,
712                            XrmBindingList     bindings,
713                            XrmQuarkList       quarks,
714                            XrmRepresentation  *type,
715                            XrmValue           *value,
716                            XPointer           closure )
717 {
718 
719   xmubResourceMappingInfoRef  info;
720   int                         key_length;
721   char*                       keyword;
722   int                         length;
723   char*                       start_ptr;
724   int                         tok_index;
725   char*                       tok_start;
726 
727   /* Code. */
728 
729   info = (xmubResourceMappingInfoRef) closure;
730 
731 
732   /* Check if the substring is present in the value. */
733   /* The keyword is in the last quark. */
734   for( length = 0; quarks[ length ] != NULLQUARK; length ++ );
735 
736   keyword    = XrmQuarkToString( quarks[ length - 1 ] );
737   key_length = strlen( keyword );
738 
739 
740   start_ptr = info -> value;
741 
742   while( start_ptr < ( info -> value + value -> size ) ){
743 
744     if( ( tok_start = strstr( start_ptr, keyword ) ) != NULL ){
745 
746       tok_index = (int) ( tok_start - start_ptr );
747 
748       /* Check if the substring is delimited by the correct characters. */
749       if( ( ( tok_index == 0 ) ||
750             ( strchr( info -> substring_delimiters,
751                       info -> value[ tok_index - 1 ] ) != NULL ) ) &&
752           ( ( strlen( tok_start ) == key_length ) ||
753             ( strchr( info -> substring_delimiters,
754                       info -> value[ tok_index + key_length ] ) != NULL ) ) ){
755 
756         /* Ok. Replace the substring. */
757         /* The translation is in value. */
758 
759         if( value -> size - 1 == key_length )
760           strncpy( tok_start, (char *) value -> addr, value -> size - 1 );
761 
762         else if( value -> size - 1 < key_length ){
763           strncpy( tok_start, (char *) value -> addr, value -> size - 1 );
764           memmove( (void *) &( info -> value[ tok_index +
765                                               value -> size - 1 ] ),
766                    (void *) &( info -> value[ tok_index + key_length ] ),
767                    strlen( &( info -> value[ tok_index + key_length ] ) ) +
768                    1 );
769 
770         } else {
771           /* The replacement is longer, so we need to extend the string. */
772           info -> value = XtRealloc( info -> value,
773                                      strlen( info -> value ) + value -> size );
774 
775           memmove( (void *) &( info -> value[ tok_index +
776                                               value -> size - 1 ] ),
777                    (void *) &( info -> value[ tok_index + key_length ] ),
778                    strlen( &( info -> value[ tok_index + key_length ] ) ) +
779                    1 );
780           strncpy( &( info -> value[ tok_index ] ), (char *) value -> addr,
781                    value -> size - 1 );
782         }
783 
784 
785         info -> replaced = True;
786       }
787 
788       start_ptr = tok_start + key_length;
789 
790 
791     } else
792       /* The substring did not occur. */
793       break;
794 
795   }
796 
797 
798   return( False );
799 
800 } /* ModifySubstringResource */
801 
802 
803 /*----------------------------------------------------------------------*/
804 
805 static int
StringComp(const void * s1,const void * s2)806   StringComp( const void  *s1,
807               const void  *s2 )
808 {
809 
810   String  *str1;
811   String  *str2;
812 
813   /* Code. */
814 
815   str1 = (String *) s1;
816   str2 = (String *) s2;
817 
818 
819 #ifdef VMS
820   return( strcmp( *str1, *str2 ) );
821 #else
822   return( strcoll( *str1, *str2 ) );
823 #endif
824 
825 } /* StringComp */
826 
827 
828 /*----------------------------------------------------------------------*/
829 
830 Boolean
xmubResAddMapFile(xmubResourceMappingInfoRef info,char * file_name,Boolean add_defaults,xmubAppResDesc resource_sets[],Cardinal num_resource_sets)831 xmubResAddMapFile( xmubResourceMappingInfoRef  info,
832                    char*                       file_name,
833                    Boolean                     add_defaults,
834                    xmubAppResDesc              resource_sets[],
835                    Cardinal                    num_resource_sets )
836 {
837 
838   Boolean      allocated_file_name = False;
839   XrmDatabase  file_db;
840   Boolean      ok;
841 
842   /* Code. */
843 
844   if( file_name == NULL ){
845     file_name = xmubResGetMappingFileName( info -> display );
846     allocated_file_name = True;
847   }
848 
849   if( file_name == NULL )
850     return False;
851 
852   /* Read the contents of the file into a temporary database. */
853   /* The function also tests if the file is accessible. */
854   if( ( file_db = XrmGetFileDatabase( file_name ) ) == NULL )
855     return( False );
856 
857   ok = xmubResAddMappings( info, file_db, add_defaults,
858                            resource_sets, num_resource_sets );
859 
860 
861   if( allocated_file_name )
862     XtFree( file_name );
863 
864 
865   /* Save the mapping base in the mapping database.
866      file_db is automatically destroyed. */
867   XrmMergeDatabases( file_db, &( info -> mapping_db ) );
868 
869 
870   return( ok );
871 
872 }
873 
874 
875 /*----------------------------------------------------------------------*/
876 
877 Boolean
xmubResAddMappings(xmubResourceMappingInfoRef info,XrmDatabase db,Boolean add_defaults,xmubAppResDesc resource_sets[],Cardinal num_resource_sets)878 xmubResAddMappings( xmubResourceMappingInfoRef  info,
879                     XrmDatabase                 db,
880                     Boolean                     add_defaults,
881                     xmubAppResDesc              resource_sets[],
882                     Cardinal                    num_resource_sets )
883 {
884 
885   Bool      bok;
886   int       index;
887   XrmQuark  name_list[ 2 ];
888 
889   /* Code. */
890 
891   info -> selected = False;
892 
893   /* Add the general resource specifications. */
894   if( add_defaults ){
895 
896     name_list[ 0 ] = XrmStringToQuark( "*" );
897     name_list[ 1 ] = NULLQUARK;
898 
899     info -> specific = False;
900 
901 #if XlibSpecificationRelease > 4
902     bok = XrmEnumerateDatabase(
903 #else
904     bok = LoopThroughDatabase(
905 #endif
906       db, name_list, name_list, XrmEnumAllLevels,
907       InsertGeneralMappingResources, (XPointer) info );
908   }
909 
910 
911   /* Specific resources from sets. */
912   if( num_resource_sets > 0 ){
913 
914     char**  values;
915 
916     /* Extract the values for the defined resource sets. */
917     values = (char **) XtMalloc( sizeof( char *) * num_resource_sets );
918     GetResourceValues( info, resource_sets, num_resource_sets, values );
919 
920     info -> specific = True;
921 
922     /* For some reason, we must call for the different options separately. */
923     for( index = 0; index < num_resource_sets; index ++ ){
924 
925       if( values[ index ] != NULL ){
926         name_list[ 0 ] = XrmStringToQuark( values[ index ] );
927         name_list[ 1 ] = NULLQUARK;
928 
929 #if XlibSpecificationRelease > 4
930         bok = XrmEnumerateDatabase(
931 #else
932         bok = LoopThroughDatabase(
933 #endif
934           db, name_list, name_list, XrmEnumAllLevels,
935           InsertSpecificMappingResources, (XPointer) info );
936       }
937 
938     }
939 
940     for( index = 0; index < num_resource_sets; index ++ )
941       if( values[ index ] != NULL )
942         XtFree( values[ index ] );
943 
944     XtFree( (char  *) values );
945 
946   }
947 
948   return info -> selected;
949 
950 }
951 
952 
953 /*----------------------------------------------------------------------*/
954 
955 void
xmubResAddSetChangedCallback(xmubResourceMappingInfoRef info,xmubResSetChangeCallback callback,XtPointer client_data)956 xmubResAddSetChangedCallback( xmubResourceMappingInfoRef  info,
957                               xmubResSetChangeCallback    callback,
958                               XtPointer                   client_data )
959 {
960   /* Code. */
961 
962   info -> num_set_change_callbacks ++;
963 
964   /* Extend the list. */
965   if( info -> num_set_change_callbacks == 1 )
966     info -> set_change_callbacks = (xmubResSetChangeCallbackList)
967       XtMalloc( sizeof( xmubResSetChangeCallbackRec ) );
968 
969   else
970     info -> set_change_callbacks = (xmubResSetChangeCallbackList)
971       XtRealloc( (char *) info -> set_change_callbacks,
972                  sizeof( xmubResSetChangeCallbackRec ) *
973                  info -> num_set_change_callbacks );
974 
975   /* Insert the information. */
976   info -> set_change_callbacks[
977     info -> num_set_change_callbacks - 1 ].callback = callback;
978   info -> set_change_callbacks[
979     info -> num_set_change_callbacks - 1 ].client_data = client_data;
980 
981 }
982 
983 
984 /*----------------------------------------------------------------------*/
985 
986 void
xmubResAddStringMapping(xmubResourceMappingInfoRef info,char * keyword,char * translation)987 xmubResAddStringMapping( xmubResourceMappingInfoRef  info,
988                          char*                       keyword,
989                          char*                       translation )
990 {
991   char*  specifier;
992 
993   /* Code. */
994 
995   specifier = XtMalloc( strlen( keyword ) + 2 );
996   sprintf( specifier, "*%s", keyword );
997 
998   XrmPutStringResource( &( info -> mapping_db ), specifier, translation );
999   XrmPutStringResource( &( info -> translation_db ), specifier, translation );
1000 
1001   XtFree( specifier );
1002 
1003 }
1004 
1005 
1006 /*----------------------------------------------------------------------*/
1007 
1008 Widget
xmubAppInitialize(XtAppContext * app_context_return,String application_class,XrmOptionDescList options,Cardinal num_options,Cardinal * argc_in_out,String * argv_in_out,String * fallback_resources,ArgList args,Cardinal num_args,xmubAppResDesc * resource_sets,Cardinal num_resource_sets,xmubResourceMappingInfoRef * ref_return)1009   xmubAppInitialize( XtAppContext                *app_context_return,
1010                      String                      application_class,
1011                      XrmOptionDescList           options,
1012                      Cardinal                    num_options,
1013                      Cardinal                    *argc_in_out,
1014                      String                      *argv_in_out,
1015                      String                      *fallback_resources,
1016                      ArgList                     args,
1017                      Cardinal                    num_args,
1018                      xmubAppResDesc              *resource_sets,
1019                      Cardinal                    num_resource_sets,
1020                      xmubResourceMappingInfoRef  *ref_return )
1021 {
1022 
1023   XtAppContext                app;
1024   Display                     *display;
1025   Arg                         iargs[ 5 ];
1026   int                         index;
1027   xmubResourceMappingInfoRef  info;
1028   Cardinal                    n;
1029   Cardinal                    orig_argc;
1030   String                      *orig_argv = NULL;
1031   Widget                      toplevel;
1032 
1033   /* Code. */
1034 
1035   /* Make a copy of the original arguments. */
1036   orig_argc = *argc_in_out;
1037 
1038   if( orig_argc > 0 ){
1039     orig_argv = (char**) XtMalloc( sizeof( char* ) * orig_argc );
1040 
1041     for( index = 0; index < orig_argc; index++ )
1042       orig_argv[ index ] = XtNewString( argv_in_out[ index ] );
1043   }
1044 
1045   /* Initialize the application. */
1046   XtToolkitInitialize();
1047   app = XtCreateApplicationContext();
1048 
1049   /* Fallback resources. */
1050   if( fallback_resources != NULL )
1051     XtAppSetFallbackResources( app, fallback_resources );
1052 
1053   /* Open the display. */
1054   display = XtOpenDisplay( app, NULL, NULL, application_class,
1055                            options, num_options,
1056                            (int *) argc_in_out, argv_in_out );
1057 
1058   xmubInitResourceMapping( display, resource_sets, num_resource_sets, &info );
1059 
1060   /* Create the shell. */
1061   n = 0;
1062   XtSetArg( iargs[ n ], XtNargc, orig_argc ); n++;
1063   XtSetArg( iargs[ n ], XtNargv, orig_argv ); n++;
1064   toplevel = XtAppCreateShell( NULL, application_class,
1065                                applicationShellWidgetClass,
1066                                display, iargs, n );
1067 
1068   /* We don't have to free argv. */
1069 
1070   /* Set the arguments on the shell. */
1071   XtSetValues( toplevel, args, num_args );
1072 
1073 
1074   /* Set returned values. */
1075   if( app_context_return != NULL )
1076     *app_context_return = app;
1077 
1078   if( ref_return != NULL )
1079     *ref_return = info;
1080   else
1081     xmubResFreeInfo( info );
1082 
1083 
1084   return( toplevel );
1085 
1086 }
1087 
1088 
1089 /*----------------------------------------------------------------------*/
1090 
1091 void
xmubInitResourceMapping(Display * display,xmubAppResDesc resource_sets[],Cardinal num_resource_sets,xmubResourceMappingInfoRef * res_info)1092 xmubInitResourceMapping( Display*                    display,
1093                          xmubAppResDesc              resource_sets[],
1094                          Cardinal                    num_resource_sets,
1095                          xmubResourceMappingInfoRef  *res_info )
1096 {
1097 
1098   xmubResourceMappingInfoRef  info;
1099   Boolean                     ok;
1100 
1101   /* Code. */
1102 
1103   /* Initialize out parameter. */
1104   if( res_info != NULL )
1105     *res_info = NULL;
1106 
1107   /* Initialize. */
1108   info = xmubResInitialize( display );
1109   if( info == NULL )
1110     return;
1111 
1112   /* Add mappings from the default file. */
1113   ok = xmubResAddMapFile( info, NULL, True, resource_sets, num_resource_sets );
1114   if( ! ok ){
1115     xmubResFreeInfo( info );
1116     return;
1117   }
1118 
1119   /* Replace the keywords. */
1120   xmubResReplace( info, NULL );
1121 
1122   /* Merge the translations into the display database. */
1123   xmubResMergeMappedResources( info, NULL );
1124 
1125   if( res_info != NULL )
1126     *res_info = info;
1127   else
1128     xmubResFreeInfo( info );
1129 
1130 }
1131 
1132 
1133 /*----------------------------------------------------------------------*/
1134 
1135 void
xmubResClearInternalDatabases(xmubResourceMappingInfoRef info,Boolean clear_orig_db,Boolean clear_mapping_db,Boolean clear_translation_db,Boolean clear_merge_db)1136 xmubResClearInternalDatabases(
1137   xmubResourceMappingInfoRef  info,
1138   Boolean                     clear_orig_db,
1139   Boolean                     clear_mapping_db,
1140   Boolean                     clear_translation_db,
1141   Boolean                     clear_merge_db )
1142 {
1143 
1144   /* Code. */
1145 
1146   if( clear_orig_db ){
1147     XrmDestroyDatabase( info -> orig_db );
1148     info -> orig_db = NULL;
1149   }
1150 
1151   if( clear_mapping_db ){
1152     XrmDestroyDatabase( info -> mapping_db );
1153     info -> mapping_db = NULL;
1154   }
1155 
1156   if( clear_translation_db ){
1157     XrmDestroyDatabase( info -> translation_db );
1158     info -> translation_db = NULL;
1159   }
1160 
1161   if( clear_merge_db ){
1162     XrmDestroyDatabase( info -> merge_db );
1163     info -> merge_db = NULL;
1164   }
1165 }
1166 
1167 
1168 /*----------------------------------------------------------------------*/
1169 
1170 void
xmubResFreeInfo(xmubResourceMappingInfoRef info)1171 xmubResFreeInfo( xmubResourceMappingInfoRef  info )
1172 {
1173 
1174   /* Code. */
1175 
1176   /* Destroy the databases. */
1177   xmubResClearInternalDatabases( info, True, True, True, True );
1178 
1179   /* Free allocated strings. */
1180   XtFree( info -> app_name );
1181   XtFree( info -> app_class );
1182 
1183   /* Temporary fields must be freed by the allocator. */
1184 
1185   /* Free the record itself. */
1186   XtFree( (char *) info );
1187 
1188 }
1189 
1190 
1191 /*----------------------------------------------------------------------*/
1192 
1193 #ifdef VMS
1194 char*
xmubResGetMappingFileName(Display * display)1195 xmubResGetMappingFileName( Display  *display )
1196 {
1197 
1198   /* VMS version. */
1199 
1200   String   app_class;
1201   Boolean  class_file;
1202   String   filename = NULL;
1203   String   fname;
1204   String   env;
1205   String   name;
1206 
1207   /* Code. */
1208 
1209   /* Start by trying the environment variable. */
1210   env = getenv( XRESOURCE_MAP_FILE );
1211   if( ( env != NULL ) && FileReadAccess( env ) ){
1212     filename = XtNewString( env );
1213     return( filename );
1214   }
1215 
1216   /* File not accessible via environment variable. */
1217   /* Look for file with the name "app-class".map in all paths.
1218      If not found, look for default file "xresource.map" in the same paths. */
1219 
1220   XtGetApplicationNameAndClass( display, &name, &app_class );
1221 
1222 
1223   class_file = True;
1224 
1225   for( ;; ){
1226 
1227     if( class_file )
1228       fname = app_class;
1229     else
1230       fname = MAP_FILE_NAME;
1231 
1232     /* Try user defaults. */
1233     filename = (String) XtMalloc( strlen( fname ) + 30 );
1234     sprintf( filename, "DECW$USER_DEFAULTS:%s%s", fname, MAP_FILE_SUFFIX );
1235 
1236     if( FileReadAccess( filename ) )
1237       return( filename );
1238 
1239     /* Try system defaults. */
1240     sprintf( filename, "DECW$SYSTEM_DEFAULTS:%s%s", fname, MAP_FILE_SUFFIX );
1241 
1242     if( FileReadAccess( filename ) )
1243       return( filename );
1244     else
1245       XtFree( filename );
1246 
1247     /* Try local directory. */
1248     sprintf( filename, "%s%s", fname, MAP_FILE_SUFFIX );
1249 
1250     if( FileReadAccess( filename ) )
1251       return( filename );
1252     else
1253       XtFree( filename );
1254 
1255     /* Second round checks for general file. */
1256     if( class_file )
1257       class_file = False;
1258     else
1259       break;
1260 
1261   }
1262 
1263 
1264   return( NULL );
1265 
1266 }
1267 
1268 #else
1269 
1270 
1271 /*----------------------------------------------------------------------*/
1272 
1273 char*
xmubResGetMappingFileName(Display * display)1274 xmubResGetMappingFileName( Display  *display )
1275 {
1276 
1277   /* Unix version. */
1278 
1279   String   app_class;
1280   Boolean  class_file;
1281   String   filename = NULL;
1282   String   fname;
1283   String   env;
1284   String   homedir = NULL;
1285   String   name;
1286   String   path = NULL;
1287 
1288   /* Code. */
1289 
1290   /* Start by trying the environment variable. */
1291   env = getenv( XRESOURCE_MAP_FILE );
1292   if( ( env != NULL ) && FileReadAccess( env ) ){
1293     filename = XtNewString( env );
1294     return( filename );
1295   }
1296 
1297   /* File not accessible via environment variable. */
1298   /* Look for file with the name "app-class".map in all paths.
1299      If not found, look for default file "xresource.map" in the same paths. */
1300 
1301   XtGetApplicationNameAndClass( display, &name, &app_class );
1302 
1303 
1304   class_file = True;
1305 
1306   for( ;; ){
1307 
1308     if( class_file )
1309       fname = app_class;
1310     else
1311       fname = MAP_FILE_NAME;
1312 
1313     /* Try user file search path. */
1314     env = getenv( "XUSERFILESEARCHPATH" );
1315     if( env != NULL ){
1316       /* Copy path so it is not overwritten. */
1317       path = XtNewString( env );
1318 
1319       filename = XtResolvePathname( display, MAP_FILE_DIRTYPE, fname,
1320                                     MAP_FILE_SUFFIX, path,
1321                                     (Substitution) NULL, 0,
1322                                     (XtFilePredicate) NULL );
1323 
1324       XtFree( path );
1325       path = NULL;
1326 
1327       if( ( filename != NULL ) && FileReadAccess( filename ) )
1328         return( filename );
1329       else if( filename != NULL )
1330         XtFree( filename );
1331     }
1332 
1333     /* Try application resource directory or home directory. */
1334     homedir = getenv( "HOME" );
1335 
1336     env = getenv( "XAPPLRESDIR" );
1337     if( env != NULL ){
1338 
1339       /* Construct path containing appl res dir. */
1340       path = (String) XtMalloc( strlen( env ) * 3 +
1341                                 ( homedir != NULL ? strlen( homedir ) : 0 ) +
1342                                 40 );
1343       if( homedir != NULL )
1344         sprintf( path, "%s%s:%s%s:%s%s:%s%s:.",
1345                        env, "/%L/%N/%S", env, "/%l/%N%S", env, "/%N%S",
1346                        homedir, "/%N%S" );
1347       else
1348         sprintf( path, "%s%s:%s%s:%s%s:.",
1349                        env, "/%L/%N/%S", env, "/%l/%N%S", env, "/%N%S" );
1350 
1351     } else if( homedir != NULL ){
1352       /* XAPPLRESDIR was not defined. Use path with home directory. */
1353       path = (String) XtMalloc( strlen( homedir ) * 3 + 25 );
1354       sprintf( path, "%s%s:%s%s:%s%s:.",
1355                      homedir, "/%L/%N%S", homedir, "/%l%N%S",
1356                      homedir, "/%N%S" );
1357     }
1358 
1359     if( path != NULL ){
1360       filename = XtResolvePathname( display, MAP_FILE_DIRTYPE, fname,
1361                                     MAP_FILE_SUFFIX, path,
1362                                     (Substitution) NULL, 0,
1363                                     (XtFilePredicate) NULL );
1364       XtFree( path );
1365     }
1366 
1367     if( ( filename != NULL ) && FileReadAccess( filename ) )
1368       return( filename );
1369     else if( filename != NULL )
1370       XtFree( filename );
1371 
1372 
1373     /* Last chance is the system default path. */
1374     filename = XtResolvePathname( display, MAP_FILE_DIRTYPE, fname,
1375                                   MAP_FILE_SUFFIX, NULL,
1376                                   (Substitution) NULL, 0,
1377                                   (XtFilePredicate) NULL );
1378 
1379     if( ( filename != NULL ) && FileReadAccess( filename ) )
1380       return( filename );
1381     else if( filename != NULL )
1382       XtFree( filename );
1383 
1384 
1385     /* Second round checks for general file. */
1386     if( class_file )
1387       class_file = False;
1388     else
1389       break;
1390   }
1391 
1392 
1393   /* If we had found a file we would have returned by now. */
1394 
1395   return( NULL );
1396 
1397 }
1398 #endif
1399 
1400 /*----------------------------------------------------------------------*/
1401 
1402 xmubResourceMappingInfoRef
xmubResInitialize(Display * display)1403 xmubResInitialize( Display*  display )
1404 {
1405 
1406   char*          app_class;
1407   char*          app_name;
1408   xmubResourceMappingInfoRef  info;
1409 
1410   /* Code. */
1411 
1412   info = (xmubResourceMappingInfoRef) XtMalloc(
1413     sizeof( xmubResourceMappingInfo ) );
1414 
1415   XtGetApplicationNameAndClass( display, &app_name, &app_class );
1416 
1417   /* Copy the name and class of the application. */
1418   info -> app_name  = XtNewString( app_name );
1419   info -> app_class = XtNewString( app_class );
1420 
1421   /* Set the database entries to NULL. */
1422   info -> orig_db         = NULL;
1423   info -> mapping_db      = NULL;
1424   info -> translation_db  = NULL;
1425   info -> merge_db        = NULL;
1426 
1427   info -> display = display;
1428 
1429   info -> string_quark = XrmStringToQuark( "String" );
1430 
1431   info -> set_change_callbacks     = NULL;
1432   info -> num_set_change_callbacks = 0;
1433 
1434 
1435   return( info );
1436 
1437 }
1438 
1439 
1440 /*----------------------------------------------------------------------*/
1441 
1442 char**
xmubResListClasses(xmubResourceMappingInfoRef info,char * keyword,Boolean sorted,XrmDatabase db)1443 xmubResListClasses( xmubResourceMappingInfoRef  info,
1444                     char*                       keyword,
1445                     Boolean                     sorted,
1446                     XrmDatabase                 db )
1447 {
1448 
1449   Bool             bok;
1450   char**           class_table;
1451   int              index;
1452   ListClassesInfo  listinfo;
1453 
1454   /* Code. */
1455 
1456   if( db == NULL )
1457     db = info -> mapping_db;
1458 
1459   if( db == NULL )
1460     return NULL;
1461 
1462   /* Loop through all resources. */
1463   listinfo.info            = info;
1464   listinfo.keyword_quark   = XrmStringToQuark( keyword );
1465   listinfo.sets            = NULL;
1466   listinfo.num_sets        = 0;
1467   listinfo.set_list_length = 0;
1468 
1469   /* XrmEnumerateDatabase cannot handle NULL parameters for name_list
1470      and class_list, but LoopThroughDatabase can!! */
1471   bok = LoopThroughDatabase(
1472     db, NULL, NULL, XrmEnumAllLevels, ExtractKeywordClass,
1473     (XPointer) &listinfo );
1474 
1475   if( listinfo.num_sets > 0 ){
1476     class_table = (char **) XtMalloc( sizeof( char* ) *
1477                                       ( listinfo.num_sets + 1 ) );
1478 
1479     for( index = 0; index < listinfo.num_sets; index ++ )
1480       class_table[ index ] =
1481         XtNewString( XrmQuarkToString( listinfo.sets[ index ] ) );
1482 
1483     class_table[ listinfo.num_sets ] = NULL;
1484 
1485   } else
1486     class_table = NULL;
1487 
1488   if( listinfo.sets != NULL )
1489     XtFree( (char *) listinfo.sets );
1490 
1491 
1492   /* Sort the table. */
1493   if( sorted && ( class_table != NULL ) )
1494     qsort( (void *) class_table, (size_t) listinfo.num_sets,
1495            (size_t) sizeof( char* ), StringComp );
1496 
1497 
1498   return( class_table );
1499 
1500 }
1501 
1502 
1503 /*----------------------------------------------------------------------*/
1504 
1505 void
xmubResMergeMappedResources(xmubResourceMappingInfoRef info,XrmDatabase target_db)1506 xmubResMergeMappedResources( xmubResourceMappingInfoRef  info,
1507                              XrmDatabase                 target_db )
1508 {
1509   /* Code. */
1510 
1511   if( target_db == NULL )
1512     target_db = XtDatabase( info -> display );
1513 
1514   /* This call destroys the merge database. Replace it later. */
1515   XrmMergeDatabases( info -> merge_db, &( target_db ) );
1516 
1517   /* The database was destroyed. */
1518   info -> merge_db = NULL;
1519 
1520 }
1521 
1522 
1523 /*----------------------------------------------------------------------*/
1524 
1525 void
xmubResRemoveSetChangedCallback(xmubResourceMappingInfoRef info,xmubResSetChangeCallback callback,XtPointer client_data)1526 xmubResRemoveSetChangedCallback( xmubResourceMappingInfoRef  info,
1527                                  xmubResSetChangeCallback    callback,
1528                                  XtPointer                   client_data )
1529 {
1530 
1531   Boolean  found = False;
1532   int      pos;
1533 
1534   /* Code. */
1535 
1536   /* Find the callback info position. */
1537   for( pos = 0; pos < info -> num_set_change_callbacks; pos ++ ){
1538     if( ( info -> set_change_callbacks[ pos ].callback == callback ) &&
1539         ( info -> set_change_callbacks[ pos ].client_data == client_data ) ){
1540       found = True;
1541       break;
1542     }
1543   }
1544 
1545   if( ! found )
1546     return;
1547 
1548   /* The callback was present. */
1549   if( info -> num_set_change_callbacks == 1 ){
1550     info -> num_set_change_callbacks = 0;
1551     XtFree( (char *) info -> set_change_callbacks );
1552     info -> set_change_callbacks = NULL;
1553 
1554     return;
1555   }
1556 
1557   /* Just overwrite the old one. Don't care about wasted memory. */
1558   memmove( &( info -> set_change_callbacks[ pos ] ),
1559            &( info -> set_change_callbacks[ pos + 1 ] ),
1560            info -> num_set_change_callbacks - pos - 1 );
1561 
1562   info -> num_set_change_callbacks --;
1563 
1564 }
1565 
1566 
1567 /*----------------------------------------------------------------------*/
1568 
1569 void
xmubResReplace(xmubResourceMappingInfoRef info,XrmDatabase start_db)1570 xmubResReplace( xmubResourceMappingInfoRef  info,
1571                 XrmDatabase                 start_db )
1572 {
1573 
1574   Boolean   allocated_delimiters = False;
1575   char*     delimiters;
1576   int       index;
1577   Bool      ok;
1578   char*     res_class;
1579   char*     res_name;
1580   char*     search_string;
1581   char**    str_list;
1582   int       str_list_index;
1583   int       str_list_size;
1584   char*     str_type_return;
1585   char*     token;
1586   XrmValue  value_return;
1587 
1588   /* Code. */
1589 
1590   /* First pass, replace without substring support. */
1591   xmubResReplaceKeywords( info, start_db, False, NULL, NULL, 0, False );
1592 
1593   /* Get the resource definitions. */
1594   /* We cannot use XtGetApplication resources, since it requires a widget. */
1595   res_name  = XtMalloc( strlen( info -> app_name ) + 30 );
1596   res_class = XtMalloc( strlen( info -> app_class ) + 30 );
1597 
1598   sprintf( res_name,  "%s.%s", info -> app_name, XmUbNsubstringResources );
1599   sprintf( res_class, "%s.%s", info -> app_class, XmUbCSubstringResources );
1600 
1601   /* Get the resource first from the source database, if not specified
1602      there, try display database. */
1603   if( start_db != NULL )
1604     ok = XrmGetResource( start_db, res_name, res_class,
1605                          &str_type_return, &value_return );
1606   else
1607     ok = (Bool) False;
1608 
1609   if( ! ok )
1610     ok = XrmGetResource( XtDatabase( info -> display ), res_name, res_class,
1611                          &str_type_return, &value_return );
1612 
1613   if( ok ){
1614     /* The resource was specified. */
1615     /* Construct string list from extracted string. */
1616     str_list_size = 5;
1617     str_list_index = 0;
1618     str_list = (char **) XtMalloc( sizeof( char *) * str_list_size );
1619     search_string = (char *) value_return.addr;
1620 
1621 
1622     while( ( token = strtok( search_string, " " ) ) != NULL ){
1623 
1624       if( str_list_index == str_list_size ){
1625         str_list_size += 5;
1626         str_list = (char **) XtRealloc( (char *) str_list,
1627                                         sizeof( char *) * str_list_size );
1628       }
1629 
1630       str_list[ str_list_index ] = XtNewString( token );
1631       str_list_index ++;
1632 
1633       /* Nullify for next call. */
1634       search_string = NULL;
1635     }
1636 
1637     /* The string list has been constructed. */
1638     /* Get the delimiter list. */
1639     sprintf( res_name,  "%s.%s", info -> app_name, XmUbNsubstringDelimiters );
1640     sprintf( res_class, "%s.%s", info -> app_class, XmUbCSubstringDelimiters );
1641 
1642     if( start_db != NULL )
1643       ok = XrmGetResource( start_db, res_name, res_class,
1644                            &str_type_return, &value_return );
1645     else
1646       ok = (Bool) False;
1647 
1648     if( ! ok )
1649       ok = XrmGetResource( XtDatabase( info -> display ), res_name, res_class,
1650                            &str_type_return, &value_return );
1651 
1652     if( ok ){
1653       delimiters = XtMalloc( sizeof( char ) * ( value_return.size + 1 ) );
1654       strncpy( delimiters, (char *) value_return.addr, value_return.size );
1655       delimiters[ value_return.size ] = '\0';
1656       allocated_delimiters = True;
1657 
1658     } else
1659       delimiters = DEFAULT_DELIMITERS;
1660 
1661     /* Replace the keywords. */
1662     xmubResReplaceKeywords( info, start_db, True, delimiters,
1663                             str_list, str_list_index, True );
1664 
1665 
1666     /* Free up. */
1667     for( index = 0; index < str_list_index; index ++ )
1668       XtFree( str_list[ index ] );
1669 
1670     XtFree( (char *) str_list );
1671     if( allocated_delimiters )
1672       XtFree( delimiters );
1673 
1674   }
1675 
1676   XtFree( res_name );
1677   XtFree( res_class );
1678 
1679 }
1680 
1681 
1682 /*----------------------------------------------------------------------*/
1683 
1684 void
xmubResReplaceKeywords(xmubResourceMappingInfoRef info,XrmDatabase start_db,Boolean replace_substrings,char * substring_delimiters,char ** resource_selection,Cardinal num_resource_selection,Boolean inclusive_selection)1685 xmubResReplaceKeywords( xmubResourceMappingInfoRef  info,
1686                         XrmDatabase                 start_db,
1687                         Boolean                     replace_substrings,
1688                         char*                       substring_delimiters,
1689                         char**                      resource_selection,
1690                         Cardinal                    num_resource_selection,
1691                         Boolean                     inclusive_selection )
1692 {
1693 
1694   Bool         bok;
1695   XrmQuark     class_list[ 3 ];
1696   int          index;
1697   XrmQuark     name_list[ 3 ];
1698 
1699   /* Code. */
1700 
1701   /* If no input database is defined, take the display database. */
1702   if( start_db == NULL )
1703     start_db = XtDatabase( info -> display );
1704 
1705   /* If a resource selection was defined, set it up as quarks, to allow for
1706      faster comparison. */
1707   info -> num_selections = num_resource_selection;
1708 
1709   if( num_resource_selection > 0 ){
1710     info -> selection =
1711       (XrmQuark *) XtMalloc( num_resource_selection * sizeof( XrmQuark ) );
1712     info -> inclusive_selection = inclusive_selection;
1713 
1714     for( index = 0; index < num_resource_selection; index ++ )
1715       info -> selection[ index ] =
1716         XrmStringToQuark( resource_selection[ index ] );
1717 
1718   } else
1719     info -> selection = NULL;
1720 
1721 
1722   /* We need two passes since we want to insert the general resources first,
1723      and override with the specific ones later. */
1724 
1725   /* General resources. */
1726   name_list[ 0 ] = XrmStringToQuark( "*" );
1727   name_list[ 1 ] = NULLQUARK;
1728 
1729   class_list[ 0 ] = XrmStringToQuark( "*" );
1730   class_list[ 1 ] = NULLQUARK;
1731 
1732   info -> specific     = False;
1733 
1734   info -> replace_substrings   = replace_substrings;
1735   info -> substring_delimiters = substring_delimiters;
1736 
1737   if( start_db == info -> orig_db )
1738     info -> save_in_orig = False;
1739   else
1740     info -> save_in_orig = True;
1741 
1742 #if XlibSpecificationRelease > 4
1743   bok = XrmEnumerateDatabase(
1744 #else
1745   bok = LoopThroughDatabase(
1746 #endif
1747     start_db, name_list, class_list, XrmEnumAllLevels, ModifyKeywordResource,
1748     (XPointer) info );
1749 
1750   /* Application specific resources. */
1751   name_list[ 0 ] = XrmStringToQuark( info -> app_name );
1752   name_list[ 1 ] = XrmStringToQuark( "_FontLists_" );
1753   name_list[ 2 ] = NULLQUARK;
1754 
1755   class_list[ 0 ] = XrmStringToQuark( info -> app_class );
1756   class_list[ 1 ] = XrmStringToQuark( "_FontLists_" );
1757   class_list[ 2 ] = NULLQUARK;
1758 
1759   info -> specific = True;
1760 
1761 #if XlibSpecificationRelease > 4
1762   bok = XrmEnumerateDatabase(
1763 #else
1764   bok = LoopThroughDatabase(
1765 #endif
1766     start_db, name_list, class_list, XrmEnumAllLevels, ModifyKeywordResource,
1767     (XPointer) info );
1768 
1769 
1770   /* Clean up. */
1771   if( info -> selection != NULL )
1772     XtFree( (char *) info -> selection );
1773 
1774 }
1775 
1776 
1777 /*----------------------------------------------------------------------*/
1778 
1779 Boolean
xmubResUpdateAllResources(xmubResourceMappingInfoRef info,xmubAppResDesc resource_sets[],Cardinal num_resource_sets,xmubResSetChangeCallback apply_callback,XtPointer client_data)1780 xmubResUpdateAllResources( xmubResourceMappingInfoRef  info,
1781                            xmubAppResDesc              resource_sets[],
1782                            Cardinal                    num_resource_sets,
1783                            xmubResSetChangeCallback    apply_callback,
1784                            XtPointer                   client_data )
1785 {
1786 
1787   Bool                            bok;
1788   xmubResSetChangeCallbackStruct  cb;
1789   int                             index;
1790   Boolean                         ok;
1791   char*                           res_class;
1792   char*                           res_name;
1793   int                             res_number;
1794   char*                           str_type_return;
1795   XrmValue                        value_return;
1796 
1797   /* Code. */
1798 
1799   /* Clear the translation and merge databases. */
1800   xmubResClearInternalDatabases( info, False, False, True, True );
1801 
1802   ok = xmubResAddMappings( info, info -> mapping_db, True,
1803                            resource_sets, num_resource_sets );
1804 
1805   if( ok ){
1806     xmubResReplace( info, info -> orig_db );
1807     xmubResMergeMappedResources( info, NULL );
1808   }
1809 
1810   /* Call callbacks for each resource. */
1811 
1812   /* Set up the callback structure. */
1813   cb.reason          = XMUB_RES_SET_CHANGED;
1814   cb.res_name        = NULL;
1815   cb.res_class       = NULL;
1816   cb.new_value       = NULL;
1817   cb.mapping_changed = ok;
1818 
1819   /* Call the apply callback. */
1820   if( apply_callback != NULL )
1821     (* ( apply_callback ) ) ( info, client_data, &cb );
1822 
1823   /* Call the resource change callbacks. */
1824   for( res_number = 0; res_number < num_resource_sets; res_number ++ ){
1825 
1826     res_name = XtMalloc( strlen( resource_sets[ res_number ].res_name ) +
1827                          strlen( info -> app_name ) + 5 );
1828     sprintf( res_name, "%s.%s", info -> app_name,
1829                                 resource_sets[ res_number ].res_name );
1830 
1831     res_class = XtMalloc( strlen( resource_sets[ res_number ].res_class ) +
1832                           strlen( info -> app_class ) + 5 );
1833     sprintf( res_class, "%s.%s", info -> app_class,
1834                                  resource_sets[ res_number ].res_class );
1835 
1836     bok = XrmGetResource( XtDatabase( info -> display ), res_name, res_class,
1837                           &str_type_return, &value_return );
1838 
1839     cb.reason          = XMUB_RES_SET_CHANGED;
1840     cb.res_name        = resource_sets[ res_number ].res_name;
1841     cb.res_class       = resource_sets[ res_number ].res_class;
1842     if( bok )
1843       cb.new_value = (char *) value_return.addr;
1844     else
1845       cb.new_value = NULL;
1846     cb.mapping_changed = True;
1847 
1848     for( index = 0; index < info -> num_set_change_callbacks; index ++ )
1849       (* ( info -> set_change_callbacks[ index ].callback ) )
1850         ( info, info -> set_change_callbacks[ index ].client_data, &cb );
1851 
1852     XtFree( res_name );
1853     XtFree( res_class );
1854 
1855 
1856   }
1857 
1858   return( ok );
1859 
1860 }
1861 
1862 
1863 /*----------------------------------------------------------------------*/
1864 
1865 Boolean
xmubResUpdateResourceSet(xmubResourceMappingInfoRef info,char * res_name,char * res_class,char * new_value,xmubResSetChangeCallback apply_callback,XtPointer client_data)1866 xmubResUpdateResourceSet( xmubResourceMappingInfoRef  info,
1867                           char*                       res_name,
1868                           char*                       res_class,
1869                           char*                       new_value,
1870                           xmubResSetChangeCallback    apply_callback,
1871                           XtPointer                   client_data )
1872 {
1873 
1874   xmubResSetChangeCallbackStruct  cb;
1875   XrmDatabase                     db;
1876   int                             index;
1877   Boolean                         ok;
1878   char*                           resource_line;
1879   xmubAppResDesc                  res_sets;
1880 
1881   /* Code. */
1882 
1883   /* Set the new resource in the display database. */
1884   resource_line = XtMalloc( strlen( res_name ) + strlen( new_value ) + 5 );
1885   sprintf( resource_line, "*%s: %s", res_name, new_value );
1886   db = XtDatabase( info -> display );
1887 
1888   XrmPutLineResource( &db, resource_line );
1889 
1890   XtFree( resource_line );
1891 
1892   /* Clear the translation and merge databases. */
1893   xmubResClearInternalDatabases( info, False, False, True, True );
1894 
1895   /* Select the mappings from the mapping database. */
1896   res_sets.res_name  = res_name;
1897   res_sets.res_class = res_class;
1898   ok = xmubResAddMappings( info, info -> mapping_db, False, &res_sets, 1 );
1899 
1900   if( ok ){
1901     xmubResReplace( info, info -> orig_db );
1902     xmubResMergeMappedResources( info, NULL );
1903   }
1904 
1905   /* Set up the callback structure. */
1906   cb.reason          = XMUB_RES_SET_CHANGED;
1907   cb.res_name        = res_name;
1908   cb.res_class       = res_class;
1909   cb.new_value       = new_value;
1910   cb.mapping_changed = ok;
1911 
1912   /* Call the apply callback. */
1913   if( apply_callback != NULL )
1914     (* ( apply_callback ) ) ( info, client_data, &cb );
1915 
1916   /* Call the resource change callbacks. */
1917   for( index = 0; index < info -> num_set_change_callbacks; index ++ )
1918     (* ( info -> set_change_callbacks[ index ].callback ) )
1919       ( info, info -> set_change_callbacks[ index ].client_data, &cb );
1920 
1921 
1922   return( ok );
1923 
1924 }
1925