ISO/ IEC JTC1/SC22/WG14 N592

						WG14/N592 X3J11/96-056

Proposal UK009b - Introduction of a va_list copying function
============================================================

Summary
-------
This proposal provides an additional facility to make variable arguments
easier to use: a function to copy a va_list.


Conformance
-----------
This proposal includes a new identifier.  The present proposal uses names
in the reserved namespace in order to avoid affecting strictly conforming
programs. If more attractive names not in the reserved namespace are used
instead, some strictly conforming programs will be affected.

No other aspect of the proposal affects any strictly conforming program.


Discussion
----------
Sometimes processing variable arguments would be easier if the state of
processing could be copied, and then reverted to at a later point. However,
there is currently no way to do this. This proposal adds such a copying
mechanism.

There is no way to do this operation in C89. It is quite possible that a
value of type va_list includes a pointer to allocated memory. If so, then
that memory needs to be copied as well. There is, obviously, no way for a
strictly-conforming program to determine what is necessary to do this.

WG14 will have to decide whether the new identifier defined is "va_copy"
or "__va_copy". Apart from this, this proposal contains the required
changes to be made to C9X draft 6.


Detailed proposal
-----------------
In subclause 7.9 (7.8 in C89), replace:

  The header <stdarg.h> declares a type and defines three macros,

with:

  The header <stdarg.h> declares a type and defines four macros,

and replace:

  which is a type suitable for holding information  needed  by
  the  macros  va_start, va_arg, and va_end.

with:

  which is a type suitable for holding information  needed  by
  the  macros  va_start, va_arg, va_end, and __va_copy.

In subclause 7.9.1 (7.8.1 in C89), replace:

  It is unspecified whether va_end is a  macro  or
  an  identifier  declared  with external linkage.  If a macro
  definition is  suppressed  in  order  to  access  an  actual
  function,  or  a program defines an external identifier with
  the name va_end, the behavior is  undefined.

with:

  It is unspecified whether va_end and __va_copy are macros or
  identifiers declared  with external linkage.  If a macro
  definition is  suppressed  in  order  to  access  an  actual
  function,  or  a program defines an external identifier with
  the name va_end or __va_copy, the behavior is  undefined.

Add a new subclause 7.9.1.4 before the example:

  7.9.1.4  The __va_copy macro

  Synopsis

    #include <stdarg.h>
    void __va_copy (va_list dest, va_list src);

  Description

  The __va_copy function or macro makes the va_list dest be a copy of
  the va_list src, as if the va_start macro had been applied to it
  followed by the same sequence of uses of the va_arg macro as
  had previously been used to reach the present state of src.

  Returns

    The __va_copy function or macro returns no value.

Add a second example:

  Example

  The function f3 is similar, but saves the status of the variable argument
  list after the indicated number of arguments; after f2 has been called
  once with the whole list, the trailing part of the list is gathered
  again and passed to function f4.

    #include <stdarg.h>
    #define MAXARGS 31

    void f3(int n_ptrs, int f4_after, ...)
    {
        va_list ap, ap_save;
        char *array[MAXARGS];
        int ptr_no = 0;
        if (n_ptrs > MAXARGS)
            n_ptrs = MAXARGS;
        va_start(ap, n_ptrs);
        while (ptr_no < n_ptrs)
                {
            array[ptr_no++] = va_arg(ap, char *);
                        if (ptr_no == f4_after)
                            __va_copy(ap_save, ap);
        }
        va_end(ap);
        f2(n_ptrs, array);

        /* Now process the saved copy */

                n_ptrs -= f4_after;
                ptr_no = 0;
        while (ptr_no < n_ptrs)
            array[ptr_no++] = va_arg(ap_save, char *);
        va_end(ap_save);
        f4(n_ptrs, array);
    }