#include "stl.h"
typedef unsigned long size_t;
typedef struct {} FILE;

int snprintf(char *s, size_t n, const char *format, ...);
int sprintf(char *s, const char *format, ...);
int swprintf(wchar_t *s, size_t n, const wchar_t *format, ...);

typedef void *va_list;
#define va_start(ap, parmN)
#define va_end(ap)
#define va_arg(ap, type) ((type)0)

int vsnprintf(char *s, size_t n, const char *format, va_list arg);

int mysprintf(char *s, size_t n, const char *format, ...)
{
	int result;

	va_list args;
	va_start(args, format);
		result = vsnprintf(s, n, format, args);
	va_end(args);

	return result;
}

int sscanf(const char *s, const char *format, ...);

// ----------

int source();
void sink(...);

namespace string
{
	char *source();
};

namespace wstring
{
	wchar_t *source();
};

// ----------

void test1()
{
	{
		char buffer[256] = {0};
		sink(snprintf(buffer, 256, "%s", "Hello."));
		sink(buffer);
	}
	{
		char buffer[256] = {0};
		sink(snprintf(buffer, 256, "%s", string::source()));
		sink(buffer); // $ ast,ir
	}
	{
		char buffer[256] = {0};
		sink(snprintf(buffer, 256, string::source(), "Hello."));
		sink(buffer); // $ ast,ir
	}
	{
		char buffer[256] = {0};
		sink(snprintf(buffer, 256, "%s %s %s", "a", "b", string::source()));
		sink(buffer); // $ ast,ir
	}
	{
		char buffer[256] = {0};
		sink(snprintf(buffer, 256, "%.*s", 10, string::source()));
		sink(buffer); // $ ast,ir
	}

	{
		char buffer[256] = {0};
		sink(snprintf(buffer, 256, "%i", 0));
		sink(buffer);
	}
	{
		char buffer[256] = {0};
		sink(snprintf(buffer, 256, "%i", source()));
		sink(buffer); // $ ast,ir
	}
	{
		char buffer[256] = {0};
		sink(snprintf(buffer, 256, "%.*s", source(), "Hello."));
		sink(buffer); // $ ast,ir
	}

	{
		char buffer[256] = {0};
		sink(snprintf(buffer, 256, "%p", string::source()));
		sink(buffer); // $ ast,ir // tainted (debatable)
	}

	{
		char buffer[256] = {0};
		sink(sprintf(buffer, "%s", string::source()));
		sink(buffer); // $ ast,ir
	}
	{
		char buffer[256] = {0};
		sink(sprintf(buffer, "%ls", wstring::source()));
		sink(buffer); // $ ast,ir
	}
	{
		wchar_t wbuffer[256] = {0};
		sink(swprintf(wbuffer, 256, L"%s", wstring::source()));
		sink(wbuffer); // $ ast,ir
	}
	{
		char buffer[256] = {0};
		sink(mysprintf(buffer, 256, "%s", string::source()));
		sink(buffer); // $ ast,ir
	}

	{
		int i = 0;
		sink(sscanf("123", "%i", &i));
		sink(i);
	}
	{
		int i = 0;
		sink(sscanf(string::source(), "%i", &i));
		sink(i); // $ ast,ir
	}
	{
		char buffer[256] = {0};
		sink(sscanf("Hello.", "%s", &buffer));
		sink(buffer);
	}
	{
		char buffer[256] = {0};
		sink(sscanf(string::source(), "%s", &buffer));
		sink(buffer); // $ ast,ir
	}
}

// ----------

size_t strlen(const char *s);
size_t wcslen(const wchar_t *s);

void test2()
{
	char *s = string::source();
	wchar_t *ws = wstring::source();
	int i;

	sink(strlen(s));
	sink(wcslen(ws));

	i = strlen(s) + 1;
	sink(i);

	sink(s[strlen(s) - 1]); // $ ast,ir
	sink(ws + (wcslen(ws) / 2)); // $ ast,ir
}

void test_format() {
  auto s = std::format("{}", string::source());
  sink(s); // $ ir MISSING: ast

  auto s2 = std::format(string::source());
  sink(s2); // $ ir MISSING: ast
}

void test(std::format_string s) {
  int x = source();
  int y = std::same_signature_as_format_but_different_name(s, x);
  sink(y); // clean
}