about summary refs log tree commit diff stats
path: root/wrapperhelper/src/generator.c
diff options
context:
space:
mode:
Diffstat (limited to 'wrapperhelper/src/generator.c')
-rw-r--r--wrapperhelper/src/generator.c478
1 files changed, 284 insertions, 194 deletions
diff --git a/wrapperhelper/src/generator.c b/wrapperhelper/src/generator.c
index 98e254ed..e162d0e4 100644
--- a/wrapperhelper/src/generator.c
+++ b/wrapperhelper/src/generator.c
@@ -6,149 +6,173 @@
 static const char *rft2str[8] = {
 	[RQT_FUN] = "",
 	[RQT_FUN_2] = "",
-	[RQT_FUN_MY] = "(my) ",
-	[RQT_FUN_D] = "(D) ",
+	[RQT_FUN_MY] = " (my)",
+	[RQT_FUN_D] = " (D)",
 	[RQT_DATA] = "",
-	[RQT_DATAV] = "(V) ",
-	[RQT_DATAB] = "(B) ",
-	[RQT_DATAM] = "(my) ",
+	[RQT_DATAV] = " (V)",
+	[RQT_DATAB] = " (B)",
+	[RQT_DATAM] = " (my)",
 };
 #define IS_RQT_FUN2(rty) (((rty) == RQT_FUN_2) || ((rty) == RQT_FUN_D))
 #define IS_RQT_FUNCTION(rty) ((rty) < RQT_DATA)
 
-void request_print(request_t *req) {
-	printf("%s", string_content(req->obj_name));
-	if (req->has_default && req->has_val && (IS_RQT_FUNCTION(req->def.rty) != IS_RQT_FUNCTION(req->val.rty))) {
-		printf(" => conflict: was/is data, is/was function\n");
-	}
-	int is_fun;
-	if (req->has_default) is_fun = IS_RQT_FUNCTION(req->def.rty);
-	else if (req->has_val) is_fun = IS_RQT_FUNCTION(req->val.rty);
-	else {
-		printf(" => (no value)\n");
-		return;
-	}
-	
-	if (is_fun) {
-		printf(" => %sfunction", req->weak ? "weak " : "");
-		if (req->has_default) {
-			printf(" with %sdefault %s%s%s%s",
-				req->default_comment ? "commented " : "",
+void request_print(const request_t *req) {
+	printf("%s%s: %sdefault", string_content(req->obj_name), req->weak ? " (weak)" : "", req->default_comment ? "commented " : "");
+	switch (req->def.rty) {
+	case RQT_FUN:
+	case RQT_FUN_2:
+	case RQT_FUN_MY:
+	case RQT_FUN_D:
+		if (req->def.fun.typ) {
+			printf(" function%s %s%s%s",
 				rft2str[req->def.rty],
 				string_content(req->def.fun.typ),
-				(req->def.rty == RQT_FUN_2) ? " -> " : "",
-				(req->def.rty == RQT_FUN_2) ? string_content(req->def.fun.fun2) : "");
-		}
-		if (req->has_val) {
-			printf(" with solved %s%s%s%s",
-				rft2str[req->val.rty],
-				string_content(req->val.fun.typ),
-				(req->val.rty == RQT_FUN_2) ? " -> " : "",
-				(req->val.rty == RQT_FUN_2) ? string_content(req->val.fun.fun2) : "");
+				req->def.fun.fun2 ? " -> " : "",
+				req->def.fun.fun2 ? string_content(req->def.fun.fun2) : "");
+		} else {
+			printf(" untyped function%s", rft2str[req->def.rty]);
 		}
-	} else {
-		printf(" => %sdata", req->weak ? "weak " : "");
-		if (req->has_default) {
-			if (req->def.dat.has_size) printf(" with default %zu", req->def.dat.sz);
-			else printf(" with no default");
+		break;
+	case RQT_DATA:
+	case RQT_DATAV:
+	case RQT_DATAB:
+	case RQT_DATAM:
+		if (req->def.dat.has_size) {
+			printf(" data%s %zu", rft2str[req->def.rty], req->def.dat.sz);
+		} else {
+			printf(" unsized data%s", rft2str[req->def.rty]);
 		}
-		if (req->has_val) {
-			if (req->def.dat.has_size) printf(" with solved %zu", req->def.dat.sz);
-			else printf(" with no solved");
+		break;
+	}
+	if (req->has_val) {
+		printf(" => solved");
+		switch (req->val.rty) {
+		case RQT_FUN:
+		case RQT_FUN_2:
+		case RQT_FUN_MY:
+		case RQT_FUN_D:
+			if (req->val.fun.typ) {
+				printf(" function%s %s%s%s",
+					rft2str[req->val.rty],
+					string_content(req->val.fun.typ),
+					req->val.fun.fun2 ? " -> " : "",
+					req->val.fun.fun2 ? string_content(req->val.fun.fun2) : "");
+			} else {
+				printf(" untyped function%s", rft2str[req->val.rty]);
+			}
+			break;
+		case RQT_DATA:
+		case RQT_DATAV:
+		case RQT_DATAB:
+		case RQT_DATAM:
+			if (req->val.dat.has_size) {
+				printf(" data%s %zu", rft2str[req->val.rty], req->val.dat.sz);
+			} else {
+				printf(" unsized data%s", rft2str[req->val.rty]);
+			}
+			break;
 		}
 	}
 	printf("\n");
 }
-void request_print_check(request_t *req) {
-	if (req->has_default && req->has_val && (IS_RQT_FUNCTION(req->def.rty) != IS_RQT_FUNCTION(req->val.rty))) {
-		printf("%s => conflict: was/is data, is/was function\n", string_content(req->obj_name));
+void request_print_check(const request_t *req) {
+	if (req->ignored) {
+		return;
 	}
-	int is_fun;
-	if (req->has_default) is_fun = IS_RQT_FUNCTION(req->def.rty);
-	else if (req->has_val) is_fun = IS_RQT_FUNCTION(req->val.rty);
-	else {
-		printf(" => (no value)\n");
+	if (!req->has_val) {
+		// printf("%s: no value\n", string_content(req->obj_name));
 		return;
 	}
-	if (is_fun) {
-		if (req->has_val) {
-			if (req->has_default) {
-				int similar = 1;
-				// if (req->def.rty != req->val.rty) similar = 0;
-				if (similar && strcmp(string_content(req->def.fun.typ), string_content(req->val.fun.typ))) {
-					// similar = 0;
-					// TODO
-					if (req->def.rty == RQT_FUN_MY) {
-						similar =
-							string_len(req->def.fun.typ) >= 3 &&
-							string_content(req->def.fun.typ)[2] == 'E' &&
-							!strncmp(string_content(req->def.fun.typ), string_content(req->val.fun.typ), 2) &&
-							!strcmp(string_content(req->def.fun.typ) + 3, string_content(req->val.fun.typ) + 2);
-						if (similar) {
-							// We need to add the 'E' back here
-						}
-					} else {
-						similar = 0;
-					}
-				}
-				if (!similar) {
-					printf("%s => %sfunction with %sdefault %s%s%s%s and different solved %s%s%s%s\n",
-						string_content(req->obj_name),
-						req->weak ? "weak " : "",
-						req->default_comment ? "commented " : "",
-						rft2str[req->def.rty],
-						string_content(req->def.fun.typ),
-						(req->def.rty == RQT_FUN_2) ? " -> " : "",
-						(req->def.rty == RQT_FUN_2) ? string_content(req->def.fun.fun2) : "",
-						rft2str[req->val.rty],
-						string_content(req->val.fun.typ),
-						(req->val.rty == RQT_FUN_2) ? " -> " : "",
-						(req->val.rty == RQT_FUN_2) ? string_content(req->val.fun.fun2) : "");
-				}
-			} else {
-				printf("%s => %sfunction with solved %s%s%s%s\n",
-					string_content(req->obj_name),
-					req->weak ? "weak " : "",
-					rft2str[req->val.rty],
-					string_content(req->val.fun.typ),
-					(req->val.rty == RQT_FUN_2) ? " -> " : "",
-					(req->val.rty == RQT_FUN_2) ? string_content(req->val.fun.fun2) : "");
-			}
-		} else if (req->has_default) {
-			/* printf("%s => unsolved %sfunction with %sdefault %s%s%s%s\n",
+	if ((IS_RQT_FUNCTION(req->def.rty) != IS_RQT_FUNCTION(req->val.rty))) {
+		printf("%s: conflict: %s data, %s function\n",
+			string_content(req->obj_name),
+			IS_RQT_FUNCTION(req->def.rty) ? "is" : "was",
+			IS_RQT_FUNCTION(req->def.rty) ? "was" : "is");
+		return;
+	}
+	if (IS_RQT_FUNCTION(req->def.rty) && !req->def.fun.typ) return;       // No default (function)
+	if (!IS_RQT_FUNCTION(req->def.rty) && !req->def.dat.has_size) return; // No default (data)
+	// We have a default and a value, both are functions or data
+	int similar;
+	switch (req->def.rty) {
+	case RQT_FUN:
+	case RQT_FUN_2:
+	case RQT_FUN_MY:
+	case RQT_FUN_D:
+		similar = !req->default_comment || (req->val.rty != RQT_FUN); // From comment to no comment is dissimilar
+		if (similar && (req->def.rty != req->val.rty)) similar = 0;
+		if (similar && strcmp(string_content(req->def.fun.typ), string_content(req->val.fun.typ))) {
+			similar = 0;
+		}
+		if (!similar) {
+			printf("%s%s: function with %s%sdefault%s%s%s%s%s and dissimilar %ssolved%s%s%s%s%s\n",
 				string_content(req->obj_name),
-				req->weak ? "weak " : "",
+				req->weak ? " (weak)" : "",
 				req->default_comment ? "commented " : "",
+				req->def.fun.typ ? "" : "untyped ",
 				rft2str[req->def.rty],
+				req->def.fun.typ ? " " : "",
 				string_content(req->def.fun.typ),
-				(req->def.rty == RQT_FUN_2) ? " -> " : "",
-				(req->def.rty == RQT_FUN_2) ? string_content(req->def.fun.fun2) : ""); */
-		}
-	} else {
-		printf("%s => %sdata", string_content(req->obj_name), req->weak ? "weak " : "");
-		if (req->has_default) {
-			if (req->def.dat.has_size) printf(" with default %zu", req->def.dat.sz);
-			else printf(" with no default");
+				req->def.fun.fun2 ? " -> " : "",
+				req->def.fun.fun2 ? string_content(req->def.fun.fun2) : "",
+				req->val.fun.typ ? "" : "untyped ",
+				rft2str[req->val.rty],
+				req->val.fun.typ ? " " : "",
+				string_content(req->val.fun.typ),
+				req->val.fun.fun2 ? " -> " : "",
+				req->val.fun.fun2 ? string_content(req->val.fun.fun2) : "");
 		}
-		if (req->has_val) {
-			if (req->def.dat.has_size) printf(" with solved %zu", req->def.dat.sz);
-			else printf(" with no solved");
+		break;
+	case RQT_DATA:
+	case RQT_DATAV:
+	case RQT_DATAB:
+	case RQT_DATAM:
+		similar = 1;
+		if (similar && (req->def.rty != req->val.rty)) similar = 0;
+		if (similar && (!!req->def.dat.has_size != !!req->val.dat.has_size)) similar = 0;
+		if (similar && req->def.dat.has_size && (req->def.dat.sz != req->val.dat.sz)) similar = 0;
+		if (!similar) {
+			printf("%s%s: data with %s%sdefault%s",
+				string_content(req->obj_name),
+				req->weak ? " (weak)" : "",
+				req->default_comment ? "commented " : "",
+				req->def.fun.typ ? "" : "untyped ",
+				rft2str[req->def.rty]);
+			if (req->def.dat.has_size) {
+				printf(" %zu", req->def.dat.sz);
+			} else {
+				printf(" unsized");
+			}
+			printf(" and dissimilar %ssolved%s",
+				req->val.fun.typ ? "" : "untyped ",
+				rft2str[req->val.rty]);
+			if (req->val.dat.has_size) {
+				printf(" %zu", req->val.dat.sz);
+			} else {
+				printf(" unsized");
+			}
+			printf("\n");
 		}
+		break;
+	}
+}
+void references_print_check(const VECTOR(references) *refs) {
+	vector_for(references, ref, refs) {
+		if (ref->typ == REF_REQ) request_print_check(&ref->req);
 	}
 }
+
 static void request_del(request_t *req) {
 	string_del(req->obj_name);
-	if (req->has_default) {
-		switch (req->def.rty) {
-		case RQT_FUN:    string_del(req->def.fun.typ);                                break;
-		case RQT_FUN_2:  string_del(req->def.fun.typ); string_del(req->def.fun.fun2); break;
-		case RQT_FUN_MY: string_del(req->def.fun.typ);                                break;
-		case RQT_FUN_D:  string_del(req->def.fun.typ); string_del(req->def.fun.fun2); break;
-		case RQT_DATA:   break;
-		case RQT_DATAV:  break;
-		case RQT_DATAB:  break;
-		case RQT_DATAM:  break;
-		}
+	switch (req->def.rty) {
+	case RQT_FUN:    if (req->def.fun.typ) string_del(req->def.fun.typ);                                                       break;
+	case RQT_FUN_2:  if (req->def.fun.typ) string_del(req->def.fun.typ); if (req->def.fun.fun2) string_del(req->def.fun.fun2); break;
+	case RQT_FUN_MY: if (req->def.fun.typ) string_del(req->def.fun.typ);                                                       break;
+	case RQT_FUN_D:  if (req->def.fun.typ) string_del(req->def.fun.typ); if (req->def.fun.fun2) string_del(req->def.fun.fun2); break;
+	case RQT_DATA:   break;
+	case RQT_DATAV:  break;
+	case RQT_DATAB:  break;
+	case RQT_DATAM:  break;
 	}
 	if (req->has_val) {
 		switch (req->val.rty) {
@@ -169,8 +193,13 @@ static void reference_del(reference_t *ref) {
 		request_del(&ref->req);
 		break;
 	case REF_LINE:
+	case REF_IFDEF:
+	case REF_IFNDEF:
 		string_del(ref->line);
 		break;
+	case REF_ELSE:
+	case REF_ENDIF:
+		break;
 	}
 }
 
@@ -194,31 +223,33 @@ static const char *rqt_suffix[8] = {
 	[RQT_DATAM] = "M",
 };
 
-static void request_output(FILE *f, request_t *req) {
+static void request_output(FILE *f, const request_t *req) {
 	if (!req->has_val) {
-		if (!req->has_default) {
-			// printf("Warning: %s has no value and no default, assuming function\n", string_content(req->obj_name));
-			fprintf(f, "//GO%s(%s, \n", req->weak ? "W" : "", string_content(req->obj_name));
-		} else if (IS_RQT_FUNCTION(req->def.rty)) {
-			fprintf(f, "%sGO%s%s(%s, %s%s%s%s%s)%s\n",
-				req->default_comment ? "//" : "",
-				req->weak ? "W" : "",
-				rqt_suffix[req->def.rty],
-				string_content(req->obj_name),
-				valid_reqtype(req->def.fun.typ) ? "" : "\"",
-				string_content(req->def.fun.typ),
-				valid_reqtype(req->def.fun.typ) ? "" : "\"",
-				IS_RQT_FUN2(req->def.rty) ? ", " : "",
-				IS_RQT_FUN2(req->def.rty) ? string_content(req->def.fun.fun2) : "",
-				req->default_comment ? "" : " // Warning: failed to confirm");
+		if (IS_RQT_FUNCTION(req->def.rty)) {
+			if (!req->def.fun.typ) {
+				fprintf(f, "//GO%s%s(%s, \n", req->weak ? "W" : "", rqt_suffix[req->def.rty], string_content(req->obj_name));
+			} else {
+				fprintf(f, "%sGO%s%s(%s, %s%s%s%s%s)%s\n",
+					req->default_comment ? "//" : "",
+					req->weak ? "W" : "",
+					rqt_suffix[req->def.rty],
+					string_content(req->obj_name),
+					valid_reqtype(req->def.fun.typ) ? "" : "\"",
+					string_content(req->def.fun.typ),
+					valid_reqtype(req->def.fun.typ) ? "" : "\"",
+					IS_RQT_FUN2(req->def.rty) ? ", " : "",
+					IS_RQT_FUN2(req->def.rty) ? string_content(req->def.fun.fun2) : "",
+					(req->ignored || req->default_comment) ? "" : " // Warning: failed to confirm");
+			}
 		} else {
 			if (req->def.dat.has_size) {
-				fprintf(f, "%sDATA%s%s(%s, %zu) // Warning: failed to confirm\n",
+				fprintf(f, "%sDATA%s%s(%s, %zu)%s\n",
 					req->default_comment ? "//" : "",
 					req->weak ? "W" : "",
 					rqt_suffix[req->def.rty],
 					string_content(req->obj_name),
-					req->def.dat.sz);
+					req->def.dat.sz,
+					(req->ignored || req->default_comment) ? "" : " // Warning: failed to confirm");
 			} else {
 				fprintf(f, "//DATA%s%s(%s, \n",
 					req->weak ? "W" : "",
@@ -229,7 +260,8 @@ static void request_output(FILE *f, request_t *req) {
 	} else {
 		if (IS_RQT_FUNCTION(req->val.rty)) {
 			int is_comment =
-				(req->has_default && !req->default_comment) ? (req->val.rty != req->def.rty) : (req->val.rty != RQT_FUN);
+				(IS_RQT_FUNCTION(req->def.rty) && req->def.fun.typ && !req->default_comment)
+				  ? (req->val.rty != req->def.rty) : (req->val.rty != RQT_FUN);
 			fprintf(f, "%sGO%s%s(%s, %s%s%s)\n",
 				is_comment ? "//" : "",
 				req->weak ? "W" : "",
@@ -240,7 +272,7 @@ static void request_output(FILE *f, request_t *req) {
 				IS_RQT_FUN2(req->val.rty) ? req->val.fun.fun2 ? string_content(req->val.fun.fun2) : "<error: no val>" : "");
 		} else {
 			if (req->val.dat.has_size) {
-				int is_comment = !req->has_default || req->default_comment || (req->def.rty != req->val.rty);
+				int is_comment = IS_RQT_FUNCTION(req->def.rty) || !req->def.dat.has_size || req->default_comment || (req->def.rty != req->val.rty);
 				fprintf(f, "%sDATA%s(%s, %zu)\n",
 					is_comment ? "//" : "",
 					rqt_suffix[req->val.rty],
@@ -254,7 +286,7 @@ static void request_output(FILE *f, request_t *req) {
 		}
 	}
 }
-static void reference_output(FILE *f, reference_t *ref) {
+static void reference_output(FILE *f, const reference_t *ref) {
 	switch (ref->typ) {
 	case REF_REQ:
 		request_output(f, &ref->req);
@@ -263,12 +295,24 @@ static void reference_output(FILE *f, reference_t *ref) {
 		fputs(string_content(ref->line), f);
 		fputc('\n', f);
 		break;
+	case REF_IFDEF:
+		fprintf(f, "#ifdef %s\n", string_content(ref->line));
+		break;
+	case REF_IFNDEF:
+		fprintf(f, "#ifndef %s\n", string_content(ref->line));
+		break;
+	case REF_ELSE:
+		fputs("#else\n", f);
+		break;
+	case REF_ENDIF:
+		fputs("#endif\n", f);
+		break;
 	}
 }
-void output_from_references(FILE *f, VECTOR(references) *reqs) {
-	fprintf(f, "#if !(defined(GO) && defined(GOM) && defined(GO2) && defined(DATA))\n#error Meh...\n#endif\n\n");
-	vector_for(references, req, reqs) {
-		reference_output(f, req);
+void output_from_references(FILE *f, const VECTOR(references) *refs) {
+	fprintf(f, "#if !(defined(GO) && defined(GOM) && defined(GO2) && defined(DATA))\n#error Meh...\n#endif\n");
+	vector_for(references, ref, refs) {
+		reference_output(f, ref);
 	}
 }
 
@@ -350,14 +394,13 @@ VECTOR(references) *references_from_file(const char *filename, FILE *f) {
 			}
 		}
 		if ((tok.tokt == PPTOK_SYM) && (tok.tokv.sym == SYM_HASH)) {
-			ADD_CHAR('#', 0, "start of preprocessor command")
+			string_clear(line);
 			tok = pre_next_token(prep, 0);
 			if (tok.tokt != PPTOK_IDENT) {
 				printf("Error: invalid reference file: invalid preprocessor line\n");
 				preproc_token_del(&tok);
 				goto failed;
 			}
-			ADD_STR(tok.tokv.str, 1, "preprocessor command")
 			if (!strcmp(string_content(tok.tokv.str), "ifdef")) {
 				string_del(tok.tokv.str);
 				tok = pre_next_token(prep, 0);
@@ -366,10 +409,12 @@ VECTOR(references) *references_from_file(const char *filename, FILE *f) {
 					preproc_token_del(&tok);
 					goto failed;
 				}
-				ADD_CHAR(' ', 1, "preprocessor command")
-				ADD_STR(tok.tokv.str, 1, "preprocessor command")
 				++if_depth;
-				string_del(tok.tokv.str);
+				if (!vector_push(references, ret, ((reference_t){.typ = REF_IFDEF, .line = tok.tokv.str}))) {
+					printf("Error: failed to memorize reference line %d\n", lineno);
+					string_del(tok.tokv.str);
+					goto failed;
+				}
 				tok = pre_next_token(prep, 0);
 			} else if (!strcmp(string_content(tok.tokv.str), "ifndef")) {
 				string_del(tok.tokv.str);
@@ -379,22 +424,32 @@ VECTOR(references) *references_from_file(const char *filename, FILE *f) {
 					preproc_token_del(&tok);
 					goto failed;
 				}
-				ADD_CHAR(' ', 1, "preprocessor command")
-				ADD_STR(tok.tokv.str, 1, "preprocessor command")
 				if (if_depth == entered_depth) ++entered_depth;
 				++if_depth;
-				string_del(tok.tokv.str);
+				if (!vector_push(references, ret, ((reference_t){.typ = REF_IFNDEF, .line = tok.tokv.str}))) {
+					printf("Error: failed to memorize reference line %d\n", lineno);
+					string_del(tok.tokv.str);
+					goto failed;
+				}
 				tok = pre_next_token(prep, 0);
 			} else if (!strcmp(string_content(tok.tokv.str), "else")) {
 				string_del(tok.tokv.str);
 				tok = pre_next_token(prep, 0);
 				if (if_depth == entered_depth + 1) ++entered_depth;
 				else if (if_depth == entered_depth) --entered_depth;
+				if (!vector_push(references, ret, ((reference_t){.typ = REF_ELSE}))) {
+					printf("Error: failed to memorize reference line %d\n", lineno);
+					goto failed;
+				}
 			} else if (!strcmp(string_content(tok.tokv.str), "endif")) {
 				string_del(tok.tokv.str);
 				tok = pre_next_token(prep, 0);
 				if (if_depth == entered_depth) --entered_depth;
 				--if_depth;
+				if (!vector_push(references, ret, ((reference_t){.typ = REF_ENDIF}))) {
+					printf("Error: failed to memorize reference line %d\n", lineno);
+					goto failed;
+				}
 			} else {
 				printf("Error: invalid reference file: invalid preprocessor command '%s'\n", string_content(tok.tokv.str));
 				string_del(tok.tokv.str);
@@ -404,7 +459,6 @@ VECTOR(references) *references_from_file(const char *filename, FILE *f) {
 				preproc_token_del(&tok);
 				tok = pre_next_token(prep, 0);
 			}
-			PUSH_LINE(0)
 			++lineno;
 			if (preproc_token_isend(&tok)) {
 				if (tok.tokt == PPTOK_EOF) goto success;
@@ -431,9 +485,9 @@ VECTOR(references) *references_from_file(const char *filename, FILE *f) {
 			if (is_comment) prepare_mark_nocomment(prep);
 			int isweak = (string_content(tok.tokv.str)[2] == 'W');
 			request_t req = {
-				.has_default = 0,
 				.default_comment = is_comment,
 				.has_val = 0,
+				.ignored = 0,
 				.obj_name = NULL,
 				.weak = isweak,
 				.def = {
@@ -472,7 +526,6 @@ VECTOR(references) *references_from_file(const char *filename, FILE *f) {
 			tok = pre_next_token(prep, 0);
 			if ((tok.tokt == PPTOK_IDENT) || (tok.tokt == PPTOK_STRING)) {
 				req.def.fun.typ = (tok.tokt == PPTOK_STRING) ? tok.tokv.sstr : tok.tokv.str;
-				req.has_default = 1;
 				// Token moved
 				tok = pre_next_token(prep, 0);
 				if ((req.def.rty == RQT_FUN_2) || (req.def.rty == RQT_FUN_D)) {
@@ -515,17 +568,13 @@ VECTOR(references) *references_from_file(const char *filename, FILE *f) {
 				preproc_token_del(&tok);
 				goto failed;
 			}
-			if (if_depth == entered_depth) {
-				if (!vector_push(references, ret, ((reference_t){.typ = REF_REQ, .req = req}))) {
-					printf("Error: failed to add reference for %s\n", string_content(req.obj_name));
-					string_del(req.obj_name);
-					if (req.def.fun.typ) string_del(req.def.fun.typ);
-					if (req.def.fun.fun2) string_del(req.def.fun.fun2);
-					// Empty destructor
-					goto failed;
-				}
-			} else {
-				request_del(&req);
+			if (!vector_push(references, ret, ((reference_t){.typ = REF_REQ, .req = req}))) {
+				printf("Error: failed to add reference for %s\n", string_content(req.obj_name));
+				string_del(req.obj_name);
+				if (req.def.fun.typ) string_del(req.def.fun.typ);
+				if (req.def.fun.fun2) string_del(req.def.fun.fun2);
+				// Empty destructor
+				goto failed;
 			}
 			++lineno;
 		} else if ((tok.tokt == PPTOK_IDENT)
@@ -536,9 +585,9 @@ VECTOR(references) *references_from_file(const char *filename, FILE *f) {
 			string_clear(line);
 			if (is_comment) prepare_mark_nocomment(prep);
 			request_t req = {
-				.has_default = 1,
 				.default_comment = is_comment,
 				.has_val = 0,
+				.ignored = 0,
 				.obj_name = NULL,
 				.weak = (string_content(tok.tokv.str)[4] == 'V'),
 				.def = {
@@ -614,15 +663,11 @@ VECTOR(references) *references_from_file(const char *filename, FILE *f) {
 				preproc_token_del(&tok);
 				goto failed;
 			}
-			if (if_depth == entered_depth) {
-				if (!vector_push(references, ret, ((reference_t){.typ = REF_REQ, .req = req}))) {
-					printf("Error: failed to add reference for %s\n", string_content(req.obj_name));
-					request_del(&req);
-					// Empty destructor
-					goto failed;
-				}
-			} else {
+			if (!vector_push(references, ret, ((reference_t){.typ = REF_REQ, .req = req}))) {
+				printf("Error: failed to add reference for %s\n", string_content(req.obj_name));
 				request_del(&req);
+				// Empty destructor
+				goto failed;
 			}
 			++lineno;
 		} else if (is_comment) {
@@ -663,6 +708,10 @@ success:
 }
 
 static int is_simple_type_ptr_to(type_t *typ, int *needs_D, int *needs_my) {
+	if (typ->converted) {
+		// printf("Warning: %s uses a converted type but is not the converted type\n", string_content(obj_name));
+		*needs_my = 1;
+	}
 	switch (typ->typ) {
 	case TYPE_BUILTIN:
 		return 1; // Assume pointers to builtin are simple
@@ -670,7 +719,6 @@ static int is_simple_type_ptr_to(type_t *typ, int *needs_D, int *needs_my) {
 		if (typ->val.array.array_sz == (size_t)-1) return 0; // VLA are not simple
 		return is_simple_type_ptr_to(typ->val.array.typ, needs_D, needs_my);
 	case TYPE_STRUCT_UNION:
-		if (typ->val.st->explicit_simple) return 1;
 		if (typ->_internal_use) return 1; // Recursive structures are OK as long as every other members are OK
 		if (!typ->val.st->is_defined) return 1; // Undefined structures are OK since they are opaque
 		typ->_internal_use = 1;
@@ -696,6 +744,10 @@ static int is_simple_type_ptr_to(type_t *typ, int *needs_D, int *needs_my) {
 	}
 }
 static int is_simple_type(type_t *typ, int *needs_D, int *needs_my) {
+	if (typ->converted) {
+		// printf("Warning: %s uses a converted type but is not the converted type\n", string_content(obj_name));
+		*needs_my = 1;
+	}
 	switch (typ->typ) {
 	case TYPE_BUILTIN:
 		return 1; // Assume pointers to builtin are simple
@@ -703,7 +755,6 @@ static int is_simple_type(type_t *typ, int *needs_D, int *needs_my) {
 		if (typ->val.array.array_sz == (size_t)-1) return 0; // VLA are not simple
 		return is_simple_type_ptr_to(typ->val.array.typ, needs_D, needs_my);
 	case TYPE_STRUCT_UNION:
-		if (typ->val.st->explicit_simple) return 1;
 		if (typ->_internal_use) return 1; // Recursive structures are OK as long as every other members are OK
 		// if (!typ->val.st->is_defined) return 1; // Undefined structures are OK since they are opaque
 		// To be safe, don't allow opaque structures
@@ -732,6 +783,13 @@ static int is_simple_type(type_t *typ, int *needs_D, int *needs_my) {
 }
 
 static int convert_type(string_t *dest, type_t *typ, int is_ret, int *needs_D, int *needs_my, string_t *obj_name) {
+	if (typ->converted) {
+		if (!string_add_string(dest, typ->converted)) {
+			printf("Error: failed to add explicit type char\n");
+			return 0;
+		}
+		return 1;
+	}
 	if (typ->is_atomic) {
 		printf("TODO: convert_type for atomic types\n");
 		return 0;
@@ -831,13 +889,6 @@ static int convert_type(string_t *dest, type_t *typ, int is_ret, int *needs_D, i
 	case TYPE_ENUM:
 		return convert_type(dest, typ->val.typ, is_ret, needs_D, needs_my, obj_name);
 	case TYPE_PTR:
-		if ((typ->val.typ->typ == TYPE_STRUCT_UNION) && typ->val.typ->val.st->tag && !strcmp(string_content(typ->val.typ->val.st->tag), "_IO_FILE")) {
-			if (!string_add_char(dest, 'S')) {
-				printf("Error: failed to add type char for %s\n", builtin2str[typ->val.builtin]);
-				return 0;
-			}
-			return 1;
-		}
 		if (is_simple_type_ptr_to(typ->val.typ, needs_D, needs_my)) {
 			if (!string_add_char(dest, 'p')) {
 				printf("Error: failed to add type char for simple pointer\n");
@@ -861,6 +912,7 @@ static int convert_type(string_t *dest, type_t *typ, int is_ret, int *needs_D, i
 	}
 }
 static int convert_type_post(string_t *dest, type_t *typ, string_t *obj_name) {
+	if (typ->converted) return 1;
 	if (typ->is_atomic) {
 		printf("TODO: convert_type_post for atomic types\n");
 		return 0;
@@ -893,7 +945,7 @@ static int convert_type_post(string_t *dest, type_t *typ, string_t *obj_name) {
 
 int solve_request(request_t *req, type_t *typ) {
 	if (typ->typ == TYPE_FUNCTION) {
-		int needs_D = 0, needs_my = req->has_default && (req->def.rty == RQT_FUN_MY), needs_2 = 0;
+		int needs_D = 0, needs_my = req->def.fun.typ && (req->def.rty == RQT_FUN_MY), needs_2 = 0;
 		int convert_post;
 		req->val.fun.typ = string_new();
 		if (!req->val.fun.typ) {
@@ -905,7 +957,7 @@ int solve_request(request_t *req, type_t *typ) {
 			printf("Error: failed to add convention char\n");
 			goto fun_fail;
 		}
-		if (req->has_default && (req->def.rty == RQT_FUN_MY) && (string_content(req->def.fun.typ)[2] == 'E')) {
+		if (req->def.fun.typ && (req->def.rty == RQT_FUN_MY) && (string_content(req->def.fun.typ)[2] == 'E')) {
 			if (!string_add_char(req->val.fun.typ, 'E')) {
 				printf("Error: failed to add emu char\n");
 				goto fun_fail;
@@ -933,23 +985,36 @@ int solve_request(request_t *req, type_t *typ) {
 				if (!convert_type(req->val.fun.typ, typ->val.fun.args[i], 0, &needs_D, &needs_my, req->obj_name)) goto fun_fail;
 			}
 			if (typ->val.fun.has_varargs) {
-				needs_my = 1;
-				if (!string_add_char(req->val.fun.typ, 'V')) {
-					printf("Error: failed to add type char for %s\n", builtin2str[typ->val.builtin]);
-					goto fun_fail;
+				if (req->def.fun.typ
+				      && (string_len(req->def.fun.typ) == string_len(req->val.fun.typ) + 1)
+				      && !strncmp(string_content(req->def.fun.typ), string_content(req->val.fun.typ), string_len(req->val.fun.typ))
+				      && ((string_content(req->def.fun.typ)[string_len(req->val.fun.typ)] == 'M')
+				       || (string_content(req->def.fun.typ)[string_len(req->val.fun.typ)] == 'N'))) {
+					if (!string_add_char(req->val.fun.typ, string_content(req->def.fun.typ)[string_len(req->val.fun.typ)])) {
+						printf("Error: failed to add type char '%c' for %s\n",
+							string_content(req->def.fun.typ)[string_len(req->val.fun.typ)],
+							builtin2str[typ->val.builtin]);
+						goto fun_fail;
+					}
+				} else {
+					needs_my = 1;
+					if (!string_add_char(req->val.fun.typ, 'V')) {
+						printf("Error: failed to add type char 'V' for %s\n", builtin2str[typ->val.builtin]);
+						goto fun_fail;
+					}
 				}
 			}
 		}
 		
 	// fun_succ:
-		if (req->has_default && (req->def.rty == RQT_FUN_2) && !needs_my) {
+		if (req->def.fun.typ && (req->def.rty == RQT_FUN_2) && !needs_my) {
 			needs_2 = 1;
 			req->val.fun.fun2 = string_dup(req->def.fun.fun2);
 			if (!req->val.fun.fun2) {
 				printf("Error: failed to duplicate string (request for function %s with default redirection)\n", string_content(req->obj_name));
 				return 0;
 			}
-		} else if (req->has_default && (req->def.rty == RQT_FUN_D) && !needs_my) {
+		} else if (req->def.fun.typ && (req->def.rty == RQT_FUN_D) && !needs_my) {
 			needs_2 = 0;
 			req->val.fun.fun2 = string_dup(req->def.fun.fun2);
 			if (!req->val.fun.fun2) {
@@ -974,10 +1039,10 @@ int solve_request(request_t *req, type_t *typ) {
 		string_del(req->val.fun.typ);
 		return 0;
 	} else {
-		int needs_D = 0, needs_my = req->has_default && (req->def.rty == RQT_FUN_MY);
+		int needs_D = 0, needs_my = req->def.dat.has_size && (req->def.rty == RQT_DATAM);
 		if (is_simple_type(typ, &needs_D, &needs_my)) {
 			// TODO: Hmm...
-			req->val.rty = needs_my ? RQT_DATAM : req->has_default ? req->def.rty : req->weak ? RQT_DATAV : RQT_DATA;
+			req->val.rty = needs_my ? RQT_DATAM : req->def.dat.has_size ? req->def.rty : req->weak ? RQT_DATAV : RQT_DATA;
 			req->val.dat.has_size = 1;
 			req->val.dat.sz = typ->szinfo.size;
 			req->has_val = 1;
@@ -1002,9 +1067,34 @@ int solve_request_map(request_t *req, khash_t(type_map) *decl_map) {
 }
 int solve_references(VECTOR(references) *refs, khash_t(type_map) *decl_map) {
 	int ret = 1;
+	int cond_depth = 0, ok_depth = 0;
 	vector_for(references, ref, refs) {
-		if (ref->typ != REF_REQ) continue;
-		if (!solve_request_map(&ref->req, decl_map)) ret = 0;
+		switch (ref->typ) {
+		case REF_REQ:
+			if (ok_depth == cond_depth) {
+				if (!solve_request_map(&ref->req, decl_map)) ret = 0;
+			} else {
+				ref->req.ignored = 1;
+			}
+			break;
+		case REF_LINE:
+			break;
+		case REF_IFDEF:
+			++cond_depth;
+			break;
+		case REF_IFNDEF:
+			if (cond_depth == ok_depth) ++ok_depth;
+			++cond_depth;
+			break;
+		case REF_ELSE:
+			if (cond_depth == ok_depth) --ok_depth;
+			else if (cond_depth == ok_depth + 1) ++ok_depth;
+			break;
+		case REF_ENDIF:
+			if (cond_depth == ok_depth) --ok_depth;
+			--cond_depth;
+			break;
+		}
 	}
 	return ret;
 }