Varargs.c revision 0568f49b
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( 43 XtTypedArgList avlist, 44 int *total_count, 45 int *typed_count) 46{ 47 for (; avlist->name != NULL; avlist++) { 48 if (strcmp(avlist->name, XtVaNestedList) == 0) { 49 _XtCountNestedList((XtTypedArgList)avlist->value, total_count, 50 typed_count); 51 } else { 52 if (avlist->type != NULL) { 53 ++(*typed_count); 54 } 55 ++(*total_count); 56 } 57 } 58} 59 60 61/* 62 * Given a variable length attribute-value list, _XtCountVaList() 63 * returns counts of the total number of attribute-value pairs, 64 * and the count of the number of those attributes that are typed. 65 * The list is counted recursively. 66 */ 67void 68_XtCountVaList(va_list var, int* total_count, int* typed_count) 69{ 70 String attr; 71 72 *total_count = 0; 73 *typed_count = 0; 74 75 for(attr = va_arg(var, String) ; attr != NULL; 76 attr = va_arg(var, String)) { 77 if (strcmp(attr, XtVaTypedArg) == 0) { 78 (void)va_arg(var, String); 79 (void)va_arg(var, String); 80 (void)va_arg(var, XtArgVal); 81 (void)va_arg(var, int); 82 ++(*total_count); 83 ++(*typed_count); 84 } else if (strcmp(attr, XtVaNestedList) == 0) { 85 _XtCountNestedList(va_arg(var, XtTypedArgList), total_count, 86 typed_count); 87 } else { 88 (void)va_arg(var, XtArgVal); 89 ++(*total_count); 90 } 91 } 92} 93 94 95/* 96 * Given a variable length attribute-value list, XtVaCreateArgsList() 97 * constructs an attribute-value list of type XtTypedArgList and 98 * returns the list. 99 */ 100XtVarArgsList 101XtVaCreateArgsList(XtPointer unused, ...) 102{ 103 va_list var; 104 XtTypedArgList avlist; 105 int count = 0; 106 String attr; 107 108 /* 109 * Count the number of attribute-value pairs in the list. 110 * Note: The count is required only to allocate enough space to store 111 * the list. Therefore nested lists are not counted recursively. 112 */ 113 va_start(var,unused); 114 for(attr = va_arg(var, String) ; attr != NULL; 115 attr = va_arg(var, String)) { 116 ++count; 117 if (strcmp(attr, XtVaTypedArg) == 0) { 118 (void)va_arg(var, String); 119 (void)va_arg(var, String); 120 (void)va_arg(var, XtArgVal); 121 (void)va_arg(var, int); 122 } else { 123 (void)va_arg(var, XtArgVal); 124 } 125 } 126 va_end(var); 127 128 va_start(var,unused); 129 avlist = _XtVaCreateTypedArgList(var, count); 130 va_end(var); 131 return (XtVarArgsList)avlist; 132} 133 134 135XtTypedArgList _XtVaCreateTypedArgList(va_list var, register int count) 136{ 137 String attr; 138 XtTypedArgList avlist; 139 140 avlist = (XtTypedArgList) 141 __XtCalloc((Cardinal)count + 1, (unsigned)sizeof(XtTypedArg)); 142 143 for(attr = va_arg(var, String), count = 0; attr != NULL; 144 attr = va_arg(var, String)) { 145 if (strcmp(attr, XtVaTypedArg) == 0) { 146 avlist[count].name = va_arg(var, String); 147 avlist[count].type = va_arg(var, String); 148 avlist[count].value = va_arg(var, XtArgVal); 149 avlist[count].size = va_arg(var, int); 150 } else { 151 avlist[count].name = attr; 152 avlist[count].type = NULL; 153 avlist[count].value = va_arg(var, XtArgVal); 154 } 155 ++count; 156 } 157 avlist[count].name = NULL; 158 159 return avlist; 160} 161 162 163/* 164 * TypedArgToArg() invokes a resource converter to convert the 165 * passed typed arg into a name/value pair and stores the name/value 166 * pair in the passed Arg structure. If memory is allocated for the 167 * converted value, the address is returned in the value field of 168 * memory_return; otherwise that field is NULL. The function returns 169 * 1 if the conversion succeeded and 0 if the conversion failed. 170 */ 171static int 172TypedArgToArg( 173 Widget widget, 174 XtTypedArgList typed_arg, 175 ArgList arg_return, 176 XtResourceList resources, 177 Cardinal num_resources, 178 ArgList memory_return) 179{ 180 String to_type = NULL; 181 XrmValue from_val, to_val; 182 183 184 if (widget == NULL) { 185 XtAppWarningMsg(XtWidgetToApplicationContext(widget), 186 "nullWidget", XtNxtConvertVarToArgList, XtCXtToolkitError, 187 "XtVaTypedArg conversion needs non-NULL widget handle", 188 NULL, NULL); 189 return(0); 190 } 191 192 /* again we assume that the XtResourceList is un-compiled */ 193 194 for (; num_resources--; resources++) 195 if (strcmp(typed_arg->name, resources->resource_name) == 0) { 196 to_type = resources->resource_type; 197 break; 198 } 199 200 if (to_type == NULL) { 201 XtAppWarningMsg(XtWidgetToApplicationContext(widget), 202 "unknownType", XtNxtConvertVarToArgList, XtCXtToolkitError, 203 "Unable to find type of resource for conversion", 204 NULL, NULL); 205 return(0); 206 } 207 208 to_val.addr = NULL; 209 from_val.size = (Cardinal) typed_arg->size; 210 if ((strcmp(typed_arg->type, XtRString) == 0) || 211 ((unsigned) typed_arg->size > sizeof(XtArgVal))) { 212 from_val.addr = (XPointer)typed_arg->value; 213 } else { 214 from_val.addr = (XPointer)&typed_arg->value; 215 } 216 217 LOCK_PROCESS; 218 XtConvertAndStore(widget, typed_arg->type, &from_val, to_type, &to_val); 219 220 if (to_val.addr == NULL) { 221 UNLOCK_PROCESS; 222 XtAppWarningMsg(XtWidgetToApplicationContext(widget), 223 "conversionFailed", XtNxtConvertVarToArgList, XtCXtToolkitError, 224 "Type conversion failed", NULL, 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/* 258 * NestedArgtoArg() converts the passed nested list into 259 * an ArgList/count. 260 */ 261static int 262NestedArgtoArg( 263 Widget widget, 264 XtTypedArgList avlist, 265 ArgList args, 266 XtResourceList resources, 267 Cardinal num_resources, 268 ArgList memory_return) 269{ 270 int count = 0; 271 272 for (; avlist->name != NULL; avlist++) { 273 if (avlist->type != NULL) { 274 /* If widget is NULL, the typed arg is ignored */ 275 if (widget != NULL) { 276 /* this is a typed arg */ 277 count += TypedArgToArg(widget, avlist, (args+count), 278 resources, num_resources, 279 (memory_return+count)); 280 } 281 } else if (strcmp(avlist->name, XtVaNestedList) == 0) { 282 count += NestedArgtoArg(widget, (XtTypedArgList)avlist->value, 283 (args+count), resources, num_resources, 284 (memory_return+count)); 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( 314 ArgList args, /* as returned by _XtVaToArgList */ 315 int total_count, /* argument count returned by _XtCountVaList */ 316 int typed_count) /* typed arg count returned by _XtCountVaList */ 317{ 318 if (args) { 319 if (typed_count) { 320 ArgList p; 321 for (p = args + total_count; total_count--; ++p) { 322 XtFree((char *)p->value); 323 } 324 } 325 XtFree((char *)args); 326 } 327} 328 329 330static void GetResources(Widget widget, XtResourceList *res_list, 331 Cardinal *number); 332 333 334/* 335 * Given a variable argument list, _XtVaToArgList() returns the 336 * equivalent ArgList and count. _XtVaToArgList() handles nested 337 * lists and typed arguments. If typed arguments are present, the 338 * ArgList should be freed with _XtFreeArgList. 339 */ 340void 341_XtVaToArgList( 342 Widget widget, 343 va_list var, 344 int max_count, 345 ArgList *args_return, 346 Cardinal *num_args_return) 347{ 348 String attr; 349 int count; 350 ArgList args = (ArgList)NULL; 351 XtTypedArg typed_arg; 352 XtResourceList resources = (XtResourceList)NULL; 353 Cardinal num_resources = 0; 354 Boolean fetched_resource_list = False; 355 356 if (max_count == 0) { 357 *num_args_return = 0; 358 *args_return = (ArgList)NULL; 359 return; 360 } 361 362 args = (ArgList)__XtMalloc((Cardinal)((size_t)(max_count * 2) * sizeof(Arg))); 363 if (args) { 364 for (count = max_count * 2; --count >= 0; ) 365 args[count].value = (XtArgVal) NULL; 366 count = 0; 367 368 for(attr = va_arg(var, String) ; attr != NULL; 369 attr = va_arg(var, String)) { 370 if (strcmp(attr, XtVaTypedArg) == 0) { 371 typed_arg.name = va_arg(var, String); 372 typed_arg.type = va_arg(var, String); 373 typed_arg.value = va_arg(var, XtArgVal); 374 typed_arg.size = va_arg(var, int); 375 376 /* if widget is NULL, typed args are ignored */ 377 if (widget != NULL) { 378 if (!fetched_resource_list) { 379 GetResources(widget, &resources, &num_resources); 380 fetched_resource_list = True; 381 } 382 count += TypedArgToArg(widget, &typed_arg, &args[count], 383 resources, num_resources, 384 &args[max_count + count]); 385 } 386 } else if (strcmp(attr, XtVaNestedList) == 0) { 387 if (widget != NULL) { 388 if (!fetched_resource_list) { 389 GetResources(widget, &resources, &num_resources); 390 fetched_resource_list = True; 391 } 392 } 393 394 count += NestedArgtoArg(widget, va_arg(var, XtTypedArgList), 395 &args[count], resources, num_resources, 396 &args[max_count + count]); 397 } else { 398 args[count].name = attr; 399 args[count].value = va_arg(var, XtArgVal); 400 count ++; 401 } 402 } 403 } else { 404 count = 0; 405 } 406 407 XtFree((XtPointer)resources); 408 409 *num_args_return = (Cardinal)count; 410 *args_return = (ArgList)args; 411} 412 413/* Function Name: GetResources 414 * Description: Retrieves the normal and constraint resources 415 * for this widget. 416 * Arguments: widget - the widget. 417 * RETURNED res_list - the list of resource for this widget 418 * RETURNED number - the number of resources in the above list. 419 * Returns: none 420 */ 421 422static void 423GetResources( 424 Widget widget, 425 XtResourceList * res_list, 426 Cardinal * number) 427{ 428 Widget parent = XtParent(widget); 429 430 XtInitializeWidgetClass(XtClass(widget)); 431 XtGetResourceList(XtClass(widget), res_list, number); 432 433 if (!XtIsShell(widget) && parent && XtIsConstraint(parent)) { 434 XtResourceList res, constraint, cons_top; 435 Cardinal num_constraint, temp; 436 437 XtGetConstraintResourceList(XtClass(parent), &constraint, 438 &num_constraint); 439 440 cons_top = constraint; 441 *res_list = (XtResourceList) XtRealloc((char*)*res_list, 442 (Cardinal)((*number + num_constraint) * 443 sizeof(XtResource))); 444 445 for (temp= num_constraint, res= *res_list + *number; temp != 0; temp--) 446 *res++ = *constraint++; 447 448 *number += num_constraint; 449 XtFree( (XtPointer) cons_top); 450 } 451} 452 453static int NestedArgtoTypedArg( 454 XtTypedArgList args, 455 XtTypedArgList avlist) 456{ 457 int count = 0; 458 459 for (; avlist->name != NULL; avlist++) { 460 if (avlist->type != NULL) { 461 (args+count)->name = avlist->name; 462 (args+count)->type = avlist->type; 463 (args+count)->size = avlist->size; 464 (args+count)->value = avlist->value; 465 ++count; 466 } else if(strcmp(avlist->name, XtVaNestedList) == 0) { 467 count += NestedArgtoTypedArg((args+count), 468 (XtTypedArgList)avlist->value); 469 } else { 470 (args+count)->name = avlist->name; 471 (args+count)->type = NULL; 472 (args+count)->value = avlist->value; 473 ++count; 474 } 475 } 476 return(count); 477} 478 479 480/* 481 * Given a variable argument list, _XtVaToTypedArgList() returns 482 * the equivalent TypedArgList. _XtVaToTypedArgList() handles nested 483 * lists. 484 * Note: _XtVaToTypedArgList() does not do type conversions. 485 */ 486void 487_XtVaToTypedArgList( 488 va_list var, 489 int max_count, 490 XtTypedArgList *args_return, 491 Cardinal *num_args_return) 492{ 493 XtTypedArgList args = NULL; 494 String attr; 495 int count; 496 497 args = (XtTypedArgList) 498 __XtMalloc((Cardinal)((size_t) max_count * sizeof(XtTypedArg))); 499 500 for(attr = va_arg(var, String), count = 0 ; attr != NULL; 501 attr = va_arg(var, String)) { 502 if (strcmp(attr, XtVaTypedArg) == 0) { 503 args[count].name = va_arg(var, String); 504 args[count].type = va_arg(var, String); 505 args[count].value = va_arg(var, XtArgVal); 506 args[count].size = va_arg(var, int); 507 ++count; 508 } else if (strcmp(attr, XtVaNestedList) == 0) { 509 count += NestedArgtoTypedArg(&args[count], 510 va_arg(var, XtTypedArgList)); 511 } else { 512 args[count].name = attr; 513 args[count].type = NULL; 514 args[count].value = va_arg(var, XtArgVal); 515 ++count; 516 } 517 } 518 519 *args_return = args; 520 *num_args_return = (Cardinal) count; 521} 522