diff options
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | include/mailutils/Makefile.am | 1 | ||||
-rw-r--r-- | include/mailutils/mailutils.h | 1 | ||||
-rw-r--r-- | include/mailutils/mimetypes.h (renamed from mimeview/mimeview.h) | 24 | ||||
-rw-r--r-- | include/mailutils/stream.h | 2 | ||||
-rw-r--r-- | include/mailutils/sys/Makefile.am | 1 | ||||
-rw-r--r-- | include/mailutils/sys/mimetypes.h | 102 | ||||
-rw-r--r-- | libmailutils/Makefile.am | 2 | ||||
-rw-r--r-- | libmailutils/diag/debcat | 1 | ||||
-rw-r--r-- | libmailutils/locus/linetrack.c | 2 | ||||
-rw-r--r-- | libmailutils/mimetypes/.gitignore | 9 | ||||
-rw-r--r-- | libmailutils/mimetypes/eval.c | 551 | ||||
-rw-r--r-- | libmailutils/mimetypes/grammar.y | 627 | ||||
-rw-r--r-- | libmailutils/mimetypes/lexer.l (renamed from mimeview/lexer.l) | 33 | ||||
-rw-r--r-- | libmailutils/stream/file_stream.c | 2 | ||||
-rw-r--r-- | mimeview/Makefile.am | 25 | ||||
-rw-r--r-- | mimeview/grammar.y | 1111 | ||||
-rw-r--r-- | mimeview/mimeview.c | 34 | ||||
-rw-r--r-- | mimeview/tests/testsuite.at | 2 | ||||
-rw-r--r-- | po/POTFILES.in | 6 |
20 files changed, 1357 insertions, 1180 deletions
diff --git a/configure.ac b/configure.ac index 452b611cc..4fa4ab65a 100644 --- a/configure.ac +++ b/configure.ac @@ -1568,6 +1568,7 @@ AC_CONFIG_FILES([ libmailutils/mailcap/Makefile libmailutils/mailer/Makefile libmailutils/mime/Makefile + libmailutils/mimetypes/Makefile libmailutils/msgset/Makefile libmailutils/opt/Makefile libmailutils/property/Makefile diff --git a/include/mailutils/Makefile.am b/include/mailutils/Makefile.am index cbbbfbf35..7d4f00400 100644 --- a/include/mailutils/Makefile.am +++ b/include/mailutils/Makefile.am @@ -77,6 +77,7 @@ pkginclude_HEADERS = \ message.h\ mh.h\ mime.h\ + mimetypes.h\ monitor.h\ msgset.h\ mu_auth.h\ diff --git a/include/mailutils/mailutils.h b/include/mailutils/mailutils.h index 32cb36e84..d53e1d0de 100644 --- a/include/mailutils/mailutils.h +++ b/include/mailutils/mailutils.h @@ -72,5 +72,6 @@ #include <mailutils/sockaddr.h> #include <mailutils/cidr.h> #include <mailutils/msgset.h> +#include <mailutils/mimetypes.h> /* EOF */ diff --git a/mimeview/mimeview.h b/include/mailutils/mimetypes.h index 867de1b20..1e75e81d0 100644 --- a/mimeview/mimeview.h +++ b/include/mailutils/mimetypes.h @@ -1,34 +1,32 @@ /* GNU Mailutils -- a suite of utilities for electronic mail Copyright (C) 2005-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 + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser 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, + This library 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. + GNU Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <mailutils/mailutils.h> -#include <mailutils/locus.h> -#include <mailutils/yyloc.h> -#include <fnmatch.h> +#ifndef _MAILUTILS_MIMETYPES_H +#define _MAILUTILS_MIMETYPES_H + +#include <mailutils/types.h> typedef struct mu_mimetypes *mu_mimetypes_t; -mu_mimetypes_t mimetypes_open (const char *name); +mu_mimetypes_t mu_mimetypes_open (const char *name); void mu_mimetypes_close (mu_mimetypes_t mt); const char *mu_mimetypes_stream_type (mu_mimetypes_t mt, char const *name, mu_stream_t str); const char *mu_mimetypes_file_type (mu_mimetypes_t mt, const char *file); const char *mu_mimetypes_fd_type (mu_mimetypes_t mt, const char *file, int fd); +#endif diff --git a/include/mailutils/stream.h b/include/mailutils/stream.h index f5c8a673e..608a355dd 100644 --- a/include/mailutils/stream.h +++ b/include/mailutils/stream.h @@ -431,7 +431,7 @@ int mu_file_stream_create (mu_stream_t *pstream, const char *filename, int flags struct mu_tempfile_hints; int mu_temp_file_stream_create (mu_stream_t *pstream, struct mu_tempfile_hints *hints, int flags); -int mu_fd_stream_create (mu_stream_t *pstream, char *filename, int fd, +int mu_fd_stream_create (mu_stream_t *pstream, char const *filename, int fd, int flags); #define MU_STDIN_FD 0 diff --git a/include/mailutils/sys/Makefile.am b/include/mailutils/sys/Makefile.am index f5db48ffc..b5f68e15a 100644 --- a/include/mailutils/sys/Makefile.am +++ b/include/mailutils/sys/Makefile.am @@ -45,6 +45,7 @@ sysinclude_HEADERS = \ message_stream.h\ message.h\ mime.h\ + mimetypes.h\ monitor.h\ msgset.h\ nullstream.h\ diff --git a/include/mailutils/sys/mimetypes.h b/include/mailutils/sys/mimetypes.h new file mode 100644 index 000000000..254d8167b --- /dev/null +++ b/include/mailutils/sys/mimetypes.h @@ -0,0 +1,102 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2009-2021 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _MAILUTILS_SYS_MIMETYPES_H +#define _MAILUTILS_SYS_MIMETYPES_H + +#include <regex.h> +#include <mailutils/locus.h> + +#define L_OR 0 +#define L_AND 1 + +enum node_type + { + true_node, + functional_node, + binary_node, + negation_node, + suffix_node + }; + +struct mimetypes_string +{ + char *ptr; + size_t len; +}; + +union argument +{ + struct mimetypes_string *string; + unsigned number; + int c; + regex_t rx; +}; + +struct input_file +{ + char const *name; + mu_stream_t stream; +}; + +typedef int (*builtin_t) (union argument *args, struct input_file *input); + +struct builtin_tab +{ + char *name; + char *args; + builtin_t handler; +}; + +struct node +{ + enum node_type type; + struct mu_locus_range loc; + union + { + struct + { + struct builtin_tab const *builtin; + union argument *args; + } function; + struct node *arg; + struct + { + int op; + struct node *arg1; + struct node *arg2; + } bin; + struct mimetypes_string suffix; + } v; +}; + +struct rule_tab +{ + char *type; + int priority; + struct mu_locus_range loc; + struct node *node; +}; + +struct mu_mimetypes +{ + mu_list_t rule_list; + mu_opool_t pool; +}; + +struct builtin_tab const *mu_mimetypes_builtin (char const *ident); + +#endif diff --git a/libmailutils/Makefile.am b/libmailutils/Makefile.am index 6e7fb09f6..501f2bba9 100644 --- a/libmailutils/Makefile.am +++ b/libmailutils/Makefile.am @@ -31,6 +31,7 @@ SUBDIRS = \ mailcap\ mailer\ mime\ + mimetypes\ msgset\ opt\ server\ @@ -68,6 +69,7 @@ libmailutils_la_LIBADD = \ mailcap/libmailcap.la\ mailer/libmailer.la\ mime/libmime.la\ + mimetypes/libmimetypes.la\ msgset/libmsgset.la\ opt/libopt.la\ property/libproperty.la\ diff --git a/libmailutils/diag/debcat b/libmailutils/diag/debcat index 600668085..6666222bc 100644 --- a/libmailutils/diag/debcat +++ b/libmailutils/diag/debcat @@ -31,6 +31,7 @@ mailbox mailer message mime +mimetypes mailcap property remote diff --git a/libmailutils/locus/linetrack.c b/libmailutils/locus/linetrack.c index 3cd5be6e0..88141574f 100644 --- a/libmailutils/locus/linetrack.c +++ b/libmailutils/locus/linetrack.c @@ -238,7 +238,7 @@ mu_linetrack_create (mu_linetrack_t *ret, free (trk); return rc; } - + *ret = trk; return 0; } diff --git a/libmailutils/mimetypes/.gitignore b/libmailutils/mimetypes/.gitignore new file mode 100644 index 000000000..4a207381a --- /dev/null +++ b/libmailutils/mimetypes/.gitignore @@ -0,0 +1,9 @@ +.deps +.gdbinit +.libs +Makefile +Makefile.in +grammar.c +grammar.h +grammar.output +lexer.c diff --git a/libmailutils/mimetypes/eval.c b/libmailutils/mimetypes/eval.c new file mode 100644 index 000000000..4babff4ef --- /dev/null +++ b/libmailutils/mimetypes/eval.c @@ -0,0 +1,551 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2009-2021 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <fnmatch.h> +#include <regex.h> +#include <inttypes.h> +#include <mailutils/stream.h> +#include <mailutils/locus.h> +#include <mailutils/diag.h> +#include <mailutils/cctype.h> +#include <mailutils/cstr.h> +#include <mailutils/stdstream.h> +#include <mailutils/list.h> +#include <mailutils/nls.h> +#include <mailutils/errno.h> +#include <mailutils/sys/mimetypes.h> +#include <mailutils/mimetypes.h> + +/* + * match("pattern") + * Pattern match on filename + */ +static int +b_match (union argument *args, struct input_file *input) +{ + return fnmatch (args[0].string->ptr, input->name, 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, struct input_file *input) +{ + int i; + int rc; + + rc = mu_stream_seek (input->stream, args[0].number, MU_SEEK_SET, NULL); + if (rc) + { + mu_debug (MU_DEBCAT_MIMETYPES, MU_DEBUG_ERROR, + ("mu_stream_seek: %s", mu_strerror (rc))); + return 0; + } + + for (i = 0; i < args[1].number; i++) + { + unsigned char c; + size_t n; + + rc = mu_stream_read (input->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, struct input_file *input) +{ + int i; + int rc; + + rc = mu_stream_seek (input->stream, args[0].number, MU_SEEK_SET, NULL); + if (rc) + { + mu_debug (MU_DEBCAT_MIMETYPES, MU_DEBUG_ERROR, + ("mu_stream_seek: %s", mu_strerror (rc))); + return 0; + } + + for (i = 0; i < args[1].number; i++) + { + unsigned char c; + size_t n; + + rc = mu_stream_read (input->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 input_file *input) +{ + struct mimetypes_string *str = args[1].string; + int i; + int rc; + + rc = mu_stream_seek (input->stream, args[0].number, MU_SEEK_SET, NULL); + if (rc) + { + mu_debug (MU_DEBCAT_MIMETYPES, MU_DEBUG_ERROR, + ("mu_stream_seek: %s", mu_strerror (rc))); + return 0; + } + + for (i = 0; i < str->len; i++) + { + char c; + size_t n; + + rc = mu_stream_read (input->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, struct input_file *input) +{ + int i; + struct mimetypes_string *str = args[1].string; + + int rc; + + rc = mu_stream_seek (input->stream, args[0].number, MU_SEEK_SET, NULL); + if (rc) + { + mu_debug (MU_DEBCAT_MIMETYPES, MU_DEBUG_ERROR, + ("mu_stream_seek: %s", mu_strerror (rc))); + return 0; + } + + for (i = 0; i < str->len; i++) + { + char c; + size_t n; + + rc = mu_stream_read (input->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, struct input_file *input, + void *sample, void *buf, size_t size) +{ + int rc; + size_t n; + + rc = mu_stream_seek (input->stream, args[0].number, MU_SEEK_SET, NULL); + if (rc) + { + mu_debug (MU_DEBCAT_MIMETYPES, MU_DEBUG_ERROR, + ("mu_stream_seek: %s", mu_strerror (rc))); + return 0; + } + + rc = mu_stream_read (input->stream, buf, size, &n); + if (rc) + { + mu_debug (MU_DEBCAT_MIMETYPES, MU_DEBUG_ERROR, + ("mu_stream_read: %s", mu_strerror (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, struct input_file *input) +{ + char val = args[1].number; + char buf; + return compare_bytes (args, input, &val, &buf, sizeof (buf)); +} + +/* + * short(offset,value) + * True if 16-bit integer is identical + * FIXME: Byte order + */ +static int +b_short (union argument *args, struct input_file *input) +{ + uint16_t val = args[1].number; + uint16_t buf; + return compare_bytes (args, input, &val, &buf, sizeof (buf)); +} + +/* + * int(offset,value) + * True if 32-bit integer is identical + * FIXME: Byte order + */ +static int +b_int (union argument *args, struct input_file *input) +{ + uint32_t val = args[1].number; + uint32_t buf; + return compare_bytes (args, input, &val, &buf, sizeof (buf)); +} + +/* + * locale("string") + * True if current locale matches string + */ +static int +b_locale (union argument *args, struct input_file *input) +{ + abort (); /* FIXME */ + return 0; +} + +/* + * contains(offset,range,"string") + * True if the range contains the string + */ +static int +b_contains (union argument *args, struct input_file *input) +{ + size_t i, count; + char *buf; + struct mimetypes_string *str = args[2].string; + int rc; + + rc = mu_stream_seek (input->stream, args[0].number, MU_SEEK_SET, NULL); + if (rc) + { + mu_debug (MU_DEBCAT_MIMETYPES, MU_DEBUG_ERROR, + ("mu_stream_seek: %s", mu_strerror (rc))); + return 0; + } + + if ((buf = malloc (args[1].number)) == NULL) + { + mu_debug (MU_DEBCAT_MIMETYPES, MU_DEBUG_ERROR, + ("malloc: %s", mu_strerror (rc))); + return 0; + } + + rc = mu_stream_read (input->stream, buf, args[1].number, &count); + if (rc) + { + mu_debug (MU_DEBCAT_MIMETYPES, MU_DEBUG_ERROR, + ("mu_stream_read: %s", mu_strerror (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, struct input_file *input) +{ + size_t count; + int rc; + char buf[MIME_MAX_BUFFER]; + + rc = mu_stream_seek (input->stream, args[0].number, MU_SEEK_SET, NULL); + if (rc) + { + mu_debug (MU_DEBCAT_MIMETYPES, MU_DEBUG_ERROR, + ("mu_stream_seek: %s", mu_strerror (rc))); + return 0; + } + + rc = mu_stream_read (input->stream, buf, sizeof buf - 1, &count); + if (rc) + { + mu_debug (MU_DEBCAT_MIMETYPES, MU_DEBUG_ERROR, + ("mu_stream_read: %s", mu_strerror (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 builtin_tab const * +mu_mimetypes_builtin (char const *ident) +{ + struct builtin_tab *p; + for (p = builtin_tab; p->name; p++) + if (strcmp (ident, p->name) == 0) + return p; + return NULL; +} + +static int +check_suffix (char *suf, struct input_file *input) +{ + char *p = strrchr (input->name, '.'); + 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_MIMETYPES, 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, struct input_file *input) +{ + int result; + + switch (root->type) + { + case true_node: + result = 1; + break; + + case functional_node: + result = root->v.function.builtin->handler (root->v.function.args, input); + break; + + case binary_node: + result = eval_rule (root->v.bin.arg1, input); + switch (root->v.bin.op) + { + case L_OR: + if (!result) + result |= eval_rule (root->v.bin.arg2, input); + break; + + case L_AND: + if (result) + result &= eval_rule (root->v.bin.arg2, input); + break; + + default: + abort (); + } + break; + + case negation_node: + result = !eval_rule (root->v.arg, input); + break; + + case suffix_node: + result = check_suffix (root->v.suffix.ptr, input); + 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, call_data)) + { + 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 * +mu_mimetypes_stream_type (mu_mimetypes_t mt, char const *name, mu_stream_t str) +{ + mu_list_t res = NULL; + const char *type = NULL; + struct input_file input; + + input.name = name; + input.stream = str; + + mu_stream_seek (str, 0, MU_SEEK_SET, NULL); + mu_list_map (mt->rule_list, evaluate, &input, 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; +} + +const char * +mu_mimetypes_file_type (mu_mimetypes_t mt, const char *file) +{ + int rc; + mu_stream_t str; + const char *res; + + rc = mu_file_stream_create (&str, file, MU_STREAM_READ); + if (rc) + { + mu_debug (MU_DEBCAT_MIMETYPES, MU_DEBUG_ERROR, + ("cannot open %s: %s", file, mu_strerror (rc))); + return NULL; + } + res = mu_mimetypes_stream_type (mt, file, str); + mu_stream_destroy (&str); + return res; +} + +const char * +mu_mimetypes_fd_type (mu_mimetypes_t mt, const char *file, int fd) +{ + int rc; + mu_stream_t str; + const char *res; + + rc = mu_fd_stream_create (&str, file, fd, MU_STREAM_READ); + if (rc) + { + mu_debug (MU_DEBCAT_MIMETYPES, MU_DEBUG_ERROR, + ("cannot open %s: %s", file, mu_strerror (rc))); + return NULL; + } + res = mu_mimetypes_stream_type (mt, file, str); + mu_stream_destroy (&str); + return res; +} diff --git a/libmailutils/mimetypes/grammar.y b/libmailutils/mimetypes/grammar.y new file mode 100644 index 000000000..31979002b --- /dev/null +++ b/libmailutils/mimetypes/grammar.y @@ -0,0 +1,627 @@ +%{ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2005-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 <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <mailutils/mimetypes.h> +#include <grammar.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 struct node *make_node (mu_mimetypes_t mth, + enum node_type type, + struct mu_locus_range const *loc); +static struct node *make_binary_node (mu_mimetypes_t mth, + int op, + struct node *left, struct node *rigth, + struct mu_locus_range const *loc); +static struct node *make_negation_node (mu_mimetypes_t mth, + struct node *p, + struct mu_locus_range const *loc); + +static struct node *make_suffix_node (mu_mimetypes_t mth, + struct mimetypes_string *suffix, + struct mu_locus_range const *loc); +static struct node *make_functional_node (mu_mimetypes_t mth, + char *ident, mu_list_t list, + struct mu_locus_range const *loc); + +static void * +mimetypes_malloc (mu_mimetypes_t mth, size_t size) +{ + mu_opool_alloc (mth->pool, size); + return mu_opool_finish (mth->pool, NULL); +} + +static struct mimetypes_string * +mimetypes_string_dup (mu_mimetypes_t mth, struct mimetypes_string *s) +{ + mu_opool_append (mth->pool, s, sizeof *s); + return mu_opool_finish (mth->pool, NULL); +} + +static void rule_destroy_item (void *ptr); + +%} + +%define api.pure full +%define api.prefix {mimetypes_yy} + +%code requires { +#include <stdio.h> +#include <regex.h> +#include <mailutils/stream.h> +#include <mailutils/cctype.h> +#include <mailutils/cstr.h> +#include <mailutils/locus.h> +#include <mailutils/yyloc.h> +#include <mailutils/opool.h> +#include <mailutils/list.h> +#include <mailutils/nls.h> +#include <mailutils/diag.h> +#include <mailutils/stdstream.h> +#include <mailutils/iterator.h> +#include <mailutils/util.h> +#include <mailutils/mimetypes.h> +#include <mailutils/sys/mimetypes.h> + +#define MIMETYPES_YYLTYPE struct mu_locus_range + +typedef void *yyscan_t; + +struct parser_control +{ + mu_linetrack_t trk; + struct mu_locus_point string_beg; + size_t errors; + mu_mimetypes_t mth; +}; + +} + +%code provides { +int mimetypes_yylex (MIMETYPES_YYSTYPE *lvalp, MIMETYPES_YYLTYPE *llocp, + yyscan_t yyscanner); +int mimetypes_yylex_init_extra (struct parser_control *, yyscan_t *); +int mimetypes_yylex_destroy (yyscan_t); +void mimetypes_yyerror (MIMETYPES_YYLTYPE const *llocp, + struct parser_control *pctl, yyscan_t scanner, + char const *fmt, ...) + MU_PRINTFLIKE(4,5); +int mimetypes_scanner_open (yyscan_t scanner, const char *name); + +void lex_next_rule (MIMETYPES_YYLTYPE *llocp, yyscan_t scanner); +} + +%parse-param { struct parser_control *pctl } { void *yyscanner } +%lex-param { yyscan_t yyscanner } +%initial-action { + /* + * yylloc is a local variable of yyparse. It is maintained in sync with + * the trk member of struct parser_control, and need to be deallocated + * before returning from yyparse. Since Bison does not provide any + * %final-action, the variable is deinited in the <<EOF>> scanner rule. + */ + mu_locus_range_init (&yylloc); +} +%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; +} + +%destructor { mu_lis |