93 files changed, 3448 insertions, 1234 deletions
@@ -1,4 +1,4 @@ -GNU mailutils NEWS -- history of user-visible changes. 2017-06-01 +GNU mailutils NEWS -- history of user-visible changes. 2017-06-16 Copyright (C) 2002-2017 Free Software Foundation, Inc. See the end of file for copying conditions. @@ -75,6 +75,13 @@ value is anything but "no", the settings from the global "tls" section will be used. In this case, it is an error if the global "tls" section is not defined. +* Source location API + +Libmailutils provides functions for keeping track of locations in +source files for diagnostic purposes. + +* Improve error reporting + * AM_GNU_MAILUTILS autoconf macro Required version must be literal string. diff --git a/am/bison.m4 b/am/bison.m4 new file mode 100644 index 0000000..875b326 --- a/dev/null +++ b/am/bison.m4 @@ -0,0 +1,11 @@ +# bison.m4 serial 1 +AC_DEFUN([MU_PROG_BISON], +[ + if test "x$ac_cv_prog_YACC" = x; then + AC_PROG_YACC + if ! $YACC --version 2>/dev/null | grep -q '^bison '; then + YACC="$SHELL $missing_dir/missing bison" + fi + fi +]) + diff --git a/am/flex.m4 b/am/flex.m4 new file mode 100644 index 0000000..58d2c4b --- a/dev/null +++ b/am/flex.m4 @@ -0,0 +1,12 @@ +# flex.m4 serial 1 +AC_DEFUN([MU_PROG_FLEX], +[ + if test "x$LEX" = x; then + AC_PROG_LEX + if ! $LEX --version 2>/dev/null | grep -q '^flex '; then + LEX="$SHELL $missing_dir/missing flex" + AC_SUBST([LEX_OUTPUT_ROOT], [lex.yy]) + AC_SUBST([LEXLIB], ['']) + fi +]) + diff --git a/comsat/action.c b/comsat/action.c index 6ff766a..24080a5 100644 --- a/comsat/action.c +++ b/comsat/action.c @@ -298,7 +298,7 @@ struct biffrc_environ mu_stream_t logstr; mu_message_t msg; mu_stream_t input; - struct mu_locus locus; + struct mu_locus_range locus; int use_default; char *errbuf; size_t errsize; @@ -523,16 +523,16 @@ eval_biffrc (struct biffrc_environ *env) ws.ws_comment = "#"; wsflags = MU_WRDSF_DEFFLAGS | MU_WRDSF_COMMENT; mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, - MU_IOCTL_LOGSTREAM_SET_LOCUS, &env->locus); + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, &env->locus); mu_stream_ioctl (env->logstr, MU_IOCTL_LOGSTREAM, - MU_IOCTL_LOGSTREAM_SET_LOCUS, &env->locus); + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, &env->locus); while (mu_stream_getline (env->input, &stmt, &size, &n) == 0 && n > 0) { if (strncmp (stmt, "#line ", 6) == 0) { char *p; - env->locus.mu_line = strtoul (stmt + 6, &p, 10); + env->locus.beg.mu_line = strtoul (stmt + 6, &p, 10); if (*p != '\n') { report_error (env, _("malformed #line directive: %s")); @@ -541,10 +541,10 @@ eval_biffrc (struct biffrc_environ *env) { mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_SET_LOCUS_LINE, - &env->locus.mu_line); + &env->locus.beg.mu_line); mu_stream_ioctl (env->logstr, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_SET_LOCUS_LINE, - &env->locus.mu_line); + &env->locus.beg.mu_line); } continue; } @@ -600,9 +600,9 @@ eval_biffrc (struct biffrc_environ *env) free (stmt); mu_wordsplit_free (&ws); mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, - MU_IOCTL_LOGSTREAM_SET_LOCUS, NULL); + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, NULL); mu_stream_ioctl (env->logstr, MU_IOCTL_LOGSTREAM, - MU_IOCTL_LOGSTREAM_SET_LOCUS, NULL); + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, NULL); } void @@ -645,13 +645,14 @@ run_user_action (const char *device, mu_message_t msg) if (!rcname) { mu_diag_funcall (MU_DIAG_ERROR, "mu_make_file_name", NULL, ENOMEM); - env.locus.mu_file = BIFF_RC; + env.locus.beg.mu_file = BIFF_RC; } else - env.locus.mu_file = rcname; + env.locus.beg.mu_file = rcname; - env.locus.mu_line = 1; - env.locus.mu_col = 0; + env.locus.beg.mu_line = 1; + env.locus.beg.mu_col = 0; + memset (&env.locus.end, 0, sizeof env.locus.end); env.use_default = 0; eval_biffrc (&env); mu_stream_destroy (&env.input); @@ -679,9 +680,9 @@ run_user_action (const char *device, mu_message_t msg) } else { - env.locus.mu_file = "<default>"; - env.locus.mu_line = 1; - env.locus.mu_col = 0; + env.locus.beg.mu_file = "<default>"; + env.locus.beg.mu_line = 1; + env.locus.beg.mu_col = 0; eval_biffrc (&env); mu_stream_destroy (&env.input); } diff --git a/configure.ac b/configure.ac index 3f84188..86bc16f 100644 --- a/configure.ac +++ b/configure.ac @@ -71,6 +71,9 @@ AC_SUBST(MU_LIB_COMMON_INCLUDES,'-I${top_builddir} -I${top_srcdir}/include -I${ AC_SUBST(MU_APP_COMMON_INCLUDES,'-I${srcdir} -I${top_srcdir}/include -I${top_srcdir}/lib -I${top_srcdir}/lib/gnu -I${top_builddir}/lib/gnu -I${top_builddir} -I${top_builddir}/include') +# Use our replacement for the ylwrap tool +AC_SUBST([MU_YLWRAP],'$(mu_aux_dir)/gylwrap --') + dnl Check for programs AC_PROG_CC AM_PROG_CC_C_O @@ -80,8 +83,8 @@ AC_PROG_INSTALL AC_PROG_LN_S AC_LIBTOOL_DLOPEN AC_PROG_LIBTOOL -AC_PROG_YACC -AM_PROG_LEX +MU_PROG_BISON +MU_PROG_LEX AM_PROG_LIBTOOL ## Predefine several variables used to display configuration status @@ -1495,6 +1498,7 @@ AC_CONFIG_FILES([ libmailutils/filter/Makefile libmailutils/imapio/Makefile libmailutils/list/Makefile + libmailutils/locus/Makefile libmailutils/mailbox/Makefile libmailutils/mailer/Makefile libmailutils/mime/Makefile diff --git a/include/mailutils/Makefile.am b/include/mailutils/Makefile.am index 6b83274..95de7e7 100644 --- a/include/mailutils/Makefile.am +++ b/include/mailutils/Makefile.am @@ -73,6 +73,7 @@ pkginclude_HEADERS = \ kwd.h\ ldap.h\ list.h\ + locus.h\ locker.h\ log.h\ mailbox.h\ @@ -116,7 +117,8 @@ pkginclude_HEADERS = \ types.h\ url.h\ version.h\ - wordsplit.h + wordsplit.h\ + yyloc.h if MU_COND_SUPPORT_CXX CPP_DIR = cpp diff --git a/include/mailutils/assoc.h b/include/mailutils/assoc.h index a8f9845..930ff2d 100644 --- a/include/mailutils/assoc.h +++ b/include/mailutils/assoc.h @@ -37,6 +37,8 @@ int mu_assoc_install (mu_assoc_t assoc, const char *name, void *value); int mu_assoc_lookup_ref (mu_assoc_t assoc, const char *name, void *dataptr); int mu_assoc_install_ref (mu_assoc_t assoc, const char *name, void *pval); +int mu_assoc_install_ref2 (mu_assoc_t assoc, const char *name, + void *ret_val, const char **ret_name); int mu_assoc_get_iterator (mu_assoc_t assoc, mu_iterator_t *piterator); int mu_assoc_remove (mu_assoc_t assoc, const char *name); diff --git a/include/mailutils/auth.h b/include/mailutils/auth.h index 04dbfd3..998779b 100644 --- a/include/mailutils/auth.h +++ b/include/mailutils/auth.h @@ -20,6 +20,7 @@ #define _MAILUTILS_AUTH_H #include <mailutils/types.h> +#include <mailutils/locus.h> #ifdef __cplusplus extern "C" { @@ -77,7 +78,7 @@ int mu_wicket_set_get_ticket (mu_wicket_t wicket, int mu_file_wicket_create (mu_wicket_t *pwicket, const char *filename); struct mu_debug_locus; -int mu_wicket_stream_match_url (mu_stream_t stream, struct mu_locus *loc, +int mu_wicket_stream_match_url (mu_stream_t stream, struct mu_locus_point *loc, mu_url_t url, int parse_flags, mu_url_t *pticket_url); int mu_wicket_file_match_url (const char *name, mu_url_t url, diff --git a/include/mailutils/cfg.h b/include/mailutils/cfg.h index 8ccd7f4..de84af6 100644 --- a/include/mailutils/cfg.h +++ b/include/mailutils/cfg.h @@ -23,6 +23,7 @@ #include <mailutils/debug.h> #include <mailutils/opool.h> #include <mailutils/util.h> +#include <mailutils/locus.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> @@ -64,7 +65,7 @@ enum mu_cfg_node_type struct mu_cfg_node { - struct mu_locus locus; + struct mu_locus_range locus; enum mu_cfg_node_type type; char *tag; mu_config_value_t *label; @@ -119,8 +120,6 @@ int mu_cfg_tree_union (mu_cfg_tree_t **pa, mu_cfg_tree_t **pb); int mu_cfg_tree_postprocess (mu_cfg_tree_t *tree, struct mu_cfg_parse_hints *hints); -extern struct mu_locus mu_cfg_locus; - mu_opool_t mu_cfg_lexer_pool (void); #define MU_CFG_ITER_OK 0 @@ -285,7 +284,7 @@ int mu_cfg_parse_file (mu_cfg_tree_t **return_tree, const char *file, int mu_cfg_tree_create (struct mu_cfg_tree **ptree); mu_cfg_node_t *mu_cfg_tree_create_node (struct mu_cfg_tree *tree, enum mu_cfg_node_type type, - const struct mu_locus *loc, + const struct mu_locus_range *loc, const char *tag, const char *label, mu_list_t nodelist); diff --git a/include/mailutils/debug.h b/include/mailutils/debug.h index 647a058..8ec2e88 100644 --- a/include/mailutils/debug.h +++ b/include/mailutils/debug.h @@ -106,7 +106,7 @@ int mu_debug_get_iterator (mu_iterator_t *piterator, int skipunset); if (mu_debug_line_info) \ { \ mu_debug_log_begin ("\033X<%d>%s:%d: ", \ - MU_LOGMODE_LOCUS, __FILE__, __LINE__); \ + MU_LOGMODE_LOCUS, __FILE__, __LINE__); \ mu_debug_log_end s; \ } \ else \ diff --git a/include/mailutils/diag.h b/include/mailutils/diag.h index 3b57aae..03a0eac 100644 --- a/include/mailutils/diag.h +++ b/include/mailutils/diag.h @@ -24,6 +24,7 @@ #include <mailutils/types.h> #include <mailutils/log.h> #include <mailutils/debug.h> +#include <mailutils/locus.h> #ifdef __cplusplus extern "C" { @@ -51,8 +52,10 @@ void mu_diag_cont_printf (const char *fmt, ...) MU_PRINTFLIKE(1,2); void mu_diag_voutput (int, const char *, va_list); void mu_diag_output (int, const char *, ...) MU_PRINTFLIKE(2,3); -void mu_diag_at_locus (int level, struct mu_locus const *loc, - const char *fmt, ...); +void mu_diag_at_locus_point (int level, struct mu_locus_point const *loc, + const char *fmt, ...); +void mu_diag_at_locus_range (int level, struct mu_locus_range const *loc, + const char *fmt, ...); int mu_diag_level_to_syslog (int level); const char *mu_diag_level_to_string (int level); diff --git a/include/mailutils/locus.h b/include/mailutils/locus.h new file mode 100644 index 0000000..f8efa13 --- a/dev/null +++ b/include/mailutils/locus.h @@ -0,0 +1,111 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2017 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 of the License, 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 this library. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _MAILUTILS_LOCUS_H +#define _MAILUTILS_LOCUS_H + +#include <string.h> +#include <stdarg.h> + +struct mu_locus_point +{ + char const *mu_file; + unsigned mu_line; + unsigned mu_col; +}; + +#define MU_LOCUS_POINT_INITIALIZER { NULL, 0, 0 } + +struct mu_locus_range +{ + struct mu_locus_point beg; + struct mu_locus_point end; +}; + +#define MU_LOCUS_RANGE_INITIALIZER \ + { MU_LOCUS_POINT_INITIALIZER, MU_LOCUS_POINT_INITIALIZER } + +typedef struct mu_linetrack *mu_linetrack_t; + +struct mu_linetrack_stat +{ + unsigned start_line; /* Start line number (1-based) */ + size_t n_lines; /* Number of lines, including the recent (incomplete) + one */ + size_t n_chars; /* Total number of characters */ +}; + +int mu_ident_ref (char const *name, char const **refname); +int mu_ident_deref (char const *); +void mu_ident_stat (mu_stream_t str); + +int mu_locus_point_set_file (struct mu_locus_point *pt, const char *filename); +void mu_locus_point_init (struct mu_locus_point *pt); +void mu_locus_point_deinit (struct mu_locus_point *pt); +int mu_locus_point_copy (struct mu_locus_point *dest, + struct mu_locus_point const *src); + +void mu_locus_range_init (struct mu_locus_range *dest); +int mu_locus_range_copy (struct mu_locus_range *dest, + struct mu_locus_range const *src); +void mu_locus_range_deinit (struct mu_locus_range *lr); + +static inline int +mu_locus_point_same_file (struct mu_locus_point const *a, + struct mu_locus_point const *b) +{ + return a->mu_file == b->mu_file + || (a->mu_file && b->mu_file && strcmp(a->mu_file, b->mu_file) == 0); +} + +static inline int +mu_locus_point_same_line (struct mu_locus_point const *a, + struct mu_locus_point const *b) +{ + return mu_locus_point_same_file (a, b) && a->mu_line == b->mu_line; +} + +int mu_linetrack_create (mu_linetrack_t *ret, + char const *file_name, size_t max_lines); +int mu_linetrack_rebase (mu_linetrack_t trk, struct mu_locus_point const *pt); +void mu_linetrack_free (mu_linetrack_t trk); +void mu_linetrack_destroy (mu_linetrack_t *trk); +void mu_linetrack_advance (mu_linetrack_t trk, + struct mu_locus_range *loc, + char const *text, size_t leng); +int mu_linetrack_retreat (mu_linetrack_t trk, size_t n); + +int mu_linetrack_locus (struct mu_linetrack *trk, struct mu_locus_point *lp); +int mu_linetrack_stat (mu_linetrack_t trk, struct mu_linetrack_stat *st); +int mu_linetrack_at_bol (struct mu_linetrack *trk); + +void mu_stream_print_locus_point (mu_stream_t stream, + struct mu_locus_point const *lpt); +void mu_stream_print_locus_range (mu_stream_t stream, + struct mu_locus_range const *loc); + +void mu_stream_vlprintf (mu_stream_t stream, + struct mu_locus_range const *loc, + char const *fmt, va_list ap); +void mu_stream_lprintf (mu_stream_t stream, + struct mu_locus_range const *loc, + char const *fmt, ...); +void mu_lrange_debug (struct mu_locus_range const *loc, + char const *fmt, ...); + + +#endif diff --git a/include/mailutils/log.h b/include/mailutils/log.h index 53cccd2..34aeb63 100644 --- a/include/mailutils/log.h +++ b/include/mailutils/log.h @@ -32,8 +32,8 @@ extern "C" { #define MU_LOG_ALERT 6 #define MU_LOG_EMERG 7 -#define MU_LOGMODE_SEVERITY 0x0001 -#define MU_LOGMODE_LOCUS 0x0002 +#define MU_LOGMODE_SEVERITY 0x0001 +#define MU_LOGMODE_LOCUS 0x0002 int mu_log_stream_create (mu_stream_t *, mu_stream_t); int mu_syslog_stream_create (mu_stream_t *, int); diff --git a/include/mailutils/mailutils.h b/include/mailutils/mailutils.h index be4985e..d5aadf8 100644 --- a/include/mailutils/mailutils.h +++ b/include/mailutils/mailutils.h @@ -36,6 +36,7 @@ #include <mailutils/header.h> #include <mailutils/iterator.h> #include <mailutils/kwd.h> +#include <mailutils/locus.h> #include <mailutils/sieve.h> #include <mailutils/list.h> #include <mailutils/locker.h> diff --git a/include/mailutils/sieve.h b/include/mailutils/sieve.h index 8d9c2c1..63d81c7 100644 --- a/include/mailutils/sieve.h +++ b/include/mailutils/sieve.h @@ -23,6 +23,7 @@ #include <stdarg.h> #include <mailutils/mailutils.h> #include <mailutils/cli.h> +#include <mailutils/locus.h> #ifdef __cplusplus extern "C" { @@ -87,6 +88,7 @@ typedef struct { mu_sieve_data_type type; char *tag; + struct mu_locus_range locus; union mu_sieve_value_storage v; } mu_sieve_value_t; @@ -162,7 +164,9 @@ void mu_sieve_reclaim_default (void *p); void mu_sieve_reclaim_value (void *p); size_t mu_sieve_value_create (mu_sieve_machine_t mach, - mu_sieve_data_type type, void *data); + mu_sieve_data_type type, + struct mu_locus_range const *locus, + void *data); /* Symbol space functions */ mu_sieve_registry_t *mu_sieve_registry_add (mu_sieve_machine_t mach, @@ -287,7 +291,7 @@ int mu_sieve_set_dry_run (mu_sieve_machine_t mach, int val); void mu_sieve_get_argc (mu_sieve_machine_t mach, size_t *args, size_t *tags); mu_mailer_t mu_sieve_get_mailer (mu_sieve_machine_t mach); -int mu_sieve_get_locus (mu_sieve_machine_t mach, struct mu_locus *); +int mu_sieve_get_locus (mu_sieve_machine_t mach, struct mu_locus_range *); char *mu_sieve_get_daemon_email (mu_sieve_machine_t mach); const char *mu_sieve_get_identifier (mu_sieve_machine_t mach); @@ -322,9 +326,13 @@ const char *mu_sieve_type_str (mu_sieve_data_type type); /* Principal entry points */ int mu_sieve_compile (mu_sieve_machine_t mach, const char *name); +int mu_sieve_compile_text (mu_sieve_machine_t mach, + const char *buf, size_t bufsize, + struct mu_locus_point const *pt); int mu_sieve_compile_buffer (mu_sieve_machine_t mach, const char *buf, int bufsize, - const char *fname, int line); + const char *fname, int line) + MU_DEPRECATED; int mu_sieve_mailbox (mu_sieve_machine_t mach, mu_mailbox_t mbox); int mu_sieve_message (mu_sieve_machine_t mach, mu_message_t message); int mu_sieve_disass (mu_sieve_machine_t mach); diff --git a/include/mailutils/stream.h b/include/mailutils/stream.h index f7f58ba..4e82b92 100644 --- a/include/mailutils/stream.h +++ b/include/mailutils/stream.h @@ -83,7 +83,7 @@ enum mu_buffer_type /* Opcodes common for various families */ #define MU_IOCTL_OP_GET 0 #define MU_IOCTL_OP_SET 1 - + /* Opcodes for MU_IOCTL_PROGSTREAM */ #define MU_IOCTL_PROG_STATUS 0 #define MU_IOCTL_PROG_PID 1 @@ -106,11 +106,21 @@ enum mu_buffer_type */ #define MU_IOCTL_LOGSTREAM_GET_SEVERITY 0 #define MU_IOCTL_LOGSTREAM_SET_SEVERITY 1 + + /* The following two subcommands are deprecated and provided for + backward compatibility. Please use the MU_IOCTL_LOGSTREAM_GET_LOCUS_RANGE + and MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE instead. */ /* Get or set locus. - Arg: struct mu_locus * + Arg: struct mu_locus_DEPRECATED * */ -#define MU_IOCTL_LOGSTREAM_GET_LOCUS 2 -#define MU_IOCTL_LOGSTREAM_SET_LOCUS 3 +#define MU_IOCTL_LOGSTREAM_GET_LOCUS_DEPRECATED 2 +#define MU_IOCTL_LOGSTREAM_SET_LOCUS_DEPRECATED 3 + +int mu_ioctl_logstream_get_locus_deprecated (void) MU_DEPRECATED; +#define MU_IOCTL_LOGSTREAM_GET_LOCUS mu_ioctl_logstream_get_locus_deprecated () +int mu_ioctl_logstream_set_locus_deprecated (void) MU_DEPRECATED; +#define MU_IOCTL_LOGSTREAM_SET_LOCUS mu_ioctl_logstream_set_locus_deprecated () + /* Get or set log mode. Arg: int * */ @@ -158,6 +168,15 @@ enum mu_buffer_type Arg: mu_stream_t* */ #define MU_IOCTL_LOGSTREAM_CLONE 14 + + /* Get locus range. + Arg: struct mu_locus_range * + */ +#define MU_IOCTL_LOGSTREAM_GET_LOCUS_RANGE 15 + /* Set locus range. + Arg: struct mu_locus_range * + */ +#define MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE 16 /* Opcodes for MU_IOCTL_XSCRIPTSTREAM */ /* Swap transcript levels. diff --git a/include/mailutils/sys/logstream.h b/include/mailutils/sys/logstream.h index 8bb1c1e..d480110 100644 --- a/include/mailutils/sys/logstream.h +++ b/include/mailutils/sys/logstream.h @@ -19,6 +19,7 @@ #include <mailutils/types.h> #include <mailutils/sys/stream.h> +#include <mailutils/locus.h> struct _mu_log_stream { @@ -30,7 +31,7 @@ struct _mu_log_stream int logmode; /* Mode flags */ int sevmask; /* Mask out the output of severity level for these severities. */ - struct mu_locus locus; /* Location */ + struct mu_locus_range locrange; /* Location in the source file */ }; void _mu_log_stream_setup (struct _mu_log_stream *sp, mu_stream_t transport); diff --git a/include/mailutils/types.hin b/include/mailutils/types.hin index 2a0ee17..e1a9ac4 100644 --- a/include/mailutils/types.hin +++ b/include/mailutils/types.hin @@ -149,13 +149,25 @@ typedef unsigned int mu_debug_level_t; #define MU_DEFAULT_RECORD _MU_DEFAULT_RECORD_ -struct mu_locus +/* This structure used to be called mu_locus in mailutils up to + 3.2.91-46 [release-3.2-71-g719e64a]. It is superseded by + structs mu_locus_point and mu_locus_range, defined in + <mailutils/locus.h>. + + This definition is provided for backward compatibility. Authors are + urged to switch to the new API as soon as their time permits. + + Please see http://mailutils.org/wiki/Source_location_API#Deprecated_interface + for detailed guidelines. +*/ +struct mu_locus_DEPRECATED { char *mu_file; unsigned mu_line; unsigned mu_col; }; - +#define mu_locus mu_locus_DEPRECATED + #ifdef __cplusplus } #endif diff --git a/include/mailutils/yyloc.h b/include/mailutils/yyloc.h new file mode 100644 index 0000000..951ccf0 --- a/dev/null +++ b/include/mailutils/yyloc.h @@ -0,0 +1,46 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2017 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 of the License, 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 this library. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _MAILUTILS_YYLOC_H +#define _MAILUTILS_YYLOC_H + +void mu_file_print_locus_point (FILE *, + struct mu_locus_point const *lpt); +void mu_file_print_locus_range (FILE *, + struct mu_locus_range const *loc); + +#define YYLTYPE struct mu_locus_range +#define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + { \ + if (N) \ + { \ + (Current).beg = YYRHSLOC(Rhs, 1).beg; \ + (Current).end = YYRHSLOC(Rhs, N).end; \ + } \ + else \ + { \ + (Current).beg = YYRHSLOC(Rhs, 0).end; \ + (Current).end = (Current).beg; \ + } \ + } while (0) + +#define YY_LOCATION_PRINT(File, Loc) \ + mu_file_print_locus_range (File, &(Loc)) + +#endif + diff --git a/libmailutils/Makefile.am b/libmailutils/Makefile.am index a105f38..22aaef6 100644 --- a/libmailutils/Makefile.am +++ b/libmailutils/Makefile.am @@ -18,7 +18,7 @@ SUBDIRS = \ auth base address list sockaddr cidr cfg cli diag\ - filter mailbox mailer mime msgset opt server string stream stdstream\ + filter locus mailbox mailer mime msgset opt server string stream stdstream\ property url imapio datetime . tests lib_LTLIBRARIES = libmailutils.la @@ -39,6 +39,7 @@ libmailutils_la_LIBADD = \ filter/libfilter.la\ imapio/libimapio.la\ list/liblist.la\ + locus/liblocus.la\ mailbox/libmailbox.la\ mailer/libmailer.la\ mime/libmime.la\ diff --git a/libmailutils/base/.gitignore b/libmailutils/base/.gitignore index e3e0cf0..0b756b1 100644 --- a/libmailutils/base/.gitignore +++ b/libmailutils/base/.gitignore @@ -1 +1,2 @@ parsedate.c + diff --git a/libmailutils/base/Makefile.am b/libmailutils/base/Makefile.am index 437dbbe..0936a2d 100644 --- a/libmailutils/base/Makefile.am +++ b/libmailutils/base/Makefile.am @@ -54,7 +54,7 @@ libbase_la_SOURCES = \ observer.c\ onexit.c\ opool.c\ - parsedate.c\ + parsedate.y\ permstr.c\ registrar.c\ refcount.c\ @@ -82,17 +82,10 @@ AM_CPPFLAGS = \ -DLOCALEDIR=\"$(localedir)\" -YLWRAP = $(SHELL) $(mu_aux_dir)/gylwrap -AM_YFLAGS=-vt -AM_LFLAGS=-dp +YLWRAP = @MU_YLWRAP@ +EXTRA_DIST = gylwrap.conf +AM_YFLAGS= +AM_LFLAGS= -EXTRA_DIST = parsedate.y - -BUILT_SOURCES = parsedate.c - -parsedate.c: $(srcdir)/parsedate.y - $(YLWRAP) "$(YACC) $(AM_YFLAGS)" $< \ - y.tab.c parsedate.c y.output parsedate.y.output \ - -- -yy pd_yy diff --git a/libmailutils/base/assoc.c b/libmailutils/base/assoc.c index b0e353d..a597ca4 100644 --- a/libmailutils/base/assoc.c +++ b/libmailutils/base/assoc.c @@ -387,7 +387,9 @@ mu_assoc_lookup_ref (mu_assoc_t assoc, const char *name, void *dataptr) } int -mu_assoc_install_ref (mu_assoc_t assoc, const char *name, void *pval) +mu_assoc_install_ref2 (mu_assoc_t assoc, const char *name, + void *ret_val, + const char **ret_name) { int rc; int inst; @@ -425,11 +427,20 @@ mu_assoc_install_ref (mu_assoc_t assoc, const char *name, void *pval) assoc_elem_link (assoc, idx); } - *(void**)pval = &assoc->tab[idx]->data; + *(void**)ret_val = &assoc->tab[idx]->data; + if (ret_name) + *ret_name = assoc->tab[idx]->name; + return inst ? 0 : MU_ERR_EXISTS; } int +mu_assoc_install_ref (mu_assoc_t assoc, const char *name, void *pval) +{ + return mu_assoc_install_ref2 (assoc, name, pval, NULL); +} + +int mu_assoc_remove (mu_assoc_t assoc, const char *name) { int rc; diff --git a/libmailutils/base/copyfile.c b/libmailutils/base/copyfile.c index 9a72228..16518ab 100644 --- a/libmailutils/base/copyfile.c +++ b/libmailutils/base/copyfile.c @@ -163,7 +163,7 @@ copy_regular_file (const char *srcpath, const char *dstpath, int flags, rc = mu_stream_ioctl (dst, MU_IOCTL_TRANSPORT, MU_IOCTL_OP_GET, trans); if (rc == 0) { - if (fchmod ((int) trans[0], mode)) + if (fchmod ((int) (intptr_t) trans[0], mode)) { mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, (_("%s: cannot chmod: %s"), @@ -193,7 +193,7 @@ copy_regular_file (const char *srcpath, const char *dstpath, int flags, if (gid != -1) { - if (fchown ((int) trans[0], uid, gid)) + if (fchown ((int) (intptr_t) trans[0], uid, gid)) { mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, (_("%s: cannot chown to %lu.%lu: %s"), diff --git a/libmailutils/base/gylwrap.conf b/libmailutils/base/gylwrap.conf new file mode 100644 index 0000000..33b8c12 --- a/dev/null +++ b/libmailutils/base/gylwrap.conf @@ -0,0 +1,3 @@ +# Configuration settings for gylwrap. +# See ../../mu-aux/gylwrap --help, for details. +yyrepl = pd_yy diff --git a/libmailutils/base/wicket.c b/libmailutils/base/wicket.c index bb5ad2e..1acecff 100644 --- a/libmailutils/base/wicket.c +++ b/libmailutils/base/wicket.c @@ -248,7 +248,7 @@ _file_wicket_get_ticket (mu_wicket_t wicket, void *data, } int -mu_wicket_stream_match_url (mu_stream_t stream, struct mu_locus *loc, +mu_wicket_stream_match_url (mu_stream_t stream, struct mu_locus_point *loc, mu_url_t url, int parse_flags, mu_url_t *pticket_url) { @@ -329,7 +329,7 @@ mu_wicket_file_match_url (const char *name, mu_url_t url, { mu_stream_t stream; int rc; - struct mu_locus loc; + struct mu_locus_point loc; rc = mu_file_stream_create (&stream, name, MU_STREAM_READ); if (rc) diff --git a/libmailutils/cfg/.gitignore b/libmailutils/cfg/.gitignore index 8993e60..97bc813 100644 --- a/libmailutils/cfg/.gitignore +++ b/libmailutils/cfg/.gitignore @@ -1,3 +1,4 @@ lexer.c parser.c parser.h +parser.output diff --git a/libmailutils/cfg/Makefile.am b/libmailutils/cfg/Makefile.am index d2d3f44..eb299fa 100644 --- a/libmailutils/cfg/Makefile.am +++ b/libmailutils/cfg/Makefile.am @@ -20,8 +20,8 @@ noinst_LTLIBRARIES = libcfg.la libcfg_la_SOURCES = \ driver.c\ format.c\ - lexer.c\ - parser.c + lexer.l\ + parser.y localedir = $(datadir)/locale AM_CPPFLAGS = \ @@ -29,25 +29,15 @@ AM_CPPFLAGS = \ -DSYSCONFDIR=\"$(sysconfdir)\"\ -DLOCALEDIR=\"$(localedir)\" - EXTRA_DIST = \ lexer.l\ parser.y\ - parser.h + parser.h\ + gylwrap.conf BUILT_SOURCES = parser.c parser.h lexer.c -YLWRAP = $(SHELL) $(mu_aux_dir)/gylwrap -AM_YFLAGS=-vt +YLWRAP = @MU_YLWRAP@ +AM_YFLAGS=-vdt AM_LFLAGS=-dp -parser.c parser.h: $(srcdir)/parser.y - $(YLWRAP) "$(YACC) $(AM_YFLAGS) -d" $< \ - y.tab.c parser.c y.tab.h parser.h \ - y.output parser.y.output \ - -- -yy mu_cfg_yy - -lexer.c: $(srcdir)/lexer.l parser.h - $(YLWRAP) "$(LEX) $(AM_LFLAGS) $(LFLAGS)" \ - $(srcdir)/lexer.l lex.yy.c lexer.c \ - -- -yy mu_cfg_yy diff --git a/libmailutils/cfg/format.c b/libmailutils/cfg/format.c index a751c57..78d84b1 100644 --- a/libmailutils/cfg/format.c +++ b/libmailutils/cfg/format.c @@ -152,10 +152,10 @@ format_node (const mu_cfg_node_t *node, void *data) { struct tree_print *tp = data; - if ((tp->flags & MU_CF_FMT_LOCUS) && node->locus.mu_file) + if ((tp->flags & MU_CF_FMT_LOCUS) && node->locus.beg.mu_file) mu_stream_printf (tp->stream, "# %lu \"%s\"\n", - (unsigned long) node->locus.mu_line, - node->locus.mu_file); + (unsigned long) node->locus.beg.mu_line, + node->locus.beg.mu_file); format_level (tp->stream, tp->level); switch (node->type) { diff --git a/libmailutils/cfg/gylwrap.conf b/libmailutils/cfg/gylwrap.conf new file mode 100644 index 0000000..4a93e6f --- a/dev/null +++ b/libmailutils/cfg/gylwrap.conf @@ -0,0 +1,4 @@ +# Configuration settings for gylwrap. +# See ../../mu-aux/gylwrap --help, for details. + +yyrepl = mu_cfg_yy diff --git a/libmailutils/cfg/lexer.l b/libmailutils/cfg/lexer.l index 88f2486..0465196 100644 --- a/libmailutils/cfg/lexer.l +++ b/libmailutils/cfg/lexer.l @@ -38,7 +38,10 @@ #include <mailutils/cfg.h> #include <mailutils/list.h> #include <mailutils/util.h> - +#include <mailutils/locus.h> +#include <mailutils/stream.h> +#include <mailutils/stdstream.h> +#include <mailutils/yyloc.h> #include "parser.h" void _mu_line_begin (void); @@ -66,7 +69,16 @@ static int (*char_to_strip)(char); /* Strip matching characters of each static int isemptystr(int off); static mu_opool_t pool; - +static mu_linetrack_t trk; +static struct mu_locus_point string_beg; +#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); %} %option nounput @@ -83,7 +95,7 @@ P [1-9][0-9]* "/*" BEGIN(COMMENT); <COMMENT>[^*\n]* /* eat anything that's not a '*' */ <COMMENT>"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */ -<COMMENT>\n ++mu_cfg_locus.mu_line; +<COMMENT>\n ; <COMMENT>"*"+"/" BEGIN (INITIAL); /* End-of-line comments */ #debug=.*\n { @@ -91,9 +103,9 @@ P [1-9][0-9]* mu_cfg_set_debug (); mu_cfg_set_lex_debug (); } -#.*\n { mu_cfg_locus.mu_line++; } +#.*\n ; #.* /* end-of-file comment */; -"//".*\n { mu_cfg_locus.mu_line++; } +"//".*\n ; "//".* /* end-of-file comment */; /* Identifiers */ <INITIAL>{ID} { @@ -113,6 +125,7 @@ P [1-9][0-9]* return MU_TOK_QSTRING; } \"[^\\"\n]*\\. | \"[^\\"\n]*\\\n { BEGIN (STR); + mu_locus_point_copy (&string_beg, &yylloc.beg); _mu_line_begin (); _mu_line_add_unescape_last (yytext + 1, yyleng - 1); } <STR>[^\\"\n]*\\. | @@ -121,6 +134,10 @@ P [1-9][0-9]* if (yyleng > 1) _mu_line_add (yytext, yyleng - 1); yylval.string = _mu_line_finish (); + + mu_locus_point_copy (&yylloc.beg, &string_beg); + mu_locus_point_deinit (&string_beg); + return MU_TOK_QSTRING; } /* Multiline strings */ "<<"(-" "?)?\\?{ID}[ \t]*#.*\n | @@ -130,8 +147,8 @@ P [1-9][0-9]* "<<"(-" "?)?\"{ID}\"[ \t]*"//".*\n | "<<"(-" "?)?\"{ID}\"[ \t]*\n { BEGIN (ML); + mu_locus_point_copy (&string_beg, &yylloc.beg); multiline_begin (yytext+2); - mu_cfg_locus.mu_line++; } <ML>.*\n { char *p = multiline_strip_tabs (yytext); @@ -142,21 +159,21 @@ P [1-9][0-9]* multiline_delimiter = NULL; BEGIN (INITIAL); yylval.string = multiline_finish (); + + mu_locus_point_copy (&yylloc.beg, &string_beg); + mu_locus_point_deinit (&string_beg); + /* FIXME: Adjust yylloc.end without retreating trk */ return MU_TOK_MSTRING; } - mu_cfg_locus.mu_line++; multiline_add (p); } {WS} ; /* Other tokens */ -\n { mu_cfg_locus.mu_line++; } +\n ; [,;{}()] return yytext[0]; . { if (mu_isprint (yytext[0])) - mu_diag_at_locus (MU_LOG_ERROR, &mu_cfg_locus, - _("stray character %c"), yytext[0]); + mu_error (_("stray character %c"), yytext[0]); else - mu_diag_at_locus (MU_LOG_ERROR, &mu_cfg_locus, - _("stray character \\%03o"), - (unsigned char) yytext[0]); + mu_error (_("stray character \\%03o"), (unsigned char) yytext[0]); mu_cfg_error_count++; } %% @@ -175,8 +192,7 @@ unescape_to_line (int c) char t = mu_wordsplit_c_unquote_char (c); if (t == c && t != '\\' && t != '\"') { - mu_diag_at_locus (MU_LOG_ERROR, &mu_cfg_locus, - _("unknown escape sequence '\\%c'"), c); + mu_error (_("unknown escape sequence '\\%c'"), c); mu_cfg_error_count++; } mu_opool_append_char (pool, t); @@ -365,29 +381,24 @@ mu_cfg_parse_file (mu_cfg_tree_t **return_tree, const char *file, int flags) mu_cfg_set_lex_debug (); - /* Initialize locus: */ - /* 1. Save file name in the lexer object pool and point `file' member - to this copy. Free full_name: it is not used after that. */ - _mu_line_begin (); - _mu_line_add (full_name, strlen (full_name)); - mu_cfg_locus.mu_file = _mu_line_finish (); - free (full_name); - /* 2. Initialize line number */ - mu_cfg_locus.mu_line = 1; - + /* Initialize tracker */ + mu_linetrack_create (&trk, full_name, 2); + memset (&string_beg, 0, sizeof string_beg); /* Parse configuration */ yyrestart (fp); rc = mu_cfg_parse (return_tree); fclose (fp); if (flags & MU_CF_VERBOSE) - mu_diag_output (MU_DIAG_INFO, _("finished parsing file `%s'"), - mu_cfg_locus.mu_file); - + mu_diag_output (MU_DIAG_INFO, _("finished parsing file `%s'"), full_name); + free (full_name); + mu_linetrack_destroy (&trk); + mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, NULL); return rc == 0 ? 0 : MU_ERR_FAILURE; } mu_opool_t -mu_cfg_lexer_pool () +mu_cfg_lexer_pool (void) { mu_opool_t p = pool; pool = NULL; diff --git a/libmailutils/cfg/parser.y b/libmailutils/cfg/parser.y index 80b940f..4503c77 100644 --- a/libmailutils/cfg/parser.y +++ b/libmailutils/cfg/parser.y @@ -40,10 +40,10 @@ #include <mailutils/stream.h> #include <mailutils/stdstream.h> #include <mailutils/cidr.h> +#include <mailutils/yyloc.h> int mu_cfg_parser_verbose; static mu_list_t /* of mu_cfg_node_t */ parse_node_list; -struct mu_locus mu_cfg_locus; size_t mu_cfg_error_count; static int _mu_cfg_errcnt; @@ -57,7 +57,7 @@ char *_mu_line_finish (void); static int yyerror (char *s) { - mu_diag_at_locus (MU_LOG_ERROR, &mu_cfg_locus, "%s", s); + mu_error ("%s", s); mu_cfg_error_count++; return 0; } @@ -85,7 +85,7 @@ _node_set_parent (void *item, void *data) } static mu_cfg_node_t * -mu_cfg_alloc_node (enum mu_cfg_node_type type, struct mu_locus *loc, +mu_cfg_alloc_node (enum mu_cfg_node_type type, struct mu_locus_range *loc, const char *tag, mu_config_value_t *label, mu_list_t nodelist) { @@ -94,7 +94,8 @@ mu_cfg_alloc_node (enum mu_cfg_node_type type, struct mu_locus *loc, size_t size = sizeof *np + strlen (tag) + 1; np = mu_alloc (size); np->type = type; - np->locus = *loc; + mu_locus_range_init (&np->locus); + mu_locus_range_copy (&np->locus, loc); p = (char*) (np + 1); np->tag = p; strcpy (p, tag); @@ -121,17 +122,15 @@ debug_print_node (mu_cfg_node_t *node) if (node->type == mu_cfg_node_undefined) { /* Stay on the safe side */ - mu_diag_at_locus (MU_LOG_ERROR, &mu_cfg_locus, - _("unknown statement type!")); + mu_error (_("unknown statement type!")); mu_cfg_error_count++; } else { /* FIXME: How to print label? */ - mu_diag_at_locus (MU_LOG_DEBUG, &node->locus, - "statement: %s, id: %s", - node_type_str (node->type), - node->tag ? node->tag : "(null)"); + mu_error ("statement: %s, id: %s", + node_type_str (node->type), + node->tag ? node->tag : "(null)"); } } } @@ -170,6 +169,9 @@ mu_cfg_create_node_list (mu_list_t *plist) %} +%locations +%expect 1 + %union { mu_cfg_node_t node; mu_cfg_node_t *pnode; @@ -177,7 +179,6 @@ mu_cfg_create_node_list (mu_list_t *plist) char *string; mu_config_value_t value, *pvalue; mu_list_t list; - struct { const char *name; struct mu_locus locus; } ident; } %token <string> MU_TOK_IDENT MU_TOK_STRING MU_TOK_QSTRING MU_TOK_MSTRING @@ -186,7 +187,7 @@ mu_cfg_create_node_list (mu_list_t *plist) %type <value> value %type <pvalue> tag vallist %type <list> values list vlist -%type <ident> ident +%type <string> ident %type <nodelist> stmtlist %type <pnode> stmt simple block @@ -217,32 +218,32 @@ stmt : simple simple : ident vallist ';' { - $$ = mu_cfg_alloc_node (mu_cfg_node_param, &$1.locus, - $1.name, $2, - NULL); + struct mu_locus_range lr; + lr.beg = @1.beg; + lr.end = @3.end; + $$ = mu_cfg_alloc_node (mu_cfg_node_param, &lr, $1, $2, NULL); } ; block : ident tag '{' '}' opt_sc { - $$ = mu_cfg_alloc_node (mu_cfg_node_statement, &$1.locus, - $1.name, $2, - NULL); + struct mu_locus_range lr; + lr.beg = @1.beg; + lr.end = @5.end; + $$ = mu_cfg_alloc_node (mu_cfg_node_statement, &lr, $1, $2, NULL); } | ident tag '{' stmtlist '}' opt_sc { - $$ = mu_cfg_alloc_node (mu_cfg_node_statement, &$1.locus, - $1.name, $2, $4); + struct mu_locus_range lr; + lr.beg = @1.beg; + lr.end = @6.end; + $$ = mu_cfg_alloc_node (mu_cfg_node_statement, &lr, $1, $2, $4); mu_list_foreach ($4, _node_set_parent, $$); } ; ident : MU_TOK_IDENT - { - $$.name = $1; - $$.locus = mu_cfg_locus; - } - ; + ; tag : /* empty */ { @@ -270,8 +271,7 @@ vallist : vlist val.v.arg.v = mu_alloc (n * sizeof (val.v.arg.v[0])); if (!val.v.arg.v) { - mu_diag_at_locus (MU_LOG_ERROR, &mu_cfg_locus, - _("not enough memory")); + mu_error (_("not enough memory")); abort(); } @@ -292,9 +292,7 @@ vlist : value int rc = mu_list_create (&$$); if (rc) { - mu_diag_at_locus (MU_LOG_ERROR, &mu_cfg_locus, - _("cannot create list: %s"), - mu_strerror (rc)); + mu_error (_("cannot create list: %s"), mu_strerror (rc)); abort (); } mu_list_append ($$, config_value_dup (&$1)); /* FIXME */ @@ -401,14 +399,15 @@ mu_cfg_parse (mu_cfg_tree_t **ptree) mu_cfg_tree_t *tree; mu_opool_t pool; int save_mode = 0, mode; - struct mu_locus save_locus = { NULL, }; + struct mu_locus_range save_locus = MU_LOCUS_RANGE_INITIALIZER; mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_GET_MODE, &save_mode); mode = save_mode | MU_LOGMODE_LOCUS; mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_SET_MODE, &mode); - mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_GET_LOCUS, + mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_GET_LOCUS_RANGE, &save_locus); mu_cfg_set_debug (); @@ -432,9 +431,10 @@ mu_cfg_parse (mu_cfg_tree_t **ptree) mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_SET_MODE, &save_mode); - mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_SET_LOCUS, + mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, &save_locus); - free (save_locus.mu_file); + mu_locus_range_deinit (&save_locus); /* FIXME: refcount? */ return rc; } @@ -480,7 +480,7 @@ mu_cfg_tree_union (mu_cfg_tree_t **pa, mu_cfg_tree_t **pb) static mu_cfg_tree_t * do_include (const char *name, struct mu_cfg_parse_hints *hints, - struct mu_locus *loc) + struct mu_locus_range const *loc) { struct stat sb; char *tmpname = NULL; @@ -520,15 +520,15 @@ do_include (const char *name, struct mu_cfg_parse_hints *hints, } else if (errno == ENOENT) { - mu_diag_at_locus (MU_LOG_ERROR, loc, - _("include file or directory does not exist")); + mu_diag_at_locus_range (MU_LOG_ERROR, loc, + _("include file or directory does not exist")); mu_cfg_error_count++; } else { - mu_diag_at_locus (MU_LOG_ERROR, loc, - _("cannot stat include file or directory: %s"), - mu_strerror (errno)); + mu_diag_at_locus_range (MU_LOG_ERROR, loc, + _("cannot stat include file or directory: %s"), + mu_strerror (errno)); mu_cfg_error_count++; } @@ -576,7 +576,7 @@ mu_cfg_tree_postprocess (mu_cfg_tree_t *tree, struct mu_cfg_parse_hints *hints) } else { - mu_diag_at_locus (MU_LOG_ERROR, &mu_cfg_locus, + mu_diag_at_locus_range (MU_LOG_ERROR, &node->locus, _("argument to `program' is not a string")); mu_cfg_error_count++; mu_iterator_ctl (itr, mu_itrctl_delete, NULL); @@ -602,7 +602,7 @@ mu_cfg_tree_postprocess (mu_cfg_tree_t *tree, struct mu_cfg_parse_hints *hints) } else { - mu_diag_at_locus (MU_LOG_ERROR, &mu_cfg_locus, + mu_diag_at_locus_range (MU_LOG_ERROR, &node->locus, _("argument to `include' is not a string")); mu_cfg_error_count++; } @@ -760,8 +760,7 @@ push_section (struct scan_tree_data *dat, struct mu_cfg_section *sec) struct mu_cfg_section_list *p = mu_alloc (sizeof *p); if (!p) { - mu_diag_at_locus (MU_LOG_ERROR, &mu_cfg_locus, - _("not enough memory")); + mu_error (_("not enough memory")); mu_cfg_error_count++; return 1; } @@ -782,7 +781,7 @@ pop_section (struct scan_tree_data *dat) } static int -valcvt (const struct mu_locus *locus, +valcvt (const struct mu_locus_range *locus, void *tgt, mu_c_type_t type, mu_config_value_t *val) { int rc; @@ -790,7 +789,7 @@ valcvt (const struct mu_locus *locus, if (val->type != MU_CFG_STRING) { - mu_diag_at_locus (MU_LOG_ERROR, locus, _("expected string value")); + mu_diag_at_locus_range (MU_LOG_ERROR, locus, _("expected string value")); mu_cfg_error_count++; return 1; } @@ -798,8 +797,8 @@ valcvt (const struct mu_locus *locus, rc = mu_str_to_c (val->v.string, type, tgt, &errmsg); if (rc) { - mu_diag_at_locus (MU_LOG_ERROR, locus, "%s", - errmsg ? errmsg : mu_strerror (rc)); + mu_diag_at_locus_range (MU_LOG_ERROR, locus, "%s", + errmsg ? errmsg : mu_strerror (rc)); free (errmsg); } return rc; @@ -810,7 +809,7 @@ struct set_closure mu_list_t list; int type; struct scan_tree_data *sdata; - const struct mu_locus *locus; + const struct mu_locus_range *locus; }; static size_t config_type_size[] = { @@ -840,7 +839,7 @@ _set_fun (void *item, void *data) if ((size_t) clos->type >= MU_ARRAY_SIZE(config_type_size) || (size = config_type_size[clos->type]) == 0) { - mu_diag_at_locus (MU_LOG_EMERG, clos->locus, + mu_diag_at_locus_range (MU_LOG_EMERG, clos->locus, _("INTERNAL ERROR at %s:%d: unhandled data type %d"), __FILE__, __LINE__, clos->type); mu_cfg_error_count++; @@ -850,7 +849,8 @@ _set_fun (void *item, void *data) tgt = mu_alloc (size); if (!tgt) { - mu_diag_at_locus (MU_LOG_ERROR, clos->locus, _("not enough memory")); + mu_diag_at_locus_range (MU_LOG_ERROR, clos->locus, + _("not enough memory")); mu_cfg_error_count++; return 1; } @@ -870,9 +870,9 @@ parse_param (struct scan_tree_data *sdata, const mu_cfg_node_t *node) if (!param) { - mu_diag_at_locus (MU_LOG_ERROR, &node->locus, - _("unknown keyword `%s'"), - node->tag); + mu_diag_at_locus_range (MU_LOG_ERROR, &node->locus, + _("unknown keyword `%s'"), + node->tag); mu_cfg_error_count++; return 1; } @@ -887,7 +887,7 @@ parse_param (struct scan_tree_data *sdata, const mu_cfg_node_t *node) tgt = NULL; else { - mu_diag_at_locus (MU_LOG_EMERG, &node->locus, + mu_diag_at_locus_range (MU_LOG_EMERG, &node->locus, _("INTERNAL ERROR: cannot determine target offset for " "%s"), param->ident); abort (); @@ -915,7 +915,7 @@ parse_param (struct scan_tree_data *sdata, const mu_cfg_node_t *node) break; case MU_CFG_ARRAY: - mu_diag_at_locus (MU_LOG_ERROR, &node->locus, + mu_diag_at_locus_range (MU_LOG_ERROR, &node->locus, _("expected list, but found array")); mu_cfg_error_count++; return 1; @@ -929,13 +929,13 @@ parse_param (struct scan_tree_data *sdata, const mu_cfg_node_t *node) { if (!param->callback) { - mu_diag_at_locus (MU_LOG_EMERG, &node->locus, + mu_diag_at_locus_range (MU_LOG_EMERG, &node->locus, _("INTERNAL ERROR: %s: callback not defined"), node->tag); abort (); } mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, - MU_IOCTL_LOGSTREAM_SET_LOCUS, + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, (void*) &node->locus); if (param->callback (tgt, node->label)) return 1; @@ -964,9 +964,9 @@ _scan_tree_helper (const mu_cfg_node_t *node, void *data) { if (mu_cfg_parser_verbose) { - mu_diag_at_locus (MU_LOG_WARNING, &node->locus, - _("unknown section `%s'"), - node->tag); + mu_diag_at_locus_range (MU_LOG_WARNING, &node->locus, + _("unknown section `%s'"), + node->tag); } return MU_CFG_ITER_SKIP; } @@ -983,7 +983,7 @@ _scan_tree_helper (const mu_cfg_node_t *node, void *data) if (sec->parser) { mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, - MU_IOCTL_LOGSTREAM_SET_LOCUS, + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, (void*) &node->locus); if (sec->parser (mu_cfg_section_start, node, sec->label, &sec->target, @@ -1041,7 +1041,7 @@ mu_cfg_scan_tree (mu_cfg_tree_t *tree, struct mu_cfg_section *sections, struct scan_tree_data dat; struct mu_cfg_iter_closure clos; int save_mode = 0, mode; - struct mu_locus save_locus = { NULL, }; + struct mu_locus_range save_locus = MU_LOCUS_RANGE_INITIALIZER; int rc; dat.tree = tree; @@ -1056,7 +1056,7 @@ mu_cfg_scan_tree (mu_cfg_tree_t *tree, struct mu_cfg_section *sections, mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_SET_MODE, &mode); mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, - MU_IOCTL_LOGSTREAM_GET_LOCUS, &save_locus); + MU_IOCTL_LOGSTREAM_GET_LOCUS_RANGE, &save_locus); if (push_section (&dat, sections)) return 1; @@ -1070,8 +1070,7 @@ mu_cfg_scan_tree (mu_cfg_tree_t *tree, struct mu_cfg_section *sections, mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_SET_MODE, &save_mode); mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, - MU_IOCTL_LOGSTREAM_SET_LOCUS, &save_locus); - free (save_locus.mu_file); + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, &save_locus); return dat.error; } @@ -1124,7 +1123,7 @@ mu_cfg_tree_create (struct mu_cfg_tree **ptree) mu_cfg_node_t * mu_cfg_tree_create_node (struct mu_cfg_tree *tree, enum mu_cfg_node_type type, - const struct mu_locus *loc, + const struct mu_locus_range *loc, const char *tag, const char *label, mu_list_t nodelist) { @@ -1136,7 +1135,7 @@ mu_cfg_tree_create_node (struct mu_cfg_tree *tree, np = mu_alloc (size); np->type = type; if (loc) - np->locus = *loc; + mu_locus_range_copy (&np->locus, loc); else memset (&np->locus, 0, sizeof np->locus); p = (char*) (np + 1); @@ -1478,11 +1477,7 @@ mu_cfg_create_subtree (const char *path, mu_cfg_node_t **pnode) char **argv; enum mu_cfg_node_type type; mu_cfg_node_t *node = NULL; - struct mu_locus locus; - - locus.mu_file = "<int>"; - locus.mu_line = 0; - locus.mu_col = 0; + struct mu_locus_range locus = MU_LOCUS_RANGE_INITIALIZER; rc = split_cfg_path (path, &argc, &argv); if (rc) diff --git a/libmailutils/diag/diag.c b/libmailutils/diag/diag.c index 318afe0..b5a7482 100644 --- a/libmailutils/diag/diag.c +++ b/libmailutils/diag/diag.c @@ -29,6 +29,7 @@ #include <mailutils/errno.h> #include <mailutils/stdstream.h> #include <mailutils/stream.h> +#include <mailutils/locus.h> void mu_diag_init () @@ -56,17 +57,52 @@ mu_diag_output (int level, const char *fmt, ...) } void -mu_diag_at_locus (int level, struct mu_locus const *loc, const char *fmt, ...) +mu_vdiag_at_locus_range (int level, struct mu_locus_range const *loc, + const char *fmt, va_list ap) +{ + struct mu_locus_range old = MU_LOCUS_RANGE_INITIALIZER; + int restore = 0; + + if (loc) + { + if (mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_GET_LOCUS_RANGE, &old) == 0) + { + mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, (void*) loc); + restore = 1; + } + } + + mu_diag_voutput (level, fmt, ap); + + if (restore) + { + mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, &old); + mu_locus_range_deinit (&old); + } +} + +void +mu_diag_at_locus_range (int level, struct mu_locus_range const *loc, + const char *fmt, ...) { va_list ap; + va_start (ap, fmt); + mu_vdiag_at_locus_range (level, loc, fmt, ap); + va_end (ap); +} +void +mu_diag_at_locus_point (int level, struct mu_locus_point const *loc, + const char *fmt, ...) +{ + va_list ap; + struct mu_locus_range lr = MU_LOCUS_RANGE_INITIALIZER; + lr.beg = *loc; va_start (ap, fmt); - if (loc && loc->mu_file) - mu_stream_printf (mu_strerr, "\033f<%d>%s\033l<%u>\033c<%u>", - (unsigned) strlen (loc->mu_file), loc->mu_file, - loc->mu_line, - loc->mu_col); - mu_diag_voutput (level, fmt, ap); + mu_vdiag_at_locus_range (level, &lr, fmt, ap); va_end (ap); } diff --git a/libmailutils/locus/Makefile.am b/libmailutils/locus/Makefile.am new file mode 100644 index 0000000..8a9f384 --- a/dev/null +++ b/libmailutils/locus/Makefile.am @@ -0,0 +1,31 @@ +# GNU Mailutils -- a suite of utilities for electronic mail +# Copyright (C) 2017 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 of the License, 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 this library. If not, see +# <http://www.gnu.org/licenses/>. + +noinst_LTLIBRARIES = liblocus.la + +liblocus_la_SOURCES = \ + ident.c\ + debug.c\ + linetrack.c\ + locus.c\ + filprloc.c\ + strprloc.c + +EXTRA_DIST = genprloc.c + +AM_CPPFLAGS = @MU_LIB_COMMON_INCLUDES@ -I/libmailutils + diff --git a/libmailutils/locus/debug.c b/libmailutils/locus/debug.c new file mode 100644 index 0000000..3e95af1 --- a/dev/null +++ b/libmailutils/locus/debug.c @@ -0,0 +1,74 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2017 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 of the License, 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 this library. If not, see + <http://www.gnu.org/licenses/>. */ + +#include <stdlib.h> +#include <stdarg.h> +#include <mailutils/types.h> +#include <mailutils/locus.h> +#include <mailutils/error.h> +#include <mailutils/errno.h> +#include <mailutils/diag.h> +#include <mailutils/stream.h> +#include <mailutils/stdstream.h> + +void +mu_stream_vlprintf (mu_stream_t stream, + struct mu_locus_range const *loc, + char const *fmt, va_list ap) +{ + mu_stream_print_locus_range (stream, loc); + mu_stream_write (stream, ": ", 2, NULL); + mu_stream_vprintf (stream, fmt, ap); +} + +void +mu_stream_lprintf (mu_stream_t stream, + struct mu_locus_range const *loc, + char const *fmt, ...) +{ + va_list ap; + va_start (ap, fmt); + mu_stream_vlprintf (stream, loc, fmt, ap); + va_end (ap); +} + +void +mu_lrange_debug (struct mu_locus_range const *loc, + char const *fmt, ...) +{ + va_list ap; + int rc, mode; + + rc = mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_GET_MODE, &mode); + if (rc == 0) + { + int new_mode = mode & ~MU_LOGMODE_LOCUS; + rc = mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_MODE, &new_mode); + } + + va_start (ap, fmt); + mu_stream_vlprintf (mu_strerr, loc, fmt, ap); + va_end (ap); + mu_stream_write (mu_strerr, "\n", 1, NULL); + + if (rc == 0) + mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_MODE, &mode); + +} diff --git a/libmailutils/locus/filprloc.c b/libmailutils/locus/filprloc.c new file mode 100644 index 0000000..e1cdfa4 --- a/dev/null +++ b/libmailutils/locus/filprloc.c @@ -0,0 +1,7 @@ +#include <stdio.h> + +#define STREAM_TYPE FILE* +#define STREAM_PRINTF fprintf +#define PRINT_LOCUS_POINT mu_file_print_locus_point +#define PRINT_LOCUS_RANGE mu_file_print_locus_range +#include "genprloc.c" diff --git a/libmailutils/locus/genprloc.c b/libmailutils/locus/genprloc.c new file mode 100644 index 0000000..cc15030 --- a/dev/null +++ b/libmailutils/locus/genprloc.c @@ -0,0 +1,71 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2017 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 of the License, 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 this library. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef STREAM_TYPE +# error "STREAM_TYPE not defined" +#endif +#ifndef PRINT_LOCUS_POINT +# error "PRINT_LOCUS_POINT not defined" +#endif +#ifndef PRINT_LOCUS_RANGE +# error "PRINT_LOCUS_RANGE not defined" +#endif +#ifndef STREAM_PRINTF +# error "STREAM_PRINTF not defined" +#endif + +#include <mailutils/types.h> +#include <mailutils/locus.h> + +void +PRINT_LOCUS_POINT (STREAM_TYPE stream, struct mu_locus_point const *lp) +{ + if (lp->mu_file) + { + STREAM_PRINTF (stream, "%s:%u", + lp->mu_file, lp->mu_line); + if (lp->mu_col) + STREAM_PRINTF (stream, ".%u", lp->mu_col); + } +} + +void +PRINT_LOCUS_RANGE (STREAM_TYPE stream, struct mu_locus_range const *loc) +{ + PRINT_LOCUS_POINT (stream, &loc->beg); + if (loc->end.mu_file) + { + if (!mu_locus_point_same_file (&loc->beg, &loc->end)) + { + STREAM_PRINTF (stream, "-"); + PRINT_LOCUS_POINT (stream, &loc->end); + } + else if (loc->beg.mu_line != loc->end.mu_line) + { + STREAM_PRINTF (stream, "-"); + STREAM_PRINTF (stream, "%u", loc->end.mu_line); + if (loc->end.mu_col) + STREAM_PRINTF (stream, ".%u", loc->end.mu_col); + } + else if (loc->beg.mu_col + && loc->beg.mu_col != loc->end.mu_col) + { + STREAM_PRINTF (stream, "-"); + STREAM_PRINTF (stream, "%u", loc->end.mu_col); + } + } +} diff --git a/libmailutils/locus/ident.c b/libmailutils/locus/ident.c new file mode 100644 index 0000000..cb7591e --- a/dev/null +++ b/libmailutils/locus/ident.c @@ -0,0 +1,152 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2017 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 of the License, 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 this library. If not, see + <http://www.gnu.org/licenses/>. */ + +#include <stdlib.h> +#include <mailutils/types.h> +#include <mailutils/assoc.h> +#include <mailutils/locus.h> +#include <mailutils/error.h> +#include <mailutils/errno.h> +#include <mailutils/diag.h> +#include <mailutils/list.h> +#include <mailutils/io.h> +#include <mailutils/stream.h> +#include <mailutils/iterator.h> + +struct mu_ident_ref +{ + size_t count; +}; + +static mu_assoc_t nametab; + +int +mu_ident_ref (char const *name, char const **refname) +{ + int rc; + struct mu_ident_ref *ref, **refptr; + + if (!refname) + return MU_ERR_OUT_PTR_NULL; + if (!name) + { + *refname = NULL; + return 0; + } + + if (!nametab) + { + rc = mu_assoc_create (&nametab, 0); + if (rc) + { + mu_diag_funcall (MU_DIAG_ERROR, "mu_assoc_create", NULL, rc); + return rc; + } + mu_assoc_set_destroy_item (nametab, mu_list_free_item); + } + rc = mu_assoc_install_ref2 (nametab, name, &refptr, refname); + switch (rc) + { + case 0: + ref = malloc (sizeof *ref); + if (!ref) + { + rc = errno; + mu_assoc_remove (nametab, name); + return rc; + } + *refptr = ref; + ref->count = 0; + break; + + case MU_ERR_EXISTS: + ref = *refptr; + break; + + default: + mu_diag_funcall (MU_DIAG_ERROR, "mu_assoc_install_ref2", name, rc); + return rc; + } + + ref->count++; + return 0; +} + +int +mu_ident_deref (char const *name) +{ + struct mu_ident_ref *ref; + int rc; + + if (!name || !nametab) + return 0; + + rc = mu_assoc_lookup (nametab, name, &ref); + switch (rc) + { + case 0: + if (--ref->count == 0) + mu_assoc_remove (nametab, name); + break; + + case MU_ERR_NOENT: + break; + + default: + mu_diag_funcall (MU_DIAG_ERROR, "mu_assoc_lookup", name, rc); + return rc; + } + + return 0; +} + +void +mu_ident_stat (mu_stream_t str) +{ + size_t count, i; + mu_iterator_t itr; + + mu_stream_printf (str, "BEGIN IDENT STAT\n"); + + mu_assoc_count (nametab, &count); + mu_stream_printf (str, "N=%zu\n", count); + + if (count > 0) + { + int rc = mu_assoc_get_iterator (nametab, &itr); + if (rc) + mu_stream_printf (str, "mu_assoc_get_iterator: %s\n", + mu_strerror (rc)); + else + { + i = 0; + for (mu_iterator_first (itr); !mu_iterator_is_done (itr); + mu_iterator_next (itr), i) + { + const char *key; + struct mu_ident_ref *ref; + + mu_iterator_current_kv (itr, + (const void **)&key, (void **)&ref); + mu_stream_printf (str, "%04zu: %s: %zu\n", i, key, ref->count); + } + } + mu_iterator_destroy (&itr); + } + mu_stream_printf (str, "END IDENT STAT\n"); +} + diff --git a/libmailutils/locus/linetrack.c b/libmailutils/locus/linetrack.c new file mode 100644 index 0000000..86a3dd8 --- a/dev/null +++ b/libmailutils/locus/linetrack.c @@ -0,0 +1,268 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2017 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 of the License, 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 this library. If not, see + <http://www.gnu.org/licenses/>. */ + +#include <stdlib.h> +#include <errno.h> +#include <mailutils/types.h> +#include <mailutils/locus.h> +#include <mailutils/error.h> + +/* The line-tracker structure keeps track of the last N lines read from a + text input file. For each line read it keeps the number of characters + in that line including the newline. This information is stored in a + syclic stack of N elements. Top of stack always represents the current + line. For the purpose of line tracker, current line is the line that is + being visited, such that its final newline character has not yet been + seen. Once the newline is seen, the line is pushed on stack, and a new + current line is assumed. + + The value of N must not be less than 2. +*/ +struct mu_linetrack +{ + char const *file_name; /* Name of the source file */ + size_t max_lines; /* Max. number of lines history kept by tracker (N) */ + size_t head; /* Index of the eldest element on stack */ + size_t tos; /* Index of the most recent element on stack + (< max_lines) */ + unsigned hline; /* Number of line corresponding to cols[head] */ + unsigned *cols; /* Cyclic stack or character counts. + Number of characters in line (hline + n) is + cols[head + n] (0 <= n <= tos). */ +}; + +static inline unsigned * +cols_ptr (mu_linetrack_t trk, size_t n) +{ + return &trk->cols[(trk->head + n) % trk->max_lines]; +} + +static inline unsigned * +cols_tos_ptr (mu_linetrack_t trk) +{ + return cols_ptr (trk, trk->tos); +} + +static inline unsigned +cols_peek (mu_linetrack_t trk, size_t n) +{ + return *cols_ptr (trk, n); +} + +int +mu_linetrack_create (mu_linetrack_t *ret, + char const *file_name, size_t max_lines) +{ + int rc; + struct mu_linetrack *trk; + + trk = malloc (sizeof *trk); + if (!trk) + return errno; + trk->cols = calloc (max_lines, sizeof (trk->cols[0])); + if (!trk->cols) + { + rc = errno; + free (trk); + return rc; + } + rc = mu_ident_ref (file_name, &trk->file_name); + if (rc) + { + free (trk->cols); + free (trk); + return rc; + } + + if (max_lines < 2) + max_lines = 2; + trk->max_lines = max_lines; + trk->head = 0; + trk->tos = 0; + trk->hline = 1; + trk->cols[0] = 0; + + *ret = trk; + return 0; +} + +int +mu_linetrack_rebase (mu_linetrack_t trk, struct mu_locus_point const *pt) +{ + char const *file_name; + int rc = mu_ident_ref (pt->mu_file, &file_name); + if (rc) + return rc; + mu_ident_deref (trk->file_name); + trk->file_name = file_name; + trk->hline = pt->mu_line; + *cols_ptr (trk, 0) = pt->mu_col; + return 0; +} + +void +mu_linetrack_free (mu_linetrack_t trk) +{ + if (trk) + { + mu_ident_deref (trk->file_name); + free (trk->cols); + free (trk); + } +} + +void +mu_linetrack_destroy (mu_linetrack_t *trk) +{ + if (trk) + { + mu_linetrack_free (*trk); + *trk = NULL; + } +} + +static inline unsigned * +push (mu_linetrack_t trk) +{ + unsigned *ptr; + if (trk->tos == trk->max_lines - 1) + { + trk->head++; + trk->hline++; + } + else + trk->tos++; + *(ptr = cols_tos_ptr (trk)) = 0; + return ptr; +} + +static inline unsigned * +pop (mu_linetrack_t trk) +{ + if (trk->tos == 0) + return NULL; + trk->tos--; + return cols_tos_ptr (trk); +} + +#ifndef SIZE_MAX +# define SIZE_MAX (~((size_t)0)) +#endif + +int +mu_linetrack_stat (struct mu_linetrack *trk, struct mu_linetrack_stat *st) +{ + size_t i, nch = 0; + + for (i = 0; i <= trk->tos; i++) + { + unsigned n = cols_peek (trk, i); + if (SIZE_MAX - nch < n) + return ERANGE; + nch += n; + } + + st->start_line = trk->hline; + st->n_lines = trk->tos + 1; + st->n_chars = nch; + + return 0; +} + +int +mu_linetrack_at_bol (struct mu_linetrack *trk) +{ + return *cols_tos_ptr (trk) == 0; +} + +void +mu_linetrack_advance (struct mu_linetrack *trk, + struct mu_locus_range *loc, + char const *text, size_t leng) +{ + unsigned *ptr; + + if (text == NULL || leng == 0) + return; + + mu_locus_point_set_file (&loc->beg, trk->file_name); + mu_locus_point_set_file (&loc->end, trk->file_name); + loc->beg.mu_line = trk->hline + trk->tos; + ptr = cols_tos_ptr (trk); + loc->beg.mu_col = *ptr + 1; + while (leng--) + { + (*ptr)++; + if (*text == '\n') + ptr = push (trk); + text++; + } + if (*ptr) + { + loc->end.mu_line = trk->hline + trk->tos; + loc->end.mu_col = *ptr; + } + else + { + /* Text ends with a newline. Keep the previous line number. */ + loc->end.mu_line = trk->hline + trk->tos - 1; + loc->end.mu_col = cols_peek (trk, trk->tos - 1) - 1; + if (loc->end.mu_col + 1 == loc->beg.mu_col) + { + /* This happens if the previous line contained only newline. */ + loc->beg.mu_col = loc->end.mu_col; + } + } +} + +int +mu_linetrack_locus (struct mu_linetrack *trk, struct mu_locus_point *lp) +{ + lp->mu_line = trk->hline + trk->tos; + return mu_locus_point_set_file (lp, trk->file_name); +} + +int +mu_linetrack_retreat (struct mu_linetrack *trk, size_t n) +{ + struct mu_linetrack_stat st; + + mu_linetrack_stat (trk, &st); + if (n > st.n_chars) + return ERANGE; + else + { + unsigned *ptr = cols_tos_ptr (trk); + while (n--) + { + if (*ptr == 0) + { + ptr = pop (trk); + if (!ptr || *ptr == 0) + { + mu_error ("%s:%d: INTERNAL ERROR: out of pop back\n", + __FILE__, __LINE__); + return ERANGE; + } + } + --*ptr; + } + } + return 0; +} + + diff --git a/libmailutils/locus/locus.c b/libmailutils/locus/locus.c new file mode 100644 index 0000000..cfa8080 --- a/dev/null +++ b/libmailutils/locus/locus.c @@ -0,0 +1,101 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2017 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 of the License, 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 this library. If not, see + <http://www.gnu.org/licenses/>. */ + +#include <stdlib.h> +#include <errno.h> +#include <mailutils/types.h> +#include <mailutils/locus.h> +#include <mailutils/error.h> +#include <mailutils/errno.h> + +int +mu_locus_point_set_file (struct mu_locus_point *pt, const char *filename) +{ + int rc; + char const *ref; + + rc = mu_ident_ref (filename, &ref); + if (rc) + return rc; + mu_ident_deref (pt->mu_file); + pt->mu_file = ref; + return 0; +} + +void +mu_locus_point_init (struct mu_locus_point *pt) +{ + memset (pt, 0, sizeof *pt); +} + +void +mu_locus_point_deinit (struct mu_locus_point *pt) +{ + mu_ident_deref (pt->mu_file); + memset (pt, 0, sizeof *pt); +} + +int +mu_locus_point_copy (struct mu_locus_point *dest, + struct mu_locus_point const *src) +{ + int rc = mu_locus_point_set_file (dest, src->mu_file); + if (rc == 0) + { + dest->mu_col = src->mu_col; + dest->mu_line = src->mu_line; + } + return rc; +} + +void +mu_locus_range_init (struct mu_locus_range *dest) +{ + memset (dest, 0, sizeof *dest); +} + +int +mu_locus_range_copy (struct mu_locus_range *dest, + struct mu_locus_range const *src) +{ + int rc; + struct mu_locus_range tmp = MU_LOCUS_RANGE_INITIALIZER; + + if (!dest) + return MU_ERR_OUT_PTR_NULL; + + rc = mu_locus_point_copy (&tmp.beg, &src->beg); + if (rc == 0) + { + rc = mu_locus_point_copy (&tmp.end, &src->end); + if (rc) + mu_locus_point_deinit (&tmp.beg); + else + { + mu_locus_range_deinit (dest); + *dest = tmp; + } + } + return rc; +} + +void +mu_locus_range_deinit (struct mu_locus_range *lr) +{ + mu_locus_point_deinit (&lr->beg); + mu_locus_point_deinit (&lr->end); +} diff --git a/libmailutils/locus/strprloc.c b/libmailutils/locus/strprloc.c new file mode 100644 index 0000000..4f074a7 --- a/dev/null +++ b/libmailutils/locus/strprloc.c @@ -0,0 +1,10 @@ +#include <mailutils/types.h> +#include <mailutils/locus.h> +#include <mailutils/stream.h> + +#define STREAM_TYPE mu_stream_t +#define STREAM_PRINTF mu_stream_printf +#define PRINT_LOCUS_POINT mu_stream_print_locus_point +#define PRINT_LOCUS_RANGE mu_stream_print_locus_range +#include "genprloc.c" + diff --git a/libmailutils/stream/logstream.c b/libmailutils/stream/logstream.c index 5bca3c2..1cc2b4b 100644 --- a/libmailutils/stream/logstream.c +++ b/libmailutils/stream/logstream.c @@ -30,6 +30,7 @@ #include <mailutils/nls.h> #include <mailutils/stream.h> #include <mailutils/debug.h> +#include <mailutils/locus.h> #include <mailutils/sys/logstream.h> char *_mu_severity_str[] = { @@ -69,25 +70,77 @@ mu_severity_to_string (unsigned n, const char **pstr) return 0; } +static void +lr_set_line (struct mu_locus_range *loc, unsigned val, int end) +{ + if (end) + loc->end.mu_line = val; + else + loc->beg.mu_line = val; +} + +static void +lr_set_col (struct mu_locus_range *loc, unsigned val, int end) +{ + if (end) + loc->end.mu_col = val; + else + loc->beg.mu_col = val; +} + static int -_locus_set_file (struct mu_locus *loc, const char *file, size_t len) +lr_set_file (struct mu_locus_range *loc, char const *fname, unsigned len, + int end) { - free (loc->mu_file); - if (file) + char const *refname; + struct mu_locus_point *pt = end ? &loc->end : &loc->beg; + int rc; + + if (fname == NULL) { - loc->mu_file = malloc (len + 1); - if (!loc->mu_file) - return ENOMEM; - memcpy (loc->mu_file, file, len); - loc->mu_file[len] = 0; + refname = NULL; + rc = 0; } + else if (len == 0) + rc = mu_ident_ref (fname, &refname); else - loc->mu_file = NULL; + { + char *name; + + name = malloc (len + 1); + if (!name) + return errno; + memcpy (name, fname, len); + name[len] = 0; + rc = mu_ident_ref (name, &refname); + free (name); + } + if (rc) + return rc; + mu_ident_deref (pt->mu_file); + pt->mu_file = refname; return 0; } -#define _locus_set_line(loc, line) ((loc)->mu_line = line) -#define _locus_set_col(loc, col) ((loc)->mu_col = col) +/* Field modification map (binary): + + FfLlCc + + The bits f, l, and c (file, line, and column) are toggled cyclically. + The value 0 means locus beg, 1 meand locus end. + The bits F, L, and C are set once and indicate that the corresponding + bit was toggled at least once. + */ +#define FMM_COL 0 +#define FMM_LINE 1 +#define FMM_FILE 2 + +#define FMM_SHIFT(n) ((n)<<1) +#define FMM_MASK(n) (0x3 << FMM_SHIFT (n)) +#define FMM_VAL(m,n) (((m) >> FMM_SHIFT (n)) & 0x1) +#define FMM_SET(m,n,v) ((m) = ((m) & ~FMM_MASK (n)) | (((v) << FMM_SHIFT (n))|0x2)) +#define FMM_CYCLE(m, n) \ + FMM_SET ((m), (n), ((FMM_VAL ((m), (n)) + 1) % 2)) static int _log_write (struct _mu_stream *str, const char *buf, size_t size, @@ -96,8 +149,8 @@ _log_write (struct _mu_stream *str, const char *buf, size_t size, struct _mu_log_stream *sp = (struct _mu_log_stream *)str; unsigned severity = sp->severity; int logmode = sp->logmode; - struct mu_locus loc = sp->locus; - const char *fname = NULL; + struct mu_locus_range loc; + int fmm = 0; unsigned flen = 0; int save_locus = 0; int rc; @@ -120,6 +173,10 @@ _log_write (struct _mu_stream *str, const char *buf, size_t size, n = __x; \ } while (0) + loc = sp->locrange; + mu_ident_ref (loc.beg.mu_file, &loc.beg.mu_file); + mu_ident_ref (loc.end.mu_file, &loc.end.mu_file); + /* Tell them we've consumed everything */ *pnwrite = size; @@ -167,21 +224,24 @@ _log_write (struct _mu_stream *str, const char *buf, size_t size, case 'l': /* Input line (decimal) */ READNUM (n); - _locus_set_line (&loc, n); + lr_set_line (&loc, n, FMM_VAL (fmm, FMM_LINE)); + FMM_CYCLE (fmm, FMM_LINE); logmode |= MU_LOGMODE_LOCUS; break; case 'c': /* Column in input line (decimal) */ READNUM (n); - _locus_set_col (&loc, n); + lr_set_col (&loc, n, FMM_VAL (fmm, FMM_COL)); + FMM_CYCLE (fmm, FMM_COL); logmode |= MU_LOGMODE_LOCUS; break; case 'f': /* File name. Format: <N>S */ READNUM (flen); - fname = buf; + lr_set_file (&loc, buf, flen, FMM_VAL (fmm, FMM_FILE)); + FMM_CYCLE (fmm, FMM_FILE); buf += flen; size -= flen; logmode |= MU_LOGMODE_LOCUS; @@ -197,58 +257,37 @@ _log_write (struct _mu_stream *str, const char *buf, size_t size, if (severity >= _mu_severity_num) severity = MU_LOG_EMERG; - if (fname) - { - loc.mu_file = NULL; - _locus_set_file (&loc, fname, flen); - } - if (save_locus) - { - _locus_set_file (&sp->locus, loc.mu_file, strlen (loc.mu_file)); - _locus_set_line (&sp->locus, loc.mu_line); - _locus_set_col (&sp->locus, loc.mu_col); - } + mu_locus_range_copy (&sp->locrange, &loc); if (severity < sp->threshold) + rc = 0; + else { - if (fname) - free (loc.mu_file); - return 0; - } - - mu_stream_ioctl (sp->transport, MU_IOCTL_LOGSTREAM, - MU_IOCTL_LOGSTREAM_SET_SEVERITY, &severity); + mu_stream_ioctl (sp->transport, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_SEVERITY, &severity); - if (logmode & MU_LOGMODE_LOCUS) - { - if (loc.mu_file) + if ((logmode & MU_LOGMODE_LOCUS) && loc.beg.mu_file) + { + mu_stream_print_locus_range (sp->transport, &loc); + mu_stream_write (sp->transport, ": ", 2, NULL); + } + + if ((logmode & MU_LOGMODE_SEVERITY) && + !(sp->sevmask & MU_DEBUG_LEVEL_MASK (severity))) { - mu_stream_write (sp->transport, loc.mu_file, - strlen (loc.mu_file), NULL); - mu_stream_write (sp->transport, ":", 1, NULL); - if (loc.mu_line) - mu_stream_printf (sp->transport, "%u", loc.mu_line); - mu_stream_write (sp->transport, ":", 1, NULL); - if (loc.mu_col) - mu_stream_printf (sp->transport, "%u:", loc.mu_col); - mu_stream_write (sp->transport, " ", 1, NULL); + char *s = gettext (_mu_severity_str[severity]); + rc = mu_stream_write (sp->transport, s, strlen (s), NULL); + if (rc) + return rc; + mu_stream_write (sp->transport, ": ", 2, NULL); } + rc = mu_stream_write (sp->transport, buf, size, NULL); } - - if (fname) - free (loc.mu_file); - if ((logmode & MU_LOGMODE_SEVERITY) && - !(sp->sevmask & MU_DEBUG_LEVEL_MASK(severity))) - { - char *s = gettext (_mu_severity_str[severity]); - rc = mu_stream_write (sp->transport, s, strlen (s), NULL); - if (rc) - return rc; - mu_stream_write (sp->transport, ": ", 2, NULL); - } - return mu_stream_write (sp->transport, buf, size, NULL); + mu_ident_deref (loc.beg.mu_file); + mu_ident_deref (loc.end.mu_file); + return rc; } static int @@ -262,6 +301,7 @@ static void _log_done (struct _mu_stream *str) { struct _mu_log_stream *sp = (struct _mu_log_stream *)str; + mu_locus_range_deinit (&sp->locrange); mu_stream_destroy (&sp->transport); } @@ -375,72 +415,133 @@ _log_ctl (struct _mu_stream *str, int code, int opcode, void *arg) sp->logmode = *(int*)arg; break; - case MU_IOCTL_LOGSTREAM_GET_LOCUS: + case MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE: + { + struct mu_locus_range *lr = arg; + if (!arg) + { + mu_ident_deref (sp->locrange.beg.mu_file); + mu_ident_deref (sp->locrange.end.mu_file); + memset (&sp->locrange, 0, sizeof sp->locrange); + } + else + { + char const *begname, *endname; + + status = mu_ident_ref (lr->beg.mu_file, &begname); + if (status) + return status; + status = mu_ident_ref (lr->end.mu_file, &endname); + if (status) + { + mu_ident_deref (begname); + return status; + } + mu_ident_deref (sp->locrange.beg.mu_file); + sp->locrange.beg.mu_file = begname; + sp->locrange.beg.mu_line = lr->beg.mu_line; + sp->locrange.beg.mu_col = lr->beg.mu_col; + + mu_ident_deref (sp->locrange.end.mu_file); + sp->locrange.end.mu_file = endname; + sp->locrange.end.mu_line = lr->end.mu_line; + sp->locrange.end.mu_col = lr->end.mu_col; + } + } + break; + + case MU_IOCTL_LOGSTREAM_GET_LOCUS_RANGE: + if (!arg) + return EINVAL; + else + { + struct mu_locus_range *lr = arg; + char const *begname, *endname; + + status = mu_ident_ref (sp->locrange.beg.mu_file, &begname); + if (status) + return status; + status = mu_ident_ref (sp->locrange.end.mu_file, &endname); + if (status) + { + mu_ident_deref (begname); + return status; + } + lr->beg.mu_file = begname; + lr->beg.mu_line = sp->locrange.beg.mu_line; + lr->beg.mu_col = sp->locrange.beg.mu_col; + lr->end.mu_file = endname; + lr->end.mu_line = sp->locrange.end.mu_line; + lr->end.mu_col = sp->locrange.end.mu_col; + } + break; + + case MU_IOCTL_LOGSTREAM_GET_LOCUS_DEPRECATED: if (!arg) return EINVAL; else { - struct mu_locus *ploc = arg; - if (sp->locus.mu_file) + struct mu_locus_DEPRECATED *ploc = arg; + if (sp->locrange.beg.mu_file) { - ploc->mu_file = strdup (sp->locus.mu_file); + ploc->mu_file = strdup (sp->locrange.beg.mu_file); if (!ploc->mu_file) return ENOMEM; } else ploc->mu_file = NULL; - ploc->mu_line = sp->locus.mu_line; - ploc->mu_col = sp->locus.mu_col; + ploc->mu_line = sp->locrange.beg.mu_line; + ploc->mu_col = sp->locrange.beg.mu_col; } break; - case MU_IOCTL_LOGSTREAM_SET_LOCUS: + case MU_IOCTL_LOGSTREAM_SET_LOCUS_DEPRECATED: { - struct mu_locus *ploc = arg; - if (!arg) + struct mu_locus_DEPRECATED *ploc = arg; + + mu_ident_deref (sp->locrange.end.mu_file); + sp->locrange.end.mu_file = NULL; + if (arg) { - free (sp->locus.mu_file); - sp->locus.mu_file = NULL; - sp->locus.mu_line = 0; - sp->locus.mu_col = 0; + status = lr_set_file (&sp->locrange, ploc->mu_file, 0, 0); + if (status) + return status; + lr_set_line (&sp->locrange, ploc->mu_line, 0); + lr_set_col (&sp->locrange, ploc->mu_col, 0); } else { - if (ploc->mu_file) - _locus_set_file (&sp->locus, ploc->mu_file, - strlen (ploc->mu_file)); - if (ploc->mu_line) - _locus_set_line (&sp->locus, ploc->mu_line); - if (ploc->mu_col) - _locus_set_col (&sp->locus, ploc->mu_col); + mu_ident_deref (sp->locrange.beg.mu_file); + sp->locrange.beg.mu_file = NULL; } + break; } case MU_IOCTL_LOGSTREAM_SET_LOCUS_LINE: if (!arg) return EINVAL; - sp->locus.mu_line = *(unsigned*)arg; + sp->locrange.beg.mu_line = *(unsigned*)arg; break; case MU_IOCTL_LOGSTREAM_SET_LOCUS_COL: if (!arg) return EINVAL; - sp->locus.mu_col = *(unsigned*)arg; + sp->locrange.beg.mu_col = *(unsigned*)arg; break; case MU_IOCTL_LOGSTREAM_ADVANCE_LOCUS_LINE: if (!arg) - sp->locus.mu_line++; + sp->locrange.beg.mu_line++; else - sp->locus.mu_line += *(int*)arg; + sp->locrange.beg.mu_line += *(int*)arg; break; case MU_IOCTL_LOGSTREAM_ADVANCE_LOCUS_COL: if (!arg) - sp->locus.mu_col++; + sp->locrange.beg.mu_col++; else - sp->locus.mu_col += *(int*)arg; + sp->locrange.beg.mu_col += *(int*)arg; break; case MU_IOCTL_LOGSTREAM_SUPPRESS_SEVERITY: @@ -484,14 +585,12 @@ _log_ctl (struct _mu_stream *str, int code, int opcode, void *arg) newp->threshold = sp->threshold; newp->logmode = sp->logmode; newp->sevmask = sp->sevmask; - if (sp->locus.mu_file) - { - newp->locus.mu_file = strdup (sp->locus.mu_file); - if (!newp->locus.mu_file) - return ENOMEM; - } - newp->locus.mu_line = sp->locus.mu_line; - newp->locus.mu_col = sp->locus.mu_col; + newp->locrange = sp->locrange; + mu_ident_ref (sp->locrange.beg.mu_file, + &sp->locrange.beg.mu_file); + mu_ident_ref (sp->locrange.end.mu_file, + &sp->locrange.end.mu_file); + *(mu_stream_t*) arg = str; } break; @@ -545,5 +644,33 @@ mu_log_stream_create (mu_stream_t *pstr, mu_stream_t transport) return 0; } + +static char wiki_url[] = "http://mailutils.org/wiki/Source_location_API#Deprecated_interface"; + +int +mu_ioctl_logstream_get_locus_deprecated (void) +{ + static int warned; + if (!warned) + { + mu_error (_("the program uses MU_IOCTL_LOGSTREAM_GET_LOCUS, which is deprecated")); + mu_error (_("please see %s, for detailed guidelines"), wiki_url); + warned = 1; + } + return MU_IOCTL_LOGSTREAM_GET_LOCUS_DEPRECATED; +} + +int +mu_ioctl_logstream_set_locus_deprecated (void) +{ + static int warned; + if (!warned) + { + mu_error (_("program uses MU_IOCTL_LOGSTREAM_SET_LOCUS, which is deprecated")); + mu_error (_("please see %s, for detailed guidelines"), wiki_url); + warned = 1; + } + return MU_IOCTL_LOGSTREAM_SET_LOCUS_DEPRECATED; +} diff --git a/libmailutils/tests/.gitignore b/libmailutils/tests/.gitignore index 39018d5..f0c34b9 100644 --- a/libmailutils/tests/.gitignore +++ b/libmailutils/tests/.gitignore @@ -19,6 +19,8 @@ fsfolder globtest imapio listop +linetrack +logstr mailcap mimehdr modmesg diff --git a/libmailutils/tests/Makefile.am b/libmailutils/tests/Makefile.am index f4f7fe2..e870cd7 100644 --- a/libmailutils/tests/Makefile.am +++ b/libmailutils/tests/Makefile.am @@ -54,6 +54,8 @@ noinst_PROGRAMS = \ globtest\ imapio\ listop\ + linetrack\ + logstr\ mailcap\ mimehdr\ modtofsaf\ @@ -105,6 +107,8 @@ TESTSUITE_AT = \ inline-comment.at\ linecon.at\ list.at\ + linetrack.at\ + logstr.at\ mailcap.at\ mimehdr.at\ modmesg00.at\ diff --git a/libmailutils/tests/linetrack.at b/libmailutils/tests/linetrack.at new file mode 100644 index 0000000..6f01b4d --- a/dev/null +++ b/libmailutils/tests/linetrack.at @@ -0,0 +1,109 @@ +# This file is part of GNU Mailutils. -*- Autotest -*- +# Copyright (C) 2017 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/>. + +AT_BANNER([Line tracker]) + +m4_pushdef([TRACKTEST],[ +AT_SETUP([$1]) +AT_KEYWORDS([tracker $2]) +AT_CHECK([linetrack liber $3 <<EOT +$4[]EOT +], +[0], +[$5], +[$6]) +AT_CLEANUP +]) + +TRACKTEST([normal operation],[],[7], +[ +agnosco +veteris\n +vestigia +flamme +\n +\n +Publius +Ovidius +Naso +], +[liber:1.1-7: agnosco +liber:1.8-14: veteris\n +liber:2.1-8: vestigia +liber:2.9-14: flamme +liber:2.14: \n +liber:3: \n +liber:4.1-7: Publius +liber:4.8-14: Ovidius +liber:4.15-18: Naso +]) + +TRACKTEST([retreat],[],[3], +[ +agnosco +\-4 +veteris +vestigia\n +flamme +\-8 +Publius +], +[liber:1.1-7: agnosco +liber:1.4-10: veteris +liber:1.11-18: vestigia\n +liber:2.1-6: flamme +liber:1.18-24: Publius +]) + +TRACKTEST([retreat over several lines],[],[4], +[ +one\n +two\n +three +\-11 +four +], +[liber:1.1-3: one\n +liber:2.1-3: two\n +liber:3.1-5: three +liber:1.3-6: four +]) + +TRACKTEST([retreat to the beginning],[],[4], +[one\n +two\n +\-8 +three +], +[liber:1.1-3: one\n +liber:2.1-3: two\n +liber:1.1-5: three +]) + +TRACKTEST([too big retreat],[],[2], +[one\n +two\n +\-10 +three +], +[liber:1.1-3: one\n +liber:2.1-3: two\n +liber:3.1-5: three +], +[linetrack: retreat count too big +]) + +m4_popdef([TRACKTEST]) diff --git a/libmailutils/tests/linetrack.c b/libmailutils/tests/linetrack.c new file mode 100644 index 0000000..c99440e --- a/dev/null +++ b/libmailutils/tests/linetrack.c @@ -0,0 +1,66 @@ +#include <mailutils/mailutils.h> +#include <mailutils/locus.h> + +int +main (int argc, char **argv) +{ + unsigned long max_lines; + char *end; + mu_linetrack_t trk; + int rc; + char *buf = NULL; + size_t size, n; + + mu_set_program_name (argv[0]); + mu_stdstream_setup (MU_STDSTREAM_RESET_NONE); + + if (argc != 3) + { + mu_error ("usage: %s FILE LINES", mu_program_name); + return 1; + } + max_lines = strtoul (argv[2], &end, 10); + if (*end || max_lines == 0) + { + mu_error ("invalid number of lines"); + return 1; + } + + MU_ASSERT (mu_linetrack_create (&trk, argv[1], max_lines)); + while ((rc = mu_stream_getline (mu_strin, &buf, &size, &n)) == 0 && n > 0) + { + struct mu_locus_range lr = MU_LOCUS_RANGE_INITIALIZER; + char *tok; + + n = mu_rtrim_class (buf, MU_CTYPE_SPACE); + if (n == 0) + continue; + if (buf[0] == '\\' && buf[1] == '-') + { + long x = strtol (buf+2, &end, 10); + if (*end || x == 0) + { + mu_error ("bad number"); + continue; + } + rc = mu_linetrack_retreat (trk, x); + if (rc == ERANGE) + mu_error ("retreat count too big"); + else if (rc) + mu_diag_funcall (MU_DIAG_ERROR, "mu_linetrack_retreat", buf+2, + rc); + } + else + { + mu_c_str_unescape (buf, "\\\n", "\\n", &tok); + mu_linetrack_advance (trk, &lr, tok, strlen (tok)); + free (tok); + mu_stream_lprintf (mu_strout, &lr, "%s\n", buf); + } + mu_locus_range_deinit (&lr); + } + mu_linetrack_destroy (&trk); + return 0; +} + + diff --git a/libmailutils/tests/logstr.at b/libmailutils/tests/logstr.at new file mode 100644 index 0000000..8a97dea --- a/dev/null +++ b/libmailutils/tests/logstr.at @@ -0,0 +1,77 @@ +# This file is part of GNU Mailutils. -*- Autotest -*- +# Copyright (C) 2017 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/>. + +AT_SETUP(Logger stream) +AT_KEYWORDS([logstream]) +AT_CHECK([logstr], +[0], +[00. simple print +hello world +01. severity +info: one +emerg: two +mode was: 0x0001 +02. suppress severity +info: this message is seen +emerg: and this one as well +03. suppress severity name +info: this message is seen +emerg: and this one as well +04. severity mask +one +two +emerg: three +05. locus: file, line +input:1: file, line +06. locus: file, line, col +input:1.1-10: file, line, col +07. locus: file, line-range +input:1-2: file, line-range +08. locus: file, line-range, col +input:1.1-2.10: file, line-range, col +09. locus: file-range, line-range, col-range +input:1.1-next:2.10: file-range, line-range, col-range +10. set locus line +input:1.1-next:2.10: initial +input:8.1-next:2.10: locus line changed +11. advance locus line +input:1.1-next:5.10: initial +input:3.1-next:5.10: locus line advanced +12. set locus column +input:1.1-next:2.10: initial +input:1.8-next:2.10: locus column changed +13. advance locus column +input:1.1-next:5.10: initial +input:1.5-next:5.10: locus line advanced +14. fmt: severity +info: severity +15. fmt: locus (file, line) +a:10: one +16. fmt: locus (file, line, column) +a:10.5: one +17. fmt: locus (range) +a:10.5-b:14.8: one +18. fmt: locus; restore defaults +a:10.5-b:14.8: one +default +19. fmt: locus; restore defaults, display locus +a:10.5-b:14.8: one +input:1.1-next:5.10: default +20. fmt: set locus +a:10.5-b:14.8: one +a:10.5-b:14.8: default +]) +AT_CLEANUP
\ No newline at end of file diff --git a/libmailutils/tests/logstr.c b/libmailutils/tests/logstr.c new file mode 100644 index 0000000..bf65e21 --- a/dev/null +++ b/libmailutils/tests/logstr.c @@ -0,0 +1,729 @@ +/* This file is part of GNU Mailutils test suite + Copyright (C) 2017 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/>. */ + +#include <mailutils/mailutils.h> +#include <mailutils/locus.h> + +/* Check normal operation. + Expected output: hello world +*/ +static void +simple_print (mu_stream_t str) +{ + mu_stream_printf (str, "hello world\n"); +} + +/* Check severity control. + Expected output: + info: one + emerg: two + mode was: 0x0001 +*/ +static void +check_severity (mu_stream_t str) +{ + unsigned severity = MU_DIAG_INFO; + int mode = MU_LOGMODE_SEVERITY, old_mode; + + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_MODE, &mode); + + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_SEVERITY, &severity); + mu_stream_printf (str, "one\n"); + + severity = MU_DIAG_EMERG; + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_SEVERITY, &severity); + mu_stream_printf (str, "two\n"); + + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_GET_MODE, &old_mode); + + mode = 0; + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_MODE, &mode); + mu_stream_printf (str, "mode was: 0x%04X\n", old_mode); +} + +/* Check severity suppression mechanism. + Expected output: + info: this message is seen + emerg: and this one as well +*/ +static void +check_suppress (mu_stream_t str) +{ + unsigned severity; + int mode = MU_LOGMODE_SEVERITY; + + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_MODE, &mode); + + severity = MU_DIAG_INFO; + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SUPPRESS_SEVERITY, + &severity); + + severity = MU_DIAG_DEBUG; + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_SEVERITY, &severity); + + mu_stream_printf (str, "this message is not seen\n"); + + severity = MU_DIAG_INFO; + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_SEVERITY, &severity); + mu_stream_printf (str, "this message is seen\n"); + + severity = MU_DIAG_EMERG; + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_SEVERITY, &severity); + mu_stream_printf (str, "and this one as well\n"); +} + +/* Check suppression by severity name. + Expected output: + info: this message is seen + emerg: and this one as well +*/ +static void +check_suppress_name (mu_stream_t str) +{ + int mode = MU_LOGMODE_SEVERITY, severity; + + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_MODE, &mode); + + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SUPPRESS_SEVERITY_NAME, + "info"); + + severity = MU_DIAG_DEBUG; + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_SEVERITY, &severity); + + mu_stream_printf (str, "this message is not seen\n"); + + severity = MU_DIAG_INFO; + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_SEVERITY, &severity); + mu_stream_printf (str, "this message is seen\n"); + + severity = MU_DIAG_EMERG; + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_SEVERITY, &severity); + mu_stream_printf (str, "and this one as well\n"); +} + +static void +comp_range (mu_stream_t str, struct mu_locus_range *lr1, + char const *file, int line) +{ + struct mu_locus_range lr2; + + MU_ASSERT (mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_GET_LOCUS_RANGE, &lr2)); + if (strcmp (lr1->beg.mu_file, lr2.beg.mu_file)) + mu_error ("%s:%d: beg.mu_file differs", file, line); + if (lr1->beg.mu_line != lr2.beg.mu_line) + mu_error ("%s:%d: beg.mu_line differs", file, line); + if (lr1->beg.mu_col != lr2.beg.mu_col) + mu_error ("%s:%d: beg.mu_col differs", file, line); + mu_ident_deref (lr2.beg.mu_file); + + if (strcmp (lr1->end.mu_file, lr2.end.mu_file)) + mu_error ("%s:%d: end.mu_file differs", __FILE__, __LINE__); + if (lr1->end.mu_line != lr2.end.mu_line) + mu_error ("%s:%d: end.mu_line differs", __FILE__, __LINE__); + if (lr1->end.mu_col != lr2.end.mu_col) + mu_error ("%s:%d: end.mu_col differs", __FILE__, __LINE__); + + mu_ident_deref (lr2.end.mu_file); +} + +/* Check MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE. + Passed: file, line. + Expected output: + input:1: file, line +*/ +static void +lr_file_line (mu_stream_t str) +{ + int mode = MU_LOGMODE_LOCUS; + struct mu_locus_range lr; + + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_MODE, &mode); + + lr.beg.mu_file = "input"; + lr.beg.mu_line = 1; + lr.beg.mu_col = 0; + + lr.end.mu_file = "input"; + lr.end.mu_line = 1; + lr.end.mu_col = 0; + + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, &lr); + + mu_stream_printf (str, "file, line\n"); + + comp_range (str, &lr, __FILE__, __LINE__); +} + +/* Check MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE. + Passed: file, line, col. + Expected output: + input:1.1-10: file, line, col +*/ +static void +lr_file_line_col (mu_stream_t str) +{ + int mode = MU_LOGMODE_LOCUS; + struct mu_locus_range lr; + + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_MODE, &mode); + + lr.beg.mu_file = "input"; + lr.beg.mu_line = 1; + lr.beg.mu_col = 1; + + lr.end.mu_file = "input"; + lr.end.mu_line = 1; + lr.end.mu_col = 10; + + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, &lr); + + mu_stream_printf (str, "file, line, col\n"); + + comp_range (str, &lr, __FILE__, __LINE__); +} + +/* Check MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE. + Passed: file, line-range + Expected output: + input:1-2: file, line-range +*/ +static void +lr_file_line2 (mu_stream_t str) +{ + int mode = MU_LOGMODE_LOCUS; + struct mu_locus_range lr; + + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_MODE, &mode); + + lr.beg.mu_file = "input"; + lr.beg.mu_line = 1; + lr.beg.mu_col = 0; + + lr.end.mu_file = "input"; + lr.end.mu_line = 2; + lr.end.mu_col = 0; + + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, &lr); + + mu_stream_printf (str, "file, line-range\n"); + + comp_range (str, &lr, __FILE__, __LINE__); +} + +/* Check MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE. + Passed: file, line-range, column + Expected output: + input:1.1-2.10: file, line-range, col +*/ +static void +lr_file_line2_col (mu_stream_t str) +{ + int mode = MU_LOGMODE_LOCUS; + struct mu_locus_range lr; + + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_MODE, &mode); + + lr.beg.mu_file = "input"; + lr.beg.mu_line = 1; + lr.beg.mu_col = 1; + + lr.end.mu_file = "input"; + lr.end.mu_line = 2; + lr.end.mu_col = 10; + + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, &lr); + + mu_stream_printf (str, "file, line-range, col\n"); + + comp_range (str, &lr, __FILE__, __LINE__); +} + +/* Check MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE. + Passed: file-range, line-range, column-range + Expected output: + input:1.1-next:2.10: file-range, line-range, col-range +*/ +static void +lr_file2_line_col (mu_stream_t str) +{ + int mode = MU_LOGMODE_LOCUS; + struct mu_locus_range lr; + + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_MODE, &mode); + + lr.beg.mu_file = "input"; + lr.beg.mu_line = 1; + lr.beg.mu_col = 1; + + lr.end.mu_file = "next"; + lr.end.mu_line = 2; + lr.end.mu_col = 10; + + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, &lr); + + mu_stream_printf (str, "file-range, line-range, col-range\n"); + + comp_range (str, &lr, __FILE__, __LINE__); +} + +/* Check MU_IOCTL_LOGSTREAM_SET_LOCUS_LINE. + Expected output: + input:1.1-next:2.10: initial + input:8.1-next:2.10: locus line changed +*/ +static void +set_locus_line (mu_stream_t str) +{ + int mode = MU_LOGMODE_LOCUS; + struct mu_locus_range lr; + unsigned line; + + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_MODE, &mode); + + lr.beg.mu_file = "input"; + lr.beg.mu_line = 1; + lr.beg.mu_col = 1; + + lr.end.mu_file = "next"; + lr.end.mu_line = 2; + lr.end.mu_col = 10; + + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, &lr); + mu_stream_printf (str, "initial\n"); + line = 8; + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_LOCUS_LINE, &line); + mu_stream_printf (str, "locus line changed\n"); + lr.beg.mu_line = line; + comp_range (str, &lr, __FILE__, __LINE__); +} + +/* Check MU_IOCTL_LOGSTREAM_ADVANCE_LOCUS_LINE. + Expected output: + input:1.1-next:5.10: initial + input:3.1-next:5.10: locus line advanced +*/ +static void +advance_locus_line (mu_stream_t str) +{ + int mode = MU_LOGMODE_LOCUS; + struct mu_locus_range lr; + unsigned line; + + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_MODE, &mode); + + lr.beg.mu_file = "input"; + lr.beg.mu_line = 1; + lr.beg.mu_col = 1; + + lr.end.mu_file = "next"; + lr.end.mu_line = 5; + lr.end.mu_col = 10; + + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, &lr); + mu_stream_printf (str, "initial\n"); + line = 2; + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_ADVANCE_LOCUS_LINE, &line); + mu_stream_printf (str, "locus line advanced\n"); + + lr.beg.mu_line += line; + comp_range (str, &lr, __FILE__, __LINE__); +} + +/* Check MU_IOCTL_LOGSTREAM_SET_LOCUS_COL. + Expected output: + input:1.1-next:2.10: initial + input:1.8-next:2.10: locus column changed +*/ +static void +set_locus_col (mu_stream_t str) +{ + int mode = MU_LOGMODE_LOCUS; + struct mu_locus_range lr; + unsigned col; + + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_MODE, &mode); + + lr.beg.mu_file = "input"; + lr.beg.mu_line = 1; + lr.beg.mu_col = 1; + + lr.end.mu_file = "next"; + lr.end.mu_line = 2; + lr.end.mu_col = 10; + + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, &lr); + mu_stream_printf (str, "initial\n"); + col = 8; + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_LOCUS_COL, &col); + mu_stream_printf (str, "locus column changed\n"); + lr.beg.mu_col = col; + comp_range (str, &lr, __FILE__, __LINE__); +} + +/* Check MU_IOCTL_LOGSTREAM_ADVANCE_LOCUS_COL. + Expected output: + input:1.1-next:5.10: initial + input:1.5-next:5.10: locus line advanced +*/ +static void +advance_locus_col (mu_stream_t str) +{ + int mode = MU_LOGMODE_LOCUS; + struct mu_locus_range lr; + unsigned col; + + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_MODE, &mode); + + lr.beg.mu_file = "input"; + lr.beg.mu_line = 1; + lr.beg.mu_col = 1; + + lr.end.mu_file = "next"; + lr.end.mu_line = 5; + lr.end.mu_col = 10; + + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, &lr); + mu_stream_printf (str, "initial\n"); + col = 4; + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_ADVANCE_LOCUS_COL, &col); + mu_stream_printf (str, "locus line advanced\n"); + + lr.beg.mu_col += col; + comp_range (str, &lr, __FILE__, __LINE__); +} + +/* Check severity mask. + Expected output: + one + two + emerg: two + */ +static void +check_severity_mask (mu_stream_t str) +{ + unsigned severity; + int mode = MU_LOGMODE_SEVERITY, mask; + + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_MODE, &mode); + + mask = MU_DEBUG_LEVEL_UPTO (MU_DIAG_NOTICE); + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_SEVERITY_MASK, &mask); + + severity = MU_DIAG_INFO; + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_SEVERITY, &severity); + mu_stream_printf (str, "one\n"); + + severity = MU_DIAG_NOTICE; + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_SEVERITY, &severity); + mu_stream_printf (str, "two\n"); + + severity = MU_DIAG_EMERG; + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_SEVERITY, &severity); + mu_stream_printf (str, "three\n"); +} + +/* Check ESC-s & ESC-O format specifiers. + Expected output: + info: severity +*/ +static void +fmt_severity (mu_stream_t str) +{ + mu_stream_printf (str, "\033s<%d>\033O<%d>severity\n", + MU_DIAG_INFO, MU_LOGMODE_SEVERITY); +} + +/* Check ESC-f and ESC-l format specifiers. + Expected output: + a:10: one +*/ +static void +fmt_locus1 (mu_stream_t str) +{ + char *file = "a"; + mu_stream_printf (str, "\033f<%d>%s\033l<%d>one\n", + (int) strlen (file), file, 10); +} + +/* Check ESC-f, ESC-l, and ESC-c format specifiers. + Expected output: + a:10.5: one +*/ +static void +fmt_locus2 (mu_stream_t str) +{ + char *file = "a"; + mu_stream_printf (str, "\033f<%d>%s\033l<%d>\033c<%d>one\n", + (int) strlen (file), file, 10, 5); +} + +/* Check setting range with ESC-f, ESC-l, and ESC-c format specifiers. + Expected output: + a:10.5-b:14.8: one +*/ +static void +fmt_locus3 (mu_stream_t str) +{ + char *file[] = { "a", "b" }; + mu_stream_printf (str, "\033f<%d>%s\033l<%d>\033c<%d>" + "\033f<%d>%s\033l<%d>\033c<%d>one\n", + (int) strlen (file[0]), file[0], 10, 5, + (int) strlen (file[1]), file[1], 14, 8); +} + +/* Check that ESC-f, ESC-l, and ESC-c format specifiers don't clobber + default stream settings. + Expected output: + a:10.5-b:14.8: one + default +*/ +static void +fmt_locus4 (mu_stream_t str) +{ + char *file[] = { "a", "b" }; + struct mu_locus_range lr; + + lr.beg.mu_file = "input"; + lr.beg.mu_line = 1; + lr.beg.mu_col = 1; + + lr.end.mu_file = "next"; + lr.end.mu_line = 5; + lr.end.mu_col = 10; + + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, &lr); + + mu_stream_printf (str, "\033f<%d>%s\033l<%d>\033c<%d>" + "\033f<%d>%s\033l<%d>\033c<%d>one\n", + (int) strlen (file[0]), file[0], 10, 5, + (int) strlen (file[1]), file[1], 14, 8); + mu_stream_printf (str, "default\n"); +} + +/* Check that ESC-f, ESC-l, and ESC-c format specifiers don't clobber + default stream settings and locus. + Expected output: + a:10.5-b:14.8: one + input:1.1-next:5.10: default +*/ +static void +fmt_locus5 (mu_stream_t str) +{ + char *file[] = { "a", "b" }; + struct mu_locus_range lr; + int mode; + + lr.beg.mu_file = "input"; + lr.beg.mu_line = 1; + lr.beg.mu_col = 1; + + lr.end.mu_file = "next"; + lr.end.mu_line = 5; + lr.end.mu_col = 10; + + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, &lr); + + mode = MU_LOGMODE_LOCUS; + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_MODE, &mode); + mu_stream_printf (str, "\033f<%d>%s\033l<%d>\033c<%d>" + "\033f<%d>%s\033l<%d>\033c<%d>one\n", + (int) strlen (file[0]), file[0], 10, 5, + (int) strlen (file[1]), file[1], 14, 8); + mu_stream_printf (str, "default\n"); +} + +/* Check the ESC-S specifier (store locus). + Expected output: + a:10.5-b:14.8: one + a:10.5-b:14.8: default +*/ +static void +fmt_locus6 (mu_stream_t str) +{ + char *file[] = { "a", "b" }; + struct mu_locus_range lr; + int mode; + + lr.beg.mu_file = "input"; + lr.beg.mu_line = 1; + lr.beg.mu_col = 1; + + lr.end.mu_file = "next"; + lr.end.mu_line = 5; + lr.end.mu_col = 10; + + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, &lr); + + mode = MU_LOGMODE_LOCUS; + mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_MODE, &mode); + mu_stream_printf (str, "\033S\033f<%d>%s\033l<%d>\033c<%d>" + "\033f<%d>%s\033l<%d>\033c<%d>one\n", + (int) strlen (file[0]), file[0], 10, 5, + (int) strlen (file[1]), file[1], 14, 8); + mu_stream_printf (str, "default\n"); +} + + +struct testcase +{ + char const *id; + void (*handler) (mu_stream_t); + int enabled; +}; + +struct testcase testcases[] = { + { "simple print", simple_print }, + { "severity", check_severity }, + { "suppress severity", check_suppress }, + { "suppress severity name", check_suppress_name }, + { "severity mask", check_severity_mask }, + { "locus: file, line", lr_file_line }, + { "locus: file, line, col", lr_file_line_col }, + { "locus: file, line-range", lr_file_line2 }, + { "locus: file, line-range, col", lr_file_line2_col }, + { "locus: file-range, line-range, col-range", lr_file2_line_col }, + { "set locus line", set_locus_line }, + { "advance locus line", advance_locus_line }, + { "set locus column", set_locus_col }, + { "advance locus column", advance_locus_col }, + { "fmt: severity", fmt_severity }, + { "fmt: locus (file, line)", fmt_locus1 }, + { "fmt: locus (file, line, column)", fmt_locus2 }, + { "fmt: locus (range)", fmt_locus3 }, + { "fmt: locus; restore defaults", fmt_locus4 }, + { "fmt: locus; restore defaults, display locus", fmt_locus5 }, + { "fmt: set locus", fmt_locus6 }, + { NULL } +}; + +static mu_stream_t +create_log (void) +{ + mu_stream_t str, transport; + int yes = 1; + + MU_ASSERT (mu_stdio_stream_create (&transport, MU_STDOUT_FD, 0)); + mu_stream_ioctl (transport, MU_IOCTL_FD, MU_IOCTL_FD_SET_BORROW, &yes); + MU_ASSERT (mu_log_stream_create (&str, transport)); + mu_stream_unref (transport); + return str; +} + +static void +log_reset (mu_stream_t str) +{ + int mode = 0; + MU_ASSERT (mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_MODE, &mode)); + MU_ASSERT (mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, NULL)); + mode = 0; + MU_ASSERT (mu_stream_ioctl (str, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_SEVERITY_MASK, + &mode)); +} + +int +main (int argc, char **argv) +{ + mu_stream_t log; + struct testcase *tp; + int i; + int ena = 0; + + mu_set_program_name (argv[0]); + mu_stdstream_setup (MU_STDSTREAM_RESET_NONE); + + if (argc > 1) + { + ena = 1; + for (i = 1; i < argc; i++) + { + char *p; + int n = strtol (argv[i], &p, 10); + if (! (*p == 0 && n >= 0) ) + { + mu_error ("erroneous argument %s\n", argv[i]); + return 1; + } + testcases[n].enabled = ena; + } + } + + log = create_log (); + + for (i = 0, tp = testcases; tp->id; tp++, i++) + { + if (tp->enabled == ena) + { + mu_stream_printf (log, "%02d. %s\n", i, tp->id); + tp->handler (log); + log_reset (log); + } + } + + return 0; +} + + diff --git a/libmailutils/tests/testsuite.at b/libmailutils/tests/testsuite.at index d962bd6..f064462 100644 --- a/libmailutils/tests/testsuite.at +++ b/libmailutils/tests/testsuite.at @@ -153,6 +153,10 @@ m4_include([strin.at]) m4_include([strout.at]) m4_include([strerr.at]) +AT_BANNER([Streams]) +m4_include([logstr.at]) +m4_include([xscript.at]) + m4_include([list.at]) m4_include([address.at]) m4_include([wordsplit.at]) @@ -209,4 +213,4 @@ m4_include([msgset.at]) m4_include([globtest.at]) -m4_include([xscript.at]) +m4_include([linetrack.at]) diff --git a/libmailutils/tests/wicket.c b/libmailutils/tests/wicket.c index 1d77946..e5cf5b5 100644 --- a/libmailutils/tests/wicket.c +++ b/libmailutils/tests/wicket.c @@ -30,7 +30,7 @@ match_string (const char *str) { int rc; mu_url_t u, url; - struct mu_locus loc; + struct mu_locus_point loc; if ((rc = mu_url_create (&u, str)) != 0) { diff --git a/libmailutils/tests/xscript.at b/libmailutils/tests/xscript.at index 34189ba..47b2bea 100644 --- a/libmailutils/tests/xscript.at +++ b/libmailutils/tests/xscript.at @@ -14,7 +14,6 @@ # You should have received a copy of the GNU General Public License # along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. -AT_BANNER([Transcript stream]) AT_SETUP([Transcript stream]) AT_KEYWORDS([stream xscript]) AT_DATA([input],[first line diff --git a/libmu_auth/radius.c b/libmu_auth/radius.c index acd5634..68d3061 100644 --- a/libmu_auth/radius.c +++ b/libmu_auth/radius.c @@ -84,7 +84,8 @@ enum parse_state state_lhs, state_op, state_rhs, - state_delim + state_delim, + state_err }; static int @@ -96,7 +97,7 @@ cb_request (void *data, mu_config_value_t *val) enum parse_state state; grad_locus_t loc; char *name; - struct mu_locus locus; + struct mu_locus_range locus; if (mu_cfg_assert_value_type (val, MU_CFG_STRING)) return 1; @@ -111,11 +112,11 @@ cb_request (void *data, mu_config_value_t *val) } if (mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, - MU_IOCTL_LOGSTREAM_GET_LOCUS, + MU_IOCTL_LOGSTREAM_GET_LOCUS_RANGE, &locus) == 0) { - loc.file = locus.mu_file; - loc.line = locus.mu_line; + loc.file = (char*) locus.beg.mu_file; + loc.line = locus.beg.mu_line; } else { @@ -123,7 +124,7 @@ cb_request (void *data, mu_config_value_t *val) loc.line = 0; } - for (i = 0, state = state_lhs; i < ws.ws_wordc; i++) + for (i = 0, state = state_lhs; state != state_err && i < ws.ws_wordc; i++) { grad_avp_t *pair; @@ -146,23 +147,36 @@ cb_request (void *data, mu_config_value_t *val) if (!pair) { mu_error (_("cannot create radius A/V pair `%s'"), name); - return 1; + state = state_err; + } + else + { + grad_avl_merge (plist, &pair); + state = state_delim; } - grad_avl_merge (plist, &pair); - state = state_delim; break; case state_delim: if (strcmp (ws.ws_wordv[i], ",")) { mu_error (_("expected `,' but found `%s'"), ws.ws_wordv[i]); - return 1; + state = state_err; } - state = state_lhs; + else + state = state_lhs; + break; + + default: + abort (); } } - mu_wordsplit_free (&ws); + mu_wordsplit_free (&ws); + mu_locus_range_deinit (&locus); + + if (state == state_err) + return 1; + if (state != state_delim && state != state_delim) { mu_error (_("malformed radius A/V list")); diff --git a/libmu_sieve/Makefile.am b/libmu_sieve/Makefile.am index 1e75e33..2954794 100644 --- a/libmu_sieve/Makefile.am +++ b/libmu_sieve/Makefile.am @@ -15,7 +15,7 @@ ## You should have received a copy of the GNU General Public License ## along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. -YLWRAP = $(SHELL) $(mu_aux_dir)/gylwrap +YLWRAP = @MU_YLWRAP@ AM_YFLAGS = -dtv #AM_LEXFLAGS=-dvp AM_CPPFLAGS =\ @@ -39,9 +39,8 @@ libmu_sieve_la_SOURCES = \ relational.c\ require.c\ runtime.c\ - sieve-gram.c\ - sieve-gram.h\ - sieve-lex.c\ + sieve-gram.y\ + sieve-lex.l\ strexp.c\ string.c\ tests.c\ @@ -50,24 +49,14 @@ libmu_sieve_la_SOURCES = \ libmu_sieve_la_LIBADD = ${MU_LIB_MAILUTILS} @LTDL_LIB@ libmu_sieve_la_LDFLAGS = -version-info @VI_CURRENT@:@VI_REVISION@:@VI_AGE@ -noinst_HEADERS = sieve-priv.h +noinst_HEADERS = sieve-priv.h sieve-gram.h BUILT_SOURCES = \ sieve-gram.c sieve-gram.h \ sieve-lex.c -MAINTAINERCLEANFILES=$(BUILT_SOURCES) - -EXTRA_DIST = sieve.y sieve.l +EXTRA_DIST=gylwrap.conf -sieve-lex.c: $(srcdir)/sieve.l sieve-gram.h - $(YLWRAP) "$(LEX) $(AM_LEXFLAGS) $(LEXFLAGS)" \ - $(srcdir)/sieve.l lex.yy.c sieve-lex.c \ - -- -yy mu_sieve_yy - -sieve-gram.c sieve-gram.h: $(srcdir)/sieve.y - $(YLWRAP) "$(YACC) $(AM_YFLAGS) $(YFLAGS)" $(srcdir)/sieve.y \ - y.tab.c sieve-gram.c y.tab.h sieve-gram.h y.output y.output \ - -- -yy mu_sieve_yy +MAINTAINERCLEANFILES=$(BUILT_SOURCES) diff --git a/libmu_sieve/actions.c b/libmu_sieve/actions.c index 93b33e0..39b66fc 100644 --- a/libmu_sieve/actions.c +++ b/libmu_sieve/actions.c @@ -528,8 +528,8 @@ perms_tag_checker (mu_sieve_machine_t mach) { if (mu_parse_stream_perm_string (&flag, t->v.string, &p)) { - mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, - _("invalid permissions (near %s)"), p); + mu_diag_at_locus_range (MU_LOG_ERROR, &t->locus, + _("invalid permissions (near %s)"), p); mu_i_sv_error (mach); err = 1; } diff --git a/libmu_sieve/comparator.c b/libmu_sieve/comparator.c index 8b7e583..1a3be1a 100644 --- a/libmu_sieve/comparator.c +++ b/libmu_sieve/comparator.c @@ -174,7 +174,7 @@ mu_sieve_match_part_checker (mu_sieve_machine_t mach) { if (match) { - mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, + mu_diag_at_locus_range (MU_LOG_ERROR, &t->locus, _("match type specified twice in call to `%s'"), mach->identifier); mu_i_sv_error (mach); @@ -209,7 +209,7 @@ mu_sieve_match_part_checker (mu_sieve_machine_t mach) if (compname && strcmp (compname, "i;ascii-numeric")) { - mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, + mu_diag_at_locus_range (MU_LOG_ERROR, &match->locus, /* TRANSLATORS: Do not translate ':count'. It is the name of a Sieve tag */ _("comparator %s is incompatible with " @@ -235,7 +235,7 @@ mu_sieve_match_part_checker (mu_sieve_machine_t mach) break; /* fall through */ default: - mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, + mu_diag_at_locus_range (MU_LOG_ERROR, &val->locus, _(":count requires second argument to be a list of one element")); mu_i_sv_error (mach); return 1; @@ -246,7 +246,7 @@ mu_sieve_match_part_checker (mu_sieve_machine_t mach) char *p = mu_str_skip_class (argstr->orig, MU_CTYPE_DIGIT); if (*p) { - mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, + mu_diag_at_locus_range (MU_LOG_ERROR, &val->locus, _("second argument cannot be converted to number")); mu_i_sv_error (mach); return 1; @@ -258,7 +258,7 @@ mu_sieve_match_part_checker (mu_sieve_machine_t mach) if (mu_sieve_str_to_relcmp (str, NULL, NULL)) { - mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, + mu_diag_at_locus_range (MU_LOG_ERROR, &match->locus, _("invalid relational match `%s' in call to `%s'"), str, mach->identifier); mu_i_sv_error (mach); @@ -278,10 +278,16 @@ mu_sieve_match_part_checker (mu_sieve_machine_t mach) compfun = mu_sieve_comparator_lookup (mach, compname, matchtype); if (!compfun) { - mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, + if (match) + mu_diag_at_locus_range (MU_LOG_ERROR, &match->locus, + _("comparator `%s' is incompatible with match type `%s' in call to `%s'"), + compname, match->tag, + mach->identifier); + else + mu_diag_at_locus_range (MU_LOG_ERROR, &mach->locus, _("comparator `%s' is incompatible with match type `%s' in call to `%s'"), - compname, match ? match->tag : "is", - mach->identifier); + compname, "is", + mach->identifier); mu_i_sv_error (mach); return 1; } diff --git a/libmu_sieve/extensions/moderator.c b/libmu_sieve/extensions/moderator.c index 5ec61d2..f82e615 100644 --- a/libmu_sieve/extensions/moderator.c +++ b/libmu_sieve/extensions/moderator.c @@ -103,7 +103,7 @@ moderator_filter_message (mu_sieve_machine_t mach, } else if (mu_sieve_get_tag (mach, "program", SVT_STRING, &arg)) { - struct mu_locus locus; + struct mu_locus_range locrange = MU_LOCUS_RANGE_INITIALIZER; rc = mu_sieve_machine_clone (mach, &newmach); if (rc) @@ -112,10 +112,10 @@ moderator_filter_message (mu_sieve_machine_t mach, mu_strerror (rc)); return 1; } - mu_sieve_get_locus (mach, &locus); - rc = mu_sieve_compile_buffer (newmach, - arg, strlen (arg), - locus.mu_file, locus.mu_line); + mu_sieve_get_locus (mach, &locrange); + rc = mu_sieve_compile_text (newmach, + arg, strlen (arg), + &locrange.beg); if (rc) mu_sieve_error (mach, _("cannot compile subprogram")); } diff --git a/libmu_sieve/gylwrap.conf b/libmu_sieve/gylwrap.conf new file mode 100644 index 0000000..3f574d7 --- a/dev/null +++ b/libmu_sieve/gylwrap.conf @@ -0,0 +1,4 @@ +# Configuration settings for gylwrap. +# See ../mu-aux/gylwrap --help, for details. + +yyrepl=mu_sieve_yy diff --git a/libmu_sieve/mem.c b/libmu_sieve/mem.c index 5a89fa8..f98e747 100644 --- a/libmu_sieve/mem.c +++ b/libmu_sieve/mem.c @@ -218,7 +218,7 @@ mu_i_sv_2nrealloc (mu_sieve_machine_t mach, void **pptr, size_t *pnmemb, worth the trouble. */ if ((size_t) -1 / 3 * 2 / size <= nmemb) { - mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, + mu_diag_at_locus_range (MU_LOG_ERROR, &mach->locus, _("requested too much memory %zu * %zu"), nmemb, size); mu_sieve_abort (mach); @@ -232,19 +232,19 @@ mu_i_sv_2nrealloc (mu_sieve_machine_t mach, void **pptr, size_t *pnmemb, *pnmemb = nmemb; } -char * -mu_i_sv_id_canon (mu_sieve_machine_t mach, char const *name) +size_t +mu_i_sv_id_num (mu_sieve_machine_t mach, char const *name) { size_t i; char *p; if (!name) - return NULL; + abort (); for (i = 0; i < mach->idcount; i++) { if (strcmp (mach->idspace[i], name) == 0) - return mach->idspace[i]; + return i; } if (mach->idcount == mach->idmax) @@ -256,24 +256,11 @@ mu_i_sv_id_canon (mu_sieve_machine_t mach, char const *name) } p = mu_sieve_strdup (mach, name); - mach->idspace[mach->idcount++] = p; + mach->idspace[mach->idcount] = p; - return p; + return mach->idcount++; } -size_t -mu_i_sv_id_num (mu_sieve_machine_t mach, char const *name) -{ - size_t i; - - for (i = 0; i < mach->idcount; i++) - { - if (mach->idspace[i] == name || strcmp (mach->idspace[i], name) == 0) - return i; - } - abort (); -} - char * mu_i_sv_id_str (mu_sieve_machine_t mach, size_t n) { diff --git a/libmu_sieve/prog.c b/libmu_sieve/prog.c index dc2ae93..70e0453 100644 --- a/libmu_sieve/prog.c +++ b/libmu_sieve/prog.c @@ -35,32 +35,48 @@ mu_i_sv_code (struct mu_sieve_machine *mach, sieve_op_t op) mach->prog[mach->pc++] = op; } -static int -file_eq (char const *a, char const *b) -{ - if (a) - return b ? (strcmp (a, b) == 0) : 1; - return b ? 0 : 1; -} - -/* FIXME: 1. Only beg is stored - 2. mu_col is not used - */ int mu_i_sv_locus (struct mu_sieve_machine *mach, struct mu_locus_range *lr) { - if (!file_eq (mach->locus.mu_file, lr->beg.mu_file)) + if (!mu_locus_point_same_file (&mach->locus.beg, &lr->beg)) { mu_i_sv_code (mach, (sieve_op_t) _mu_i_sv_instr_source); mu_i_sv_code (mach, (sieve_op_t) mu_i_sv_id_num (mach, lr->beg.mu_file)); + mu_i_sv_code (mach, (sieve_op_t) (int) 0); } - if (mach->locus.mu_line != lr->beg.mu_line) + if (mach->locus.beg.mu_line != lr->beg.mu_line) { mu_i_sv_code (mach, (sieve_op_t) _mu_i_sv_instr_line); mu_i_sv_code (mach, (sieve_op_t) lr->beg.mu_line); + mu_i_sv_code (mach, (sieve_op_t) (int) 0); + } + if (mach->locus.beg.mu_col != lr->beg.mu_col) + { + mu_i_sv_code (mach, (sieve_op_t) _mu_i_sv_instr_col); + mu_i_sv_code (mach, (sieve_op_t) lr->beg.mu_col); + mu_i_sv_code (mach, (sieve_op_t) (int) 0); + } + + if (!mu_locus_point_same_file (&mach->locus.end, &lr->end)) + { + mu_i_sv_code (mach, (sieve_op_t) _mu_i_sv_instr_source); + mu_i_sv_code (mach, (sieve_op_t) mu_i_sv_id_num (mach, lr->end.mu_file)); + mu_i_sv_code (mach, (sieve_op_t) (int) 1); + } + if (mach->locus.end.mu_line != lr->end.mu_line) + { + mu_i_sv_code (mach, (sieve_op_t) _mu_i_sv_instr_line); + mu_i_sv_code (mach, (sieve_op_t) lr->end.mu_line); + mu_i_sv_code (mach, (sieve_op_t) (int) 1); + } + if (mach->locus.end.mu_col != lr->end.mu_col) + { + mu_i_sv_code (mach, (sieve_op_t) _mu_i_sv_instr_col); + mu_i_sv_code (mach, (sieve_op_t) lr->end.mu_col); + mu_i_sv_code (mach, (sieve_op_t) (int) 1); } - mach->locus = lr->beg; + mu_locus_range_copy (&mach->locus, lr); return 0; } @@ -155,7 +171,7 @@ mu_i_sv_lint_command (struct mu_sieve_machine *mach, if (!tag) { - mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, + mu_diag_at_locus_range (MU_LOG_ERROR, &val->locus, _("invalid tag name `%s' for `%s'"), val->v.string, reg->name); mu_i_sv_error (mach); @@ -175,7 +191,8 @@ mu_i_sv_lint_command (struct mu_sieve_machine *mach, { if (i + 1 == node->v.command.argcount) { - mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, + /* FIXME: more exact locus */ + mu_diag_at_locus_range (MU_LOG_ERROR, &mach->locus, _("required argument for tag %s is missing"), tag->name); mu_i_sv_error (mach); @@ -192,11 +209,11 @@ mu_i_sv_lint_command (struct mu_sieve_machine *mach, if (val->type != tag->argtype) { - mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, + mu_diag_at_locus_range (MU_LOG_ERROR, &val->locus, _("type mismatch in argument to " "tag `%s'"), tag->name); - mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, + mu_diag_at_locus_range (MU_LOG_ERROR, &val->locus, _("expected %s but passed %s"), mu_sieve_type_str (tag->argtype), mu_sieve_type_str (val->type)); @@ -210,7 +227,7 @@ mu_i_sv_lint_command (struct mu_sieve_machine *mach, { if (!chk_list && (rc = mu_list_create (&chk_list))) { - mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, + mu_diag_at_locus_range (MU_LOG_ERROR, &mach->locus, _("cannot create check list: %s"), mu_strerror (rc)); mu_i_sv_error (mach); @@ -222,7 +239,7 @@ mu_i_sv_lint_command (struct mu_sieve_machine *mach, rc = mu_list_append (chk_list, cf); if (rc) { - mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, + mu_diag_at_locus_range (MU_LOG_ERROR, &mach->locus, "mu_list_append: %s", mu_strerror (rc)); mu_i_sv_error (mach); @@ -243,7 +260,7 @@ mu_i_sv_lint_command (struct mu_sieve_machine *mach, } else { - mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, + mu_diag_at_locus_range (MU_LOG_ERROR, &mach->locus, _("too many arguments in call to `%s'"), reg->name); mu_i_sv_error (mach); @@ -258,11 +275,11 @@ mu_i_sv_lint_command (struct mu_sieve_machine *mach, /* compatible types */; else { - mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, + mu_diag_at_locus_range (MU_LOG_ERROR, &val->locus, _("type mismatch in argument %lu to `%s'"), (unsigned long) (exp_arg - reg->v.command.req_args + 1), reg->name); - mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, + mu_diag_at_locus_range (MU_LOG_ERROR, &val->locus, _("expected %s but passed %s"), mu_sieve_type_str (*exp_arg), mu_sieve_type_str (val->type)); @@ -277,9 +294,9 @@ mu_i_sv_lint_command (struct mu_sieve_machine *mach, if (!err && !opt_args && *exp_arg != SVT_VOID) { - mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, - _("too few arguments in call to `%s'"), - reg->name); + mu_diag_at_locus_range (MU_LOG_ERROR, &mach->locus, + _("too few arguments in call to `%s'"), + reg->name); mu_i_sv_error (mach); err = 1; } diff --git a/libmu_sieve/require.c b/libmu_sieve/require.c index 597af98..b5c9699 100644 --- a/libmu_sieve/require.c +++ b/libmu_sieve/require.c @@ -56,7 +56,7 @@ mu_sieve_require (mu_sieve_machine_t mach, mu_sieve_slice_t list) if (rc) { - mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, _("can't require %s"), + mu_diag_at_locus_range (MU_LOG_ERROR, &mach->locus, _("can't require %s"), name); mu_i_sv_error (mach); } diff --git a/libmu_sieve/runtime.c b/libmu_sieve/runtime.c index c5c1ab5..b18b996 100644 --- a/libmu_sieve/runtime.c +++ b/libmu_sieve/runtime.c @@ -34,26 +34,46 @@ void _mu_i_sv_instr_source (mu_sieve_machine_t mach) { - mach->locus.mu_file = mu_i_sv_id_str (mach, SIEVE_RT_ARG (mach, 0, pc)); - mu_stream_ioctl (mach->errstream, MU_IOCTL_LOGSTREAM, - MU_IOCTL_LOGSTREAM_SET_LOCUS, - &mach->locus); + char const *file = mu_i_sv_id_str (mach, SIEVE_RT_ARG (mach, 0, pc)); + int what = SIEVE_RT_ARG (mach, 1, inum); + mu_locus_point_set_file (what ? &mach->locus.beg : &mach->locus.end, file); if (INSTR_DEBUG (mach)) - mu_i_sv_debug (mach, mach->pc - 1, "SOURCE %s", mach->locus.mu_file); - SIEVE_RT_ADJUST (mach, 1); + mu_i_sv_debug (mach, mach->pc - 2, "SOURCE %s %d", file, what); + SIEVE_RT_ADJUST (mach, 2); + mu_stream_ioctl (mach->errstream, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, &mach->locus); } void _mu_i_sv_instr_line (mu_sieve_machine_t mach) { - mach->locus.mu_line = SIEVE_RT_ARG (mach, 0, line); + unsigned line = SIEVE_RT_ARG (mach, 0, line); + int what = SIEVE_RT_ARG (mach, 1, inum); + if (what == 0) + mach->locus.beg.mu_line = line; + else + mach->locus.end.mu_line = line; + if (INSTR_DEBUG (mach)) + mu_i_sv_debug (mach, mach->pc - 1, "LINE %u %d", line, what); + SIEVE_RT_ADJUST (mach, 2); mu_stream_ioctl (mach->errstream, MU_IOCTL_LOGSTREAM, - MU_IOCTL_LOGSTREAM_SET_LOCUS, - &mach->locus); + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, &mach->locus); +} + +void +_mu_i_sv_instr_col (mu_sieve_machine_t mach) +{ + unsigned col = SIEVE_RT_ARG (mach, 0, line); + int what = SIEVE_RT_ARG (mach, 1, inum); + if (what == 0) + mach->locus.beg.mu_col = col; + else + mach->locus.end.mu_col = col; if (INSTR_DEBUG (mach)) - mu_i_sv_debug (mach, mach->pc - 1, "LINE %u", - mach->locus.mu_line); - SIEVE_RT_ADJUST (mach, 1); + mu_i_sv_debug (mach, mach->pc - 2, "COLUMN %u %d", col, what); + SIEVE_RT_ADJUST (mach, 2); + mu_stream_ioctl (mach->errstream, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, &mach->locus); } static int @@ -173,14 +193,9 @@ mu_sieve_get_data (mu_sieve_machine_t mach) } int -mu_sieve_get_locus (mu_sieve_machine_t mach, struct mu_locus *loc) +mu_sieve_get_locus (mu_sieve_machine_t mach, struct mu_locus_range *loc) { - if (mach->locus.mu_file) - { - *loc = mach->locus; - return 0; - } - return 1; + return mu_locus_range_copy (loc, &mach->locus); } mu_mailbox_t diff --git a/libmu_sieve/sieve.y b/libmu_sieve/sieve-gram.y index 067489f..38a85b2 100644 --- a/libmu_sieve/sieve.y +++ b/libmu_sieve/sieve-gram.y @@ -36,44 +36,6 @@ static struct mu_sieve_node *node_alloc (enum mu_sieve_node_type, static void node_list_add (struct mu_sieve_node_list *list, struct mu_sieve_node *node); - -#define YYLLOC_DEFAULT(Current, Rhs, N) \ - do \ - { \ - if (N) \ - { \ - (Current).beg = YYRHSLOC(Rhs, 1).beg; \ - (Current).end = YYRHSLOC(Rhs, N).end; \ - } \ - else \ - { \ - (Current).beg = YYRHSLOC(Rhs, 0).end; \ - (Current).end = (Current).beg; \ - } \ - } while (0) - -#define LOCUS_EQ(a,b) \ - ((((a)->mu_file == (b)->mu_file) \ - || ((a)->mu_file && (b)->mu_file \ - && strcmp((a)->mu_file, (b)->mu_file) == 0)) \ - && (a)->mu_line == (b)->mu_line) - -#define YY_LOCATION_PRINT(File, Loc) \ - do \ - { \ - if (LOCUS_EQ(&(Loc).beg, &(Loc).end)) \ - fprintf(File, "%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 \ - fprintf(File, "%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); \ - } \ - while (0) %} %error-verbose @@ -87,6 +49,7 @@ static void node_list_add (struct mu_sieve_node_list *list, struct { char *ident; + struct mu_locus_range idloc; size_t first; size_t count; } command; @@ -242,21 +205,21 @@ test : command { mu_sieve_registry_t *reg; - mu_sieve_machine->locus = @1.beg; + mu_locus_range_copy (&mu_sieve_machine->locus, &@1); reg = mu_sieve_registry_lookup (mu_sieve_machine, $1.ident, mu_sieve_record_test); if (!reg) { - mu_diag_at_locus (MU_LOG_ERROR, &@1.beg, - _("unknown test: %s"), - $1.ident); + mu_diag_at_locus_range (MU_LOG_ERROR, &$1.idloc, + _("unknown test: %s"), + $1.ident); mu_i_sv_error (mu_sieve_machine); } else if (!reg->required) { - mu_diag_at_locus (MU_LOG_ERROR, &@1.beg, - _("test `%s' has not been required"), - $1.ident); + mu_diag_at_locus_range (MU_LOG_ERROR, &$1.idloc, + _("test `%s' has not been required"), + $1.ident); mu_i_sv_error (mu_sieve_machine); } @@ -281,6 +244,7 @@ test : command command : IDENT maybe_arglist { $$.ident = $1; + $$.idloc = @1; $$.first = $2.first; $$.count = $2.count; } @@ -290,22 +254,22 @@ action : command { mu_sieve_registry_t *reg; - mu_sieve_machine->locus = @1.beg; + mu_locus_range_copy (&mu_sieve_machine->locus, &@1); reg = mu_sieve_registry_lookup (mu_sieve_machine, $1.ident, mu_sieve_record_action); if (!reg) { - mu_diag_at_locus (MU_LOG_ERROR, &@1.beg, - _("unknown action: %s"), - $1.ident); + mu_diag_at_locus_range (MU_LOG_ERROR, &$1.idloc, + _("unknown action: %s"), + $1.ident); mu_i_sv_error (mu_sieve_machine); } else if (!reg->required) { - mu_diag_at_locus (MU_LOG_ERROR, &@1.beg, - _("action `%s' has not been required"), - $1.ident); + mu_diag_at_locus_range (MU_LOG_ERROR, &$1.idloc, + _("action `%s' has not been required"), + $1.ident); mu_i_sv_error (mu_sieve_machine); } @@ -341,23 +305,27 @@ arglist : arg arg : stringlist { $$ = mu_sieve_value_create (mu_sieve_machine, - SVT_STRING_LIST, &$1); + SVT_STRING_LIST, &@1, &$1); } | STRING { - $$ = mu_sieve_value_create (mu_sieve_machine, SVT_STRING, $1); + $$ = mu_sieve_value_create (mu_sieve_machine, SVT_STRING, + &@1, $1); } | MULTILINE { - $$ = mu_sieve_value_create (mu_sieve_machine, SVT_STRING, $1); + $$ = mu_sieve_value_create (mu_sieve_machine, SVT_STRING, + &@1, $1); } | NUMBER { - $$ = mu_sieve_value_create (mu_sieve_machine, SVT_NUMBER, &$1); + $$ = mu_sieve_value_create (mu_sieve_machine, SVT_NUMBER, + &@1, &$1); } | TAG { - $$ = mu_sieve_value_create (mu_sieve_machine, SVT_TAG, $1); + $$ = mu_sieve_value_create (mu_sieve_machine, SVT_TAG, + &@1, $1); } ; @@ -393,10 +361,7 @@ slist : STRING int yyerror (const char *s) { - extern struct mu_locus mu_sieve_locus; - - mu_sieve_machine->locus = mu_sieve_locus; - mu_diag_at_locus (MU_LOG_ERROR, &mu_sieve_locus, "%s", s); + mu_error ("%s", s); mu_i_sv_error (mu_sieve_machine); return 0; } @@ -423,7 +388,8 @@ node_alloc (enum mu_sieve_node_type type, struct mu_locus_range *lr) { node->prev = node->next = NULL; node->type = type; - node->locus = *lr; + mu_locus_range_init (&node->locus); + mu_locus_range_copy (&node->locus, lr); } return node; } @@ -1104,15 +1070,9 @@ copy_stream_state (mu_sieve_machine_t child, mu_sieve_machine_t parent) { child->state_flags = parent->state_flags; child->err_mode = parent->err_mode; - child->err_locus = parent->err_locus; - if (child->err_locus.mu_file) - child->err_locus.mu_file = - mu_sieve_strdup (child, child->err_locus.mu_file); + mu_locus_range_copy (&child->err_locus, &parent->err_locus); child->dbg_mode = parent->dbg_mode; - child->dbg_locus = parent->dbg_locus; - if (child->dbg_locus.mu_file) - child->dbg_locus.mu_file = - mu_sieve_strdup (child, child->dbg_locus.mu_file); + mu_locus_range_copy (&child->dbg_locus, &parent->dbg_locus); child->errstream = parent->errstream; mu_stream_ref (child->errstream); child->dbgstream = parent->dbgstream; @@ -1266,9 +1226,9 @@ mu_sieve_machine_dup (mu_sieve_machine_t const in, mu_sieve_machine_t *out) mach->state_flags = in->state_flags; mach->err_mode = in->err_mode; - mach->err_locus = in->err_locus; + mu_locus_range_copy (&mach->err_locus, &in->err_locus); mach->dbg_mode = in->dbg_mode; - mach->dbg_locus = in->dbg_locus; + mu_locus_range_copy (&mach->dbg_locus, &in->dbg_locus); copy_stream_state (mach, in); @@ -1456,8 +1416,7 @@ mu_sieve_machine_destroy (mu_sieve_machine_t *pmach) } int -with_machine (mu_sieve_machine_t mach, char const *name, - int (*thunk) (void *), void *data) +with_machine (mu_sieve_machine_t mach, int (*thunk) (void *), void *data) { int rc = 0; mu_stream_t save_errstr; @@ -1523,11 +1482,21 @@ static int sieve_parse (void) { int rc; + int old_mode, mode; sieve_tree = NULL; yydebug = mu_debug_level_p (mu_sieve_debug_handle, MU_DEBUG_TRACE3); + 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); + mu_i_sv_lex_finish (); if (rc) mu_i_sv_error (mu_sieve_machine); @@ -1547,9 +1516,8 @@ sieve_parse (void) mu_i_sv_code (mu_sieve_machine, (sieve_op_t) (sieve_instr_t) 0); /* Clear location, so that mu_i_sv_locus will do its job. */ - mu_sieve_machine->locus.mu_file = NULL; - mu_sieve_machine->locus.mu_line = 0; - mu_sieve_machine->locus.mu_col = 0; + /* FIXME: is it still needed? */ + mu_locus_range_deinit (&mu_sieve_machine->locus); tree_code (mu_sieve_machine, sieve_tree); mu_i_sv_code (mu_sieve_machine, (sieve_op_t) (sieve_instr_t) 0); @@ -1581,39 +1549,50 @@ sieve_compile_file (void *name) int mu_sieve_compile (mu_sieve_machine_t mach, const char *name) { - return with_machine (mach, name, sieve_compile_file, (void *) name); + return with_machine (mach, sieve_compile_file, (void *) name); } struct strbuf { const char *ptr; size_t size; - const char *file; - int line; + struct mu_locus_point const *pt; }; static int sieve_compile_strbuf (void *name) { struct strbuf *buf = name; - if (mu_i_sv_lex_begin_string (buf->ptr, buf->size, buf->file, buf->line) == 0) + if (mu_i_sv_lex_begin_string (buf->ptr, buf->size, buf->pt) == 0) return sieve_parse (); return MU_ERR_FAILURE; } int -mu_sieve_compile_buffer (mu_sieve_machine_t mach, - const char *str, int strsize, - const char *fname, int line) +mu_sieve_compile_text (mu_sieve_machine_t mach, + const char *str, size_t strsize, + struct mu_locus_point const *loc) { struct strbuf buf; buf.ptr = str; buf.size = strsize; - buf.file = fname; - buf.line = line; - return with_machine (mach, fname, sieve_compile_strbuf, &buf); + buf.pt = loc; + return with_machine (mach, sieve_compile_strbuf, &buf); } +int +mu_sieve_compile_buffer (mu_sieve_machine_t mach, + const char *buf, int bufsize, + const char *fname, int line) +{ + int rc; + struct mu_locus_point loc = MU_LOCUS_POINT_INITIALIZER; + mu_locus_point_set_file (&loc, fname); + loc.mu_line = line; + rc = mu_sieve_compile_text (mach, buf, bufsize, &loc); + mu_locus_point_deinit (&loc); + return rc; +} diff --git a/libmu_sieve/sieve.l b/libmu_sieve/sieve-lex.l index 099fc77..fd145bf 100644 --- a/libmu_sieve/sieve.l +++ b/libmu_sieve/sieve-lex.l @@ -54,10 +54,8 @@ static void sieve_searchpath (void); static char *str_unescape (char *text, size_t len); static int isemptystr (char *text); +static mu_linetrack_t trk; static ino_t sieve_source_inode; -struct mu_locus mu_sieve_locus; -static int newline; - static mu_stream_t input_stream; static int @@ -71,8 +69,10 @@ fillbuf (char *buf, size_t max_size) rc = mu_stream_read (input_stream, buf, max_size, &max_size); if (rc) { - mu_diag_funcall (MU_DIAG_ERROR, "mu_stream_read", - mu_sieve_locus.mu_file, rc); + struct mu_locus_point pt; + mu_linetrack_locus (trk, &pt); + mu_diag_funcall (MU_DIAG_ERROR, "mu_stream_read", pt.mu_file, rc); + mu_locus_point_deinit (&pt); return 0; } return max_size; @@ -90,40 +90,33 @@ fillbuf (char *buf, size_t max_size) yy_switch_to_buffer (s); \ } while (0) -static void -init_locus (char const *name, ino_t ino) -{ - mu_sieve_locus.mu_file = mu_i_sv_id_canon (mu_sieve_machine, name); - mu_sieve_locus.mu_line = 1; - mu_sieve_locus.mu_col = 0; - newline = 0; - sieve_source_inode = ino; -} +#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); + static void -advance_locus (void) +init_locus (char const *name, ino_t ino) { - if (newline) + if (name) { - mu_sieve_locus.mu_line++; - mu_sieve_locus.mu_col = 0; - yylloc.beg = yylloc.end = mu_sieve_locus; + MU_ASSERT (mu_linetrack_create (&trk, name, 2)); } else - { - mu_sieve_locus.mu_col += yyleng; - yylloc.beg = yylloc.end = mu_sieve_locus; - yylloc.beg.mu_col -= yyleng; - } - newline = yytext[yyleng-1] == '\n'; + mu_linetrack_destroy (&trk); + sieve_source_inode = ino; } - -#define YY_USER_ACTION advance_locus (); struct buffer_ctx { struct buffer_ctx *prev; - struct mu_locus locus; + mu_linetrack_t trk; + struct mu_locus_range incl_range; ino_t i_node; mu_stream_t input; LEX_BUFFER_STATE state; @@ -156,13 +149,12 @@ push_source (const char *name) if (stat (name, &st)) { - mu_diag_at_locus (MU_LOG_ERROR, &mu_sieve_locus, - _("cannot stat `%s': %s"), name, strerror (errno)); + mu_error (_("cannot stat `%s': %s"), name, strerror (errno)); mu_i_sv_error (mu_sieve_machine); return 1; } - if (mu_sieve_locus.mu_file && st.st_ino == sieve_source_inode) + if (yylloc.beg.mu_file && st.st_ino == sieve_source_inode) { yyerror (_("recursive inclusion")); return 1; @@ -172,16 +164,14 @@ push_source (const char *name) yyerror (_("recursive inclusion")); if (ctx->prev) { - mu_diag_at_locus (MU_LOG_ERROR, &ctx->prev->locus, - _("`%s' already included here"), - name); + mu_diag_at_locus_range (MU_LOG_ERROR, &ctx->incl_range, + _("`%s' already included here"), + name); mu_i_sv_error (mu_sieve_machine); } else { - mu_diag_at_locus (MU_LOG_ERROR, &mu_sieve_locus, - _("`%s' already included at top level"), - name); + mu_error (_("`%s' already included at top level"), name); mu_i_sv_error (mu_sieve_machine); } return 1; @@ -190,19 +180,17 @@ push_source (const char *name) rc = mu_file_stream_create (&stream, name, MU_STREAM_READ); if (rc) { - mu_diag_at_locus (MU_LOG_ERROR, &mu_sieve_locus, - _("cannot open file `%s': %s"), - name, mu_strerror (rc)); + mu_error (_("cannot open file `%s': %s"), name, mu_strerror (rc)); mu_i_sv_error (mu_sieve_machine); return 1; } /* Push current context */ - if (mu_sieve_locus.mu_file) + if (trk) { - advance_locus (); ctx = mu_sieve_malloc (mu_sieve_machine, sizeof (*ctx)); - ctx->locus = mu_sieve_locus; + ctx->trk = trk; + mu_locus_range_copy (&ctx->incl_range, &yylloc); ctx->i_node = sieve_source_inode; ctx->input = input_stream; ctx->prev = context_stack; @@ -233,7 +221,9 @@ pop_source () } /* Restore previous context */ input_stream = context_stack->input; - mu_sieve_locus = context_stack->locus; + mu_linetrack_destroy (&trk); + trk = context_stack->trk; + mu_locus_range_deinit (&context_stack->incl_range); sieve_source_inode = context_stack->i_node; RESTORE_BUFFER_STATE (context_stack->state); ctx = context_stack->prev; @@ -449,12 +439,10 @@ mu_i_sv_lex_begin (const char *name) int mu_i_sv_lex_begin_string (const char *buf, int bufsize, - const char *fname, int line) + struct mu_locus_point const *pt) { int rc; - if (!fname) - return 1; yyrestart (NULL); rc = mu_static_memory_stream_create (&input_stream, buf, bufsize); @@ -465,7 +453,8 @@ mu_i_sv_lex_begin_string (const char *buf, int bufsize, return 1; } - init_locus (fname, 0); + init_locus (pt->mu_file, 0); + mu_linetrack_rebase (trk, pt); return 0; } @@ -643,9 +632,7 @@ line_finish (void) } else if (rc != MU_ERR_CANCELED) { - mu_diag_at_locus (MU_LOG_ERROR, &mu_sieve_locus, - _("error expandind string: %s"), - mu_strerror (rc)); + mu_error (_("error expandind string: %s"), mu_strerror (rc)); } } yylval.string = str; diff --git a/libmu_sieve/sieve-priv.h b/libmu_sieve/sieve-priv.h index 041b4ea..ba5bad9 100644 --- a/libmu_sieve/sieve-priv.h +++ b/libmu_sieve/sieve-priv.h @@ -18,6 +18,8 @@ #include <mailutils/sieve.h> #include <mailutils/assoc.h> +#include <mailutils/locus.h> +#include <mailutils/yyloc.h> #include <setjmp.h> #include <string.h> #include <regex.h> @@ -38,13 +40,6 @@ typedef union unsigned unum; } sieve_op_t; -struct mu_locus_range -{ - struct mu_locus beg; - struct mu_locus end; -}; - -#define YYLTYPE struct mu_locus_range #define MU_SV_SAVED_ERR_STATE 0x01 #define MU_SV_SAVED_DBG_STATE 0x02 @@ -62,7 +57,7 @@ enum mu_sieve_state struct mu_sieve_machine { /* Static data */ - struct mu_locus locus; /* Approximate location in the code */ + struct mu_locus_range locus; /* Approximate location in the code */ mu_list_t memory_pool; /* Pool of allocated memory objects */ mu_list_t destr_list; /* List of destructor functions */ @@ -118,9 +113,9 @@ struct mu_sieve_machine /* Stream state info */ int state_flags; int err_mode; - struct mu_locus err_locus; + struct mu_locus_range err_locus; int dbg_mode; - struct mu_locus dbg_locus; + struct mu_locus_range dbg_locus; /* User supplied data */ mu_stream_t errstream; @@ -182,7 +177,7 @@ int mu_sieve_yylex (void); int mu_i_sv_lex_begin (const char *name); int mu_i_sv_lex_begin_string (const char *buf, int bufsize, - const char *fname, int line); + struct mu_locus_point const *pt); void mu_i_sv_lex_finish (void); extern mu_sieve_machine_t mu_sieve_machine; @@ -204,6 +199,7 @@ void _mu_i_sv_instr_brz (mu_sieve_machine_t mach); void _mu_i_sv_instr_brnz (mu_sieve_machine_t mach); void _mu_i_sv_instr_source (mu_sieve_machine_t mach); void _mu_i_sv_instr_line (mu_sieve_machine_t mach); +void _mu_i_sv_instr_col (mu_sieve_machine_t mach); int mu_i_sv_load_add_dir (mu_sieve_machine_t mach, const char *name); @@ -244,7 +240,6 @@ void mu_i_sv_lint_command (struct mu_sieve_machine *mach, size_t mu_i_sv_string_create (mu_sieve_machine_t mach, char *str); -char *mu_i_sv_id_canon (mu_sieve_machine_t mach, char const *name); size_t mu_i_sv_id_num (mu_sieve_machine_t mach, char const *name); char *mu_i_sv_id_str (mu_sieve_machine_t mach, size_t n); void mu_i_sv_free_idspace (mu_sieve_machine_t mach); diff --git a/libmu_sieve/util.c b/libmu_sieve/util.c index 7cc9227..3d4763c 100644 --- a/libmu_sieve/util.c +++ b/libmu_sieve/util.c @@ -28,6 +28,7 @@ size_t mu_sieve_value_create (mu_sieve_machine_t mach, mu_sieve_data_type type, + struct mu_locus_range const *locus, void *data) { size_t idx; @@ -43,6 +44,18 @@ mu_sieve_value_create (mu_sieve_machine_t mach, mu_sieve_data_type type, memset (val, 0, sizeof *val); val->type = type; + + /* Copy locus. */ + val->locus.beg.mu_file = + mu_i_sv_id_str (mach, mu_i_sv_id_num (mach, locus->beg.mu_file)); + val->locus.beg.mu_line = locus->beg.mu_line; + val->locus.beg.mu_col = locus->beg.mu_col; + val->locus.end.mu_file = + mu_i_sv_id_str (mach, mu_i_sv_id_num (mach, locus->end.mu_file)); + val->locus.end.mu_line = locus->end.mu_line; + val->locus.end.mu_col = locus->end.mu_col; + + mu_locus_range_copy (&val->locus, locus); switch (type) { case SVT_NUMBER: @@ -205,12 +218,6 @@ mu_sieve_error (mu_sieve_machine_t mach, const char *fmt, ...) va_start (ap, fmt); mu_stream_printf (mach->errstream, "\033s<%d>", MU_LOG_ERROR); - if (mach->locus.mu_file) - mu_stream_printf (mach->errstream, "\033O<%d>\033f<%u>%s\033l<%u>", - MU_LOGMODE_LOCUS, - (unsigned) strlen (mach->locus.mu_file), - mach->locus.mu_file, - mach->locus.mu_line); if (mach->identifier) mu_stream_printf (mach->errstream, "%s: ", mach->identifier); mu_stream_vprintf (mach->errstream, fmt, ap); @@ -253,11 +260,11 @@ mu_i_sv_debug (mu_sieve_machine_t mach, size_t pc, const char *fmt, ...) unsigned severity = MU_LOG_DEBUG; mu_stream_ioctl (mach->dbgstream, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_SET_SEVERITY, &severity); - if (mach->locus.mu_file) + if (mach->locus.beg.mu_file) { int mode = mach->dbg_mode | MU_LOGMODE_LOCUS; mu_stream_ioctl (mach->dbgstream, MU_IOCTL_LOGSTREAM, - MU_IOCTL_LOGSTREAM_SET_LOCUS, &mach->locus); + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, &mach->locus); mu_stream_ioctl (mach->dbgstream, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_SET_MODE, &mode); } @@ -281,11 +288,11 @@ mu_i_sv_debug_command (mu_sieve_machine_t mach, unsigned severity = MU_LOG_DEBUG; mu_stream_ioctl (mach->dbgstream, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_SET_SEVERITY, &severity); - if (mach->locus.mu_file) + if (mach->locus.beg.mu_file) { int mode = mach->dbg_mode | MU_LOGMODE_LOCUS; mu_stream_ioctl (mach->dbgstream, MU_IOCTL_LOGSTREAM, - MU_IOCTL_LOGSTREAM_SET_LOCUS, &mach->locus); + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, &mach->locus); mu_stream_ioctl (mach->dbgstream, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_SET_MODE, &mode); } @@ -309,12 +316,6 @@ mu_i_sv_trace (mu_sieve_machine_t mach, const char *what) return; mu_stream_printf (mach->errstream, "\033s<%d>", MU_LOG_DEBUG); - if (mach->locus.mu_file) - mu_stream_printf (mach->errstream, "\033O<%d>\033f<%u>%s\033l<%u>", - MU_LOGMODE_LOCUS, - (unsigned) strlen (mach->locus.mu_file), - mach->locus.mu_file, - mach->locus.mu_line); mu_stream_printf (mach->errstream, "%zu: %s %s", mach->msgno, what, mach->identifier); for (i = 0; i < mach->argcount; i++) @@ -333,8 +334,6 @@ mu_sieve_log_action (mu_sieve_machine_t mach, const char *action, if (!mach->logger) return; - mu_stream_ioctl (mach->errstream, MU_IOCTL_LOGSTREAM, - MU_IOCTL_LOGSTREAM_SET_LOCUS, &mach->locus); va_start (ap, fmt); mach->logger (mach, action, fmt, ap); va_end (ap); @@ -479,13 +478,15 @@ mu_sieve_stream_save (mu_sieve_machine_t mach) if (mu_stream_ioctl (mach->errstream, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_GET_MODE, &mach->err_mode) == 0 && mu_stream_ioctl (mach->errstream, MU_IOCTL_LOGSTREAM, - MU_IOCTL_LOGSTREAM_GET_LOCUS, &mach->err_locus) == 0) + MU_IOCTL_LOGSTREAM_GET_LOCUS_RANGE, + &mach->err_locus) == 0) mach->state_flags |= MU_SV_SAVED_ERR_STATE; if (mu_stream_ioctl (mach->dbgstream, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_GET_MODE, &mach->dbg_mode) == 0 && mu_stream_ioctl (mach->dbgstream, MU_IOCTL_LOGSTREAM, - MU_IOCTL_LOGSTREAM_GET_LOCUS, &mach->dbg_locus) == 0) + MU_IOCTL_LOGSTREAM_GET_LOCUS_RANGE, + &mach->dbg_locus) == 0) mach->state_flags |= MU_SV_SAVED_DBG_STATE; mach->state_flags |= MU_SV_SAVED_STATE; @@ -502,7 +503,7 @@ mu_sieve_stream_restore (mu_sieve_machine_t mach) mu_stream_ioctl (mach->errstream, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_SET_MODE, &mach->err_mode); mu_stream_ioctl (mach->errstream, MU_IOCTL_LOGSTREAM, - MU_IOCTL_LOGSTREAM_SET_LOCUS, &mach->err_locus); + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, &mach->err_locus); } if (mach->dbgstream != mach->errstream @@ -511,7 +512,7 @@ mu_sieve_stream_restore (mu_sieve_machine_t mach) mu_stream_ioctl (mach->dbgstream, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_SET_MODE, &mach->dbg_mode); mu_stream_ioctl (mach->dbgstream, MU_IOCTL_LOGSTREAM, - MU_IOCTL_LOGSTREAM_SET_LOCUS, &mach->dbg_locus); + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, &mach->dbg_locus); } mach->state_flags = 0; diff --git a/libmu_sieve/variables.c b/libmu_sieve/variables.c index 91550ef..ec24287 100644 --- a/libmu_sieve/variables.c +++ b/libmu_sieve/variables.c @@ -226,9 +226,12 @@ set_tag_checker (mu_sieve_machine_t mach) *mu_sieve_get_tag_n (mach, j + 1) = *t; else if (prec == tmp_prec) { - mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, - _("%s and %s can't be used together"), - tmp.tag, t->tag); + mu_diag_at_locus_range (MU_LOG_ERROR, &t->locus, + _("%s and %s can't be used together"), + tmp.tag, t->tag); + mu_diag_at_locus_range (MU_LOG_ERROR, &tmp.locus, + _("%s encountered here"), + tmp.tag); mu_i_sv_error (mach); return 1; } diff --git a/mail/Makefile.am b/mail/Makefile.am index 7c2cebc..b206151 100644 --- a/mail/Makefile.am +++ b/mail/Makefile.am @@ -15,6 +15,7 @@ ## You should have received a copy of the GNU General Public License ## along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. +YLWRAP = @MU_YLWRAP@ AM_YFLAGS=-vt AM_CPPFLAGS = \ @MU_APP_COMMON_INCLUDES@ @MU_AUTHINCS@\ diff --git a/mail/source.c b/mail/source.c index 802e298..80b7929 100644 --- a/mail/source.c +++ b/mail/source.c @@ -49,7 +49,7 @@ mail_source (int argc, char **argv) { mu_stream_t input; int save_term; - struct mu_locus locus; + struct mu_locus_range locus = MU_LOCUS_RANGE_INITIALIZER; int rc; if (argc != 2) @@ -69,15 +69,15 @@ mail_source (int argc, char **argv) save_term = interactive; interactive = 0; - locus.mu_file = argv[1]; - locus.mu_line = 0; - locus.mu_col = 0; + locus.beg.mu_file = argv[1]; + locus.beg.mu_line = 0; + locus.beg.mu_col = 0; mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, - MU_IOCTL_LOGSTREAM_SET_LOCUS, &locus); + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, &locus); mail_mainloop (source_readline, input, 0); interactive = save_term; mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, - MU_IOCTL_LOGSTREAM_SET_LOCUS, NULL); + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, NULL); mu_stream_unref (input); return 0; } diff --git a/mh/.gitignore b/mh/.gitignore index 4e2b87b..99f999a 100644 --- a/mh/.gitignore +++ b/mh/.gitignore @@ -14,8 +14,7 @@ forw inc install-mh mark -mh_alias.h -mh_alias_gram.c +mh_alias_gram.[ch] mh_alias_lex.c mh_fmtgram.c mhl diff --git a/mh/Makefile.am b/mh/Makefile.am index 3107602..d4c89a8 100644 --- a/mh/Makefile.am +++ b/mh/Makefile.am @@ -68,33 +68,33 @@ noinst_LIBRARIES = libmh.a libmh_a_SOURCES= \ compcommon.c\ mboxprop.c\ - mh_alias_gram.c\ - mh_alias_lex.c\ + mh_alias_gram.y\ + mh_alias_lex.l\ mh_getopt.c\ mh_global.c\ mh_format.c\ mh_init.c\ mh_list.c\ - mh_fmtgram.c\ + mh_fmtgram.y\ mh_msgset.c\ mh_sequence.c\ mh_stream.c\ mh_whatnow.c\ mh_whom.c\ whatnowenv.c -noinst_HEADERS = mh.h mh_alias.h mh_format.h mh_getopt.h +noinst_HEADERS = mh.h mh_alias_gram.h mh_format.h mh_getopt.h -BUILT_SOURCES= \ - mh_fmtgram.c \ - pick-gram.c \ - pick-gram.h \ - mh_alias_gram.c \ - mh_alias_lex.c \ - mh_alias.h +BUILT_SOURCES=\ + mh_fmtgram.c\ + pick-gram.c\ + pick-gram.h\ + mh_alias_gram.c\ + mh_alias_gram.h\ + mh_alias_lex.c MAINTAINERCLEANFILES=$(BUILT_SOURCES) -EXTRA_DIST = mh_fmtgram.y pick.y mh_alias.y mh_alias.l +EXTRA_DIST = gylwrap.conf mhlibdir = $(pkgdatadir)/mh @@ -119,9 +119,9 @@ mh_LIBS = \ @MU_COMMON_LIBRARIES@ LDADD = $(mh_LIBS) scan_LDADD = $(mh_LIBS) @CURSES_LIBS@ -pick_SOURCES = pick.c pick.h pick-gram.c pick-gram.h +pick_SOURCES = pick.c pick.h pick-gram.y pick-gram.h -YLWRAP = $(SHELL) $(mu_aux_dir)/gylwrap +YLWRAP = @MU_YLWRAP@ AM_YFLAGS=-vt inc_LDADD = \ @@ -144,29 +144,6 @@ inc_LDADD = \ ${MU_LIB_MAILUTILS}\ @MU_COMMON_LIBRARIES@ - -pick-gram.c pick-gram.h: $(srcdir)/pick.y - $(YLWRAP) "$(YACC) $(AM_YFLAGS) -d" $< \ - y.tab.c pick-gram.c y.tab.h pick-gram.h \ - y.output pick.output \ - -- -yy pick_yy - -mh_fmtgram.c: $(srcdir)/mh_fmtgram.y - $(YLWRAP) "$(YACC) $(AM_YFLAGS)" $< \ - y.tab.c mh_fmtgram.c y.output fmtgram.y.output \ - -- -yy fmt_yy - -mh_alias_gram.c mh_alias.h: $(srcdir)/mh_alias.y - $(YLWRAP) "$(YACC) $(AM_YFLAGS) -d" $< \ - y.tab.c mh_alias_gram.c y.tab.h mh_alias.h \ - y.output mh_alias.output \ - -- -yy ali_yy - -mh_alias_lex.c: $(srcdir)/mh_alias.l mh_alias.h - $(YLWRAP) "$(LEX) $(AM_LEXFLAGS) $(LEXFLAGS)" \ - $(srcdir)/mh_alias.l lex.yy.c mh_alias_lex.c \ - -- -yy ali_yy - install-exec-hook: @here=`pwd`; \ cd $(DESTDIR)$(bindir); \ diff --git a/mh/gylwrap.conf b/mh/gylwrap.conf new file mode 100644 index 0000000..9954962 --- a/dev/null +++ b/mh/gylwrap.conf @@ -0,0 +1,13 @@ +# Configuration settings for gylwrap. +# See ../mu-aux/gylwrap --help, for details. + +[pick-gram.y] + yyrepl = pick_yy + flags = -d +[mh_fmtgram.y] + yyrepl = fmt_yy +[mh_alias_gram.y] + yyrepl = ali_yy + flags = -d +[mh_alias_lex.l] + yyrepl = ali_yy @@ -385,7 +385,6 @@ const char *mh_seq_read (mu_mailbox_t mbox, const char *name, int flags); void mh_comp_draft (const char *formfile, const char *draftfile); int check_draft_disposition (struct mh_whatnow_env *wh, int use_draft); -void ali_parse_error (const char *fmt, ...) MU_PRINTFLIKE(1,2); void ali_verbatim (int enable); char *mh_safe_make_file_name (const char *dir, const char *file); diff --git a/mh/mh_alias.y b/mh/mh_alias_gram.y index 54e3cd1..26b13ec 100644 --- a/mh/mh_alias.y +++ b/mh/mh_alias_gram.y @@ -20,6 +20,8 @@ #include <pwd.h> #include <grp.h> #include <sys/types.h> +#include <mailutils/locus.h> +#include <mailutils/yyloc.h> struct mh_alias { @@ -31,7 +33,7 @@ struct mh_alias static mu_list_t alias_list; static mu_list_t -list_create_or_die () +list_create_or_die (void) { int status; mu_list_t list; @@ -39,7 +41,7 @@ list_create_or_die () status = mu_list_create (&list); if (status) { - ali_parse_error (_("can't create list: %s"), mu_strerror (status)); + mu_error (_("can't create list: %s"), mu_strerror (status)); exit (1); } return list; @@ -86,6 +88,17 @@ ali_list_to_string (mu_list_t *plist) return string; } +static void +ali_append (struct mh_alias *ali) +{ + if (ali) + { + if (!alias_list) + alias_list = list_create_or_die (); + mu_list_append (alias_list, ali); + } +} + static mu_list_t unix_group_to_list (char *name); static mu_list_t unix_gid_to_list (char *name); static mu_list_t unix_passwd_to_list (void); @@ -101,37 +114,34 @@ int yylex (void); struct mh_alias *alias; } +%token EOL %token <string> STRING %type <list> address_list address_group string_list %type <string> address %type <alias> alias +%locations + %% -input : /* empty */ - | alias_list - | alias_list nl - | nl alias_list - | nl alias_list nl +input : alias_list ; alias_list : alias { - if (!alias_list) - alias_list = list_create_or_die (); - mu_list_append (alias_list, $1); + ali_append ($1); } - | alias_list nl alias + | alias_list EOL alias { - mu_list_append (alias_list, $3); + ali_append ($3); } ; -nl : '\n' - | nl '\n' - ; - -alias : STRING ':' { ali_verbatim (1); } address_group +alias : /* empty */ + { + $$ = NULL; + } + | STRING ':' { ali_verbatim (1); } address_group { ali_verbatim (0); $$ = mu_alloc (sizeof (*$$)); @@ -489,7 +499,7 @@ unix_passwd_to_list () } int -mh_read_aliases () +mh_read_aliases (void) { const char *p; diff --git a/mh/mh_alias.l b/mh/mh_alias_lex.l index 0deb7c9..371353e 100644 --- a/mh/mh_alias.l +++ b/mh/mh_alias_lex.l @@ -23,58 +23,23 @@ %{ #include <mh.h> -#include <mh_alias.h> +#include <mailutils/locus.h> +#include <mailutils/yyloc.h> +#include <mh_alias_gram.h> #include <sys/stat.h> #include <mailutils/cctype.h> #include <mailutils/io.h> - -char *ali_filename; -size_t ali_line_num; -ino_t ali_source_inode; - -void -va_ali_parse_error_loc (const char *name, size_t line, - const char *fmt, va_list ap) -{ - char *buf = NULL; - size_t size = 0; - mu_vasnprintf (&buf, &size, fmt, ap); - if (name) - mu_error ("%s:%lu: %s", name, (unsigned long) line, buf); - else - mu_error ("%s", buf); - free (buf); -} - -void -ali_parse_error_loc (const char *name, size_t line, const char *fmt, ...) -{ - va_list ap; - - va_start (ap, fmt); - va_ali_parse_error_loc (name, line, fmt, ap); - va_end (ap); -} - -void -ali_parse_error (const char *fmt, ...) -{ - va_list ap; - - va_start (ap, fmt); - va_ali_parse_error_loc (ali_filename, ali_line_num, fmt, ap); - va_end (ap); -} +static mu_linetrack_t trk; +static ino_t ali_source_inode; int yyerror (char *s) { - ali_parse_error ("%s", s); + mu_error ("%s", s); return 0; } -#ifdef FLEX_SCANNER #define xinput() (yyin ? getc(yyin) : EOF) #undef YY_INPUT #define YY_INPUT(buf,result,max_size) do { \ @@ -97,127 +62,20 @@ yyerror (char *s) yy_switch_to_buffer(s); \ } while (0) -#else -/* AT&T Lex */ - -static void lex_set_buffer (FILE *fp); -static void lex_delete_buffer (LEX_BUFFER_STATE buf); -static int xinput (void); -static int xunput (void); - -#undef unput -#define unput(c) xunput(c) -#undef input -#define input() xinput() - -#define LEX_BUF_SIZE 16384 -#define LEX_PUTBACK_SIZE 32 - -typedef struct { - FILE *yyin; - char *buffer; - size_t bufsize; - size_t level; - char *ptr; - char *putback; - size_t pb_size; - size_t pb_level; -} LEX_BUFFER_STATE; -LEX_BUFFER_STATE current_buffer; +#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); -#define SET_BUFFER_STATE(s) do { \ - (s) = current_buffer; \ - lex_set_buffer(yyin); \ -} while (0) -#define RESTORE_BUFFER_STATE(s) do { \ - lex_delete_buffer(current_buffer); \ - current_buffer = (s); \ - yyin = current_buffer.yyin; \ -} while (0) - -void -lex_set_buffer (FILE *fp) -{ - char *buf; - size_t size; - - for (size = LEX_BUF_SIZE; size > 1; size /= 2) - if (buf = malloc (size)) - break; - - if (!buf) - { - ali_parse_error (_("not enough memory")); - abort (); - } - - current_buffer.yyin = yyin; - current_buffer.buffer = buf; - current_buffer.bufsize = size; - current_buffer.level = 0; - current_buffer.ptr = current_buffer.buffer; - current_buffer.pb_size = current_buffer.pb_level = 0; - current_buffer.putback = NULL; -} - -void -lex_delete_buffer (LEX_BUFFER_STATE buf) -{ - free (buf.buffer); - if (buf.putback) - free (buf.putback); -} - -int -xinput () -{ - if (!yyin) - return EOF; - - if (current_buffer.pb_level) - return current_buffer.putback[--current_buffer.pb_level]; - - if (current_buffer.level <= 0) - { - int n; - - if (feof (yyin)) - return 0; - n = fread (current_buffer.buffer, 1, - current_buffer.bufsize, yyin); - if (n <= 0) - return 0; - current_buffer.level = n; - current_buffer.ptr = current_buffer.buffer; - } - current_buffer.level--; - return *current_buffer.ptr++; -} - -int -xunput (int c) -{ - if (current_buffer.pb_level == current_buffer.pb_size) - { - char *putback; - current_buffer.pb_size += LEX_PUTBACK_SIZE; - putback = mu_alloc (current_buffer.pb_size); - memcpy (putback, current_buffer.putback, - current_buffer.pb_level); - free (current_buffer.putback); - current_buffer.putback = putback; - } - current_buffer.putback[current_buffer.pb_level++] = c; - return c; -} - -#endif - struct buffer_ctx { struct buffer_ctx *prev; - char *filename; - int line; + mu_linetrack_t trk; ino_t i_node; + struct mu_locus_range incl_range; FILE *yyin; int exec_p; LEX_BUFFER_STATE state; @@ -250,27 +108,26 @@ push_source (const char *name, int fail) if (stat (filename, &st)) { if (fail) - ali_parse_error (_("can't stat `%s': %s"), filename, strerror (errno)); + mu_error (_("can't stat `%s': %s"), filename, strerror (errno)); free (filename); return 1; } - if (ali_filename && st.st_ino == ali_source_inode) + if (yylloc.beg.mu_file && st.st_ino == ali_source_inode) { - ali_parse_error (_("recursive inclusion")); + mu_error (_("recursive inclusion")); free (filename); return 1; } if ((ctx = ctx_lookup (st.st_ino))) { - ali_parse_error (_("recursive inclusion")); + mu_error (_("recursive inclusion")); if (ctx->prev) - ali_parse_error_loc (ctx->prev->filename, ctx->prev->line, - _("`%s' already included here"), - filename); + mu_diag_at_locus_range (MU_LOG_ERROR, &ctx->incl_range, + _("`%s' already included here"), + filename); else - ali_parse_error (_("`%s' already included at top level"), - filename); + mu_error (_("`%s' already included at top level"), filename); free (filename); return 1; } @@ -278,7 +135,7 @@ push_source (const char *name, int fail) fp = fopen (filename, "r"); if (!fp) { - ali_parse_error (_("can't open `%s': %s"), filename, strerror (errno)); + mu_error (_("can't open `%s': %s"), filename, strerror (errno)); free (filename); return 1; } @@ -295,8 +152,8 @@ push_source (const char *name, int fail) fp = popen (filename, "r"); if (!fp) { - ali_parse_error (_("can't execute `%s': %s"), - filename, strerror (errno)); + mu_error (_("can't execute `%s': %s"), + filename, strerror (errno)); free (filename); return 1; } @@ -306,12 +163,12 @@ push_source (const char *name, int fail) } /* Push current context */ - if (ali_filename) + if (yylloc.beg.mu_file) { ctx = mu_alloc (sizeof (*ctx)); - ctx->filename = ali_filename; + ctx->trk = trk; + mu_locus_range_copy (&ctx->incl_range, &yylloc); ctx->exec_p = exec_p; - ctx->line = ali_line_num; ctx->i_node = ali_source_inode; ctx->yyin = yyin; ctx->prev = context_stack; @@ -330,34 +187,30 @@ push_source (const char *name, int fail) lex_set_buffer (yyin); #endif } - ali_filename = filename; - ali_line_num = 1; + 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 () +pop_source (void) { struct buffer_ctx *ctx; if (yyin) (exec_p ? pclose : fclose) (yyin); -#ifndef FLEX_SCANNER - lex_delete_buffer (current_buffer); -#endif - if (ali_filename) - free (ali_filename); - ali_filename = NULL; + 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 */ - ali_filename = context_stack->filename; - ali_line_num = context_stack->line + 1; /* < line did not increment it */ + trk = context_stack->trk; ali_source_inode = context_stack->i_node; exec_p = context_stack->exec_p; RESTORE_BUFFER_STATE (context_stack->state); @@ -378,15 +231,15 @@ WORD [^ \t\n,:;<+=\*]+ SPEC [,:;+=\*] %s VERBATIM %% -\\\n { ali_line_num++; } -\n { ali_line_num++; return '\n';} -^[ \t]*\;.*\n ali_line_num++; +\\\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;} + return STRING; } {WS} ; {WORD} { yylval.string = mu_strdup (yytext); return STRING;} ^{WS}?"<"{WS}?{WORD} { @@ -403,24 +256,22 @@ SPEC [,:;+=\*] memcpy(yylval.string, yytext, yyleng); yylval.string[yyleng] = 0; return STRING;} -. { char *p; - mu_asprintf (&p, - _("Stray character %03o in alias file"), - yytext[0]); - yyerror (p); - free (p); } +. { mu_error (_("Stray character %03o in alias file"), + yytext[0]); } %% int -yywrap () +yywrap (void) { - return pop_source(); + 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"); @@ -431,7 +282,16 @@ mh_alias_read (char const *name, int fail) return 1; if (yydebug) fprintf (stderr, "Starting parse of %s\n", name); - return yyparse (); + + 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 diff --git a/mh/pick.y b/mh/pick-gram.y index ef2bdaa..ef2bdaa 100644 --- a/mh/pick.y +++ b/mh/pick-gram.y diff --git a/mh/tests/ali.at b/mh/tests/ali.at index d18a910..28c0e54 100644 --- a/mh/tests/ali.at +++ b/mh/tests/ali.at @@ -70,8 +70,8 @@ exit $code [0], [gray, polak, admin ], -[ali: mh_aliases2:2: recursive inclusion -ali: mh_aliases2:2: `mh_aliases' already included at top level +[ali: mh_aliases2:2.1-11: recursive inclusion +ali: mh_aliases2:2.1-11: `mh_aliases' already included at top level ]) MH_CHECK([ali: group name],[ali04 ali-group-name],[ diff --git a/mimeview/.gitignore b/mimeview/.gitignore index b18e41a..cee470e 100644 --- a/mimeview/.gitignore +++ b/mimeview/.gitignore @@ -3,11 +3,8 @@ .libs Makefile Makefile.in -lex.yy.c -mimetypes-decl.h -mimetypes-gram.c -mimetypes-lex.c -mimetypes.output +grammar.c +grammar.h +grammar.output +lexer.c mimeview -y.output -y.tab.c diff --git a/mimeview/Makefile.am b/mimeview/Makefile.am index 5334e40..039e2be 100644 --- a/mimeview/Makefile.am +++ b/mimeview/Makefile.am @@ -25,28 +25,15 @@ AM_CPPFLAGS = \ bin_PROGRAMS = mimeview mimeview_SOURCES = \ mimeview.c \ - mimetypes-gram.c \ - mimetypes-lex.c \ - mimetypes-decl.h \ - mimeview.h + grammar.y \ + lexer.l \ + mimeview.h\ + grammar.h -YLWRAP = $(SHELL) $(mu_aux_dir)/gylwrap -AM_YFLAGS=-vt +YLWRAP = @MU_YLWRAP@ +AM_YFLAGS=-vtd AM_LEXFLAGS=-d -EXTRA_DIST = mimetypes.y mimetypes.l - -mimetypes-gram.c mimetypes-decl.h: $(srcdir)/mimetypes.y - $(AM_V_GEN)$(YLWRAP) "$(YACC) $(AM_YFLAGS) -d" $< \ - y.tab.c mimetypes-gram.c y.tab.h mimetypes-decl.h \ - y.output mimetypes.output \ - -- -yy mimetypes_yy - -mimetypes-lex.c: $(srcdir)/mimetypes.l mimetypes-decl.h - $(AM_V_GEN)$(YLWRAP) "$(LEX) $(AM_LEXFLAGS) $(LEXFLAGS)" \ - $(srcdir)/mimetypes.l lex.yy.c mimetypes-lex.c \ - -- -yy mimetypes_yy - -BUILT_SOURCES = mimetypes-gram.c mimetypes-lex.c mimetypes-decl.h +EXTRA_DIST = gylwrap.conf mimeview_LDADD = \ ${MU_APP_LIBRARIES}\ diff --git a/mimeview/mimetypes.y b/mimeview/grammar.y index cfb4fbe..cb36f39 100644 --- a/mimeview/mimetypes.y +++ b/mimeview/grammar.y @@ -22,7 +22,7 @@ #include <mailutils/cctype.h> #include <mimeview.h> -#include <mimetypes-decl.h> +#include <grammar.h> #include <regex.h> static void @@ -122,10 +122,11 @@ struct rule_tab }; static mu_list_t rule_list; +static size_t errors; %} %locations -%expect 12 +%expect 15 %token <string> TYPE IDENT %token <string> STRING @@ -165,16 +166,21 @@ rule_line: /* empty */ p->type = $1.ptr; p->node = $2; p->priority = $3; - p->loc.beg = @1.beg; - p->loc.end = @3.end; + 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); arg_list = NULL; @@ -228,6 +234,10 @@ stmt : '!' stmt $$ = make_suffix_node (&$1, &@1); } | function + | BOGUS + { + YYERROR; + } ; priority : PRIORITY '(' arglist ')' @@ -280,6 +290,10 @@ arglist : arg ; arg : STRING + | BOGUS + { + YYERROR; + } ; %% @@ -290,10 +304,10 @@ mimetypes_parse (const char *name) int rc; if (mimetypes_open (name)) return 1; - yydebug = mu_debug_level_p (MU_DEBCAT_MIME, MU_DEBUG_TRACE3); + yydebug = mu_debug_level_p (MU_DEBCAT_APP, MU_DEBUG_TRACE3); rc = yyparse (); mimetypes_close (); - return rc || rule_list == NULL; + return rc || errors; } static struct node * @@ -301,7 +315,7 @@ make_node (enum node_type type, struct mu_locus_range const *loc) { struct node *p = mimetypes_malloc (sizeof *p); p->type = type; - p->loc = *loc; + mu_locus_range_copy (&p->loc, loc); return p; } @@ -333,7 +347,7 @@ make_suffix_node (struct mimetypes_string *suffix, node->v.suffix = *suffix; return node; } - + struct builtin_tab { char *name; @@ -759,7 +773,7 @@ check_suffix (char *suf) void mime_debug (int lev, struct mu_locus_range const *loc, char const *fmt, ...) { - if (mu_debug_level_p (MU_DEBCAT_MIME, lev)) + if (mu_debug_level_p (MU_DEBCAT_APP, lev)) { va_list ap; diff --git a/mimeview/gylwrap.conf b/mimeview/gylwrap.conf new file mode 100644 index 0000000..cd41ab2 --- a/dev/null +++ b/mimeview/gylwrap.conf @@ -0,0 +1,3 @@ +# Configuration settings for gylwrap. +# See ../mu-aux/gylwrap --help, for details. +yyrepl = mimetypes_yy diff --git a/mimeview/mimetypes.l b/mimeview/lexer.l index dd2311b..71de5d7 100644 --- a/mimeview/mimetypes.l +++ b/mimeview/lexer.l @@ -26,12 +26,12 @@ #include <stdio.h> #include <sys/stat.h> #include <mimeview.h> -#include <mimetypes-decl.h> +#include <grammar.h> #include <mailutils/io.h> -static struct mu_locus loc; -static int newline; - +static mu_linetrack_t trk; +struct mu_locus_point string_beg; + static mu_opool_t pool; static unsigned @@ -42,53 +42,24 @@ digit_to_number (char c) c-'a'+10); } -static struct mu_locus prev_loc; -static struct mu_locus string_beg; -static int prev_newline; - static void -advance_locus (void) +drop_string (void) { - prev_loc = loc; - prev_newline = newline; - - if (newline) - { - loc.mu_line++; - loc.mu_col = 1; - } - yylloc.beg = loc; - loc.mu_col += yyleng; - yylloc.end = loc; - yylloc.end.mu_col--; - -#if 0 - printf ("+%2d> %u:%u-%u:%u: %s\n", - yyleng, - yylloc.beg.mu_line, yylloc.beg.mu_col, - yylloc.end.mu_line, yylloc.end.mu_col, yytext); -#endif - newline = yytext[yyleng-1] == '\n'; - mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, - MU_IOCTL_LOGSTREAM_SET_LOCUS, &loc); + mu_opool_clear (pool); } - -static void -retreat_locus (void) -{ - loc = prev_loc; - newline = prev_newline; -} - + static void finish_string (void) { mu_opool_append_char (pool, 0); yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len); yylval.string.len--; - yylloc.end = yylloc.beg; + + mu_locus_point_copy (&yylloc.end, &yylloc.beg); yylloc.end.mu_col--; - yylloc.beg = string_beg; + mu_locus_point_copy (&yylloc.beg, &string_beg); + mu_locus_point_deinit (&string_beg); + if (mu_debug_level_p (MU_DEBCAT_APP, MU_DEBUG_TRACE5)) { size_t i; @@ -106,7 +77,15 @@ finish_string (void) #endif } -#define YY_USER_ACTION advance_locus (); +#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); + %} %x RULE ARGS ASTRING @@ -127,6 +106,11 @@ WS [ \t][ \t]* BEGIN (RULE); return TYPE; } + +. { + mu_error (_("type/subtype is missing")); + return BOGUS; +} } <RULE>{ @@ -174,12 +158,11 @@ WS [ \t][ \t]* {WS} mu_error ("unexpected whitespace in argument list"); \n { mu_error ("unexpected newline in argument list"); - BEGIN (RULE); - return EOL; + return BOGUS; } . { - string_beg = yylloc.beg; - retreat_locus (); + mu_locus_point_copy (&string_beg, &yylloc.beg); + mu_linetrack_retreat (trk, 1); yyless (0); BEGIN (ASTRING); } @@ -217,8 +200,14 @@ WS [ \t][ \t]* mu_opool_append (pool, yytext, yyleng); } -. { - retreat_locus (); +\n { + mu_error ("unexpected newline in argument"); + drop_string (); + return BOGUS; +} + +. { + mu_linetrack_retreat (trk, 1); yyless (0); BEGIN (ARGS); finish_string (); @@ -232,8 +221,9 @@ mimetypes_open (const char *name) { struct stat st; int mode; - - yy_flex_debug = mu_debug_level_p (MU_DEBCAT_MIME, MU_DEBUG_TRACE4); + char *filename; + + yy_flex_debug = mu_debug_level_p (MU_DEBCAT_APP, MU_DEBUG_TRACE4); if (stat (name, &st)) { @@ -242,28 +232,26 @@ mimetypes_open (const char *name) } if (S_ISDIR (st.st_mode)) - loc.mu_file = mu_make_file_name (name, "mime.types"); + filename = mu_make_file_name (name, "mime.types"); else - loc.mu_file = mu_strdup (name); - loc.mu_line = 1; - loc.mu_col = 1; - newline = 0; - - yyin = fopen (loc.mu_file, "r"); + filename = mu_strdup (name); + + yyin = fopen (filename, "r"); if (!yyin) { - mu_error (_("cannot open `%s': %s"), loc.mu_file, mu_strerror (errno)); - free (loc.mu_file); + mu_error (_("cannot open `%s': %s"), filename, mu_strerror (errno)); + free (filename); return -1; } + MU_ASSERT (mu_linetrack_create (&trk, filename, 3)); + free (filename); + mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_GET_MODE, &mode); mode |= MU_LOGMODE_LOCUS; mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_SET_MODE, &mode); - mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, - MU_IOCTL_LOGSTREAM_SET_LOCUS, &loc); mu_opool_create (&pool, MU_OPOOL_ENOMEMABRT); return 0; @@ -275,16 +263,15 @@ mimetypes_close () int mode; fclose (yyin); - /* FIXME: Don't free (loc.mu_file), because it is referenced by - mu_locus structures in the parse tree */ - + mu_locus_range_deinit (&yylloc); + mu_linetrack_destroy (&trk); mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_GET_MODE, &mode); mode &= ~MU_LOGMODE_LOCUS; mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_SET_MODE, &mode); mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, - MU_IOCTL_LOGSTREAM_SET_LOCUS, NULL); + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, NULL); } int @@ -319,49 +306,34 @@ mimetypes_malloc (size_t size) void lex_next_rule (void) { - int bol = 0; int c; - - if (newline) - { - loc.mu_col = 0; - loc.mu_line++; - newline = 0; - bol = 1; - } + int dbg = yy_flex_debug + || mu_debug_level_p (MU_DEBCAT_APP, MU_DEBUG_TRACE6); - if (yy_flex_debug) + if (dbg) { YY_LOCATION_PRINT (stderr, yylloc); fprintf (stderr, ": started error recovery\n"); } while ((c = input ()) != EOF) { - loc.mu_col++; - if (c == '\n') - { - loc.mu_line++; - loc.mu_col = 0; - bol = 1; - } - else if (bol) + char ch = c; + if (!mu_isspace (c) && mu_linetrack_at_bol (trk)) { - bol = 0; - if (!(c == ' ' || c == '\t')) - { - unput (c); - break; - } - } + unput (c); + break; + } + mu_linetrack_advance (trk, &yylloc, &ch, 1); } - if (yy_flex_debug) + if (dbg) { - yylloc.beg = yylloc.end = loc; - YY_LOCATION_PRINT (stderr, yylloc); + struct mu_locus_range lr = MU_LOCUS_RANGE_INITIALIZER; + mu_linetrack_locus (trk, &lr.beg); + YY_LOCATION_PRINT (stderr, lr); fprintf (stderr, ": finished error recovery\n"); + mu_locus_point_deinit (&lr.beg); } BEGIN (RULE); unput ('\n'); - loc.mu_col = 0; - loc.mu_line--; -} + mu_linetrack_retreat (trk, 1); + } diff --git a/mimeview/mimeview.c b/mimeview/mimeview.c index e67593d..e7194ac 100644 --- a/mimeview/mimeview.c +++ b/mimeview/mimeview.c @@ -66,7 +66,7 @@ cli_debug (struct mu_parseopt *po, struct mu_option *opt, lev = MU_DEBUG_LEVEL_UPTO (MU_DEBUG_TRACE2); else { - mu_debug_get_category_level (MU_DEBCAT_MIME, &lev); + mu_debug_get_category_level (MU_DEBCAT_APP, &lev); for (; *arg; arg++) { switch (*arg) @@ -88,7 +88,7 @@ cli_debug (struct mu_parseopt *po, struct mu_option *opt, } } } - mu_debug_set_category_level (MU_DEBCAT_MIME, lev); + mu_debug_set_category_level (MU_DEBCAT_APP, lev); } static void @@ -222,11 +222,11 @@ display_file (const char *file, const char *type) argv[5] = (char*) mimeview_file; argv[6] = NULL; - if (mu_debug_level_p (MU_DEBCAT_MIME, MU_DEBUG_TRACE0)) + if (mu_debug_level_p (MU_DEBCAT_APP, MU_DEBUG_TRACE0)) { char *string; mu_argcv_string (6, argv, &string); - mu_debug (MU_DEBCAT_MIME, MU_DEBUG_TRACE0, + mu_debug (MU_DEBCAT_APP, MU_DEBUG_TRACE0, (_("executing %s...\n"), string)); free (string); } @@ -247,7 +247,7 @@ display_file (const char *file, const char *type) { display_stream_mailcap (mimeview_file, mimeview_stream, hdr, no_ask_types, interactive, dry_run, - MU_DEBCAT_MIME); + MU_DEBCAT_APP); mu_header_destroy (&hdr); } } @@ -264,9 +264,9 @@ main (int argc, char **argv) if (dry_run) { mu_debug_level_t lev; - mu_debug_get_category_level (MU_DEBCAT_MIME, &lev); + mu_debug_get_category_level (MU_DEBCAT_APP, &lev); lev |= MU_DEBUG_LEVEL_UPTO (MU_DEBUG_TRACE2); - mu_debug_set_category_level (MU_DEBCAT_MIME, lev); + mu_debug_set_category_level (MU_DEBCAT_APP, lev); } if (argc == 0 && !lint) diff --git a/mimeview/mimeview.h b/mimeview/mimeview.h index 39fb7f4..0f0d61f 100644 --- a/mimeview/mimeview.h +++ b/mimeview/mimeview.h @@ -22,6 +22,8 @@ # include <strings.h> #endif #include <mailutils/mailutils.h> +#include <mailutils/locus.h> +#include <mailutils/yyloc.h> #include <fnmatch.h> struct mimetypes_string @@ -48,29 +50,3 @@ const char *get_file_type (void); extern char const *mimeview_file; extern mu_stream_t mimeview_stream; -struct mu_locus_range -{ - struct mu_locus beg; - struct mu_locus end; -}; - -#define YYLTYPE struct mu_locus_range -#define YYLLOC_DEFAULT(Current, Rhs, N) \ - do \ - { \ - if (N) \ - { \ - (Current).beg = YYRHSLOC(Rhs, 1).beg; \ - (Current).end = YYRHSLOC(Rhs, N).end; \ - } \ - else \ - { \ - (Current).beg = YYRHSLOC(Rhs, 0).end; \ - (Current).end = (Current).beg; \ - } \ - } while (0) -#define YY_LOCATION_PRINT(File, Loc) \ - fprintf(File, "%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) diff --git a/mimeview/tests/testsuite.at b/mimeview/tests/testsuite.at index 971b1a2..05c7b87 100644 --- a/mimeview/tests/testsuite.at +++ b/mimeview/tests/testsuite.at @@ -40,8 +40,8 @@ $2: $4 m4_pushdef([build_expect],[__build_expect([],m4_shift(m4_shift($@)))]) -# MIMETEST(NAME,TYPES,FILE,CONTENT,RES) -m4_pushdef([MIMETEST],[ +# MIMEIDENTIFY(NAME,TYPES,FILE,CONTENT,RES) +m4_pushdef([MIMEIDENTIFY],[ AT_SETUP([$1]) AT_KEYWORDS([mimeview]) AT_CHECK([ @@ -55,17 +55,29 @@ mimeview MIMEVIEW_OPTIONS --identify -f mime.types select_args($@) AT_CLEANUP ]) +m4_pushdef([MIMETEST],[ +AT_SETUP([$1]) +AT_KEYWORDS([mimeview]) +AT_CHECK([ +AT_DATA([mime.types],[$2 +]) +mimeview MIMEVIEW_OPTIONS --debug-level=app.=trace6 -t -f mime.types +], +m4_shift(m4_shift($@))) +AT_CLEANUP +]) + dnl ------------------------------------------------------------ AT_INIT AT_TESTED([mimeview]) MUT_VERSION([mimeview]) -MIMETEST([default], +MIMEIDENTIFY([default], [application/octet-stream], [input], [], [application/octet-stream]) -MIMETEST([suffixes], +MIMEIDENTIFY([suffixes], [foo/x-bar bar baz foo/x-qux qux quux ], @@ -74,13 +86,13 @@ foo/x-qux qux quux [a.quux], [], [foo/x-qux], [a.qx], [], [unknown]) -MIMETEST([default ordering], +MIMEIDENTIFY([default ordering], [text/foo bar text/bar bar ], [a.bar], [], [text/bar]) -MIMETEST([priority], +MIMEIDENTIFY([priority], [text/bar bar text/foo bar priority(20) ], @@ -89,7 +101,7 @@ text/foo bar priority(20) AT_BANNER([Functions]) # match("pattern") Pattern match on filename -MIMETEST([match], +MIMEIDENTIFY([match], [application/x-csource match(*.c) ], [a.c],[],[application/x-csource], @@ -97,7 +109,7 @@ MIMETEST([match], # ascii(offset,length) True if bytes are valid printable ASCII # (CR, NL, TAB, BS, 32-126) -MIMETEST([ascii], +MIMEIDENTIFY([ascii], [application/x-bar ascii(16,6) ], [one],[-seek 16 -string foobar -int 100],[application/x-bar], @@ -105,7 +117,7 @@ MIMETEST([ascii], # printable(offset,length) True if bytes are printable 8-bit chars # (CR, NL, TAB, BS, 32-126, 128-254) -MIMETEST([printable], +MIMEIDENTIFY([printable], [application/x-bar printable(16,6) ], [one],[-seek 16 -string foobar -int 100],[application/x-bar], @@ -113,14 +125,14 @@ MIMETEST([printable], [three],[-seek 16 -string fooba -byte 127],[unknown]) # regex(offset,"regex") True if bytes match regular expression -MIMETEST([regex], +MIMEIDENTIFY([regex], [application/pdf regex(0,^[[\n\r]]*%PDF) ], [one],[-byte 10 -byte 10 -byte 13 -byte 10 -string %PDF],[application/pdf], [two],[-byte 10 -byte 10 -byte 13 -byte 7 -string %PDF],[unknown]) # string(offset,"string") True if bytes are identical to string -MIMETEST([string], +MIMEIDENTIFY([string], [application/x-foo string(5,FOO) ], [one],[-seek 5 -string FOO],[application/x-foo], @@ -128,28 +140,28 @@ MIMETEST([string], # istring(offset,"string") True if bytes are identical to # case-insensitive string -MIMETEST([istring], +MIMEIDENTIFY([istring], [application/x-foo istring(5,FOO) ], [one],[-seek 5 -string foO],[application/x-foo], [two],[-seek 4 -string FOO],[unknown]) # char(offset,value) True if byte is identical -MIMETEST([char], +MIMEIDENTIFY([char], [application/x-foo char(5,15) ], [one],[-seek 5 -byte 15],[application/x-foo], [two],[-seek 5 -byte 1],[unknown]) # short(offset,value) True if 16-bit integer is identical -MIMETEST([short], +MIMEIDENTIFY([short], [application/x-foo short(5,1600) ], [one],[-seek 5 -short 1600],[application/x-foo], [two],[-seek 5 -short 1601],[unknown]) # int(offset,value) True if 32-bit integer is identical -MIMETEST([int], +MIMEIDENTIFY([int], [application/x-foo int(5,16578) ], [one],[-seek 5 -int 16578],[application/x-foo], @@ -159,13 +171,13 @@ MIMETEST([int], # FIXME # contains(offset,range,"string") True if the range contains the string -MIMETEST([contains], +MIMEIDENTIFY([contains], [application/x-foo contains(10,1024,"TESTSTRING") ], [one],[-seek 512 -string TESTSTRING],[application/x-foo], [two],[-seek 512 -string TEST],[unknown]) -MIMETEST([argument strings], +MIMEIDENTIFY([argument strings], [application/x-foo string(0,"FOO") application/x-bar string(0,'B A R') application/x-baz string(0,"B A"Z<1B0103>BAZ) @@ -176,7 +188,7 @@ application/x-qux string(0,<1B>45" Q "<01>) [three],[-string "B AZ" -byte 0x1b -byte 0x01 -byte 0x03 -string BAZ],[application/x-baz], [four],[-byte 0x1b -string '45 Q ' -byte 0x01],[application/x-qux]) -MIMETEST([logical or], +MIMEIDENTIFY([logical or], [text/x-bar bar baz string(0,bar) printable(3,10) ], [one.bar],[],[text/x-bar], @@ -185,16 +197,53 @@ MIMETEST([logical or], [bar],[-seek 3 -string teststring],[text/x-bar], [baz],[-seek 3 -string test -byte 0 -string tring],[unknown]) -MIMETEST([logical and], +MIMEIDENTIFY([logical and], [text/x-foo bar + string(0,bar<10>) + printable(4,10) ], [one.bar],[-string bar -byte 0x10 -string TESTSTRING],[text/x-foo], [one],[-string bar -byte 0x10 -string TESTSTRING],[unknown], [two.bar],[-string bar -byte 0x13 -byte 0x10 -string TEST],[unknown]) -MIMETEST([grouping], +MIMEIDENTIFY([grouping], [text/x-foo bar (string(0,bar) + printable(4,10)) ], [one.bar],[-string foo],[text/x-foo], [two.baz],[-string bar -byte 0x10 -string TESTSTRING],[text/x-foo], [three],[-string bar -byte 0x13 -byte 0x10 -string TESTSTRING],[unknown]) + +MIMETEST([error recovery], +[text/x-foo bar (string(0,bar) + printable(4,10)) + string(10,baz) +application/x-baz +], +[1], +[], +[mimeview: mime.types:2.1: type/subtype is missing +mime.types:2.1: started error recovery +mime.types:3: finished error recovery +]) + +MIMETEST([multiple error recovery], +[text/x-foo bar (string(0,bar) + printable(4,10)) + string(10,baz) +application/x-baz baz +image/jpeg jpeg jpg jpe string(0,<FFD8FF>) &&\ + (char(3,0xe0) char(3,0xe1) char(3,0xe2) char(3,0xe3)\ + char(3,0xe4) char(3,0xe5) char(3,0xe6) char(3,0xe7) + char(3,0xe8) char(3,0xe9) char(3,0xea) char(3,0xeb)\ + char(3,0xec) char(3,0xed) char(3,0xee) char(3,0xef)) +image/tiff tiff tif string(0,MM<002A>) string(0,II<2A00>) +], +[1], +[], +[mimeview: mime.types:2.1: type/subtype is missing +mime.types:2.1: started error recovery +mime.types:3: finished error recovery +mimeview: mime.types:6.63: syntax error +mime.types:6.63: started error recovery +mime.types:9: finished error recovery +]) + + +m4_popdef([MIMETEST]) +m4_popdef([MIMEIDENTIFY])
\ No newline at end of file diff --git a/mu-aux/gencl b/mu-aux/gencl index 6e7ca58..4373bfd 100755 --- a/mu-aux/gencl +++ b/mu-aux/gencl @@ -2,6 +2,22 @@ eval '(exit $?0)' && eval 'exec perl -wS "$0" "$@"' & eval 'exec perl -wS "$0" $argv:q' if 0; +# This file is part of GNU Mailutils. +# Copyright (C) 2017 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/>. + use strict; use POSIX qw(strftime); use Getopt::Long qw(:config gnu_getopt no_ignore_case); @@ -589,3 +605,7 @@ EOT $fd = select($fd); close $fd; } + +# Local Variables: +# mode: perl +# End: diff --git a/mu-aux/gitinfo b/mu-aux/gitinfo index a932f2a..a830ff3 100755 --- a/mu-aux/gitinfo +++ b/mu-aux/gitinfo @@ -522,3 +522,6 @@ if (ref($format) eq 'CODE') { print eval_format($format); } +# Local Variables: +# mode: perl +# End: diff --git a/mu-aux/gylwrap b/mu-aux/gylwrap index c91ab48..7dc0cc4 100755 --- a/mu-aux/gylwrap +++ b/mu-aux/gylwrap @@ -1,184 +1,357 @@ -#! /bin/sh -# ylwrap - wrapper for lex/yacc invocations. -# Copyright 1996-1999, 2007, 2010-2012, 2014-2017 Free Software -# Foundation, Inc. -# Written by Tom Tromey <tromey@cygnus.com>. +eval '(exit $?0)' && eval 'exec perl -wS "$0" "$@"' + & eval 'exec perl -wS "$0" $argv:q' + if 0; + +# This file is part of GNU Mailutils. +# Copyright (C) 2017 Free Software Foundation, Inc. # -# This program 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 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. # -# This program 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 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 this program. If not, see <http://www.gnu.org/licenses/>. - -# Usage: -# ylwrap PROGRAM [ARGS] INPUT [OUTPUT DESIRED]... -- [-yy repl] [ARGS]... -# * PROGRAM is program to run; options can follow but must start with `-'. -# * INPUT is the input file -# * OUTPUT is file PROG generates -# * DESIRED is file we actually want -# * ARGS are passed to PROG -# * Optional -yy introduces the sequence to replace yy prefixes with. -# Any number of OUTPUT,DESIRED pairs may be used. - -# The program to run. -prog="$1" -shift -# Make any relative path in $prog absolute. -case "$prog" in - /* | [A-Za-z]:*) ;; - */*) prog="`pwd`/$prog" ;; -esac - -# We also have to accept options here and append them to the program. -# Why? Suppose YACC is set to `bison -y'. Clearly nobody uses -# ylwrap, or this would have been discovered earlier! -while :; do - case "$1" in - -*) - prog="$prog $1" - shift - ;; - *) - break - ;; - esac -done - -# The input. -input="$1" -shift -case "$input" in - /* | [A-Za-z]:*) - # Absolute path; do nothing. - ;; - *) - # Relative path. Make it absolute. - input="`pwd`/$input" - ;; -esac - -# The directory holding the input. -input_dir="`echo $input | sed -e 's,/[^/]*$,,'`" -# Quote $INPUT_DIR so we can use it in a regexp. -# FIXME: really we should care about more than `.'. -input_rx="`echo $input_dir | sed -e 's,\.,\\\.,g'`" - -pairlist= -defout=$1 -while test "$#" -ne 0; do - if test "$1" = "--"; then - shift - break - fi - pairlist="$pairlist $1" - shift -done - -STDOUT="" -if [ $# -ne 0 ]; then - while test "$#" -ne 0; do - case "x$1" in - x-yy) - shift - if [ $# -eq 0 ]; then - echo "ylwrap: -yy requires an argument" - exit 1 - fi - YYREPL=$1 - shift;; - x-stdout) - shift - STDOUT=$defout - ;; - *) - break;; - esac - done -fi - -# FIXME: add hostname here for parallel makes that run commands on -# other machines. But that might take us over the 14-char limit. -dirname=ylwrap$$ -trap "cd `pwd`; rm -rf $dirname > /dev/null 2>&1" 1 2 3 15 -mkdir $dirname || exit 1 - -cd $dirname - -if [ -n "$STDOUT" ]; then - $prog ${1+"$@"} "$input" > $STDOUT -else - $prog ${1+"$@"} "$input" -fi -status=$? - -if test $status -eq 0; then - set X $pairlist - shift - first=yes - # Since DOS filename conventions don't allow two dots, - # the DOS version of Bison writes out y_tab.c instead of y.tab.c - # and y_tab.h instead of y.tab.h. Test to see if this is the case. - y_tab_nodot="no" - if test -f y_tab.c || test -f y_tab.h; then - y_tab_nodot="yes" - fi - - while test "$#" -ne 0; do - from="$1" - # Handle y_tab.c and y_tab.h output by DOS - if test $y_tab_nodot = "yes"; then - if test $from = "y.tab.c"; then - from="y_tab.c" - else - if test $from = "y.tab.h"; then - from="y_tab.h" - fi - fi - fi - if test -f "$from"; then - # If $2 is an absolute path name, then just use that, - # otherwise prepend `../'. - case "$2" in - /* | [A-Za-z]:*) target="$2";; - *) target="../$2";; - esac - - # Edit out `#line' or `#' directives. We don't want the - # resulting debug information to point at an absolute srcdir; - # it is better for it to just mention the .y file with no - # path. - T=`basename $target` - EXPR="/^#/ s,$input_rx/,,;s,\"$from\",\"$T\"," - if [ ! -z "$YYREPL" ]; then - EXPR="$EXPR;s/yy/$YYREPL/g" - fi - sed -e "$EXPR" "$from" > "$target" || status=$? - else - # A missing file is only an error for the first file. This - # is a blatant hack to let us support using "yacc -d". If -d - # is not specified, we don't want an error when the header - # file is "missing". - if test $first = yes; then - status=1 - fi - fi - shift - shift - first=no - done -else - status=$? -fi - -# Remove the directory. -cd .. -rm -rf $dirname - -exit $status +# along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. + +use strict; +use warnings; +use Getopt::Long qw(:config gnu_getopt no_ignore_case require_order auto_version); +use File::Basename; +use File::Temp qw(tempdir); +use Pod::Man; +use Pod::Usage; +use Cwd 'abs_path'; +use List::Regexp; + +=head1 NAME + +gylwrap - wrapper for yacc, lex and similar programs + +=head1 SYNOPSIS + +B<gylwrap> +[B<-?>] +[B<--yyrepl=>I<PREFIX>] +[B<--yysym=>I<STRING>] +[B<--help>] +[B<--version>] +I<INPUT> +[I<OUTPUT> I<DESIRED>]... +B<--> I<PROGRAM> [I<ARGS>] + +=head1 DESCRIPTION + +Wraps B<lex> and B<yacc> invocations to rename their output files. +It also ensures that multiple I<COMMAND> instances can be invoked +in a single directory in parallel and allows for renaming global +symbols to avoid clashes when multiple parsers and/or lexers are +linked in a single executable. + +To achieve this, B<gylwrap> creates a temporary directory, changes +to it, and runs I<PROGRAM>, with I<ARGS> and I<INPUT> as its arguments. +Upon successful exit from I<PROGRAM>, B<gylwrap> processes the +I<OUTPUT>-I<DESIRED> pairs. Each I<OUTPUT> file is then renamed +to the file I<DESIRED>, taking care to fix up any eventual B<#line> +directives. + +If B<--yyrepl=I<PREFIX>> is given, the global symbols that can cause +name clashes are renamed by replacing the initial B<yy> with I<PREFIX>. +For a list of symbols that are subject for replacement, inspect the +B<@sym> variable at the start of the script. Additional names can be +added to this list using the B<--yysym> option. + +Prior to running the I<PROGRAM>, B<gylwrap> program checks whether the +file named B<gylwrap.conf> exists in directory of the I<INPUT> file. +If found, it is parsed as follows. Empty lines and comments (introduced +by the hash sign) are ignored. Rest of lines are either option +assignements, or section headings. + +Option assignements have the form B<I<OPTION> = I<VALUE>>, and generally, +have the same meaning as the corresponding command line option without +the leading two dashes: + +=over 4 + +=item B<yyrepl => I<PREFIX> + +Replace the B<yy> prefix with I<PREFIX> in the identifiers. + +=item B<yysym => I<NAME> + +Add I<NAME> to the list of symbols suitable for prefix replacement. +This keyword can appear multiple times. + +=item B<flags => I<STRING> + +Add I<STRING> to the invocation of I<COMMAND>. This is useful, if you +have several parsers in the same directory, and some of them require +the B<-d> option, while others don't. + +=back + +Section headers have the form B<[I<FILE>]>. The settings under a +section header have effect only if I<FILE> is the same as the I<INPUT> +command line argument. + +=head1 OPTIONS + +=over 4 + +=item B<--yyrepl=>I<PREFIX> + +Replace the B<yy> prefix in global symbols with I<PREFIX>. + +=item B<--yysym=>I<SYMBOL> + +Add I<SYMBOL> to the list of symbols subject for replacement. + +=item B<-?>, B<--help> + +Displays help text and exit + +=item B<--version> + +Displays program version and exits. + +=back + +=head1 NOTE + +This script is an improved version of the B<ylwrap> script, included +in the GNU Automake distribution. + +=cut + +# List of symbols suitable for prefix replacements. See the +# options --yyrepl and --yysym, and similar statements in the configuration +# file. +my @yysym = qw( + yymaxdepth + yyparse + yylex + yyerror + yylval + yychar + yydebug + yypact + yyr1 + yyr2 + yydef + yychk + yypgo + yyact + yyexca + yyerrflag + yynerrs + yyps + yypv + yys + yy_yys + yystate + yytmp + yyv + yy_yyv + yyval + yylloc + yyreds + yytoks + yylhs + yylen + yydefred + yydgoto + yysindex + yyrindex + yygindex + yytable + yycheck + yyname + yyrule + + yy_create_buffer + yy_delete_buffer + yy_flex_debug + yy_init_buffer + yy_flush_buffer + yy_load_buffer_state + yy_switch_to_buffer + yyin + yyleng + yylex + yylineno + yyout + yyrestart + yytext + yywrap + yyalloc + yyrealloc + yyfree +); + +our $VERSION = '1.00'; + +# If prefix replacement is requested, the list above is assembled into +# a single regular expression, stored here. +my $yyrx; + +# String to replace the "yy" prefix with. +my $yyrepl; + +# Input directory with special characters escaped, for "#line" directive +# fixup. +my $input_rx; + +# Configuration settings from the "gylwrap.conf" file. Indexed by +# input file name. Default entry is ''. +my %config; + +# Name of the first output file. This is used to avoid bailing out if +# one of the output files (except the principal one) does not exist. +my $parser; + +# Name this program was invoked as. +my $progname = basename($0); + +# List of files created during the run, for cleanup purposes. +my @created; + +sub filter { + my ($from, $to) = @_; + my $target = basename($to); + my $ifd; + unless (open($ifd, '<', $from)) { + return if $from ne $parser; + die "can't open input file $from: $!"; + } + open(my $ofd, '>', $to) + or die "can't open output file $to: $!"; + push @created, $to; + while (<$ifd>) { + if (/^#/) { + s{$input_rx/}{}; + s{"$from"}{"$target"}; + } + if ($yyrx) { + s{\byy($yyrx)\b}{${yyrepl}$1}g; + } + print $ofd $_ + } + close $ifd; + close $ofd; +} + +sub readconf { + my $file = shift; + open(my $fd, '<', $file) + or die "can't open $file: $!"; + my $key = ''; + while (<$fd>) { + chomp; + s/^\s+//; + if (/^#/ || /^$/) { + next; + } elsif (/^\[(.+)\]/) { + $key = $1; + } elsif (m/(.+?)\s*=\s*(.+)$/) { + if ($1 eq 'yysym' || $1 eq 'flags') { + push @{$config{$key}{$1}}, (split /\s+/, $2); + } else { + $config{$key}{$1} = $2; + } + } else { + print STDERR "$file:$.: unrecognized line\n"; + } + } + close($fd); +} + +my $input; +my @output; + +GetOptions("yyrepl=s" => \$yyrepl, + "yysym=s@" => \@yysym, + "help|?" => sub { + pod2usage(-exitstatus => 0, -verbose => 2); + } + ) or exit(1); + +$input = shift @ARGV; +while (my $arg = shift @ARGV) { + last if ($arg eq '--'); + push @output, $arg; +} + +pod2usage(-exitstatus => 1, -verbose => 0, -output => \*STDERR) + unless (@output && (@output % 2) == 0); + +# Make sure input file name is absolute +$input = abs_path($input); + +my $input_dir = dirname($input); +$input_rx = qr($input_dir); + +my $confile = "$input_dir/gylwrap.conf"; +readconf($confile) if -r $confile; + +my $input_base = basename($input); +unless ($yyrepl) { + $yyrepl = $config{$input_base}{yyrepl} || $config{''}{yyrepl}; +} +if ($yyrepl) { + push @yysym, @{$config{$input_base}{yysym}} + if exists $config{$input_base}{yysym}; + push @yysym, @{$config{''}{yysym}} + if exists $config{''}{yysym}; + if ($yyrepl) { + $yyrx = regexp_opt({ type => 'pcre' }, map { s/^yy//; $_ } @yysym); + } +} + +if (my $flags = $config{$input_base}{flags} || $config{''}{flags}) { + push @ARGV, @$flags; +} +push @ARGV, $input; + +$parser = $output[0]; + +# Create working directory +my $wd = tempdir("ylXXXXXX", DIR => '.', CLEANUP => 1) + or die "cannot create temporary directory"; +chdir $wd + or die "cannot change to the temporary directory"; +END { + if ($?) { + unlink @created; + } + chdir ".."; +} + +system(@ARGV); +if ($? == -1) { + print STDERR "$ARGV[0]: $!\n"; + exit(127); +} elsif ($? & 127) { + print STDERR "$ARGV[0] died with signal ".($? & 127)."\n"; + exit(127); +} else { + my $code = $? >> 8; + exit($code) if $code; +} + +while (my $from = shift @output) { + my $to = shift @output; + $to = '../' . $to unless $to =~ m{^/}; + filter($from, $to); +} + +exit 0; + +# Local Variables: +# mode: perl +# End: + + diff --git a/mu/libexec/dbm.c b/mu/libexec/dbm.c index 50fe4ec..32d66c9 100644 --- a/mu/libexec/dbm.c +++ b/mu/libexec/dbm.c @@ -260,15 +260,17 @@ input_getline (struct iobuf *inp) inp->length = mu_rtrim_class (inp->buffer, MU_CTYPE_ENDLN); if (inp->buffer[0] == '#' && !is_dbm_directive (inp)) { - struct mu_locus loc; + struct mu_locus_range loc; mu_stream_ioctl (mu_strerr, - MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_GET_LOCUS, + MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_GET_LOCUS_RANGE, &loc); - loc.mu_line = strtoul (inp->buffer + 1, NULL, 10); + loc.beg.mu_line = strtoul (inp->buffer + 1, NULL, 10); mu_stream_ioctl (mu_strerr, - MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_SET_LOCUS, + MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, &loc); - free (loc.mu_file); + mu_locus_range_deinit (&loc); continue; } break; @@ -1322,7 +1324,8 @@ add_records (int mode, int replace) const char *flt_argv[] = { "inline-comment", "#", "-S", "-i", "#", NULL }; int rc; int save_log_mode = 0, log_mode; - struct mu_locus save_locus = { NULL, }, locus; + struct mu_locus_range save_locus = MU_LOCUS_RANGE_INITIALIZER, + locus = MU_LOCUS_RANGE_INITIALIZER; struct mu_dbm_datum key, contents; struct iobuf input; struct mu_wordsplit ws; @@ -1364,18 +1367,21 @@ add_records (int mode, int replace) /* Configure error stream to output input file location before each error message */ - locus.mu_file = input_file ? input_file : "<stdin>"; - locus.mu_line = 0; - locus.mu_col = 0; + locus.beg.mu_file = input_file ? input_file : "<stdin>"; + locus.beg.mu_line = 0; + locus.beg.mu_col = 0; + memset (&locus.end, 0, sizeof locus.end); mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_GET_MODE, &save_log_mode); - mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_GET_LOCUS, + mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_GET_LOCUS_RANGE, &save_locus); log_mode = save_log_mode | MU_LOGMODE_LOCUS; mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_SET_MODE, &log_mode); - mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_SET_LOCUS, + mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, &locus); /* Initialize I/O data */ @@ -1443,7 +1449,8 @@ add_records (int mode, int replace) mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_SET_MODE, &save_log_mode); - mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_SET_LOCUS, + mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, &save_locus); if (known_meta_data) diff --git a/mu/libexec/logger.c b/mu/libexec/logger.c index d40f7d9..daa85a9 100644 --- a/mu/libexec/logger.c +++ b/mu/libexec/logger.c @@ -26,7 +26,7 @@ static char logger_args_doc[] = N_("[TEXT]"); static char *input_file = NULL; static int logger_type = MU_STRERR_STDERR; static int log_severity = MU_LOG_ERROR; -static struct mu_locus locus; +static struct mu_locus_range locus = MU_LOCUS_RANGE_INITIALIZER; static int syslog_facility = LOG_USER; static int syslog_priority = LOG_ERR; static char *syslog_tag = NULL; @@ -83,32 +83,67 @@ set_severity (struct mu_parseopt *po, struct mu_option *opt, } static void -set_locus (struct mu_parseopt *po, struct mu_option *opt, - char const *arg) +parse_locus_point (char **ptr, struct mu_locus_point *pt, + struct mu_parseopt *po) { + char *str = *ptr; char *s; - - locus.mu_file = mu_strdup (arg); - s = strchr (arg, ':'); + + s = strchr (str, ':'); if (s) { + char *end; *s++ = 0; - locus.mu_line = strtoul (s, &s, 10); - if (*s == ':') + if (*str) + mu_locus_point_set_file (pt, str); + pt->mu_line = strtoul (s, &end, 10); + if (end == s) + { + mu_parseopt_error (po, _("bad line number: %s"), s); + exit (po->po_exit_error); + } + s = end; + if (*s == '.' || *s == ':') { - locus.mu_col = strtoul (s + 1, &s, 10); - if (*s) + s++; + pt->mu_col = strtoul (s, &end, 10); + if (end == s) { - mu_parseopt_error (po, _("bad column number: %s"), arg); + mu_parseopt_error (po, _("bad column number: %s"), s); exit (po->po_exit_error); } - } - else if (*s) - { - mu_parseopt_error (po, _("bad line number: %s"), arg); - exit (po->po_exit_error); + s = end; } } + else + { + mu_parseopt_error (po, _("missing line number after %s"), s); + exit (po->po_exit_error); + } + *ptr = s; +} + +static void +set_locus (struct mu_parseopt *po, struct mu_option *opt, + char const *arg) +{ + char *s; + char *tmp; + + tmp = mu_strdup (arg); + s = tmp; + parse_locus_point (&s, &locus.beg, po); + if (*s == '-') + { + mu_locus_point_set_file (&locus.end, locus.beg.mu_file); + locus.end.mu_line = locus.beg.mu_line; + locus.end.mu_col = locus.end.mu_col; + s++; + parse_locus_point (&s, &locus.end, po); + } + + if (*s) + mu_parseopt_error (po, _("locus format error near %s"), s); } static struct mu_option logger_options[] = { @@ -127,7 +162,7 @@ static struct mu_option logger_options[] = { { "severity", 's', N_("SEV"), MU_OPTION_DEFAULT, N_("log at Mailutils severity level SEV"), mu_c_string, NULL, set_severity }, - { "locus", 'l', N_("FILE:LINE[:COL]"), MU_OPTION_DEFAULT, + { "locus", 'l', N_("FILE:LINE[.COL][-FILE:LINE[.COL]]"), MU_OPTION_DEFAULT, N_("set locus for logging"), mu_c_string, NULL, set_locus }, { "tag", 't', N_("TAG"), MU_OPTION_DEFAULT, @@ -166,9 +201,9 @@ main (int argc, char **argv) mode = MU_LOGMODE_SEVERITY | MU_LOGMODE_LOCUS; mu_stream_ioctl (logger, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_SET_MODE, &mode); - if (locus.mu_file) + if (locus.beg.mu_file) mu_stream_ioctl (logger, MU_IOCTL_LOGSTREAM, - MU_IOCTL_LOGSTREAM_SET_LOCUS, &locus); + MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, &locus); mu_stream_ioctl (logger, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_SET_SEVERITY, &log_severity); diff --git a/mu/libexec/wicket.c b/mu/libexec/wicket.c index a9d586a..422d2f3 100644 --- a/mu/libexec/wicket.c +++ b/mu/libexec/wicket.c @@ -52,7 +52,7 @@ wicket_match (mu_stream_t stream, const char *str) { int rc, ret; mu_url_t u, url; - struct mu_locus loc; + struct mu_locus_point loc; int flags = MU_URL_PARSE_ALL; if (wicket_verbose > 2) diff --git a/po/POTFILES.in b/po/POTFILES.in index d3c413c..11e993c 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -43,8 +43,8 @@ libmu_sieve/prog.c libmu_sieve/relational.c libmu_sieve/require.c libmu_sieve/runtime.c -libmu_sieve/sieve.l -libmu_sieve/sieve.y +libmu_sieve/sieve-lex.l +libmu_sieve/sieve-gram.y libmu_sieve/tests.c libmu_sieve/util.c libmu_sieve/variables.c @@ -174,8 +174,8 @@ mh/send.c mh/whatnow.c mh/whom.c -mimeview/mimetypes.l -mimeview/mimetypes.y +mimeview/lexer.l +mimeview/grammar.y mimeview/mimeview.c movemail/movemail.c diff --git a/sieve/sieve.c b/sieve/sieve.c index a87b261..6d718e0 100644 --- a/sieve/sieve.c +++ b/sieve/sieve.c @@ -495,8 +495,13 @@ main (int argc, char *argv[]) mu_sieve_set_logger (mach, _sieve_action_log); if (expression_option) - rc = mu_sieve_compile_buffer (mach, script, strlen (script), - "stdin", 1); + { + struct mu_locus_point pt; + pt.mu_file = "stdin"; + pt.mu_line = 1; + pt.mu_col = 0; + rc = mu_sieve_compile_text (mach, script, strlen (script), &pt); + } else rc = mu_sieve_compile (mach, script); if (rc) diff --git a/sieve/tests/i-numeric.at b/sieve/tests/i-numeric.at index 842661b..a357db4 100644 --- a/sieve/tests/i-numeric.at +++ b/sieve/tests/i-numeric.at @@ -38,7 +38,7 @@ if header :comparator "i;ascii-numeric" :contains "X-Number" "15" discard; } ],[78],[], -[sieve: prog:4:1: comparator `i;ascii-numeric' is incompatible with match type `contains' in call to `header' +[sieve: prog:4.41-49: comparator `i;ascii-numeric' is incompatible with match type `contains' in call to `header' ]) AT_CLEANUP |