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