/* $Id: sformat.c,v 1.2 2008/10/28 17:40:35 kiesling Exp $ -*-c-*-*/

/*
  This file is part of ctalk.
  Copyright © 2005-2008  Robert Kiesling, ctalk@ctalklang.org.
  Permission is granted to copy this software provided that this copyright
  notice is included in all source code modules.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software Foundation, 
  Inc., 51 Franklin St., Fifth Floor, Boston, MA 02110-1301 USA.
*/

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

#ifndef MAXMSG
#define MAXMSG 8192
#endif

/*    format_string ()
 *
 *    Formats a string using a printf-like format and an argument 
 *    list.  The calling function must call va_start first.
 *    The function recognizes the following format escapes.
 *
 *    %s - Character string.
 *    %p - Pointer, formatted as a hexadecimal number.
 *    %d - Decimal integer.
 */

char *_format_str (char *buf, char *fmt, va_list ap) {

  char *s;
  int d;
  double db;
  long double ldb = 0.0;         /* Avoid warnings. */
  long int li;
  long long int lli = 0L;
  char tbuf[MAXMSG];

  *buf = 0;

  while (*fmt) {
    if (*fmt == '%') {
      (void) *fmt++;
      switch (*fmt++)
	{
	case 's':
	  s = va_arg (ap, char *);
	  if (s)
	    strcat (buf, s);
	  else 
	    strcat (buf, "(null)");
	  break;
	case 'p':
	  s = va_arg (ap, char *);
	  if (s) {
 	    sprintf (tbuf, "0x%p", (void *)s);
	    strcat (buf, tbuf);
	  } else {
 	    sprintf (tbuf, "0x%p", (void *)NULL);
	    strcat (buf, tbuf);
	  }
	case 'd':
	  d = va_arg (ap, int);
	  sprintf (tbuf, "%d", d);
	  strcat (buf, tbuf);
	  break;
	case 'f':
	  db = va_arg (ap, double);
	  sprintf (tbuf, "%f", db);
	  strcat (buf, tbuf);
	  break;
	case 'L':
	  switch (*fmt++)
	    {
	    case 'd':
	      lli = va_arg (ap, long long int);
	      sprintf (tbuf, "%lld", lli);
	      strcat (buf, tbuf);
	      break;
	    case 'f':
	      db = va_arg (ap, long double);
	      sprintf (buf, "%Lf", ldb);
	      strcat (buf, tbuf);
	      break;
	    }
	  break;
	case 'l':
	  switch (*fmt++)
	    {
	    case 'd':
	      li = va_arg (ap, long int);
	      sprintf (tbuf, "%ld", li);
	      strcat (buf, tbuf);
	      break;
	    case 'f':
	      db = va_arg (ap, double);
	      sprintf (tbuf, "%f", db);
	      strcat (buf, tbuf);
	      break;
	    case 'l':
	      switch (*fmt++)
		{
		case 'd':
		  li = va_arg (ap, long long int);
		  sprintf (tbuf, "%lld", lli);
		  strcat (buf, tbuf);
		  break;
		case 'f':
		  db = va_arg (ap, long double);
		  sprintf (tbuf, "%Lf", ldb);
		  strcat (buf, tbuf);
		  break;
		}
	      break;  /* case 'l': */
	    }
	  break;  /* case 'l': */
	}
    } else {
      sprintf (tbuf, "%c", *fmt++);
      strcat (buf, tbuf);
    }
  }

  return buf;
}

char *__ctalkCPrintFmtToCtalkFmt (char *c_fmt, char *ctalk_fmt) {

  int i, j;

  for (i = 0, j = 0; c_fmt[i];) {
    if (c_fmt[i] == '%') {
      ctalk_fmt[j++] = c_fmt[i++];
      while (!strpbrk(&c_fmt[i++], "diouxXeEfFgGaAcsp"))
	;
      ctalk_fmt[j++] = 's';
    } else {
      ctalk_fmt[j++] = c_fmt[i++];
    }
  }
  ctalk_fmt[j] = '\0';
  return ctalk_fmt;
}
