Commit 110d13ec 110d13ec5187a06c59a53deb0f76b2e944c334ef by Sergey Poznyakoff

Implement "inline-comment" filter.

* include/mailutils/filter.h (mu_filter_xcode_t): Change signature.
(mu_filter_create_args): New proto.
(mu_inline_comment_filter): New extern.

* libmailutils/filter/inline-comment.c: New file.
* libmailutils/filter/Makefile.am (libfilter_la_SOURCES): Add inline-comment.c.
* libmailutils/filter/crlfdot.c (alloc_state): Update declaration.
* libmailutils/filter/crlfflt.c: Likewise.
* libmailutils/filter/dot.c: Likewise.
* libmailutils/filter/fromflt.c (_from_alloc_state): Likewise.
* libmailutils/filter/filter.c (mu_filter_create_args): New function.
(mu_filter_create): Rewrite via mu_filter_create_args.

mh: inline comments are allowed for use in components and forwcomp files.

* mh/compcommon.c (mh_comp_draft): Fix erroneous conditional.
* mh/components: Add comments.
* mh/mh_init.c (mh_file_copy): Rewrite using new API.

mu filter: new option to list supported filters.

* mu/filter.c (filter_options): New option --list (-L).
(filter_parse_opt): Handle the -L option.
(filter_printer, list_filters): New functions.
(main): Print a list of filters if --list was given.
1 parent 90450be6
......@@ -64,11 +64,16 @@ enum mu_filter_result
#define MU_FILTER_MAX_AGAIN 5
typedef int (*mu_filter_new_data_t) (void **, int, void *);
typedef enum mu_filter_result (*mu_filter_xcode_t) (void *data,
enum mu_filter_command cmd,
struct mu_filter_io *iobuf);
typedef int (*mu_filter_new_data_t) (void **, int, int argc,
const char **argv);
typedef enum mu_filter_result
(*mu_filter_xcode_t) (void *data, enum mu_filter_command cmd,
struct mu_filter_io *iobuf);
int mu_filter_create_args (mu_stream_t *pstream, mu_stream_t stream,
const char *name, int argc, const char **argv,
int mode, int flags);
int mu_filter_stream_create (mu_stream_t *pflt,
mu_stream_t str,
int mode,
......@@ -103,6 +108,7 @@ extern mu_filter_record_t mu_bit7_filter;
extern mu_filter_record_t mu_rfc_2047_Q_filter;
extern mu_filter_record_t mu_rfc_2047_B_filter;
extern mu_filter_record_t mu_from_filter;
extern mu_filter_record_t mu_inline_comment_filter;
enum mu_iconv_fallback_mode
{
......
......@@ -27,6 +27,7 @@ libfilter_la_SOURCES =\
filter.c\
filter_iconv.c\
fromflt.c\
inline-comment.c\
linelenflt.c\
qpflt.c
......
......@@ -316,7 +316,8 @@ _crlfdot_encoder (void *xd,
}
static int
alloc_state (void **pret, int mode MU_ARG_UNUSED, void *data MU_ARG_UNUSED)
alloc_state (void **pret, int mode MU_ARG_UNUSED,
int argc MU_ARG_UNUSED, const char **argv MU_ARG_UNUSED)
{
*pret = malloc (sizeof (int));
if (!*pret)
......
......@@ -140,7 +140,8 @@ _crlf_decoder (void *xd MU_ARG_UNUSED,
}
static int
alloc_state (void **pret, int mode, void *data MU_ARG_UNUSED)
alloc_state (void **pret, int mode,
int argc MU_ARG_UNUSED, const char **argv MU_ARG_UNUSED)
{
switch (mode)
{
......
......@@ -248,7 +248,8 @@ _dot_encoder (void *xd,
}
static int
alloc_state (void **pret, int mode MU_ARG_UNUSED, void *data MU_ARG_UNUSED)
alloc_state (void **pret, int mode MU_ARG_UNUSED,
int argc MU_ARG_UNUSED, const char **argv MU_ARG_UNUSED)
{
*pret = malloc (sizeof (int));
if (!*pret)
......
......@@ -78,6 +78,7 @@ mu_filter_get_list (mu_list_t *plist)
mu_list_append (filter_list, mu_rfc_2047_Q_filter);
mu_list_append (filter_list, mu_rfc_2047_B_filter);
mu_list_append (filter_list, mu_from_filter);
mu_list_append (filter_list, mu_inline_comment_filter);
/* FIXME: add the default encodings? */
}
*plist = filter_list;
......@@ -129,7 +130,7 @@ filter_create_wr (mu_stream_t *pstream, mu_stream_t stream,
{
int status;
mu_stream_t fltstream, instream = NULL, tmpstr;
flags &= ~MU_STREAM_AUTOCLOSE;
if (max_line_length)
......@@ -157,13 +158,15 @@ filter_create_wr (mu_stream_t *pstream, mu_stream_t stream,
}
int
mu_filter_create (mu_stream_t *pstream, mu_stream_t stream, const char *name,
int mode, int flags)
mu_filter_create_args (mu_stream_t *pstream, mu_stream_t stream,
const char *name, int argc, const char **argv,
int mode, int flags)
{
int status;
mu_filter_record_t frec;
mu_list_t list;
void *xdata = NULL;
mu_filter_xcode_t xcode;
if ((flags & MU_STREAM_RDWR) == MU_STREAM_RDWR)
return EINVAL;
......@@ -173,9 +176,13 @@ mu_filter_create (mu_stream_t *pstream, mu_stream_t stream, const char *name,
if (status)
return status;
xcode = mode == MU_FILTER_ENCODE ? frec->encoder : frec->decoder;
if (!xcode)
return MU_ERR_EMPTY_VFN;
if (frec->newdata)
{
status = frec->newdata (&xdata, mode, NULL);
status = frec->newdata (&xdata, mode, argc, argv);
if (status)
return status;
}
......@@ -184,10 +191,22 @@ mu_filter_create (mu_stream_t *pstream, mu_stream_t stream, const char *name,
(pstream, stream,
mode == MU_FILTER_ENCODE ? frec->max_line_length : 0,
mode,
mode == MU_FILTER_ENCODE ? frec->encoder : frec->decoder,
xcode,
xdata,
flags);
if (status)
free (xdata);
return status;
}
int
mu_filter_create (mu_stream_t *pstream, mu_stream_t stream, const char *name,
int mode, int flags)
{
const char *argv[2];
argv[0] = name;
argv[1] = NULL;
return mu_filter_create_args (pstream, stream, name, 1, argv, mode,
flags);
}
......
......@@ -262,7 +262,8 @@ _from_encoder (void *xd,
}
static int
_from_alloc_state (void **pret, int mode, void *data MU_ARG_UNUSED)
_from_alloc_state (void **pret, int mode,
int argc MU_ARG_UNUSED, const char **argv MU_ARG_UNUSED)
{
*pret = malloc (sizeof (int));
if (!*pret)
......
/* Simple inline comment filter for GNU Mailutils.
Copyright (C) 2010 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/>. */
/* This filter removes all inline comments from the input.
An inline comment begins with a comment starter character at the beginning
of a line and ends with the newline character.
Default comment starter is semicolon. Another comment starter can
be given as the first argument to the filter creation routine.
Limitations:
1. Comment starter must be a single character. This should be
fixed in future.
2. Comment starter must appear at the beginning of a line. This is
hard (if not downright impossible) to fix, because the filter
has no information about lexical structure of the input stream.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <mailutils/errno.h>
#include <mailutils/filter.h>
enum ilcmt_state
{
ilcmt_initial,
ilcmt_newline,
ilcmt_copy,
ilcmt_comment
};
struct ilcmt_data
{
enum ilcmt_state state;
int cstart;
};
static int
new_ilcmt_state (struct ilcmt_data *pd, int c)
{
switch (pd->state)
{
case ilcmt_initial:
case ilcmt_newline:
if (c == pd->cstart)
{
pd->state = ilcmt_comment;
return 0;
}
else
pd->state = ilcmt_copy;
break;
case ilcmt_copy:
if (c == '\n')
pd->state = ilcmt_newline;
break;
case ilcmt_comment:
if (c == '\n')
pd->state = ilcmt_newline;
return 0;
}
return 1;
}
static enum mu_filter_result
_ilcmt_decoder (void *xd, enum mu_filter_command cmd,
struct mu_filter_io *iobuf)
{
struct ilcmt_data *pd = xd;
size_t i, j;
const unsigned char *iptr;
size_t isize;
char *optr;
size_t osize;
switch (cmd)
{
case mu_filter_init:
pd->state = ilcmt_initial;
return mu_filter_ok;
case mu_filter_done:
return mu_filter_ok;
default:
break;
}
iptr = (const unsigned char *) iobuf->input;
isize = iobuf->isize;
optr = iobuf->output;
osize = iobuf->osize;
for (i = j = 0; i < isize && j < osize; i++)
{
unsigned char c = *iptr++;
if (new_ilcmt_state (pd, c))
optr[j++] = c;
}
iobuf->isize = i;
iobuf->osize = j;
return mu_filter_ok;
}
static int
alloc_state (void **pret, int mode MU_ARG_UNUSED, int argc, const char **argv)
{
struct ilcmt_data *pd = malloc (sizeof (*pd));
if (!pd)
return ENOMEM;
if (argc == 2)
pd->cstart = argv[1][0];
else
pd->cstart = ';';
*pret = pd;
return 0;
}
static struct _mu_filter_record _inline_comment_filter = {
"INLINE-COMMENT",
0,
alloc_state,
NULL,
_ilcmt_decoder
};
mu_filter_record_t mu_inline_comment_filter = &_inline_comment_filter;
......@@ -34,7 +34,7 @@ mh_comp_draft (const char *formfile, const char *defformfile,
if (formfile)
{
s = mh_expand_name (MHLIBDIR, formfile, 0);
if (mh_file_copy (s, draftfile) == 0)
if (mh_file_copy (s, draftfile))
exit (1);
}
else
......
;; Default components file for GNU MH.
;; Lines beginning with ; are ignored. Rest of lines is copied verbatim.
To:
cc:
Subject:
......
......@@ -583,34 +583,19 @@ mh_spawnp (const char *prog, const char *file)
return rc;
}
/* Copy data from FROM to TO, creating the latter if necessary.
FIXME: How about formats?
*/
int
mh_file_copy (const char *from, const char *to)
{
char *buffer;
size_t bufsize, rdsize;
struct stat st;
mu_stream_t in;
mu_stream_t out;
mu_stream_t in, out, flt;
int rc;
if (stat (from, &st))
{
mu_error ("mh_copy: %s", mu_strerror (errno));
return -1;
}
for (bufsize = st.st_size; bufsize > 0 && (buffer = malloc (bufsize)) == 0;
bufsize /= 2)
;
if (!bufsize)
mh_err_memory (1);
if ((rc = mu_file_stream_create (&in, from, MU_STREAM_READ)))
{
mu_error (_("cannot open input file `%s': %s"),
from, mu_strerror (rc));
free (buffer);
return 1;
}
......@@ -618,31 +603,28 @@ mh_file_copy (const char *from, const char *to)
{
mu_error (_("cannot open output file `%s': %s"),
to, mu_strerror (rc));
free (buffer);
mu_stream_close (in);
mu_stream_destroy (&in);
return 1;
}
while (st.st_size > 0
&& (rc = mu_stream_read (in, buffer, bufsize, &rdsize)) == 0
&& rdsize > 0)
rc = mu_filter_create (&flt, in, "INLINE-COMMENT", MU_FILTER_DECODE,
MU_STREAM_READ);
mu_stream_unref (in);
if (rc)
{
if ((rc = mu_stream_write (out, buffer, rdsize, NULL)) != 0)
{
mu_error (_("write error on `%s': %s"),
to, mu_strerror (rc));
break;
}
st.st_size -= rdsize;
mu_error (_("cannot open filter stream: %s"), mu_strerror (rc));
mu_stream_destroy (&out);
return 1;
}
free (buffer);
mu_stream_close (in);
mu_stream_close (out);
mu_stream_destroy (&in);
rc = mu_stream_copy (out, flt, 0, NULL);
mu_stream_destroy (&flt);
mu_stream_destroy (&out);
if (rc)
mu_error (_("error copying file `%s' to `%s': %s"),
from, to, mu_strerror (rc));
return rc;
}
......
......@@ -25,13 +25,14 @@
static char filter_doc[] = N_("mu filter - apply a filter to the input");
char filter_docstring[] = N_("apply a filter to the input");
static char filter_args_doc[] = N_("NAME");
static char filter_args_doc[] = N_("NAME [ARGS]");
static struct argp_option filter_options[] = {
{ "encode", 'e', NULL, 0, N_("encode the input (default)") },
{ "decode", 'd', NULL, 0, N_("decode the input") },
{ "line-length", 'l', N_("NUMBER"), 0, N_("limit output line length") },
{ "newline", 'n', NULL, 0, N_("print additional newline") },
{ "list", 'L', NULL, 0, N_("list supported filters") },
{ NULL }
};
......@@ -39,6 +40,7 @@ static int filter_mode = MU_FILTER_ENCODE;
static int newline_option = 0;
static size_t line_length;
static int line_length_option = 0;
static int list_option;
static error_t
filter_parse_opt (int key, char *arg, struct argp_state *state)
......@@ -65,6 +67,10 @@ filter_parse_opt (int key, char *arg, struct argp_state *state)
argp_error (state, N_("not a number"));
line_length_option = 1;
break;
case 'L':
list_option = 1;
break;
default:
return ARGP_ERR_UNKNOWN;
......@@ -98,6 +104,28 @@ reset_line_length (const char *name, size_t length)
/* don't bail out, leave that to mu_filter_create */
}
static int
filter_printer (void *item, void *data)
{
mu_filter_record_t rec = item;
printf ("%s\n", rec->name);
return 0;
}
static int
list_filters ()
{
mu_list_t list;
int rc = mu_filter_get_list (&list);
if (rc)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_filter_get_list", NULL, rc);
return 1;
}
return mu_list_do (list, filter_printer, NULL);
}
int
mutool_filter (int argc, char **argv)
{
......@@ -111,7 +139,17 @@ mutool_filter (int argc, char **argv)
argc -= index;
argv += index;
if (argc != 1)
if (list_option)
{
if (argc)
{
mu_error (_("excess arguments"));
return 1;
}
return list_filters ();
}
if (argc == 0)
{
mu_error (_("what filter do you want?"));
return 1;
......@@ -136,7 +174,8 @@ mutool_filter (int argc, char **argv)
if (line_length_option)
reset_line_length (fltname, line_length);
rc = mu_filter_create (&flt, in, fltname, filter_mode, MU_STREAM_READ);
rc = mu_filter_create_args (&flt, in, fltname, argc, (const char **)argv,
filter_mode, MU_STREAM_READ);
if (rc)
{
mu_error (_("cannot open filter stream: %s"), mu_strerror (rc));
......