Varargs.c revision 9e7bcd65
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(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) __XtMalloc(to_val.size);
247	    memory_return->value = (XtArgVal)
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    ArgList p;
319
320    if (args) {
321	if (typed_count)
322	    for (p = args + total_count; total_count--; ++p) {
323		XtFree((char *)p->value);
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;
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((unsigned)(max_count * 2 * sizeof(Arg)));
363    for (count = max_count * 2; --count >= 0; )
364	args[count].value = (XtArgVal) NULL;
365    count = 0;
366
367    for(attr = va_arg(var, String) ; attr != NULL;
368			attr = va_arg(var, String)) {
369	if (strcmp(attr, XtVaTypedArg) == 0) {
370	    typed_arg.name = va_arg(var, String);
371	    typed_arg.type = va_arg(var, String);
372	    typed_arg.value = va_arg(var, XtArgVal);
373	    typed_arg.size = va_arg(var, int);
374
375	    /* if widget is NULL, typed args are ignored */
376	    if (widget != NULL) {
377		if (!fetched_resource_list) {
378		    GetResources(widget, &resources, &num_resources);
379		    fetched_resource_list = True;
380		}
381		count += TypedArgToArg(widget, &typed_arg, &args[count],
382					  resources, num_resources,
383					  &args[max_count + count]);
384	    }
385	} else if (strcmp(attr, XtVaNestedList) == 0) {
386	    if (widget != NULL) {
387		if (!fetched_resource_list) {
388		    GetResources(widget, &resources, &num_resources);
389		    fetched_resource_list = True;
390		}
391	    }
392
393	    count += NestedArgtoArg(widget, va_arg(var, XtTypedArgList),
394				       &args[count], resources, num_resources,
395				       &args[max_count + count]);
396	} else {
397	    args[count].name = attr;
398	    args[count].value = va_arg(var, XtArgVal);
399	    count ++;
400	}
401    }
402
403    XtFree((XtPointer)resources);
404
405    *num_args_return = (Cardinal)count;
406    *args_return = (ArgList)args;
407}
408
409/*	Function Name: GetResources
410 *	Description: Retreives the normal and constraint resources
411 *                   for this widget.
412 *	Arguments: widget - the widget.
413 * RETURNED        res_list - the list of resource for this widget
414 * RETURNED        number - the number of resources in the above list.
415 *	Returns: none
416 */
417
418static void
419GetResources(
420    Widget widget,
421    XtResourceList * res_list,
422    Cardinal * number)
423{
424    Widget parent = XtParent(widget);
425
426    XtInitializeWidgetClass(XtClass(widget));
427    XtGetResourceList(XtClass(widget), res_list, number);
428
429    if (!XtIsShell(widget) && parent && XtIsConstraint(parent)) {
430	XtResourceList res, constraint, cons_top;
431	Cardinal num_constraint, temp;
432
433	XtGetConstraintResourceList(XtClass(parent), &constraint,
434				    &num_constraint);
435
436	cons_top = constraint;
437	*res_list = (XtResourceList) XtRealloc((char*)*res_list,
438					       ((*number + num_constraint) *
439						sizeof(XtResource)));
440
441	for (temp= num_constraint, res= *res_list + *number; temp != 0; temp--)
442	    *res++ = *constraint++;
443
444	*number += num_constraint;
445	XtFree( (XtPointer) cons_top);
446    }
447}
448
449static int NestedArgtoTypedArg(
450    XtTypedArgList      args,
451    XtTypedArgList      avlist)
452{
453    int         count = 0;
454
455    for (; avlist->name != NULL; avlist++) {
456        if (avlist->type != NULL) {
457            (args+count)->name = avlist->name;
458            (args+count)->type = avlist->type;
459            (args+count)->size = avlist->size;
460            (args+count)->value = avlist->value;
461            ++count;
462        } else if(strcmp(avlist->name, XtVaNestedList) == 0) {
463            count += NestedArgtoTypedArg((args+count),
464                            (XtTypedArgList)avlist->value);
465        } else {
466            (args+count)->name = avlist->name;
467	    (args+count)->type = NULL;
468            (args+count)->value = avlist->value;
469            ++count;
470        }
471    }
472    return(count);
473}
474
475
476/*
477 *    Given a variable argument list, _XtVaToTypedArgList() returns
478 *    the equivalent TypedArgList. _XtVaToTypedArgList() handles nested
479 *    lists.
480 *    Note: _XtVaToTypedArgList() does not do type conversions.
481 */
482void
483_XtVaToTypedArgList(
484    va_list             var,
485    int			max_count,
486    XtTypedArgList   	*args_return,
487    Cardinal            *num_args_return)
488{
489    XtTypedArgList	args = NULL;
490    String              attr;
491    int			count;
492
493    args = (XtTypedArgList)
494	__XtMalloc((unsigned)(max_count * sizeof(XtTypedArg)));
495
496    for(attr = va_arg(var, String), count = 0 ; attr != NULL;
497		    attr = va_arg(var, String)) {
498        if (strcmp(attr, XtVaTypedArg) == 0) {
499	    args[count].name = va_arg(var, String);
500	    args[count].type = va_arg(var, String);
501	    args[count].value = va_arg(var, XtArgVal);
502	    args[count].size = va_arg(var, int);
503	    ++count;
504	} else if (strcmp(attr, XtVaNestedList) == 0) {
505	    count += NestedArgtoTypedArg(&args[count],
506			va_arg(var, XtTypedArgList));
507	} else {
508	    args[count].name = attr;
509	    args[count].type = NULL;
510	    args[count].value = va_arg(var, XtArgVal);
511	    ++count;
512	}
513    }
514
515    *args_return = args;
516    *num_args_return = count;
517}
518