/* stdarg.c (emx+gcc) -- Copyright (c) 1996 by Eberhard Mattes */

/* This sample program shows how to use the macros of <stdarg.h>. */

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


/* Print an error message and terminate.  This function is called like
   printf(), but it never returns.  The message will be preceded by
   "stdarg: " and will be followed by a newline. */

void error (const char *fmt, ...)
{
  va_list arg_ptr;

  va_start (arg_ptr, fmt);
  fprintf (stderr, "stdarg: ");
  vfprintf (stderr, fmt, arg_ptr);
  va_end (arg_ptr);
  fputc ('\n', stderr);
  exit (2);
}


/* Concatenate strings.  The last string pointer must be followed by a
   NULL pointer.  Memory for the resulting string is allocated with
   malloc(), don't forget to call free()! */

char *concat (const char *first, ...)
{
  va_list arg_ptr;
  size_t total_len, len;
  const char *str;
  char *result;

  if (first == NULL)
    error ("concat() expects at least one string.");

  /* Traverse the arguments to compute the length of the
     concatenation. */

  total_len = strlen (first);
  va_start (arg_ptr, first);
  while ((str = va_arg (arg_ptr, const char *)) != NULL)
    total_len += strlen (str);
  va_end (arg_ptr);

  /* Allocate memory.  Don't forget to allocate an extra byte for the
     terminating null character. */

  result = (char *)malloc (total_len + 1);
  if (result == NULL)
    error ("Allocation of %lu bytes in concat() failed.",
           (unsigned long)(total_len + 1));

  /* Traverse the arguments again, copying to RESULT. */

  total_len = 0;
  len = strlen (first);
  memcpy (result + total_len, first, len); total_len += len;
  va_start (arg_ptr, first);
  while ((str = va_arg (arg_ptr, const char *)) != NULL)
    {
      len = strlen (str);
      memcpy (result + total_len, str, len); total_len += len;
    }
  va_end (arg_ptr);

  /* Add the terminating null character. */

  result[total_len] = 0;

  return result;
}


/* Test concat(). */

static void test_concat (void)
{
  /* Note that we have to cast NULL to a pointer type here as concat()
     doesn't have a 4th formal parameter. */

  char *p = concat ("Hello, ", "world", "!", (char *)NULL);
  puts (p);
  free (p);
}


/* Show how to run this program. */

static void usage (void)
{
  puts ("Usage:\n"
        "  stdarg error     -- show an error message\n"
        "  stdarg concat    -- concatenate some strings");
  exit (1);
}


/* This program starts here. */

int main (int argc, char *argv[])
{
  if (argc == 2 && strcmp (argv[1], "error") == 0)
    error ("This is a %s error message.", "sample");
  else if (argc == 2 && strcmp (argv[1], "concat") == 0)
    test_concat ();
  else
    usage ();
  return 0;
}
