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