Varargs.c revision bdf0f55d
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((int)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 (String *)NULL, (Cardinal *)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 (String *)NULL, (Cardinal *)NULL); 205 return(0); 206 } 207 208 to_val.addr = NULL; 209 from_val.size = 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", (String *)NULL, (Cardinal *)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(short)) 238 arg_return->value = (XtArgVal) *(short *)to_val.addr; 239 else if (to_val.size == sizeof(char)) 240 arg_return->value = (XtArgVal) *(char *)to_val.addr; 241 else if (to_val.size == sizeof(XtArgVal)) 242 arg_return->value = *(XtArgVal *)to_val.addr; 243 else if (to_val.size > sizeof(XtArgVal)) { 244 arg_return->value = (XtArgVal) __XtMalloc(to_val.size); 245 memory_return->value = (XtArgVal) 246 memcpy((void *)arg_return->value, to_val.addr, to_val.size); 247 } 248 } 249 UNLOCK_PROCESS; 250 251 return(1); 252} 253 254 255/* 256 * NestedArgtoArg() converts the passed nested list into 257 * an ArgList/count. 258 */ 259static int 260NestedArgtoArg( 261 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 } else if (strcmp(avlist->name, XtVaNestedList) == 0) { 280 count += NestedArgtoArg(widget, (XtTypedArgList)avlist->value, 281 (args+count), resources, num_resources, 282 (memory_return+count)); 283 } else { 284 (args+count)->name = avlist->name; 285 (args+count)->value = avlist->value; 286 ++count; 287 } 288 } 289 290 return(count); 291} 292 293/* 294 * Free memory allocated through _XtVaToArgList. The actual args array 295 * size is expected to be total_count * 2, where total_count is the number 296 * of elements needed for resource representations. The lower half of the 297 * array contains pairs of resource names and values as usual. For each 298 * element [n] in the lower half of the array, the value field of the 299 * corresponding element [n + total_count] in the upper half of the array 300 * has been pressed into service in order to note whether the resource value 301 * is a pointer to memory that was allocated in TypedArgToArg. In the 302 * upper half, if the value field is not NULL, it contains the address of 303 * memory which should now be freed. That memory could have been allocated 304 * only as a result of the conversion of typed arguments. Therefore, if 305 * there were no typed arguments in the original varargs, there is no need 306 * to examine the upper half of the array. In the choice of data structure 307 * to make this representation, priority was given to the wish to retrofit 308 * the release of memory around the existing signature of _XtVaToArgList. 309 */ 310void 311_XtFreeArgList( 312 ArgList args, /* as returned by _XtVaToArgList */ 313 int total_count, /* argument count returned by _XtCountVaList */ 314 int typed_count) /* typed arg count returned by _XtCountVaList */ 315{ 316 ArgList p; 317 318 if (args) { 319 if (typed_count) 320 for (p = args + total_count; total_count--; ++p) { 321 XtFree((char *)p->value); 322 } 323 XtFree((char *)args); 324 } 325} 326 327 328static void GetResources(Widget widget, XtResourceList *res_list, 329 Cardinal *number); 330 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( 340 Widget widget, 341 va_list var, 342 int max_count, 343 ArgList *args_return, 344 Cardinal *num_args_return) 345{ 346 String attr; 347 int count; 348 ArgList args = (ArgList)NULL; 349 XtTypedArg typed_arg; 350 XtResourceList resources = (XtResourceList)NULL; 351 Cardinal num_resources; 352 Boolean fetched_resource_list = False; 353 354 if (max_count == 0) { 355 *num_args_return = 0; 356 *args_return = (ArgList)NULL; 357 return; 358 } 359 360 args = (ArgList)__XtMalloc((unsigned)(max_count * 2 * sizeof(Arg))); 361 for (count = max_count * 2; --count >= 0; ) 362 args[count].value = (XtArgVal) NULL; 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 401 XtFree((XtPointer)resources); 402 403 *num_args_return = (Cardinal)count; 404 *args_return = (ArgList)args; 405} 406 407/* Function Name: GetResources 408 * Description: Retreives the normal and constraint resources 409 * for this widget. 410 * Arguments: widget - the widget. 411 * RETURNED res_list - the list of resource for this widget 412 * RETURNED number - the number of resources in the above list. 413 * Returns: none 414 */ 415 416static void 417GetResources( 418 Widget widget, 419 XtResourceList * res_list, 420 Cardinal * number) 421{ 422 Widget parent = XtParent(widget); 423 424 XtInitializeWidgetClass(XtClass(widget)); 425 XtGetResourceList(XtClass(widget), res_list, number); 426 427 if (!XtIsShell(widget) && parent && XtIsConstraint(parent)) { 428 XtResourceList res, constraint, cons_top; 429 Cardinal num_constraint, temp; 430 431 XtGetConstraintResourceList(XtClass(parent), &constraint, 432 &num_constraint); 433 434 cons_top = constraint; 435 *res_list = (XtResourceList) XtRealloc((char*)*res_list, 436 ((*number + num_constraint) * 437 sizeof(XtResource))); 438 439 for (temp= num_constraint, res= *res_list + *number; temp != 0; temp--) 440 *res++ = *constraint++; 441 442 *number += num_constraint; 443 XtFree( (XtPointer) cons_top); 444 } 445} 446 447static int NestedArgtoTypedArg( 448 XtTypedArgList args, 449 XtTypedArgList avlist) 450{ 451 int count = 0; 452 453 for (; avlist->name != NULL; avlist++) { 454 if (avlist->type != NULL) { 455 (args+count)->name = avlist->name; 456 (args+count)->type = avlist->type; 457 (args+count)->size = avlist->size; 458 (args+count)->value = avlist->value; 459 ++count; 460 } else if(strcmp(avlist->name, XtVaNestedList) == 0) { 461 count += NestedArgtoTypedArg((args+count), 462 (XtTypedArgList)avlist->value); 463 } else { 464 (args+count)->name = avlist->name; 465 (args+count)->type = NULL; 466 (args+count)->value = avlist->value; 467 ++count; 468 } 469 } 470 return(count); 471} 472 473 474/* 475 * Given a variable argument list, _XtVaToTypedArgList() returns 476 * the equivalent TypedArgList. _XtVaToTypedArgList() handles nested 477 * lists. 478 * Note: _XtVaToTypedArgList() does not do type conversions. 479 */ 480void 481_XtVaToTypedArgList( 482 va_list var, 483 int max_count, 484 XtTypedArgList *args_return, 485 Cardinal *num_args_return) 486{ 487 XtTypedArgList args = NULL; 488 String attr; 489 int count; 490 491 args = (XtTypedArgList) 492 __XtMalloc((unsigned)(max_count * sizeof(XtTypedArg))); 493 494 for(attr = va_arg(var, String), count = 0 ; attr != NULL; 495 attr = va_arg(var, String)) { 496 if (strcmp(attr, XtVaTypedArg) == 0) { 497 args[count].name = va_arg(var, String); 498 args[count].type = va_arg(var, String); 499 args[count].value = va_arg(var, XtArgVal); 500 args[count].size = va_arg(var, int); 501 ++count; 502 } else if (strcmp(attr, XtVaNestedList) == 0) { 503 count += NestedArgtoTypedArg(&args[count], 504 va_arg(var, XtTypedArgList)); 505 } else { 506 args[count].name = attr; 507 args[count].type = NULL; 508 args[count].value = va_arg(var, XtArgVal); 509 ++count; 510 } 511 } 512 513 *args_return = args; 514 *num_args_return = count; 515} 516