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