Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / lib / DtSvc / DtUtil2 / addToRes.c
1 /*                                                                            *
2  * (c) Copyright 1993, 1994 Hewlett-Packard Company                           *
3  * (c) Copyright 1993, 1994 International Business Machines Corp.             *
4  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                            *
5  * (c) Copyright 1993, 1994 Novell, Inc.                                      *
6  */
7 /*Add a string to the XA_RESOURCE_MANAGER*/
8 /*
9  *                        COPYRIGHT 1987
10  *                 DIGITAL EQUIPMENT CORPORATION
11  *                     MAYNARD, MASSACHUSETTS
12  *                      ALL RIGHTS RESERVED.
13  *
14  * THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND
15  * SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION.
16  * DIGITAL MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR
17  * ANY PURPOSE.  IT IS SUPPLIED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
18  *
19  * IF THE SOFTWARE IS MODIFIED IN A MANNER CREATING DERIVATIVE COPYRIGHT RIGHTS,
20  * APPROPRIATE LEGENDS MAY BE PLACED ON THE DERIVATIVE WORK IN ADDITION TO THAT
21  * SET FORTH ABOVE.
22  *
23  *
24  * Permission to use, copy, modify, and distribute this software and its
25  * documentation for any purpose and without fee is hereby granted, provided
26  * that the above copyright notice appear in all copies and that both that
27  * copyright notice and this permission notice appear in supporting
28  * documentation, and that the name of Digital Equipment Corporation not be
29  * used in advertising or publicity pertaining to distribution of the software
30  * without specific, written prior permission.
31  */
32
33 /*Lifted from xrdb(1X)*/
34 /* -*-C-*-
35 *******************************************************************************
36 *
37 * File:         addToResource.c
38 * RCS:          $TOG: addToRes.c /main/8 1999/10/14 16:01:17 mgreess $
39 * Description:  Source code for adding strings to RESOURCE_PROPERTY on 
40                   default root window
41 * Author:       DEC, Robert Williams
42 * Created:      Thu Apr 26 14:42:08 PDT 1990
43 * Modified:     Kim Dronesen
44 * Language:     C
45 * Package:      N/A
46 * Status:       Experimental (Do Not Distribute)
47 *
48 * (C) Copyright 1990, Hewlett-Packard, all rights reserved.
49 *
50 *******************************************************************************
51 */
52 /*$TOG: addToRes.c /main/8 1999/10/14 16:01:17 mgreess $ */
53
54 #include <X11/Xlib.h>
55 #include <X11/Xatom.h>
56 #include <X11/Xos.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <ctype.h>
60 #include <Dt/DtP.h>
61 #include <Dt/SessionM.h>
62 #include "DtSvcLock.h"
63
64 /****************************************/
65 /* Global variables */
66 /****************************************/
67
68 typedef struct _Entry {
69     char *tag, *value;
70     int lineno;
71     Bool usable;
72 } Entry;
73 typedef struct _Buffer {
74     char *buff;
75     int  room, used;
76     Bool freebuff;
77 } Buffer;
78 typedef struct _Entries {
79     Entry *entry;
80     int   room, used;
81 } Entries;
82
83 #define INIT_BUFFER_SIZE 10000
84 #define INIT_ENTRY_SIZE 500
85
86
87 /********    Public Function Declarations    ********/
88
89 static Buffer * _DtAllocBuffer(const char **buff);
90 static void _DtFreeBuffer(Buffer *b);
91 static void _DtAppendToBuffer( 
92                         register Buffer *b,
93                         char *str,
94                         register int len) ;
95 static void _DtAppendEntryToBuffer( 
96                         register Buffer *buffer,
97                         Entry entry) ;
98
99 static Entries * _DtAllocEntries( void) ;
100 static  void _DtFreeEntries( Entries *) ;
101 static void _DtAddEntry( 
102                         register Entries *e,
103                         Entry entry) ;
104 static int _DtCompareEntries( 
105                         Entry *e1,
106                         Entry *e2) ;
107 static char * _DtFindFirst( 
108                         register char *string,
109                         register char dest) ;
110 static void _DtGetEntries( 
111                         register Entries *entries,
112                         Buffer *buff,
113                         int dosort) ;
114 static void _DtMergeEntries( 
115                         Buffer *buffer,
116                         Entries new,
117                         Entries old) ;
118 static void _DtAddToResProp(
119                         Display *dpy,
120                         unsigned int id,
121                         Entries db) ;
122 static void _getWinProp(
123                         Display *dpy,
124                         unsigned int id,
125                         Window *win,
126                         Atom *prop);
127
128 /********    End Public Function Declarations    ********/
129
130 /****************************************/
131 /*The meat*/
132 /****************************************/
133
134 static Buffer *
135 _DtAllocBuffer(
136         const char **buff )
137 {
138     Buffer *b = (Buffer *)malloc(sizeof(Buffer));
139     b->room = INIT_BUFFER_SIZE;
140     b->buff = buff ? (char*) *buff :
141                      (char *)malloc(INIT_BUFFER_SIZE*sizeof(char));
142     b->used = buff && *buff ? strlen(*buff) : 0;
143     b->freebuff = buff ? False : True;
144     return(b);
145 }
146
147 static void
148 _DtFreeBuffer(
149         Buffer *b)
150 {
151     if (b->freebuff == True) free(b->buff);
152     free(b);
153 }
154
155 static void 
156 _DtAppendToBuffer(
157         register Buffer *b,
158         char *str,
159         register int len )
160 {
161     while (b->used + len > b->room) {
162         b->buff = (char *)realloc(b->buff, 2*b->room*(sizeof(char)));
163         b->room *= 2;
164     }
165     strncpy(b->buff + b->used, str, len);
166     b->used += len;
167 }
168
169 static Entries *
170 _DtAllocEntries( void )
171 {
172     Entries *e = (Entries *)malloc(sizeof(Entries));
173     e->room = INIT_ENTRY_SIZE;
174     e->used = 0;
175     e->entry = (Entry *)malloc(INIT_ENTRY_SIZE*sizeof(Entry));
176     return(e);
177 }
178
179 static void
180 _DtFreeEntries( 
181     Entries *e)
182 {
183     int n = 0;
184
185     while (n < e->used)
186     {
187         free(e->entry[n].tag);
188         free(e->entry[n].value);
189         n++;
190     }
191     free(e->entry);
192     free(e);
193 }
194
195 static void 
196 _DtAddEntry(
197         register Entries *e,
198         Entry entry )
199 {
200     register int n;
201
202     for (n = 0; n < e->used; n++)
203     {
204         if (strcmp(e->entry[n].tag, entry.tag) == 0)
205         { /* overwrite old entry  - free its memory first*/
206             free(e->entry[n].tag);
207             free(e->entry[n].value);
208             e->entry[n] = entry;
209             return ;  /* ok to leave, now there's only one of each tag in db */
210         }
211     }
212
213     if (e->used == e->room) {
214         e->entry = (Entry *)realloc(e->entry, 2*e->room*(sizeof(Entry)));
215         e->room *= 2;
216     }
217     entry.usable = True;
218     e->entry[e->used++] = entry;
219 }
220
221 static int 
222 _DtCompareEntries(
223         Entry *e1,
224         Entry *e2 )
225 {
226     return strcmp(e1->tag, e2->tag);
227 }
228
229 static void 
230 _DtAppendEntryToBuffer(
231         register Buffer *buffer,
232         Entry entry )
233 {
234     _DtAppendToBuffer(buffer, entry.tag, strlen(entry.tag));
235     _DtAppendToBuffer(buffer, ":\t", 2);
236     _DtAppendToBuffer(buffer, entry.value, strlen(entry.value));
237     _DtAppendToBuffer(buffer, "\n", 1);
238 }
239
240 static char * 
241 _DtFindFirst(
242         register char *string,
243         register char dest )
244 {
245     int len;
246
247     for (;;) {
248         if((len = mblen(string, MB_CUR_MAX)) > 1) {
249             string += len;
250             continue;
251         }
252         if (*string == '\0')
253             return NULL;
254         if (*string == '\\') {
255             if (*++string == '\0')
256                 return NULL;
257         }
258         else if (*string == dest)
259             return string;
260         string++;
261     }
262 }
263
264 static void 
265 _DtGetEntries(
266         register Entries *entries,
267         Buffer *buff,
268         int dosort )
269 {
270     register char *line, *colon, *temp, *str, *temp2;
271     Entry entry;
272     register int length;
273     int lineno = 0;
274
275     str = buff->buff;
276     if (!str) return;
277     for (; str < buff->buff + buff->used; str = line + 1)
278     {
279         line = _DtFindFirst(str, '\n');
280         lineno++;
281         if (line == NULL)
282             break;
283         if (str[0] == '!')
284             continue;
285         if (str[0] == '\n')
286             continue;
287         if (str[0] == '#')
288         {
289             int dummy;
290             if (sscanf (str, "# %d", &dummy) == 1) lineno = dummy - 1;
291             continue;
292         }
293         for (temp = str;
294              *temp && *temp != '\n' && isascii(*temp) && isspace((u_char)*temp);
295              temp++) ;
296         if (!*temp || *temp == '\n') continue;
297
298         colon = _DtFindFirst(str, ':');
299         if (colon == NULL)
300             break;
301         if (colon > line)
302         {
303             line[0] = '\0';
304             fprintf (stderr,
305                      "%s:  colon missing on line %d, ignoring entry \"%s\"\n",
306                      "dtprefs", lineno, str);
307             continue;
308         }
309
310         temp2 = str;
311         while (temp2[0] == ' ' || temp2[0] == '\t')
312         {
313             temp2++;
314         }
315         temp = (char *)malloc((length = colon - temp2) + 1);
316         strncpy(temp, temp2, length);
317         temp[length] = '\0';
318         while (temp[length-1] == ' ' || temp[length-1] == '\t')
319             temp[--length] = '\0';
320         entry.tag = temp;
321         
322
323         temp2 = colon + 1;
324         while (temp2[0] == ' ' || temp2[0] == '\t')
325         {
326             temp2++;
327         }
328         temp = (char *)malloc((length = line - temp2) + 1);
329         strncpy(temp, temp2, length);
330         temp[length] = '\0';
331         entry.value = temp;
332         entry.lineno = lineno;
333
334         _DtAddEntry(entries, entry);
335     }
336     
337     if (dosort && (entries->used > 0))
338       qsort(entries->entry, entries->used, sizeof(Entry), 
339             (int (*)(const void *, const void *))_DtCompareEntries);
340 }
341
342 static void 
343 _DtMergeEntries(
344         Buffer *buffer,
345         Entries new,
346         Entries old )
347 {
348     int n, o, cmp;
349
350     buffer->used = 0;
351     n = o = 0;
352     while ((n < new.used) && (o < old.used))
353     {
354         cmp = strcmp(new.entry[n].tag, old.entry[o].tag);
355         if (cmp > 0)
356         {
357             _DtAppendEntryToBuffer(buffer, old.entry[o]);
358             o++;
359         }
360         else
361         {
362             _DtAppendEntryToBuffer(buffer, new.entry[n]);
363             n++;
364             if (cmp == 0)
365             {
366                 o++;
367             }
368         }
369     }
370     
371     while (n < new.used)
372     {
373         _DtAppendEntryToBuffer(buffer, new.entry[n]);
374         n++;
375     }
376     while (o < old.used)
377     {
378         _DtAppendEntryToBuffer(buffer, old.entry[o]);
379         o++;
380     }
381     
382     _DtAppendToBuffer(buffer, "\0", 1);
383 }
384
385 static void
386 _getWinProp(
387         Display *dpy,
388         unsigned int id,
389         Window *win,
390         Atom *prop)
391 {
392   static Bool init = True;
393   static Window winprop;
394   static Atom xa_resmgr;
395   static Atom xa_prefs;
396
397   _DtSvcProcessLock();
398   if (init == True)
399   {
400     winprop = XRootWindow(dpy, 0);
401     xa_resmgr = XA_RESOURCE_MANAGER;
402     xa_prefs = XInternAtom (dpy, _XA_DT_SM_PREFERENCES, False);
403     init = False;
404   }
405   _DtSvcProcessUnlock();
406
407   *win = winprop;
408   *prop = id == _DT_ATR_RESMGR ? xa_resmgr : xa_prefs;
409 }
410
411
412 static void 
413 _DtAddToResProp(
414         Display *dpy,
415         unsigned int id,
416         Entries db)
417 {
418     char *xdefs;
419     Buffer *oldBuffer, *newBuffer;
420     Entries *oldDB;
421     int                 defStatus;
422     Atom                actualType;
423     int                 actualFormat;
424     unsigned long       nitems, leftover;
425     Window              win;
426     Atom                prop;
427
428    /*
429     * Get window and property
430     */
431     _getWinProp(dpy, id, &win, &prop);
432     if (win == (Window)0)
433     {
434       return;
435     }
436
437    /*
438     * Get resource database from specified window and property.
439     */
440     defStatus = XGetWindowProperty(dpy, win,
441                                    prop, 0L,
442                                    100000000L,False,XA_STRING,&actualType,
443                                    &actualFormat,&nitems,&leftover,
444                                    (unsigned char**) &xdefs);
445
446
447    /*
448     * Allocate oldBuffer and init from resource database string
449     */
450     oldBuffer = _DtAllocBuffer((const char**) &xdefs);
451
452    /*
453     * Allocate oldDB
454     */
455     oldDB = _DtAllocEntries();
456
457    /*
458     * Convert oldBuffer to oldDB.
459     */
460     _DtGetEntries(oldDB, oldBuffer, 1);
461
462    /*
463     * Init empty newBuffer, then populate by merging db into oldDB.
464     */
465     newBuffer = _DtAllocBuffer(NULL);
466     _DtMergeEntries(newBuffer, db, *oldDB);
467
468    /*
469     * Finally, store newBuffer into resource database.
470     */
471     XChangeProperty (dpy, win, prop,
472                      XA_STRING, 8, PropModeReplace,
473                      (unsigned char *)newBuffer->buff, newBuffer->used);
474
475     XSync(dpy, False);
476
477    /*
478     * Free buffer memory
479     */
480     if (oldBuffer->buff) XFree(oldBuffer->buff);
481     _DtFreeBuffer(oldBuffer);
482     _DtFreeBuffer(newBuffer);
483     _DtFreeEntries(oldDB);
484 }
485
486 char *
487 _DtGetResString(
488         Display *dpy,
489         unsigned int id)
490 {
491     char *xdefs;
492     Buffer *oldBuffer, *newBuffer;
493     Entries *oldDB;
494     int                 defStatus;
495     Atom                actualType;
496     int                 actualFormat;
497     unsigned long       nitems, leftover;
498     Window              win;
499     Atom                prop;
500
501    /*
502     * Get window and property
503     */
504     _getWinProp(dpy, id, &win, &prop);
505     if (win == (Window)0)
506     {
507       return NULL;
508     }
509
510    /*
511     * Get resource database from specified window and property.
512     */
513     defStatus = XGetWindowProperty(dpy, win,
514                                    prop, 0L,
515                                    100000000L,False,XA_STRING,&actualType,
516                                    &actualFormat,&nitems,&leftover,
517                                    (unsigned char**) &xdefs);
518
519     return(xdefs);
520 }
521
522 void 
523 _DtAddToResource(
524         Display *dpy,
525         const char *data )
526 {
527   _DtAddResString( dpy, data, _DT_ATR_RESMGR|_DT_ATR_PREFS);
528 }
529
530 void 
531 _DtAddResString(
532         Display *dpy,
533         const char *data, 
534         unsigned int flags)
535 {
536     char *xdefs;
537     int i;
538     Buffer *buffer; 
539     Entries *newDB;
540     int                 defStatus;
541     Atom                actualType;
542     int                 actualFormat;
543     unsigned long       nitems, leftover;
544
545     if((data == NULL) || (*data == NULL))
546     {
547         return;
548     }
549   
550    /*
551     * Init buffer with input data
552     */ 
553     buffer = _DtAllocBuffer(&data); 
554
555    /*
556     * Init, then populate, newDB from buffer
557     */
558     newDB = _DtAllocEntries();
559     _DtGetEntries(newDB, buffer, 1);
560
561     if (flags & _DT_ATR_RESMGR)
562     {
563      /*
564       * Merge newDB into RESOURCE_MANAGER
565       */
566       _DtAddToResProp(dpy, _DT_ATR_RESMGR, *newDB);
567     }
568
569     if (flags & _DT_ATR_PREFS)
570     {
571      /*
572       * Merge newDB into _DT_SM_PREFERENCES
573       */
574       _DtAddToResProp(dpy, _DT_ATR_PREFS, *newDB);
575     }
576
577    /*
578     * Free objects
579     */
580     _DtFreeBuffer(buffer);
581     _DtFreeEntries(newDB);
582 }