| 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 | } |