Varargs.c revision 249c3046
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 if (p->value) 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 if (resources != NULL) 402 XtFree((XtPointer)resources); 403 404 *num_args_return = (Cardinal)count; 405 *args_return = (ArgList)args; 406} 407 408/* Function Name: GetResources 409 * Description: Retreives the normal and constraint resources 410 * for this widget. 411 * Arguments: widget - the widget. 412 * RETURNED res_list - the list of resource for this widget 413 * RETURNED number - the number of resources in the above list. 414 * Returns: none 415 */ 416 417static void 418GetResources( 419 Widget widget, 420 XtResourceList * res_list, 421 Cardinal * number) 422{ 423 Widget parent = XtParent(widget); 424 425 XtInitializeWidgetClass(XtClass(widget)); 426 XtGetResourceList(XtClass(widget), res_list, number); 427 428 if (!XtIsShell(widget) && parent && XtIsConstraint(parent)) { 429 XtResourceList res, constraint, cons_top; 430 Cardinal num_constraint, temp; 431 432 XtGetConstraintResourceList(XtClass(parent), &constraint, 433 &num_constraint); 434 435 cons_top = constraint; 436 *res_list = (XtResourceList) XtRealloc((char*)*res_list, 437 ((*number + num_constraint) * 438 sizeof(XtResource))); 439 440 for (temp= num_constraint, res= *res_list + *number; temp != 0; temp--) 441 *res++ = *constraint++; 442 443 *number += num_constraint; 444 XtFree( (XtPointer) cons_top); 445 } 446} 447 448static int NestedArgtoTypedArg( 449 XtTypedArgList args, 450 XtTypedArgList avlist) 451{ 452 int count = 0; 453 454 for (; avlist->name != NULL; avlist++) { 455 if (avlist->type != NULL) { 456 (args+count)->name = avlist->name; 457 (args+count)->type = avlist->type; 458 (args+count)->size = avlist->size; 459 (args+count)->value = avlist->value; 460 ++count; 461 } else if(strcmp(avlist->name, XtVaNestedList) == 0) { 462 count += NestedArgtoTypedArg((args+count), 463 (XtTypedArgList)avlist->value); 464 } else { 465 (args+count)->name = avlist->name; 466 (args+count)->type = NULL; 467 (args+count)->value = avlist->value; 468 ++count; 469 } 470 } 471 return(count); 472} 473 474 475/* 476 * Given a variable argument list, _XtVaToTypedArgList() returns 477 * the equivalent TypedArgList. _XtVaToTypedArgList() handles nested 478 * lists. 479 * Note: _XtVaToTypedArgList() does not do type conversions. 480 */ 481void 482_XtVaToTypedArgList( 483 va_list var, 484 int max_count, 485 XtTypedArgList *args_return, 486 Cardinal *num_args_return) 487{ 488 XtTypedArgList args = NULL; 489 String attr; 490 int count; 491 492 args = (XtTypedArgList) 493 __XtMalloc((unsigned)(max_count * sizeof(XtTypedArg))); 494 495 for(attr = va_arg(var, String), count = 0 ; attr != NULL; 496 attr = va_arg(var, String)) { 497 if (strcmp(attr, XtVaTypedArg) == 0) { 498 args[count].name = va_arg(var, String); 499 args[count].type = va_arg(var, String); 500 args[count].value = va_arg(var, XtArgVal); 501 args[count].size = va_arg(var, int); 502 ++count; 503 } else if (strcmp(attr, XtVaNestedList) == 0) { 504 count += NestedArgtoTypedArg(&args[count], 505 va_arg(var, XtTypedArgList)); 506 } else { 507 args[count].name = attr; 508 args[count].type = NULL; 509 args[count].value = va_arg(var, XtArgVal); 510 ++count; 511 } 512 } 513 514 *args_return = args; 515 *num_args_return = count; 516} 517