1    | /*****
2    |  ** ** Module Header ******************************************************* **
3    |  ** 									     **
4    |  **   Modules Revision 3.0						     **
5    |  **   Providing a flexible user environment				     **
6    |  ** 									     **
7    |  **   File:		cmdXResource.c					     **
8    |  **   First Edition:	1991/10/23					     **
9    |  ** 									     **
10   |  **   Authors:	John Furlan, jlf@behere.com				     **
11   |  **		Leif Hedstrom<hedstrom"@boot.org>			     **
12   |  **		Jens Hamisch, jens@Strawberry.COM			     **
13   |  ** 									     **
14   |  **   Description:	Module command to merge/remove resources from the X11**
15   |  **			resource manager. The database is update internally, **
16   |  **			ie. its not done at evaluation of string modulecmd   **
17   |  **			returns. It will do something like "xrdb -merge"     **
18   |  **			using the default display ($DISPLAY).		     **
19   |  ** 									     **
20   |  **   Exports:		xresourceFinish					     **
21   |  **			cmdXResource					     **
22   |  ** 									     **
23   |  **   Notes:		Fragments of this code are from the original xrdb    **
24   |  **			source, Copyright 1987 & 1991 by DIGITAL EQUIPMENT   **
25   |  **			CORPORATION. Xrdb was written and modified by:	     **
26   |  ** 									     **
27   |  **				Jim Gettys, August 28, 1987		     **
28   |  **				Phil Karlton, January 5, 1987		     **
29   |  **				Bob Scheifler, February, 1991		     **
30   |  ** 									     **
31   |  **   ToDo/Bugs:	+ The command only handles screen independant re-    **
32   |  **                       sources.                                           **
33   |  ** ************************************************************************ **
34   |  ****/
35   | 
36   | /** ** Copyright *********************************************************** **
37   |  ** 									     **
38   |  ** Copyright 1991-1994 by John L. Furlan.                      	     **
39   |  ** see LICENSE.GPL, which must be provided, for details		     **
40   |  ** 									     ** 
41   |  ** ************************************************************************ **/
42   | 
43   | static char Id[] = "@(#)$Id: cmdXResource.c.src.html,v 1.6 2006/01/18 05:35:11 rkowen Exp $";
44   | static void *UseId[] = { &UseId, Id };
45   | 
46   | /** ************************************************************************ **/
47   | /** 				      HEADERS				     **/
48   | /** ************************************************************************ **/
49   | 
50   | #include "modules_def.h"
51   | 
52   | #ifdef HAS_X11LIBS
53   | #include <X11/Xlib.h>
54   | #include <X11/Xatom.h>
55   | #endif
56   | 
57   | /** ************************************************************************ **/
58   | /** 				  LOCAL DATATYPES			     **/
59   | /** ************************************************************************ **/
60   | 
61   | #ifdef HAS_X11LIBS
62   | typedef struct _ResourceDB {
63   |     Tcl_HashTable *data;
64   |     Window root;
65   |     Atom prop;
66   | } ResourceDB;
67   | #endif
68   | 
69   | /** ************************************************************************ **/
70   | /** 				     CONSTANTS				     **/
71   | /** ************************************************************************ **/
72   | 
73   | #ifndef R_OK
74   | #define F_OK		0		/** does file exist		     **/
75   | #define X_OK		1		/** is it executable by caller	     **/
76   | #define W_OK		2		/** is it writable by caller	     **/
77   | #define R_OK		4		/** is it readable by caller	     **/
78   | #endif
79   | 
80   | /** ************************************************************************ **/
81   | /**				      MACROS				     **/
82   | /** ************************************************************************ **/
83   | 
84   | #ifdef HAS_X11LIBS
85   | #define MAXHOSTNAME	 255
86   | #define Resolution( pixels, mm)	(((pixels * 100000 / mm) + 50) / 100)
87   | #endif
88   | 
89   | /** ************************************************************************ **/
90   | /** 				    LOCAL DATA				     **/
91   | /** ************************************************************************ **/
92   | 
93   | static	char	module_name[] = "cmdXResource.c";	/** File name of this module **/
94   | 
95   | #if WITH_DEBUGGING_UTIL_2
96   | static	char	_proc_addDef[] = "addDef";
97   | static	char	_proc_addNum[] = "addNum";
98   | #endif
99   | #if WITH_DEBUGGING_UTIL_1
100  | static	char	_proc_doDisplayDefines[] = "doDisplayDefines";
101  | static	char	_proc_doScreenDefines[] = "doScreenDefines";
102  | static	char	_proc_readFile[] = "readFile";
103  | static	char	_proc_getEntries[] = "getEntries";
104  | static	char	_proc_storeResProp[] = "storeResProp";
105  | static	char	_proc_getOld[] = "getOld";
106  | static	char	_proc_initBuffers[] = "initBuffers";
107  | static	char	_proc_xresourceFinish[] = "xresourceFinish";
108  | #endif
109  | #if WITH_DEBUGGING_CALLBACK
110  | static	char	_proc_cmdXResource[] = "cmdXResource";
111  | #endif
112  | 
113  | #ifdef HAS_X11LIBS
114  | static Display		*dpy		= (Display *) NULL;
115  | static char		*defines	= (char *) NULL;
116  | static int		def_base	= 0;
117  | static Tcl_DString	*buffer		= (Tcl_DString *) NULL;
118  | static ResourceDB	resDB		= { NULL, (Window) 0, (Atom) 0 };
119  | #endif
120  | 
121  | /** ************************************************************************ **/
122  | /**				    PROTOTYPES				     **/
123  | /** ************************************************************************ **/
124  | 
125  | static	void	addDef(	char*, char*);
126  | static	void	addNum(	char*, int);
127  | static	void	doDisplayDefines(void);
128  | static	void	doScreenDefines( int);
129  | static	int	readFile( register FILE	*, int);
130  | static	ErrType getEntries(Tcl_Interp*,  Tcl_HashTable*, register char*, int);
131  | #ifdef HAS_X11LIBS
132  | static	void	storeResProp( register ResourceDB* );
133  | #endif
134  | static	ErrType getOld( register char**);
135  | static	ErrType	initBuffers(Tcl_Interp*, register int );
136  | 
137  | #ifdef HAS_X11LIBS
138  | 
139  | /*++++
140  |  ** ** Function-Header ***************************************************** **
141  |  ** 									     **
142  |  **   Function:		addDef, addNum					     **
143  |  ** 									     **
144  |  **   Description:	Adds DEFINES to the define buffer. This code is main-**
145  |  **			ly the same as in the original xrdb.c		     **
146  |  ** 									     **
147  |  **   First Edition:	1991/10/23					     **
148  |  ** 									     **
149  |  **   Parameters:	char	*title		Name of the resource	     **
150  |  **			char	*value		and its value		     **
151  |  ** 									     **
152  |  **   Result:		-						     **
153  |  ** 									     **
154  |  **   Attached Globals:	defines		Buffer for all DEFINES which will be **
155  |  **					written here in command lien syntax: **
156  |  **					   -D <titel>=<value>		     **
157  |  ** 									     **
158  |  ** ************************************************************************ **
159  |  ++++*/
160  | 
161  | static	void	addDef(	char	*title,
162  | 			char	*value)
163  | {
164  |     register int quote;
165  | 
166  | #if WITH_DEBUGGING_UTIL_2
167  |     ErrorLogger( NO_ERR_START, LOC, _proc_addDef, NULL);
168  | #endif
169  | 
170  |     /**
171  |      **  Add '-D title' at first
172  |      **/
173  | 
174  |     if( title && *title) {
175  | 
176  | 	strcat( defines, " -D");
177  | 	strcat( defines, title);
178  | 
179  | 	/**
180  | 	 **  Add the value if there is one
181  | 	 **/
182  | 
183  | 	if( value && *value) {
184  | 
185  | 	    quote = (value && strchr( value, ' '));
186  | 	    strcat( defines, (quote ? "=\"" : "="));
187  | 	    strcat( defines, value);
188  | 	    if( quote)
189  | 		strcat( defines,"\"");
190  | 
191  | 	} /** if( value) **/
192  |     } /** if( title) **/
193  | 
194  | } /** End of 'addDef' **/
195  | 
196  | static	void	addNum(	char	*title,
197  | 			int	 value)
198  | {
199  |     char num[ 20];
200  | 
201  | #if WITH_DEBUGGING_UTIL_2
202  |     ErrorLogger( NO_ERR_START, LOC, _proc_addNum, NULL);
203  | #endif
204  | 
205  |     sprintf( num, "%d", value);
206  |     addDef( title, num);
207  | 
208  | } /** End of 'addNum' **/
209  | 
210  | /*++++
211  |  ** ** Function-Header ***************************************************** **
212  |  ** 									     **
213  |  **   Function:		doDisplayDefines				     **
214  |  ** 									     **
215  |  **   Description:	Put the client and server specific defines on the    **
216  |  **			define buffer					     **
217  |  ** 									     **
218  |  **   First Edition:	1991/10/23					     **
219  |  ** 									     **
220  |  **   Parameters:	-						     **
221  |  ** 									     **
222  |  **   Result:		-						     **
223  |  ** 									     **
224  |  **   Attached Globals:	dpy		For seeking the name of the display  **
225  |  **			defines		(via addDef and addNum)	  	     **
226  |  ** 									     **
227  |  ** ************************************************************************ **
228  |  ++++*/
229  | 
230  | static	void	doDisplayDefines()
231  | {
232  |     char	 client[ MAXHOSTNAME],		/** X client name buffer     **/
233  | 		 server[ MAXHOSTNAME],		/** X server name buffer     **/
234  | 		*colon;				/** Pointer for seeking the  **/
235  | 						/** colon in the server name **/
236  | #if WITH_DEBUGGING_UTIL_1
237  |     ErrorLogger( NO_ERR_START, LOC, _proc_doDisplayDefines, NULL);
238  | #endif
239  | 
240  |     /**
241  |      **  Get client and server hostname. Remove everything after the ':' from
242  |      **  the server name. If there's no server name available, the server de-
243  |      **  faults to the client.
244  |      **/
245  | 
246  |     gethostname(client,MAXHOSTNAME);
247  |     strcpy( server, XDisplayName( NULL));
248  | 
249  |     if( colon = strchr( server, ':'))
250  | 	*colon = '\0';
251  |     if( !*server)
252  | 	strcpy( server, client);
253  | 
254  |     /**
255  |      **  Add the standard defines now ...
256  |      **/
257  | 
258  |     addDef( "HOST", server);
259  |     addDef( "SERVERHOST", server);
260  |     addDef( "CLIENTHOST", client);
261  |     addNum( "VERSION", ProtocolVersion( dpy));
262  |     addNum( "REVISION", ProtocolRevision( dpy));
263  |     addDef( "VENDOR", ServerVendor( dpy));
264  |     addNum( "RELEASE", VendorRelease( dpy));
265  | 
266  | } /** End of 'doDisplayDefines' **/
267  | 
268  | /*++++
269  |  ** ** Function-Header ***************************************************** **
270  |  ** 									     **
271  |  **   Function:		doScreenDefines					     **
272  |  ** 									     **
273  |  **   Description:	Put the screen specific defines on the define buffer **
274  |  ** 									     **
275  |  **   First Edition:	1991/10/23					     **
276  |  ** 									     **
277  |  **   Parameters:	int	scrno	Screen number			     **
278  |  ** 									     **
279  |  **   Result:		-						     **
280  |  ** 									     **
281  |  **   Attached Globals:	dpy		For seeking the name of the display  **
282  |  **			defines		(via addDef and addNum)	  	     **
283  |  ** 									     **
284  |  ** ************************************************************************ **
285  |  ++++*/
286  | 
287  | static	void	 doScreenDefines( int	scrno)
288  | {
289  |     register Screen	*screen;
290  |     register Visual	*visual;
291  |     
292  | #if WITH_DEBUGGING_UTIL_1
293  |     ErrorLogger( NO_ERR_START, LOC, _proc_doScreenDefines, NULL);
294  | #endif
295  | 
296  |     /**
297  |      **  Get screen data at first
298  |      **/
299  | 
300  |     screen = ScreenOfDisplay( dpy, scrno);
301  |     visual = DefaultVisualOfScreen( screen);
302  | 
303  |     /**
304  |      **  Put screen data on the defines buffer
305  |      **/
306  | 
307  |     addNum( "WIDTH", screen->width);
308  |     addNum( "HEIGHT", screen->height);
309  |     addNum( "X_RESOLUTION", Resolution( screen->width, screen->mwidth));
310  |     addNum( "Y_RESOLUTION", Resolution( screen->height, screen->mheight));
311  |     addNum( "PLANES", DisplayPlanes( dpy, scrno));
312  |     addNum( "BITS_PER_RGB", visual->bits_per_rgb);
313  | 
314  |     /**
315  |      **  The CLASS and COLOR do depend on the screen class
316  |      **/
317  | 
318  |     switch(visual->class) {
319  | 
320  | 	case StaticGray:	addDef( "CLASS", "StaticGray");
321  | 				break;
322  | 
323  | 	case GrayScale:		addDef( "CLASS", "GrayScale");
324  | 				break;
325  | 
326  | 	case StaticColor:	addDef( "CLASS", "StaticColor");
327  | 				addDef( "COLOR", NULL);
328  | 				break;
329  | 
330  | 	case PseudoColor:	addDef( "CLASS", "PseudoColor");
331  | 				addDef( "COLOR", NULL);
332  | 				break;
333  | 
334  | 	case TrueColor:		addDef( "CLASS", "TrueColor");
335  | 				addDef( "COLOR", NULL);
336  | 				break;
337  | 
338  | 	case DirectColor:	addDef( "CLASS", "DirectColor");
339  | 				addDef( "COLOR", NULL);
340  | 				break;
341  |     } /** switch **/
342  | 
343  | } /** End of 'doScreenDefines' **/
344  | 
345  | /*++++
346  |  ** ** Function-Header ***************************************************** **
347  |  ** 									     **
348  |  **   Function:		readFile					     **
349  |  ** 									     **
350  |  **   Description:	Read resource from a file, which normally is a pipe  **
351  |  **			opened with popen.				     **
352  |  **			The file will be closed, when reading is finished    **
353  |  **									     **
354  |  **   Note:		This routine uses the global variable 'line', declar-**
355  |  **			ed in another file!!!				     **
356  |  ** 									     **
357  |  **   First Edition:	1991/10/23					     **
358  |  ** 									     **
359  |  **   Parameters:	register FILE	*input	The stream to be read from   **
360  |  **			int		 do_cpp	Differs betweem a pipe or a  **
361  |  **						file being assigned to input **
362  |  ** 									     **
363  |  **   Result:		-						     **
364  |  ** 									     **
365  |  **   Attached Globals:	line		Buffer for a line to be read	     **
366  |  **			buffer		Buffer for the whole resource file  **
367  |  **					image				     **
368  |  ** 									     **
369  |  ** ************************************************************************ **
370  |  ++++*/
371  | 
372  | static	int	readFile(	register FILE	*input,
373  | 				int		 do_cpp)
374  | {
375  |     register int bytes;
376  | 
377  | #if WITH_DEBUGGING_UTIL_1
378  |     ErrorLogger( NO_ERR_START, LOC, _proc_readFile, NULL);
379  | #endif
380  | 
381  |     while( !feof( input) && (bytes = fread( line, 1, LINELENGTH, input)))
382  | 	Tcl_DStringAppend( buffer, line, bytes);
383  | 
384  |     if( do_cpp) {
385  | 	if( -1 == pclose( input))
386  | 	    if( OK != ErrorLogger( ERR_PCLOSE, LOC, NULL))
387  | 		return( TCL_ERROR);	/** -------- EXIT (FAILURE) -------> **/
388  |     } else {
389  | 	if( EOF == fclose( input))
390  | 	    if( OK != ErrorLogger( ERR_CLOSE, LOC, NULL))
391  | 		return( TCL_ERROR);	/** -------- EXIT (FAILURE) -------> **/
392  |     }
393  | 
394  |     return( TCL_OK);
395  | 
396  | } /**  End of 'readFile' **/
397  | 
398  | /*++++
399  |  ** ** Function-Header ***************************************************** **
400  |  ** 									     **
401  |  **   Function:		getEntries					     **
402  |  ** 									     **
403  |  **   Description:	Updates the resources database (which is a Tcl hash **
404  |  **			table) with the resources passed in the buffer. The **
405  |  **			buffer contains a X resource lookalike text image.  **
406  |  ** 									     **
407  |  **   First Edition:	1991/10/23					     **
408  |  ** 									     **
409  |  **   Parameters:	Tcl_Interp	*interp		According Tcl interp.**
410  |  **			Tcl_HashTable	*data	The hash tables holding the  **
411  |  **						resource data		     **
412  |  **			register char	*buf	The buffer containing the    **
413  |  **						resources to be modified in **
414  |  **						X resource syntax	     **
415  |  **			int		 remove	Remove or add resources     **
416  |  ** 									     **
417  |  **   Result:		ErrType	NO_ERR		Success			     **
418  |  **				ERR_PARSE	Parse error		     **
419  |  ** 									     **
420  |  **   Attached Globals:	-						     **
421  |  ** 									     **
422  |  ** ************************************************************************ **
423  |  ++++*/
424  | 
425  | static	ErrType getEntries(	Tcl_Interp	*interp,
426  | 				Tcl_HashTable	*data,
427  | 				register char	*buf,
428  | 				int		 remove)
429  | {
430  |     Tcl_RegExp		res_exp = (Tcl_RegExp) NULL;
431  |     register Tcl_HashEntry	*entry;
432  |     char			*end;
433  |     int				 new_res;
434  | 
435  | #if WITH_DEBUGGING_UTIL_1
436  |     ErrorLogger( NO_ERR_START, LOC, _proc_getEntries, NULL);
437  | #endif
438  | 
439  |     /**
440  |      **  The following regular expression matches pattern like
441  |      **
442  |      **       <resource>:	<value>
443  |      **
444  |      **  The resource will be returned as \1 and the value as \2
445  |      **  Set the regexp pointer only, if it hasn't already been set. This 
446  |      **  is a constant regexp!
447  |      **/
448  | 
449  |     if( !res_exp)
450  | 	res_exp  = Tcl_RegExpCompile(interp,
451  | 		 "^[ \t]*([^ \t]*)[ \t]*:[ \t]*(.*)[ \t]*$");
452  | 
453  |     /**
454  |      **  Seek for the lines (buffers) end. Put a terminator there. Take care of
455  |      **  escaped newlines!
456  |      **/
457  | 
458  |     for( end = buf; *end; end++)
459  | 	if( *end == '\\' && *(end+1) == '\n')
460  | 	    end++;
461  | 	else if( *end == '\n')
462  | 	    *end = '\0';
463  | 
464  |     /**
465  |      **  Now read the whole buffer.
466  |      **  At first, we have to ignore comments
467  |      **/
468  | 
469  |     while( buf <= end) {
470  | 
471  | 	if( *buf == '#' || *buf == '!' || !*buf) {
472  | 	    while( *buf++) ;
473  | 
474  | 	/**
475  | 	 **  Otherwise we're seeking for a syntacticl correct X resource entry
476  | 	 **/
477  | 
478  | 	} else if( !Tcl_RegExpExec(interp, res_exp, buf, buf)) {
479  | 	    if( OK != ErrorLogger( ERR_PARSE, LOC, NULL)) {
480  | 		return( ERR_PARSE);	/** ------ EXIT (PARSE ERROR) -----> **/
481  | 	    }
482  | 
483  | 	} else {
484  | 
485  | 	    /**
486  | 	     **  Valid entry found. Set up buf pointing behind the pattern
487  | 	     **  that has matched and put a terminator at the end of either the
488  | 	     **  resource name and its value.
489  | 	     **/
490  | 
491  | 	    char *startp, *endp;
492  | 	    Tcl_RegExpRange(res_exp, 0,
493  | 		(CONST84 char **) &startp, (CONST84 char **) &endp);
494  | 	    buf = endp + 1;
495  | 	    Tcl_RegExpRange(res_exp, 1,
496  | 		(CONST84 char **) &startp, (CONST84 char **) &endp);
497  | 	    *endp = '\0';
498  | 	    Tcl_RegExpRange(res_exp, 2,
499  | 		(CONST84 char **) &startp, (CONST84 char **) &endp);
500  | 	    *endp = '\0';
501  | 
502  | 	    /**
503  | 	     **  Now create (or remove) a hash entry for the parsed resource
504  | 	     **/
505  | 
506  | 	    if( remove) {
507  | 	        Tcl_RegExpRange(res_exp, 1,
508  | 			(CONST84 char **) &startp, (CONST84 char **) &endp);
509  | 		if( entry = Tcl_FindHashEntry( data, startp)) {
510  | 		    null_free((void *) &( Tcl_GetHashValue( entry)));
511  | 		    Tcl_DeleteHashEntry( entry);
512  | 		}
513  | 	    } else {
514  | 	        Tcl_RegExpRange(res_exp, 1,
515  | 			(CONST84 char **) &startp, (CONST84 char **) &endp);
516  | 		entry = Tcl_CreateHashEntry( data, startp, &new_res);
517  | 		if( !new_res)
518  | 		    null_free((void *) &( Tcl_GetHashValue( entry)));
519  | 	        Tcl_RegExpRange(res_exp, 2,
520  | 			(CONST84 char **) &startp, (CONST84 char **) &endp);
521  | 		Tcl_SetHashValue( entry, strdup( startp));
522  | 	    }
523  | 
524  | 	} /** if( reg exp matched) **/
525  |     } /** while **/
526  | 
527  |     /**
528  |      **  Return on success
529  |      **/
530  | 
531  |     return( NO_ERR);
532  | 
533  | } /** end of 'getEntries' **/
534  | 
535  | /*++++
536  |  ** ** Function-Header ***************************************************** **
537  |  ** 									     **
538  |  **   Function:		storeResProp					     **
539  |  ** 									     **
540  |  **   Description:	Update the X11 resource property, adding new resour- **
541  |  **			ces.						     **
542  |  ** 									     **
543  |  **   First Edition:	1991/10/23					     **
544  |  ** 									     **
545  |  **   Parameters:	register ResourceDB *rdb	Resource database   **
546  |  ** 									     **
547  |  **   Result:		-						     **
548  |  ** 									     **
549  |  **   Attached Globals:	-						     **
550  |  ** 									     **
551  |  ** ************************************************************************ **
552  |  ++++*/
553  | 
554  | #ifdef HAS_X11LIBS
555  | static	void	storeResProp(	register ResourceDB *rdb)
556  | {
557  |     Tcl_HashSearch	search;
558  |     register int	mode = PropModeReplace;
559  |     register int	max = (XMaxRequestSize( dpy) << 2) - 28;
560  |     register int	left;
561  |     register Tcl_HashEntry *entry = Tcl_FirstHashEntry( rdb->data, &search);
562  |     unsigned char	*buf;
563  | 
564  | #if WITH_DEBUGGING_UTIL_1
565  |     ErrorLogger( NO_ERR_START, LOC, _proc_storeResProp, NULL);
566  | #endif
567  | 
568  |     /**
569  |      **	 Write all attached resources into the buffer. Follow the X 
570  |      **  resource syntax:
571  |      **
572  |      **        <resource>:	<value>
573  |      **/
574  | 
575  |     Tcl_DStringTrunc( buffer, 0);
576  |     while( entry) {
577  | 	Tcl_DStringAppend( buffer, Tcl_GetHashKey(rdb->data, entry), -1);
578  | 	Tcl_DStringAppend( buffer, ":\t", 2);
579  | 	Tcl_DStringAppend( buffer, (char *)Tcl_GetHashValue( entry), -1);
580  | 	Tcl_DStringAppend( buffer, "\n", 1);
581  | 	entry = Tcl_NextHashEntry( &search);
582  |     }
583  | 
584  |     /**
585  |      **  In case of the request being larger than the largest request the X
586  |      **  server may handle, spool it block by block until the final one.
587  |      **/
588  | 
589  |     buf = (unsigned char *) Tcl_DStringValue( buffer);
590  |     if( max < (left = Tcl_DStringLength( buffer))) {
591  | 	XGrabServer( dpy);
592  | 	mode = PropModeAppend;
593  | 	do {
594  | 	    XChangeProperty( dpy, rdb->root, rdb->prop, XA_STRING, 8, mode, buf,
595  | 		max);
596  | 	    buf += max;
597  | 	} while( max < (left -= max));
598  |     }
599  | 
600  |     /**
601  |      **  Put the final request block (which may be the only one, if the if-
602  |      **  statement above doesn't match) to the X server
603  |      **/
604  | 
605  |     XChangeProperty( dpy, rdb->root, rdb->prop, XA_STRING, 8, mode, buf, left);
606  | 
607  |     if( mode != PropModeReplace)
608  | 	XUngrabServer( dpy);
609  | 
610  | } /** End of 'storeResProp' **/
611  | #endif
612  | 
613  | /*++++
614  |  ** ** Function-Header ***************************************************** **
615  |  ** 									     **
616  |  **   Function:		getOld						     **
617  |  ** 									     **
618  |  **   Description:	First, we have to find the resources already loaded  **
619  |  **			into the X11 resource property. This routine current-**
620  |  **			ly only handles one screen, the default screen for   **
621  |  **			the DISPLAY. This routine should only be called if   **
622  |  **			resDB.data is NULL.				     **
623  |  ** 									     **
624  |  **   First Edition:	1991/10/23					     **
625  |  ** 									     **
626  |  **   Parameters:	register char	**buf	Buffer for the old resource **
627  |  **						database		     **
628  |  ** 									     **
629  |  **   Result:		ErrType	ERR_PARAM	resDB.data != NULL	     **
630  |  **				ERR_ALLOC	out of memory		     **
631  |  **				NO_ERR		Success			     **
632  |  ** 									     **
633  |  **   Attached Globals:	resDB		The data area will be installed as a **
634  |  **					Tcl hash table			     **
635  |  **			dpy		The current display		     **
636  |  ** 									     **
637  |  ** ************************************************************************ **
638  |  ++++*/
639  | 
640  | static	ErrType getOld( register char **buf)
641  | {
642  | 
643  | #if WITH_DEBUGGING_UTIL_1
644  |     ErrorLogger( NO_ERR_START, LOC, _proc_getOld, NULL);
645  | #endif
646  | 
647  |     /**
648  |      **  Allocate memory for the hash table
649  |      **/
650  | 
651  |     if( resDB.data)
652  | 	if( OK != ErrorLogger( ERR_PARAM, LOC, "Resource database", NULL))
653  | 	    return( ERR_PARAM);		/** ------- EXIT (PARAMETER) -----> **/
654  | 
655  |     if( !(resDB.data = (Tcl_HashTable *) malloc( sizeof( Tcl_HashTable))))
656  | 	if( OK != ErrorLogger( ERR_ALLOC, LOC, NULL))
657  | 	    return( ERR_ALLOC);		/** ----- EXIT (OUT OF MEMORY) ----> **/
658  | 
659  |     /**
660  |      **  Initialize the hash table and read in the old resources
661  |      **/
662  | 
663  |     Tcl_InitHashTable( resDB.data, TCL_STRING_KEYS);
664  |     resDB.root = RootWindow( dpy, 0);
665  |     resDB.prop = XA_RESOURCE_MANAGER;
666  |     *buf = XResourceManagerString( dpy);
667  | 
668  |     /**
669  |      **  Success
670  |      **/
671  | 
672  |     return( NO_ERR);
673  | 
674  | } /** End of 'getOld' **/
675  | 
676  | /*++++
677  |  ** ** Function-Header ***************************************************** **
678  |  ** 									     **
679  |  **   Function:		initBuffers					     **
680  |  ** 									     **
681  |  **   Description:	Initilize buffers if not already done, or reinitia-  **
682  |  **			lize some variables if buffers already exists.	     **
683  |  ** 									     **
684  |  **   First Edition:	1991/10/23					     **
685  |  ** 									     **
686  |  **   Parameters:	Tcl_Interp	*interp		According Tcl interp.**
687  |  **   			register int is_file	Differs between a single X   **
688  |  **						resource to be modified or  **
689  |  **						a resource file to be merged**
690  |  ** 									     **
691  |  **   Result:		ErrType	ERR_DISPLAY	Cannot open DISPLAY	     **
692  |  **				ERR_ALLOC	ALLOC failure		     **
693  |  **				ERR_EXTRACT				     **
694  |  **				NO_ERR		Success			     **
695  |  ** 									     **
696  |  **   Attached Globals:	dpy		Display will be openend		     **
697  |  **			resDB		Resource database will be filled up **
698  |  **					with the current setup		     **
699  |  **			defines						     **
700  |  ** 									     **
701  |  ** ************************************************************************ **
702  |  ++++*/
703  | 
704  | static	ErrType	initBuffers(	Tcl_Interp *interp,
705  | 				register int is_file)
706  | {
707  |     char *tmpbuf;
708  | 
709  | #if WITH_DEBUGGING_UTIL_1
710  |     ErrorLogger( NO_ERR_START, LOC, _proc_initBuffers, NULL);
711  | #endif
712  | 
713  |     /**
714  |      **  Open the display
715  |      **/
716  | 
717  |     if( !dpy && !(dpy = XOpenDisplay( NULL)))
718  | 	if( OK != ErrorLogger( ERR_DISPLAY, LOC, NULL))
719  | 	    return( ERR_DISPLAY);	/** -------- EXIT (FAILURE) -------> **/
720  | 
721  |     /**
722  |      **  Read in the old setup at first and put it into the resource database
723  |      **/
724  | 
725  |     if( !resDB.data) {
726  | 
727  | 	if( getOld( &tmpbuf) != NO_ERR)	/** NULL if no resources exists      **/
728  | 	    if( OK != ErrorLogger( ERR_ALLOC, LOC, NULL))
729  | 		return( ERR_ALLOC);	/** ----- EXIT (OUT OF MEMORY) ----> **/
730  | 
731  | 	if( tmpbuf && (getEntries(interp, resDB.data, tmpbuf, 0) != NO_ERR))
732  | 	    if( OK != ErrorLogger( ERR_EXTRACT, LOC, NULL))
733  | 		return( ERR_EXTRACT);
734  |     }
735  | 
736  |     /**
737  |      **  Conditionally allocate a buffer and initialize this guy
738  |      **/
739  | 
740  |     if( !buffer) {
741  | 	if( !(buffer = (Tcl_DString *) malloc( sizeof( Tcl_DString)))) {
742  | 	    if( OK != ErrorLogger( ERR_ALLOC, LOC, NULL))
743  | 		return( ERR_ALLOC);	/** ----- EXIT (OUT OF MEMORY) ----> **/
744  | 	} else 
745  | 	    Tcl_DStringInit( buffer);
746  |     } else
747  | 	Tcl_DStringTrunc( buffer, 0);
748  | 
749  |     /**
750  |      **  Set up all the defines according display and screen
751  |      **/
752  | 
753  |     if( defines)
754  | 	defines[ def_base] = '\0';
755  |     else if( is_file) {
756  | 
757  | 	if( !(defines = (char *) malloc( BUFSIZ * sizeof( char))))
758  | 	    if( OK != ErrorLogger( ERR_ALLOC, LOC, NULL))
759  | 		return( ERR_ALLOC);	/** ----- EXIT (OUT OF MEMORY) ----> **/
760  | 
761  | 	/* sprintf( defines, "%s %s ", CPPSTDIN, CPPMINUS); */
762  | 	strcpy( defines, CPPSTDIN);
763  | 	strcat( defines, " ");
764  | 	strcat( defines, CPPMINUS);
765  | 	strcat( defines, " ");
766  | 	doDisplayDefines();
767  | 	doScreenDefines( DefaultScreen( dpy));
768  | 	def_base = strlen( strcat( defines, " "));
769  |     }
770  | 
771  |     /**
772  |      **  Return on success
773  |      **/
774  | 
775  |     return( NO_ERR);
776  | 
777  | } /** End of 'initBuffers' **/
778  | #endif
779  | 
780  | /*++++
781  |  ** ** Function-Header ***************************************************** **
782  |  ** 									     **
783  |  **   Function:		xresourceFinish					     **
784  |  ** 									     **
785  |  **   Description:	Update the resource property if everything is ok.    **
786  |  **			This routine should be called when all properies have**
787  |  **			been defines or updated. Remember that this routine  **
788  |  **			always will be called, even if there was no 	     **
789  |  **			"x-resource" command in the module!		     **
790  |  ** 									     **
791  |  **   First Edition:    1991/10/23                                             **
792  |  **                                                                          **
793  |  **   Parameters:                                                            **
794  |  **                                                                          **
795  |  **   Result:                                                                **
796  |  **                                                                          **
797  |  **   Attached Globals: -                                                    **
798  |  **                                                                          **
799  |  ** ************************************************************************ **
800  |  ++++*/
801  | 
802  | void xresourceFinish(register int no_errors)
803  | {
804  | 
805  | #if WITH_DEBUGGING_UTIL_1
806  |     ErrorLogger( NO_ERR_START, LOC, _proc_xresourceFinish, NULL);
807  | #endif
808  | 
809  | #ifdef HAS_X11LIBS
810  | 
811  |     /**
812  |      **  If there is data stored in the resource database, spool it to the
813  |      **  according X server
814  |      **/
815  | 
816  |     if( resDB.data && no_errors)
817  | 	storeResProp( &resDB);
818  | 
819  |     /**
820  |      **  Close the display and free what has been used
821  |      **/
822  | 
823  |     if( dpy)
824  | 	XCloseDisplay( dpy);
825  |     if( buffer)
826  | 	Tcl_DStringFree( buffer);
827  | 
828  | #endif
829  | 
830  | } /** End of 'xresourceFinish' **/
831  | 
832  | /*++++
833  |  ** ** Function-Header ***************************************************** **
834  |  ** 									     **
835  |  **   Function:	 	cmdXResource					     **
836  |  ** 									     **
837  |  **   Description:	Callback function for 'x-resource'. The function    **
838  |  **			sets up a hash table containing all resources to be **
839  |  **			passed to the X server. This hash table will be	     **
840  |  **			flushed whenever the function xresourceFinish is cal-**
841  |  **			led.						     **
842  |  ** 									     **
843  |  **   First Edition:	1991/10/23					     **
844  |  ** 									     **
845  |  **   Parameters:	ClientData	 client_data			     **
846  |  **			Tcl_Interp	*interp		According Tcl interp.**
847  |  **			int		 argc		Number of arguments  **
848  |  **			char		*argv[]		Argument array	     **
849  |  ** 									     **
850  |  **   Result:		int	TCL_OK		Successfull completion	     **
851  |  **				TCL_ERROR	Any error		     **
852  |  ** 									     **
853  |  **   Attached Globals:	g_flags		These are set up accordingly before  **
854  |  **					this function is called in order to  **
855  |  **					control everything		     **
856  |  ** 									     **
857  |  ** ************************************************************************ **
858  |  ++++*/
859  | 
860  | int	cmdXResource(	ClientData	 client_data,
861  | 			Tcl_Interp	*interp,
862  | 			int		 argc,
863  | 			CONST84 char	*argv[])
864  | {
865  |     register FILE	*inp;
866  |     int			 is_file, i,
867  | 			 do_cpp = 1,
868  |     			 opt_ind = 1;
869  | 
870  | #if WITH_DEBUGGING_CALLBACK
871  |     ErrorLogger( NO_ERR_START, LOC, _proc_cmdXResource, NULL);
872  | #endif
873  | 
874  |     /**
875  |      **  Whatis mode?
876  |      **/
877  | 
878  |     if( g_flags & (M_WHATIS | M_HELP))
879  |         return( TCL_OK);		/** ------- EXIT PROCEDURE -------> **/
880  | 
881  |     if( !getenv("DISPLAY")) {
882  |       /* don't bother trying to set display variables, if there is no display */
883  |       return(TCL_OK);
884  |     }
885  |     
886  | 	
887  |     /**
888  |      **  Parameter check
889  |      **/
890  | 
891  |     if( argc > 1 && !strcmp( argv[1], "-nocpp")) {
892  | 	do_cpp = 0;
893  | 	opt_ind++;
894  |     }
895  | 
896  |     if( argc <= opt_ind) {
897  | 	if( OK != ErrorLogger( ERR_USAGE, LOC, argv[0], "[ -nocpp ] strings", NULL))
898  | 	    return( TCL_ERROR);		/** -------- EXIT (FAILURE) -------> **/
899  |     }
900  | 
901  |     /**
902  |      **  Ok, now let's treat all remaining arguments as X resources or
903  |      **  X resource files. At first let's check if it is a file ...
904  |      **/
905  | 
906  |     while( opt_ind < argc) {
907  | 	is_file = (access( argv[ opt_ind], R_OK & F_OK) == 0);
908  | 
909  | #ifdef HAS_X11LIBS
910  | 
911  | 	if( g_flags & M_DISPLAY) {
912  | 	    fprintf( stderr, "xrdb -merge\t ");
913  | 	    for( i=1; i<argc; i++)
914  | 		fprintf( stderr, "%s ", argv[ i]);
915  | 	    fprintf( stderr, "\n");
916  | 
917  | 	} else {
918  | 
919  | 	    /**
920  | 	     **  Initialize read buffers
921  | 	     **/
922  | 
923  | 	    if( NO_ERR != initBuffers(interp, is_file)) 
924  | 		return( TCL_ERROR);	/** -------- EXIT (FAILURE) -------> **/
925  | 
926  | 	    /**
927  | 	     **  This puts all required resources into a text image buffer ...
928  | 	     **/
929  | 
930  | 	    if( !is_file) {
931  | 		Tcl_DStringAppend( buffer, argv[ opt_ind], -1);
932  | 	    } else {
933  | 
934  | 		if( NULL == (inp = (do_cpp ?
935  | 		    popen( strcat( defines, argv[ opt_ind]), "r") : 
936  | 		    fopen( argv[ opt_ind], "r")) ) )
937  | 		    if( OK != ErrorLogger( (do_cpp ? ERR_POPEN : ERR_OPEN), LOC,
938  | 			"argv[ opt_ind]", "reading" ))
939  | 			return( TCL_ERROR);     /** ---- EXIT (FAILURE) ---> **/
940  | 
941  | 		if( TCL_ERROR == readFile( inp, do_cpp))
942  | 		    return( TCL_ERROR);	/** -------- EXIT (FAILURE) -------> **/
943  | 	    }
944  | 
945  | 	    /**
946  | 	     **  ... and this transforms the text image buffer into a Tcl hash
947  | 	     **  table
948  | 	     **/
949  | 
950  | 	    if( NO_ERR != getEntries(interp, resDB.data,
951  | 		Tcl_DStringValue( buffer), g_flags & M_REMOVE)) {
952  | 		return( TCL_ERROR);	/** -------- EXIT (FAILURE) -------> **/
953  | 	    }
954  | 	}
955  | #else
956  | 	if( g_flags & M_DISPLAY) {
957  | 	    fprintf( stderr, "xrdb -merge\t ");
958  | 	    for( i=1; i<argc; i++)
959  | 		fprintf( stderr, "%s ", argv[ i]);
960  | 	    fprintf( stderr, "*** ignored ***\n");
961  | 	}
962  | #endif
963  | 
964  | 	opt_ind++; 
965  | 
966  |     } /** while **/
967  | 
968  | #if WITH_DEBUGGING_CALLBACK
969  |     ErrorLogger( NO_ERR_END, LOC, _proc_cmdXResource, NULL);
970  | #endif
971  | 
972  |     return( TCL_OK);
973  | 
974  | } /** End of 'cmdXResource' **/