1444c061aSmrg/*
2444c061aSmrg
3444c061aSmrgCopyright 1987, 1988, 1998  The Open Group
4444c061aSmrg
5444c061aSmrgPermission to use, copy, modify, distribute, and sell this software and its
6444c061aSmrgdocumentation for any purpose is hereby granted without fee, provided that
7444c061aSmrgthe above copyright notice appear in all copies and that both that
8444c061aSmrgcopyright notice and this permission notice appear in supporting
9444c061aSmrgdocumentation.
10444c061aSmrg
11444c061aSmrgThe above copyright notice and this permission notice shall be included in
12444c061aSmrgall copies or substantial portions of the Software.
13444c061aSmrg
14444c061aSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15444c061aSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16444c061aSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17444c061aSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18444c061aSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19444c061aSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20444c061aSmrg
21444c061aSmrgExcept as contained in this notice, the name of The Open Group shall not be
22444c061aSmrgused in advertising or otherwise to promote the sale, use or other dealings
23444c061aSmrgin this Software without prior written authorization from The Open Group.
24444c061aSmrg
25444c061aSmrg*/
26444c061aSmrg/*****************************************************************
27444c061aSmrg
28444c061aSmrg(C) COPYRIGHT International Business Machines Corp. 1992,1997
29444c061aSmrg    All Rights Reserved
30444c061aSmrg
31444c061aSmrgPermission is hereby granted, free of charge, to any person obtaining a copy
32444c061aSmrgof this software and associated documentation files (the "Software"), to deal
33444c061aSmrgin the Software without restriction, including without limitation the rights
34444c061aSmrgto use, copy, modify, merge, publish, distribute, sublicense, and/or sell
35444c061aSmrgcopies of the Software.
36444c061aSmrg
37444c061aSmrgThe above copyright notice and this permission notice shall be included in
38444c061aSmrgall copies or substantial portions of the Software.
39444c061aSmrg
40444c061aSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
41444c061aSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
42444c061aSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
43444c061aSmrgTHE IBM CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
44444c061aSmrgBUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
45444c061aSmrgWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
46444c061aSmrgIN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
47444c061aSmrg
48444c061aSmrgExcept as contained in this notice, the name of the IBM Corporation shall
49444c061aSmrgnot be used in advertising or otherwise to promote the sale, use or other
50444c061aSmrgdealings in this Software without prior written authorization from the IBM
51444c061aSmrgCorporation.
52444c061aSmrg
53444c061aSmrg******************************************************************/
54444c061aSmrg
55444c061aSmrg#ifdef HAVE_CONFIG_H
56444c061aSmrg#include <config.h>
57444c061aSmrg#endif
58444c061aSmrg#include "Intrinsic.h"
59444c061aSmrg#include "IntrinsicI.h"
60444c061aSmrg#include "Core.h"
61444c061aSmrg#include "CoreP.h"
62444c061aSmrg#include "ShellP.h"
63444c061aSmrg#include "StringDefs.h"
64444c061aSmrg#include "ResConfigP.h"
65444c061aSmrg#include <X11/Xatom.h>
66444c061aSmrg#include <stdio.h>
67444c061aSmrg#include <stdlib.h>
68444c061aSmrg
69444c061aSmrg#define MAX_BUFFER 512
70444c061aSmrg
71444c061aSmrgstatic void _search_child(Widget, char *, char *, char *, char *, char, char *);
72362b94d5Smrgstatic void _set_and_search(Widget, char *, char *, char *, char *, char,
73362b94d5Smrg                            char *);
74444c061aSmrgstatic int _locate_children(Widget, Widget **);
75444c061aSmrg
76444c061aSmrg/*
77444c061aSmrg * NAME: _set_resource_values
78444c061aSmrg *
79444c061aSmrg * FUNCTION:
80362b94d5Smrg *      This function sets the value on the widget.  It must first determine
81362b94d5Smrg *      if the last part is a valid resource for that widget.  (eg.
82362b94d5Smrg *      labelString is a valid resource for label but not for bulletin board)
83362b94d5Smrg *      It must also add the resource to the application's resource database
84362b94d5Smrg *      and then query it out using specific resource strings that it builds
85362b94d5Smrg *      from the widget information.  This ensures that a customizing tool
86362b94d5Smrg *      on-the-fly paradigm is followed:  an application that is
87362b94d5Smrg *      instantaneously updated should look the same as one that is restarted
88362b94d5Smrg *      and uses the .Xdefaults file.
89444c061aSmrg *
90444c061aSmrg * PARAMETERS:
91362b94d5Smrg *      w               the widget to match
92362b94d5Smrg *      resource        the resource string to be matched
93362b94d5Smrg *      value           the value to be set
94362b94d5Smrg *      last_part       the last resource part (e.g. *background)
95444c061aSmrg *
96444c061aSmrg * RETURN VALUES: void
97444c061aSmrg *
98444c061aSmrg * ERRORS: none
99444c061aSmrg */
100444c061aSmrgstatic void
101362b94d5Smrg_set_resource_values(Widget w, char *resource, char *value, char *last_part)
102444c061aSmrg{
103362b94d5Smrg    XrmDatabase db = NULL;
104362b94d5Smrg    char *resource_name = NULL;
105362b94d5Smrg    char *resource_class = NULL;
106362b94d5Smrg    char *return_type;
107362b94d5Smrg    XrmValue return_value;
108362b94d5Smrg    char *resource_value;
109362b94d5Smrg    Widget cur = w;
110362b94d5Smrg    char *temp;
111362b94d5Smrg    XtResourceList resources_return = NULL;
112362b94d5Smrg    Cardinal num_resources_return = 0;
113362b94d5Smrg    Cardinal res_index;
114362b94d5Smrg    Boolean found_resource = False;
115362b94d5Smrg    Display *dpy;
116362b94d5Smrg    XrmDatabase tmp_db;
117362b94d5Smrg
118362b94d5Smrg    if (last_part == NULL)
119362b94d5Smrg        return;
120362b94d5Smrg
121362b94d5Smrg    if (!XtIsWidget(w)) {
122362b94d5Smrg        if (w == 0 || w->core.parent == 0)
123362b94d5Smrg            return;
124362b94d5Smrg        dpy = XtDisplay(w->core.parent);
125362b94d5Smrg    }
126362b94d5Smrg    else {
127362b94d5Smrg        dpy = XtDisplay(w);
128362b94d5Smrg    }
129362b94d5Smrg    tmp_db = XtDatabase(dpy);
130362b94d5Smrg
131362b94d5Smrg    /*
132362b94d5Smrg     * get a list of all the valid resources for this widget
133362b94d5Smrg     */
134362b94d5Smrg    XtGetResourceList(w->core.widget_class,
135362b94d5Smrg                      &resources_return, &num_resources_return);
136362b94d5Smrg
137362b94d5Smrg    /*
138362b94d5Smrg     * try to match the last_part of the resource string with
139362b94d5Smrg     * a resource in this resource list
140362b94d5Smrg     */
141362b94d5Smrg    for (res_index = 0; res_index < num_resources_return; res_index++) {
142362b94d5Smrg        if ((strcmp(last_part,
143362b94d5Smrg                    resources_return[res_index].resource_name) == 0) ||
144362b94d5Smrg            (strcmp(last_part,
145362b94d5Smrg                    resources_return[res_index].resource_class) == 0)) {
146362b94d5Smrg            found_resource = True;
147362b94d5Smrg            break;
148362b94d5Smrg        }
149362b94d5Smrg    }
150362b94d5Smrg
151362b94d5Smrg    /*
152362b94d5Smrg     * if resource is not a valid resource for this widget
153362b94d5Smrg     * or the resource name or class are NULL
154362b94d5Smrg     * then exit this function
155362b94d5Smrg     */
156362b94d5Smrg    if (!found_resource
157362b94d5Smrg        || !resources_return[res_index].resource_name
158362b94d5Smrg        || !resources_return[res_index].resource_class) {
159362b94d5Smrg        XtFree((char *) resources_return);
160362b94d5Smrg        return;
161362b94d5Smrg    }
162362b94d5Smrg
163362b94d5Smrg    /*
164362b94d5Smrg     * build the full resource name and class specifications so
165362b94d5Smrg     * that you can query the resource database
166362b94d5Smrg     *      eg: .app.button1.foreground
167362b94d5Smrg     *          .App.XmPushButton.Foreground
168362b94d5Smrg     */
169362b94d5Smrg    while (cur != NULL) {
170362b94d5Smrg        /*
171362b94d5Smrg         * create resource name string
172362b94d5Smrg         */
173362b94d5Smrg        if (resource_name) {
174362b94d5Smrg            XtAsprintf(&temp, ".%s%s", cur->core.name, resource_name);
175362b94d5Smrg            XtFree(resource_name);
176362b94d5Smrg        }
177362b94d5Smrg        else if (!XtIsWidget(cur) || !cur->core.name) {
178362b94d5Smrg            cur = XtParent(cur);
179362b94d5Smrg            continue;
180362b94d5Smrg        }
181362b94d5Smrg        else {
182362b94d5Smrg            XtAsprintf(&temp, ".%s", cur->core.name);
183362b94d5Smrg        }
184362b94d5Smrg        resource_name = temp;
185362b94d5Smrg
186362b94d5Smrg        /*
187362b94d5Smrg         * create resource class string
188362b94d5Smrg         */
189362b94d5Smrg        if ((XtIsTopLevelShell(cur)) && (XtParent(cur) == NULL)) {
190362b94d5Smrg            ApplicationShellWidget top = (ApplicationShellWidget) (cur);
191362b94d5Smrg
192362b94d5Smrg            if (resource_class) {
193362b94d5Smrg                XtAsprintf(&temp, ".%s%s",
194362b94d5Smrg                           top->application.class, resource_class);
195362b94d5Smrg            }
196362b94d5Smrg            else {
197362b94d5Smrg                XtAsprintf(&temp, ".%s", top->application.class);
198362b94d5Smrg            }
199362b94d5Smrg        }
200362b94d5Smrg        else {
201362b94d5Smrg            if (resource_class) {
202362b94d5Smrg                XtAsprintf(&temp, ".%s%s",
203362b94d5Smrg                           cur->core.widget_class->core_class.class_name,
204362b94d5Smrg                           resource_class);
205362b94d5Smrg            }
206362b94d5Smrg            else {
207362b94d5Smrg                XtAsprintf(&temp, ".%s",
208362b94d5Smrg                           cur->core.widget_class->core_class.class_name);
209362b94d5Smrg            }
210362b94d5Smrg        }
211362b94d5Smrg
212362b94d5Smrg        XtFree(resource_class);
213362b94d5Smrg        resource_class = temp;
214362b94d5Smrg
215362b94d5Smrg        cur = XtParent(cur);
216362b94d5Smrg    }
217362b94d5Smrg
218362b94d5Smrg    /*
219362b94d5Smrg     * add the resource name to the end of the resource name string
220362b94d5Smrg     */
221362b94d5Smrg    XtAsprintf(&temp, "%s.%s", resource_name,
222362b94d5Smrg               resources_return[res_index].resource_name);
223362b94d5Smrg
224362b94d5Smrg    XtFree(resource_name);
225362b94d5Smrg    resource_name = temp;
226362b94d5Smrg
227362b94d5Smrg    /*
228362b94d5Smrg     * add the resource class to the end of the resource class string
229362b94d5Smrg     */
230362b94d5Smrg    XtAsprintf(&temp, "%s.%s", resource_class,
231362b94d5Smrg               resources_return[res_index].resource_class);
232362b94d5Smrg
233362b94d5Smrg    XtFree(resource_class);
234362b94d5Smrg    resource_class = temp;
235444c061aSmrg
236444c061aSmrg#ifdef DEBUG
237362b94d5Smrg    fprintf(stderr, "resource_name = %s\n", resource_name);
238362b94d5Smrg    fprintf(stderr, "resource_class = %s\n", resource_class);
239444c061aSmrg#endif
240444c061aSmrg
241362b94d5Smrg    /*
242362b94d5Smrg     * put the resource and its value in a resource database and
243362b94d5Smrg     * then query it back out again using the specific name and
244362b94d5Smrg     * class resource strings that were built above.  This is
245362b94d5Smrg     * necessary to maintain a precedence similar to the .Xdefaults
246362b94d5Smrg     * file
247362b94d5Smrg     */
248362b94d5Smrg    XrmPutStringResource(&db, resource, value);
249362b94d5Smrg    XrmMergeDatabases(db, &tmp_db);
250362b94d5Smrg    XrmGetResource(tmp_db, resource_name, resource_class,
251362b94d5Smrg                   &return_type, &return_value);
252362b94d5Smrg    if (return_type)
253362b94d5Smrg        resource_value = XtNewString(return_value.addr);
254362b94d5Smrg    else
255362b94d5Smrg        resource_value = XtNewString(value);
256444c061aSmrg
257444c061aSmrg#ifdef DEBUG
258362b94d5Smrg    fprintf(stderr,
259362b94d5Smrg            "Apply:\n\twidget = %s\n\tlast_part = %s\n\tvalue = %s\n",
260362b94d5Smrg            (w->core.name == NULL) ? "NULL" : w->core.name,
261362b94d5Smrg            resources_return[res_index].resource_name, resource_value);
262444c061aSmrg#endif
263362b94d5Smrg    /*
264362b94d5Smrg     * use XtVaSetValues with XtVaTypedArg to convert the value of
265362b94d5Smrg     * type String the the same type as the resource (last_part).
266362b94d5Smrg     * Then set the value.
267362b94d5Smrg     */
268362b94d5Smrg    XtVaSetValues(w,
269362b94d5Smrg                  XtVaTypedArg, resources_return[res_index].resource_name,
270362b94d5Smrg                  XtRString, resource_value, strlen(resource_value) + 1, NULL);
271362b94d5Smrg
272362b94d5Smrg    XtFree((char *) resources_return);
273362b94d5Smrg    XtFree(resource_name);
274362b94d5Smrg    XtFree(resource_class);
275362b94d5Smrg    XtFree(resource_value);
276444c061aSmrg}
277444c061aSmrg
278444c061aSmrg/*
279444c061aSmrg * NAME: _apply_values_to_children
280444c061aSmrg *
281444c061aSmrg * FUNCTION:
282362b94d5Smrg *      Once the resource string matches the value must be applied to
283362b94d5Smrg *      all children if applicable. (eg. App*Form.background must apply
284362b94d5Smrg *      background to all children of the Form widget)
285444c061aSmrg *
286444c061aSmrg * PARAMETERS:
287362b94d5Smrg *      w               the widget to match
288362b94d5Smrg *      remainder       the part of the resource string left over
289362b94d5Smrg *      resource        the resource string to be matched
290362b94d5Smrg *      value           the value to be set
291a773ec55Smrg *      last_token      the last * or . before the final resource part
292362b94d5Smrg *      last_part       the last resource part (e.g. *background)
293444c061aSmrg *
294444c061aSmrg * RETURN VALUES: void
295444c061aSmrg *
296444c061aSmrg * ERRORS: none
297444c061aSmrg */
298444c061aSmrgstatic void
299362b94d5Smrg_apply_values_to_children(Widget w,
300362b94d5Smrg                          char *remainder,
301362b94d5Smrg                          char *resource,
302362b94d5Smrg                          char *value,
303362b94d5Smrg                          char last_token,
304362b94d5Smrg                          char *last_part)
305444c061aSmrg{
306362b94d5Smrg    int i;
307362b94d5Smrg    int num_children;
308362b94d5Smrg    Widget *children;
309444c061aSmrg
310362b94d5Smrg    /*
311362b94d5Smrg     * Recursively search through the children
312362b94d5Smrg     */
313362b94d5Smrg    num_children = _locate_children(w, &children);
314444c061aSmrg
315362b94d5Smrg    for (i = 0; i < num_children; i++) {
316444c061aSmrg
317444c061aSmrg#ifdef DEBUG
318362b94d5Smrg        if (XtIsWidget(children[i]) && XtIsWidget(w))
319362b94d5Smrg            fprintf(stderr, "searching child %s of parent %s\n",
320362b94d5Smrg                    children[i]->core.name, w->core.name);
321362b94d5Smrg        else
322362b94d5Smrg            fprintf(stderr, "searching child (NULL) of parent %s\n",
323362b94d5Smrg                    w->core.name);
324362b94d5Smrg        if (!XtIsWidget(children[i]))
325362b94d5Smrg            fprintf(stderr, "children[%d] is NOT a widget\n", i);
326362b94d5Smrg        if (!XtIsWidget(w))
327362b94d5Smrg            fprintf(stderr, "w is NOT a widget\n");
328444c061aSmrg#endif
329444c061aSmrg
330362b94d5Smrg        _set_resource_values(children[i], resource, value, last_part);
331362b94d5Smrg        _apply_values_to_children(children[i], remainder,
332362b94d5Smrg                                  resource, value, last_token, last_part);
333362b94d5Smrg    }
334444c061aSmrg
335362b94d5Smrg    XtFree((char *) children);
336444c061aSmrg}
337444c061aSmrg
338444c061aSmrg/*
339444c061aSmrg * NAME: _search_child
340444c061aSmrg *
341444c061aSmrg * FUNCTION:
342362b94d5Smrg *      descends through each child of the tree
343444c061aSmrg *
344444c061aSmrg * PARAMETERS:
345362b94d5Smrg *      w               the widget whose children are to be searched
346362b94d5Smrg *      indx            index into the resource string
347362b94d5Smrg *      remainder       the remaining part of the resource string
348362b94d5Smrg *      resource        the resource string to be matched
349362b94d5Smrg *      value           the value to be applied
350a773ec55Smrg *      last_token      the last * or . before the final resource part
351362b94d5Smrg *      last_part       the last resource part (e.g. *background)
352444c061aSmrg *
353444c061aSmrg * RETURN VALUES: none
354444c061aSmrg *
355444c061aSmrg * ERRORS: none
356444c061aSmrg */
357444c061aSmrgstatic void
358362b94d5Smrg_search_child(Widget w,
359362b94d5Smrg              char *indx,
360362b94d5Smrg              char *remainder,
361362b94d5Smrg              char *resource,
362362b94d5Smrg              char *value,
363362b94d5Smrg              char last_token,
364362b94d5Smrg              char *last_part)
365444c061aSmrg{
366362b94d5Smrg    int i;
367362b94d5Smrg    int num_children;
368362b94d5Smrg    Widget *children;
369362b94d5Smrg
370362b94d5Smrg    /*
371362b94d5Smrg     * Recursively search through the children
372362b94d5Smrg     */
373362b94d5Smrg    num_children = _locate_children(w, &children);
374362b94d5Smrg    for (i = 0; i < num_children; i++) {
375362b94d5Smrg        _set_and_search(children[i], indx, remainder, resource,
376362b94d5Smrg                        value, last_token, last_part);
377362b94d5Smrg    }
378362b94d5Smrg
379362b94d5Smrg    XtFree((char *) children);
380444c061aSmrg}
381444c061aSmrg
382444c061aSmrg/*
383444c061aSmrg * NAME: _get_part
384444c061aSmrg *
385444c061aSmrg * FUNCTION:
386362b94d5Smrg *      This routine will return the token and following part of the resource
387362b94d5Smrg *      when given the current index it will update the index accordingly
388444c061aSmrg *
389444c061aSmrg * PARAMETERS:
390362b94d5Smrg *      remainder       the part of the resource string left over
391362b94d5Smrg *      indx            the index into the resource string
392362b94d5Smrg *      part            the parsed off part of the resource string
393444c061aSmrg *
394444c061aSmrg * RETURN VALUES:
395362b94d5Smrg *      char            the token (* or . or ?) preceding the resource part
396362b94d5Smrg *      indx            the index into the resource string
397362b94d5Smrg *      part            the parsed off part of the resource string
398444c061aSmrg *
399444c061aSmrg * ERRORS: none
400444c061aSmrg */
401444c061aSmrgstatic char
402362b94d5Smrg_get_part(char *remainder _X_UNUSED, char **indx, char **part)
403444c061aSmrg{
404362b94d5Smrg    char buffer[MAX_BUFFER];
405362b94d5Smrg    char *buf_ptr;
406362b94d5Smrg    char token = **indx;
407362b94d5Smrg    int i = 0;
408362b94d5Smrg
409362b94d5Smrg    /*
410362b94d5Smrg     * copy the remainder part into the buffer
411362b94d5Smrg     */
412362b94d5Smrg    buf_ptr = buffer;
413362b94d5Smrg    (*indx)++;                  /* get rid of the token         */
414362b94d5Smrg    while (**indx && (**indx != '.') && (**indx != '*')) {
415362b94d5Smrg        *buf_ptr++ = *(*indx)++;
416362b94d5Smrg        if (++i >= MAX_BUFFER - 1)
417362b94d5Smrg            break;
418362b94d5Smrg    }
419362b94d5Smrg    *buf_ptr = '\0';
420362b94d5Smrg
421362b94d5Smrg    *part = XtNewString(buffer);        /* return a new string to part  */
422362b94d5Smrg
423362b94d5Smrg    if (strcmp(*indx, "") == 0)
424362b94d5Smrg        *indx = NULL;
425362b94d5Smrg
426362b94d5Smrg    return (token);             /* return the token             */
427444c061aSmrg}
428444c061aSmrg
429444c061aSmrg/*
430444c061aSmrg * NAME: _match_resource_to_widget
431444c061aSmrg *
432444c061aSmrg * FUNCTION:
433362b94d5Smrg *      This function matches the resource part to the widget name or class
434444c061aSmrg *
435444c061aSmrg * PARAMETERS:
436362b94d5Smrg *      w               the widget to match
437362b94d5Smrg *      part            the parsed off part of the resource string
438444c061aSmrg *
439444c061aSmrg * RETURN VALUES:
440362b94d5Smrg *      Boolean         true if a match occurs
441444c061aSmrg *
442444c061aSmrg * ERRORS: none
443444c061aSmrg */
444444c061aSmrgstatic Boolean
445362b94d5Smrg_match_resource_to_widget(Widget w, char *part)
446444c061aSmrg{
447362b94d5Smrg    /*
448362b94d5Smrg     * Match any widget at this level if the ? is used
449362b94d5Smrg     */
450362b94d5Smrg    if (strcmp(part, "?") == 0)
451362b94d5Smrg        return (True);
452362b94d5Smrg
453362b94d5Smrg    /*
454362b94d5Smrg     * if the object is really a widget then its name can be matched
455362b94d5Smrg     * otherwise only use its class.  Note that if you try to reference
456362b94d5Smrg     * a widget name when the object is not a widget, you may get a
457362b94d5Smrg     * core dump from an invalid pointer reference.
458362b94d5Smrg     */
459362b94d5Smrg    if (XtIsWidget(w)) {
460362b94d5Smrg        if ((strcmp(w->core.name, part) == 0) ||
461362b94d5Smrg            (strcmp(w->core.widget_class->core_class.class_name, part) == 0))
462362b94d5Smrg            return (True);
463362b94d5Smrg        else
464362b94d5Smrg            return (False);
465362b94d5Smrg    }
466362b94d5Smrg    else {
467362b94d5Smrg        if ((strcmp(w->core.widget_class->core_class.class_name, part) == 0))
468362b94d5Smrg            return (True);
469362b94d5Smrg        else
470362b94d5Smrg            return (False);
471362b94d5Smrg    }
472444c061aSmrg}
473444c061aSmrg
474444c061aSmrg/*
475444c061aSmrg * NAME: _set_and_search
476444c061aSmrg *
477444c061aSmrg * FUNCTION:
478362b94d5Smrg *      The algorithm to search the widget tree and apply a resource string
479444c061aSmrg *
480444c061aSmrg * PARAMETERS:
481362b94d5Smrg *      w               the widget to match
482362b94d5Smrg *      indx            the index into the resource string
483362b94d5Smrg *      remainder       the part of the resource string left over
484362b94d5Smrg *      resource        the resource string to be matched
485362b94d5Smrg *      value           the value to be set
486a773ec55Smrg *      last_token      the last * or . before the final resource part
487362b94d5Smrg *      last_part       the last resource part (e.g. *background)
488444c061aSmrg *
489444c061aSmrg * RETURN VALUES: none
490444c061aSmrg *
491444c061aSmrg * ERRORS: none
492444c061aSmrg *
493444c061aSmrg * ALGORITHM:
494444c061aSmrg * loop (look at all children)
495362b94d5Smrg *      if (resource segment and current widget match)
496362b94d5Smrg *              if '.'
497362b94d5Smrg *                      if at end of resource string
498362b94d5Smrg *                              set values (    .=over all children
499362b94d5Smrg *                                              *=this widget only)
500362b94d5Smrg *                      else
501362b94d5Smrg *                              descend the widget tree
502362b94d5Smrg *                              and parse off resource segment
503362b94d5Smrg *                      exit the loop
504362b94d5Smrg *              if '*'
505362b94d5Smrg *                      if at end of resource string
506362b94d5Smrg *                              set values (    .=over all children
507362b94d5Smrg *                                              *=this widget only)
508362b94d5Smrg *                      descend and parse
509362b94d5Smrg *      else
510362b94d5Smrg *              if '.'
511362b94d5Smrg *                      continue looping
512362b94d5Smrg *              if '*'
513362b94d5Smrg *                      descend but don't parse
514362b94d5Smrg *                      continue looping
515444c061aSmrg * end loop
516444c061aSmrg *
517444c061aSmrg * NOTE:  the _set_resource_values routine will not allow a value to be
518362b94d5Smrg *      set on a resource against the rules of the resource database manager
519444c061aSmrg */
520444c061aSmrgstatic void
521362b94d5Smrg_set_and_search(Widget w,
522362b94d5Smrg                char *indx,
523362b94d5Smrg                char *remainder,
524362b94d5Smrg                char *resource,
525362b94d5Smrg                char *value,
526362b94d5Smrg                char last_token,
527362b94d5Smrg                char *last_part)
528444c061aSmrg{
529362b94d5Smrg    char *part;
530362b94d5Smrg    char *local_index = indx;
531362b94d5Smrg    char token;
532362b94d5Smrg
533362b94d5Smrg    /*
534362b94d5Smrg     * parse off one part, return token and the new index
535362b94d5Smrg     */
536362b94d5Smrg    token = _get_part(remainder, &local_index, &part);
537362b94d5Smrg
538362b94d5Smrg    if (_match_resource_to_widget(w, part)) {
539362b94d5Smrg        if (token == '.') {
540362b94d5Smrg            if (local_index == NULL) {
541362b94d5Smrg                if (last_token == '.') {
542362b94d5Smrg                    _set_resource_values(w, resource, value, last_part);
543362b94d5Smrg                }
544362b94d5Smrg                else if (last_token == '*') {
545362b94d5Smrg                    _set_resource_values(w, resource, value, last_part);
546362b94d5Smrg                    _apply_values_to_children(w,
547362b94d5Smrg                                              remainder, resource, value,
548362b94d5Smrg                                              last_token, last_part);
549362b94d5Smrg                }
550362b94d5Smrg            }
551362b94d5Smrg            else
552362b94d5Smrg                _search_child(w, local_index, remainder,
553362b94d5Smrg                              resource, value, last_token, last_part);
554362b94d5Smrg            XtFree(part);
555362b94d5Smrg            return;
556362b94d5Smrg        }
557362b94d5Smrg        if (token == '*') {
558362b94d5Smrg            if (local_index == NULL) {
559362b94d5Smrg                if (last_token == '.') {
560362b94d5Smrg                    _set_resource_values(w, resource, value, last_part);
561362b94d5Smrg                }
562362b94d5Smrg                else if (last_token == '*') {
563362b94d5Smrg                    _set_resource_values(w, resource, value, last_part);
564362b94d5Smrg                    _apply_values_to_children(w,
565362b94d5Smrg                                              remainder, resource, value,
566362b94d5Smrg                                              last_token, last_part);
567362b94d5Smrg                }
568362b94d5Smrg            }
569362b94d5Smrg            else
570362b94d5Smrg                _search_child(w, local_index, remainder,
571362b94d5Smrg                              resource, value, last_token, last_part);
572362b94d5Smrg        }
573362b94d5Smrg    }
574362b94d5Smrg    else {                      /* if the widget name and class don't match the part */
575362b94d5Smrg        /* if (token == '.') just continue looping */
576362b94d5Smrg
577362b94d5Smrg        if (token == '*') {
578362b94d5Smrg            _search_child(w, indx, remainder, resource, value,
579362b94d5Smrg                          last_token, last_part);
580362b94d5Smrg        }
581362b94d5Smrg    }
582362b94d5Smrg
583362b94d5Smrg    XtFree(part);
584444c061aSmrg}
585444c061aSmrg
586444c061aSmrg/*
587444c061aSmrg * NAME: _get_last_part
588444c061aSmrg *
589444c061aSmrg * FUNCTION:
590362b94d5Smrg *      This routine will parse off the last segment of a resource string
591362b94d5Smrg *      and its token and return them.  the remainder of resource is also
592362b94d5Smrg *      returned.  strcoll is used to guarantee no problems with
593362b94d5Smrg *      international strings.
594444c061aSmrg *
595444c061aSmrg * PARAMETERS:
596362b94d5Smrg *      remainder       the part of the resource string left over
597362b94d5Smrg *      part            the parsed off part of the resource string
598444c061aSmrg *
599444c061aSmrg * RETURN VALUES:
600362b94d5Smrg *      char            the token (* or . or ?) preceding the resource part
601362b94d5Smrg *      remainder       the part of the resource string left over
602362b94d5Smrg *      part            the parsed off part of the resource string
603444c061aSmrg *
604444c061aSmrg * ERRORS: none
605444c061aSmrg */
606444c061aSmrgstatic char
607362b94d5Smrg_get_last_part(char *remainder, char **part)
608444c061aSmrg{
609362b94d5Smrg    char *loose, *tight;
610362b94d5Smrg
611362b94d5Smrg    loose = strrchr(remainder, '*');
612362b94d5Smrg    tight = strrchr(remainder, '.');
613362b94d5Smrg
614362b94d5Smrg    if ((loose == NULL) && (tight == NULL)) {
615362b94d5Smrg        *part = XtNewString(remainder);
616362b94d5Smrg        return ('.');
617362b94d5Smrg    }
618362b94d5Smrg    if ((loose == NULL) || (tight && (strcoll(loose, tight) < 0))) {
619362b94d5Smrg        *tight++ = '\0';        /* shorten the remainder string */
620362b94d5Smrg        *part = XtNewString(tight);
621362b94d5Smrg        return ('.');
622362b94d5Smrg    }
623a773ec55Smrg    if ((tight == NULL) || (strcoll(tight, loose) < 0)) {
624362b94d5Smrg        *loose++ = '\0';
625362b94d5Smrg        *part = XtNewString(loose);
626362b94d5Smrg        return ('*');
627362b94d5Smrg    }
628362b94d5Smrg    *part = NULL;
629362b94d5Smrg
630362b94d5Smrg    return ('0');               /* error - return 0 */
631444c061aSmrg}
632444c061aSmrg
633444c061aSmrg/*
634444c061aSmrg * NAME: _search_widget_tree
635444c061aSmrg *
636444c061aSmrg * FUNCTION:
637362b94d5Smrg *      This function tries to match a resource string to the widgets
638362b94d5Smrg *      it applies to.  The functions it invokes to do this then set
639362b94d5Smrg *      the value for that resource to each widget.
640362b94d5Smrg *
641362b94d5Smrg *      The resource string has to be parsed into the following format:
642362b94d5Smrg *              resource = App*Form*button1.background
643362b94d5Smrg *              remainder = *Form*button1
644362b94d5Smrg *              last_part = background          last_token = .
645362b94d5Smrg *      As the widget tree is recursively descended, these variables are
646362b94d5Smrg *      passed.  The remainder is parsed at each level in the widget
647362b94d5Smrg *      tree as the _set_and_search function attempts to match
648362b94d5Smrg *      the resource part (eg. part = Form  token = *) to a widget.  When
649362b94d5Smrg *      the entire resource string has been matched, the _set_resource_values
650362b94d5Smrg *      functions is called to apply the value to the widget or widgets.
651444c061aSmrg *
652444c061aSmrg * PARAMETERS:
653362b94d5Smrg *      w               a widget from whose toplevel shell ancestor
654362b94d5Smrg *                      the search will start
655362b94d5Smrg *      resource        the resource string to match
656362b94d5Smrg *      value           the value to apply
657444c061aSmrg *
658444c061aSmrg * RETURN VALUES: none
659444c061aSmrg *
660444c061aSmrg * ERRORS: none
661444c061aSmrg */
662444c061aSmrgstatic void
663362b94d5Smrg_search_widget_tree(Widget w, char *resource, char *value)
664444c061aSmrg{
665362b94d5Smrg    Widget parent = w;
666362b94d5Smrg    char *last_part;
667362b94d5Smrg    char *remainder = NULL;
668362b94d5Smrg    char *loose, *tight;
669362b94d5Smrg    int loose_len, tight_len;
670362b94d5Smrg
671a773ec55Smrg    if (resource == NULL)
672a773ec55Smrg        return;
673a773ec55Smrg
674362b94d5Smrg    /*
675362b94d5Smrg     * Find the root of the tree given any widget
676362b94d5Smrg     */
677362b94d5Smrg    while (XtParent(parent) != NULL) {
678362b94d5Smrg        parent = XtParent(parent);
679362b94d5Smrg    }
680444c061aSmrg#ifdef DEBUG
681362b94d5Smrg    if (XtIsWidget(w) && XtIsWidget(parent))
682362b94d5Smrg        fprintf(stderr, "widget = %s parent = %s\n",
683362b94d5Smrg                w->core.name, parent->core.name);
684362b94d5Smrg    else
685362b94d5Smrg        fprintf(stderr, "widget = NULL parent = NULL\n");
686444c061aSmrg#endif
687444c061aSmrg
688362b94d5Smrg    /*
689362b94d5Smrg     * parse off the Class name that was prepended to this string in
690362b94d5Smrg     * a customizing tool
691362b94d5Smrg     */
692362b94d5Smrg    loose = strchr(resource, '*');
693362b94d5Smrg    tight = strchr(resource, '.');
694362b94d5Smrg    if ((loose == NULL) && (tight == NULL))
695362b94d5Smrg        return;
696362b94d5Smrg
697362b94d5Smrg    loose_len = (loose) ? (int) strlen(loose) : 0;
698362b94d5Smrg    tight_len = (tight) ? (int) strlen(tight) : 0;
699362b94d5Smrg
700362b94d5Smrg    if ((loose == NULL) || (tight_len > loose_len))
701362b94d5Smrg        remainder = XtNewString(tight);
702362b94d5Smrg    else if ((tight == NULL) || (loose_len > tight_len))
703362b94d5Smrg        remainder = XtNewString(loose);
704362b94d5Smrg
705362b94d5Smrg    /*
706362b94d5Smrg     * Parse last segment off of resource string, (eg. background, font,
707362b94d5Smrg     * etc.)
708362b94d5Smrg     */
709362b94d5Smrg    if (remainder) {
710a773ec55Smrg        char last_token;
711a773ec55Smrg
712362b94d5Smrg        last_token = _get_last_part(remainder, &last_part);
713362b94d5Smrg        /*
714362b94d5Smrg         * this case covers resources of only one level (eg. *background)
715362b94d5Smrg         */
716362b94d5Smrg        if (remainder[0] == 0) {
717362b94d5Smrg            _set_resource_values(w, resource, value, last_part);
718362b94d5Smrg            if (last_token == '*')
719362b94d5Smrg                _apply_values_to_children(parent, remainder, resource,
720362b94d5Smrg                                          value, last_token, last_part);
721362b94d5Smrg            /*
722362b94d5Smrg             * all other resource strings are recursively applied to the widget tree.
723362b94d5Smrg             * Prepend a '.' to the remainder string if there is no leading token.
724362b94d5Smrg             */
725362b94d5Smrg        }
726362b94d5Smrg        else {
727362b94d5Smrg            char *indx, *copy;
728362b94d5Smrg
729362b94d5Smrg            if (remainder[0] != '*' && remainder[0] != '.') {
730362b94d5Smrg                XtAsprintf(&copy, ".%s", remainder);
731362b94d5Smrg                XtFree(remainder);
732362b94d5Smrg                remainder = copy;
733362b94d5Smrg            }
734362b94d5Smrg            indx = remainder;
735362b94d5Smrg            _set_and_search(parent, indx, remainder, resource, value,
736362b94d5Smrg                            last_token, last_part);
737362b94d5Smrg        }
738362b94d5Smrg
739362b94d5Smrg        XtFree(remainder);
740362b94d5Smrg        XtFree(last_part);
741362b94d5Smrg    }
742444c061aSmrg}
743444c061aSmrg
744444c061aSmrg/*
745444c061aSmrg * NAME: _locate_children
746444c061aSmrg *
747444c061aSmrg * FUNCTION:
748362b94d5Smrg *      returns a list of all of a widget's children
749444c061aSmrg *
750444c061aSmrg * PARAMETERS:
751362b94d5Smrg *      w               the parent to search for its children
752362b94d5Smrg *      children        the list of children that is created
753362b94d5Smrg *      normal          flag for normal children
754362b94d5Smrg *      popup           flag for popup children
755444c061aSmrg *
756444c061aSmrg * RETURN VALUES:
757362b94d5Smrg *      int             the number of children
758362b94d5Smrg *      children        the list of children found
759444c061aSmrg *
760444c061aSmrg * ERRORS: none
761444c061aSmrg */
762444c061aSmrgstatic int
763362b94d5Smrg_locate_children(Widget parent, Widget **children)
764444c061aSmrg{
765362b94d5Smrg    CompositeWidget comp = (CompositeWidget) parent;
766362b94d5Smrg    Cardinal i;
767362b94d5Smrg    int num_children = 0;
768362b94d5Smrg    int current = 0;
769362b94d5Smrg
770362b94d5Smrg    /*
771362b94d5Smrg     * count the number of children
772362b94d5Smrg     */
773362b94d5Smrg    if (XtIsWidget(parent))
774362b94d5Smrg        num_children =
775362b94d5Smrg            (int) ((Cardinal) num_children + parent->core.num_popups);
776362b94d5Smrg    if (XtIsComposite(parent))
777362b94d5Smrg        num_children =
778362b94d5Smrg            (int) ((Cardinal) num_children + comp->composite.num_children);
779362b94d5Smrg    if (num_children == 0) {
780362b94d5Smrg        *children = NULL;
781362b94d5Smrg        return (0);
782362b94d5Smrg    }
783362b94d5Smrg
784a773ec55Smrg    *children = XtMallocArray((Cardinal)num_children, (Cardinal)sizeof(Widget));
785362b94d5Smrg
786362b94d5Smrg    if (XtIsComposite(parent)) {
787362b94d5Smrg        for (i = 0; i < comp->composite.num_children; i++) {
788362b94d5Smrg            (*children)[current] = comp->composite.children[i];
789362b94d5Smrg            current++;
790362b94d5Smrg        }
791362b94d5Smrg    }
792362b94d5Smrg
793362b94d5Smrg    if (XtIsWidget(parent)) {
794362b94d5Smrg        for (i = 0; i < parent->core.num_popups; i++) {
795362b94d5Smrg            (*children)[current] = comp->core.popup_list[i];
796362b94d5Smrg            current++;
797362b94d5Smrg        }
798362b94d5Smrg    }
799362b94d5Smrg
800362b94d5Smrg    return (num_children);
801444c061aSmrg}
802444c061aSmrg
803444c061aSmrg#ifdef DEBUG
804444c061aSmrg/*
805444c061aSmrg * NAME: dump_widget_tree
806444c061aSmrg *
807444c061aSmrg * FUNCTION:
808362b94d5Smrg *      recursively printout entire widget tree
809444c061aSmrg *
810444c061aSmrg * PARAMETERS:
811362b94d5Smrg *      w               the widget to match
812362b94d5Smrg *      indent          the amount to indent each line
813444c061aSmrg *
814444c061aSmrg * RETURN VALUES: void
815444c061aSmrg *
816444c061aSmrg * ERRORS: none
817444c061aSmrg */
818444c061aSmrgstatic void
819362b94d5Smrgdump_widget_tree(Widget w, int indent)
820444c061aSmrg{
821362b94d5Smrg    int i, j;
822362b94d5Smrg    int num_children;
823362b94d5Smrg    Widget *children;
824362b94d5Smrg
825362b94d5Smrg    /*
826362b94d5Smrg     * Recursively search through the children
827362b94d5Smrg     */
828362b94d5Smrg    num_children = _locate_children(w, &children);
829362b94d5Smrg    indent += 2;
830362b94d5Smrg    for (i = 0; i < num_children; i++) {
831362b94d5Smrg        if (children[i] != NULL) {
832362b94d5Smrg            for (j = 0; j < indent; j++)
833362b94d5Smrg                fprintf(stderr, " ");
834362b94d5Smrg            if (XtIsWidget(children[i])) {
835362b94d5Smrg                fprintf(stderr, "(%s)\t", children[i]->core.name);
836362b94d5Smrg                fprintf(stderr, "(%s)\n",
837362b94d5Smrg                        children[i]->core.widget_class->core_class.class_name);
838362b94d5Smrg            }
839362b94d5Smrg            else {
840362b94d5Smrg                fprintf(stderr, "(NULL)\t");
841362b94d5Smrg                fprintf(stderr, "(%s)\n",
842362b94d5Smrg                        children[i]->core.widget_class->core_class.class_name);
843362b94d5Smrg            }
844362b94d5Smrg        }
845362b94d5Smrg        dump_widget_tree(children[i], indent);
846362b94d5Smrg    }
847362b94d5Smrg
848362b94d5Smrg    XtFree((char *) children);
849444c061aSmrg}
850444c061aSmrg#endif
851444c061aSmrg
852444c061aSmrg/*
853444c061aSmrg * NAME: _XtResourceConfiguationEH
854444c061aSmrg *
855444c061aSmrg * FUNCTION:
856362b94d5Smrg *      This function is the event handler for the on-the-fly communication
857362b94d5Smrg *      with a resource customization tool.  This event handler must be
858444c061aSmrg *      registered for the toplevel shell of each app.  This is best done
859444c061aSmrg *      in the _XtCreatePopupShell and _XtAppCreateShell functions in Xt's
860362b94d5Smrg *      Create.c source file.
861362b94d5Smrg *
862362b94d5Smrg *      The property used to communicate with a customizing tool is
863362b94d5Smrg *      placed on the toplevel shell window of the application.  The
864362b94d5Smrg *      customizing tool places a property on this window which causes
865362b94d5Smrg *      this event handler to be invoked via the PropertyNotify event.
866362b94d5Smrg *      This event handler reads the property and then deletes it from
867362b94d5Smrg *      the server.  The contents of the property are a resource string
868362b94d5Smrg *      and value.  The event handler then calls functions to walk the
869362b94d5Smrg *      applications widget tree, determining which widgets are affected
870362b94d5Smrg *      by the resource string, and then applying the value with XtSetValues.
871444c061aSmrg *
872444c061aSmrg * PARAMETERS:
873362b94d5Smrg *      w               the widget that invoked this event handler
874362b94d5Smrg *      client_data     not used
875362b94d5Smrg *      event           the event structure
876444c061aSmrg *
877444c061aSmrg * RETURN VALUES: none
878444c061aSmrg *
879444c061aSmrg * ERRORS: none
880444c061aSmrg */
881444c061aSmrgvoid
882362b94d5Smrg_XtResourceConfigurationEH(Widget w,
883362b94d5Smrg                           XtPointer client_data _X_UNUSED,
8847854a16aSmrg                           XEvent *event,
8857854a16aSmrg                           Boolean *continue_to_dispatch _X_UNUSED)
886444c061aSmrg{
887362b94d5Smrg    Atom actual_type;
888362b94d5Smrg    int actual_format;
889362b94d5Smrg    unsigned long nitems;
890362b94d5Smrg    unsigned long leftover;
891362b94d5Smrg    char *data = NULL;
892362b94d5Smrg    char *data_ptr;
893362b94d5Smrg
894444c061aSmrg#ifdef DEBUG
895362b94d5Smrg    int indent = 0;
896444c061aSmrg#endif
897362b94d5Smrg    XtPerDisplay pd;
898444c061aSmrg
899444c061aSmrg#ifdef DEBUG
900362b94d5Smrg    fprintf(stderr, "in _XtResourceConfiguationEH atom = %u\n",
901362b94d5Smrg            (unsigned) event->xproperty.atom);
902362b94d5Smrg    fprintf(stderr, "    window = %x\n", (unsigned) XtWindow(w));
903362b94d5Smrg    if (XtIsWidget(w))
904362b94d5Smrg        fprintf(stderr, "    widget = %zx   name = %s\n", (size_t) w,
905362b94d5Smrg                w->core.name);
906444c061aSmrg#endif
907444c061aSmrg
908362b94d5Smrg    pd = _XtGetPerDisplay(XtDisplay(w));
909444c061aSmrg
910362b94d5Smrg    /*
911362b94d5Smrg     * The window on which a customizing tool places the property
912362b94d5Smrg     * is determined at this point.  It should be the applications
913362b94d5Smrg     * toplevel shell window.
914362b94d5Smrg     *
915362b94d5Smrg     * A customizing tool sends a "ping" to the application on
916362b94d5Smrg     * the RCM_INIT property.  The application answers the ping
917362b94d5Smrg     * by deleting the property.
918362b94d5Smrg     */
919362b94d5Smrg    if (event->xproperty.atom == pd->rcm_init) {
920362b94d5Smrg        XDeleteProperty(XtDisplay(w), XtWindow(w), pd->rcm_init);
921444c061aSmrg
922444c061aSmrg#ifdef DEBUG
923362b94d5Smrg        if (XtIsWidget(w))
924362b94d5Smrg            fprintf(stderr, "%s\n", w->core.name);
925362b94d5Smrg        else
926362b94d5Smrg            fprintf(stderr, "NULL name\n");
927362b94d5Smrg        dump_widget_tree(w, indent);
928444c061aSmrg
929362b94d5Smrg        fprintf(stderr, "answer ping\n");
930444c061aSmrg#endif
931362b94d5Smrg    }
932362b94d5Smrg
933362b94d5Smrg    /*
934362b94d5Smrg     * This event handler ignores any property notify events that
935362b94d5Smrg     * are not RCM_INIT or RCM_DATA
936362b94d5Smrg     */
937362b94d5Smrg    if (event->xproperty.atom != pd->rcm_data)
938362b94d5Smrg        return;
939362b94d5Smrg
940362b94d5Smrg    /*
941362b94d5Smrg     * Retrieve the data from the property
942362b94d5Smrg     */
943444c061aSmrg#ifdef DEBUG
944362b94d5Smrg    fprintf(stderr, "receiving RCM_DATA property\n");
945444c061aSmrg#endif
946362b94d5Smrg    if (XGetWindowProperty(XtDisplay(w),
947362b94d5Smrg                           XtWindow(w),
948362b94d5Smrg                           pd->rcm_data, 0L, 8192L,
949362b94d5Smrg                           TRUE, XA_STRING,
950362b94d5Smrg                           &actual_type, &actual_format, &nitems, &leftover,
951362b94d5Smrg                           (unsigned char **) &data) == Success &&
952362b94d5Smrg        actual_type == XA_STRING && actual_format == 8) {
953362b94d5Smrg        /*
954362b94d5Smrg         *      data format is:
955362b94d5Smrg         *
956362b94d5Smrg         *      resource_length, resource, value
957362b94d5Smrg         *
958362b94d5Smrg         *      convert the resource_length to a long, skip over it, put a
959362b94d5Smrg         *      zero byte at the end of the resource, and pick off the
960362b94d5Smrg         *      resource and value fields.
961362b94d5Smrg         */
962362b94d5Smrg        if (data) {
963362b94d5Smrg            char *data_end = data + nitems;
964362b94d5Smrg            char *data_value;
965362b94d5Smrg            unsigned long resource_len;
966362b94d5Smrg
967362b94d5Smrg            resource_len = strtoul(data, &data_ptr, 10);
968362b94d5Smrg
969362b94d5Smrg            if (data_ptr != (char *) data) {
970362b94d5Smrg                data_ptr++;
971362b94d5Smrg                data_value = data_ptr + resource_len;
972362b94d5Smrg            }
973362b94d5Smrg            else                /* strtoul failed to convert a number */
974362b94d5Smrg                data_ptr = data_value = NULL;
975362b94d5Smrg
976362b94d5Smrg            if (data_value > data_ptr && data_value < data_end) {
977362b94d5Smrg                char *resource;
978362b94d5Smrg                char *value;
979362b94d5Smrg
980362b94d5Smrg                *data_value++ = '\0';
981362b94d5Smrg
982362b94d5Smrg                resource = XtNewString(data_ptr);
983362b94d5Smrg                value = XtNewString(data_value);
984444c061aSmrg#ifdef DEBUG
985362b94d5Smrg                fprintf(stderr, "resource_len=%lu\n", resource_len);
986362b94d5Smrg                fprintf(stderr, "resource = %s\t value = %s\n",
987362b94d5Smrg                        resource, value);
988444c061aSmrg#endif
989362b94d5Smrg                /*
990362b94d5Smrg                 * descend the application widget tree and
991362b94d5Smrg                 * apply the value to the appropriate widgets
992362b94d5Smrg                 */
993362b94d5Smrg                _search_widget_tree(w, resource, value);
994362b94d5Smrg
995362b94d5Smrg                XtFree(resource);
996362b94d5Smrg                XtFree(value);
997362b94d5Smrg            }
998362b94d5Smrg        }
999362b94d5Smrg    }
1000362b94d5Smrg
1001362b94d5Smrg    XFree((char *) data);
1002444c061aSmrg}
1003