#include "nawmmod.h"

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

int nawm_modrev = 1;
static int file_type;

void sprintf_fun(int argc, nawmval *argv, nawmval *ret);

void modinit(void)
{
  file_type = module_define_type("file");

  module_define_variable("stdin", file_type, (nawmval)stdin);
  module_define_variable("stdout", file_type, (nawmval)stdout);
  module_define_variable("stderr", file_type, (nawmval)stderr);

  module_define_variable("_IOFBF", T_INT, _IOFBF);
  module_define_variable("_IOLBF", T_INT, _IOLBF);
  module_define_variable("_IONBF", T_INT, _IONBF);

  module_define_procedure("remove", T_INT, remove_fun, 1, T_STR);
  module_define_procedure("rename", T_INT, rename_fun, 2, T_STR, T_STR);
  module_define_procedure("fclose", T_INT, fclose_fun, 1, file_type);
  module_define_procedure("fflush", T_INT, fflush_fun, 1, file_type);
  module_define_procedure("fopen", file_type, fopen_fun, 2, T_STR, T_STR);
  module_define_procedure("freopen", file_type, freopen_fun, 3,
			  T_STR, T_STR, file_type);
  module_define_procedure("setvbuf", T_INT, setvbuf_fun, 2, file_type, T_INT);
  module_define_procedure("fprintf", T_INT, fprintf_fun, -2, file_type, T_STR);
  module_define_procedure("printf", T_INT, printf_fun, -1, T_STR);
  module_define_procedure("fgetc", T_INT, fgetc_fun, 1, file_type);
  module_define_procedure("fgets", T_STR, fgets_fun, 1, file_type);
  module_define_procedure("fputc", T_INT, fputc_fun, 2, T_INT, file_type);
  module_define_procedure("fputs", T_STR, fputs_fun, 2, T_STR, file_type);

  module_define_procedure("sprintf", T_STR, sprintf_fun, -1, T_STR);
}

void sprintf_fun(int argc, nawmval *argv, nawmval *ret)
{
  char *fmt = (char *)argv[0], *p, *buf, *str, tmp[20];
  int bufsiz, arg = 1, len, left;

  bufsiz = left = 128;
  p = buf = xmalloc(bufsiz);

  while (*fmt)
    {
      if (*fmt == '%')
	{
	  switch (*++fmt)
	    {
	    case 's':
	      str = (char *)argv[arg++];
	      len = strlen(str);
	      break;

	    case 'd':
	      sprintf(str = tmp, "%d", argv[arg++]);
	      len = strlen(str);
	      break;

	    case 'c':
	      sprintf(str = tmp, "%c", argv[arg++]);
	      len = 1;
	      break;

	    case '%':
	      strcpy(str = tmp, "%");
	      len = 1;
	      break;

	    default:
	      sprintf(str = tmp, "%%%c", *fmt);
	      len = 2;
	      break;
	    }
	  fmt++;
	}
      else
	{
	  char *nextarg = strchr(fmt, '%');
	  if (!nextarg)
	    len = strlen(fmt);
	  else
	    len = nextarg - fmt;
	  str = fmt;
	  fmt += len;
	}

      if (left < len)
	{
	  char *nbuf;

	  while (left < len)
	    {
	      left += bufsiz;
	      bufsiz *= 2;
	    }
	  nbuf = xrealloc(buf, bufsiz + 1);
	  p = nbuf + (p - buf);
	  buf = nbuf;
	}
      strncpy(p, str, len);
      p += len;
      left -= len;
    }
  *p = '\0';

  *ret = (nawmval)gcstrdup(buf);
  free(buf);
}  
