reading <stdarg.h>'s va_list twice

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • tonybalinski@gmail.com

    reading <stdarg.h>'s va_list twice

    I'd like to be able to scan a va_list twice in a v... function, but
    can't see how to do it. For example

    char *strdupcat(cons t char *first, ...)
    {
    char *result, pos;
    va_list arg;
    size_t len;
    const char *next;

    va_start(arg, first);
    next = first;
    while (next) {
    len += strlen(next);
    next = va_arg(arg, const char *);
    }
    va_end(arg);

    result = pos = malloc(len + 1);

    va_start(arg, first);
    next = first;
    while (next) {
    strcpy(pos, next);
    pos += strlen(pos);
    next = va_arg(arg, const char *);
    }
    va_end(arg);
    *pos = 0;

    return result;
    }

    This should be fine (it's a close paraphrase, but I haven't tried it).
    It concatenates string arguments on the argument until one which is
    NULL is reached. Now I want to have a function (analogous to vprintf
    for printf) that does the same thing called from another variadic
    function - how do I handle the rewinding done by va_end/va_start in a
    portable way, given that I won't have "first" again? In other words,
    how can I write (portably) vstrdupcat in:

    char *choseThenConca t(int which, const char *first, ...)
    {
    char *res;
    /* do something with which, then */
    va_list args;
    va_start(args, first);
    res = vstrdupcat(firs t, args);
    va_end();
    /* do stuff with res */
    return ...something-or-other...
    }
  • Ben Bacarisse

    #2
    Re: reading &lt;stdarg.h&gt ;'s va_list twice

    tonybalinski@gm ail.com writes:
    I'd like to be able to scan a va_list twice in a v... function, but
    can't see how to do it.
    <snip>
    how do I handle the rewinding done by va_end/va_start in a
    portable way, given that I won't have "first" again? In other words,
    how can I write (portably) vstrdupcat in:
    >
    char *choseThenConca t(int which, const char *first, ...)
    {
    char *res;
    /* do something with which, then */
    va_list args;
    va_start(args, first);
    res = vstrdupcat(firs t, args);
    va_end();
    /* do stuff with res */
    return ...something-or-other...
    }
    va_copy

    --
    Ben.

    Comment

    • tonybalinski@gmail.com

      #3
      Re: reading &lt;stdarg.h&gt ;'s va_list twice



      Ben Bacarisse wrote:
      tonybalinski@gm ail.com writes:
      >
      I'd like to be able to scan a va_list twice in a v... function, but
      can't see how to do it.
      <snip>
      >
      va_copy
      Where would you put the va_copy?
      And for pre-C99? I want this to work with C89, if at all possible.

      Tony

      Comment

      • Ben Bacarisse

        #4
        Re: reading &lt;stdarg.h&gt ;'s va_list twice

        tonybalinski@gm ail.com writes:
        Ben Bacarisse wrote:
        >tonybalinski@gm ail.com writes:
        >>
        I'd like to be able to scan a va_list twice in a v... function, but
        can't see how to do it.
        ><snip>
        >>
        >va_copy
        >
        Where would you put the va_copy?
        Inside a function that takes a va_list you can do this:

        void example(va_list alist)
        {
        va_list copy_of_alist;
        va_copy(copy_of _alist, alist);
        /* process original alist */
        /* process copy_of_alist */
        va_end(alist);
        va_end(copy_of_ alist);
        }
        And for pre-C99? I want this to work with C89, if at all possible.
        Ah. In that case I break you concatenation function into two. One to
        whatever the first pass does (no doubt count the strings and their
        lengths) and another to do the concatenation.

        In fact, I'd be inclined do this anyway.

        --
        Ben.

        Comment

        • tonybalinski@gmail.com

          #5
          Re: reading &lt;stdarg.h&gt ;'s va_list twice



          Ben Bacarisse wrote:
          tonybalinski@gm ail.com writes:
          And for pre-C99? I want this to work with C89, if at all possible.
          >
          Ah. In that case I break you concatenation function into two. One to
          whatever the first pass does (no doubt count the strings and their
          lengths) and another to do the concatenation.
          >
          In fact, I'd be inclined do this anyway.
          >
          --
          Ben.
          I was afraid you'd say that... but thanks anyway!

          Comment

          • Ben Pfaff

            #6
            Re: reading &lt;stdarg.h&gt ;'s va_list twice

            Ben Bacarisse <ben.usenet@bsb .me.ukwrites:
            tonybalinski@gm ail.com writes:
            >[va_copy]
            >And for pre-C99? I want this to work with C89, if at all possible.
            >
            Ah. In that case I break you concatenation function into two.
            If you are willing to give up strict portability, then you may
            find that the following (or similar; I have not carefully
            proofread it) is good enough:

            #include <stdarg.h>
            #ifndef va_copy
            # ifdef __va_copy
            # define va_copy(a, b) __va_copy(a, b)
            # else
            # define va_copy(a, b) ((a) = (b))
            # endif
            #endif
            In that case I break you concatenation function into two. One to
            whatever the first pass does (no doubt count the strings and their
            lengths) and another to do the concatenation.
            Of course, that will definitely work.
            --
            "What is appropriate for the master is not appropriate for the novice.
            You must understand the Tao before transcending structure."
            --The Tao of Programming

            Comment

            • Peter Nilsson

              #7
              Re: reading &lt;stdarg.h&gt ;'s va_list twice

              Ben Bacarisse <ben.use...@bsb .me.ukwrote:
              ...
              void example(va_list alist)
              {
                  va_list copy_of_alist;
                  va_copy(copy_of _alist, alist);
                  /* process original alist */
                  /* process copy_of_alist */
                  va_end(alist);
              No, va_end should be applied to alist in the function
              that initialised alist with va_start or va_copy.
                  va_end(copy_of_ alist);
              >
              }
              >
              And for pre-C99? I want this to work with C89, if at
              all possible.
              >
              Ah.  In that case I break you concatenation function
              into two.  One to whatever the first pass does (no
              doubt count the strings and their lengths) and another
              to do the concatenation.
              Or pass two va_lists.
              In fact, I'd be inclined do this anyway.
              --
              Peter

              Comment

              • Ben Bacarisse

                #8
                Re: reading &lt;stdarg.h&gt ;'s va_list twice

                Peter Nilsson <airia@acay.com .auwrites:
                Ben Bacarisse <ben.use...@bsb .me.ukwrote:
                >...
                >void example(va_list alist)
                >{
                >    va_list copy_of_alist;
                >    va_copy(copy_of _alist, alist);
                >    /* process original alist */
                >    /* process copy_of_alist */
                >    va_end(alist);
                >
                No, va_end should be applied to alist in the function
                that initialised alist with va_start or va_copy.
                Yes, thanks. I don't know how that got in there.
                >    va_end(copy_of_ alist);
                >>
                >}
                >>
                And for pre-C99? I want this to work with C89, if at
                all possible.
                >>
                >Ah.  In that case I break you concatenation function
                >into two.  One to whatever the first pass does (no
                >doubt count the strings and their lengths) and another
                >to do the concatenation.
                >
                Or pass two va_lists.
                I am probably too old to say it but I am thinking "sweet!" :-) (and
                also "why didn't I think of that?").

                --
                Ben.

                Comment

                • Peter Nilsson

                  #9
                  Re: reading &lt;stdarg.h&gt ;'s va_list twice

                  tonybalin...@gm ail.com wrote:
                  I'd like to be able to scan a va_list twice in a v...
                  function, but can't see how to do it. For example
                  >
                    char *strdupcat(cons t char *first, ...)
                    {
                  You don't have to scan it twice...

                  #include <stdarg.h>
                  #include <stdlib.h>
                  #include <string.h>

                  static
                  char *vzjoin(size_t z, const char *head, va_list ap)
                  {
                  char *r;

                  if (head == 0)
                  {
                  r = malloc(z + 1);
                  r[z] = 0;
                  }
                  else
                  {
                  size_t hz = strlen(head);
                  char *tail = va_arg(ap, char *);
                  r = vzjoin(z + hz, tail, ap);
                  memcpy(r + z, head, hz);
                  }

                  return r;
                  }

                  char *vjoin(const char *head, va_list ap)
                  {
                  return vzjoin(0, head, ap);
                  }

                  char *join(const char *head, ...)
                  {
                  char *r;
                  va_list ap;

                  va_start(ap, head);
                  r = vjoin(head, ap);
                  va_end(ap);

                  return r;
                  }

                  --
                  Peter

                  Comment

                  • Tim Rentsch

                    #10
                    Re: reading &lt;stdarg.h&gt ;'s va_list twice

                    Ben Pfaff <blp@cs.stanfor d.eduwrites:
                    Ben Bacarisse <ben.usenet@bsb .me.ukwrites:
                    >
                    tonybalinski@gm ail.com writes:
                    [va_copy]
                    And for pre-C99? I want this to work with C89, if at all possible.
                    Ah. In that case I break you concatenation function into two.
                    >
                    If you are willing to give up strict portability, then you may
                    find that the following (or similar; I have not carefully
                    proofread it) is good enough:
                    >
                    #include <stdarg.h>
                    #ifndef va_copy
                    # ifdef __va_copy
                    # define va_copy(a, b) __va_copy(a, b)
                    # else
                    # define va_copy(a, b) ((a) = (b))
                    # endif
                    #endif
                    It's probably better to use memcpy() rather than assignment,
                    in case the type involved is an array type (and __va_copy
                    isn't available, even though it "hopefully will be").

                    Comment

                    Working...