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