typedef struct
{
} FILE;

typedef void *locale_t;

int scanf(const char *format, ...);
int fscanf(FILE *stream, const char *format, ...);
int sscanf(const char *s, const char *format, ...);
int _scanf_l(const char *format, locale_t locale, ...);

void use(int i);

void set_by_ref(int &i);
void set_by_ptr(int *i);
bool maybe();

FILE *get_a_stream();
const char *get_a_string();
extern locale_t get_a_locale();

typedef long size_t;

void *malloc(size_t size);
void free(void *ptr);

int main()
{
	// --- simple cases ---

	{
		int i;

		scanf("%d", &i); // $ Source[cpp/missing-check-scanf]
		use(i); // $ Alert[cpp/missing-check-scanf] // BAD: may not have written `i`
	}

	{
		int i;

		if (scanf("%d", &i) == 1)
		{
			use(i); // GOOD: checks return value
		}
	}

	{
		int i = 0;

		scanf("%d", &i);
		use(i); // GOOD. Design choice: already initialized variables are fine.
	}

	{
		int i;
		use(i); // GOOD: only care about uses after scanf call

		if (scanf("%d", &i) == 1)
		{
			use(i); // GOOD
		}
	}

	{
		int i; // Reused variable

		scanf("%d", &i); // $ Source[cpp/missing-check-scanf]
		use(i); // $ Alert[cpp/missing-check-scanf] // BAD

		if (scanf("%d", &i) == 1)
		{
			use(i); // GOOD
		}
	}

	{
		int i; // Reset variable

		scanf("%d", &i); // $ Source[cpp/missing-check-scanf]
		use(i); // $ Alert[cpp/missing-check-scanf] // BAD

		i = 1;
		use(i); // GOOD
	}

	{
		int *i = (int*)malloc(sizeof(int)); // Allocated variable

		scanf("%d", i); // $ Source[cpp/missing-check-scanf]
		use(*i); // $ Alert[cpp/missing-check-scanf] // BAD
		free(i); // GOOD
	}

	{
		int *i = new int; // Allocated variable

		scanf("%d", i); // $ Source[cpp/missing-check-scanf]
		use(*i); // $ Alert[cpp/missing-check-scanf] // BAD
		delete i; // GOOD
	}

	// --- different scanf functions ---

	{
		int i;

		fscanf(get_a_stream(), "%d", &i); // $ Source[cpp/missing-check-scanf]
		use(i); // $ Alert[cpp/missing-check-scanf] // BAD: may not have written `i`
	}

	{
		int i;

		sscanf(get_a_string(), "%d", &i); // $ Source[cpp/missing-check-scanf]
		use(i); // $ Alert[cpp/missing-check-scanf] // BAD: may not have written `i`
	}

	{
		int i;

		if (_scanf_l("%d", get_a_locale(), &i) == 1)
		{
			use(i); // GOOD
		}
	}

	// --- different ways of checking ---

	{
		int i;

		if (scanf("%d", &i) >= 1)
		{
			use(i); // GOOD
		}
	}

	{
		int i;

		if (scanf("%d", &i) == 1)
		{
			use(i); // GOOD
		}
	}

	{
		int i;

		if (0 < scanf("%d", &i))
		{
			if (true)
			{
				use(i); // GOOD
			}
		}
	}

	{
		int i;

		if (scanf("%d", &i) != 0) // $ Alert[cpp/incorrectly-checked-scanf]
		{
			use(i); // BAD: scanf can return EOF
		}
	}

	{
		int i;

		if (scanf("%d", &i) == 0) // $ Alert[cpp/incorrectly-checked-scanf]
		{
			use(i); // BAD: checks return value incorrectly
		}
	}

	{
		int r;
		int i;

		r = scanf("%d", &i);

		if (r >= 1)
		{
			use(i); // GOOD
		}
	}

	{
		bool b;
		int i;

		b = scanf("%d", &i); // $ Alert[cpp/incorrectly-checked-scanf]

		if (b >= 1)
		{
			use(i); // BAD: scanf can return EOF (boolifies true)
		}
	}

	{
		int i;

		if (scanf("%d", &i)) // $ Alert[cpp/incorrectly-checked-scanf]
			use(i); // BAD
	}

	{
		int i, j;

		if (scanf("%d %d", &i) >= 2)
		{
			use(i); // GOOD
			use(j); // GOOD: `j` is not a scanf arg, so out of scope of MissingCheckScanf
		}
	}

	{
		int i, j;

		if (scanf("%d %d", &i, &j) >= 1) // $ Source[cpp/missing-check-scanf]
		{
			use(i); // GOOD
			use(j); // $ Alert[cpp/missing-check-scanf] // BAD: checks return value incorrectly
		}
	}

	{
		int i, j;

		if (scanf("%d %d", &i, &j) >= 2)
		{
			use(i); // GOOD
			use(j); // GOOD
		}
	}

	{
		char c[5];
		int d;

		while(maybe()) {
			if (maybe()) {
				break;
			}
			else if (maybe() && (scanf("%5c %d", c, &d) == 1)) { // $ Source[cpp/missing-check-scanf] // GOOD
				use(*(int *)c); // GOOD
				use(d); // $ Alert[cpp/missing-check-scanf] // BAD
			}
			else if ((scanf("%5c %d", c, &d) == 1) && maybe()) { // $ Source[cpp/missing-check-scanf] // GOOD
				use(*(int *)c); // GOOD
				use(d); // $ Alert[cpp/missing-check-scanf] // BAD
			}
		}
	}

	// --- different initialization ---

	{
		int i;
		i = 0;

		scanf("%d", &i);
		use(i); // GOOD
	}

	{
		int i;

		set_by_ref(i);
		scanf("%d", &i); // $ Source[cpp/missing-check-scanf]
		use(i); // $ SPURIOUS: Alert[cpp/missing-check-scanf] // GOOD [FALSE POSITIVE]
	}

	{
		int i;

		set_by_ptr(&i);
		scanf("%d", &i); // $ Source[cpp/missing-check-scanf]
		use(i); // $ SPURIOUS: Alert[cpp/missing-check-scanf] // GOOD [FALSE POSITIVE]
	}

	{
		int i;

		if (maybe())
		{
			i = 0;
		}

		scanf("%d", &i); // $ Source[cpp/missing-check-scanf]
		use(i); // $ Alert[cpp/missing-check-scanf] // BAD: `i` may not have been initialized
	}

	// --- different use ---

	{
		int i;
		int *ptr_i = &i;

		scanf("%d", &i);
		use(*ptr_i); // $ MISSING: Alert // BAD [NOT DETECTED]: may not have written `i`
	}

	{
		int i;
		int *ptr_i = &i;

		scanf("%d", ptr_i);
		use(i); // $ MISSING: Alert // BAD [NOT DETECTED]: may not have written `*ptr_i`
	}

	{
		int i;
		scanf("%d", &i);
		i = 42;
		use(i); // GOOD
	}

	// --- weird formatting strings ---

	{
		int i, j;

		if (sscanf("123", "%n %*d %n", &i, &j) >= 0)
		{
			use(i); // GOOD (`%n` does not consume input, but writes 0 to i)
			use(j); // GOOD (`%n` does not consume input, but writes 3 to j)
		}
	}

	{
		int i;

		if (scanf("%% %d", &i) >= 1)
		{
			use(i); // GOOD (`%%` does not consume input)
		}
	}

	{
		int i;

		if (scanf("%*d %d", &i) >= 1)
		{
			use(i); // GOOD (`%*d` does not consume input)
		}
	}

	{
		int d, n;

		if (scanf("%*d %d %n", &d, &n) == 1) {
			use(d); // GOOD
			use(n); // GOOD
		}
	}

	{
		char substr[32];
		int n;
        while (sscanf(get_a_string(), "%31[^:]: %d", substr, &n) == 2) { // GOOD: cycle from write to unguarded access
			use(*(int *)substr); // GOOD
            use(n); // GOOD
		}
	}
}

// --- Non-local cases ---

bool my_scan_int(int &i)
{
	return scanf("%d", &i) == 1; // GOOD
}

void my_scan_int_test()
{
	int i;

	use(i); // GOOD: used before scanf

	my_scan_int(i);
	use(i); // $ MISSING: Alert // BAD [NOT DETECTED]

	if (my_scan_int(i))
	{
		use(i); // GOOD
	}
}

// --- Can be OK'd given a sufficiently smart analysis ---

char *my_string_copy() {
	static const char SRC_STRING[] = "48656C6C6F";
	static       char DST_STRING[] = ".....";

	int len = sizeof(SRC_STRING) - 1;
    const char *src = SRC_STRING;
    char *ptr = DST_STRING;

    for (int i = 0; i < len; i += 2) {
		unsigned int u;
	    sscanf(src + i, "%2x", &u); // $ Source[cpp/missing-check-scanf]
        *ptr++ = (char) u; // $ SPURIOUS: Alert[cpp/missing-check-scanf] // GOOD [FALSE POSITIVE]? src+i+{0,1} are always valid %x digits, so this should be OK.
    }
	*ptr++ = 0;
	return DST_STRING;
}

void scan_and_write() {
	{
		int i;
		if (scanf("%d", &i) < 1) { // $ Source[cpp/missing-check-scanf]
			i = 0;
		}
		use(i);  // $ SPURIOUS: Alert[cpp/missing-check-scanf] // GOOD [FALSE POSITIVE]: variable is overwritten with a default value when scanf fails
	}
	{
		int i;
		if (scanf("%d", &i) != 1) { // $ Source[cpp/missing-check-scanf]
			i = 0;
		}
		use(i);  // $ SPURIOUS: Alert[cpp/missing-check-scanf] // GOOD [FALSE POSITIVE]: variable is overwritten with a default value when scanf fails
	}
}

void scan_and_static_variable() {
	static int i;
	scanf("%d", &i);
	use(i);  // GOOD: static variables are always 0-initialized
}

void bad_check() {
	{
		int i = 0;
		if (scanf("%d", &i) != 0) { // $ Alert[cpp/incorrectly-checked-scanf]
			return;
		}
		use(i);  // GOOD [FALSE POSITIVE]: Technically no security issue, but code is incorrect.
	}
	{
		int i = 0;
		int r = scanf("%d", &i); // $ Alert[cpp/incorrectly-checked-scanf]
		if (!r) {
			return;
		}
		use(i);  // GOOD [FALSE POSITIVE]: Technically no security issue, but code is incorrect.
	}
}

#define EOF (-1)

void disjunct_boolean_condition(const char* modifier_data) {
	long value;
	auto rc = sscanf(modifier_data, "%lx", &value); // $ Source[cpp/missing-check-scanf]

	if((rc == EOF) || (rc == 0)) {
		return;
	}
	use(value); // $ Alert[cpp/missing-check-scanf] // GOOD
}

void check_for_negative_test() {
	int res;
	int value;

	res = scanf("%d", &value); // $ Source[cpp/missing-check-scanf] // GOOD
	if(res == 0) {
		return;
	}
	if (res < 0) {
		return;
	}
	use(value); // $ Alert[cpp/missing-check-scanf]
}

void multiple_checks() {
	{
		int i;
		int res = scanf("%d", &i); // $ Source[cpp/missing-check-scanf]

		if (res >= 0) {
			if (res != 0) {
				use(i); // $ SPURIOUS: Alert[cpp/missing-check-scanf] // GOOD: checks return value [FALSE POSITIVE]
			}
		}
	}

	{
		int i;
		int res = scanf("%d", &i); // $ Source[cpp/missing-check-scanf]

		if (res < 0) return;
		if (res != 0) {
			use(i); // $ SPURIOUS: Alert[cpp/missing-check-scanf] // GOOD: checks return value [FALSE POSITIVE]
		}
	}

	{
		int i;
		int res = scanf("%d", &i);

		if (res >= 1) {
			if (res != 0) {
				use(i); // GOOD: checks return value
			}
		}
	}

	{
		int i;
		int res = scanf("%d", &i);

		if (res == 1) {
			if (res != 0) {
				use(i); // GOOD: checks return value
			}
		}
	}
}

void switch_cases(const char *data) {
	float a, b, c;

	switch (sscanf(data, "%f %f %f", &a, &b, &c)) {
		case 2:
			use(a); // GOOD
			use(b); // GOOD
			break;
		case 3:
			use(a); // GOOD
			use(b); // GOOD
			use(c); // GOOD
			break;
		default:
			break;
	}

	float d, e, f;

	switch (sscanf(data, "%f %f %f", &d, &e, &f)) { // $ Source[cpp/missing-check-scanf]
		case 2:
			use(d); // GOOD
			use(e); // GOOD
			use(f); // $ Alert[cpp/missing-check-scanf] // BAD
			break;
		case 3:
			use(d); // GOOD
			use(e); // GOOD
			use(f); // GOOD
			break;
		default:
			break;
	}
}

void test_scanf_compared_right_away() {
  int i;
  bool success = scanf("%d", &i) == 1;
  if(success) {
    use(i); // GOOD
  }
}

void test_scanf_compared_in_conjunct_right(bool b) {
  int i;
  bool success = b && scanf("%d", &i) == 1;
  if(success) {
    use(i); // GOOD
  }
}

void test_scanf_compared_in_conjunct_left(bool b) {
  int i;
  bool success = scanf("%d", &i) == 1 && b;
  if(success) {
    use(i); // GOOD
  }
}
