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