File: | ResConfig.c |
Location: | line 728, column 6 |
Description: | Array access (from variable 'remainder') results in a null pointer dereference |
1 | /* | ||
2 | |||
3 | Copyright 1987, 1988, 1998 The Open Group | ||
4 | |||
5 | Permission to use, copy, modify, distribute, and sell this software and its | ||
6 | documentation for any purpose is hereby granted without fee, provided that | ||
7 | the above copyright notice appear in all copies and that both that | ||
8 | copyright notice and this permission notice appear in supporting | ||
9 | documentation. | ||
10 | |||
11 | The above copyright notice and this permission notice shall be included in | ||
12 | all copies or substantial portions of the Software. | ||
13 | |||
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
17 | OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN | ||
18 | AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
19 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
20 | |||
21 | Except as contained in this notice, the name of The Open Group shall not be | ||
22 | used in advertising or otherwise to promote the sale, use or other dealings | ||
23 | in this Software without prior written authorization from The Open Group. | ||
24 | |||
25 | */ | ||
26 | /***************************************************************** | ||
27 | |||
28 | (C) COPYRIGHT International Business Machines Corp. 1992,1997 | ||
29 | All Rights Reserved | ||
30 | |||
31 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
32 | of this software and associated documentation files (the "Software"), to deal | ||
33 | in the Software without restriction, including without limitation the rights | ||
34 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
35 | copies of the Software. | ||
36 | |||
37 | The above copyright notice and this permission notice shall be included in | ||
38 | all copies or substantial portions of the Software. | ||
39 | |||
40 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
41 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
42 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
43 | THE IBM CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, | ||
44 | BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, | ||
45 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR | ||
46 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
47 | |||
48 | Except as contained in this notice, the name of the IBM Corporation shall | ||
49 | not be used in advertising or otherwise to promote the sale, use or other | ||
50 | dealings in this Software without prior written authorization from the IBM | ||
51 | Corporation. | ||
52 | |||
53 | ******************************************************************/ | ||
54 | |||
55 | #ifdef HAVE_CONFIG_H1 | ||
56 | #include <config.h> | ||
57 | #endif | ||
58 | #include "Intrinsic.h" | ||
59 | #include "IntrinsicI.h" | ||
60 | #include "Core.h" | ||
61 | #include "CoreP.h" | ||
62 | #include "ShellP.h" | ||
63 | #include "StringDefs.h" | ||
64 | #include "ResConfigP.h" | ||
65 | #include <X11/Xatom.h> | ||
66 | #include <stdio.h> | ||
67 | #include <stdlib.h> | ||
68 | |||
69 | #define MAX_BUFFER512 512 | ||
70 | |||
71 | static void _search_child(Widget, char *, char *, char *, char *, char, char *); | ||
72 | static void _set_and_search(Widget, char *, char *, char *, char *, char , char *); | ||
73 | static int _locate_children(Widget, Widget **); | ||
74 | |||
75 | #if defined(sun) && !defined(SVR4) | ||
76 | # define Strtoul(a,b,c)strtoul(a,b,c) (unsigned long)strtol(a,b,c) | ||
77 | #else | ||
78 | # define Strtoul(a,b,c)strtoul(a,b,c) strtoul(a,b,c) | ||
79 | #endif | ||
80 | |||
81 | |||
82 | /* | ||
83 | * NAME: _set_resource_values | ||
84 | * | ||
85 | * FUNCTION: | ||
86 | * This function sets the value on the widget. It must first determine | ||
87 | * if the last part is a valid resource for that widget. (eg. | ||
88 | * labelString is a valid resource for label but not for bulletin board) | ||
89 | * It must also add the resource to the application's resource database | ||
90 | * and then query it out using specific resource strings that it builds | ||
91 | * from the widget information. This ensures that a customizing tool | ||
92 | * on-the-fly paradigm is followed: an application that is | ||
93 | * instantaneously updated should look the same as one that is restarted | ||
94 | * and uses the .Xdefaults file. | ||
95 | * | ||
96 | * PARAMETERS: | ||
97 | * w the widget to match | ||
98 | * resource the resource string to be matched | ||
99 | * value the value to be set | ||
100 | * last_part the last resource part (e.g. *background) | ||
101 | * | ||
102 | * RETURN VALUES: void | ||
103 | * | ||
104 | * ERRORS: none | ||
105 | */ | ||
106 | static void | ||
107 | _set_resource_values ( | ||
108 | Widget w, | ||
109 | char *resource, | ||
110 | char *value, | ||
111 | char *last_part) | ||
112 | { | ||
113 | XrmDatabase db = NULL((void*)0); | ||
114 | char *resource_name = NULL((void*)0); | ||
115 | char *resource_class = NULL((void*)0); | ||
116 | char *return_type; | ||
117 | XrmValue return_value; | ||
118 | char *resource_value; | ||
119 | Widget cur = w; | ||
120 | char *temp; | ||
121 | XtResourceList resources_return = NULL((void*)0); | ||
122 | Cardinal num_resources_return = 0; | ||
123 | Cardinal res_index; | ||
124 | Boolean found_resource = False0; | ||
125 | Display *dpy; | ||
126 | XrmDatabase tmp_db; | ||
127 | |||
128 | if (!XtIsWidget (w)(((Object)(w))->object.widget_class->core_class.class_inited & 0x04)) | ||
129 | dpy = XtDisplay (w->core.parent)(((w->core.parent)->core.screen)->display); | ||
130 | else | ||
131 | dpy = XtDisplay (w)(((w)->core.screen)->display); | ||
132 | tmp_db = XtDatabase(dpy); | ||
133 | |||
134 | /* | ||
135 | * get a list of all the valid resources for this widget | ||
136 | */ | ||
137 | XtGetResourceList (w->core.widget_class, | ||
138 | &resources_return, &num_resources_return); | ||
139 | |||
140 | /* | ||
141 | * try to match the last_part of the resource string with | ||
142 | * a resource in this resource list | ||
143 | */ | ||
144 | for (res_index=0; res_index<num_resources_return; res_index++) { | ||
145 | if ((strcmp (last_part, | ||
146 | resources_return[res_index].resource_name) == 0) || | ||
147 | (strcmp (last_part, | ||
148 | resources_return[res_index].resource_class) == 0)) { | ||
149 | found_resource = True1; | ||
150 | break; | ||
151 | } | ||
152 | } | ||
153 | |||
154 | /* | ||
155 | * if resource is not a valid resource for this widget | ||
156 | * or the resource name or class are NULL | ||
157 | * then exit this function | ||
158 | */ | ||
159 | if (!found_resource | ||
160 | || !resources_return[res_index].resource_name | ||
161 | || !resources_return[res_index].resource_class) { | ||
162 | XtFree ((char *) resources_return); | ||
163 | return; | ||
164 | } | ||
165 | |||
166 | /* | ||
167 | * build the full resource name and class specifications so | ||
168 | * that you can query the resource database | ||
169 | * eg: .app.button1.foreground | ||
170 | * .App.XmPushButton.Foreground | ||
171 | */ | ||
172 | while (cur != NULL((void*)0)) { | ||
173 | /* | ||
174 | * create resource name string | ||
175 | */ | ||
176 | if (resource_name) { | ||
177 | XtAsprintf (&temp, ".%s%s", cur->core.name, resource_name); | ||
178 | XtFree (resource_name); | ||
179 | } else if (!XtIsWidget (cur)(((Object)(cur))->object.widget_class->core_class.class_inited & 0x04) || !cur->core.name) { | ||
180 | cur = XtParent(cur)((cur)->core.parent); | ||
181 | continue; | ||
182 | } else { | ||
183 | XtAsprintf (&temp, ".%s", cur->core.name); | ||
184 | } | ||
185 | resource_name = temp; | ||
186 | |||
187 | /* | ||
188 | * create resource class string | ||
189 | */ | ||
190 | if ((XtIsTopLevelShell (cur)(((Object)(cur))->object.widget_class->core_class.class_inited & 0x80)) && (XtParent (cur)((cur)->core.parent) == NULL((void*)0))) { | ||
191 | ApplicationShellWidget top = | ||
192 | (ApplicationShellWidget) (cur); | ||
193 | |||
194 | if (resource_class) { | ||
195 | XtAsprintf (&temp, ".%s%s", | ||
196 | top->application.class, resource_class); | ||
197 | } else { | ||
198 | XtAsprintf (&temp, ".%s", | ||
199 | top->application.class); | ||
200 | } | ||
201 | } else { | ||
202 | if (resource_class) { | ||
203 | XtAsprintf (&temp, ".%s%s", | ||
204 | cur->core.widget_class->core_class.class_name, | ||
205 | resource_class); | ||
206 | } else { | ||
207 | XtAsprintf (&temp, ".%s", | ||
208 | cur->core.widget_class->core_class.class_name); | ||
209 | } | ||
210 | } | ||
211 | if (resource_class != NULL((void*)0)) | ||
212 | XtFree (resource_class); | ||
213 | resource_class = temp; | ||
214 | |||
215 | cur = XtParent(cur)((cur)->core.parent); | ||
216 | } | ||
217 | |||
218 | /* | ||
219 | * add the resource name to the end of the resource name string | ||
220 | */ | ||
221 | XtAsprintf (&temp, "%s.%s", resource_name, | ||
222 | resources_return[res_index].resource_name); | ||
223 | if (resource_name != NULL((void*)0)) | ||
224 | XtFree (resource_name); | ||
225 | resource_name = temp; | ||
226 | |||
227 | /* | ||
228 | * add the resource class to the end of the resource class string | ||
229 | */ | ||
230 | XtAsprintf (&temp, "%s.%s", resource_class, | ||
231 | resources_return[res_index].resource_class); | ||
232 | if (resource_class != NULL((void*)0)) | ||
233 | XtFree (resource_class); | ||
234 | resource_class = temp; | ||
235 | |||
236 | #ifdef DEBUG | ||
237 | fprintf (stderrstderr, "resource_name = %s\n", resource_name); | ||
238 | fprintf (stderrstderr, "resource_class = %s\n", resource_class); | ||
239 | #endif | ||
240 | |||
241 | /* | ||
242 | * put the resource and its value in a resource database and | ||
243 | * then query it back out again using the specific name and | ||
244 | * class resource strings that were built above. This is | ||
245 | * necessary to maintain a precedence similar to the .Xdefaults | ||
246 | * file | ||
247 | */ | ||
248 | XrmPutStringResource (&db, resource, value); | ||
249 | XrmMergeDatabases (db, &tmp_db); | ||
250 | XrmGetResource (tmp_db, resource_name, resource_class, | ||
251 | &return_type, &return_value); | ||
252 | if (return_type) | ||
253 | resource_value = XtNewString (return_value.addr)((return_value.addr) != ((void*)0) ? (strcpy(XtMalloc((unsigned )strlen(return_value.addr) + 1), return_value.addr)) : ((void *)0)); | ||
254 | else | ||
255 | resource_value = XtNewString (value)((value) != ((void*)0) ? (strcpy(XtMalloc((unsigned)strlen(value ) + 1), value)) : ((void*)0)); | ||
256 | |||
257 | #ifdef DEBUG | ||
258 | fprintf (stderrstderr, | ||
259 | "Apply:\n\twidget = %s\n\tlast_part = %s\n\tvalue = %s\n", | ||
260 | (w->core.name == NULL((void*)0)) ? "NULL" : w->core.name, | ||
261 | resources_return[res_index].resource_name, | ||
262 | resource_value); | ||
263 | #endif | ||
264 | /* | ||
265 | * use XtVaSetValues with XtVaTypedArg to convert the value of | ||
266 | * type String the the same type as the resource (last_part). | ||
267 | * Then set the value. | ||
268 | */ | ||
269 | XtVaSetValues (w, | ||
270 | XtVaTypedArg"XtVaTypedArg", resources_return[res_index].resource_name, | ||
271 | XtRString((char*)&XtStrings[1797]), resource_value, | ||
272 | strlen (resource_value) + 1, | ||
273 | NULL((void*)0)); | ||
274 | |||
275 | XtFree ((char *) resources_return); | ||
276 | XtFree (resource_name); | ||
277 | XtFree (resource_class); | ||
278 | XtFree (resource_value); | ||
279 | } | ||
280 | |||
281 | /* | ||
282 | * NAME: _apply_values_to_children | ||
283 | * | ||
284 | * FUNCTION: | ||
285 | * Once the resource string matches the value must be applied to | ||
286 | * all children if applicable. (eg. App*Form.background must apply | ||
287 | * background to all children of the Form widget) | ||
288 | * | ||
289 | * PARAMETERS: | ||
290 | * w the widget to match | ||
291 | * remainder the part of the resource string left over | ||
292 | * resource the resource string to be matched | ||
293 | * value the value to be set | ||
294 | * last_token the last * or . before the final resoruce part | ||
295 | * last_part the last resource part (e.g. *background) | ||
296 | * | ||
297 | * RETURN VALUES: void | ||
298 | * | ||
299 | * ERRORS: none | ||
300 | */ | ||
301 | static void | ||
302 | _apply_values_to_children ( | ||
303 | Widget w, | ||
304 | char *remainder, | ||
305 | char *resource, | ||
306 | char *value, | ||
307 | char last_token, | ||
308 | char *last_part) | ||
309 | { | ||
310 | int i; | ||
311 | int num_children; | ||
312 | Widget *children; | ||
313 | |||
314 | /* | ||
315 | * Recursively search through the children | ||
316 | */ | ||
317 | num_children = _locate_children (w, &children); | ||
318 | |||
319 | for (i=0; i<num_children; i++) { | ||
320 | |||
321 | #ifdef DEBUG | ||
322 | if (XtIsWidget (children[i])(((Object)(children[i]))->object.widget_class->core_class .class_inited & 0x04) && XtIsWidget (w)(((Object)(w))->object.widget_class->core_class.class_inited & 0x04)) | ||
323 | fprintf (stderrstderr, "searching child %s of parent %s\n", | ||
324 | children[i]->core.name, w->core.name); | ||
325 | else | ||
326 | fprintf (stderrstderr,"searching child (NULL) of parent %s\n", | ||
327 | w->core.name); | ||
328 | if (!XtIsWidget (children[i])(((Object)(children[i]))->object.widget_class->core_class .class_inited & 0x04)) | ||
329 | fprintf (stderrstderr, "children[%d] is NOT a widget\n", i); | ||
330 | if (!XtIsWidget (w)(((Object)(w))->object.widget_class->core_class.class_inited & 0x04)) | ||
331 | fprintf (stderrstderr, "w is NOT a widget\n"); | ||
332 | #endif | ||
333 | |||
334 | _set_resource_values (children[i], resource, value, last_part); | ||
335 | _apply_values_to_children (children[i], remainder, | ||
336 | resource, value, last_token, last_part); | ||
337 | } | ||
338 | |||
339 | XtFree ((char *)children); | ||
340 | } | ||
341 | |||
342 | /* | ||
343 | * NAME: _search_child | ||
344 | * | ||
345 | * FUNCTION: | ||
346 | * descends through each child of the tree | ||
347 | * | ||
348 | * PARAMETERS: | ||
349 | * w the widget whose children are to be searched | ||
350 | * indx index into the resource string | ||
351 | * remainder the remaining part of the resource string | ||
352 | * resource the resource string to be matched | ||
353 | * value the value to be applied | ||
354 | * last_token the last * or . before the final resoruce part | ||
355 | * last_part the last resource part (e.g. *background) | ||
356 | * | ||
357 | * RETURN VALUES: none | ||
358 | * | ||
359 | * ERRORS: none | ||
360 | */ | ||
361 | static void | ||
362 | _search_child ( | ||
363 | Widget w, | ||
364 | char *indx, | ||
365 | char *remainder, | ||
366 | char *resource, | ||
367 | char *value, | ||
368 | char last_token, | ||
369 | char *last_part) | ||
370 | { | ||
371 | int i; | ||
372 | int num_children; | ||
373 | Widget *children; | ||
374 | |||
375 | /* | ||
376 | * Recursively search through the children | ||
377 | */ | ||
378 | num_children = _locate_children (w, &children); | ||
379 | for (i=0; i<num_children; i++) { | ||
380 | _set_and_search (children[i], indx, remainder, resource, | ||
381 | value, last_token, last_part); | ||
382 | } | ||
383 | |||
384 | XtFree ((char *)children); | ||
385 | } | ||
386 | |||
387 | /* | ||
388 | * NAME: _get_part | ||
389 | * | ||
390 | * FUNCTION: | ||
391 | * This routine will return the token and following part of the resource | ||
392 | * when given the current index it will update the index accordingly | ||
393 | * | ||
394 | * PARAMETERS: | ||
395 | * remainder the part of the resource string left over | ||
396 | * indx the index into the resource string | ||
397 | * part the parsed off part of the resource string | ||
398 | * | ||
399 | * RETURN VALUES: | ||
400 | * char the token (* or . or ?) preceding the resource part | ||
401 | * indx the index into the resource string | ||
402 | * part the parsed off part of the resource string | ||
403 | * | ||
404 | * ERRORS: none | ||
405 | */ | ||
406 | /* ARGSUSED */ | ||
407 | static char | ||
408 | _get_part ( | ||
409 | char *remainder, | ||
410 | char **indx, | ||
411 | char **part) | ||
412 | { | ||
413 | char buffer[MAX_BUFFER512]; | ||
414 | char *buf_ptr; | ||
415 | char token = **indx; | ||
416 | int i = 0; | ||
417 | |||
418 | /* | ||
419 | * copy the remainder part into the buffer | ||
420 | */ | ||
421 | buf_ptr = buffer; | ||
422 | (*indx)++; /* get rid of the token */ | ||
423 | while (**indx && (**indx != '.') && (**indx != '*')) { | ||
424 | *buf_ptr++ = *(*indx)++; | ||
425 | if (++i >= MAX_BUFFER512 - 1) | ||
426 | break; | ||
427 | } | ||
428 | *buf_ptr = '\0'; | ||
429 | |||
430 | *part = XtNewString (buffer)((buffer) != ((void*)0) ? (strcpy(XtMalloc((unsigned)strlen(buffer ) + 1), buffer)) : ((void*)0)); /* return a new string to part */ | ||
431 | |||
432 | if (strcmp (*indx, "") == 0) | ||
433 | *indx = NULL((void*)0); | ||
434 | |||
435 | return (token); /* return the token */ | ||
436 | } | ||
437 | |||
438 | /* | ||
439 | * NAME: _match_resource_to_widget | ||
440 | * | ||
441 | * FUNCTION: | ||
442 | * This function matches the resource part to the widget name or class | ||
443 | * | ||
444 | * PARAMETERS: | ||
445 | * w the widget to match | ||
446 | * part the parsed off part of the resource string | ||
447 | * | ||
448 | * RETURN VALUES: | ||
449 | * Boolean true if a match occurs | ||
450 | * | ||
451 | * ERRORS: none | ||
452 | */ | ||
453 | static Boolean | ||
454 | _match_resource_to_widget ( | ||
455 | Widget w, | ||
456 | char *part) | ||
457 | { | ||
458 | /* | ||
459 | * Match any widget at this level if the ? is used | ||
460 | */ | ||
461 | if (strcmp (part, "?") == 0) | ||
462 | return (True1); | ||
463 | |||
464 | /* | ||
465 | * if the object is really a widget then its name can be matched | ||
466 | * otherwise only use its class. Note that if you try to reference | ||
467 | * a widget name when the object is not a widget, you may get a | ||
468 | * core dump from an invalid pointer reference. | ||
469 | */ | ||
470 | if (XtIsWidget (w)(((Object)(w))->object.widget_class->core_class.class_inited & 0x04)) { | ||
471 | if ((strcmp (w->core.name, part) == 0) || | ||
472 | (strcmp (w->core.widget_class->core_class.class_name, | ||
473 | part) == 0)) | ||
474 | return (True1); | ||
475 | else | ||
476 | return (False0); | ||
477 | } else { | ||
478 | if ((strcmp (w->core.widget_class->core_class.class_name, | ||
479 | part) == 0)) | ||
480 | return (True1); | ||
481 | else | ||
482 | return (False0); | ||
483 | } | ||
484 | } | ||
485 | |||
486 | /* | ||
487 | * NAME: _set_and_search | ||
488 | * | ||
489 | * FUNCTION: | ||
490 | * The algorithm to search the widget tree and apply a resource string | ||
491 | * | ||
492 | * PARAMETERS: | ||
493 | * w the widget to match | ||
494 | * indx the index into the resource string | ||
495 | * remainder the part of the resource string left over | ||
496 | * resource the resource string to be matched | ||
497 | * value the value to be set | ||
498 | * last_token the last * or . before the final resoruce part | ||
499 | * last_part the last resource part (e.g. *background) | ||
500 | * | ||
501 | * RETURN VALUES: none | ||
502 | * | ||
503 | * ERRORS: none | ||
504 | * | ||
505 | * ALGORITHM: | ||
506 | * loop (look at all children) | ||
507 | * if (resource segment and current widget match) | ||
508 | * if '.' | ||
509 | * if at end of resource string | ||
510 | * set values ( .=over all children | ||
511 | * *=this widget only) | ||
512 | * else | ||
513 | * descend the widget tree | ||
514 | * and parse off resource segment | ||
515 | * exit the loop | ||
516 | * if '*' | ||
517 | * if at end of resource string | ||
518 | * set values ( .=over all children | ||
519 | * *=this widget only) | ||
520 | * descend and parse | ||
521 | * else | ||
522 | * if '.' | ||
523 | * continue looping | ||
524 | * if '*' | ||
525 | * descend but don't parse | ||
526 | * continue looping | ||
527 | * end loop | ||
528 | * | ||
529 | * NOTE: the _set_resource_values routine will not allow a value to be | ||
530 | * set on a resource against the rules of the resource database manager | ||
531 | */ | ||
532 | static void | ||
533 | _set_and_search ( | ||
534 | Widget w, | ||
535 | char *indx, | ||
536 | char *remainder, | ||
537 | char *resource, | ||
538 | char *value, | ||
539 | char last_token, | ||
540 | char *last_part) | ||
541 | { | ||
542 | char *part; | ||
543 | char *local_index = indx; | ||
544 | char token; | ||
545 | |||
546 | /* | ||
547 | * parse off one part, return token and the new index | ||
548 | */ | ||
549 | token = _get_part (remainder, &local_index, &part); | ||
550 | |||
551 | if (_match_resource_to_widget (w, part)) { | ||
552 | if (token == '.') { | ||
553 | if (local_index == NULL((void*)0)) { | ||
554 | if (last_token == '.') { | ||
555 | _set_resource_values (w, resource, | ||
556 | value, last_part); | ||
557 | } else if (last_token == '*') { | ||
558 | _set_resource_values (w, resource, | ||
559 | value, last_part); | ||
560 | _apply_values_to_children (w, | ||
561 | remainder, resource, value, | ||
562 | last_token, last_part); | ||
563 | } | ||
564 | } else | ||
565 | _search_child (w, local_index, remainder, | ||
566 | resource, value, last_token, last_part); | ||
567 | return; | ||
568 | } | ||
569 | if (token == '*') { | ||
570 | if (local_index == NULL((void*)0)) { | ||
571 | if (last_token == '.') { | ||
572 | _set_resource_values (w, resource, | ||
573 | value, last_part); | ||
574 | } else if (last_token == '*') { | ||
575 | _set_resource_values (w, resource, | ||
576 | value, last_part); | ||
577 | _apply_values_to_children ( w, | ||
578 | remainder, resource, value, | ||
579 | last_token, last_part); | ||
580 | } | ||
581 | } else | ||
582 | _search_child (w, local_index, remainder, | ||
583 | resource, value, last_token, last_part); | ||
584 | } | ||
585 | } else {/* if the widget name and class don't match the part */ | ||
586 | /* if (token == '.') just continue looping */ | ||
587 | |||
588 | if (token == '*') { | ||
589 | _search_child (w, indx, remainder, resource, value, | ||
590 | last_token, last_part); | ||
591 | } | ||
592 | } | ||
593 | |||
594 | XtFree (part); | ||
595 | } | ||
596 | |||
597 | /* | ||
598 | * NAME: _get_last_part | ||
599 | * | ||
600 | * FUNCTION: | ||
601 | * This routine will parse off the last segment of a resource string | ||
602 | * and its token and return them. the remainder of resource is also | ||
603 | * returned. strcoll is used to guarantee no problems with | ||
604 | * international strings. | ||
605 | * | ||
606 | * PARAMETERS: | ||
607 | * remainder the part of the resource string left over | ||
608 | * part the parsed off part of the resource string | ||
609 | * | ||
610 | * RETURN VALUES: | ||
611 | * char the token (* or . or ?) preceding the resource part | ||
612 | * remainder the part of the resource string left over | ||
613 | * part the parsed off part of the resource string | ||
614 | * | ||
615 | * ERRORS: none | ||
616 | */ | ||
617 | static char | ||
618 | _get_last_part ( | ||
619 | char *remainder, | ||
620 | char **part) | ||
621 | { | ||
622 | char *loose, *tight; | ||
623 | |||
624 | loose = strrchr (remainder, '*'); | ||
625 | tight = strrchr (remainder, '.'); | ||
626 | |||
627 | if ((loose == NULL((void*)0)) && (tight == NULL((void*)0))) { | ||
628 | *part = XtNewString (remainder)((remainder) != ((void*)0) ? (strcpy(XtMalloc((unsigned)strlen (remainder) + 1), remainder)) : ((void*)0)); | ||
629 | return ('.'); | ||
630 | } | ||
631 | if ((loose == NULL((void*)0)) || (tight && (strcoll (loose, tight) < 0))) { | ||
632 | *tight++ = '\0'; /* shorten the remainder string */ | ||
633 | *part = XtNewString (tight)((tight) != ((void*)0) ? (strcpy(XtMalloc((unsigned)strlen(tight ) + 1), tight)) : ((void*)0)); | ||
634 | return ('.'); | ||
635 | } | ||
636 | if ((tight == NULL((void*)0)) || (loose && (strcoll (tight, loose) < 0))) { | ||
637 | *loose++ = '\0'; | ||
638 | *part = XtNewString (loose)((loose) != ((void*)0) ? (strcpy(XtMalloc((unsigned)strlen(loose ) + 1), loose)) : ((void*)0)); | ||
639 | return ('*'); | ||
640 | } | ||
641 | *part = NULL((void*)0); | ||
642 | |||
643 | return ('0'); /* error - return 0 */ | ||
644 | } | ||
645 | |||
646 | /* | ||
647 | * NAME: _search_widget_tree | ||
648 | * | ||
649 | * FUNCTION: | ||
650 | * This function tries to match a resource string to the widgets | ||
651 | * it applies to. The functions it invokes to do this then set | ||
652 | * the value for that resource to each widget. | ||
653 | * | ||
654 | * The resource string has to be parsed into the following format: | ||
655 | * resource = App*Form*button1.background | ||
656 | * remainder = *Form*button1 | ||
657 | * last_part = background last_token = . | ||
658 | * As the widget tree is recursively descended, these variables are | ||
659 | * passed. The remainder is parsed at each level in the widget | ||
660 | * tree as the _set_and_search function attempts to match | ||
661 | * the resource part (eg. part = Form token = *) to a widget. When | ||
662 | * the entire resource string has been matched, the _set_resource_values | ||
663 | * functions is called to apply the value to the widget or widgets. | ||
664 | * | ||
665 | * PARAMETERS: | ||
666 | * w a widget from whose toplevel shell ancestor | ||
667 | * the search will start | ||
668 | * resource the resource string to match | ||
669 | * value the value to apply | ||
670 | * | ||
671 | * RETURN VALUES: none | ||
672 | * | ||
673 | * ERRORS: none | ||
674 | */ | ||
675 | static void | ||
676 | _search_widget_tree ( | ||
677 | Widget w, | ||
678 | char *resource, | ||
679 | char *value) | ||
680 | { | ||
681 | Widget parent = w; | ||
682 | char *last_part; | ||
683 | char *remainder = NULL((void*)0); | ||
684 | char last_token; | ||
685 | char *indx, *copy; | ||
686 | char *loose, *tight; | ||
687 | int loose_len, tight_len; | ||
688 | |||
689 | /* | ||
690 | * Find the root of the tree given any widget | ||
691 | */ | ||
692 | while (XtParent(parent)((parent)->core.parent) != NULL((void*)0)) { | ||
| |||
693 | parent = XtParent(parent)((parent)->core.parent); | ||
694 | } | ||
695 | #ifdef DEBUG | ||
696 | if (XtIsWidget (w)(((Object)(w))->object.widget_class->core_class.class_inited & 0x04) && XtIsWidget (parent)(((Object)(parent))->object.widget_class->core_class.class_inited & 0x04)) | ||
697 | fprintf (stderrstderr, "widget = %s parent = %s\n", | ||
698 | w->core.name, parent->core.name); | ||
699 | else | ||
700 | fprintf (stderrstderr, "widget = NULL parent = NULL\n"); | ||
701 | #endif | ||
702 | |||
703 | /* | ||
704 | * parse off the Class name that was prepended to this string in | ||
705 | * a customizing tool | ||
706 | */ | ||
707 | loose = strchr (resource, '*'); | ||
708 | tight = strchr (resource, '.'); | ||
709 | if ((loose == NULL((void*)0)) && (tight == NULL((void*)0))) | ||
| |||
| |||
710 | return; | ||
711 | |||
712 | loose_len = (loose) ? strlen (loose) : 0; | ||
| |||
713 | tight_len = (tight) ? strlen (tight) : 0; | ||
| |||
| |||
714 | |||
715 | if ((loose == NULL((void*)0)) || (tight_len > loose_len)) | ||
| |||
716 | remainder = XtNewString (tight)((tight) != ((void*)0) ? (strcpy(XtMalloc((unsigned)strlen(tight ) + 1), tight)) : ((void*)0)); | ||
717 | else if ((tight == NULL((void*)0)) || (loose_len > tight_len)) | ||
| |||
718 | remainder = XtNewString (loose)((loose) != ((void*)0) ? (strcpy(XtMalloc((unsigned)strlen(loose ) + 1), loose)) : ((void*)0)); | ||
719 | |||
720 | /* | ||
721 | * Parse last segment off of resource string, (eg. background, font, | ||
722 | * etc.) | ||
723 | */ | ||
724 | last_token = _get_last_part (remainder, &last_part); | ||
725 | /* | ||
726 | * this case covers resources of only one level (eg. *background) | ||
727 | */ | ||
728 | if (remainder[0] == 0) { | ||
| |||
729 | _set_resource_values (w, resource, value, last_part); | ||
730 | if (last_token == '*') | ||
731 | _apply_values_to_children (parent, remainder, resource, | ||
732 | value, last_token, last_part); | ||
733 | /* | ||
734 | * all other resource strings are recursively applied to the widget tree. | ||
735 | * Prepend a '.' to the remainder string if there is no leading token. | ||
736 | */ | ||
737 | } else { | ||
738 | if (remainder[0] != '*' && remainder[0] != '.') { | ||
739 | XtAsprintf (©, ".%s", remainder); | ||
740 | XtFree (remainder); | ||
741 | remainder = copy; | ||
742 | } | ||
743 | indx = remainder; | ||
744 | _set_and_search (parent, indx, remainder, resource, value, | ||
745 | last_token, last_part); | ||
746 | } | ||
747 | |||
748 | XtFree (remainder); | ||
749 | XtFree (last_part); | ||
750 | } | ||
751 | |||
752 | /* | ||
753 | * NAME: _locate_children | ||
754 | * | ||
755 | * FUNCTION: | ||
756 | * returns a list of all of a widget's children | ||
757 | * | ||
758 | * PARAMETERS: | ||
759 | * w the parent to search for its children | ||
760 | * children the list of children that is created | ||
761 | * normal flag for normal children | ||
762 | * popup flag for popup children | ||
763 | * | ||
764 | * RETURN VALUES: | ||
765 | * int the number of children | ||
766 | * children the list of children found | ||
767 | * | ||
768 | * ERRORS: none | ||
769 | */ | ||
770 | static int | ||
771 | _locate_children ( | ||
772 | Widget parent, | ||
773 | Widget **children) | ||
774 | { | ||
775 | CompositeWidget comp = (CompositeWidget) parent; | ||
776 | Cardinal i; | ||
777 | int num_children = 0; | ||
778 | int current = 0; | ||
779 | |||
780 | /* | ||
781 | * count the number of children | ||
782 | */ | ||
783 | if (XtIsWidget (parent)(((Object)(parent))->object.widget_class->core_class.class_inited & 0x04)) | ||
784 | num_children += parent->core.num_popups; | ||
785 | if (XtIsComposite (parent)(((Object)(parent))->object.widget_class->core_class.class_inited & 0x08)) | ||
786 | num_children += comp->composite.num_children; | ||
787 | if (num_children == 0) { | ||
788 | *children = NULL((void*)0); | ||
789 | return (0); | ||
790 | } | ||
791 | |||
792 | *children = (Widget *) | ||
793 | XtMalloc ((Cardinal) sizeof(Widget) * num_children); | ||
794 | |||
795 | if (XtIsComposite (parent)(((Object)(parent))->object.widget_class->core_class.class_inited & 0x08)) { | ||
796 | for (i=0; i<comp->composite.num_children; i++) { | ||
797 | (*children)[current] = comp->composite.children[i]; | ||
798 | current++; | ||
799 | } | ||
800 | } | ||
801 | |||
802 | if (XtIsWidget (parent)(((Object)(parent))->object.widget_class->core_class.class_inited & 0x04)) { | ||
803 | for (i=0; i<parent->core.num_popups; i++) { | ||
804 | (*children)[current] = comp->core.popup_list[i]; | ||
805 | current++; | ||
806 | } | ||
807 | } | ||
808 | |||
809 | return (num_children); | ||
810 | } | ||
811 | |||
812 | #ifdef DEBUG | ||
813 | /* | ||
814 | * NAME: dump_widget_tree | ||
815 | * | ||
816 | * FUNCTION: | ||
817 | * recursively printout entire widget tree | ||
818 | * | ||
819 | * PARAMETERS: | ||
820 | * w the widget to match | ||
821 | * indent the amount to indent each line | ||
822 | * | ||
823 | * RETURN VALUES: void | ||
824 | * | ||
825 | * ERRORS: none | ||
826 | */ | ||
827 | static void | ||
828 | dump_widget_tree ( | ||
829 | Widget w, | ||
830 | int indent) | ||
831 | { | ||
832 | int i,j; | ||
833 | int num_children; | ||
834 | Widget *children; | ||
835 | |||
836 | /* | ||
837 | * Recursively search through the children | ||
838 | */ | ||
839 | num_children = _locate_children (w, &children); | ||
840 | indent += 2; | ||
841 | for (i=0; i<num_children; i++) { | ||
842 | if (children[i] != NULL((void*)0)) { | ||
843 | for (j=0; j<indent; j++) | ||
844 | fprintf (stderrstderr, " "); | ||
845 | if (XtIsWidget (children[i])(((Object)(children[i]))->object.widget_class->core_class .class_inited & 0x04)) { | ||
846 | fprintf (stderrstderr, "(%s)\t",children[i]->core.name); | ||
847 | fprintf (stderrstderr, "(%s)\n", | ||
848 | children[i]->core.widget_class->core_class.class_name); | ||
849 | } else { | ||
850 | fprintf (stderrstderr, "(NULL)\t"); | ||
851 | fprintf (stderrstderr, "(%s)\n", | ||
852 | children[i]->core.widget_class->core_class.class_name); | ||
853 | } | ||
854 | } | ||
855 | dump_widget_tree (children[i], indent); | ||
856 | } | ||
857 | |||
858 | XtFree ((char *)children); | ||
859 | } | ||
860 | #endif | ||
861 | |||
862 | /* | ||
863 | * NAME: _XtResourceConfiguationEH | ||
864 | * | ||
865 | * FUNCTION: | ||
866 | * This function is the event handler for the on-the-fly communication | ||
867 | * with a resource customization tool. This event handler must be | ||
868 | * registered for the toplevel shell of each app. This is best done | ||
869 | * in the _XtCreatePopupShell and _XtAppCreateShell functions in Xt's | ||
870 | * Create.c source file. | ||
871 | * | ||
872 | * The property used to communicate with a customizing tool is | ||
873 | * placed on the toplevel shell window of the application. The | ||
874 | * customizing tool places a property on this window which causes | ||
875 | * this event handler to be invoked via the PropertyNotify event. | ||
876 | * This event handler reads the property and then deletes it from | ||
877 | * the server. The contents of the property are a resource string | ||
878 | * and value. The event handler then calls functions to walk the | ||
879 | * applications widget tree, determining which widgets are affected | ||
880 | * by the resource string, and then applying the value with XtSetValues. | ||
881 | * | ||
882 | * PARAMETERS: | ||
883 | * w the widget that invoked this event handler | ||
884 | * client_data not used | ||
885 | * event the event structure | ||
886 | * | ||
887 | * RETURN VALUES: none | ||
888 | * | ||
889 | * ERRORS: none | ||
890 | */ | ||
891 | /* ARGSUSED */ | ||
892 | void | ||
893 | _XtResourceConfigurationEH ( | ||
894 | Widget w, | ||
895 | XtPointer client_data, | ||
896 | XEvent *event) | ||
897 | { | ||
898 | Atom actual_type; | ||
899 | int actual_format; | ||
900 | unsigned long nitems; | ||
901 | unsigned long leftover; | ||
902 | unsigned char *data = NULL((void*)0); | ||
903 | unsigned long resource_len; | ||
904 | char *data_ptr; | ||
905 | char *resource; | ||
906 | char *value; | ||
907 | #ifdef DEBUG | ||
908 | int indent = 0; | ||
909 | #endif | ||
910 | XtPerDisplay pd; | ||
911 | |||
912 | #ifdef DEBUG | ||
913 | fprintf (stderrstderr, "in _XtResourceConfiguationEH atom = %d\n",event->xproperty.atom); | ||
914 | fprintf (stderrstderr, " window = %x\n", XtWindow (w)((w)->core.window)); | ||
915 | if (XtIsWidget (w)(((Object)(w))->object.widget_class->core_class.class_inited & 0x04)) | ||
916 | fprintf (stderrstderr, " widget = %x name = %s\n", w, w->core.name); | ||
917 | #endif | ||
918 | |||
919 | pd = _XtGetPerDisplay (XtDisplay (w)(((w)->core.screen)->display)); | ||
920 | |||
921 | /* | ||
922 | * The window on which a customizing tool places the property | ||
923 | * is determined at this point. It should be the applications | ||
924 | * toplevel shell window. | ||
925 | * | ||
926 | * A customizing tool sends a "ping" to the application on | ||
927 | * the RCM_INIT property. The application answers the ping | ||
928 | * by deleting the property. | ||
929 | */ | ||
930 | if (event->xproperty.atom == pd->rcm_init) { | ||
931 | XDeleteProperty (XtDisplay(w)(((w)->core.screen)->display), XtWindow (w)((w)->core.window), pd->rcm_init); | ||
932 | |||
933 | #ifdef DEBUG | ||
934 | if (XtIsWidget (w)(((Object)(w))->object.widget_class->core_class.class_inited & 0x04)) | ||
935 | fprintf (stderrstderr, "%s\n", w->core.name); | ||
936 | else | ||
937 | fprintf (stderrstderr, "NULL name\n"); | ||
938 | dump_widget_tree(w, indent); | ||
939 | |||
940 | fprintf (stderrstderr, "answer ping\n"); | ||
941 | #endif | ||
942 | } | ||
943 | |||
944 | /* | ||
945 | * This event handler ignores any property notify events that | ||
946 | * are not RCM_INIT or RCM_DATA | ||
947 | */ | ||
948 | if (event->xproperty.atom != pd->rcm_data) | ||
949 | return; | ||
950 | |||
951 | /* | ||
952 | * Retrieve the data from the property | ||
953 | */ | ||
954 | #ifdef DEBUG | ||
955 | fprintf (stderrstderr, "receiving RCM_DATA property\n"); | ||
956 | #endif | ||
957 | if (XGetWindowProperty (XtDisplay(w)(((w)->core.screen)->display), | ||
958 | XtWindow (w)((w)->core.window), | ||
959 | pd->rcm_data, 0L, 8192L, | ||
960 | TRUE1, XA_STRING((Atom) 31), | ||
961 | &actual_type, &actual_format, &nitems, &leftover, | ||
962 | &data ) == Success0 && actual_type == XA_STRING((Atom) 31) | ||
963 | && actual_format == 8) { | ||
964 | /* | ||
965 | * data format is: | ||
966 | * | ||
967 | * resource_length, resource, value | ||
968 | * | ||
969 | * convert the resource_length to a long, skip over it, put a | ||
970 | * zero byte at the end of the resource, and pick off the | ||
971 | * resource and value fields. | ||
972 | */ | ||
973 | if (data) { | ||
974 | resource_len = Strtoul ((void *)data, &data_ptr, 10)strtoul((void *)data,&data_ptr,10); | ||
975 | data_ptr++; | ||
976 | |||
977 | data_ptr[resource_len] = '\0'; | ||
978 | |||
979 | resource = XtNewString (data_ptr)((data_ptr) != ((void*)0) ? (strcpy(XtMalloc((unsigned)strlen (data_ptr) + 1), data_ptr)) : ((void*)0)); | ||
980 | value = XtNewString (&data_ptr[resource_len + 1])((&data_ptr[resource_len + 1]) != ((void*)0) ? (strcpy(XtMalloc ((unsigned)strlen(&data_ptr[resource_len + 1]) + 1), & data_ptr[resource_len + 1])) : ((void*)0)); | ||
981 | #ifdef DEBUG | ||
982 | fprintf (stderrstderr, "resource_len=%d\n",resource_len); | ||
983 | fprintf (stderrstderr, "resource = %s\t value = %s\n", | ||
984 | resource, value); | ||
985 | #endif | ||
986 | /* | ||
987 | * descend the application widget tree and | ||
988 | * apply the value to the appropriate widgets | ||
989 | */ | ||
990 | _search_widget_tree (w, resource, value); | ||
991 | |||
992 | XtFree (resource); | ||
993 | XtFree (value); | ||
994 | } | ||
995 | } | ||
996 | |||
997 | if (data) | ||
998 | XFree ((char *)data); | ||
999 | } |