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