--- a/editors/awk.c
+++ b/editors/awk.c
@@ -53,9 +53,14 @@ typedef struct chain_s {
 } chain;
 
 /* Function */
+typedef var *(*awk_cfunc)(var *res, var *args, int nargs);
 typedef struct func_s {
 	unsigned nargs;
+	enum { AWKFUNC, CFUNC } type;
+	union {
+		awk_cfunc cfunc;
 	struct chain_s body;
+	} x;
 } func;
 
 /* I/O stream */
@@ -1395,7 +1400,8 @@ static void parse_program(char *p)
 			next_token(TC_FUNCTION);
 			g_pos++;
 			f = newfunc(t_string);
-			f->body.first = NULL;
+			f->type = AWKFUNC;
+			f->x.body.first = NULL;
 			f->nargs = 0;
 			while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) {
 				v = findvar(ahash, t_string);
@@ -1404,7 +1410,7 @@ static void parse_program(char *p)
 				if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM)
 					break;
 			}
-			seq = &(f->body);
+			seq = &(f->x.body);
 			chain_group();
 			clear_array(ahash);
 
@@ -2367,7 +2373,8 @@ static var *evaluate(node *op, var *res)
 			break;
 
 		case XC( OC_FUNC ):
-			if (!op->r.f->body.first)
+			if ((op->r.f->type == AWKFUNC) &&
+				!op->r.f->x.body.first)
 				syntax_error(EMSG_UNDEF_FUNC);
 
 			X.v = R.v = nvalloc(op->r.f->nargs+1);
@@ -2384,7 +2391,10 @@ static var *evaluate(node *op, var *res)
 			fnargs = X.v;
 
 			L.s = g_progname;
-			res = evaluate(op->r.f->body.first, res);
+			if (op->r.f->type == AWKFUNC)
+				res = evaluate(op->r.f->x.body.first, res);
+			else if (op->r.f->type == CFUNC)
+				res = op->r.f->x.cfunc(res, fnargs, op->r.f->nargs);
 			g_progname = L.s;
 
 			nvfree(fnargs);
@@ -2747,6 +2757,143 @@ static rstream *next_input_file(void)
 #undef files_happen
 }
 
+/* read the contents of an entire file */
+static char *get_file(const char *fname)
+{
+	FILE *F;
+	char *s = NULL;
+	int i, j, flen;
+
+	F = fopen(fname, "r");
+	if (!F) {
+		return NULL;
+	}
+
+	if (fseek(F, 0, SEEK_END) == 0) {
+		flen = ftell(F);
+		s = (char *)xmalloc(flen+4);
+		fseek(F, 0, SEEK_SET);
+		i = 1 + fread(s+1, 1, flen, F);
+	} else {
+		for (i=j=1; j>0; i+=j) {
+			s = (char *)xrealloc(s, i+4096);
+			j = fread(s+i, 1, 4094, F);
+		}
+	}
+
+	s[i] = '\0';
+	fclose(F);
+	return s;
+}
+
+
+/* parse_include():
+ *
+ * taken from parse_program from awk.c
+ * END{} is not parsed here, and BEGIN{} is executed immediately
+ */
+static void parse_include(char *p)
+{
+	uint32_t tclass;
+	chain *initseq = NULL;
+	chain tmp;
+	func *f;
+	var *v, *tv;
+
+	tv = nvalloc(1);
+	memset(&tmp, 0, sizeof(tmp));
+	g_pos = p;
+	t_lineno = 1;
+	while ((tclass = next_token(TC_EOF | TC_OPSEQ |
+				TC_OPTERM | TC_BEGIN | TC_FUNCDECL)) != TC_EOF) {
+		if (tclass & TC_OPTERM)
+			continue;
+
+		seq = &tmp;
+		if (tclass & TC_BEGIN) {
+			initseq = xzalloc(sizeof(chain));
+			seq = initseq;
+			chain_group();
+		} else if (tclass & TC_FUNCDECL) {
+			next_token(TC_FUNCTION);
+			g_pos++;
+			f = newfunc(t_string);
+			f->type = AWKFUNC;
+			f->x.body.first = NULL;
+			f->nargs = 0;
+			while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) {
+				v = findvar(ahash, t_string);
+				v->x.aidx = (f->nargs)++;
+
+				if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM)
+					break;
+			}
+			seq = &(f->x.body);
+			chain_group();
+			clear_array(ahash);
+		}
+	}
+	if (initseq && initseq->first)
+		tv = evaluate(initseq->first, tv);
+	nvfree(tv);
+}
+
+
+/* include an awk file and run its BEGIN{} section */
+static xhash *includes = NULL;
+static void include_file(const char *filename)
+{
+	char *s;
+	var *v;
+	int oldlnr = g_lineno;
+	const char *oldprg = g_progname;
+
+	if (!includes)
+		includes = hash_init();
+
+	/* find out if the file has been included already */
+	v = findvar(includes, filename);
+	if (istrue(v))
+		return;
+	setvar_s(v, "1");
+
+	/* read include file */
+	s = get_file(filename);
+	if (!s) {
+		fprintf(stderr, "Could not open file.\n");
+		return;
+	}
+	g_lineno = 1;
+	g_progname = xstrdup(filename);
+	parse_include(s+1);
+	free(s);
+	g_lineno = oldlnr;
+	g_progname = oldprg;
+}
+
+static var *include(var *res, var *args, int nargs)
+{
+	const char *s;
+
+	nargs = nargs; /* shut up, gcc */
+	s = getvar_s(args);
+	if (s && (strlen(s) > 0))
+		include_file(s);
+
+	return res;
+}
+
+/* registers a global c function for the awk interpreter */
+static void register_cfunc(const char *name, awk_cfunc cfunc, int nargs)
+{
+	func *f;
+
+	f = newfunc(name);
+	f->type = CFUNC;
+	f->x.cfunc = cfunc;
+	f->nargs = nargs;
+}
+
 int awk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int awk_main(int argc, char **argv)
 {
@@ -2812,6 +2959,9 @@ int awk_main(int argc, char **argv)
 			*s1 = '=';
 		}
 	}
+
+	register_cfunc("include", include, 1);
+
 	opt_complementary = "v::f::"; /* -v and -f can occur multiple times */
 	opt = getopt32(argv, "F:v:f:W:", &opt_F, &list_v, &list_f, &opt_W);
 	argv += optind;
