%top { /* GNU Mailutils -- a suite of utilities for electronic mail Copyright (C) 2003-2021 Free Software Foundation, Inc. GNU Mailutils is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNU Mailutils is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Mailutils. If not, see . */ #ifdef HAVE_CONFIG_H # include #endif } %{ #include #include #include #include #include #include #include static mu_linetrack_t trk; static ino_t ali_source_inode; int yyerror (char *s) { mu_error ("%s", s); return 0; } #define xinput() (yyin ? getc(yyin) : EOF) #undef YY_INPUT #define YY_INPUT(buf,result,max_size) do { \ int i; \ for (i = 0; i < max_size; i++) { \ int ch = xinput(); \ if (ch == EOF) \ break; \ buf[i] = ch; \ } \ result = i; \ } while (0) #define LEX_BUFFER_STATE YY_BUFFER_STATE #define SET_BUFFER_STATE(s) do { \ (s) = YY_CURRENT_BUFFER; \ yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); \ } while (0) #define RESTORE_BUFFER_STATE(s) do { \ yy_delete_buffer(YY_CURRENT_BUFFER); \ yy_switch_to_buffer(s); \ } while (0) #define YY_USER_ACTION \ do \ { \ mu_linetrack_advance (trk, &yylloc, yytext, yyleng); \ mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, \ MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, &yylloc); \ } \ while (0); struct buffer_ctx { struct buffer_ctx *prev; mu_linetrack_t trk; ino_t i_node; struct mu_locus_range incl_range; FILE *yyin; int exec_p; LEX_BUFFER_STATE state; }; static struct buffer_ctx *context_stack; static int exec_p; static struct buffer_ctx * ctx_lookup (ino_t ino) { struct buffer_ctx *ctx; for (ctx = context_stack; ctx; ctx = ctx->prev) if (ctx->i_node == ino) break; return ctx; } static int push_source (const char *name, int fail) { FILE *fp; struct buffer_ctx *ctx; struct stat st; char *filename; int ex = 0; filename = mh_expand_name (NULL, name, NAME_ANY); if (stat (filename, &st)) { if (fail) mu_error (_("can't stat `%s': %s"), filename, strerror (errno)); free (filename); return 1; } if (yylloc.beg.mu_file && st.st_ino == ali_source_inode) { mu_error (_("recursive inclusion")); free (filename); return 1; } if ((ctx = ctx_lookup (st.st_ino))) { mu_error (_("recursive inclusion")); if (ctx->prev) mu_diag_at_locus_range (MU_LOG_ERROR, &ctx->incl_range, _("`%s' already included here"), filename); else mu_error (_("`%s' already included at top level"), filename); free (filename); return 1; } fp = fopen (filename, "r"); if (!fp) { mu_error (_("can't open `%s': %s"), filename, strerror (errno)); free (filename); return 1; } if (access (filename, X_OK) == 0) { char sig[4]; if (fread (sig, sizeof(sig), 1, fp) == 1 && (memcmp(sig, "#!/", 3) == 0 || memcmp(sig, "#! /", 4) == 0)) { ex = 1; fclose (fp); fp = popen (filename, "r"); if (!fp) { mu_error (_("can't execute `%s': %s"), filename, strerror (errno)); free (filename); return 1; } } else rewind (fp); } /* Push current context */ if (yylloc.beg.mu_file) { ctx = mu_alloc (sizeof (*ctx)); ctx->trk = trk; mu_locus_range_init (&ctx->incl_range); mu_locus_range_copy (&ctx->incl_range, &yylloc); ctx->exec_p = exec_p; ctx->i_node = ali_source_inode; ctx->yyin = yyin; ctx->prev = context_stack; context_stack = ctx; /* Switch to the new context */ yyin = fp; SET_BUFFER_STATE (ctx->state); } else { #ifdef FLEX_SCANNER yyrestart (fp); #else yyin = fp; lex_set_buffer (yyin); #endif } MU_ASSERT (mu_linetrack_create (&trk, filename, 2)); free (filename); ali_source_inode = st.st_ino; exec_p = ex; return 0; } static int pop_source (void) { struct buffer_ctx *ctx; if (yyin) (exec_p ? pclose : fclose) (yyin); mu_linetrack_destroy (&trk); if (!context_stack) { mu_locus_range_deinit (&yylloc); yyin = NULL; return 1; } mu_locus_range_deinit (&context_stack->incl_range); /* Restore previous context */ trk = context_stack->trk; ali_source_inode = context_stack->i_node; exec_p = context_stack->exec_p; RESTORE_BUFFER_STATE (context_stack->state); ctx = context_stack->prev; free (context_stack); context_stack = ctx; return 0; } extern int yyparse (void); %} %option nounput %option noinput WS [ \t]+ WORD [^ \t\n,:;<+=\*]+ SPEC [,:;+=\*] %s VERBATIM %% \\\n ; \n+ return EOL; ^[ \t]*\;.*\n ; ^[ \t]*{WORD}\* { char *p; for (p = yytext; p < yytext + yyleng; p++) if (!mu_isspace (*p)) break; yylval.string = mu_strdup (p); return STRING; } {WS} ; {WORD} { yylval.string = mu_strdup (yytext); return STRING;} ^{WS}?"<"{WS}?{WORD} { char *p; for (p = yytext; p < yytext + yyleng && mu_isblank(*p); p++) ; for (p++; p < yytext + yyleng; p++) if (!mu_isspace (*p)) break; push_source (p, 1); } {SPEC} return yytext[0]; [^ \t\n,:;+=\*][^\n,]* { yylval.string = mu_alloc (yyleng + 1); memcpy(yylval.string, yytext, yyleng); yylval.string[yyleng] = 0; return STRING;} . { mu_error (_("Stray character %03o in alias file"), yytext[0]); } %% int yywrap (void) { return pop_source (); } /* Parses the named alias file */ int mh_alias_read (char const *name, int fail) { int rc; int old_mode, mode; extern int yydebug; char *p = getenv ("ALI_YYDEBUG"); if (p && *p > '0' && *p < '9') yydebug = 1; if (push_source (name, fail)) return 1; if (yydebug) fprintf (stderr, "Starting parse of %s\n", name); mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_GET_MODE, &old_mode); mode = old_mode | MU_LOGMODE_LOCUS; mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_SET_MODE, &mode); rc = yyparse (); mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_SET_MODE, &old_mode); return rc; } void ali_verbatim (int enable) { if (enable) BEGIN(VERBATIM); else BEGIN(INITIAL); }