1/* 2 3Copyright 1985, 1986, 1987, 1988, 1989, 1994, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21Except as contained in this notice, the name of The Open Group shall not be 22used in advertising or otherwise to promote the sale, use or other dealings 23in this Software without prior written authorization from The Open Group. 24 25*/ 26 27#ifdef HAVE_CONFIG_H 28#include <config.h> 29#endif 30#include "IntrinsicI.h" 31#include "VarargsI.h" 32#include "StringDefs.h" 33 34static String XtNxtConvertVarToArgList = "xtConvertVarToArgList"; 35 36/* 37 * Given a nested list, _XtCountNestedList() returns counts of the 38 * total number of attribute-value pairs and the count of those 39 * attributes that are typed. The list is counted recursively. 40 */ 41static void 42_XtCountNestedList(XtTypedArgList avlist, int *total_count, int *typed_count) 43{ 44 for (; avlist->name != NULL; avlist++) { 45 if (strcmp(avlist->name, XtVaNestedList) == 0) { 46 _XtCountNestedList((XtTypedArgList) avlist->value, total_count, 47 typed_count); 48 } 49 else { 50 if (avlist->type != NULL) { 51 ++(*typed_count); 52 } 53 ++(*total_count); 54 } 55 } 56} 57 58/* 59 * Given a variable length attribute-value list, _XtCountVaList() 60 * returns counts of the total number of attribute-value pairs, 61 * and the count of the number of those attributes that are typed. 62 * The list is counted recursively. 63 */ 64void 65_XtCountVaList(va_list var, int *total_count, int *typed_count) 66{ 67 String attr; 68 69 *total_count = 0; 70 *typed_count = 0; 71 72 for (attr = va_arg(var, String); attr != NULL; attr = va_arg(var, String)) { 73 if (strcmp(attr, XtVaTypedArg) == 0) { 74 (void) va_arg(var, String); 75 (void) va_arg(var, String); 76 (void) va_arg(var, XtArgVal); 77 (void) va_arg(var, int); 78 79 ++(*total_count); 80 ++(*typed_count); 81 } 82 else if (strcmp(attr, XtVaNestedList) == 0) { 83 _XtCountNestedList(va_arg(var, XtTypedArgList), total_count, 84 typed_count); 85 } 86 else { 87 (void) va_arg(var, XtArgVal); 88 ++(*total_count); 89 } 90 } 91} 92 93/* 94 * Given a variable length attribute-value list, XtVaCreateArgsList() 95 * constructs an attribute-value list of type XtTypedArgList and 96 * returns the list. 97 */ 98XtVarArgsList 99XtVaCreateArgsList(XtPointer unused _X_UNUSED, ...) 100{ 101 va_list var; 102 XtTypedArgList avlist; 103 int count = 0; 104 String attr; 105 106 /* 107 * Count the number of attribute-value pairs in the list. 108 * Note: The count is required only to allocate enough space to store 109 * the list. Therefore nested lists are not counted recursively. 110 */ 111 va_start(var, unused); 112 for (attr = va_arg(var, String); attr != NULL; attr = va_arg(var, String)) { 113 ++count; 114 if (strcmp(attr, XtVaTypedArg) == 0) { 115 (void) va_arg(var, String); 116 (void) va_arg(var, String); 117 (void) va_arg(var, XtArgVal); 118 (void) va_arg(var, int); 119 } 120 else { 121 (void) va_arg(var, XtArgVal); 122 } 123 } 124 va_end(var); 125 126 va_start(var, unused); 127 avlist = _XtVaCreateTypedArgList(var, count); 128 va_end(var); 129 return (XtVarArgsList) avlist; 130} 131 132XtTypedArgList 133_XtVaCreateTypedArgList(va_list var, register int count) 134{ 135 String attr; 136 XtTypedArgList avlist; 137 138 avlist = (XtTypedArgList) 139 __XtCalloc((Cardinal) count + 1, (unsigned) sizeof(XtTypedArg)); 140 141 for (attr = va_arg(var, String), count = 0; attr != NULL; 142 attr = va_arg(var, String)) { 143 if (strcmp(attr, XtVaTypedArg) == 0) { 144 avlist[count].name = va_arg(var, String); 145 avlist[count].type = va_arg(var, String); 146 avlist[count].value = va_arg(var, XtArgVal); 147 avlist[count].size = va_arg(var, int); 148 } 149 else { 150 avlist[count].name = attr; 151 avlist[count].type = NULL; 152 avlist[count].value = va_arg(var, XtArgVal); 153 } 154 ++count; 155 } 156 avlist[count].name = NULL; 157 158 return avlist; 159} 160 161/* 162 * TypedArgToArg() invokes a resource converter to convert the 163 * passed typed arg into a name/value pair and stores the name/value 164 * pair in the passed Arg structure. If memory is allocated for the 165 * converted value, the address is returned in the value field of 166 * memory_return; otherwise that field is NULL. The function returns 167 * 1 if the conversion succeeded and 0 if the conversion failed. 168 */ 169static int 170TypedArgToArg(Widget widget, 171 XtTypedArgList typed_arg, 172 ArgList arg_return, 173 XtResourceList resources, 174 Cardinal num_resources, 175 ArgList memory_return) 176{ 177 String to_type = NULL; 178 XrmValue from_val, to_val; 179 180 if (widget == NULL) { 181 XtAppWarningMsg(XtWidgetToApplicationContext(widget), 182 "nullWidget", XtNxtConvertVarToArgList, 183 XtCXtToolkitError, 184 "XtVaTypedArg conversion needs non-NULL widget handle", 185 NULL, NULL); 186 return (0); 187 } 188 189 /* again we assume that the XtResourceList is un-compiled */ 190 191 for (; num_resources--; resources++) 192 if (strcmp(typed_arg->name, resources->resource_name) == 0) { 193 to_type = resources->resource_type; 194 break; 195 } 196 197 if (to_type == NULL) { 198 XtAppWarningMsg(XtWidgetToApplicationContext(widget), 199 "unknownType", XtNxtConvertVarToArgList, 200 XtCXtToolkitError, 201 "Unable to find type of resource for conversion", NULL, 202 NULL); 203 return (0); 204 } 205 206 to_val.addr = NULL; 207 from_val.size = (Cardinal) typed_arg->size; 208 if ((strcmp(typed_arg->type, XtRString) == 0) || 209 ((unsigned) typed_arg->size > sizeof(XtArgVal))) { 210 from_val.addr = (XPointer) typed_arg->value; 211 } 212 else { 213 from_val.addr = (XPointer) &typed_arg->value; 214 } 215 216 LOCK_PROCESS; 217 XtConvertAndStore(widget, typed_arg->type, &from_val, to_type, &to_val); 218 219 if (to_val.addr == NULL) { 220 UNLOCK_PROCESS; 221 XtAppWarningMsg(XtWidgetToApplicationContext(widget), 222 "conversionFailed", XtNxtConvertVarToArgList, 223 XtCXtToolkitError, "Type conversion failed", NULL, 224 NULL); 225 return (0); 226 } 227 228 arg_return->name = typed_arg->name; 229 memory_return->value = (XtArgVal) NULL; 230 231 if (strcmp(to_type, XtRString) == 0) { 232 arg_return->value = (XtArgVal) to_val.addr; 233 } 234 else { 235 if (to_val.size == sizeof(long)) 236 arg_return->value = (XtArgVal) * (long *) to_val.addr; 237 else if (to_val.size == sizeof(int)) 238 arg_return->value = (XtArgVal) * (int *) to_val.addr; 239 else if (to_val.size == sizeof(short)) 240 arg_return->value = (XtArgVal) * (short *) to_val.addr; 241 else if (to_val.size == sizeof(char)) 242 arg_return->value = (XtArgVal) * (char *) to_val.addr; 243 else if (to_val.size == sizeof(XtArgVal)) 244 arg_return->value = *(XtArgVal *) to_val.addr; 245 else if (to_val.size > sizeof(XtArgVal)) { 246 arg_return->value = (XtArgVal) (void *) __XtMalloc(to_val.size); 247 if ((memory_return->value = arg_return->value) != 0) 248 memcpy((void *) arg_return->value, to_val.addr, to_val.size); 249 } 250 } 251 UNLOCK_PROCESS; 252 253 return (1); 254} 255 256/* 257 * NestedArgtoArg() converts the passed nested list into 258 * an ArgList/count. 259 */ 260static int 261NestedArgtoArg(Widget widget, 262 XtTypedArgList avlist, 263 ArgList args, 264 XtResourceList resources, 265 Cardinal num_resources, 266 ArgList memory_return) 267{ 268 int count = 0; 269 270 for (; avlist->name != NULL; avlist++) { 271 if (avlist->type != NULL) { 272 /* If widget is NULL, the typed arg is ignored */ 273 if (widget != NULL) { 274 /* this is a typed arg */ 275 count += TypedArgToArg(widget, avlist, (args + count), 276 resources, num_resources, 277 (memory_return + count)); 278 } 279 } 280 else if (strcmp(avlist->name, XtVaNestedList) == 0) { 281 count += NestedArgtoArg(widget, (XtTypedArgList) avlist->value, 282 (args + count), resources, num_resources, 283 (memory_return + count)); 284 } 285 else { 286 (args + count)->name = avlist->name; 287 (args + count)->value = avlist->value; 288 ++count; 289 } 290 } 291 292 return (count); 293} 294 295/* 296 * Free memory allocated through _XtVaToArgList. The actual args array 297 * size is expected to be total_count * 2, where total_count is the number 298 * of elements needed for resource representations. The lower half of the 299 * array contains pairs of resource names and values as usual. For each 300 * element [n] in the lower half of the array, the value field of the 301 * corresponding element [n + total_count] in the upper half of the array 302 * has been pressed into service in order to note whether the resource value 303 * is a pointer to memory that was allocated in TypedArgToArg. In the 304 * upper half, if the value field is not NULL, it contains the address of 305 * memory which should now be freed. That memory could have been allocated 306 * only as a result of the conversion of typed arguments. Therefore, if 307 * there were no typed arguments in the original varargs, there is no need 308 * to examine the upper half of the array. In the choice of data structure 309 * to make this representation, priority was given to the wish to retrofit 310 * the release of memory around the existing signature of _XtVaToArgList. 311 */ 312void 313_XtFreeArgList(ArgList args, /* as returned by _XtVaToArgList */ 314 int total_count, /* argument count returned by _XtCountVaList */ 315 int typed_count) /* typed arg count returned by _XtCountVaList */ 316{ 317 if (args) { 318 if (typed_count) { 319 ArgList p; 320 321 for (p = args + total_count; total_count--; ++p) { 322 XtFree((char *) p->value); 323 } 324 } 325 XtFree((char *) args); 326 } 327} 328 329static void GetResources(Widget widget, XtResourceList *res_list, 330 Cardinal *number); 331 332/* 333 * Given a variable argument list, _XtVaToArgList() returns the 334 * equivalent ArgList and count. _XtVaToArgList() handles nested 335 * lists and typed arguments. If typed arguments are present, the 336 * ArgList should be freed with _XtFreeArgList. 337 */ 338void 339_XtVaToArgList(Widget widget, 340 va_list var, 341 int max_count, 342 ArgList *args_return, 343 Cardinal *num_args_return) 344{ 345 String attr; 346 int count; 347 ArgList args = (ArgList)NULL; 348 XtTypedArg typed_arg; 349 XtResourceList resources = (XtResourceList)NULL; 350 Cardinal num_resources = 0; 351 Boolean fetched_resource_list = False; 352 353 *num_args_return = 0; 354 *args_return = (ArgList)NULL; 355 356 if (max_count == 0) 357 return; 358 359 args = (ArgList)__XtCalloc((Cardinal)(max_count * 2), sizeof(Arg)); 360 if (!args) 361 return; 362 363 count = 0; 364 365 for(attr = va_arg(var, String) ; attr != NULL; 366 attr = va_arg(var, String)) { 367 if (strcmp(attr, XtVaTypedArg) == 0) { 368 typed_arg.name = va_arg(var, String); 369 typed_arg.type = va_arg(var, String); 370 typed_arg.value = va_arg(var, XtArgVal); 371 typed_arg.size = va_arg(var, int); 372 373 /* if widget is NULL, typed args are ignored */ 374 if (widget != NULL) { 375 if (!fetched_resource_list) { 376 GetResources(widget, &resources, &num_resources); 377 fetched_resource_list = True; 378 } 379 count += TypedArgToArg(widget, &typed_arg, &args[count], 380 resources, num_resources, 381 &args[max_count + count]); 382 } 383 } else if (strcmp(attr, XtVaNestedList) == 0) { 384 if (widget != NULL) { 385 if (!fetched_resource_list) { 386 GetResources(widget, &resources, &num_resources); 387 fetched_resource_list = True; 388 } 389 } 390 391 count += NestedArgtoArg(widget, va_arg(var, XtTypedArgList), 392 &args[count], resources, num_resources, 393 &args[max_count + count]); 394 } else { 395 args[count].name = attr; 396 args[count].value = va_arg(var, XtArgVal); 397 count ++; 398 } 399 } 400 XtFree((XtPointer) resources); 401 402 *num_args_return = (Cardinal) count; 403 *args_return = (ArgList) args; 404} 405 406/* Function Name: GetResources 407 * Description: Retrieves the normal and constraint resources 408 * for this widget. 409 * Arguments: widget - the widget. 410 * RETURNED res_list - the list of resource for this widget 411 * RETURNED number - the number of resources in the above list. 412 * Returns: none 413 */ 414 415static void 416GetResources(Widget widget, XtResourceList *res_list, Cardinal *number) 417{ 418 Widget parent = XtParent(widget); 419 420 XtInitializeWidgetClass(XtClass(widget)); 421 XtGetResourceList(XtClass(widget), res_list, number); 422 423 if (!XtIsShell(widget) && parent && XtIsConstraint(parent)) { 424 XtResourceList res, constraint, cons_top; 425 Cardinal num_constraint, temp; 426 427 XtGetConstraintResourceList(XtClass(parent), &constraint, 428 &num_constraint); 429 430 cons_top = constraint; 431 *res_list = XtReallocArray(*res_list, *number + num_constraint, 432 (Cardinal) sizeof(XtResource)); 433 434 for (temp = num_constraint, res = *res_list + *number; temp != 0; 435 temp--) 436 *res++ = *constraint++; 437 438 *number += num_constraint; 439 XtFree((XtPointer) cons_top); 440 } 441} 442 443static int 444NestedArgtoTypedArg(XtTypedArgList args, XtTypedArgList avlist) 445{ 446 int count = 0; 447 448 for (; avlist->name != NULL; avlist++) { 449 if (avlist->type != NULL) { 450 (args + count)->name = avlist->name; 451 (args + count)->type = avlist->type; 452 (args + count)->size = avlist->size; 453 (args + count)->value = avlist->value; 454 ++count; 455 } 456 else if (strcmp(avlist->name, XtVaNestedList) == 0) { 457 count += NestedArgtoTypedArg((args + count), 458 (XtTypedArgList) avlist->value); 459 } 460 else { 461 (args + count)->name = avlist->name; 462 (args + count)->type = NULL; 463 (args + count)->value = avlist->value; 464 ++count; 465 } 466 } 467 return (count); 468} 469 470/* 471 * Given a variable argument list, _XtVaToTypedArgList() returns 472 * the equivalent TypedArgList. _XtVaToTypedArgList() handles nested 473 * lists. 474 * Note: _XtVaToTypedArgList() does not do type conversions. 475 */ 476void 477_XtVaToTypedArgList(va_list var, 478 int max_count, 479 XtTypedArgList *args_return, 480 Cardinal *num_args_return) 481{ 482 XtTypedArgList args; 483 String attr; 484 int count; 485 486 *args_return = NULL; 487 *num_args_return = 0; 488 489 if (max_count == 0) 490 return; 491 492 args = (XtTypedArgList) 493 __XtCalloc((Cardinal) max_count , sizeof(XtTypedArg)); 494 if (!args) 495 return; 496 497 count=0; 498 499 for (attr = va_arg(var, String); attr != NULL; 500 attr = va_arg(var, String)) { 501 if (strcmp(attr, XtVaTypedArg) == 0) { 502 args[count].name = va_arg(var, String); 503 args[count].type = va_arg(var, String); 504 args[count].value = va_arg(var, XtArgVal); 505 args[count].size = va_arg(var, int); 506 507 ++count; 508 } 509 else if (strcmp(attr, XtVaNestedList) == 0) { 510 count += NestedArgtoTypedArg(&args[count], 511 va_arg(var, XtTypedArgList)); 512 } 513 else { 514 args[count].name = attr; 515 args[count].type = NULL; 516 args[count].value = va_arg(var, XtArgVal); 517 ++count; 518 } 519 } 520 521 *args_return = args; 522 *num_args_return = (Cardinal) count; 523} 524