about summary refs log tree commit diff stats
path: root/wrapperhelper/src
diff options
context:
space:
mode:
authorrajdakin <rajdakin@gmail.com>2024-10-29 16:31:05 +0100
committerGitHub <noreply@github.com>2024-10-29 16:31:05 +0100
commit70a6d9674876c4622b42b8913a9ee910a9e65c12 (patch)
treee4cf7ac9693936394357a33de69ad75d1ded9e9e /wrapperhelper/src
parent4a440b6f0ab7cf63ed8f19783579e037a9e5be5f (diff)
downloadbox64-70a6d9674876c4622b42b8913a9ee910a9e65c12.tar.gz
box64-70a6d9674876c4622b42b8913a9ee910a9e65c12.zip
[WRAPPERHELPER] Added pragma once support, fixed a preprocessor bug, fixed the wrapperhelper Makefile (#1977)
Diffstat (limited to 'wrapperhelper/src')
-rw-r--r--wrapperhelper/src/generator.c33
-rw-r--r--wrapperhelper/src/main.c15
-rw-r--r--wrapperhelper/src/prepare.c46
-rw-r--r--wrapperhelper/src/prepare.h2
-rw-r--r--wrapperhelper/src/preproc.c133
-rw-r--r--wrapperhelper/src/vector.c1
-rw-r--r--wrapperhelper/src/vector.h1
7 files changed, 169 insertions, 62 deletions
diff --git a/wrapperhelper/src/generator.c b/wrapperhelper/src/generator.c
index a4762c5e..8061ba88 100644
--- a/wrapperhelper/src/generator.c
+++ b/wrapperhelper/src/generator.c
@@ -1399,7 +1399,7 @@ static enum safeness_e get_safeness(type_t *emu_typ, type_t *target_typ, int *ne
 }
 
 // needs_S != NULL iff type is return
-static int convert_type(string_t *dest, type_t *emu_typ, type_t *target_typ,
+static int convert_type(string_t *dest, type_t *emu_typ, type_t *target_typ, int allow_nesting,
                         _Bool *needs_S, int *needs_D, int *needs_my, khash_t(conv_map) *conv_map, string_t *obj_name) {
 	if (emu_typ->converted) {
 		if (!string_add_string(dest, emu_typ->converted)) {
@@ -1499,7 +1499,7 @@ static int convert_type(string_t *dest, type_t *emu_typ, type_t *target_typ,
 			return 1;
 		}
 		size_t idx = string_len(dest);
-		if (!convert_type(dest, emu_typ->val.array.typ, target_typ->val.array.typ, needs_S, needs_D, needs_my, conv_map, obj_name))
+		if (!convert_type(dest, emu_typ->val.array.typ, target_typ->val.array.typ, allow_nesting, needs_S, needs_D, needs_my, conv_map, obj_name))
 			return 0;
 		size_t end = string_len(dest);
 		if (idx == end) return 1;
@@ -1530,13 +1530,13 @@ static int convert_type(string_t *dest, type_t *emu_typ, type_t *target_typ,
 			return 1;
 		} else {
 			if ((emu_typ->val.st->nmembers == 1) && (target_typ->typ == TYPE_STRUCT_UNION) && (target_typ->val.st->nmembers == 1)) {
-				return convert_type(dest, emu_typ->val.st->members[0].typ, target_typ->val.st->members[0].typ, needs_S, needs_D, needs_my, conv_map, obj_name);
+				return convert_type(dest, emu_typ->val.st->members[0].typ, target_typ->val.st->members[0].typ, allow_nesting, needs_S, needs_D, needs_my, conv_map, obj_name);
 			}
 			printf("Error: TODO: convert_type on structure as argument (%s)\n", string_content(obj_name));
 			return 0;
 		}
 	case TYPE_ENUM:
-		return convert_type(dest, emu_typ->val.typ, target_typ->val.typ, needs_S, needs_D, needs_my, conv_map, obj_name);
+		return convert_type(dest, emu_typ->val.typ, target_typ->val.typ, allow_nesting, needs_S, needs_D, needs_my, conv_map, obj_name);
 	case TYPE_PTR:
 		switch (get_safeness_ptr(emu_typ->val.typ, target_typ->val.typ, needs_D, needs_my, conv_map, obj_name)) {
 		default:
@@ -1554,6 +1554,15 @@ static int convert_type(string_t *dest, type_t *emu_typ, type_t *target_typ,
 			return 1;
 			
 		case SAFE_EXPAND:
+			if (!allow_nesting) {
+				// TODO remove this with a better rebuild_wrappers.py
+				*needs_my = 1;
+				if (!string_add_char(dest, 'p')) {
+					printf("Error: failed to add type char for simple pointer\n");
+					return 0;
+				}
+				return 1;
+			}
 			if (!string_add_char(dest, emu_typ->is_const ? 'r' : 'b')) {
 				printf("Error: failed to add start type char for wrapping pointer\n");
 				return 0;
@@ -1564,12 +1573,12 @@ static int convert_type(string_t *dest, type_t *emu_typ, type_t *target_typ,
 		do_expanded:
 			switch (emu_typ->typ) {
 			case TYPE_BUILTIN:
-				if (!convert_type(dest, emu_typ, target_typ, needs_S, needs_D, needs_my, conv_map, obj_name)) {
+				if (!convert_type(dest, emu_typ, target_typ, 0, needs_S, needs_D, needs_my, conv_map, obj_name)) {
 					return 0;
 				}
 				break;
 			case TYPE_ARRAY:
-				if (!convert_type(dest, emu_typ, target_typ, needs_S, needs_D, needs_my, conv_map, obj_name)) {
+				if (!convert_type(dest, emu_typ, target_typ, 0, needs_S, needs_D, needs_my, conv_map, obj_name)) {
 					return 0;
 				}
 				break;
@@ -1584,7 +1593,7 @@ static int convert_type(string_t *dest, type_t *emu_typ, type_t *target_typ,
 					goto do_expanded;
 				}
 				for (size_t i = 0; i < emu_typ->val.st->nmembers; ++i) {
-					if (!convert_type(dest, emu_typ->val.st->members[i].typ, target_typ->val.st->members[i].typ, needs_S, needs_D, needs_my, conv_map, obj_name)) {
+					if (!convert_type(dest, emu_typ->val.st->members[i].typ, target_typ->val.st->members[i].typ, 0, needs_S, needs_D, needs_my, conv_map, obj_name)) {
 						return 0;
 					}
 				}
@@ -1592,17 +1601,17 @@ static int convert_type(string_t *dest, type_t *emu_typ, type_t *target_typ,
 			case TYPE_ENUM:
 				emu_typ = emu_typ->val.typ;
 				target_typ = target_typ->val.typ;
-				if (!convert_type(dest, emu_typ, target_typ, needs_S, needs_D, needs_my, conv_map, obj_name)) {
+				if (!convert_type(dest, emu_typ, target_typ, 0, needs_S, needs_D, needs_my, conv_map, obj_name)) {
 					return 0;
 				}
 				break;
 			case TYPE_PTR:
-				if (!convert_type(dest, emu_typ, target_typ, needs_S, needs_D, needs_my, conv_map, obj_name)) {
+				if (!convert_type(dest, emu_typ, target_typ, 0, needs_S, needs_D, needs_my, conv_map, obj_name)) {
 					return 0;
 				}
 				break;
 			case TYPE_FUNCTION:
-				if (!convert_type(dest, emu_typ, target_typ, needs_S, needs_D, needs_my, conv_map, obj_name)) {
+				if (!convert_type(dest, emu_typ, target_typ, 0, needs_S, needs_D, needs_my, conv_map, obj_name)) {
 					return 0;
 				}
 				break;
@@ -1666,7 +1675,7 @@ int solve_request(request_t *req, type_t *emu_typ, type_t *target_typ, khash_t(c
 			printf("Error: failed to create function type string\n");
 			return 0;
 		}
-		if (!convert_type(req->val.fun.typ, emu_typ->val.fun.ret, target_typ->val.fun.ret, &req->val.fun.needs_S, &needs_D, &needs_my, conv_map, req->obj_name))
+		if (!convert_type(req->val.fun.typ, emu_typ->val.fun.ret, target_typ->val.fun.ret, 0, &req->val.fun.needs_S, &needs_D, &needs_my, conv_map, req->obj_name))
 			goto fun_fail;
 		idx_conv = string_len(req->val.fun.typ);
 		if (!string_add_char(req->val.fun.typ, 'F')) {
@@ -1692,7 +1701,7 @@ int solve_request(request_t *req, type_t *emu_typ, type_t *target_typ, khash_t(c
 			}
 		} else {
 			for (size_t i = 0; i < emu_typ->val.fun.nargs; ++i) {
-				if (!convert_type(req->val.fun.typ, emu_typ->val.fun.args[i], target_typ->val.fun.args[i], NULL, &needs_D, &needs_my, conv_map, req->obj_name))
+				if (!convert_type(req->val.fun.typ, emu_typ->val.fun.args[i], target_typ->val.fun.args[i], 1, NULL, &needs_D, &needs_my, conv_map, req->obj_name))
 					goto fun_fail;
 			}
 			if (emu_typ->val.fun.has_varargs) {
diff --git a/wrapperhelper/src/main.c b/wrapperhelper/src/main.c
index 14a67ce6..f3938904 100644
--- a/wrapperhelper/src/main.c
+++ b/wrapperhelper/src/main.c
@@ -8,6 +8,7 @@
 #include "lang.h"
 #include "machine.h"
 #include "parse.h"
+#include "prepare.h"
 #include "khash.h"
 
 static void help(char *arg0) {
@@ -237,6 +238,7 @@ int main(int argc, char **argv) {
 			log_error_nopos("failed to parse the file\n");
 			del_machines();
 			del_str2kw();
+			prepare_cleanup();
 			return 0;
 		}
 		
@@ -246,6 +248,7 @@ int main(int argc, char **argv) {
 			file_del(emu_content);
 			del_machines();
 			del_str2kw();
+			prepare_cleanup();
 			return 2;
 		}
 		file_t *target_content = parse_file(target, in_file, f); // Takes ownership of f
@@ -254,6 +257,7 @@ int main(int argc, char **argv) {
 			file_del(emu_content);
 			del_machines();
 			del_str2kw();
+			prepare_cleanup();
 			return 0;
 		}
 		
@@ -264,6 +268,7 @@ int main(int argc, char **argv) {
 			file_del(target_content);
 			del_machines();
 			del_str2kw();
+			prepare_cleanup();
 			return 2;
 		}
 		VECTOR(references) *refs = references_from_file(ref_file, ref);
@@ -272,6 +277,7 @@ int main(int argc, char **argv) {
 			file_del(target_content);
 			del_machines();
 			del_str2kw();
+			prepare_cleanup();
 			return 2;
 		}
 		// vector_for(references, req, refs) request_print(req);
@@ -294,6 +300,7 @@ int main(int argc, char **argv) {
 			vector_del(references, refs);
 			del_machines();
 			del_str2kw();
+			prepare_cleanup();
 			return 2;
 		}
 		output_from_references(out, refs);
@@ -303,6 +310,7 @@ int main(int argc, char **argv) {
 		file_del(target_content);
 		del_machines();
 		del_str2kw();
+		prepare_cleanup();
 		return 0; }
 		
 	case MAIN_PROC: {
@@ -315,6 +323,7 @@ int main(int argc, char **argv) {
 			log_error_nopos("failed to parse the file\n");
 			del_machines();
 			del_str2kw();
+			prepare_cleanup();
 			return 0;
 		}
 		// print content
@@ -373,6 +382,7 @@ int main(int argc, char **argv) {
 		file_del(content);
 		del_machines();
 		del_str2kw();
+		prepare_cleanup();
 		return 0; }
 		
 	case MAIN_PREPARE:
@@ -380,6 +390,7 @@ int main(int argc, char **argv) {
 		dump_prepare(in_file, f); // Takes ownership of f
 		del_machines();
 		del_str2kw();
+		prepare_cleanup();
 		return 0;
 		
 	case MAIN_PREPROC: {
@@ -390,9 +401,13 @@ int main(int argc, char **argv) {
 		dump_preproc(arch, in_file, f); // Takes ownership of f
 		del_machines();
 		del_str2kw();
+		prepare_cleanup();
 		return 0; }
 	}
 	
 	log_internal_nopos("failed to run mode %u\n", ms);
+	del_machines();
+	del_str2kw();
+	prepare_cleanup();
 	return 2;
 }
diff --git a/wrapperhelper/src/prepare.c b/wrapperhelper/src/prepare.c
index ff19a067..464b7937 100644
--- a/wrapperhelper/src/prepare.c
+++ b/wrapperhelper/src/prepare.c
@@ -2,6 +2,13 @@
 
 #include <string.h>
 
+#include "log.h"
+
+static struct li_filename_s {
+	char *name;
+	struct li_filename_s *next;
+} *li_filenames = NULL;
+
 typedef struct char_s {
 	int c;
 	loginfo_t li;
@@ -32,12 +39,21 @@ prepare_t *prepare_new_file(FILE *f, const char *filename) {
 		return NULL;
 	}
 	
-	char *srcn = strdup(filename);
+	char *srcn = strdup(filename ? filename : "<unknown filename>");
 	if (!srcn) {
 		log_memory("failed to duplicate filename\n");
 		free(ret);
 		return NULL;
 	}
+	struct li_filename_s *new_lifn = malloc(sizeof *new_lifn);
+	if (!new_lifn) {
+		log_memory("failed to remember new filename\n");
+		free(srcn);
+		free(ret);
+		return NULL;
+	}
+	*new_lifn = (struct li_filename_s){ .name = srcn, .next = li_filenames };
+	li_filenames = new_lifn;
 	
 	*ret = (prepare_t){
 		.f = f,
@@ -52,7 +68,6 @@ prepare_t *prepare_new_file(FILE *f, const char *filename) {
 
 void prepare_del(prepare_t *prep) {
 	if (prep->f) fclose(prep->f);
-	if (prep->srcn) free(prep->srcn);
 	free(prep);
 }
 
@@ -504,9 +519,21 @@ start_next_token:
 
 void prepare_set_line(prepare_t *src, char *filename, size_t lineno) {
 	if (filename) {
-		if (src->srcn) free(filename);
-		src->srcn = filename;
-		src->li.filename = filename;
+		char *srcn = strdup(filename ? filename : "<unknown filename>");
+		if (!srcn) {
+			log_memory("failed to duplicate filename from #line command\n");
+			return;
+		}
+		struct li_filename_s *new_lifn = malloc(sizeof *new_lifn);
+		if (!new_lifn) {
+			log_memory("failed to remember new filename from #line command\n");
+			free(srcn);
+			return;
+		}
+		*new_lifn = (struct li_filename_s){ .name = srcn, .next = li_filenames };
+		li_filenames = new_lifn;
+		src->srcn = srcn;
+		src->li.filename = srcn;
 	}
 	size_t colno = 1;
 	for (int i = src->buf_len; i--; ) {
@@ -545,3 +572,12 @@ int pre_next_newline_token(prepare_t *src, string_t *buf) {
 		}
 	}
 }
+
+void prepare_cleanup(void) {
+	while (li_filenames) {
+		struct li_filename_s *lifn = li_filenames->next;
+		free(li_filenames->name);
+		free(li_filenames);
+		li_filenames = lifn;
+	}
+}
diff --git a/wrapperhelper/src/prepare.h b/wrapperhelper/src/prepare.h
index 9192fc78..bcf4e782 100644
--- a/wrapperhelper/src/prepare.h
+++ b/wrapperhelper/src/prepare.h
@@ -19,4 +19,6 @@ void prepare_set_line(prepare_t *src, char *filename, size_t lineno); // Takes o
 void prepare_mark_nocomment(prepare_t *src); // Change the state (usually from COMMENT) to NONE
 int pre_next_newline_token(prepare_t *src, string_t *buf); // In a comment append everything until the EOL or EOF to the buffer
 
+void prepare_cleanup(void); // Frees loginfo filenames
+
 #endif // PREPARE_H
diff --git a/wrapperhelper/src/preproc.c b/wrapperhelper/src/preproc.c
index 10ac978b..fe93ace0 100644
--- a/wrapperhelper/src/preproc.c
+++ b/wrapperhelper/src/preproc.c
@@ -203,6 +203,7 @@ VECTOR_IMPL_STATIC(ppsource, ppsource_del)
 struct preproc_s {
 	machine_t *target;
 	VECTOR(ppsource) *prep;
+	VECTOR(ccharp) *pragma_once;
 	enum preproc_state_e {
 		PPST_NONE,
 		PPST_NL,
@@ -223,6 +224,7 @@ void preproc_del(preproc_t *src) {
 	macros_map_del(src->macros_map);
 	if (src->dirname) free(src->dirname);
 	if (src->cur_file) free(src->cur_file);
+	vector_del(ccharp, src->pragma_once);
 	free(src);
 }
 
@@ -350,6 +352,16 @@ preproc_t *preproc_new_file(machine_t *target, FILE *f, char *dirname, const cha
 		free(ret);
 		return NULL;
 	}
+	ret->pragma_once = vector_new(ccharp);
+	if (!ret->pragma_once) {
+		vector_del(ppsource, ret->prep);
+		kh_destroy(macros_map, ret->macros_map);
+		kh_destroy(string_set, ret->macros_defined);
+		kh_destroy(string_set, ret->macros_used);
+		fclose(f);
+		free(ret);
+		return NULL;
+	}
 	ret->dirname = NULL;
 	ret->cur_file = NULL;
 	// ret can now be deleted by preproc_del
@@ -534,45 +546,47 @@ static VECTOR(preproc) *preproc_solve_macro(loginfo_t *li,
 #undef ONLYDIGS
 			}
 			if (do_add) {
-				preproc_token_t tok2;
 				preproc_token_t *tok1 = &mtok->val.tok;
-				switch (tok1->tokt) {
-				case PPTOK_INVALID:
-				case PPTOK_NEWLINE:
-				case PPTOK_BLANK:
-				case PPTOK_START_LINE_COMMENT:
-				case PPTOK_EOF: tok2 = (preproc_token_t){.tokt = tok1->tokt, .loginfo = *li, .tokv.c = tok1->tokv.c}; break;
-				case PPTOK_SYM: tok2 = (preproc_token_t){.tokt = tok1->tokt, .loginfo = *li, .tokv.sym = tok1->tokv.sym}; break;
-				case PPTOK_IDENT:
-				case PPTOK_IDENT_UNEXP:
-				case PPTOK_NUM: {
-					string_t *dup = string_dup(tok1->tokv.str);
-					if (!dup) {
-						LOG_MEMORY("failed to duplicate string");
-						vector_del(preproc, ret);
-						ret = NULL;
-						goto solve_done;
+				if (tok1->tokt != PPTOK_NEWLINE) {
+					preproc_token_t tok2;
+					switch (tok1->tokt) {
+					case PPTOK_INVALID:
+					case PPTOK_NEWLINE:
+					case PPTOK_BLANK:
+					case PPTOK_START_LINE_COMMENT:
+					case PPTOK_EOF: tok2 = (preproc_token_t){.tokt = tok1->tokt, .loginfo = *li, .tokv.c = tok1->tokv.c}; break;
+					case PPTOK_SYM: tok2 = (preproc_token_t){.tokt = tok1->tokt, .loginfo = *li, .tokv.sym = tok1->tokv.sym}; break;
+					case PPTOK_IDENT:
+					case PPTOK_IDENT_UNEXP:
+					case PPTOK_NUM: {
+						string_t *dup = string_dup(tok1->tokv.str);
+						if (!dup) {
+							LOG_MEMORY("failed to duplicate string");
+							vector_del(preproc, ret);
+							ret = NULL;
+							goto solve_done;
+						}
+						tok2 = (preproc_token_t){.tokt = tok1->tokt, .loginfo = *li, .tokv.str = dup};
+						break; }
+					case PPTOK_INCL:
+					case PPTOK_STRING: {
+						string_t *dup = string_dup(tok1->tokv.sstr);
+						if (!dup) {
+							LOG_MEMORY("failed to duplicate string");
+							vector_del(preproc, ret);
+							ret = NULL;
+							goto solve_done;
+						}
+						tok2 = (preproc_token_t){.tokt = tok1->tokt, .loginfo = *li, .tokv.sstr = dup, .tokv.sisstr = tok1->tokv.sisstr};
+						break; }
 					}
-					tok2 = (preproc_token_t){.tokt = tok1->tokt, .loginfo = *li, .tokv.str = dup};
-					break; }
-				case PPTOK_INCL:
-				case PPTOK_STRING: {
-					string_t *dup = string_dup(tok1->tokv.sstr);
-					if (!dup) {
-						LOG_MEMORY("failed to duplicate string");
+					if (!vector_push(preproc, ret, tok2)) {
+						LOG_MEMORY("failed to add token to output vector");
+						preproc_token_del(&tok2);
 						vector_del(preproc, ret);
 						ret = NULL;
 						goto solve_done;
 					}
-					tok2 = (preproc_token_t){.tokt = tok1->tokt, .loginfo = *li, .tokv.sstr = dup, .tokv.sisstr = tok1->tokv.sisstr};
-					break; }
-				}
-				if (!vector_push(preproc, ret, tok2)) {
-					LOG_MEMORY("failed to add token to output vector");
-					preproc_token_del(&tok2);
-					vector_del(preproc, ret);
-					ret = NULL;
-					goto solve_done;
 				}
 			}
 			vector_pop_nodel(mtoken, st);
@@ -630,7 +644,8 @@ static VECTOR(preproc) *preproc_solve_macro(loginfo_t *li,
 			}
 			if (len) {
 				preproc_token_t tok2;
-				for (preproc_token_t *tok1 = vector_begin(preproc, toks_to_add) + tta_start; tok1 != vector_end(preproc, toks_to_add); ++tok1){
+				for (preproc_token_t *tok1 = vector_begin(preproc, toks_to_add) + tta_start; tok1 != vector_end(preproc, toks_to_add); ++tok1) {
+					if (tok1->tokt == PPTOK_NEWLINE) continue;
 					switch (tok1->tokt) {
 					case PPTOK_INVALID:
 					case PPTOK_NEWLINE:
@@ -779,6 +794,7 @@ static VECTOR(preproc) *preproc_do_expand(loginfo_t *li, const khash_t(macros_ma
 		return NULL;
 	}
 	vector_for(preproc, tok, toks) {
+		if (tok->tokt == PPTOK_NEWLINE) continue;
 		preproc_token_t tok2;
 		switch (tok->tokt) {
 		case PPTOK_INVALID:
@@ -2115,7 +2131,7 @@ start_cur_token:
 								}
 								marg = vector_new(preproc);
 								if (!marg) goto solve_err_mem;
-							} else {
+							} else if (tok2.tokt != PPTOK_NEWLINE) {
 								if (!vector_push(preproc, marg, tok2)) {
 									vector_del(preproc, marg);
 									goto solve_err_mem;
@@ -2409,18 +2425,32 @@ start_cur_token:
 					}
 				}
 				// cur_pathno == 0 if cur_file was from an #include "...", otherwise idx + 1
+				int has_once = 0;
+				vector_for(ccharp, fname, src->pragma_once) {
+					if (!strcmp(*fname, string_content(incl_file))) {
+						has_once = 1;
+						break;
+					}
+				}
+				if (has_once) {
 #ifdef LOG_INCLUDE
-				printf("Opening %s as %s from system path %zu\n", string_content(incl_file),
-				       is_sys ? "system header" : "cur header", is_next ? src->cur_pathno : 0);
+					printf("Skipping opening %s as %s from system path %zu\n", string_content(incl_file),
+					       is_sys ? "system header" : "cur header", is_next ? src->cur_pathno : 0);
 #endif
-				if ((is_sys || !try_open_dir(src, incl_file)) && !try_open_sys(src, incl_file, is_next ? src->cur_pathno : 0)) {
-					log_error(&li, "failed to open %s\n", string_content(incl_file));
-					string_del(incl_file);
-					src->st = PPST_NONE;
-					ret.tokt = PTOK_INVALID;
-					ret.loginfo = li;
-					ret.tokv.c = is_sys ? '<' : '"';
-					return ret;
+				} else {
+#ifdef LOG_INCLUDE
+					printf("Opening %s as %s from system path %zu\n", string_content(incl_file),
+					       is_sys ? "system header" : "cur header", is_next ? src->cur_pathno : 0);
+#endif
+					if ((is_sys || !try_open_dir(src, incl_file)) && !try_open_sys(src, incl_file, is_next ? src->cur_pathno : 0)) {
+						log_error(&li, "failed to open %s\n", string_content(incl_file));
+						string_del(incl_file);
+						src->st = PPST_NONE;
+						ret.tokt = PTOK_INVALID;
+						ret.loginfo = li;
+						ret.tokv.c = is_sys ? '<' : '"';
+						return ret;
+					}
 				}
 				string_del(incl_file);
 				if (tok.tokt == PPTOK_NEWLINE) goto check_next_token;
@@ -2828,6 +2858,19 @@ start_cur_token:
 				if ((tok.tokt != PPTOK_IDENT) && (tok.tokt != PPTOK_IDENT_UNEXP)) {
 					log_error(&tok.loginfo, "unknown pragma directive, skipping until EOL\n");
 					goto preproc_hash_err;
+				} else if (!strcmp(string_content(tok.tokv.str), "once")) {
+					const char *fname = tok.loginfo.filename;
+					if (!vector_push(ccharp, src->pragma_once, fname)) {
+						log_memory("failed to add filename to #pragma once list\n");
+						vector_clear(ppsource, src->prep);
+						ret.tokt = PTOK_INVALID;
+						ret.loginfo = tok.loginfo;
+						ret.tokv.c = (char)EOF;
+						return ret;
+					}
+					string_del(tok.tokv.str);
+					tok = ppsrc_next_token(src);
+					goto preproc_hash_err;
 				} else if (!strcmp(string_content(tok.tokv.str), "wrappers")) {
 					string_del(tok.tokv.str);
 					tok = ppsrc_next_token(src);
diff --git a/wrapperhelper/src/vector.c b/wrapperhelper/src/vector.c
index c3f710d7..d1604e6d 100644
--- a/wrapperhelper/src/vector.c
+++ b/wrapperhelper/src/vector.c
@@ -3,6 +3,7 @@
 VECTOR_IMPL(voidp, (void))
 VECTOR_IMPL(char, (void))
 VECTOR_IMPL(charp, (void))
+VECTOR_IMPL(ccharp, (void))
 static void stringp_del(string_t **s) { return string_del(*s); }
 VECTOR_IMPL(string, stringp_del)
 
diff --git a/wrapperhelper/src/vector.h b/wrapperhelper/src/vector.h
index 6e0c124a..5573b9ac 100644
--- a/wrapperhelper/src/vector.h
+++ b/wrapperhelper/src/vector.h
@@ -208,6 +208,7 @@ int            vector_push_vec_impl(VECTOR(voidp) *v1, VECTOR(voidp) *v2, size_t
 
 VECTOR_DECLARE(char, char)
 VECTOR_DECLARE(charp, char*)
+VECTOR_DECLARE(ccharp, const char*)
 VECTOR_DECLARE(string, string_t*)
 
 #endif // VECTOR_H