510-awk_include.patch 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. --- a/editors/awk.c
  2. +++ b/editors/awk.c
  3. @@ -53,9 +53,14 @@ typedef struct chain_s {
  4. } chain;
  5. /* Function */
  6. +typedef var *(*awk_cfunc)(var *res, var *args, int nargs);
  7. typedef struct func_s {
  8. unsigned nargs;
  9. + enum { AWKFUNC, CFUNC } type;
  10. + union {
  11. + awk_cfunc cfunc;
  12. struct chain_s body;
  13. + } x;
  14. } func;
  15. /* I/O stream */
  16. @@ -1395,7 +1400,8 @@ static void parse_program(char *p)
  17. next_token(TC_FUNCTION);
  18. g_pos++;
  19. f = newfunc(t_string);
  20. - f->body.first = NULL;
  21. + f->type = AWKFUNC;
  22. + f->x.body.first = NULL;
  23. f->nargs = 0;
  24. while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) {
  25. v = findvar(ahash, t_string);
  26. @@ -1404,7 +1410,7 @@ static void parse_program(char *p)
  27. if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM)
  28. break;
  29. }
  30. - seq = &(f->body);
  31. + seq = &(f->x.body);
  32. chain_group();
  33. clear_array(ahash);
  34. @@ -2367,7 +2373,8 @@ static var *evaluate(node *op, var *res)
  35. break;
  36. case XC( OC_FUNC ):
  37. - if (!op->r.f->body.first)
  38. + if ((op->r.f->type == AWKFUNC) &&
  39. + !op->r.f->x.body.first)
  40. syntax_error(EMSG_UNDEF_FUNC);
  41. X.v = R.v = nvalloc(op->r.f->nargs+1);
  42. @@ -2384,7 +2391,10 @@ static var *evaluate(node *op, var *res)
  43. fnargs = X.v;
  44. L.s = g_progname;
  45. - res = evaluate(op->r.f->body.first, res);
  46. + if (op->r.f->type == AWKFUNC)
  47. + res = evaluate(op->r.f->x.body.first, res);
  48. + else if (op->r.f->type == CFUNC)
  49. + res = op->r.f->x.cfunc(res, fnargs, op->r.f->nargs);
  50. g_progname = L.s;
  51. nvfree(fnargs);
  52. @@ -2747,6 +2757,143 @@ static rstream *next_input_file(void)
  53. #undef files_happen
  54. }
  55. +/* read the contents of an entire file */
  56. +static char *get_file(const char *fname)
  57. +{
  58. + FILE *F;
  59. + char *s = NULL;
  60. + int i, j, flen;
  61. +
  62. + F = fopen(fname, "r");
  63. + if (!F) {
  64. + return NULL;
  65. + }
  66. +
  67. + if (fseek(F, 0, SEEK_END) == 0) {
  68. + flen = ftell(F);
  69. + s = (char *)xmalloc(flen+4);
  70. + fseek(F, 0, SEEK_SET);
  71. + i = 1 + fread(s+1, 1, flen, F);
  72. + } else {
  73. + for (i=j=1; j>0; i+=j) {
  74. + s = (char *)xrealloc(s, i+4096);
  75. + j = fread(s+i, 1, 4094, F);
  76. + }
  77. + }
  78. +
  79. + s[i] = '\0';
  80. + fclose(F);
  81. + return s;
  82. +}
  83. +
  84. +
  85. +/* parse_include():
  86. + *
  87. + * taken from parse_program from awk.c
  88. + * END{} is not parsed here, and BEGIN{} is executed immediately
  89. + */
  90. +static void parse_include(char *p)
  91. +{
  92. + uint32_t tclass;
  93. + chain *initseq = NULL;
  94. + chain tmp;
  95. + func *f;
  96. + var *v, *tv;
  97. +
  98. + tv = nvalloc(1);
  99. + memset(&tmp, 0, sizeof(tmp));
  100. + g_pos = p;
  101. + t_lineno = 1;
  102. + while ((tclass = next_token(TC_EOF | TC_OPSEQ |
  103. + TC_OPTERM | TC_BEGIN | TC_FUNCDECL)) != TC_EOF) {
  104. + if (tclass & TC_OPTERM)
  105. + continue;
  106. +
  107. + seq = &tmp;
  108. + if (tclass & TC_BEGIN) {
  109. + initseq = xzalloc(sizeof(chain));
  110. + seq = initseq;
  111. + chain_group();
  112. + } else if (tclass & TC_FUNCDECL) {
  113. + next_token(TC_FUNCTION);
  114. + g_pos++;
  115. + f = newfunc(t_string);
  116. + f->type = AWKFUNC;
  117. + f->x.body.first = NULL;
  118. + f->nargs = 0;
  119. + while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) {
  120. + v = findvar(ahash, t_string);
  121. + v->x.aidx = (f->nargs)++;
  122. +
  123. + if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM)
  124. + break;
  125. + }
  126. + seq = &(f->x.body);
  127. + chain_group();
  128. + clear_array(ahash);
  129. + }
  130. + }
  131. + if (initseq && initseq->first)
  132. + tv = evaluate(initseq->first, tv);
  133. + nvfree(tv);
  134. +}
  135. +
  136. +
  137. +/* include an awk file and run its BEGIN{} section */
  138. +static xhash *includes = NULL;
  139. +static void include_file(const char *filename)
  140. +{
  141. + char *s;
  142. + var *v;
  143. + int oldlnr = g_lineno;
  144. + const char *oldprg = g_progname;
  145. +
  146. + if (!includes)
  147. + includes = hash_init();
  148. +
  149. + /* find out if the file has been included already */
  150. + v = findvar(includes, filename);
  151. + if (istrue(v))
  152. + return;
  153. + setvar_s(v, "1");
  154. +
  155. + /* read include file */
  156. + s = get_file(filename);
  157. + if (!s) {
  158. + fprintf(stderr, "Could not open file.\n");
  159. + return;
  160. + }
  161. + g_lineno = 1;
  162. + g_progname = xstrdup(filename);
  163. + parse_include(s+1);
  164. + free(s);
  165. + g_lineno = oldlnr;
  166. + g_progname = oldprg;
  167. +}
  168. +
  169. +static var *include(var *res, var *args, int nargs)
  170. +{
  171. + const char *s;
  172. +
  173. + nargs = nargs; /* shut up, gcc */
  174. + s = getvar_s(args);
  175. + if (s && (strlen(s) > 0))
  176. + include_file(s);
  177. +
  178. + return res;
  179. +}
  180. +
  181. +/* registers a global c function for the awk interpreter */
  182. +static void register_cfunc(const char *name, awk_cfunc cfunc, int nargs)
  183. +{
  184. + func *f;
  185. +
  186. + f = newfunc(name);
  187. + f->type = CFUNC;
  188. + f->x.cfunc = cfunc;
  189. + f->nargs = nargs;
  190. +}
  191. +
  192. int awk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  193. int awk_main(int argc, char **argv)
  194. {
  195. @@ -2812,6 +2959,9 @@ int awk_main(int argc, char **argv)
  196. *s1 = '=';
  197. }
  198. }
  199. +
  200. + register_cfunc("include", include, 1);
  201. +
  202. opt_complementary = "v::f::"; /* -v and -f can occur multiple times */
  203. opt = getopt32(argv, "F:v:f:W:", &opt_F, &list_v, &list_f, &opt_W);
  204. argv += optind;