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(XtTypedArgList avlist, int *total_count, int *typed_count)
43{
44    for (; avlist->name != NULL; avlist++) {
45        if (strcmp(avlist->name, XtVaNestedList) == 0) {
46            _XtCountNestedList((XtTypedArgList) avlist->value, total_count,
47                               typed_count);
48        }
49        else {
50            if (avlist->type != NULL) {
51                ++(*typed_count);
52            }
53            ++(*total_count);
54        }
55    }
56}
57
58/*
59 *    Given a variable length attribute-value list, _XtCountVaList()
60 *    returns counts of the total number of attribute-value pairs,
61 *    and the count of the number of those attributes that are typed.
62 *    The list is counted recursively.
63 */
64void
65_XtCountVaList(va_list var, int *total_count, int *typed_count)
66{
67    String attr;
68
69    *total_count = 0;
70    *typed_count = 0;
71
72    for (attr = va_arg(var, String); attr != NULL; attr = va_arg(var, String)) {
73        if (strcmp(attr, XtVaTypedArg) == 0) {
74            (void) va_arg(var, String);
75            (void) va_arg(var, String);
76            (void) va_arg(var, XtArgVal);
77            (void) va_arg(var, int);
78
79            ++(*total_count);
80            ++(*typed_count);
81        }
82        else if (strcmp(attr, XtVaNestedList) == 0) {
83            _XtCountNestedList(va_arg(var, XtTypedArgList), total_count,
84                               typed_count);
85        }
86        else {
87            (void) va_arg(var, XtArgVal);
88            ++(*total_count);
89        }
90    }
91}
92
93/*
94 *   Given a variable length attribute-value list, XtVaCreateArgsList()
95 *   constructs an attribute-value list of type XtTypedArgList and
96 *   returns the list.
97 */
98XtVarArgsList
99XtVaCreateArgsList(XtPointer unused _X_UNUSED, ...)
100{
101    va_list var;
102    XtTypedArgList avlist;
103    int count = 0;
104    String attr;
105
106    /*
107     * Count the number of attribute-value pairs in the list.
108     * Note: The count is required only to allocate enough space to store
109     * the list. Therefore nested lists are not counted recursively.
110     */
111    va_start(var, unused);
112    for (attr = va_arg(var, String); attr != NULL; attr = va_arg(var, String)) {
113        ++count;
114        if (strcmp(attr, XtVaTypedArg) == 0) {
115            (void) va_arg(var, String);
116            (void) va_arg(var, String);
117            (void) va_arg(var, XtArgVal);
118            (void) va_arg(var, int);
119        }
120        else {
121            (void) va_arg(var, XtArgVal);
122        }
123    }
124    va_end(var);
125
126    va_start(var, unused);
127    avlist = _XtVaCreateTypedArgList(var, count);
128    va_end(var);
129    return (XtVarArgsList) avlist;
130}
131
132XtTypedArgList
133_XtVaCreateTypedArgList(va_list var, register int count)
134{
135    String attr;
136    XtTypedArgList avlist;
137
138    avlist = (XtTypedArgList)
139        __XtCalloc((Cardinal) count + 1, (unsigned) sizeof(XtTypedArg));
140
141    for (attr = va_arg(var, String), count = 0; attr != NULL;
142         attr = va_arg(var, String)) {
143        if (strcmp(attr, XtVaTypedArg) == 0) {
144            avlist[count].name = va_arg(var, String);
145            avlist[count].type = va_arg(var, String);
146            avlist[count].value = va_arg(var, XtArgVal);
147            avlist[count].size = va_arg(var, int);
148        }
149        else {
150            avlist[count].name = attr;
151            avlist[count].type = NULL;
152            avlist[count].value = va_arg(var, XtArgVal);
153        }
154        ++count;
155    }
156    avlist[count].name = NULL;
157
158    return avlist;
159}
160
161/*
162 *    TypedArgToArg() invokes a resource converter to convert the
163 *    passed typed arg into a name/value pair and stores the name/value
164 *    pair in the passed Arg structure.  If memory is allocated for the
165 *    converted value, the address is returned in the value field of
166 *    memory_return; otherwise that field is NULL.  The function returns
167 *    1 if the conversion succeeded and 0 if the conversion failed.
168 */
169static int
170TypedArgToArg(Widget widget,
171              XtTypedArgList typed_arg,
172              ArgList arg_return,
173              XtResourceList resources,
174              Cardinal num_resources,
175              ArgList memory_return)
176{
177    String to_type = NULL;
178    XrmValue from_val, to_val;
179
180    if (widget == NULL) {
181        XtAppWarningMsg(XtWidgetToApplicationContext(widget),
182                        "nullWidget", XtNxtConvertVarToArgList,
183                        XtCXtToolkitError,
184                        "XtVaTypedArg conversion needs non-NULL widget handle",
185                        NULL, NULL);
186        return (0);
187    }
188
189    /* again we assume that the XtResourceList is un-compiled */
190
191    for (; num_resources--; resources++)
192        if (strcmp(typed_arg->name, resources->resource_name) == 0) {
193            to_type = resources->resource_type;
194            break;
195        }
196
197    if (to_type == NULL) {
198        XtAppWarningMsg(XtWidgetToApplicationContext(widget),
199                        "unknownType", XtNxtConvertVarToArgList,
200                        XtCXtToolkitError,
201                        "Unable to find type of resource for conversion", NULL,
202                        NULL);
203        return (0);
204    }
205
206    to_val.addr = NULL;
207    from_val.size = (Cardinal) typed_arg->size;
208    if ((strcmp(typed_arg->type, XtRString) == 0) ||
209        ((unsigned) typed_arg->size > sizeof(XtArgVal))) {
210        from_val.addr = (XPointer) typed_arg->value;
211    }
212    else {
213        from_val.addr = (XPointer) &typed_arg->value;
214    }
215
216    LOCK_PROCESS;
217    XtConvertAndStore(widget, typed_arg->type, &from_val, to_type, &to_val);
218
219    if (to_val.addr == NULL) {
220        UNLOCK_PROCESS;
221        XtAppWarningMsg(XtWidgetToApplicationContext(widget),
222                        "conversionFailed", XtNxtConvertVarToArgList,
223                        XtCXtToolkitError, "Type conversion failed", NULL,
224                        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 *    NestedArgtoArg() converts the passed nested list into
258 *    an ArgList/count.
259 */
260static int
261NestedArgtoArg(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        }
280        else if (strcmp(avlist->name, XtVaNestedList) == 0) {
281            count += NestedArgtoArg(widget, (XtTypedArgList) avlist->value,
282                                    (args + count), resources, num_resources,
283                                    (memory_return + count));
284        }
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(ArgList args,    /* as returned by _XtVaToArgList */
314               int total_count, /* argument count returned by _XtCountVaList */
315               int typed_count) /* typed arg count returned by _XtCountVaList */
316{
317    if (args) {
318        if (typed_count) {
319            ArgList p;
320
321            for (p = args + total_count; total_count--; ++p) {
322                XtFree((char *) p->value);
323            }
324        }
325        XtFree((char *) args);
326    }
327}
328
329static void GetResources(Widget widget, XtResourceList *res_list,
330                         Cardinal *number);
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(Widget widget,
340               va_list var,
341               int max_count,
342               ArgList *args_return,
343               Cardinal *num_args_return)
344{
345    String		attr;
346    int			count;
347    ArgList		args = (ArgList)NULL;
348    XtTypedArg		typed_arg;
349    XtResourceList	resources = (XtResourceList)NULL;
350    Cardinal		num_resources = 0;
351    Boolean		fetched_resource_list = False;
352
353    *num_args_return = 0;
354    *args_return = (ArgList)NULL;
355
356    if (max_count  == 0)
357	return;
358
359    args = (ArgList)__XtCalloc((Cardinal)(max_count * 2),  sizeof(Arg));
360    if (!args)
361	return;
362
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    XtFree((XtPointer) resources);
401
402    *num_args_return = (Cardinal) count;
403    *args_return = (ArgList) args;
404}
405
406/*      Function Name: GetResources
407 *      Description: Retrieves the normal and constraint resources
408 *                   for this widget.
409 *      Arguments: widget - the widget.
410 * RETURNED        res_list - the list of resource for this widget
411 * RETURNED        number - the number of resources in the above list.
412 *      Returns: none
413 */
414
415static void
416GetResources(Widget widget, XtResourceList *res_list, Cardinal *number)
417{
418    Widget parent = XtParent(widget);
419
420    XtInitializeWidgetClass(XtClass(widget));
421    XtGetResourceList(XtClass(widget), res_list, number);
422
423    if (!XtIsShell(widget) && parent && XtIsConstraint(parent)) {
424        XtResourceList res, constraint, cons_top;
425        Cardinal num_constraint, temp;
426
427        XtGetConstraintResourceList(XtClass(parent), &constraint,
428                                    &num_constraint);
429
430        cons_top = constraint;
431        *res_list = XtReallocArray(*res_list, *number + num_constraint,
432                                   (Cardinal) sizeof(XtResource));
433
434        for (temp = num_constraint, res = *res_list + *number; temp != 0;
435             temp--)
436            *res++ = *constraint++;
437
438        *number += num_constraint;
439        XtFree((XtPointer) cons_top);
440    }
441}
442
443static int
444NestedArgtoTypedArg(XtTypedArgList args, XtTypedArgList avlist)
445{
446    int count = 0;
447
448    for (; avlist->name != NULL; avlist++) {
449        if (avlist->type != NULL) {
450            (args + count)->name = avlist->name;
451            (args + count)->type = avlist->type;
452            (args + count)->size = avlist->size;
453            (args + count)->value = avlist->value;
454            ++count;
455        }
456        else if (strcmp(avlist->name, XtVaNestedList) == 0) {
457            count += NestedArgtoTypedArg((args + count),
458                                         (XtTypedArgList) avlist->value);
459        }
460        else {
461            (args + count)->name = avlist->name;
462            (args + count)->type = NULL;
463            (args + count)->value = avlist->value;
464            ++count;
465        }
466    }
467    return (count);
468}
469
470/*
471 *    Given a variable argument list, _XtVaToTypedArgList() returns
472 *    the equivalent TypedArgList. _XtVaToTypedArgList() handles nested
473 *    lists.
474 *    Note: _XtVaToTypedArgList() does not do type conversions.
475 */
476void
477_XtVaToTypedArgList(va_list var,
478                    int max_count,
479                    XtTypedArgList *args_return,
480                    Cardinal *num_args_return)
481{
482    XtTypedArgList args;
483    String attr;
484    int count;
485
486    *args_return = NULL;
487    *num_args_return = 0;
488
489    if (max_count  == 0)
490	return;
491
492    args = (XtTypedArgList)
493        __XtCalloc((Cardinal) max_count , sizeof(XtTypedArg));
494    if (!args)
495    	return;
496
497    count=0;
498
499    for (attr = va_arg(var, String); attr != NULL;
500         attr = va_arg(var, String)) {
501        if (strcmp(attr, XtVaTypedArg) == 0) {
502            args[count].name = va_arg(var, String);
503            args[count].type = va_arg(var, String);
504            args[count].value = va_arg(var, XtArgVal);
505            args[count].size = va_arg(var, int);
506
507            ++count;
508        }
509        else if (strcmp(attr, XtVaNestedList) == 0) {
510            count += NestedArgtoTypedArg(&args[count],
511                                         va_arg(var, XtTypedArgList));
512        }
513        else {
514            args[count].name = attr;
515            args[count].type = NULL;
516            args[count].value = va_arg(var, XtArgVal);
517            ++count;
518        }
519    }
520
521    *args_return = args;
522    *num_args_return = (Cardinal) count;
523}
524