diff options
Diffstat (limited to 'mimeview/grammar.y')
-rw-r--r-- | mimeview/grammar.y | 911 |
1 files changed, 0 insertions, 911 deletions
diff --git a/mimeview/grammar.y b/mimeview/grammar.y deleted file mode 100644 index 6b40d91a5..000000000 --- a/mimeview/grammar.y +++ /dev/null @@ -1,911 +0,0 @@ -%{ -/* GNU Mailutils -- a suite of utilities for electronic mail - Copyright (C) 2005-2019 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 <http://www.gnu.org/licenses/>. */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <mailutils/cctype.h> -#include <mimeview.h> -#include <grammar.h> -#include <regex.h> - -static void -yyprint (FILE *output, unsigned short toknum, YYSTYPE val) -{ - switch (toknum) - { - case TYPE: - case IDENT: - case STRING: - fprintf (output, "[%lu] %s", (unsigned long) val.string.len, - val.string.ptr); - break; - - case EOL: - fprintf (output, "\\n"); - break; - - default: - if (mu_isprint (toknum)) - fprintf (output, "'%c'", toknum); - else - fprintf (output, "tok(%d)", toknum); - break; - } -} - -#define YYPRINT yyprint - -static mu_list_t arg_list; /* For error recovery */ - -#define L_OR 0 -#define L_AND 1 - -enum node_type - { - true_node, - functional_node, - binary_node, - negation_node, - suffix_node - }; - -union argument -{ - struct mimetypes_string *string; - unsigned number; - int c; - regex_t rx; -}; - -typedef int (*builtin_t) (union argument *args); - -struct node -{ - enum node_type type; - struct mu_locus_range loc; - union - { - struct - { - builtin_t fun; - union argument *args; - } function; - struct node *arg; - struct - { - int op; - struct node *arg1; - struct node *arg2; - } bin; - struct mimetypes_string suffix; - } v; -}; - -static struct node *make_node (enum node_type type, - struct mu_locus_range const *loc); -static struct node *make_binary_node (int op, - struct node *left, struct node *rigth, - struct mu_locus_range const *loc); -static struct node *make_negation_node (struct node *p, - struct mu_locus_range const *loc); - -static struct node *make_suffix_node (struct mimetypes_string *suffix, - struct mu_locus_range const *loc); -static struct node *make_functional_node (char *ident, mu_list_t list, - struct mu_locus_range const *loc); - -static int eval_rule (struct node *root); - -struct rule_tab -{ - char *type; - int priority; - struct mu_locus_range loc; - struct node *node; -}; - -static mu_list_t rule_list; -static size_t errors; -%} - -%locations -%expect 15 - -%token <string> TYPE IDENT -%token <string> STRING -%token EOL BOGUS PRIORITY - -%left ',' -%left '+' - -%type <string> arg -%type <list> arglist -%type <node> function stmt rule maybe_rule -%type <result> priority maybe_priority - -%union { - struct mimetypes_string string; - char *s; - mu_list_t list; - int result; - struct node *node; -} - -%% - -input : list - ; - -list : rule_line - | list EOL rule_line - ; - -rule_line: /* empty */ - | TYPE maybe_rule maybe_priority - { - struct rule_tab *p = mimetypes_malloc (sizeof (*p)); - if (!rule_list) - mu_list_create (&rule_list); - p->type = $1.ptr; - p->node = $2; - p->priority = $3; - mu_locus_point_copy (&p->loc.beg, &@1.beg); - mu_locus_point_copy (&p->loc.end, &@3.end); -#if 0 - YY_LOCATION_PRINT (stderr, p->loc); - fprintf (stderr, ": rule %s\n", p->type); -#endif - mu_list_append (rule_list, p); - } - | BOGUS - { - YYERROR; - } - | error - { - errors++; - if (arg_list) - mu_list_destroy (&arg_list); - lex_next_rule (); - yyerrok; - yyclearin; - } - ; - -maybe_rule: /* empty */ - { - $$ = make_node (true_node, &yylloc); - } - | rule - ; - -rule : stmt - | rule rule %prec ',' - { - struct mu_locus_range lr; - lr.beg = @1.beg; - lr.end = @2.end; - $$ = make_binary_node (L_OR, $1, $2, &lr); - } - | rule ',' rule - { - struct mu_locus_range lr; - lr.beg = @1.beg; - lr.end = @3.end; - $$ = make_binary_node (L_OR, $1, $3, &lr); - } - | rule '+' rule - { - struct mu_locus_range lr; - lr.beg = @1.beg; - lr.end = @3.end; - $$ = make_binary_node (L_AND, $1, $3, &lr); - } - ; - -stmt : '!' stmt - { - $$ = make_negation_node ($2, &@2); - } - | '(' rule ')' - { - $$ = $2; - } - | STRING - { - $$ = make_suffix_node (&$1, &@1); - } - | function - | BOGUS - { - YYERROR; - } - ; - -priority : PRIORITY '(' arglist ')' - { - size_t count = 0; - struct mimetypes_string *arg; - - mu_list_count ($3, &count); - if (count != 1) - { - yyerror (_("priority takes single numberic argument")); - YYERROR; - } - mu_list_head ($3, (void**) &arg); - $$ = atoi (arg->ptr); - mu_list_destroy (&$3); - } - ; - -maybe_priority: /* empty */ - { - $$ = 100; - } - | priority - ; - -function : IDENT '(' arglist ')' - { - struct mu_locus_range lr; - lr.beg = @1.beg; - lr.end = @4.end; - - $$ = make_functional_node ($1.ptr, $3, &lr); - if (!$$) - YYERROR; - } - ; - -arglist : arg - { - mu_list_create (&arg_list); - $$ = arg_list; - mu_list_append ($$, mimetypes_string_dup (&$1)); - } - | arglist ',' arg - { - mu_list_append ($1, mimetypes_string_dup (&$3)); - $$ = $1; - } - ; - -arg : STRING - | BOGUS - { - YYERROR; - } - ; - -%% - -int -mimetypes_parse (const char *name) -{ - int rc; - if (mimetypes_open (name)) - return 1; - yydebug = mu_debug_level_p (MU_DEBCAT_APP, MU_DEBUG_TRACE3); - rc = yyparse (); - mimetypes_close (); - return rc || errors; -} - -static struct node * -make_node (enum node_type type, struct mu_locus_range const *loc) -{ - struct node *p = mimetypes_malloc (sizeof *p); - p->type = type; - mu_locus_range_init (&p->loc); - mu_locus_range_copy (&p->loc, loc); - return p; -} - -static struct node * -make_binary_node (int op, struct node *left, struct node *right, - struct mu_locus_range const *loc) -{ - struct node *node = make_node (binary_node, loc); - - node->v.bin.op = op; - node->v.bin.arg1 = left; - node->v.bin.arg2 = right; - return node; -} - -struct node * -make_negation_node (struct node *p, struct mu_locus_range const *loc) -{ - struct node *node = make_node (negation_node, loc); - node->v.arg = p; - return node; -} - -struct node * -make_suffix_node (struct mimetypes_string *suffix, - struct mu_locus_range const *loc) -{ - struct node *node = make_node (suffix_node, loc); - node->v.suffix = *suffix; - return node; -} - -struct builtin_tab -{ - char *name; - char *args; - builtin_t handler; -}; - -/* match("pattern") - Pattern match on filename -*/ -static int -b_match (union argument *args) -{ - return fnmatch (args[0].string->ptr, mimeview_file, 0) == 0; -} - -/* ascii(offset,length) - True if bytes are valid printable ASCII (CR, NL, TAB, - BS, 32-126) -*/ -#define ISASCII(c) ((c) &&\ - (strchr ("\n\r\t\b",c) \ - || (32<=((unsigned) c) && ((unsigned) c)<=126))) -static int -b_ascii (union argument *args) -{ - int i; - int rc; - - rc = mu_stream_seek (mimeview_stream, args[0].number, MU_SEEK_SET, NULL); - if (rc) - { - mu_diag_funcall (MU_DIAG_ERROR, "mu_stream_seek", NULL, rc); - return 0; - } - - for (i = 0; i < args[1].number; i++) - { - unsigned char c; - size_t n; - - rc = mu_stream_read (mimeview_stream, &c, 1, &n); - if (rc || n == 0) - break; - if (!ISASCII (c)) - return 0; - } - - return 1; -} - -/* printable(offset,length) - True if bytes are printable 8-bit chars (CR, NL, TAB, - BS, 32-126, 128-254) -*/ -#define ISPRINT(c) (ISASCII (c) \ - || (128<=((unsigned) c) && ((unsigned) c)<=254)) -static int -b_printable (union argument *args) -{ - int i; - int rc; - - rc = mu_stream_seek (mimeview_stream, args[0].number, MU_SEEK_SET, NULL); - if (rc) - { - mu_diag_funcall (MU_DIAG_ERROR, "mu_stream_seek", NULL, rc); - return 0; - } - - for (i = 0; i < args[1].number; i++) - { - unsigned char c; - size_t n; - - rc = mu_stream_read (mimeview_stream, &c, 1, &n); - if (rc || n == 0) - break; - if (!ISPRINT (c)) - return 0; - } - return 1; -} - -/* string(offset,"string") - True if bytes are identical to string -*/ -static int -b_string (union argument *args) -{ - struct mimetypes_string *str = args[1].string; - int i; - int rc; - - rc = mu_stream_seek (mimeview_stream, args[0].number, MU_SEEK_SET, NULL); - if (rc) - { - mu_diag_funcall (MU_DIAG_ERROR, "mu_stream_seek", NULL, rc); - return 0; - } - - for (i = 0; i < str->len; i++) - { - char c; - size_t n; - - rc = mu_stream_read (mimeview_stream, &c, 1, &n); - if (rc || n == 0 || c != str->ptr[i]) - return 0; - } - return 1; -} - -/* istring(offset,"string") - True if a case-insensitive comparison of the bytes is - identical -*/ -static int -b_istring (union argument *args) -{ - int i; - struct mimetypes_string *str = args[1].string; - - int rc; - - rc = mu_stream_seek (mimeview_stream, args[0].number, MU_SEEK_SET, NULL); - if (rc) - { - mu_diag_funcall (MU_DIAG_ERROR, "mu_stream_seek", NULL, rc); - return 0; - } - - for (i = 0; i < str->len; i++) - { - char c; - size_t n; - - rc = mu_stream_read (mimeview_stream, &c, 1, &n); - if (rc || n == 0 || mu_tolower (c) != mu_tolower (str->ptr[i])) - return 0; - } - return 1; -} - -int -compare_bytes (union argument *args, void *sample, void *buf, size_t size) -{ - int rc; - size_t n; - - rc = mu_stream_seek (mimeview_stream, args[0].number, MU_SEEK_SET, NULL); - if (rc) - { - mu_diag_funcall (MU_DIAG_ERROR, "mu_stream_seek", NULL, rc); - return 0; - } - - rc = mu_stream_read (mimeview_stream, buf, size, &n); - if (rc) - { - mu_diag_funcall (MU_DIAG_ERROR, "mu_stream_read", NULL, rc); - return 0; - } - else if (n != size) - return 0; - return memcmp (sample, buf, size) == 0; -} - -/* char(offset,value) - True if byte is identical -*/ -static int -b_char (union argument *args) -{ - char val = args[1].number; - char buf; - return compare_bytes (args, &val, &buf, sizeof (buf)); -} - -/* short(offset,value) - True if 16-bit integer is identical - FIXME: Byte order -*/ -static int -b_short (union argument *args) -{ - uint16_t val = args[1].number; - uint16_t buf; - return compare_bytes (args, &val, &buf, sizeof (buf)); -} - -/* int(offset,value) - True if 32-bit integer is identical - FIXME: Byte order -*/ -static int -b_int (union argument *args) -{ - uint32_t val = args[1].number; - uint32_t buf; - return compare_bytes (args, &val, &buf, sizeof (buf)); -} - -/* locale("string") - True if current locale matches string -*/ -static int -b_locale (union argument *args) -{ - abort (); /* FIXME */ - return 0; -} - -/* contains(offset,range,"string") - True if the range contains the string -*/ -static int -b_contains (union argument *args) -{ - size_t i, count; - char *buf; - struct mimetypes_string *str = args[2].string; - int rc; - - rc = mu_stream_seek (mimeview_stream, args[0].number, MU_SEEK_SET, NULL); - if (rc) - { - mu_diag_funcall (MU_DIAG_ERROR, "mu_stream_seek", NULL, rc); - return 0; - } - - buf = mu_alloc (args[1].number); - rc = mu_stream_read (mimeview_stream, buf, args[1].number, &count); - if (rc) - { - mu_diag_funcall (MU_DIAG_ERROR, "mu_stream_read", NULL, rc); - } - else if (count > str->len) - for (i = 0; i <= count - str->len; i++) - if (buf[i] == str->ptr[0] && memcmp (buf + i, str->ptr, str->len) == 0) - { - free (buf); - return 1; - } - free (buf); - return 0; -} - -#define MIME_MAX_BUFFER 4096 - -/* regex(offset,"regex") True if bytes match regular expression - */ -static int -b_regex (union argument *args) -{ - size_t count; - int rc; - char buf[MIME_MAX_BUFFER]; - - rc = mu_stream_seek (mimeview_stream, args[0].number, MU_SEEK_SET, NULL); - if (rc) - { - mu_diag_funcall (MU_DIAG_ERROR, "mu_stream_seek", NULL, rc); - return 0; - } - - rc = mu_stream_read (mimeview_stream, buf, sizeof buf - 1, &count); - if (rc) - { - mu_diag_funcall (MU_DIAG_ERROR, "mu_stream_read", NULL, rc); - return 0; - } - buf[count] = 0; - - return regexec (&args[1].rx, buf, 0, NULL, 0) == 0; -} - - -static struct builtin_tab builtin_tab[] = { - { "match", "s", b_match }, - { "ascii", "dd", b_ascii }, - { "printable", "dd", b_printable }, - { "regex", "dx", b_regex }, - { "string", "ds", b_string }, - { "istring", "ds", b_istring }, - { "char", "dc", b_char }, - { "short", "dd", b_short }, - { "int", "dd", b_int }, - { "locale", "s", b_locale }, - { "contains", "dds", b_contains }, - { NULL } -}; - -struct node * -make_functional_node (char *ident, mu_list_t list, - struct mu_locus_range const *loc) -{ - size_t count, i; - struct builtin_tab *p; - struct node *node; - union argument *args; - mu_iterator_t itr; - int rc; - - for (p = builtin_tab; ; p++) - { - if (!p->name) - { - char *s; - mu_asprintf (&s, _("%s: unknown function"), ident); - yyerror (s); - free (s); - return NULL; - } - - if (strcmp (ident, p->name) == 0) - break; - } - - mu_list_count (list, &count); - i = strlen (p->args); - - if (count < i) - { - char *s; - mu_asprintf (&s, _("too few arguments in call to `%s'"), ident); - yyerror (s); - free (s); - return NULL; - } - else if (count > i) - { - char *s; - mu_asprintf (&s, _("too many arguments in call to `%s'"), ident); - yyerror (s); - free (s); - return NULL; - } - - args = mimetypes_malloc (count * sizeof *args); - - mu_list_get_iterator (list, &itr); - for (i = 0, mu_iterator_first (itr); !mu_iterator_is_done (itr); - mu_iterator_next (itr), i++) - { - struct mimetypes_string *data; - char *tmp; - - mu_iterator_current (itr, (void **)&data); - switch (p->args[i]) - { - case 'd': - args[i].number = strtoul (data->ptr, &tmp, 0); - if (*tmp) - goto err; - break; - - case 's': - args[i].string = data; - break; - - case 'x': - { - char *s; - - rc = mu_c_str_unescape_trans (data->ptr, - "\\\\\"\"a\ab\bf\fn\nr\rt\tv\v", &s); - if (rc) - { - mu_diag_funcall (MU_DIAG_ERROR, "mu_c_str_unescape_trans", - data->ptr, rc); - return NULL; - } - rc = regcomp (&args[i].rx, s, REG_EXTENDED|REG_NOSUB); - free (s); - if (rc) - { - char errbuf[512]; - regerror (rc, &args[i].rx, errbuf, sizeof errbuf); - yyerror (errbuf); - return NULL; - } - } - break; - - case 'c': - args[i].c = strtoul (data->ptr, &tmp, 0); - if (*tmp) - goto err; - break; - - default: - abort (); - } - } - - node = make_node (functional_node, loc); - node->v.function.fun = p->handler; - node->v.function.args = args; - return node; - - err: - { - char *s; - mu_asprintf (&s, - _("argument %lu has wrong type in call to `%s'"), - (unsigned long) i, ident); - yyerror (s); - free (s); - return NULL; - } -} - -static int -check_suffix (char *suf) -{ - char *p = strrchr (mimeview_file, '.'); - if (!p) - return 0; - return strcmp (p+1, suf) == 0; -} - -void -mime_debug (int lev, struct mu_locus_range const *loc, char const *fmt, ...) -{ - if (mu_debug_level_p (MU_DEBCAT_APP, lev)) - { - va_list ap; - - if (loc->beg.mu_col == 0) - mu_debug_log_begin ("%s:%u", loc->beg.mu_file, loc->beg.mu_line); - else if (strcmp(loc->beg.mu_file, loc->end.mu_file)) - mu_debug_log_begin ("%s:%u.%u-%s:%u.%u", - loc->beg.mu_file, - loc->beg.mu_line, loc->beg.mu_col, - loc->end.mu_file, - loc->end.mu_line, loc->end.mu_col); - else if (loc->beg.mu_line != loc->end.mu_line) - mu_debug_log_begin ("%s:%u.%u-%u.%u", - loc->beg.mu_file, - loc->beg.mu_line, loc->beg.mu_col, - loc->end.mu_line, loc->end.mu_col); - else if (loc->beg.mu_col != loc->end.mu_col) - mu_debug_log_begin ("%s:%u.%u-%u", - loc->beg.mu_file, - loc->beg.mu_line, loc->beg.mu_col, - loc->end.mu_col); - else - mu_debug_log_begin ("%s:%u.%u", - loc->beg.mu_file, - loc->beg.mu_line, loc->beg.mu_col); - - mu_stream_write (mu_strerr, ": ", 2, NULL); - - va_start (ap, fmt); - mu_stream_vprintf (mu_strerr, fmt, ap); - va_end (ap); - mu_debug_log_nl (); - } -} - -static int -eval_rule (struct node *root) -{ - int result; - - switch (root->type) - { - case true_node: - result = 1; - break; - - case functional_node: - result = root->v.function.fun (root->v.function.args); - break; - - case binary_node: - result = eval_rule (root->v.bin.arg1); - switch (root->v.bin.op) - { - case L_OR: - if (!result) - result |= eval_rule (root->v.bin.arg2); - break; - - case L_AND: - if (result) - result &= eval_rule (root->v.bin.arg2); - break; - - default: - abort (); - } - break; - - case negation_node: - result = !eval_rule (root->v.arg); - break; - - case suffix_node: - result = check_suffix (root->v.suffix.ptr); - break; - - default: - abort (); - } - mime_debug (MU_DEBUG_TRACE2, &root->loc, "result %s", result ? "true" : "false"); - return result; -} - -static int -evaluate (void **itmv, size_t itmc, void *call_data) -{ - struct rule_tab *p = itmv[0]; - if (eval_rule (p->node)) - { - itmv[0] = p; - mime_debug (MU_DEBUG_TRACE1, &p->loc, "rule %s matches", p->type); - return MU_LIST_MAP_OK; - } - return MU_LIST_MAP_SKIP; -} - -static int -rule_cmp (const void *a, const void *b) -{ - struct rule_tab const *arule = a; - struct rule_tab const *brule = b; - - if (arule->priority == brule->priority) - { - if (arule->node->type == true_node - && brule->node->type != true_node) - return 1; - else if (brule->node->type == true_node - && arule->node->type != true_node) - return -1; - else - return mu_c_strcasecmp (arule->type, brule->type); - } - return arule->priority - brule->priority; -} - -const char * -get_file_type () -{ - mu_list_t res = NULL; - const char *type = NULL; - - mu_list_map (rule_list, evaluate, NULL, 1, &res); - if (!mu_list_is_empty (res)) - { - struct rule_tab *rule; - mu_list_sort (res, rule_cmp); - mu_list_head (res, (void**) &rule); - mime_debug (MU_DEBUG_TRACE0, &rule->loc, "selected rule %s", rule->type); - type = rule->type; - } - mu_list_destroy (&res); - return type; -} - |