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