--- /dev/null
+--- 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;