summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--comsat/action.c40
-rw-r--r--comsat/comsat.h2
-rw-r--r--examples/.gitignore1
-rw-r--r--examples/Makefile.am16
-rw-r--r--examples/aclck.c29
-rw-r--r--examples/header.c34
-rw-r--r--examples/mta.c52
-rw-r--r--examples/pop3client.c1189
-rw-r--r--imap4d/fetch.c106
-rw-r--r--imap4d/imap4d.h2
-rw-r--r--include/mailutils/Makefile.am3
-rw-r--r--include/mailutils/argcv.h64
-rw-r--r--include/mailutils/mailutils.h1
-rw-r--r--include/mailutils/wordsplit.h135
-rw-r--r--lib/mailcap.c34
-rw-r--r--libmailutils/auth/mu_auth.c26
-rw-r--r--libmailutils/base/Makefile.am3
-rw-r--r--libmailutils/base/argcv.c112
-rw-r--r--libmailutils/base/argcvfree.c51
-rw-r--r--libmailutils/base/argcvjoin.c116
-rw-r--r--libmailutils/base/argcvrem.c55
-rw-r--r--libmailutils/base/mutil.c19
-rw-r--r--libmailutils/cfg/format.c7
-rw-r--r--libmailutils/cfg/lexer.l4
-rw-r--r--libmailutils/cfg/parser.y77
-rw-r--r--libmailutils/diag/gdebug.c29
-rw-r--r--libmailutils/mailer/mailer.c30
-rw-r--r--libmailutils/server/acl.c18
-rw-r--r--libmailutils/stream/prog_stream.c13
-rw-r--r--libmailutils/string/Makefile.am1
-rw-r--r--libmailutils/string/wordsplit.c1469
-rw-r--r--libmailutils/tests/.gitignore1
-rw-r--r--libmailutils/tests/Makefile.am6
-rw-r--r--libmailutils/tests/argcv.c1
-rw-r--r--libmailutils/tests/listop.c76
-rw-r--r--libmailutils/tests/testsuite.at1
-rw-r--r--libmailutils/tests/wordsplit.at304
-rw-r--r--libmailutils/tests/wsp.c285
-rw-r--r--libmailutils/url/copy.c2
-rw-r--r--libmailutils/url/create.c21
-rw-r--r--libmu_argp/muinit.c1
-rw-r--r--libmu_auth/ldap.c38
-rw-r--r--libmu_auth/radius.c32
-rw-r--r--libmu_sieve/sieve.l4
-rw-r--r--libproto/mailer/mbox.c36
-rw-r--r--libproto/mailer/smtp.c28
-rw-r--r--libproto/mailer/smtp_gsasl.c29
-rw-r--r--mail/mail.h1
-rw-r--r--mail/mailline.c26
-rw-r--r--mail/mailvar.c23
-rw-r--r--mail/send.c19
-rw-r--r--mail/util.c37
-rw-r--r--mh/folder.c37
-rw-r--r--mh/mh.h1
-rw-r--r--mh/mh_alias.y20
-rw-r--r--mh/mh_argp.c22
-rw-r--r--mh/mh_init.c25
-rw-r--r--mh/mh_list.c36
-rw-r--r--mh/mh_msgset.c17
-rw-r--r--mh/mh_sequence.c28
-rw-r--r--mh/mh_whatnow.c16
-rw-r--r--mh/mhn.c64
-rw-r--r--mh/send.c60
-rw-r--r--movemail/movemail.c18
-rw-r--r--mu/shell.c35
-rw-r--r--po/POTFILES.in6
-rw-r--r--pop3d/popauth.c115
-rw-r--r--readmsg/readmsg.c32
-rw-r--r--readmsg/readmsg.h2
-rw-r--r--testsuite/smtpsend.c21
70 files changed, 3318 insertions, 1946 deletions
diff --git a/comsat/action.c b/comsat/action.c
index 0e1e679cd..4a8701348 100644
--- a/comsat/action.c
+++ b/comsat/action.c
@@ -204,7 +204,7 @@ expand_line (const char *str, mu_message_t msg)
p++;
if (*p)
{
- c = mu_argcv_unquote_char (*p);
+ c = mu_wordsplit_c_unquote_char (*p);
obstack_1grow (&stk, c);
}
break;
@@ -300,7 +300,8 @@ action_exec (FILE *tty, int argc, char **argv)
if (argv[0][0] != '/')
{
- mu_diag_output (MU_DIAG_ERROR, _("not an absolute pathname: %s"), argv[0]);
+ mu_diag_output (MU_DIAG_ERROR, _("not an absolute pathname: %s"),
+ argv[0]);
return;
}
@@ -388,15 +389,14 @@ run_user_action (FILE *tty, const char *cr, mu_message_t msg)
while ((n = act_getline (fp, &stmt, &size)))
{
- int argc;
- char **argv;
+ struct mu_wordsplit ws;
- if (mu_argcv_get (stmt, "", NULL, &argc, &argv) == 0
- && argc
- && argv[0][0] != '#')
+ ws.ws_comment = "#";
+ if (mu_wordsplit (stmt, &ws, MU_WRDSF_DEFFLAGS | MU_WRDSF_COMMENT)
+ && ws.ws_wordc)
{
mu_debug_set_locus (debug, rcname, line);
- if (strcmp (argv[0], "beep") == 0)
+ if (strcmp (ws.ws_wordv[0], "beep") == 0)
{
/* FIXME: excess arguments are ignored */
action_beep (tty);
@@ -406,25 +406,27 @@ run_user_action (FILE *tty, const char *cr, mu_message_t msg)
{
/* Rest of actions require keyword expansion */
int i;
- int n_option = argc > 1 && strcmp (argv[1], "-n") == 0;
+ int n_option = ws.ws_wordc > 1 &&
+ strcmp (ws.ws_wordv[1], "-n") == 0;
- for (i = 1; i < argc; i++)
+ for (i = 1; i < ws.ws_wordc; i++)
{
- char *oldarg = argv[i];
- argv[i] = expand_line (argv[i], msg);
+ char *oldarg = ws.ws_wordv[i];
+ ws.ws_wordv[i] = expand_line (ws.ws_wordv[i], msg);
free (oldarg);
- if (!argv[i])
+ if (!ws.ws_wordv[i])
break;
}
- if (strcmp (argv[0], "echo") == 0)
+ if (strcmp (ws.ws_wordv[0], "echo") == 0)
{
- action_echo (tty, cr, n_option, argc - 1, argv + 1);
+ action_echo (tty, cr, n_option,
+ ws.ws_wordc - 1, ws.ws_wordv + 1);
nact++;
}
- else if (strcmp (argv[0], "exec") == 0)
+ else if (strcmp (ws.ws_wordv[0], "exec") == 0)
{
- action_exec (tty, argc - 1, argv + 1);
+ action_exec (tty, ws.ws_wordc - 1, ws.ws_wordv + 1);
nact++;
}
else
@@ -432,12 +434,12 @@ run_user_action (FILE *tty, const char *cr, mu_message_t msg)
fprintf (tty, _(".biffrc:%d: unknown keyword"), line);
fprintf (tty, "\r\n");
mu_diag_output (MU_DIAG_ERROR, _("unknown keyword %s"),
- argv[0]);
+ ws.ws_wordv[0]);
break;
}
}
}
- mu_argcv_free (argc, argv);
+ mu_wordsplit_free (&ws);
line += n;
}
fclose (fp);
diff --git a/comsat/comsat.h b/comsat/comsat.h
index 5148fa809..1c1381abf 100644
--- a/comsat/comsat.h
+++ b/comsat/comsat.h
@@ -53,7 +53,7 @@
#include <mailutils/registrar.h>
#include <mailutils/stream.h>
#include <mailutils/mu_auth.h>
-#include <mailutils/argcv.h>
+#include <mailutils/wordsplit.h>
#include <mailutils/nls.h>
#include <mailutils/daemon.h>
#include <mailutils/acl.h>
diff --git a/examples/.gitignore b/examples/.gitignore
index b42a9289a..af4156be3 100644
--- a/examples/.gitignore
+++ b/examples/.gitignore
@@ -20,6 +20,5 @@ muemail
murun
musocio
nntpclient
-pop3client
sfrom
url-parse
diff --git a/examples/Makefile.am b/examples/Makefile.am
index 1addf4445..45ee0fcef 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -15,10 +15,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/>.
-if MU_COND_SUPPORT_POP
- POP3CLIENT = pop3client
-endif
-
if MU_COND_SUPPORT_NNTP
NNTPCLIENT = nntpclient
endif
@@ -46,10 +42,9 @@ noinst_PROGRAMS = \
murun\
musocio\
$(NNTPCLIENT)\
- $(POP3CLIENT)\
sfrom
-EXTRA_PROGRAMS = pop3client nntpclient
+EXTRA_PROGRAMS = nntpclient
## NOTE: Numaddr must be an installable target, otherwise libtool
## will not create a shared library and `make check' will fail in
@@ -94,15 +89,6 @@ sfrom_LDADD =\
@MU_AUTHLIBS@\
${MU_LIB_MAILUTILS}
-pop3client_CPPFLAGS = @MU_APP_COMMON_INCLUDES@
-pop3client_LDADD = \
- ../lib/libmuaux.a\
- ${MU_LIB_POP}\
- ${MU_LIB_AUTH}\
- @MU_AUTHLIBS@\
- ${MU_LIB_MAILUTILS}\
- @READLINE_LIBS@
-
nntpclient_LDADD = \
../lib/libmuaux.a\
${MU_LIB_NNTP}\
diff --git a/examples/aclck.c b/examples/aclck.c
index d4d9b9549..404e87f74 100644
--- a/examples/aclck.c
+++ b/examples/aclck.c
@@ -62,8 +62,8 @@ read_rules (FILE *fp)
{
char buf[512];
int line = 0;
- int argc = 0;
- char **argv;
+ int wsflags = MU_WRDSF_DEFFLAGS | MU_WRDSF_COMMENT;
+ struct mu_wordsplit ws;
int rc;
rc = mu_acl_create (&acl);
@@ -72,7 +72,8 @@ read_rules (FILE *fp)
mu_error ("cannot create acl: %s", mu_strerror (rc));
exit (1);
}
-
+
+ ws.ws_comment = "#";
while (fgets (buf, sizeof buf, fp))
{
unsigned long netmask;
@@ -95,17 +96,20 @@ read_rules (FILE *fp)
if (buf[0] == '#')
continue;
- if (argc)
- mu_argcv_free (argc, argv);
-
- mu_argcv_get (buf, " \t", "#", &argc, &argv);
- if (argc < 2)
+ if (mu_wordsplit (buf, &ws, wsflags))
+ {
+ mu_error ("cannot split line `%s': %s", buf,
+ mu_wordsplit_strerror (&ws));
+ continue;
+ }
+ wsflags |= MU_WRDSF_REUSE;
+ if (ws.ws_wordc < 2)
{
mu_error ("%d: invalid input", line);
continue;
}
- p = strchr (argv[1], '/');
+ p = strchr (ws.ws_wordv[1], '/');
if (p)
{
char *q;
@@ -144,7 +148,7 @@ read_rules (FILE *fp)
else
netmask = 0xfffffffful;
- sa = parse_address (&salen, argv[1]);
+ sa = parse_address (&salen, ws.ws_wordv[1]);
/* accept addr
deny addr
@@ -152,7 +156,7 @@ read_rules (FILE *fp)
exec addr [rest ...]
execif addr rest ....]
*/
- if (mu_acl_string_to_action (argv[0], &action))
+ if (mu_acl_string_to_action (ws.ws_wordv[0], &action))
{
mu_error ("%d: invalid command", line);
continue;
@@ -167,7 +171,7 @@ read_rules (FILE *fp)
case mu_acl_log:
case mu_acl_exec:
case mu_acl_ifexec:
- data = strdup (argv[2]);
+ data = strdup (ws.ws_wordv[2]);
}
rc = mu_acl_append (acl, action, data, sa, salen, netmask);
@@ -175,6 +179,7 @@ read_rules (FILE *fp)
mu_error ("%d: cannot append acl entry: %s", line,
mu_strerror (rc));
}
+ mu_wordsplit_free (&ws);
}
int
diff --git a/examples/header.c b/examples/header.c
index 1d6c79097..18357a4e3 100644
--- a/examples/header.c
+++ b/examples/header.c
@@ -489,9 +489,9 @@ main (int argc, char **argv)
{
int c;
char buf[512];
- char **prevv;
+ char **prevv = NULL;
int prevc = 0;
-
+
interactive = isatty (0);
while ((c = getopt (argc, argv, "f:h")) != EOF)
{
@@ -525,36 +525,36 @@ main (int argc, char **argv)
}
}
- while (prompt(0), fgets(buf, sizeof buf, stdin))
+ while (prompt (0), fgets (buf, sizeof buf, stdin))
{
- int c;
- char **v;
- int status;
+ struct mu_wordsplit ws;
line_num++;
- status = mu_argcv_get (buf, NULL, "#", &c, &v);
- if (status)
+ ws.ws_comment = "#";
+ if (mu_wordsplit (buf, &ws, MU_WRDSF_DEFFLAGS | MU_WRDSF_COMMENT))
{
- mu_error ("%u: cannot parse: %s",
- line_num, mu_strerror (status));
+ mu_error ("cannot split line `%s': %s", buf,
+ mu_wordsplit_strerror (&ws));
continue;
}
-
- if (c == 0)
+
+ if (ws.ws_wordc == 0)
{
if (prevc)
docmd (prevc, prevv);
- else
- mu_argcv_free (c, v);
}
else
{
- docmd (c, v);
+ docmd (ws.ws_wordc, ws.ws_wordv);
mu_argcv_free (prevc, prevv);
- prevc = c;
- prevv = v;
+ prevc = ws.ws_wordc;
+ prevv = ws.ws_wordv;
+ ws.ws_wordc = 0;
+ ws.ws_wordv = NULL;
}
+ mu_wordsplit_free (&ws);
}
+ mu_argcv_free (prevc, prevv);
exit (0);
}
diff --git a/examples/mta.c b/examples/mta.c
index 705a2b0cd..bff83d541 100644
--- a/examples/mta.c
+++ b/examples/mta.c
@@ -565,30 +565,31 @@ smtp (mu_stream_t str)
char *buf = NULL;
size_t size = 0;
char *rcpt_addr;
+ int wsflags = MU_WRDSF_DEFFLAGS;
+ struct mu_wordsplit ws;
smtp_reply (str, 220, "Ready");
for (state = STATE_INIT; state != STATE_QUIT; )
{
- char *s;
- int argc;
- char **argv;
int kw;
size_t len;
if (mu_stream_getline (str, &buf, &size, &len) || len == 0)
exit (EX_PROTOCOL);
- s = mu_str_stripws (buf);
-
- if (mu_argcv_get (s, "", NULL, &argc, &argv))
- exit (EX_UNAVAILABLE);
+ if (mu_wordsplit (buf, &ws, wsflags))
+ {
+ mu_error ("cannot split line `%s': %s", buf,
+ mu_wordsplit_strerror (&ws));
+ exit (EX_UNAVAILABLE);
+ }
+ wsflags |= MU_WRDSF_REUSE;
- kw = smtp_kw (argv[0]);
+ kw = smtp_kw (ws.ws_wordv[0]);
if (kw == KW_QUIT)
{
smtp_reply (str, 221, "Done");
state = STATE_QUIT;
- mu_argcv_free (argc, argv);
continue;
}
@@ -599,13 +600,14 @@ smtp (mu_stream_t str)
{
case KW_EHLO:
case KW_HELO:
- if (argc == 2)
+ if (ws.ws_wordc == 2)
{
smtp_reply (str, 250, "pleased to meet you");
state = STATE_EHLO;
}
else
- smtp_reply (str, 501, "%s requires domain address", argv[0]);
+ smtp_reply (str, 501, "%s requires domain address",
+ ws.ws_wordv[0]);
break;
default:
@@ -618,10 +620,11 @@ smtp (mu_stream_t str)
switch (kw)
{
case KW_MAIL:
- if (argc == 2)
- from_person = check_prefix (argv[1], "from:");
- else if (argc == 3 && mu_c_strcasecmp (argv[1], "from:") == 0)
- from_person = argv[2];
+ if (ws.ws_wordc == 2)
+ from_person = check_prefix (ws.ws_wordv[1], "from:");
+ else if (ws.ws_wordc == 3 &&
+ mu_c_strcasecmp (ws.ws_wordv[1], "from:") == 0)
+ from_person = ws.ws_wordv[2];
else
from_person = NULL;
@@ -644,10 +647,11 @@ smtp (mu_stream_t str)
switch (kw)
{
case KW_RCPT:
- if (argc == 2)
- rcpt_addr = check_prefix (argv[1], "to:");
- else if (argc == 3 && mu_c_strcasecmp (argv[1], "to:") == 0)
- rcpt_addr = argv[2];
+ if (ws.ws_wordc == 2)
+ rcpt_addr = check_prefix (ws.ws_wordv[1], "to:");
+ else if (ws.ws_wordc == 3 &&
+ mu_c_strcasecmp (ws.ws_wordv[1], "to:") == 0)
+ rcpt_addr = ws.ws_wordv[2];
else
rcpt_addr = NULL;
@@ -674,10 +678,11 @@ smtp (mu_stream_t str)
switch (kw)
{
case KW_RCPT:
- if (argc == 2)
- rcpt_addr = check_prefix (argv[1], "to:");
- else if (argc == 3 && mu_c_strcasecmp (argv[1], "to:") == 0)
- rcpt_addr = argv[2];
+ if (ws.ws_wordc == 2)
+ rcpt_addr = check_prefix (ws.ws_wordv[1], "to:");
+ else if (ws.ws_wordc == 3 &&
+ mu_c_strcasecmp (ws.ws_wordv[1], "to:") == 0)
+ rcpt_addr = ws.ws_wordv[2];
else
rcpt_addr = NULL;
@@ -734,7 +739,6 @@ smtp (mu_stream_t str)
break;
}
- mu_argcv_free (argc, argv);
}
}
diff --git a/examples/pop3client.c b/examples/pop3client.c
deleted file mode 100644
index 7b1f8642f..000000000
--- a/examples/pop3client.c
+++ /dev/null
@@ -1,1189 +0,0 @@
-/* pop3client.c -- An application which demonstrates how to use the
- GNU Mailutils pop3 functions. This application interactively allows users
- to contact a pop3 server.
-
- Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 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/>. */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <strings.h>
-#include <stdlib.h>
-#include <termios.h>
-#include <signal.h>
-#include <xalloc.h>
-
-#ifdef WITH_READLINE
-# include <readline/readline.h>
-# include <readline/history.h>
-#endif
-
-#include <mailutils/pop3.h>
-#include <mailutils/iterator.h>
-#include <mailutils/error.h>
-#include <mailutils/errno.h>
-#include <mailutils/vartab.h>
-#include <mailutils/argcv.h>
-#include <mailutils/cctype.h>
-#include <mailutils/cstr.h>
-#include <mailutils/tls.h>
-#include <mailutils/util.h>
-
-/* A structure which contains information on the commands this program
- can understand. */
-
-typedef struct
-{
- const char *name; /* User printable name of the function. */
- int argmin;
- int argmax;
- int (*func) (int, char **); /* Function to call to do the job. */
- const char *doc; /* Documentation for this function. */
-}
-COMMAND;
-
-/* The names of functions that actually do the manipulation. */
-int com_apop (int, char **);
-int com_capa (int, char **);
-int com_disconnect (int, char **);
-int com_dele (int, char **);
-int com_exit (int, char **);
-int com_help (int, char **);
-int com_list (int, char **);
-int com_noop (int, char **);
-int com_connect (int, char **);
-int com_pass (int, char **);
-int com_quit (int, char **);
-int com_retr (int, char **);
-int com_rset (int, char **);
-int com_stat (int, char **);
-int com_top (int, char **);
-int com_uidl (int, char **);
-int com_user (int, char **);
-int com_verbose (int, char **);
-int com_prompt (int, char **);
-int com_stls (int, char **);
-int com_history (int, char **);
-
-COMMAND *find_command (char *);
-
-COMMAND commands[] = {
- { "apop", 3, 3, com_apop,
- "Authenticate with APOP: APOP user secret" },
- { "capa", 1, -1, com_capa,
- "List capabilities: capa [-reread] [names...]" },
- { "disconnect", 1, 1,
- com_disconnect, "Close connection: disconnect" },
- { "dele", 2, 2, com_dele,
- "Mark message: DELE msgno" },
- { "exit", 1, 1, com_exit,
- "exit program" },
- { "help", 1, 1, com_help,
- "Display this text" },
- { "?", 1, 1, com_help,
- "Synonym for `help'" },
- { "list", 1, 2, com_list,
- "List messages: LIST [msgno]" },
- { "noop", 1, 1, com_noop,
- "Send no operation: NOOP" },
- { "pass", 1, 2, com_pass,
- "Send passwd: PASS [passwd]" },
- { "prompt", -1, -1, com_prompt,
- "Set command prompt" },
- { "connect", 1, 4, com_connect,
- "Open connection: connect [-tls] hostname port" },
- { "quit", 1, 1, com_quit,
- "Go to Update state : QUIT" },
- { "retr", 2, 2, com_retr,
- "Dowload message: RETR msgno" },
- { "rset", 1, 1, com_rset,
- "Unmark all messages: RSET" },
- { "stat", 1, 1, com_stat,
- "Get the size and count of mailbox : STAT" },
- { "stls", 1, 1, com_stls,
- "Start TLS negotiation" },
- { "top", 2, 3, com_top,
- "Get the header of message: TOP msgno [lines]" },
- { "uidl", 1, 2, com_uidl,
- "Get the unique id of message: UIDL [msgno]" },
- { "user", 2, 2, com_user,
- "send login: USER user" },
- { "verbose", 1, 4, com_verbose,
- "Enable Protocol tracing: verbose [on|off|mask|unmask] [x1 [x2]]" },
-#ifdef WITH_READLINE
- { "history", 1, 1, com_history,
- "Show command history" },
-#endif
- { NULL }
-};
-
-/* Global handle for pop3. */
-mu_pop3_t pop3;
-
-/* Flag if verbosity is needed. */
-int verbose;
-#define VERBOSE_MASK(n) (1<<((n)+1))
-#define SET_VERBOSE_MASK(n) (verbose |= VERBOSE_MASK (n))
-#define CLR_VERBOSE_MASK(n) (verbose &= VERBOSE_MASK (n))
-#define QRY_VERBOSE_MASK(n) (verbose & VERBOSE_MASK (n))
-#define HAS_VERBOSE_MASK(n) (verbose & ~1)
-#define SET_VERBOSE() (verbose |= 1)
-#define CLR_VERBOSE() (verbose &= ~1)
-#define QRY_VERBOSE() (verbose & 1)
-
-/* When non-zero, this global means the user is done using this program. */
-int done;
-
-enum pop_session_status
- {
- pop_session_disconnected,
- pop_session_connected,
- pop_session_logged_in
- };
-
-enum pop_session_status pop_session_status;
-
-int connect_argc;
-char **connect_argv;
-
-/* Host we are connected to. */
-#define host connect_argv[0]
-int port = 110;
-char *username;
-
-/* Command line prompt */
-#define DEFAULT_PROMPT "pop3> "
-char *prompt;
-
-const char *
-pop_session_str (enum pop_session_status stat)
-{
- switch (stat)
- {
- case pop_session_disconnected:
- return "disconnected";
-
- case pop_session_connected:
- return "connected";
-
- case pop_session_logged_in:
- return "logged in";
- }
- return "unknown";
-}
-
-char *
-expand_prompt ()
-{
- mu_vartab_t vtab;
- char *str;
-
- if (mu_vartab_create (&vtab))
- return strdup (prompt);
- mu_vartab_define (vtab, "user",
- (pop_session_status == pop_session_logged_in) ?
- username : "not logged in", 1);
- mu_vartab_define (vtab, "host",
- (pop_session_status != pop_session_disconnected) ?
- host : "not connected", 1);
- mu_vartab_define (vtab, "program-name", mu_program_name, 1);
- mu_vartab_define (vtab, "canonical-program-name", "pop3client", 1);
- mu_vartab_define (vtab, "package", PACKAGE, 1);
- mu_vartab_define (vtab, "version", PACKAGE_VERSION, 1);
- mu_vartab_define (vtab, "status", pop_session_str (pop_session_status), 1);
-
- if (mu_vartab_expand (vtab, prompt, &str))
- str = strdup (prompt);
- mu_vartab_destroy (&vtab);
- return str;
-}
-
-
-
-#ifdef WITH_READLINE
-#define HISTFILE_SUFFIX "_history"
-
-static char *
-get_history_file_name ()
-{
- static char *filename = NULL;
-
- if (!filename)
- {
- char *hname;
-
- hname = xmalloc(3 + strlen (rl_readline_name) + sizeof HISTFILE_SUFFIX);
- strcpy (hname, "~/.");
- strcat (hname, rl_readline_name);
- strcat (hname, HISTFILE_SUFFIX);
- filename = mu_tilde_expansion (hname, "/", NULL);
- free(hname);
- }
- return filename;
-}
-
-/* Interface to Readline Completion */
-
-char *command_generator (const char *, int);
-char **pop_completion (char *, int, int);
-
-/* Tell the GNU Readline library how to complete. We want to try to complete
- on command names if this is the first word in the line, or on filenames
- if not. */
-void
-initialize_readline ()
-{
- /* Allow conditional parsing of the ~/.inputrc file. */
- rl_readline_name = (char *) "pop3client";
-
- /* Tell the completer that we want a crack first. */
- rl_attempted_completion_function = (CPPFunction *) pop_completion;
-
- read_history (get_history_file_name ());
-}
-
-void
-finish_readline ()
-{
- write_history (get_history_file_name());
-}
-
-/* Attempt to complete on the contents of TEXT. START and END bound the
- region of rl_line_buffer that contains the word to complete. TEXT is
- the word to complete. We can use the entire contents of rl_line_buffer
- in case we want to do some simple parsing. Return the array of matches,
- or NULL if there aren't any. */
-char **
-pop_completion (char *text, int start, int end MU_ARG_UNUSED)
-{
- char **matches;
-
- matches = (char **) NULL;
-
- /* If this word is at the start of the line, then it is a command
- to complete. Otherwise it is the name of a file in the current
- directory. */
- if (start == 0)
- matches = rl_completion_matches (text, command_generator);
-
- return (matches);
-}
-
-/* Generator function for command completion. STATE lets us know whether
- to start from scratch; without any state (i.e. STATE == 0), then we
- start at the top of the list. */
-char *
-command_generator (const char *text, int state)
-{
- static int list_index, len;
- const char *name;
-
- /* If this is a new word to complete, initialize now. This includes
- saving the length of TEXT for efficiency, and initializing the index
- variable to 0. */
- if (!state)
- {
- list_index = 0;
- len = strlen (text);
- }
-
- /* Return the next name which partially matches from the command list. */
- while ((name = commands[list_index].name))
- {
- list_index++;
-
- if (strncmp (name, text, len) == 0)
- return xstrdup (name);
- }
-
- /* If no names matched, then return NULL. */
- return NULL;
-}
-
-static char *pre_input_line;
-
-static int
-pre_input (void)
-{
- rl_insert_text (pre_input_line);
- free (pre_input_line);
- rl_pre_input_hook = NULL;
- rl_redisplay ();
- return 0;
-}
-
-static int
-retrieve_history (char *str)
-{
- char *out;
- int rc;
-
- rc = history_expand (str, &out);
- switch (rc)
- {
- case -1:
- mu_error ("%s", out);
- free (out);
- return 1;
-
- case 0:
- break;
-
- case 1:
- pre_input_line = out;
- rl_pre_input_hook = pre_input;
- return 1;
-
- case 2:
- printf ("%s\n", out);
- free (out);
- return 1;
- }
- return 0;
-}
-
-int
-com_history (int argc, char **argv)
-{
- int i;
- HIST_ENTRY **hlist;
-
- hlist = history_list ();
- for (i = 0; i < history_length; i++)
- printf ("%4d) %s\n", i + 1, hlist[i]->line);
-
- return 0;
-}
-
-#else
-# define initialize_readline()
-# define finish_readline()
-
-char *
-readline (char *prompt)
-{
- char buf[255];
-
- if (prompt)
- {
- printf ("%s", prompt);
- fflush (stdout);
- }
-
- if (!fgets (buf, sizeof (buf), stdin))
- return NULL;
- return xstrdup (buf);
-}
-
-void
-add_history (const char *s MU_ARG_UNUSED)
-{
-}
-#endif
-
-int
-get_bool (const char *str, int *pb)
-{
- if (mu_c_strcasecmp (str, "yes") == 0
- || mu_c_strcasecmp (str, "on") == 0
- || mu_c_strcasecmp (str, "true") == 0)
- *pb = 1;
- else if (mu_c_strcasecmp (str, "no") == 0
- || mu_c_strcasecmp (str, "off") == 0
- || mu_c_strcasecmp (str, "false") == 0)
- *pb = 0;
- else
- return 1;
-
- return 0;
-}
-
-int
-get_port (const char *port_str, int *pn)
-{
- short port_num;
- long num;
- char *p;
-
- num = port_num = strtol (port_str, &p, 0);
- if (*p == 0)
- {
- if (num != port_num)
- {
- mu_error ("bad port number: %s", port_str);
- return 1;
- }
- }
- else
- {
- struct servent *sp = getservbyname (port_str, "tcp");
- if (!sp)
- {
- mu_error ("unknown port name");
- return 1;
- }
- port_num = ntohs (sp->s_port);
- }
- *pn = port_num;
- return 0;
-}
-
-/* Parse and execute a command line. */
-int
-execute_line (char *line)
-{
- int argc;
- char **argv;
- int status = 0;
-
- if (mu_argcv_get (line, NULL, "#", &argc, &argv))
- {
- mu_error("cannot parse input line");
- return 0;
- }
-
- if (argc >= 0)
- {
- COMMAND *command = find_command (argv[0]);
-
- if (!command)
- mu_error ("%s: no such command.", argv[0]);
- else if (command->argmin > 0 && argc < command->argmin)
- mu_error ("%s: too few arguments", argv[0]);
- else if (command->argmax > 0 && argc > command->argmax)
- mu_error ("%s: too many arguments", argv[0]);
- else
- {
- if (command->argmin <= 0 && argc != 2)
- {
- char *word = mu_str_skip_class (line, MU_CTYPE_SPACE);
- char *arg = mu_str_skip_class_comp (word, MU_CTYPE_SPACE);
- if (*arg)
- {
- *arg++ = 0;
- arg = mu_str_skip_class (arg, MU_CTYPE_SPACE);
- }
-
- mu_argcv_free (argc, argv);
- argc = 2;
- argv = xcalloc (argc + 1, sizeof (argv[0]));
- argv[0] = xstrdup (word);
- argv[1] = xstrdup (arg);
- argv[2] = NULL;
- }
- status = command->func (argc, argv);
- }
- }
- mu_argcv_free (argc, argv);
- return status;
-}
-
-/* Look up NAME as the name of a command, and return a pointer to that
- command. Return a NULL pointer if NAME isn't a command name. */
-COMMAND *
-find_command (char *name)
-{
- COMMAND *cp;
-
- for (cp = commands; cp->name; cp++)
- if (strcmp (cp->name, name) == 0)
- return cp;
-
- return NULL;
-}
-
-static int
-string_to_xlev (const char *name, int *pv)
-{
- if (strcmp (name, "secure") == 0)
- *pv = MU_XSCRIPT_SECURE;
- else if (strcmp (name, "payload") == 0)
- *pv = MU_XSCRIPT_PAYLOAD;
- else
- return 1;
- return 0;
-}
-
-static int
-change_verbose_mask (int set, int argc, char **argv)
-{
- int i;
-
- for (i = 0; i < argc; i++)
- {
- int lev;
-
- if (string_to_xlev (argv[i], &lev))
- {
- mu_error ("unknown level: %s", argv[i]);
- return 1;
- }
- if (set)
- SET_VERBOSE_MASK (lev);
- else
- CLR_VERBOSE_MASK (lev);
- }
- return 0;
-}
-
-void
-set_verbose (mu_pop3_t p)
-{
- if (p)
- {
- if (QRY_VERBOSE ())
- {
- mu_pop3_trace (p, MU_POP3_TRACE_SET);
- }
- else
- mu_pop3_trace (p, MU_POP3_TRACE_CLR);
- }
-}
-
-void
-set_verbose_mask (mu_pop3_t p)
-{
- if (p)
- {
- mu_pop3_trace_mask (p, QRY_VERBOSE_MASK (MU_XSCRIPT_SECURE)
- ? MU_POP3_TRACE_SET : MU_POP3_TRACE_CLR,
- MU_XSCRIPT_SECURE);
- mu_pop3_trace_mask (p, QRY_VERBOSE_MASK (MU_XSCRIPT_PAYLOAD)
- ? MU_POP3_TRACE_SET : MU_POP3_TRACE_CLR,
- MU_XSCRIPT_PAYLOAD);
- }
-}
-
-int
-com_verbose (int argc, char **argv)
-{
- if (argc == 1)
- {
- if (QRY_VERBOSE ())
- {
- printf ("verbose is on");
- if (HAS_VERBOSE_MASK ())
- {
- char *delim = " (";
-
- if (QRY_VERBOSE_MASK (MU_XSCRIPT_SECURE))
- {
- printf("%ssecure", delim);
- delim = ", ";
- }
- if (QRY_VERBOSE_MASK (MU_XSCRIPT_PAYLOAD))
- printf("%spayload", delim);
- printf (")");
- }
- printf ("\n");
- }
- else
- printf ("verbose is off\n");
- }
- else
- {
- int bv;
-
- if (get_bool (argv[1], &bv) == 0)
- {
- verbose |= bv;
- if (argc > 2)
- change_verbose_mask (verbose, argc - 2, argv + 2);
- set_verbose (pop3);
- }
- else if (strcmp (argv[1], "mask") == 0)
- change_verbose_mask (1, argc - 2, argv + 2);
- else if (strcmp (argv[1], "unmask") == 0)
- change_verbose_mask (0, argc - 2, argv + 2);
- else
- mu_error ("unknown subcommand");
- set_verbose_mask (pop3);
- }
-
- return 0;
-}
-
-int
-com_user (int argc, char **argv)
-{
- int status;
-
- status = mu_pop3_user (pop3, argv[1]);
- if (status == 0)
- username = strdup (argv[1]);
- return status;
-}
-
-int
-com_apop (int argc, char **argv)
-{
- int status;
-
- status = mu_pop3_apop (pop3, argv[1], argv[2]);
- if (status == 0)
- {
- username = strdup (argv[1]);
- pop_session_status = pop_session_logged_in;
- }
- return status;
-}
-
-int
-com_capa (int argc, char **argv)
-{
- mu_iterator_t iterator = NULL;
- int status = 0;
- int reread = 0;
- int i = 1;
-
- for (i = 1; i < argc; i++)
- {
- if (strcmp (argv[i], "-reread") == 0)
- reread = 1;
- else
- break;
- }
-
- if (i < argc)
- {
- if (reread)
- {
- status = mu_pop3_capa (pop3, 1, NULL);
- if (status)
- return status;
- }
- for (; i < argc; i++)
- {
- const char *elt;
- int rc = mu_pop3_capa_test (pop3, argv[i], &elt);
- switch (rc)
- {
- case 0:
- if (*elt)
- printf ("%s: %s\n", argv[i], elt);
- else
- printf ("%s is set\n", argv[i]);
- break;
-
- case MU_ERR_NOENT:
- printf ("%s is not set\n", argv[i]);
- break;
-
- default:
- return rc;
- }
- }
- }
- else
- {
- status = mu_pop3_capa (pop3, reread, &iterator);
-
- if (status == 0)
- {
- for (mu_iterator_first (iterator);
- !mu_iterator_is_done (iterator); mu_iterator_next (iterator))
- {
- char *capa = NULL;
- mu_iterator_current (iterator, (void **) &capa);
- printf ("CAPA: %s\n", capa ? capa : "");
- }
- mu_iterator_destroy (&iterator);
- }
- }
- return status;
-}
-
-int
-com_uidl (int argc, char **argv)
-{
- int status = 0;
- if (argc == 1)
- {
- mu_iterator_t uidl_iterator = NULL;
- status = mu_pop3_uidl_all (pop3, &uidl_iterator);
- if (status == 0)
- {
- for (mu_iterator_first (uidl_iterator);
- !mu_iterator_is_done (uidl_iterator);
- mu_iterator_next (uidl_iterator))
- {
- char *uidl = NULL;
- mu_iterator_current (uidl_iterator, (void **) &uidl);
- printf ("UIDL: %s\n", uidl ? uidl : "");
- }
- mu_iterator_destroy (&uidl_iterator);
- }
- }
- else
- {
- char *uidl = NULL;
- unsigned int msgno = strtoul (argv[1], NULL, 10);
- status = mu_pop3_uidl (pop3, msgno, &uidl);
- if (status == 0)
- printf ("Msg: %d UIDL: %s\n", msgno, uidl ? uidl : "");
- free (uidl);
- }
- return status;
-}
-
-int
-com_list (int argc, char **argv)
-{
- int status = 0;
- if (argc == 1)
- {
- mu_iterator_t list_iterator;
- status = mu_pop3_list_all (pop3, &list_iterator);
- if (status == 0)
- {
- for (mu_iterator_first (list_iterator);
- !mu_iterator_is_done (list_iterator);
- mu_iterator_next (list_iterator))
- {
- char *list = NULL;
- mu_iterator_current (list_iterator, (void **) &list);
- printf ("LIST: %s\n", (list) ? list : "");
- }
- mu_iterator_destroy (&list_iterator);
- }
- }
- else
- {
- size_t size = 0;
- unsigned int msgno = strtoul (argv[1], NULL, 10);
- status = mu_pop3_list (pop3, msgno, &size);
- if (status == 0)
- printf ("Msg: %u Size: %lu\n", msgno, (unsigned long) size);
- }
- return status;
-}
-
-int
-com_noop (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
-{
- return mu_pop3_noop (pop3);
-}
-
-static void
-echo_off (struct termios *stored_settings)
-{
- struct termios new_settings;
- tcgetattr (0, stored_settings);
- new_settings = *stored_settings;
- new_settings.c_lflag &= (~ECHO);
- tcsetattr (0, TCSANOW, &new_settings);
-}
-
-static void
-echo_on (struct termios *stored_settings)
-{
- tcsetattr (0, TCSANOW, stored_settings);
-}
-
-int
-com_prompt (int argc, char **argv)
-{
- int quote;
- size_t size;
-
- free (prompt);
- size = mu_argcv_quoted_length (argv[1], &quote);
- prompt = malloc (size + 1);
- if (!prompt)
- {
- mu_error ("Memory exhausted");
- exit (1);
- }
- mu_argcv_unquote_copy (prompt, argv[1], size);
- return 0;
-}
-
-int
-com_pass (int argc, char **argv)
-{
- int status;
- char pass[256];
- char *pwd;
-
- if (argc == 1)
- {
- struct termios stored_settings;
-
- printf ("passwd:");
- fflush (stdout);
- echo_off (&stored_settings);
- fgets (pass, sizeof pass, stdin);
- echo_on (&stored_settings);
- putchar ('\n');
- fflush (stdout);
- pass[strlen (pass) - 1] = '\0'; /* nuke the trailing line. */
- pwd = pass;
- }
- else
- pwd = argv[1];
- status = mu_pop3_pass (pop3, pwd);
- if (status == 0)
- pop_session_status = pop_session_logged_in;
- return status;
-}
-
-int
-com_stat (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
-{
- size_t count = 0;
- mu_off_t size = 0;
- int status = 0;
-
- status = mu_pop3_stat (pop3, &count, &size);
- printf ("Mesgs: %lu Size %lu\n",
- (unsigned long) count, (unsigned long) size);
- return status;
-}
-
-int
-com_stls (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
-{
- return mu_pop3_stls (pop3);
-}
-
-int
-com_dele (int argc, char **argv)
-{
- unsigned msgno;
- msgno = strtoul (argv[1], NULL, 10);
- return mu_pop3_dele (pop3, msgno);
-}
-
-/* Print out help for ARG, or for all of the commands if ARG is
- not present. */
-int
-com_help (int argc, char **argv)
-{
- int i;
- int printed = 0;
- char *name = argv[1];
-
- for (i = 0; commands[i].name; i++)
- {
- if (!name || (strcmp (name, commands[i].name) == 0))
- {
- printf ("%s\t\t%s.\n", commands[i].name, commands[i].doc);
- printed++;
- }
- }
-
- if (!printed)
- {
- printf ("No commands match `%s'. Possibilties are:\n", name);
-
- for (i = 0; commands[i].name; i++)
- {
- /* Print in six columns. */
- if (printed == 6)
- {
- printed = 0;
- printf ("\n");
- }
-
- printf ("%s\t", commands[i].name);
- printed++;
- }
-
- if (printed)
- printf ("\n");
- }
- return 0;
-}
-
-int
-com_rset (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
-{
- return mu_pop3_rset (pop3);
-}
-
-int
-com_top (int argc, char **argv)
-{
- mu_stream_t stream;
- unsigned int msgno;
- unsigned int lines;
- int status;
-
- msgno = strtoul (argv[1], NULL, 10);
- if (argc == 3)
- lines = strtoul (argv[2], NULL, 10);
- else
- lines = 5;
-
- status = mu_pop3_top (pop3, msgno, lines, &stream);
-
- if (status == 0)
- {
- size_t n = 0;
- char buf[128];
- while ((mu_stream_readline (stream, buf, sizeof buf, &n) == 0) && n)
- printf ("%s", buf);
- mu_stream_destroy (&stream);
- }
- return status;
-}
-
-int
-com_retr (int argc, char **argv)
-{
- mu_stream_t stream;
- unsigned int msgno;
- int status;
-
- msgno = strtoul (argv[1], NULL, 10);
- status = mu_pop3_retr (pop3, msgno, &stream);
-
- if (status == 0)
- {
- size_t n = 0;
- char buf[128];
- while ((mu_stream_readline (stream, buf, sizeof buf, &n) == 0) && n)
- printf ("%s", buf);
- mu_stream_destroy (&stream);
- }
- return status;
-}
-
-int
-com_connect (int argc, char **argv)
-{
- int status;
- int n = 0;
- int tls = 0;
- int i = 1;
-
- for (i = 1; i < argc; i++)
- {
- if (strcmp (argv[i], "-tls") == 0)
- {
- if (WITH_TLS)
- tls = 1;
- else
- {
- mu_error ("TLS not supported");
- return 0;
- }
- }
- else
- break;
- }
-
- argc -= i;
- argv += i;
-
- if (argc >= 2)
- {
- if (get_port (argv[1], &n))
- return 0;
- }
- else if (tls)
- n = MU_POP3_DEFAULT_SSL_PORT;
- else
- n = MU_POP3_DEFAULT_PORT;
-
- if (pop_session_status != pop_session_disconnected)
- com_disconnect (0, NULL);
-
- status = mu_pop3_create (&pop3);
- if (status == 0)
- {
- mu_stream_t tcp;
-
- if (QRY_VERBOSE ())
- {
- set_verbose (pop3);
- set_verbose_mask (pop3);
- }
- status = mu_tcp_stream_create (&tcp, argv[0], n, MU_STREAM_READ);
- if (status == 0)
- {
-#ifdef WITH_TLS
- if (tls)
- {
- mu_stream_t tlsstream;
-
- status = mu_tls_client_stream_create (&tlsstream, tcp, tcp, 0);
- mu_stream_unref (tcp);
- if (status)
- {
- mu_error ("cannot create TLS stream: %s",
- mu_strerror (status));
- return 0;
- }
- tcp = tlsstream;
- }
-#endif
- mu_pop3_set_carrier (pop3, tcp);
- status = mu_pop3_connect (pop3);
- }
- else
- {
- mu_pop3_destroy (&pop3);
- pop3 = NULL;
- }
- }
-
- if (status)
- mu_error ("Failed to create pop3: %s", mu_strerror (status));
- else
- {
- connect_argc = argc;
- connect_argv = xcalloc (argc, sizeof (*connect_argv));
- for (i = 0; i < argc; i++)
- connect_argv[i] = xstrdup (argv[i]);
- connect_argv[i] = NULL;
- port = n;
- pop_session_status = pop_session_connected;
- }
-
- return status;
-}
-
-int
-com_disconnect (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
-{
- if (pop3)
- {
- mu_pop3_disconnect (pop3);
- mu_pop3_destroy (&pop3);
- pop3 = NULL;
-
- mu_argcv_free (connect_argc, connect_argv);
- connect_argc = 0;
- connect_argv = NULL;
- pop_session_status = pop_session_disconnected;
- }
- return 0;
-}
-
-int
-com_quit (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
-{
- int status = 0;
- if (pop3)
- {
- if (mu_pop3_quit (pop3) == 0)
- {
- status = com_disconnect (0, NULL);
- }
- else
- {
- printf ("Try 'exit' to leave %s\n", mu_program_name);
- }
- }
- else
- printf ("Try 'exit' to leave %s\n", mu_program_name);
- return status;
-}
-
-int
-com_exit (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
-{
- if (pop3)
- {
- mu_pop3_disconnect (pop3);
- mu_pop3_destroy (&pop3);
- }
- done = 1;
- return 0;
-}
-
-
-static char *
-input_line_interactive ()
-{
- char *p = expand_prompt ();
- char *line = readline (p);
- free (p);
- return line;
-}
-
-static char *
-input_line_script ()
-{
- size_t size = 0;
- char *buf = NULL;
- if (getline (&buf, &size, stdin) <= 0)
- return NULL;
- return buf;
-}
-
-int
-main (int argc MU_ARG_UNUSED, char **argv)
-{
- char *line, *s;
- int interactive = isatty (0);
- char *(*input_line) () = interactive ?
- input_line_interactive : input_line_script;
-
- mu_set_program_name (argv[0]);
- prompt = strdup (DEFAULT_PROMPT);
- if (interactive)
- initialize_readline (); /* Bind our completer. */
-
-#ifdef WITH_TLS
- mu_init_tls_libs ();
-#endif
- /* Loop reading and executing lines until the user quits. */
- while (!done)
- {
- line = input_line ();
- if (!line)
- break;
-
- /* Remove leading and trailing whitespace from the line.
- Then, if there is anything left, add it to the history list
- and execute it. */
- s = mu_str_stripws (line);
-
- if (*s)
- {
- int status;
-
-#ifdef WITH_READLINE
- if (interactive)
- {
- if (retrieve_history (s))
- continue;
- add_history (s);
- }
-#endif
-
- status = execute_line (s);
- if (status != 0)
- mu_error ("Error: %s", mu_strerror (status));
- }
-
- free (line);
- }
- if (interactive)
- finish_readline ();
- exit (0);
-}
-
diff --git a/imap4d/fetch.c b/imap4d/fetch.c
index d0475cf79..7f38e2980 100644
--- a/imap4d/fetch.c
+++ b/imap4d/fetch.c
@@ -162,12 +162,21 @@ fetch_send_header_address (mu_header_t header, const char *name,
fetch_send_address (defval);
}
+static void
+imap4d_ws_alloc_die (struct mu_wordsplit *wsp)
+{
+ imap4d_bye (ERR_NO_MEM);
+}
+
+#define IMAP4D_WS_FLAGS \
+ (MU_WRDSF_DEFFLAGS | MU_WRDSF_DELIM | \
+ MU_WRDSF_ENOMEMABRT | MU_WRDSF_ALLOC_DIE)
+
/* Send parameter list for the bodystructure. */
static void
send_parameter_list (const char *buffer)
{
- int argc = 0;
- char **argv;
+ struct mu_wordsplit ws;
if (!buffer)
{
@@ -175,9 +184,16 @@ send_parameter_list (const char *buffer)
return;
}
- mu_argcv_get (buffer, " \t\r\n;=", NULL, &argc, &argv);
+ ws.ws_delim = " \t\r\n;=";
+ ws.ws_alloc_die = imap4d_ws_alloc_die;
+ if (mu_wordsplit (buffer, &ws, IMAP4D_WS_FLAGS))
+ {
+ mu_error (_("%s failed: %s"), "mu_wordsplit",
+ mu_wordsplit_strerror (&ws));
+ return; /* FIXME: a better error handling, maybe? */
+ }
- if (argc == 0)
+ if (ws.ws_wordc == 0)
io_sendf ("NIL");
else
{
@@ -185,16 +201,16 @@ send_parameter_list (const char *buffer)
io_sendf ("(");
- p = argv[0];
+ p = ws.ws_wordv[0];
io_send_qstring (p);
- if (argc > 1)
+ if (ws.ws_wordc > 1)
{
int i, space = 0;
char *lvalue = NULL;
io_sendf ("(");
- for (i = 1; i < argc; i++)
+ for (i = 1; i < ws.ws_wordc; i++)
{
if (lvalue)
{
@@ -205,22 +221,21 @@ send_parameter_list (const char *buffer)
space = 1;
}
- switch (argv[i][0])
+ switch (ws.ws_wordv[i][0])
{
case ';':
continue;
case '=':
- if (++i < argc)
+ if (++i < ws.ws_wordc)
{
- char *p = argv[i];
io_sendf (" ");
- io_send_qstring (p);
+ io_send_qstring (ws.ws_wordv[i]);
}
break;
default:
- lvalue = argv[i];
+ lvalue = ws.ws_wordv[i];
}
}
if (lvalue)
@@ -235,7 +250,7 @@ send_parameter_list (const char *buffer)
io_sendf (" NIL");
io_sendf (")");
}
- mu_argcv_free (argc, argv);
+ mu_wordsplit_free (&ws);
}
static void
@@ -352,27 +367,33 @@ bodystructure (mu_message_t msg, int extension)
if (mu_header_aget_value (header, MU_HEADER_CONTENT_TYPE, &buffer) == 0)
{
- int argc = 0;
- char **argv;
+ struct mu_wordsplit ws;
char *s, *p;
- mu_argcv_get (buffer, " \t\r\n;=", NULL, &argc, &argv);
+ ws.ws_delim = " \t\r\n;=";
+ ws.ws_alloc_die = imap4d_ws_alloc_die;
+ if (mu_wordsplit (buffer, &ws, IMAP4D_WS_FLAGS))
+ {
+ mu_error (_("%s failed: %s"), "mu_wordsplit",
+ mu_wordsplit_strerror (&ws));
+ return RESP_BAD; /* FIXME: a better error handling, maybe? */
+ }
- if (mu_c_strcasecmp (argv[0], "MESSAGE/RFC822") == 0)
+ if (mu_c_strcasecmp (ws.ws_wordv[0], "MESSAGE/RFC822") == 0)
message_rfc822 = 1;
- else if (mu_c_strcasecmp (argv[0], "TEXT/PLAIN") == 0)
+ else if (mu_c_strcasecmp (ws.ws_wordv[0], "TEXT/PLAIN") == 0)
text_plain = 1;
- s = strchr (argv[0], '/');
+ s = strchr (ws.ws_wordv[0], '/');
if (s)
*s++ = 0;
- p = argv[0];
+ p = ws.ws_wordv[0];
io_send_qstring (p);
io_sendf (" ");
io_send_qstring (s);
/* body parameter parenthesized list: Content-type attributes */
- if (argc > 1 || text_plain)
+ if (ws.ws_wordc > 1 || text_plain)
{
int space = 0;
char *lvalue = NULL;
@@ -380,7 +401,7 @@ bodystructure (mu_message_t msg, int extension)
int i;
io_sendf (" (");
- for (i = 1; i < argc; i++)
+ for (i = 1; i < ws.ws_wordc; i++)
{
/* body parameter parenthesized list:
Content-type parameter list. */
@@ -393,25 +414,23 @@ bodystructure (mu_message_t msg, int extension)
space = 1;
}
- switch (argv[i][0])
+ switch (ws.ws_wordv[i][0])
{
case ';':
continue;
case '=':
- if (++i < argc)
+ if (++i < ws.ws_wordc)
{
- char *p = argv[i];
io_sendf (" ");
- io_send_qstring (p);
+ io_send_qstring (ws.ws_wordv[i]);
}
break;
default:
- lvalue = argv[i];
+ lvalue = ws.ws_wordv[i];
if (mu_c_strcasecmp (lvalue, "charset") == 0)
have_charset = 1;
-
}
}
@@ -432,7 +451,7 @@ bodystructure (mu_message_t msg, int extension)
}
else
io_sendf (" NIL");
- mu_argcv_free (argc, argv);
+ mu_wordsplit_free (&ws);
free (buffer);
}
else
@@ -553,13 +572,19 @@ fetch_bodystructure0 (mu_message_t message, int extension)
/* The subtype. */
if (mu_header_aget_value (header, MU_HEADER_CONTENT_TYPE, &buffer) == 0)
{
- int argc = 0;
- char **argv;
+ struct mu_wordsplit ws;
char *s;
-
- mu_argcv_get (buffer, " \t\r\n;=", NULL, &argc, &argv);
- s = strchr (argv[0], '/');
+ ws.ws_delim = " \t\r\n;=";
+ ws.ws_alloc_die = imap4d_ws_alloc_die;
+ if (mu_wordsplit (buffer, &ws, IMAP4D_WS_FLAGS))
+ {
+ mu_error (_("%s failed: %s"), "mu_wordsplit",
+ mu_wordsplit_strerror (&ws));
+ return RESP_BAD; /* FIXME: a better error handling, maybe? */
+ }
+
+ s = strchr (ws.ws_wordv[0], '/');
if (s)
s++;
io_sendf (" ");
@@ -572,7 +597,7 @@ fetch_bodystructure0 (mu_message_t message, int extension)
char *lvalue = NULL;
io_sendf (" (");
- for (i = 1; i < argc; i++)
+ for (i = 1; i < ws.ws_wordc; i++)
{
/* body parameter parenthesized list:
Content-type parameter list. */
@@ -585,22 +610,21 @@ fetch_bodystructure0 (mu_message_t message, int extension)
space = 1;
}
- switch (argv[i][0])
+ switch (ws.ws_wordv[i][0])
{
case ';':
continue;
case '=':
- if (++i < argc)
+ if (++i < ws.ws_wordc)
{
- char *p = argv[i];
io_sendf (" ");
- io_send_qstring (p);
+ io_send_qstring (ws.ws_wordv[i]);
}
break;
default:
- lvalue = argv[i];
+ lvalue = ws.ws_wordv[i];
}
}
if (lvalue)
@@ -613,7 +637,7 @@ fetch_bodystructure0 (mu_message_t message, int extension)
}
else
io_sendf (" NIL");
- mu_argcv_free (argc, argv);
+ mu_wordsplit_free (&ws);
free (buffer);
}
else
diff --git a/imap4d/imap4d.h b/imap4d/imap4d.h
index 21d3b7221..26e9fc323 100644
--- a/imap4d/imap4d.h
+++ b/imap4d/imap4d.h
@@ -98,7 +98,7 @@
#include <mailutils/pam.h>
#include <mailutils/acl.h>
#include <mailutils/server.h>
-#include <mailutils/argcv.h>
+#include <mailutils/wordsplit.h>
#include <mailutils/alloc.h>
#include <mailutils/vartab.h>
#include <mailutils/cctype.h>
diff --git a/include/mailutils/Makefile.am b/include/mailutils/Makefile.am
index 6f0a67fb2..787d04e2c 100644
--- a/include/mailutils/Makefile.am
+++ b/include/mailutils/Makefile.am
@@ -94,7 +94,8 @@ pkginclude_HEADERS = \
tls.h\
url.h\
vartab.h\
- version.h
+ version.h\
+ wordsplit.h
if MU_COND_SUPPORT_CXX
CPP_DIR = cpp
diff --git a/include/mailutils/argcv.h b/include/mailutils/argcv.h
index dd9482fe3..49d3bfa2d 100644
--- a/include/mailutils/argcv.h
+++ b/include/mailutils/argcv.h
@@ -28,31 +28,51 @@
extern "C" {
#endif
-#define MU_ARGCV_RETURN_DELIMS 0x01
+void mu_argcv_free (size_t argc, char **argv);
+void mu_argv_free (char **argv);
+
+enum mu_argcv_escape
+ {
+ mu_argcv_escape_no,
+ mu_argcv_escape_c
+ /* mu_argcv_escape_sh */
+ };
+int mu_argcv_join (int argc, char **argv, char *delim,
+ enum mu_argcv_escape esc,
+ char **pstring);
+int mu_argcv_string (int argc, char **argv, char **string);
+
+void mu_argcv_remove (int *pargc, char ***pargv,
+ int (*sel) (const char *, void *), void *);
-extern int mu_argcv_get (const char *command, const char *delim,
- const char *cmnt,
- int *argc, char ***argv);
-extern int mu_argcv_get_n (const char *command, int len,
- const char *delim, const char *cmnt,
- int *argc, char ***argv);
-extern int mu_argcv_get_np (const char *command, int len,
- const char *delim, const char *cmnt,
- int flags,
- int *pargc, char ***pargv, char **endp);
+/* Deprecated interfaces */
+#define MU_ARGCV_RETURN_DELIMS 0x01
+
+#ifndef MU_ARCGV_DEPRECATED
+# define MU_ARCGV_DEPRECATED __attribute__((deprecated))
+#endif
-extern int mu_argcv_string (int argc, char **argv, char **string);
-extern void mu_argcv_free (int argc, char **argv);
-extern void mu_argv_free (char **argv);
-
-extern int mu_argcv_unquote_char (int c);
-extern int mu_argcv_quote_char (int c);
-extern size_t mu_argcv_quoted_length (const char *str, int *quote);
-extern void mu_argcv_unquote_copy (char *dst, const char *src, size_t n);
-extern void mu_argcv_quote_copy (char *dst, const char *src);
-extern void mu_argcv_remove (int *pargc, char ***pargv,
- int (*sel) (const char *, void *), void *);
+int mu_argcv_get (const char *command, const char *delim,
+ const char *cmnt,
+ int *argc, char ***argv) MU_ARCGV_DEPRECATED;
+int mu_argcv_get_n (const char *command, int len,
+ const char *delim, const char *cmnt,
+ int *argc, char ***argv) MU_ARCGV_DEPRECATED;
+int mu_argcv_get_np (const char *command, int len,
+ const char *delim, const char *cmnt,
+ int flags,
+ int *pargc, char ***pargv, char **endp)
+ MU_ARCGV_DEPRECATED;
+int mu_argcv_unquote_char (int c) MU_ARCGV_DEPRECATED;
+int mu_argcv_quote_char (int c) MU_ARCGV_DEPRECATED;
+size_t mu_argcv_quoted_length (const char *str, int *quote)
+ MU_ARCGV_DEPRECATED;
+void mu_argcv_unquote_copy (char *dst, const char *src, size_t n)
+ MU_ARCGV_DEPRECATED;
+void mu_argcv_quote_copy (char *dst, const char *src)
+ MU_ARCGV_DEPRECATED;
+
#ifdef __cplusplus
}
#endif
diff --git a/include/mailutils/mailutils.h b/include/mailutils/mailutils.h
index cad14b6b9..cec169fbb 100644
--- a/include/mailutils/mailutils.h
+++ b/include/mailutils/mailutils.h
@@ -64,5 +64,6 @@
#include <mailutils/secret.h>
#include <mailutils/cctype.h>
#include <mailutils/cstr.h>
+#include <mailutils/wordsplit.h>
/* EOF */
diff --git a/include/mailutils/wordsplit.h b/include/mailutils/wordsplit.h
new file mode 100644
index 000000000..13edb2514
--- /dev/null
+++ b/include/mailutils/wordsplit.h
@@ -0,0 +1,135 @@
+/* wordsplit - a word splitter
+ Copyright (C) 2009, 2010 Sergey Poznyakoff
+
+ 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 of the License, 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.
+
+ You should have received a copy of the GNU General Public License along
+ with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef __MAILUTILS_WORDSPLIT_H
+#define __MAILUTILS_WORDSPLIT_H
+
+#include <stddef.h>
+
+struct mu_wordsplit
+{
+ size_t ws_wordc;
+ char **ws_wordv;
+ size_t ws_offs;
+ size_t ws_wordn;
+ int ws_flags;
+ const char *ws_delim;
+ const char *ws_comment;
+ void (*ws_alloc_die) (struct mu_wordsplit *wsp);
+ void (*ws_error) (const char *, ...)
+ __attribute__ ((__format__ (__printf__, 1, 2)));
+ void (*ws_debug) (const char *, ...)
+ __attribute__ ((__format__ (__printf__, 1, 2)));
+
+ const char **ws_env;
+ char *(*ws_getvar) (const char *, size_t);
+
+ const char *ws_input;
+ size_t ws_len;
+ size_t ws_endp;
+ int ws_errno;
+ struct mu_wordsplit_node *ws_head, *ws_tail;
+};
+
+/* Append the words found to the array resulting from a previous
+ call. */
+#define MU_WRDSF_APPEND 0x0000001
+/* Insert we_offs initial NULLs in the array ws_wordv.
+ (These are not counted in the returned ws_wordc.) */
+#define MU_WRDSF_DOOFFS 0x0000002
+/* Don't do command substitution. Reserved for future use. */
+#define MU_WRDSF_NOCMD 0x0000004
+/* The parameter p resulted from a previous call to
+ mu_wordsplit(), and mu_wordsplit_free() was not called. Reuse the
+ allocated storage. */
+#define MU_WRDSF_REUSE 0x0000008
+/* Print errors */
+#define MU_WRDSF_SHOWERR 0x0000010
+/* Consider it an error if an undefined shell variable
+ is expanded. */
+#define MU_WRDSF_UNDEF 0x0000020
+
+/* Don't do variable expansion. */
+#define MU_WRDSF_NOVAR 0x0000040
+/* Abort on ENOMEM error */
+#define MU_WRDSF_ENOMEMABRT 0x0000080
+/* Trim off any leading and trailind whitespace */
+#define MU_WRDSF_WS 0x0000100
+/* Handle quotes and escape directives */
+#define MU_WRDSF_QUOTE 0x0000200
+/* Replace each input sequence of repeated delimiters with a single
+ delimiter */
+#define MU_WRDSF_SQUEEZE_DELIMS 0x0000400
+/* Return delimiters */
+#define MU_WRDSF_RETURN_DELIMS 0x0000800
+/* Treat sed expressions as words */
+#define MU_WRDSF_SED_EXPR 0x0001000
+/* ws_delim field is initialized */
+#define MU_WRDSF_DELIM 0x0002000
+/* ws_comment field is initialized */
+#define MU_WRDSF_COMMENT 0x0004000
+/* ws_alloc_die field is initialized */
+#define MU_WRDSF_ALLOC_DIE 0x0008000
+/* ws_error field is initialized */
+#define MU_WRDSF_ERROR 0x0010000
+/* ws_debug field is initialized */
+#define MU_WRDSF_DEBUG 0x0020000
+/* ws_env field is initialized */
+#define MU_WRDSF_ENV 0x0040000
+/* ws_getvar field is initialized */
+#define MU_WRDSF_GETVAR 0x0080000
+/* enable debugging */
+#define MU_WRDSF_SHOWDBG 0x0100000
+/* Don't split input into words. Useful for side effects. */
+#define MU_WRDSF_NOSPLIT 0x0200000
+/* Keep undefined variables in place, instead of expanding them to
+ empty string */
+#define MU_WRDSF_KEEPUNDEF 0x0400000
+/* Warn about undefined variables */
+#define MU_WRDSF_WARNUNDEF 0x0800000
+/* Handle C escapes */
+#define MU_WRDSF_CESCAPES 0x1000000
+
+#define MU_WRDSF_DEFFLAGS \
+ (MU_WRDSF_NOVAR | MU_WRDSF_NOCMD | \
+ MU_WRDSF_QUOTE | MU_WRDSF_SQUEEZE_DELIMS | MU_WRDSF_CESCAPES)
+
+#define MU_WRDSE_EOF 0
+#define MU_WRDSE_QUOTE 1
+#define MU_WRDSE_NOSPACE 2
+#define MU_WRDSE_NOSUPP 3
+#define MU_WRDSE_USAGE 4
+#define MU_WRDSE_CBRACE 5
+#define MU_WRDSE_UNDEF 6
+
+int mu_wordsplit (const char *s, struct mu_wordsplit *p, int flags);
+int mu_wordsplit_len (const char *s, size_t len,
+ struct mu_wordsplit *p, int flags);
+void mu_wordsplit_free (struct mu_wordsplit *p);
+
+int mu_wordsplit_c_unquote_char (int c);
+int mu_wordsplit_c_quote_char (int c);
+size_t mu_wordsplit_c_quoted_length (const char *str, int quote_hex,
+ int *quote);
+void mu_wordsplit_sh_unquote_copy (char *dst, const char *src, size_t n);
+void mu_wordsplit_c_unquote_copy (char *dst, const char *src, size_t n);
+void mu_wordsplit_c_quote_copy (char *dst, const char *src, int quote_hex);
+
+void mu_wordsplit_perror (struct mu_wordsplit *ws);
+const char *mu_wordsplit_strerror (struct mu_wordsplit *ws);
+
+
+#endif
diff --git a/lib/mailcap.c b/lib/mailcap.c
index fc2c3ec0c..c0396d200 100644
--- a/lib/mailcap.c
+++ b/lib/mailcap.c
@@ -414,21 +414,31 @@ create_filter (char *cmd, int outfd, int *infd)
if (pid == 0)
{
/* Child process */
+ struct mu_wordsplit ws;
int argc;
char **argv;
-
+
if (need_shell_p (cmd))
{
+ char *x_argv[4];
argc = 3;
- argv = xmalloc ((argc + 1) * sizeof *argv);
+ argv = x_argv;
argv[0] = getenv ("SHELL");
argv[1] = "-c";
argv[2] = cmd;
argv[3] = NULL;
}
else
- mu_argcv_get (cmd, "", NULL, &argc, &argv);
-
+ {
+ if (mu_wordsplit (cmd, &ws, MU_WRDSF_DEFFLAGS))
+ {
+ mu_error (_("%s failed: %s"), "mu_wordsplit",
+ mu_wordsplit_strerror (&ws));
+ _exit (127);
+ }
+ argc = ws.ws_wordc;
+ argv = ws.ws_wordv;
+ }
/* Create input channel: */
if (infd)
{
@@ -440,7 +450,7 @@ create_filter (char *cmd, int outfd, int *infd)
/* Create output channel */
if (outfd != -1 && outfd != 1)
dup2 (outfd, 1);
-
+
execvp (argv[0], argv);
mu_error (_("cannot execute `%s': %s"), cmd, mu_strerror (errno));
_exit (127);
@@ -491,8 +501,7 @@ run_test (mu_mailcap_entry_t entry, struct mime_context *ctx)
if (mu_mailcap_entry_get_test (entry, NULL, 0, &size) == 0)
{
- int argc;
- char **argv;
+ struct mu_wordsplit ws;
char *str;
obstack_blank (&expand_stack, size + 1);
@@ -500,11 +509,16 @@ run_test (mu_mailcap_entry_t entry, struct mime_context *ctx)
mu_mailcap_entry_get_test (entry, str, size + 1, NULL);
expand_string (ctx, &str);
- mu_argcv_get (str, "", NULL, &argc, &argv);
+ if (mu_wordsplit (str, &ws, MU_WRDSF_DEFFLAGS))
+ {
+ mu_error (_("%s failed: %s"), "mu_wordsplit",
+ mu_wordsplit_strerror (&ws));
+ return 1;
+ }
- if (mu_spawnvp (argv[0], argv, &status))
+ if (mu_spawnvp (ws.ws_wordv[0], ws.ws_wordv, &status))
status = 1;
- mu_argcv_free (argc, argv);
+ mu_wordsplit_free (&ws);
}
return status;
}
diff --git a/libmailutils/auth/mu_auth.c b/libmailutils/auth/mu_auth.c
index f9f33ca98..f4ea60e11 100644
--- a/libmailutils/auth/mu_auth.c
+++ b/libmailutils/auth/mu_auth.c
@@ -40,7 +40,7 @@
# include <crypt.h>
#endif
-#include <mailutils/argcv.h>
+#include <mailutils/wordsplit.h>
#include <mailutils/list.h>
#include <mailutils/iterator.h>
#include <mailutils/mailbox.h>
@@ -376,32 +376,32 @@ _locate (const char *name)
static void
_add_module_list (const char *modlist, int (*fun)(const char *name))
{
- int argc;
- char **argv;
- int rc, i;
-
- rc = mu_argcv_get (modlist, ":", NULL, &argc, &argv);
- if (rc)
+ struct mu_wordsplit ws;
+ int i;
+
+ ws.ws_delim = ":";
+ if (mu_wordsplit (modlist, &ws, MU_WRDSF_DEFFLAGS|MU_WRDSF_DELIM))
{
- mu_error (_("cannot split line `%s': %s"), modlist, mu_strerror (rc));
+ mu_error (_("cannot split line `%s': %s"), modlist,
+ mu_wordsplit_strerror (&ws));
exit (1);
}
- for (i = 0; i < argc; i += 2)
+ for (i = 0; i < ws.ws_wordc; i++)
{
- if (fun (argv[i]))
+ if (fun (ws.ws_wordv[i]))
{
/* Historically,auth functions used ENOENT. We support this
return value for backward compatibility. */
if (errno == ENOENT || errno == MU_ERR_NOENT)
- mu_error (_("no such module: %s"), argv[i]);
+ mu_error (_("no such module: %s"), ws.ws_wordv[i]);
else
mu_error (_("failed to add module %s: %s"),
- argv[i], strerror (errno));
+ ws.ws_wordv[i], strerror (errno));
exit (1);
}
}
- mu_argcv_free (argc, argv);
+ mu_wordsplit_free (&ws);
}
diff --git a/libmailutils/base/Makefile.am b/libmailutils/base/Makefile.am
index c51c947be..b4f208ed7 100644
--- a/libmailutils/base/Makefile.am
+++ b/libmailutils/base/Makefile.am
@@ -21,6 +21,9 @@ libbase_la_SOURCES = \
alloc.c\
amd.c\
argcv.c\
+ argcvfree.c\
+ argcvjoin.c\
+ argcvrem.c\
assoc.c\
daemon.c\
date.c\
diff --git a/libmailutils/base/argcv.c b/libmailutils/base/argcv.c
index 6e63b23f4..142de6b6a 100644
--- a/libmailutils/base/argcv.c
+++ b/libmailutils/base/argcv.c
@@ -22,15 +22,13 @@
#include <ctype.h>
#include <errno.h>
+#define MU_ARCGV_DEPRECATED
#include <mailutils/argcv.h>
/* Keep mailutils namespace clean */
#define argcv_get mu_argcv_get
#define argcv_get_n mu_argcv_get_n
#define argcv_get_np mu_argcv_get_np
-#define argcv_string mu_argcv_string
-#define argcv_free mu_argcv_free
-#define argv_free mu_argv_free
#define argcv_unquote_char mu_argcv_unquote_char
#define argcv_quote_char mu_argcv_quote_char
#define argcv_quoted_length mu_argcv_quoted_length
@@ -404,7 +402,7 @@ argcv_get_np (const char *command, int len,
argv[i] = calloc (n + 1, sizeof (char));
if (argv[i] == NULL)
{
- argcv_free (i, argv);
+ mu_argcv_free (i, argv);
return ENOMEM;
}
if (unquote)
@@ -438,111 +436,5 @@ argcv_get (const char *command, const char *delim, const char *cmnt,
}
-/*
- * frees all elements of an argv array
- * argc is the number of elements
- * argv is the array
- */
-void
-argcv_free (int argc, char **argv)
-{
- if (argc <= 0)
- return;
- while (--argc >= 0)
- if (argv[argc])
- free (argv[argc]);
- free (argv);
-}
-
-void
-argv_free (char **argv)
-{
- int i;
-
- for (i = 0; argv[i]; i++)
- free (argv[i]);
- free (argv);
-}
-
-/* Make a argv an make string separated by ' '. */
-
-int
-argcv_string (int argc, char **argv, char **pstring)
-{
- size_t i, j, len;
- char *buffer;
-
- /* No need. */
- if (pstring == NULL)
- return EINVAL;
-
- buffer = malloc (1);
- if (buffer == NULL)
- return ENOMEM;
- *buffer = '\0';
-
- for (len = i = j = 0; i < argc; i++)
- {
- int quote;
- int toklen;
-
- toklen = argcv_quoted_length (argv[i], &quote);
-
- len += toklen + 2;
- if (quote)
- len += 2;
-
- buffer = realloc (buffer, len);
- if (buffer == NULL)
- return ENOMEM;
-
- if (i != 0)
- buffer[j++] = ' ';
- if (quote)
- buffer[j++] = '"';
- argcv_quote_copy (buffer + j, argv[i]);
- j += toklen;
- if (quote)
- buffer[j++] = '"';
- }
-
- for (; j > 0 && isspace (buffer[j-1]); j--)
- ;
- buffer[j] = 0;
- if (pstring)
- *pstring = buffer;
- return 0;
-}
-
-void
-mu_argcv_remove (int *pargc, char ***pargv,
- int (*sel) (const char *, void *), void *data)
-{
- int i, j;
- int argc = *pargc;
- char **argv = *pargv;
- int cnt = 0;
-
- for (i = j = 0; i < argc; i++)
- {
- if (sel (argv[i], data))
- {
- free (argv[i]);
- cnt++;
- }
- else
- {
- if (i != j)
- argv[j] = argv[i];
- j++;
- }
- }
- if (i != j)
- argv[j] = NULL;
- argc -= cnt;
-
- *pargc = argc;
- *pargv = argv;
-}
diff --git a/libmailutils/base/argcvfree.c b/libmailutils/base/argcvfree.c
new file mode 100644
index 000000000..737d67db8
--- /dev/null
+++ b/libmailutils/base/argcvfree.c
@@ -0,0 +1,51 @@
+/* Free an array of string pointers.
+ Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2010 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/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <stdlib.h>
+#include <mailutils/types.h>
+#include <mailutils/argcv.h>
+
+/*
+ * frees all elements of an argv array
+ * argc is the number of elements
+ * argv is the array
+ */
+void
+mu_argcv_free (size_t argc, char **argv)
+{
+ size_t i;
+
+ for (i = 0; i < argc; i++)
+ if (argv[i])
+ free (argv[i]);
+ free (argv);
+}
+
+void
+mu_argv_free (char **argv)
+{
+ int i;
+
+ for (i = 0; argv[i]; i++)
+ free (argv[i]);
+ free (argv);
+}
+
diff --git a/libmailutils/base/argcvjoin.c b/libmailutils/base/argcvjoin.c
new file mode 100644
index 000000000..a5877e823
--- /dev/null
+++ b/libmailutils/base/argcvjoin.c
@@ -0,0 +1,116 @@
+/* Join strings from an array into a single string.
+ Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2010 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/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <stdlib.h>
+#include <mailutils/types.h>
+#include <mailutils/argcv.h>
+#include <mailutils/errno.h>
+#include <mailutils/wordsplit.h>
+
+int
+mu_argcv_join (int argc, char **argv, char *delim, enum mu_argcv_escape esc,
+ char **pstring)
+{
+ size_t i, j, len;
+ char *buffer;
+ size_t delimlen = strlen (delim);
+ int quote_hex = 0;
+
+ if (pstring == NULL)
+ return EINVAL;
+
+ buffer = malloc (1);
+ if (buffer == NULL)
+ return ENOMEM;
+ *buffer = '\0';
+
+ for (len = i = j = 0; i < argc; i++)
+ {
+ int quote;
+ int toklen;
+
+ switch (esc)
+ {
+ case mu_argcv_escape_no:
+ toklen = strlen (argv[i]);
+ quote = 0;
+ break;
+
+ case mu_argcv_escape_c:
+ toklen = mu_wordsplit_c_quoted_length (argv[i], quote_hex, &quote);
+ break;
+
+#if 0
+ case mu_argcv_escape_sh:
+ FIXME
+ toklen = mu_wordsplit_sh_quoted_length (argv[i], &quote);
+ break;
+#endif
+ default:
+ return EINVAL;
+ }
+
+ len += toklen + delimlen;
+ if (quote)
+ len += 2;
+
+ buffer = realloc (buffer, len);
+ if (buffer == NULL)
+ return ENOMEM;
+
+ if (i != 0)
+ {
+ memcpy (buffer + j, delim, delimlen);
+ j += delimlen;
+ }
+ if (quote)
+ buffer[j++] = '"';
+
+ switch (esc)
+ {
+ case mu_argcv_escape_no:
+ memcpy (buffer + j, argv[i], toklen);
+ break;
+
+ case mu_argcv_escape_c:
+ mu_wordsplit_c_quote_copy (buffer + j, argv[i], quote_hex);
+ break;
+#if 0
+ case mu_argcv_escape_sh:
+ mu_wordsplit_sh_quote_copy (buffer + j, argv[i]);
+#endif
+ }
+
+ j += toklen;
+ if (quote)
+ buffer[j++] = '"';
+ }
+
+ buffer[j] = 0;
+ *pstring = buffer;
+ return 0;
+}
+
+int
+mu_argcv_string (int argc, char **argv, char **pstring)
+{
+ return mu_argcv_join (argc, argv, " ", mu_argcv_escape_c, pstring);
+}
diff --git a/libmailutils/base/argcvrem.c b/libmailutils/base/argcvrem.c
new file mode 100644
index 000000000..d6e994dea
--- /dev/null
+++ b/libmailutils/base/argcvrem.c
@@ -0,0 +1,55 @@
+/* Selectively remove elements from an array of string pointers.
+ Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2010 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/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <stdlib.h>
+#include <mailutils/types.h>
+#include <mailutils/argcv.h>
+
+void
+mu_argcv_remove (int *pargc, char ***pargv,
+ int (*sel) (const char *, void *), void *data)
+{
+ int i, j;
+ int argc = *pargc;
+ char **argv = *pargv;
+ int cnt = 0;
+
+ for (i = j = 0; i < argc; i++)
+ {
+ if (sel (argv[i], data))
+ {
+ free (argv[i]);
+ cnt++;
+ }
+ else
+ {
+ if (i != j)
+ argv[j] = argv[i];
+ j++;
+ }
+ }
+ if (i != j)
+ argv[j] = NULL;
+ argc -= cnt;
+
+ *pargc = argc;
+ *pargv = argv;
+}
diff --git a/libmailutils/base/mutil.c b/libmailutils/base/mutil.c
index ffa04dd6a..11232cfbe 100644
--- a/libmailutils/base/mutil.c
+++ b/libmailutils/base/mutil.c
@@ -22,8 +22,9 @@
#include <sys/types.h>
#include <sys/stat.h>
+#include <stdlib.h>
#include <time.h>
-#include <mailutils/argcv.h>
+#include <mailutils/wordsplit.h>
#include <mailutils/error.h>
#include <mailutils/errno.h>
#include <mailutils/nls.h>
@@ -78,20 +79,20 @@ mutil_parse_field_map (const char *map, mu_assoc_t *passoc_tab, int *perr)
{
int rc;
int i;
- int argc;
- char **argv;
+ struct mu_wordsplit ws;
mu_assoc_t assoc_tab = NULL;
- rc = mu_argcv_get (map, ":", NULL, &argc, &argv);
- if (rc)
+ ws.ws_delim = ":";
+ if (mu_wordsplit (map, &ws, MU_WRDSF_DEFFLAGS|MU_WRDSF_DELIM))
{
- mu_error (_("cannot split line `%s': %s"), map, mu_strerror (rc));
+ mu_error (_("cannot split line `%s': %s"), map,
+ mu_wordsplit_strerror (&ws));
return rc;
}
- for (i = 0; i < argc; i += 2)
+ for (i = 0; i < ws.ws_wordc; i++)
{
- char *tok = argv[i];
+ char *tok = ws.ws_wordv[i];
char *p = strchr (tok, '=');
char *pptr;
@@ -123,7 +124,7 @@ mutil_parse_field_map (const char *map, mu_assoc_t *passoc_tab, int *perr)
}
}
- mu_argcv_free (argc, argv);
+ mu_wordsplit_free (&ws);
if (rc && perr)
*perr = i;
return rc;
diff --git a/libmailutils/cfg/format.c b/libmailutils/cfg/format.c
index e7aaa7b2c..1d75b3b52 100644
--- a/libmailutils/cfg/format.c
+++ b/libmailutils/cfg/format.c
@@ -18,11 +18,12 @@
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
+#include <stdlib.h>
#include <mailutils/alloc.h>
#include <mailutils/stream.h>
#include <mailutils/error.h>
#include <mailutils/cfg.h>
-#include <mailutils/argcv.h>
+#include <mailutils/wordsplit.h>
#include <mailutils/nls.h>
#include <mailutils/iterator.h>
#include <ctype.h>
@@ -50,7 +51,7 @@ format_string_value (struct tree_print *tp, const char *str)
int quote;
char *p;
- size = mu_argcv_quoted_length (str, &quote);
+ size = mu_wordsplit_c_quoted_length (str, 1, &quote);
if (quote)
size += 2;
size++;
@@ -69,7 +70,7 @@ format_string_value (struct tree_print *tp, const char *str)
p++;
}
tp->buf[size-1] = 0;
- mu_argcv_quote_copy (p, str);
+ mu_wordsplit_c_quote_copy (p, str, 1);
mu_stream_write (tp->stream, tp->buf, size - 1, NULL);
}
diff --git a/libmailutils/cfg/lexer.l b/libmailutils/cfg/lexer.l
index 67c119947..52be3901f 100644
--- a/libmailutils/cfg/lexer.l
+++ b/libmailutils/cfg/lexer.l
@@ -32,7 +32,7 @@
#include <mailutils/errno.h>
#include <mailutils/error.h>
#include <mailutils/debug.h>
-#include <mailutils/argcv.h>
+#include <mailutils/wordsplit.h>
#include <mailutils/alloc.h>
#include <mailutils/nls.h>
#include <mailutils/cfg.h>
@@ -172,7 +172,7 @@ unescape_to_line (int c)
{
if (c != '\n')
{
- char t = mu_argcv_unquote_char (c);
+ char t = mu_wordsplit_c_unquote_char (c);
if (t == c && t != '\\' && t != '\"')
mu_cfg_parse_error (_("unknown escape sequence '\\%c'"), c);
mu_opool_append_char (pool, t);
diff --git a/libmailutils/cfg/parser.y b/libmailutils/cfg/parser.y
index 9fe5b1b2f..cc77fb96f 100644
--- a/libmailutils/cfg/parser.y
+++ b/libmailutils/cfg/parser.y
@@ -27,6 +27,7 @@
#include <netdb.h>
#include "intprops.h"
#include <mailutils/argcv.h>
+#include <mailutils/wordsplit.h>
#include <mailutils/nls.h>
#include <mailutils/cfg.h>
#include <mailutils/alloc.h>
@@ -1579,7 +1580,6 @@ mu_cfg_value_eq (mu_config_value_t *a, mu_config_value_t *b)
static int
split_cfg_path (const char *path, int *pargc, char ***pargv)
{
- int rc;
int argc;
char **argv;
char *delim = MU_CFG_PATH_DELIM_STR;
@@ -1598,25 +1598,36 @@ split_cfg_path (const char *path, int *pargc, char ***pargv)
}
argv[1] = NULL;
argc = 1;
- rc = 0;
}
else
{
+ struct mu_wordsplit ws;
+
if (mu_ispunct (path[0]))
{
delim = static_delim;
delim[0] = path[0];
path++;
}
- rc = mu_argcv_get_np (path, strlen (path), delim, NULL, 0,
- &argc, &argv, NULL);
- }
- if (rc == 0)
- {
- *pargc = argc;
- *pargv = argv;
+ ws.ws_delim = delim;
+
+ if (mu_wordsplit (path, &ws, MU_WRDSF_DEFFLAGS|MU_WRDSF_DELIM))
+ {
+ mu_error (_("cannot split line `%s': %s"), path,
+ mu_wordsplit_strerror (&ws));
+ return errno;
+ }
+ argc = ws.ws_wordc;
+ argv = ws.ws_wordv;
+ ws.ws_wordc = 0;
+ ws.ws_wordv = NULL;
+ mu_wordsplit_free (&ws);
}
- return rc;
+
+ *pargc = argc;
+ *pargv = argv;
+
+ return 0;
}
struct find_data
@@ -1665,53 +1676,63 @@ static mu_config_value_t *
parse_label (const char *str)
{
mu_config_value_t *val = NULL;
- int count, i;
- char **vect;
+ size_t i;
+ struct mu_wordsplit ws;
size_t len = strlen (str);
if (len > 1 && str[0] == '(' && str[len-1] == ')')
{
mu_list_t lst;
- mu_argcv_get_np (str + 1, len - 2,
- ", \t", NULL,
- 0,
- &count, &vect, NULL);
+
+ ws.ws_delim = ",";
+ if (mu_wordsplit_len (str + 1, len - 2, &ws,
+ MU_WRDSF_DEFFLAGS|MU_WRDSF_DELIM|MU_WRDSF_WS))
+ {
+ mu_error (_("cannot split line `%s': %s"), str,
+ mu_wordsplit_strerror (&ws));
+ return NULL;
+ }
+
mu_list_create (&lst);
mu_list_set_destroy_item (lst, destroy_value);
- for (i = 0; i < count; i++)
+ for (i = 0; i < ws.ws_wordc; i++)
{
mu_config_value_t *p = mu_alloc (sizeof (*p));
p->type = MU_CFG_STRING;
- p->v.string = vect[i];
+ p->v.string = ws.ws_wordv[i];
mu_list_append (lst, p);
}
- free (vect);
val = mu_alloc (sizeof (*val));
val->type = MU_CFG_LIST;
val->v.list = lst;
}
else
{
- mu_argcv_get (str, NULL, NULL, &count, &vect);
+ if (mu_wordsplit (str, &ws, MU_WRDSF_DEFFLAGS))
+ {
+ mu_error (_("cannot split line `%s': %s"), str,
+ mu_wordsplit_strerror (&ws));
+ return NULL;
+ }
val = mu_alloc (sizeof (*val));
- if (count == 1)
+ if (ws.ws_wordc == 1)
{
val->type = MU_CFG_STRING;
- val->v.string = vect[0];
- free (vect);
+ val->v.string = ws.ws_wordv[0];
}
else
{
val->type = MU_CFG_ARRAY;
- val->v.arg.c = count;
- val->v.arg.v = mu_alloc (count * sizeof (val->v.arg.v[0]));
- for (i = 0; i < count; i++)
+ val->v.arg.c = ws.ws_wordc;
+ val->v.arg.v = mu_alloc (ws.ws_wordc * sizeof (val->v.arg.v[0]));
+ for (i = 0; i < ws.ws_wordc; i++)
{
val->v.arg.v[i].type = MU_CFG_STRING;
- val->v.arg.v[i].v.string = vect[i];
+ val->v.arg.v[i].v.string = ws.ws_wordv[i];
}
- free (vect);
}
+ ws.ws_wordc = 0;
+ mu_wordsplit_free (&ws);
}
return val;
}
diff --git a/libmailutils/diag/gdebug.c b/libmailutils/diag/gdebug.c
index 7e6f63cc8..d2d89d556 100644
--- a/libmailutils/diag/gdebug.c
+++ b/libmailutils/diag/gdebug.c
@@ -28,7 +28,7 @@
#include <mailutils/assoc.h>
#include <mailutils/error.h>
#include <mailutils/errno.h>
-#include <mailutils/argcv.h>
+#include <mailutils/wordsplit.h>
#include <mailutils/debug.h>
#include <mailutils/cfg.h>
#include <mailutils/nls.h>
@@ -167,20 +167,22 @@ mu_debug_level_from_string (const char *string, mu_log_level_t *plev,
int
mu_global_debug_from_string (const char *string, const char *errpfx)
{
- int rc;
- int argc;
- char **argv;
- int i;
-
- rc = mu_argcv_get (string, ";", NULL, &argc, &argv);
- if (rc)
- return rc;
+ struct mu_wordsplit ws;
+ size_t i;
+
+ ws.ws_delim = ";";
+ if (mu_wordsplit (string, &ws, MU_WRDSF_DEFFLAGS|MU_WRDSF_DELIM|MU_WRDSF_WS))
+ {
+ mu_error (_("cannot split line `%s': %s"), string,
+ mu_wordsplit_strerror (&ws));
+ return errno;
+ }
- for (i = 0; i < argc; i++)
+ for (i = 0; i < ws.ws_wordc; i++)
{
char *p;
mu_log_level_t level = MU_DEBUG_INHERIT;
- char *object_name = argv[i];
+ char *object_name = ws.ws_wordv[i];
for (p = object_name; *p && *p != '='; p++)
;
@@ -199,7 +201,7 @@ mu_global_debug_from_string (const char *string, const char *errpfx)
mu_error ("%s: invalid debugging specification `%s': "
"expected levels or number after `=', "
"but found `%s'",
- errpfx, argv[i], p);
+ errpfx, ws.ws_wordv[i], p);
break;
}
}
@@ -254,8 +256,7 @@ mu_global_debug_from_string (const char *string, const char *errpfx)
mu_global_debug_set_level (object_name, level);
}
-
- mu_argcv_free (argc, argv);
+ mu_wordsplit_free (&ws);
return 0;
}
diff --git a/libmailutils/mailer/mailer.c b/libmailutils/mailer/mailer.c
index 01fb6d31e..fec7cabb4 100644
--- a/libmailutils/mailer/mailer.c
+++ b/libmailutils/mailer/mailer.c
@@ -29,6 +29,7 @@
#include <sys/time.h>
+#include <mailutils/nls.h>
#include <mailutils/cstr.h>
#include <mailutils/address.h>
#include <mailutils/debug.h>
@@ -45,7 +46,7 @@
#include <mailutils/body.h>
#include <mailutils/mailbox.h>
#include <mailutils/message.h>
-#include <mailutils/argcv.h>
+#include <mailutils/wordsplit.h>
#include <mailutils/util.h>
#include <mailutils/mime.h>
#include <mailutils/io.h>
@@ -289,7 +290,8 @@ save_fcc (mu_message_t msg)
{
mu_header_t hdr;
size_t count = 0, i;
- char buf[512], *fcc;
+ const char *buf;
+ char *fcc;
if (mu_message_get_header (msg, &hdr))
return;
@@ -302,17 +304,25 @@ save_fcc (mu_message_t msg)
{
mu_mailbox_t mbox;
- mu_header_get_field_name (hdr, i, buf, sizeof buf, NULL);
+ mu_header_sget_field_name (hdr, i, &buf);
if (mu_c_strcasecmp (buf, MU_HEADER_FCC) == 0
&& mu_header_aget_field_value (hdr, i, &fcc) == 0)
{
- int i, argc;
- char **argv;
-
- mu_argcv_get (fcc, ",", NULL, &argc, &argv);
- for (i = 0; i < argc; i += 2)
+ size_t i;
+ struct mu_wordsplit ws;
+
+ ws.ws_delim = ",";
+ if (mu_wordsplit (fcc, &ws,
+ MU_WRDSF_DEFFLAGS|MU_WRDSF_DELIM|MU_WRDSF_WS))
+ {
+ mu_error (_("cannot split line `%s': %s"), fcc,
+ mu_wordsplit_strerror (&ws));
+ continue;
+ }
+
+ for (i = 0; i < ws.ws_wordc; i += 2)
{
- if (mu_mailbox_create_default (&mbox, argv[i]))
+ if (mu_mailbox_create_default (&mbox, ws.ws_wordv[i]))
continue; /*FIXME: error message?? */
if (mu_mailbox_open (mbox,
MU_STREAM_RDWR | MU_STREAM_CREAT
@@ -324,7 +334,7 @@ save_fcc (mu_message_t msg)
mu_mailbox_close (mbox);
mu_mailbox_destroy (&mbox);
}
- mu_argcv_free (argc, argv);
+ mu_wordsplit_free (&ws);
free (fcc);
}
}
diff --git a/libmailutils/server/acl.c b/libmailutils/server/acl.c
index a3e3764f2..d7a13629a 100644
--- a/libmailutils/server/acl.c
+++ b/libmailutils/server/acl.c
@@ -28,8 +28,9 @@
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
+#include <mailutils/nls.h>
#include <mailutils/acl.h>
-#include <mailutils/argcv.h>
+#include <mailutils/wordsplit.h>
#include <mailutils/list.h>
#include <mailutils/debug.h>
#include <mailutils/error.h>
@@ -581,14 +582,19 @@ spawn_prog (const char *cmdline, int *pstatus, struct run_closure *rp)
if (pid == 0)
{
int i;
- int argc;
- char **argv;
+ struct mu_wordsplit ws;
- mu_argcv_get (s, " \t", NULL, &argc, &argv);
+ if (mu_wordsplit (s, &ws, MU_WRDSF_DEFFLAGS))
+ {
+ mu_error (_("cannot split line `%s': %s"), s,
+ mu_wordsplit_strerror (&ws));
+ _exit (127);
+ }
+
for (i = getmaxfd (); i > 2; i--)
close (i);
- execvp (argv[0], argv);
- exit (127);
+ execvp (ws.ws_wordv[0], ws.ws_wordv);
+ _exit (127);
}
free (s);
diff --git a/libmailutils/stream/prog_stream.c b/libmailutils/stream/prog_stream.c
index 437bf01e0..c05c91e43 100644
--- a/libmailutils/stream/prog_stream.c
+++ b/libmailutils/stream/prog_stream.c
@@ -29,6 +29,7 @@
#include <mailutils/types.h>
#include <mailutils/alloc.h>
#include <mailutils/argcv.h>
+#include <mailutils/wordsplit.h>
#include <mailutils/error.h>
#include <mailutils/errno.h>
#include <mailutils/nls.h>
@@ -390,17 +391,25 @@ struct _mu_prog_stream *
_prog_stream_create (const char *progname, int flags)
{
struct _mu_prog_stream *fs;
+ struct mu_wordsplit ws;
fs = (struct _mu_prog_stream *) _mu_stream_create (sizeof (*fs), flags);
if (!fs)
return NULL;
- if (mu_argcv_get (progname, "", "#", &fs->argc, &fs->argv))
+ ws.ws_comment = "#";
+ if (mu_wordsplit (progname, &ws, MU_WRDSF_DEFFLAGS|MU_WRDSF_COMMENT))
{
- mu_argcv_free (fs->argc, fs->argv);
+ mu_error (_("cannot split line `%s': %s"), progname,
+ mu_wordsplit_strerror (&ws));
free (fs);
return NULL;
}
+ fs->argc = ws.ws_wordc;
+ fs->argv = ws.ws_wordv;
+ ws.ws_wordc = 0;
+ ws.ws_wordv = NULL;
+ mu_wordsplit_free (&ws);
fs->stream.read = _prog_read;
fs->stream.write = _prog_write;
diff --git a/libmailutils/string/Makefile.am b/libmailutils/string/Makefile.am
index 485df4a67..5cb6a2368 100644
--- a/libmailutils/string/Makefile.am
+++ b/libmailutils/string/Makefile.am
@@ -35,6 +35,7 @@ libstring_la_SOURCES = \
muctype.c\
vasnprintf.c\
mkfilename.c\
+ wordsplit.c\
xdecode.c
INCLUDES = @MU_LIB_COMMON_INCLUDES@ -I/libmailutils
diff --git a/libmailutils/string/wordsplit.c b/libmailutils/string/wordsplit.c
new file mode 100644
index 000000000..301ab005f
--- /dev/null
+++ b/libmailutils/string/wordsplit.c
@@ -0,0 +1,1469 @@
+/* wordsplit - a word splitter
+ Copyright (C) 2009, 2010 Sergey Poznyakoff
+
+ 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 of the License, 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.
+
+ You should have received a copy of the GNU General Public License along
+ with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* This module is shared with Grecs: http://puszcza.gnu.org.ua/projects/grecs.
+ The intent is to keep it as mu-independent as possible, so that the two
+ projects can be easily synchronized. Some time in the future I'll think
+ about providing a better way of synching, perhaps by integrating Grecs to
+ Mailutils as a submodule. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <errno.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include <mailutils/nls.h>
+#include <mailutils/wordsplit.h>
+
+#define ISWS(c) ((c)==' '||(c)=='\t'||(c)=='\n')
+#define ISDELIM(ws,c) \
+ (strchr ((ws)->ws_delim, (c)) != NULL)
+#define ISPUNCT(c) (strchr("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",(c))!=NULL)
+#define ISUPPER(c) ('A' <= ((unsigned) (c)) && ((unsigned) (c)) <= 'Z')
+#define ISLOWER(c) ('a' <= ((unsigned) (c)) && ((unsigned) (c)) <= 'z')
+#define ISALPHA(c) (ISUPPER(c) || ISLOWER(c))
+#define ISDIGIT(c) ('0' <= ((unsigned) (c)) && ((unsigned) (c)) <= '9')
+#define ISXDIGIT(c) (strchr("abcdefABCDEF", c)!=NULL)
+#define ISALNUM(c) (ISALPHA(c) || ISDIGIT(c))
+#define ISPRINT(c) (' ' <= ((unsigned) (c)) && ((unsigned) (c)) <= 127)
+
+#define ALLOC_INIT 128
+#define ALLOC_INCR 128
+
+static void
+_wsplt_alloc_die (struct mu_wordsplit *wsp)
+{
+ wsp->ws_error (_("memory exhausted"));
+ abort ();
+}
+
+static void
+_wsplt_error (const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start (ap, fmt);
+ vfprintf (stderr, fmt, ap);
+ va_end (ap);
+ fputc ('\n', stderr);
+}
+
+static void mu_wordsplit_free_nodes (struct mu_wordsplit *);
+
+static int
+_wsplt_nomem (struct mu_wordsplit *wsp)
+{
+ errno = ENOMEM;
+ wsp->ws_errno = MU_WRDSE_NOSPACE;
+ if (wsp->ws_flags & MU_WRDSF_ENOMEMABRT)
+ wsp->ws_alloc_die (wsp);
+ if (wsp->ws_flags & MU_WRDSF_SHOWERR)
+ mu_wordsplit_perror (wsp);
+ if (!(wsp->ws_flags & MU_WRDSF_REUSE))
+ mu_wordsplit_free (wsp);
+ mu_wordsplit_free_nodes (wsp);
+ return wsp->ws_errno;
+}
+
+static int
+mu_wordsplit_init (struct mu_wordsplit *wsp, const char *input, size_t len,
+ int flags)
+{
+ wsp->ws_flags = flags;
+
+ if (!(wsp->ws_flags & MU_WRDSF_ALLOC_DIE))
+ wsp->ws_alloc_die = _wsplt_alloc_die;
+ if (!(wsp->ws_flags & MU_WRDSF_ERROR))
+ wsp->ws_error = _wsplt_error;
+
+ if (!(wsp->ws_flags & MU_WRDSF_NOVAR)
+ && !(wsp->ws_flags & (MU_WRDSF_ENV | MU_WRDSF_GETVAR)))
+ {
+ errno = EINVAL;
+ wsp->ws_errno = MU_WRDSE_USAGE;
+ if (wsp->ws_flags & MU_WRDSF_SHOWERR)
+ mu_wordsplit_perror (wsp);
+ return wsp->ws_errno;
+ }
+
+ if (!(wsp->ws_flags & MU_WRDSF_NOCMD))
+ {
+ errno = EINVAL;
+ wsp->ws_errno = MU_WRDSE_NOSUPP;
+ if (wsp->ws_flags & MU_WRDSF_SHOWERR)
+ mu_wordsplit_perror (wsp);
+ return wsp->ws_errno;
+ }
+
+ if (wsp->ws_flags & MU_WRDSF_SHOWDBG)
+ {
+ if (!(wsp->ws_flags & MU_WRDSF_DEBUG))
+ {
+ if (wsp->ws_flags & MU_WRDSF_ERROR)
+ wsp->ws_debug = wsp->ws_error;
+ else if (wsp->ws_flags & MU_WRDSF_SHOWERR)
+ wsp->ws_debug = _wsplt_error;
+ else
+ wsp->ws_flags &= ~MU_WRDSF_SHOWDBG;
+ }
+ }
+
+ wsp->ws_input = input;
+ wsp->ws_len = len;
+
+ if (!(wsp->ws_flags & MU_WRDSF_DOOFFS))
+ wsp->ws_offs = 0;
+
+ if (!(wsp->ws_flags & MU_WRDSF_DELIM))
+ wsp->ws_delim = " \t\n";
+
+ if (!(wsp->ws_flags & MU_WRDSF_COMMENT))
+ wsp->ws_comment = NULL;
+
+ if (wsp->ws_flags & MU_WRDSF_REUSE)
+ {
+ if (!(wsp->ws_flags & MU_WRDSF_APPEND))
+ wsp->ws_wordc = 0;
+ }
+ else
+ {
+ wsp->ws_wordv = NULL;
+ wsp->ws_wordc = 0;
+ wsp->ws_wordn = 0;
+ }
+ if (wsp->ws_flags & MU_WRDSF_DOOFFS)
+ wsp->ws_wordn += wsp->ws_offs;
+
+ wsp->ws_endp = 0;
+ wsp->ws_errno = 0;
+ wsp->ws_head = wsp->ws_tail = NULL;
+ return 0;
+}
+
+static int
+alloc_space (struct mu_wordsplit *wsp, size_t count)
+{
+ size_t offs = (wsp->ws_flags & MU_WRDSF_DOOFFS) ? wsp->ws_offs : 0;
+ char **ptr;
+ size_t newalloc;
+
+ if (wsp->ws_wordv == NULL)
+ {
+ newalloc = offs + count > ALLOC_INIT ? count : ALLOC_INIT;
+ ptr = calloc (newalloc, sizeof (ptr[0]));
+ }
+ else if (wsp->ws_wordn < offs + wsp->ws_wordc + count)
+ {
+ newalloc = offs + wsp->ws_wordc +
+ count > ALLOC_INCR ? count : ALLOC_INCR;
+ ptr = realloc (wsp->ws_wordv, newalloc * sizeof (ptr[0]));
+ }
+ else
+ return 0;
+
+ if (ptr)
+ {
+ wsp->ws_wordn = newalloc;
+ wsp->ws_wordv = ptr;
+ }
+ else
+ return _wsplt_nomem (wsp);
+ return 0;
+}
+
+
+/* Node state flags */
+#define _WSNF_NULL 0x01 /* null node (a noop) */
+#define _WSNF_WORD 0x02 /* node contains word in v.word */
+#define _WSNF_QUOTE 0x04 /* text is quoted */
+#define _WSNF_NOEXPAND 0x08 /* text is not subject to expansion */
+#define _WSNF_JOIN 0x10 /* node must be joined with the next node */
+#define _WSNF_SEXP 0x20 /* is a sed expression */
+
+#define _WSNF_EMPTYOK 0x0100 /* special flag indicating that
+ mu_wordsplit_add_segm must add the
+ segment even if it is empty */
+
+struct mu_wordsplit_node
+{
+ struct mu_wordsplit_node *prev; /* Previous element */
+ struct mu_wordsplit_node *next; /* Next element */
+ int flags; /* Node flags */
+ union
+ {
+ struct
+ {
+ size_t beg; /* Start of word in ws_input */
+ size_t end; /* End of word in ws_input */
+ } segm;
+ char *word;
+ } v;
+};
+
+static const char *
+wsnode_flagstr (int flags)
+{
+ static char retbuf[6];
+ char *p = retbuf;
+
+ if (flags & _WSNF_WORD)
+ *p++ = 'w';
+ else if (flags & _WSNF_NULL)
+ *p++ = 'n';
+ else
+ *p++ = '-';
+ if (flags & _WSNF_QUOTE)
+ *p++ = 'q';
+ else
+ *p++ = '-';
+ if (flags & _WSNF_NOEXPAND)
+ *p++ = 'E';
+ else
+ *p++ = '-';
+ if (flags & _WSNF_JOIN)
+ *p++ = 'j';
+ else
+ *p++ = '-';
+ if (flags & _WSNF_SEXP)
+ *p++ = 's';
+ else
+ *p++ = '-';
+ *p = 0;
+ return retbuf;
+}
+
+static const char *
+wsnode_ptr (struct mu_wordsplit *wsp, struct mu_wordsplit_node *p)
+{
+ if (p->flags & _WSNF_NULL)
+ return "";
+ else if (p->flags & _WSNF_WORD)
+ return p->v.word;
+ else
+ return wsp->ws_input + p->v.segm.beg;
+}
+
+static size_t
+wsnode_len (struct mu_wordsplit_node *p)
+{
+ if (p->flags & _WSNF_NULL)
+ return 0;
+ else if (p->flags & _WSNF_WORD)
+ return strlen (p->v.word);
+ else
+ return p->v.segm.end - p->v.segm.beg;
+}
+
+static int
+wsnode_new (struct mu_wordsplit *wsp, struct mu_wordsplit_node **pnode)
+{
+ struct mu_wordsplit_node *node = calloc (1, sizeof (*node));
+ if (!node)
+ return _wsplt_nomem (wsp);
+ *pnode = node;
+ return 0;
+}
+
+static void
+wsnode_free (struct mu_wordsplit_node *p)
+{
+ if (p->flags & _WSNF_WORD)
+ free (p->v.word);
+ free (p);
+}
+
+static void
+wsnode_append (struct mu_wordsplit *wsp, struct mu_wordsplit_node *node)
+{
+ node->next = NULL;
+ node->prev = wsp->ws_tail;
+ if (wsp->ws_tail)
+ wsp->ws_tail->next = node;
+ else
+ wsp->ws_head = node;
+ wsp->ws_tail = node;
+}
+
+static void
+wsnode_remove (struct mu_wordsplit *wsp, struct mu_wordsplit_node *node)
+{
+ struct mu_wordsplit_node *p;
+
+ p = node->prev;
+ if (p)
+ p->next = node->next;
+ else
+ wsp->ws_head = node->next;
+
+ p = node->next;
+ if (p)
+ p->prev = node->prev;
+ else
+ wsp->ws_tail = node->prev;
+
+ node->next = node->prev = NULL;
+}
+
+static void
+wsnode_insert (struct mu_wordsplit *wsp, struct mu_wordsplit_node *node,
+ struct mu_wordsplit_node *anchor, int before)
+{
+ if (!wsp->ws_head)
+ {
+ node->next = node->prev = NULL;
+ wsp->ws_head = wsp->ws_tail = node;
+ }
+ else if (before)
+ {
+ if (anchor->prev)
+ wsnode_insert (wsp, node, anchor->prev, 0);
+ else
+ {
+ node->prev = NULL;
+ node->next = anchor;
+ anchor->prev = node;
+ wsp->ws_head = node;
+ }
+ }
+ else
+ {
+ struct mu_wordsplit_node *p;
+
+ p = anchor->next;
+ if (p)
+ p->prev = node;
+ else
+ wsp->ws_tail = node;
+ node->next = p;
+ node->prev = anchor;
+ anchor->next = node;
+ }
+}
+
+static int
+mu_wordsplit_add_segm (struct mu_wordsplit *wsp, size_t beg, size_t end,
+ int flg)
+{
+ struct mu_wordsplit_node *node;
+ int rc;
+
+ if (end == beg && !(flg & _WSNF_EMPTYOK))
+ return 0;
+ rc = wsnode_new (wsp, &node);
+ if (rc)
+ return rc;
+ node->flags = flg & ~(_WSNF_WORD|_WSNF_EMPTYOK);
+ node->v.segm.beg = beg;
+ node->v.segm.end = end;
+ wsnode_append (wsp, node);
+ return 0;
+}
+
+static void
+mu_wordsplit_free_nodes (struct mu_wordsplit *wsp)
+{
+ struct mu_wordsplit_node *p;
+
+ for (p = wsp->ws_head; p;)
+ {
+ struct mu_wordsplit_node *next = p->next;
+ wsnode_free (p);
+ p = next;
+ }
+ wsp->ws_head = wsp->ws_tail = NULL;
+}
+
+static void
+mu_wordsplit_dump_nodes (struct mu_wordsplit *wsp)
+{
+ struct mu_wordsplit_node *p;
+ int n = 0;
+
+ for (p = wsp->ws_head, n = 0; p; p = p->next, n++)
+ {
+ if (p->flags & _WSNF_WORD)
+ wsp->ws_debug ("%4d: %p: %#04x (%s):%s;",
+ n, p, p->flags, wsnode_flagstr (p->flags), p->v.word);
+ else
+ wsp->ws_debug ("%4d: %p: %#04x (%s):%.*s;",
+ n, p, p->flags, wsnode_flagstr (p->flags),
+ p->v.segm.end - p->v.segm.beg,
+ wsp->ws_input + p->v.segm.beg);
+ }
+}
+
+static int
+coalesce_segment (struct mu_wordsplit *wsp, struct mu_wordsplit_node *node)
+{
+ struct mu_wordsplit_node *p, *end;
+ size_t len = 0;
+ char *buf, *cur;
+ int stop;
+
+ for (p = node; p && (p->flags & _WSNF_JOIN); p = p->next)
+ {
+ len += wsnode_len (p);
+ }
+ len += wsnode_len (p);
+ end = p;
+
+ buf = malloc (len + 1);
+ if (!buf)
+ return _wsplt_nomem (wsp);
+ cur = buf;
+
+ p = node;
+ for (stop = 0; !stop;)
+ {
+ struct mu_wordsplit_node *next = p->next;
+ const char *str = wsnode_ptr (wsp, p);
+ size_t slen = wsnode_len (p);
+
+ memcpy (cur, str, slen);
+ cur += slen;
+ if (p != node)
+ {
+ wsnode_remove (wsp, p);
+ stop = p == end;
+ wsnode_free (p);
+ }
+ p = next;
+ }
+
+ *cur = 0;
+
+ node->flags &= ~_WSNF_JOIN;
+
+ if (node->flags & _WSNF_WORD)
+ free (node->v.word);
+ else
+ node->flags |= _WSNF_WORD;
+ node->v.word = buf;
+ return 0;
+}
+
+static int
+wsnode_quoteremoval (struct mu_wordsplit *wsp)
+{
+ struct mu_wordsplit_node *p;
+ void (*uqfn) (char *, const char *, size_t) =
+ (wsp->ws_flags & MU_WRDSF_CESCAPES) ?
+ mu_wordsplit_c_unquote_copy : mu_wordsplit_sh_unquote_copy;
+
+ for (p = wsp->ws_head; p; p = p->next)
+ {
+ const char *str = wsnode_ptr (wsp, p);
+ size_t slen = wsnode_len (p);
+ int unquote;
+
+ if (wsp->ws_flags & MU_WRDSF_QUOTE)
+ {
+ unquote = !(p->flags & _WSNF_NOEXPAND);
+ }
+ else
+ unquote = 0;
+
+ if (unquote)
+ {
+ if (!(p->flags & _WSNF_WORD))
+ {
+ char *newstr = malloc (slen + 1);
+ if (!newstr)
+ return _wsplt_nomem (wsp);
+ memcpy (newstr, str, slen);
+ newstr[slen] = 0;
+ p->v.word = newstr;
+ p->flags |= _WSNF_WORD;
+ }
+ uqfn (p->v.word, str, slen);
+ }
+ }
+ return 0;
+}
+
+static int
+wsnode_coalesce (struct mu_wordsplit *wsp)
+{
+ struct mu_wordsplit_node *p;
+
+ for (p = wsp->ws_head; p; p = p->next)
+ {
+ if (p->flags & _WSNF_JOIN)
+ if (coalesce_segment (wsp, p))
+ return 1;
+ }
+ return 0;
+}
+
+static int
+mu_wordsplit_finish (struct mu_wordsplit *wsp)
+{
+ struct mu_wordsplit_node *p;
+ size_t n;
+
+ n = 0;
+
+ for (p = wsp->ws_head; p; p = p->next)
+ n++;
+
+ if (alloc_space (wsp, n + 1))
+ return 1;
+
+ for (p = wsp->ws_head; p; p = p->next)
+ {
+ const char *str = wsnode_ptr (wsp, p);
+ size_t slen = wsnode_len (p);
+ char *newstr = malloc (slen + 1);
+
+ /* Assign newstr first, even if it is NULL. This way
+ mu_wordsplit_free will work even if we return
+ nomem later. */
+ wsp->ws_wordv[wsp->ws_offs + wsp->ws_wordc] = newstr;
+ if (!newstr)
+ return _wsplt_nomem (wsp);
+ memcpy (newstr, str, slen);
+ newstr[slen] = 0;
+
+ wsp->ws_wordc++;
+
+ }
+ wsp->ws_wordv[wsp->ws_offs + wsp->ws_wordc] = NULL;
+ return 0;
+}
+
+
+/* Variable expansion */
+static int
+node_split_prefix (struct mu_wordsplit *wsp,
+ struct mu_wordsplit_node **ptail,
+ struct mu_wordsplit_node *node,
+ size_t beg, size_t len, int flg)
+{
+ struct mu_wordsplit_node *newnode;
+
+ if (len == 0)
+ return 0;
+ if (wsnode_new (wsp, &newnode))
+ return 1;
+ wsnode_insert (wsp, newnode, *ptail, 0);
+ if (node->flags & _WSNF_WORD)
+ {
+ const char *str = wsnode_ptr (wsp, node);
+ char *newstr = malloc (len + 1);
+ if (!newstr)
+ return _wsplt_nomem (wsp);
+ memcpy (newstr, str + beg, len);
+ newstr[len] = 0;
+ newnode->flags = _WSNF_WORD;
+ newnode->v.word = newstr;
+ }
+ else
+ {
+ newnode->v.segm.beg = node->v.segm.beg + beg;
+ newnode->v.segm.end = newnode->v.segm.beg + len;
+ }
+ newnode->flags |= flg;
+ *ptail = newnode;
+ return 0;
+}
+
+static int
+find_closing_cbrace (const char *str, size_t i, size_t len, size_t * poff)
+{
+ enum
+ { st_init, st_squote, st_dquote } state = st_init;
+ size_t level = 1;
+
+ for (; i < len; i++)
+ {
+ switch (state)
+ {
+ case st_init:
+ switch (str[i])
+ {
+ case '{':
+ level++;
+ break;
+
+ case '}':
+ if (--level == 0)
+ {
+ *poff = i;
+ return 0;
+ }
+ break;
+
+ case '"':
+ state = st_dquote;
+ break;
+
+ case '\'':
+ state = st_squote;
+ break;
+ }
+ break;
+
+ case st_squote:
+ if (str[i] == '\'')
+ state = st_init;
+ break;
+
+ case st_dquote:
+ if (str[i] == '\\')
+ i++;
+ else if (str[i] == '"')
+ state = st_init;
+ break;
+ }
+ }
+ return 1;
+}
+
+static const char *
+mu_wordsplit_find_env (struct mu_wordsplit *wsp, const char *name, size_t len)
+{
+ size_t i;
+
+ if (!(wsp->ws_flags & MU_WRDSF_ENV))
+ return NULL;
+ for (i = 0; wsp->ws_env[i]; i++)
+ {
+ size_t j;
+ const char *var = wsp->ws_env[i];
+
+ for (j = 0; j < len; j++)
+ if (name[j] != var[j])
+ break;
+ if (j == len && var[j] == '=')
+ return var + j + 1;
+ }
+ return NULL;
+}
+
+static int
+expvar (struct mu_wordsplit *wsp, const char *str, size_t len,
+ struct mu_wordsplit_node **ptail, const char **pend, int flg)
+{
+ size_t i = 0;
+ const char *defstr = NULL;
+ char *value;
+ const char *vptr;
+ struct mu_wordsplit_node *newnode;
+ const char *start = str - 1;
+
+ if (ISALPHA (str[0]) || str[0] == '_')
+ {
+ for (i = 1; i < len; i++)
+ if (!(ISALNUM (str[i]) || str[i] == '_'))
+ break;
+ *pend = str + i - 1;
+ }
+ else if (str[0] == '{')
+ {
+ str++;
+ len--;
+ for (i = 1; i < len; i++)
+ if (str[i] == '}' || str[i] == ':')
+ break;
+ if (str[i] == ':')
+ {
+ size_t j;
+
+ defstr = str + i + 1;
+ if (find_closing_cbrace (str, i + 1, len, &j))
+ {
+ wsp->ws_errno = MU_WRDSE_CBRACE;
+ return 1;
+ }
+ *pend = str + j;
+ }
+ else if (str[i] == '}')
+ {
+ defstr = NULL;
+ *pend = str + i;
+ }
+ else
+ {
+ wsp->ws_errno = MU_WRDSE_CBRACE;
+ return 1;
+ }
+ }
+ else
+ {
+ if (wsnode_new (wsp, &newnode))
+ return 1;
+ wsnode_insert (wsp, newnode, *ptail, 0);
+ *ptail = newnode;
+ newnode->flags = _WSNF_WORD | flg;
+ newnode->v.word = malloc (3);
+ if (!newnode->v.word)
+ return _wsplt_nomem (wsp);
+ newnode->v.word[0] = '$';
+ newnode->v.word[1] = str[0];
+ newnode->v.word[2] = 0;
+ *pend = str;
+ return 0;
+ }
+
+ /* Actually expand the variable */
+ /* str - start of the variable name
+ i - its length
+ defstr - default replacement str */
+
+ vptr = mu_wordsplit_find_env (wsp, str, i);
+ if (vptr)
+ {
+ value = strdup (vptr);
+ if (!value)
+ return _wsplt_nomem (wsp);
+ }
+ else if (wsp->ws_flags & MU_WRDSF_GETVAR)
+ value = wsp->ws_getvar (str, i);
+ else if (wsp->ws_flags & MU_WRDSF_UNDEF)
+ {
+ wsp->ws_errno = MU_WRDSE_UNDEF;
+ if (wsp->ws_flags & MU_WRDSF_SHOWERR)
+ mu_wordsplit_perror (wsp);
+ return 1;
+ }
+ else
+ {
+ if (wsp->ws_flags & MU_WRDSF_WARNUNDEF)
+ wsp->ws_error (_("warning: undefined variable `%.*s'"), i, str);
+ if (wsp->ws_flags & MU_WRDSF_KEEPUNDEF)
+ value = NULL;
+ else
+ value = "";
+ }
+ /* FIXME: handle defstr */
+ if (value)
+ {
+ if (flg & _WSNF_QUOTE)
+ {
+ if (wsnode_new (wsp, &newnode))
+ return 1;
+ wsnode_insert (wsp, newnode, *ptail, 0);
+ *ptail = newnode;
+ newnode->flags = _WSNF_WORD | _WSNF_NOEXPAND | flg;
+ newnode->v.word = strdup (value);
+ if (!newnode->v.word)
+ return _wsplt_nomem (wsp);
+ }
+ else if (*value == 0)
+ {
+ /* Empty string is a special case */
+ if (wsnode_new (wsp, &newnode))
+ return 1;
+ wsnode_insert (wsp, newnode, *ptail, 0);
+ *ptail = newnode;
+ newnode->flags = _WSNF_NULL;
+ }
+ else
+ {
+ struct mu_wordsplit ws;
+ int i;
+
+ ws.ws_delim = wsp->ws_delim;
+ if (mu_wordsplit (value, &ws,
+ MU_WRDSF_NOVAR | MU_WRDSF_NOCMD |
+ MU_WRDSF_DELIM | MU_WRDSF_SQUEEZE_DELIMS))
+ {
+ mu_wordsplit_free (&ws);
+ return 1;
+ }
+ for (i = 0; i < ws.ws_wordc; i++)
+ {
+ if (wsnode_new (wsp, &newnode))
+ return 1;
+ wsnode_insert (wsp, newnode, *ptail, 0);
+ *ptail = newnode;
+ newnode->flags = _WSNF_WORD |
+ _WSNF_NOEXPAND |
+ (i + 1 < ws.ws_wordc ? (flg & ~_WSNF_JOIN) : flg);
+ newnode->v.word = strdup (ws.ws_wordv[i]);
+ if (!newnode->v.word)
+ return _wsplt_nomem (wsp);
+ }
+ mu_wordsplit_free (&ws);
+ }
+ }
+ else if (wsp->ws_flags & MU_WRDSF_KEEPUNDEF)
+ {
+ size_t size = *pend - start + 1;
+
+ if (wsnode_new (wsp, &newnode))
+ return 1;
+ wsnode_insert (wsp, newnode, *ptail, 0);
+ *ptail = newnode;
+ newnode->flags = _WSNF_WORD | _WSNF_NOEXPAND | flg;
+ newnode->v.word = malloc (size + 1);
+ if (!newnode->v.word)
+ return _wsplt_nomem (wsp);
+ memcpy (newnode->v.word, start, size);
+ newnode->v.word[size] = 0;
+ }
+ return 0;
+}
+
+static int
+node_expand_vars (struct mu_wordsplit *wsp, struct mu_wordsplit_node *node)
+{
+ const char *str = wsnode_ptr (wsp, node);
+ size_t slen = wsnode_len (node);
+ const char *end = str + slen;
+ const char *p;
+ size_t off = 0;
+ struct mu_wordsplit_node *tail = node;
+
+ for (p = str; p < end; p++)
+ {
+ if (*p == '\\')
+ {
+ p++;
+ continue;
+ }
+ if (*p == '$')
+ {
+ size_t n = p - str;
+
+ if (tail != node)
+ tail->flags |= _WSNF_JOIN;
+ if (node_split_prefix (wsp, &tail, node, off, n, _WSNF_JOIN))
+ return 1;
+ p++;
+ if (expvar (wsp, p, slen - n, &tail, &p,
+ node->flags & (_WSNF_JOIN | _WSNF_QUOTE)))
+ return 1;
+ off += p - str + 1;
+ str = p + 1;
+ }
+ }
+ if (p > str)
+ {
+ if (tail != node)
+ tail->flags |= _WSNF_JOIN;
+ if (node_split_prefix (wsp, &tail, node, off, p - str,
+ node->flags & _WSNF_JOIN))
+ return 1;
+ }
+ if (tail != node)
+ {
+ wsnode_remove (wsp, node);
+ wsnode_free (node);
+ }
+ return 0;
+}
+
+static int
+mu_wordsplit_varexp (struct mu_wordsplit *wsp)
+{
+ struct mu_wordsplit_node *p;
+
+ for (p = wsp->ws_head; p;)
+ {
+ struct mu_wordsplit_node *next = p->next;
+ if (!(p->flags & _WSNF_NOEXPAND))
+ if (node_expand_vars (wsp, p))
+ return 1;
+ p = next;
+ }
+
+ /* Remove NULL lists */
+ for (p = wsp->ws_head; p;)
+ {
+ struct mu_wordsplit_node *next = p->next;
+ if (p->flags & _WSNF_NULL)
+ {
+ wsnode_remove (wsp, p);
+ wsnode_free (p);
+ }
+ p = next;
+ }
+
+ return 0;
+}
+
+/* Strip off any leading and trailing whitespace. This function is called
+ right after the initial scanning, therefore it assumes that every
+ node in the list is a text reference node. */
+static void
+mu_wordsplit_trimws (struct mu_wordsplit *wsp)
+{
+ struct mu_wordsplit_node *p;
+
+ for (p = wsp->ws_head; p; p = p->next)
+ {
+ size_t n;
+
+ /* Skip leading whitespace: */
+ for (n = p->v.segm.beg; n < p->v.segm.end && ISWS (wsp->ws_input[n]);
+ n++)
+ ;
+ p->v.segm.beg = n;
+ /* Trim trailing whitespace */
+ for (n = p->v.segm.end; n > p->v.segm.beg && ISWS (wsp->ws_input[n-1]);
+ n--);
+ p->v.segm.end = n;
+ }
+}
+
+static int
+skip_sed_expr (const char *command, size_t i, size_t len)
+{
+ int state;
+
+ do
+ {
+ int delim;
+
+ if (command[i] == ';')
+ i++;
+ if (!(command[i] == 's' && i + 3 < len && ISPUNCT (command[i + 1])))
+ break;
+
+ delim = command[++i];
+ state = 1;
+ for (i++; i < len; i++)
+ {
+ if (state == 3)
+ {
+ if (command[i] == delim || !ISALNUM (command[i]))
+ break;
+ }
+ else if (command[i] == '\\')
+ i++;
+ else if (command[i] == delim)
+ state++;
+ }
+ }
+ while (state == 3 && i < len && command[i] == ';');
+ return i;
+}
+
+static size_t
+skip_delim (struct mu_wordsplit *wsp)
+{
+ size_t start = wsp->ws_endp;
+ if (wsp->ws_flags & MU_WRDSF_SQUEEZE_DELIMS)
+ {
+ do
+ start++;
+ while (start < wsp->ws_len
+ && ISDELIM (wsp, wsp->ws_input[start]));
+ start--;
+ }
+
+ if (!(wsp->ws_flags & MU_WRDSF_RETURN_DELIMS))
+ start++;
+
+ return start;
+}
+
+#define _MU_WRDS_EOF 0
+#define _MU_WRDS_OK 1
+#define _MU_WRDS_ERR 2
+
+static int
+scan_qstring (struct mu_wordsplit *wsp, size_t start, size_t * end)
+{
+ size_t j;
+ const char *command = wsp->ws_input;
+ size_t len = wsp->ws_len;
+ char q = command[start];
+
+ for (j = start + 1; j < len && command[j] != q; j++)
+ if (q == '"' && command[j] == '\\')
+ j++;
+ if (j < len && command[j] == q)
+ {
+ int flags = _WSNF_QUOTE;
+ if (q == '\'')
+ flags |= _WSNF_NOEXPAND;
+ if (mu_wordsplit_add_segm (wsp, start + 1, j, flags))
+ return _MU_WRDS_ERR;
+ *end = j;
+ }
+ else
+ {
+ wsp->ws_endp = start;
+ wsp->ws_errno = MU_WRDSE_QUOTE;
+ if (wsp->ws_flags & MU_WRDSF_SHOWERR)
+ mu_wordsplit_perror (wsp);
+ return _MU_WRDS_ERR;
+ }
+ return 0;
+}
+
+static int
+scan_word (struct mu_wordsplit *wsp, size_t start)
+{
+ size_t len = wsp->ws_len;
+ const char *command = wsp->ws_input;
+ const char *comment = wsp->ws_comment;
+ int join = 0;
+ int flags = 0;
+
+ size_t i = start;
+
+ if (i >= len)
+ {
+ wsp->ws_errno = MU_WRDSE_EOF;
+ return _MU_WRDS_EOF;
+ }
+
+ start = i;
+
+ if (wsp->ws_flags & MU_WRDSF_SED_EXPR
+ && command[i] == 's' && i + 3 < len && ISPUNCT (command[i + 1]))
+ {
+ flags = _WSNF_SEXP;
+ i = skip_sed_expr (command, i, len);
+ }
+ else if (!ISDELIM (wsp, command[i]))
+ {
+ while (i < len)
+ {
+ if (comment && strchr (comment, command[i]) != NULL)
+ {
+ size_t j;
+ for (j = i + 1; j < len && command[j] != '\n'; j++)
+ ;
+ if (mu_wordsplit_add_segm (wsp, start, i, 0))
+ return _MU_WRDS_ERR;
+ wsp->ws_endp = j;
+ return _MU_WRDS_OK;
+ }
+
+ if (wsp->ws_flags & MU_WRDSF_QUOTE)
+ {
+ if (command[i] == '\\')
+ {
+ if (++i == len)
+ break;
+ i++;
+ continue;
+ }
+
+ if (command[i] == '\'' || command[i] == '"')
+ {
+ if (join && wsp->ws_tail)
+ wsp->ws_tail->flags |= _WSNF_JOIN;
+ if (mu_wordsplit_add_segm (wsp, start, i, _WSNF_JOIN))
+ return _MU_WRDS_ERR;
+ if (scan_qstring (wsp, i, &i))
+ return _MU_WRDS_ERR;
+ start = i + 1;
+ join = 1;
+ }
+ }
+
+ if (ISDELIM (wsp, command[i]))
+ break;
+ else
+ i++;
+ }
+ }
+ else if (wsp->ws_flags & MU_WRDSF_RETURN_DELIMS)
+ {
+ do
+ {
+ i++;
+ }
+ while (i < len && ISDELIM (wsp, command[i]));
+ }
+ else if (!(wsp->ws_flags & MU_WRDSF_SQUEEZE_DELIMS))
+ flags |= _WSNF_EMPTYOK;
+
+ if (join && i > start && wsp->ws_tail)
+ wsp->ws_tail->flags |= _WSNF_JOIN;
+ if (mu_wordsplit_add_segm (wsp, start, i, flags))
+ return _MU_WRDS_ERR;
+ wsp->ws_endp = i;
+
+ return _MU_WRDS_OK;
+}
+
+static char quote_transtab[] = "\\\\a\ab\bf\fn\nr\rt\tv\v";
+
+int
+mu_wordsplit_c_unquote_char (int c)
+{
+ char *p;
+
+ for (p = quote_transtab; *p; p += 2)
+ {
+ if (*p == c)
+ return p[1];
+ }
+ return c;
+}
+
+int
+mu_wordsplit_c_quote_char (int c)
+{
+ char *p;
+
+ for (p = quote_transtab + sizeof (quote_transtab) - 2;
+ p > quote_transtab; p -= 2)
+ {
+ if (*p == c)
+ return p[-1];
+ }
+ return -1;
+}
+
+#define to_num(c) \
+ (ISDIGIT(c) ? c - '0' : (ISXDIGIT(c) ? toupper(c) - 'A' + 10 : 255 ))
+
+static int
+xtonum (int *pval, const char *src, int base, int cnt)
+{
+ int i, val;
+
+ for (i = 0, val = 0; i < cnt; i++, src++)
+ {
+ int n = *(unsigned char *) src;
+ if (n > 127 || (n = to_num (n)) >= base)
+ break;
+ val = val * base + n;
+ }
+ *pval = val;
+ return i;
+}
+
+size_t
+mu_wordsplit_c_quoted_length (const char *str, int quote_hex, int *quote)
+{
+ size_t len = 0;
+
+ *quote = 0;
+ for (; *str; str++)
+ {
+ if (strchr (" \"", *str))
+ *quote = 1;
+
+ if (*str == ' ')
+ len++;
+ else if (*str == '"')
+ len += 2;
+ else if (*str != '\t' && *str != '\\' && ISPRINT (*str))
+ len++;
+ else if (quote_hex)
+ len += 3;
+ else
+ {
+ if (mu_wordsplit_c_quote_char (*str) != -1)
+ len += 2;
+ else
+ len += 4;
+ }
+ }
+ return len;
+}
+
+void
+mu_wordsplit_sh_unquote_copy (char *dst, const char *src, size_t n)
+{
+ int i;
+
+ for (i = 0; i < n;)
+ {
+ if (src[i] == '\\')
+ i++;
+ *dst++ = src[i++];
+ }
+ *dst = 0;
+}
+
+void
+mu_wordsplit_c_unquote_copy (char *dst, const char *src, size_t n)
+{
+ int i = 0;
+ int c;
+
+ while (i < n)
+ {
+ if (src[i] == '\\')
+ {
+ ++i;
+ if (src[i] == 'x' || src[i] == 'X')
+ {
+ if (n - i < 2)
+ {
+ *dst++ = '\\';
+ *dst++ = src[i++];
+ }
+ else
+ {
+ int off = xtonum (&c, src + i + 1,
+ 16, 2);
+ if (off == 0)
+ {
+ *dst++ = '\\';
+ *dst++ = src[i++];
+ }
+ else
+ {
+ *dst++ = c;
+ i += off + 1;
+ }
+ }
+ }
+ else if ((unsigned char) src[i] < 128 && ISDIGIT (src[i]))
+ {
+ if (n - i < 1)
+ {
+ *dst++ = '\\';
+ *dst++ = src[i++];
+ }
+ else
+ {
+ int off = xtonum (&c, src + i, 8, 3);
+ if (off == 0)
+ {
+ *dst++ = '\\';
+ *dst++ = src[i++];
+ }
+ else
+ {
+ *dst++ = c;
+ i += off;
+ }
+ }
+ }
+ else
+ *dst++ = mu_wordsplit_c_unquote_char (src[i++]);
+ }
+ else
+ *dst++ = src[i++];
+ }
+ *dst = 0;
+}
+
+void
+mu_wordsplit_c_quote_copy (char *dst, const char *src, int quote_hex)
+{
+ for (; *src; src++)
+ {
+ if (*src == '"')
+ {
+ *dst++ = '\\';
+ *dst++ = *src;
+ }
+ else if (*src != '\t' && *src != '\\' && ISPRINT (*src))
+ *dst++ = *src;
+ else
+ {
+ char tmp[4];
+
+ if (quote_hex)
+ {
+ snprintf (tmp, sizeof tmp, "%%%02X", *(unsigned char *) src);
+ memcpy (dst, tmp, 3);
+ dst += 3;
+ }
+ else
+ {
+ int c = mu_wordsplit_c_quote_char (*src);
+ *dst++ = '\\';
+ if (c != -1)
+ *dst++ = c;
+ else
+ {
+ snprintf (tmp, sizeof tmp, "%03o", *(unsigned char *) src);
+ memcpy (dst, tmp, 3);
+ dst += 3;
+ }
+ }
+ }
+ }
+}
+
+int
+mu_wordsplit_len (const char *command, size_t len, struct mu_wordsplit *wsp,
+ int flags)
+{
+ int rc;
+ size_t start = 0;
+
+ rc = mu_wordsplit_init (wsp, command, len, flags);
+ if (rc)
+ return rc;
+
+ if (wsp->ws_flags & MU_WRDSF_SHOWDBG)
+ wsp->ws_debug ("Input:%.*s;", len, command);
+
+ if (wsp->ws_flags & MU_WRDSF_NOSPLIT)
+ {
+ /* Treat entire input as a quoted argument */
+ if (mu_wordsplit_add_segm (wsp, 0, len, _WSNF_QUOTE))
+ return wsp->ws_errno;
+ }
+ else
+ {
+ while ((rc = scan_word (wsp, start)) == _MU_WRDS_OK)
+ start = skip_delim (wsp);
+ }
+
+ if (wsp->ws_flags & MU_WRDSF_SHOWDBG)
+ {
+ wsp->ws_debug ("Initial list:");
+ mu_wordsplit_dump_nodes (wsp);
+ }
+ if (rc)
+ {
+ mu_wordsplit_free_nodes (wsp);
+ return wsp->ws_errno;
+ }
+
+ if (wsp->ws_flags & MU_WRDSF_WS)
+ {
+ /* Trim leading and trailing whitespace */
+ mu_wordsplit_trimws (wsp);
+ if (wsp->ws_flags & MU_WRDSF_SHOWDBG)
+ {
+ wsp->ws_debug ("After WS trimming:");
+ mu_wordsplit_dump_nodes (wsp);
+ }
+ }
+
+ /* Expand variables (FIXME: & commands) */
+ if (!(wsp->ws_flags & MU_WRDSF_NOVAR))
+ {
+ if (mu_wordsplit_varexp (wsp))
+ {
+ mu_wordsplit_free_nodes (wsp);
+ return wsp->ws_errno;
+ }
+ if (wsp->ws_flags & MU_WRDSF_SHOWDBG)
+ {
+ wsp->ws_debug ("Expanded list:");
+ mu_wordsplit_dump_nodes (wsp);
+ }
+ }
+
+ do
+ {
+ if (wsnode_quoteremoval (wsp))
+ break;
+ if (wsp->ws_flags & MU_WRDSF_SHOWDBG)
+ {
+ wsp->ws_debug ("After quote removal:");
+ mu_wordsplit_dump_nodes (wsp);
+ }
+
+ if (wsnode_coalesce (wsp))
+ break;
+
+ if (wsp->ws_flags & MU_WRDSF_SHOWDBG)
+ {
+ wsp->ws_debug ("Coalesced list:");
+ mu_wordsplit_dump_nodes (wsp);
+ }
+
+ mu_wordsplit_finish (wsp);
+ }
+ while (0);
+ mu_wordsplit_free_nodes (wsp);
+ return wsp->ws_errno;
+}
+
+int
+mu_wordsplit (const char *command, struct mu_wordsplit *ws, int flags)
+{
+ return mu_wordsplit_len (command, strlen (command), ws, flags);
+}
+
+void
+mu_wordsplit_free (struct mu_wordsplit *ws)
+{
+ size_t i;
+
+ for (i = 0; i < ws->ws_wordc; i++)
+ {
+ char *p = ws->ws_wordv[ws->ws_offs + i];
+ if (p)
+ free (p);
+ }
+ free (ws->ws_wordv);
+ ws->ws_wordv = NULL;
+}
+
+void
+mu_wordsplit_perror (struct mu_wordsplit *wsp)
+{
+ switch (wsp->ws_errno)
+ {
+ case MU_WRDSE_EOF:
+ wsp->ws_error (_("no error"));
+ break;
+
+ case MU_WRDSE_QUOTE:
+ wsp->ws_error (_("missing closing %c (start near #%lu)"),
+ wsp->ws_input[wsp->ws_endp],
+ (unsigned long) wsp->ws_endp);
+ break;
+
+ case MU_WRDSE_NOSPACE:
+ wsp->ws_error (_("memory exhausted"));
+ break;
+
+ case MU_WRDSE_NOSUPP:
+ wsp->ws_error (_("command substitution is not yet supported"));
+
+ case MU_WRDSE_USAGE:
+ wsp->ws_error (_("invalid mu_wordsplit usage"));
+ break;
+
+ case MU_WRDSE_CBRACE:
+ wsp->ws_error (_("unbalanced curly brace"));
+ break;
+
+ case MU_WRDSE_UNDEF:
+ wsp->ws_error (_("undefined variable"));
+ break;
+
+ default:
+ wsp->ws_error (_("unknown error"));
+ }
+}
+
+const char *_mu_wordsplit_errstr[] = {
+ N_("no error"),
+ N_("missing closing quote"),
+ N_("memory exhausted"),
+ N_("variable expansion and command substitution " "are not yet supported"),
+ N_("invalid mu_wordsplit usage"),
+ N_("unbalanced curly brace"),
+ N_("undefined variable")
+};
+int _mu_wordsplit_nerrs =
+ sizeof (_mu_wordsplit_errstr) / sizeof (_mu_wordsplit_errstr[0]);
+
+const char *
+mu_wordsplit_strerror (struct mu_wordsplit *ws)
+{
+ if (ws->ws_errno < _mu_wordsplit_nerrs)
+ return _mu_wordsplit_errstr[ws->ws_errno];
+ return N_("unknown error");
+}
diff --git a/libmailutils/tests/.gitignore b/libmailutils/tests/.gitignore
index ec7502034..0157222e9 100644
--- a/libmailutils/tests/.gitignore
+++ b/libmailutils/tests/.gitignore
@@ -13,3 +13,4 @@ listop
mailcap
url-parse
wicket
+wsp
diff --git a/libmailutils/tests/Makefile.am b/libmailutils/tests/Makefile.am
index f714b587e..e34d2656a 100644
--- a/libmailutils/tests/Makefile.am
+++ b/libmailutils/tests/Makefile.am
@@ -48,7 +48,8 @@ noinst_PROGRAMS = \
listop\
mailcap\
url-parse\
- wicket
+ wicket\
+ wsp
LDADD = ${MU_LIB_MAILUTILS}
@@ -70,7 +71,8 @@ TESTSUITE_AT = \
mailcap.at\
testsuite.at\
url.at\
- wicket.at
+ wicket.at\
+ wordsplit.at
TESTSUITE = $(srcdir)/testsuite
M4=m4
diff --git a/libmailutils/tests/argcv.c b/libmailutils/tests/argcv.c
index 88c54a2cb..66e9060a4 100644
--- a/libmailutils/tests/argcv.c
+++ b/libmailutils/tests/argcv.c
@@ -22,6 +22,7 @@
#include <string.h>
#include <errno.h>
#include <unistd.h>
+#define MU_ARCGV_DEPRECATED
#include <mailutils/argcv.h>
#include <mailutils/errno.h>
diff --git a/libmailutils/tests/listop.c b/libmailutils/tests/listop.c
index 564e1d301..89e72eb5d 100644
--- a/libmailutils/tests/listop.c
+++ b/libmailutils/tests/listop.c
@@ -21,7 +21,6 @@
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
-#include <mailutils/argcv.h>
#include <mailutils/mailutils.h>
static int interactive;
@@ -467,9 +466,8 @@ shell (mu_list_t list)
{
char *text = NULL;
char buf[80];
- int argc;
- char **argv;
-
+ struct mu_wordsplit ws;
+
if (!itr[num])
{
rc = mu_list_get_iterator (list, &itr[num]);
@@ -487,40 +485,44 @@ shell (mu_list_t list)
if (fgets (buf, sizeof buf, stdin) == NULL)
return;
- rc = mu_argcv_get (buf, "", "#", &argc, &argv);
- if (rc)
- lperror ("mu_argcv_get", rc);
+ ws.ws_comment = "#";
+ if (mu_wordsplit (buf, &ws, MU_WRDSF_DEFFLAGS|MU_WRDSF_COMMENT))
+ {
+ mu_error ("cannot split line `%s': %s", buf,
+ mu_wordsplit_strerror (&ws));
+ exit (1);
+ }
- if (argc > 0)
+ if (ws.ws_wordc > 0)
{
- if (strcmp (argv[0], "count") == 0)
+ if (strcmp (ws.ws_wordv[0], "count") == 0)
count (list);
- else if (strcmp (argv[0], "next") == 0)
- next (itr[num], argv[1]);
- else if (strcmp (argv[0], "first") == 0)
+ else if (strcmp (ws.ws_wordv[0], "next") == 0)
+ next (itr[num], ws.ws_wordv[1]);
+ else if (strcmp (ws.ws_wordv[0], "first") == 0)
mu_iterator_first (itr[num]);
- else if (strcmp (argv[0], "del") == 0)
- delete (list, argc, argv);
- else if (strcmp (argv[0], "add") == 0)
- add (list, argc, argv);
- else if (strcmp (argv[0], "prep") == 0)
- prep (list, argc, argv);
- else if (strcmp (argv[0], "ins") == 0)
- ins (list, argc, argv);
- else if (strcmp (argv[0], "repl") == 0)
- repl (list, argc, argv);
- else if (strcmp (argv[0], "ictl") == 0)
- ictl (itr[num], argc, argv);
- else if (strcmp (argv[0], "print") == 0)
+ else if (strcmp (ws.ws_wordv[0], "del") == 0)
+ delete (list, ws.ws_wordc, ws.ws_wordv);
+ else if (strcmp (ws.ws_wordv[0], "add") == 0)
+ add (list, ws.ws_wordc, ws.ws_wordv);
+ else if (strcmp (ws.ws_wordv[0], "prep") == 0)
+ prep (list, ws.ws_wordc, ws.ws_wordv);
+ else if (strcmp (ws.ws_wordv[0], "ins") == 0)
+ ins (list, ws.ws_wordc, ws.ws_wordv);
+ else if (strcmp (ws.ws_wordv[0], "repl") == 0)
+ repl (list, ws.ws_wordc, ws.ws_wordv);
+ else if (strcmp (ws.ws_wordv[0], "ictl") == 0)
+ ictl (itr[num], ws.ws_wordc, ws.ws_wordv);
+ else if (strcmp (ws.ws_wordv[0], "print") == 0)
print (list);
- else if (strcmp (argv[0], "cur") == 0)
+ else if (strcmp (ws.ws_wordv[0], "cur") == 0)
cur (num, itr[num]);
- else if (strcmp (argv[0], "quit") == 0)
+ else if (strcmp (ws.ws_wordv[0], "quit") == 0)
return;
- else if (strcmp (argv[0], "iter") == 0)
+ else if (strcmp (ws.ws_wordv[0], "iter") == 0)
{
int n;
- if (iter (&n, argc, argv) == 0 && !itr[n])
+ if (iter (&n, ws.ws_wordc, ws.ws_wordv) == 0 && !itr[n])
{
rc = mu_list_get_iterator (list, &itr[n]);
if (rc)
@@ -529,24 +531,24 @@ shell (mu_list_t list)
}
num = n;
}
- else if (strcmp (argv[0], "close") == 0)
+ else if (strcmp (ws.ws_wordv[0], "close") == 0)
{
int n;
- if (iter (&n, argc, argv) == 0)
+ if (iter (&n, ws.ws_wordc, ws.ws_wordv) == 0)
{
mu_iterator_destroy (&itr[n]);
if (n == num && ++num == NITR)
num = 0;
}
}
- else if (strcmp (argv[0], "find") == 0)
- find (itr[num], argv[1]);
- else if (strcmp (argv[0], "help") == 0)
+ else if (strcmp (ws.ws_wordv[0], "find") == 0)
+ find (itr[num], ws.ws_wordv[1]);
+ else if (strcmp (ws.ws_wordv[0], "help") == 0)
help ();
- else if (argc == 1)
+ else if (ws.ws_wordc == 1)
{
char *p;
- size_t n = strtoul (argv[0], &p, 0);
+ size_t n = strtoul (ws.ws_wordv[0], &p, 0);
if (*p != 0)
fprintf (stderr, "?\n");
else
@@ -561,7 +563,7 @@ shell (mu_list_t list)
else
fprintf (stderr, "?\n");
}
- mu_argcv_free (argc, argv);
+ mu_wordsplit_free (&ws);
}
}
diff --git a/libmailutils/tests/testsuite.at b/libmailutils/tests/testsuite.at
index d5d02aa35..78fb693d6 100644
--- a/libmailutils/tests/testsuite.at
+++ b/libmailutils/tests/testsuite.at
@@ -56,6 +56,7 @@ AT_INIT
m4_include([list.at])
m4_include([address.at])
m4_include([argcv.at])
+m4_include([wordsplit.at])
m4_include([url.at])
m4_include([mailcap.at])
m4_include([base64e.at])
diff --git a/libmailutils/tests/wordsplit.at b/libmailutils/tests/wordsplit.at
new file mode 100644
index 000000000..dca379252
--- /dev/null
+++ b/libmailutils/tests/wordsplit.at
@@ -0,0 +1,304 @@
+# This file is part of GNU Mailutils. -*- Autotest -*-
+# Copyright (C) 2007, 2008, 2009, 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/>.
+
+dnl ------------------------------------------------------------
+dnl TESTWSP([NAME], [KW = `'], [OPTS], [INPUT], [STDOUT = `'],
+dnl [STDERR = `'], [ENV])
+dnl
+m4_pushdef([TESTWSP],[
+m4_pushdef([MU_TEST_GROUP],[Wordsplit])
+m4_pushdef([MU_TEST_KEYWORDS],[wordsplit wsp])
+m4_pushdef([MU_TEST_COMMAND],[$7 wsp $3])
+MU_GENERIC_TEST([$1],[$2],[$4],[],[$5],[$6])
+m4_popdef([MU_TEST_COMMAND])
+m4_popdef([MU_TEST_KEYWORDS])
+m4_popdef([MU_TEST_GROUP])
+])
+
+dnl ------------------------------------------------------------
+dnl The first part reproduces legacy argcv tests
+dnl ------------------------------------------------------------
+
+TESTWSP([simple input],[],[],
+[1 2 3],
+[NF: 3
+0: 1
+1: 2
+2: 3
+])
+
+TESTWSP([quoted space],[],[],
+[quoted\ space],
+[NF: 1
+0: "quoted space"
+])
+
+TESTWSP([tab character],[],[],
+[a "tab character"],
+[NF: 2
+0: a
+1: tab\tcharacter
+])
+
+TESTWSP([octal and hex escapes],[],[],
+[\157\143\164\141\154\40and\x20\x68\x65\x78],
+[NF: 1
+0: "octal and hex"
+])
+
+TESTWSP([octal and hex escapes 2],[],[],
+[\157\143\164\141\154\40 and \x20\x68\x65\x78],
+[NF: 3
+0: "octal "
+1: and
+2: " hex"
+])
+
+TESTWSP([escape representation],[],[],
+[A\x3-\48\39],
+[NF: 1
+0: A\003-\0048\0039
+])
+
+dnl ------------------------------------------------------------
+dnl Test worsplit-specific behavior
+dnl ------------------------------------------------------------
+TESTWSP([append],[],[append],
+[jeden dwa trzy
+cztery
+piec szesc],
+[NF: 3
+0: jeden
+1: dwa
+2: trzy
+NF: 4
+0: jeden
+1: dwa
+2: trzy
+3: cztery
+NF: 6
+0: jeden
+1: dwa
+2: trzy
+3: cztery
+4: piec
+5: szesc
+])
+
+TESTWSP([dooffs],[],[dooffs 3 jeden dwa trzy],
+[cztery piec],
+[NF: 2 (3)
+(0): jeden
+(1): dwa
+(2): trzy
+3: cztery
+4: piec
+])
+
+TESTWSP([variable substitutions: single var],[],[],
+[a $FOO test],
+[NF: 3
+0: a
+1: bar
+2: test
+],
+[],
+[FOO=bar])
+
+TESTWSP([variable substitutions: concatenated vars],[],[],
+[a $FOO${BAR}ent test],
+[NF: 3
+0: a
+1: stringent
+2: test
+],
+[],
+[FOO=str BAR=ing])
+
+TESTWSP([variable substitutions: field splitting],[],[],
+[a $FOO test],
+[NF: 4
+0: a
+1: variable
+2: substitution
+3: test
+],
+[],
+[FOO="variable substitution"])
+
+TESTWSP([variable substitutions: double-quoted variable],[],[],
+[a "$FOO" test],
+[NF: 3
+0: a
+1: "variable substitution"
+2: test
+],
+[],
+[FOO="variable substitution"])
+
+TESTWSP([variable substitutions: single-quoted variable],[],[],
+[a '$FOO' test],
+[NF: 3
+0: a
+1: $FOO
+2: test
+],
+[],
+[FOO="variable substitution"])
+
+TESTWSP([undefined variables 1],[],[],
+[a $FOO test a${FOO}b],
+[NF: 3
+0: a
+1: test
+2: ab
+],
+[],
+[unset FOO;])
+
+TESTWSP([undefined variables 2],[],[keepundef],
+[a $FOO test a${FOO}b],
+[NF: 4
+0: a
+1: $FOO
+2: test
+3: a${FOO}b
+],
+[],
+[unset FOO;])
+
+TESTWSP([warn about undefined variables],[],[warnundef],
+[$FOO],
+[NF: 0
+],
+[warning: undefined variable `FOO'
+],
+[unset FOO;])
+
+TESTWSP([bail out on undefined variables],[],[undef],
+[$FOO],
+[],
+[undefined variable
+],
+[unset FOO;])
+
+TESTWSP([disable variable expansion],[],[novar],
+[$FOO],
+[NF: 1
+0: $FOO
+],
+[],
+[FOO=bar])
+
+TESTWSP([nosplit with expansion],[],[nosplit],
+[a $FOO test],
+[NF: 1
+0: "a variable expansion test\n"
+],
+[],
+[FOO="variable expansion"])
+
+TESTWSP([nosplit without expansion],[],[nosplit novar],
+[a $FOO test],
+[NF: 1
+0: "a $FOO test\n"
+],
+[],
+[FOO="variable expansion"])
+
+TESTWSP([ignore quotes],[],[-quote],
+["a text"],
+[NF: 2
+0: "\"a"
+1: "text\""
+])
+
+TESTWSP([custom delimiters (squeeze)],[],[delim : -ws trimnl],
+[semicolon: separated::list: of :words],
+[NF: 5
+0: semicolon
+1: " separated"
+2: list
+3: " of "
+4: words
+])
+
+TESTWSP([custom delimiters (no squeeze)],[],[delim : -ws -squeeze_delims trimnl],
+[semicolon: separated::list: of :words],
+[NF: 6
+0: semicolon
+1: " separated"
+2: ""
+3: list
+4: " of "
+5: words
+])
+
+TESTWSP([custom, with returned delimiters],[],[delim : -ws trimnl return_delims],
+[semicolon: separated::list: of :words],
+[NF: 9
+0: semicolon
+1: :
+2: " separated"
+3: :
+4: list
+5: :
+6: " of "
+7: :
+8: words
+])
+
+TESTWSP([custom, with returned & squeezed delimiters],[],[delim : -ws trimnl return_delims -squeeze_delims],
+[semicolon: separated::list: of :words],
+[NF: 9
+0: semicolon
+1: :
+2: " separated"
+3: ::
+4: list
+5: :
+6: " of "
+7: :
+8: words
+])
+
+TESTWSP([sed expressions],[],[sed],
+[arg1 s/foo/bar/g;s/bar baz/quz quux/ arg2],
+[NF: 3
+0: arg1
+1: "s/foo/bar/g;s/bar baz/quz quux/"
+2: arg2
+])
+
+TESTWSP([C escapes on],[],[cescapes],
+[a\ttab form\ffeed and new\nline],
+[NF: 4
+0: a\ttab
+1: form\ffeed
+2: and
+3: new\nline
+])
+
+TESTWSP([C escapes off],[],[-cescapes],
+[a\ttab form\ffeed and new\nline],
+[NF: 4
+0: attab
+1: formffeed
+2: and
+3: newnline
+])
+
+m4_popdef([TESTWSP])
diff --git a/libmailutils/tests/wsp.c b/libmailutils/tests/wsp.c
new file mode 100644
index 000000000..095ce66b7
--- /dev/null
+++ b/libmailutils/tests/wsp.c
@@ -0,0 +1,285 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2005, 2007, 2009, 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/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <mailutils/wordsplit.h>
+#include <mailutils/kwd.h>
+#include <mailutils/errno.h>
+#include <mailutils/error.h>
+#include <mailutils/cstr.h>
+
+extern char **environ;
+
+struct mu_kwd bool_keytab[] = {
+ { "append", MU_WRDSF_APPEND },
+ /*{ "reuse", MU_WRDSF_REUSE },*/
+ { "undef", MU_WRDSF_UNDEF },
+ { "novar", MU_WRDSF_NOVAR },
+ { "ws", MU_WRDSF_WS },
+ { "quote", MU_WRDSF_QUOTE },
+ { "squeeze_delims", MU_WRDSF_SQUEEZE_DELIMS },
+ { "return_delims", MU_WRDSF_RETURN_DELIMS },
+ { "sed", MU_WRDSF_SED_EXPR },
+ { "debug", MU_WRDSF_SHOWDBG },
+ { "nosplit", MU_WRDSF_NOSPLIT },
+ { "keepundef", MU_WRDSF_KEEPUNDEF },
+ { "warnundef", MU_WRDSF_WARNUNDEF },
+ { "cescapes", MU_WRDSF_CESCAPES },
+ { "default", MU_WRDSF_DEFFLAGS },
+ { NULL, 0 }
+};
+
+struct mu_kwd string_keytab[] = {
+ { "delim", MU_WRDSF_DELIM },
+ { "comment", MU_WRDSF_COMMENT },
+ { NULL, 0 }
+};
+
+static void
+help ()
+{
+ size_t i;
+
+ printf ("usage: wsp [options]\n");
+ printf ("options are:\n");
+ printf (" [-]trimnl\n");
+ printf (" [-]plaintext\n");
+ putchar ('\n');
+ for (i = 0; bool_keytab[i].name; i++)
+ printf (" [-]%s\n", bool_keytab[i].name);
+ putchar ('\n');
+ for (i = 0; string_keytab[i].name; i++)
+ {
+ printf (" -%s\n", bool_keytab[i].name);
+ printf (" %s ARG\n", bool_keytab[i].name);
+ }
+ putchar ('\n');
+ printf (" -dooffs\n");
+ printf (" dooffs COUNT ARGS...\n");
+ exit (0);
+}
+
+void
+print_qword (const char *word, int plaintext)
+{
+ static char *qbuf = NULL;
+ static size_t qlen = 0;
+ int quote;
+ size_t size = mu_wordsplit_c_quoted_length (word, 0, &quote);
+
+ if (plaintext)
+ {
+ printf ("%s", word);
+ return;
+ }
+
+ if (*word == 0)
+ quote = 1;
+
+ if (size >= qlen)
+ {
+ qlen = size + 1;
+ qbuf = realloc (qbuf, qlen);
+ if (!qbuf)
+ {
+ mu_error ("not enough memory");
+ abort ();
+ }
+ }
+ mu_wordsplit_c_quote_copy (qbuf, word, 0);
+ qbuf[size] = 0;
+ if (quote)
+ printf ("\"%s\"", qbuf);
+ else
+ printf ("%s", qbuf);
+}
+
+int
+main (int argc, char **argv)
+{
+ char buf[1024];
+ int i, offarg = 0;
+ int trimnl_option = 0;
+ int plaintext_option = 0;
+ int wsflags = (MU_WRDSF_DEFFLAGS & ~MU_WRDSF_NOVAR) |
+ MU_WRDSF_ENOMEMABRT |
+ MU_WRDSF_ENV | MU_WRDSF_SHOWERR;
+ struct mu_wordsplit ws;
+
+ for (i = 1; i < argc; i++)
+ {
+ char *opt = argv[i];
+ int negate;
+ int flag;
+
+ if (opt[0] == '-')
+ {
+ negate = 1;
+ opt++;
+ }
+ else if (opt[0] == '+')
+ {
+ negate = 0;
+ opt++;
+ }
+ else
+ negate = 0;
+
+ if (strcmp (opt, "h") == 0 ||
+ strcmp (opt, "help") == 0 ||
+ strcmp (opt, "-help") == 0)
+ {
+ help ();
+ }
+
+ if (strcmp (opt, "trimnl") == 0)
+ {
+ trimnl_option = !negate;
+ continue;
+ }
+
+ if (strcmp (opt, "plaintext") == 0)
+ {
+ plaintext_option = !negate;
+ continue;
+ }
+
+ if (mu_kwd_xlat_name (bool_keytab, opt, &flag) == 0)
+ {
+ if (negate)
+ wsflags &= ~flag;
+ else
+ wsflags |= flag;
+ continue;
+ }
+
+ if (mu_kwd_xlat_name (string_keytab, opt, &flag) == 0)
+ {
+ if (negate)
+ wsflags &= ~flag;
+ else
+ {
+ i++;
+ if (i == argc)
+ {
+ mu_error ("%s missing argument", opt);
+ exit (1);
+ }
+
+ switch (flag)
+ {
+ case MU_WRDSF_DELIM:
+ ws.ws_delim = argv[i];
+ break;
+
+ case MU_WRDSF_COMMENT:
+ ws.ws_comment = argv[i];
+ break;
+ }
+
+ wsflags |= flag;
+ }
+ continue;
+ }
+
+ if (strcmp (opt, "dooffs") == 0)
+ {
+ if (negate)
+ wsflags &= ~MU_WRDSF_DOOFFS;
+ else
+ {
+ char *p;
+
+ i++;
+
+ if (i == argc)
+ {
+ mu_error ("%s missing arguments", opt);
+ exit (1);
+ }
+ ws.ws_offs = strtoul (argv[i], &p, 10);
+ if (*p)
+ {
+ mu_error ("invalid number: %s", argv[i]);
+ exit (1);
+ }
+
+ i++;
+ if (i + ws.ws_offs > argc)
+ {
+ mu_error ("%s: not enough arguments", opt);
+ exit (1);
+ }
+ offarg = i;
+ i += ws.ws_offs - 1;
+ wsflags |= MU_WRDSF_DOOFFS;
+ }
+ continue;
+ }
+
+ mu_error ("%s: unrecognized argument", opt);
+ exit (1);
+ }
+
+ ws.ws_env = (const char **) environ;
+
+ while (fgets (buf, sizeof (buf), stdin))
+ {
+ int rc;
+ size_t i;
+
+ if (trimnl_option)
+ mu_rtrim_cset (buf, "\n");
+ rc = mu_wordsplit (buf, &ws, wsflags);
+ if (rc)
+ {
+ if (!(wsflags & MU_WRDSF_SHOWERR))
+ mu_wordsplit_perror (&ws);
+ continue;
+ }
+
+ if (offarg)
+ {
+ for (i = 0; i < ws.ws_offs; i++)
+ ws.ws_wordv[i] = argv[offarg + i];
+ offarg = 0;
+ }
+
+ wsflags |= MU_WRDSF_REUSE;
+ printf ("NF: %lu", (unsigned long) ws.ws_wordc);
+ if (wsflags & MU_WRDSF_DOOFFS)
+ printf (" (%lu)", (unsigned long) ws.ws_offs);
+ putchar ('\n');
+ for (i = 0; i < ws.ws_offs; i++)
+ {
+ printf ("(%lu): ", (unsigned long) i);
+ print_qword (ws.ws_wordv[i], plaintext_option);
+ putchar ('\n');
+ }
+ for (; i < ws.ws_offs + ws.ws_wordc; i++)
+ {
+ printf ("%lu: ", (unsigned long) i);
+ print_qword (ws.ws_wordv[i], plaintext_option);
+ putchar ('\n');
+ }
+ }
+ return 0;
+}
diff --git a/libmailutils/url/copy.c b/libmailutils/url/copy.c
index 7190b4212..ee5ad47dd 100644
--- a/libmailutils/url/copy.c
+++ b/libmailutils/url/copy.c
@@ -24,7 +24,7 @@
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
-
+#include <stdlib.h>
#include <mailutils/types.h>
#include <mailutils/argcv.h>
#include <mailutils/secret.h>
diff --git a/libmailutils/url/create.c b/libmailutils/url/create.c
index 674a52469..0d0cb304d 100644
--- a/libmailutils/url/create.c
+++ b/libmailutils/url/create.c
@@ -26,10 +26,12 @@
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
+#include <stdlib.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <limits.h>
+#include <mailutils/wordsplit.h>
#include <mailutils/util.h>
#include <mailutils/errno.h>
#include <mailutils/argcv.h>
@@ -375,19 +377,24 @@ _mu_url_create_internal (struct mu_url_ctx *ctx, mu_url_t hint)
if ((ctx->flags & MU_URL_PARSE_PIPE) && ctx->input[0] == '|')
{
+ struct mu_wordsplit ws;
+
rc = str_assign (&url->scheme, "prog");
if (rc)
return rc;
url->flags |= MU_URL_SCHEME;
ctx->flags &= ~MU_URL_PARSE_HEXCODE;
- rc = mu_argcv_get (ctx->input + 1, NULL, NULL, &url->qargc, &url->qargv);
+ if (mu_wordsplit (ctx->input + 1, &ws, MU_WRDSF_DEFFLAGS))
+ return errno;
+ url->qargc = ws.ws_wordc;
+ url->qargv = ws.ws_wordv;
+ ws.ws_wordc = 0;
+ ws.ws_wordv = NULL;
+ mu_wordsplit_free (&ws);
+ url->flags |= MU_URL_QUERY;
+ rc = str_assign (&url->path, url->qargv[0]);
if (rc == 0)
- {
- url->flags |= MU_URL_QUERY;
- rc = str_assign (&url->path, url->qargv[0]);
- if (rc == 0)
- url->flags |= MU_URL_PATH;
- }
+ url->flags |= MU_URL_PATH;
}
else if ((ctx->flags & MU_URL_PARSE_SLASH) && ctx->input[0] == '/')
{
diff --git a/libmu_argp/muinit.c b/libmu_argp/muinit.c
index ab6e9c94d..7bffdea3b 100644
--- a/libmu_argp/muinit.c
+++ b/libmu_argp/muinit.c
@@ -22,6 +22,7 @@
#include <unistd.h>
#include <stdlib.h>
#include <mailutils/stream.h>
+#include <mailutils/io.h>
#include "xalloc.h"
#include <string.h>
#ifdef MU_ALPHA_RELEASE
diff --git a/libmu_auth/ldap.c b/libmu_auth/ldap.c
index 250aa4083..435c99df4 100644
--- a/libmu_auth/ldap.c
+++ b/libmu_auth/ldap.c
@@ -19,15 +19,18 @@
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
+#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <ctype.h>
#include <mailutils/mu_auth.h>
#include <mailutils/cstr.h>
+#include <mailutils/io.h>
#ifdef WITH_LDAP
#include "mailutils/argcv.h"
+#include "mailutils/wordsplit.h"
#include "mailutils/assoc.h"
#include "mailutils/list.h"
#include "mailutils/iterator.h"
@@ -129,10 +132,9 @@ _mu_conn_setup (LDAP **pld)
{
/* if no host but a DN is provided, try DNS SRV to gather the
host list */
- char *domain = NULL, *hostlist = NULL, **hosts = NULL;
- int hostcnt;
- int i;
- int len_proto = strlen(lud->lud_scheme);
+ char *domain = NULL, *hostlist = NULL;
+ size_t i;
+ struct mu_wordsplit ws;
if (ldap_dn2domain (lud->lud_dn, &domain) || !domain)
{
@@ -148,16 +150,15 @@ _mu_conn_setup (LDAP **pld)
domain);
goto dnssrv_free;
}
-
- rc = mu_argcv_get (hostlist, " ", NULL, &hostcnt, &hosts);
- if (rc)
+
+ if (mu_wordsplit (hostlist, &ws, MU_WRDSF_DEFFLAGS))
{
mu_error (_("DNS SRV: could not parse hostlist=\"%s\": %s"),
- hostlist, mu_strerror (rc));
+ hostlist, mu_wordsplit_strerror (&ws));
goto dnssrv_free;
}
- tmp = realloc (urls, sizeof(char *) * (nurls + hostcnt + 1));
+ tmp = realloc (urls, sizeof(char *) * (nurls + ws.ws_wordc + 1));
if (!tmp)
{
mu_error ("DNS SRV %s", mu_strerror (errno));
@@ -167,28 +168,23 @@ _mu_conn_setup (LDAP **pld)
urls = tmp;
urls[nurls] = NULL;
- for (i = 0; i < hostcnt; i++)
+ for (i = 0; i < ws.ws_wordc; i++)
{
- size_t len = len_proto + sizeof "://" - 1
- + strlen (hosts[i])
- + 1;
-
urls[nurls + i + 1] = NULL;
- urls[nurls + i] = malloc (len);
- if (!urls[nurls + i])
+ rc = mu_asprintf (&urls[nurls + i],
+ "%s://%s",
+ lud->lud_scheme, ws.ws_wordv[i]);
+ if (rc)
{
- mu_error ("DNS SRV %s", mu_strerror (errno));
+ mu_error ("DNS SRV %s", mu_strerror (rc));
goto dnssrv_free;
}
-
- snprintf (urls[nurls + i], len, "%s://%s",
- lud->lud_scheme, hosts[i]);
}
nurls += i;
dnssrv_free:
- mu_argcv_free (hostcnt, hosts);
+ mu_wordsplit_free (&ws);
ber_memfree (hostlist);
ber_memfree (domain);
}
diff --git a/libmu_auth/radius.c b/libmu_auth/radius.c
index 048a9c7ca..8c8a64816 100644
--- a/libmu_auth/radius.c
+++ b/libmu_auth/radius.c
@@ -35,13 +35,14 @@
#include <mailutils/iterator.h>
#include <mailutils/mailbox.h>
#include <mailutils/radius.h>
-#include <mailutils/argcv.h>
+#include <mailutils/wordsplit.h>
#include <mailutils/mu_auth.h>
#include <mailutils/error.h>
#include <mailutils/errno.h>
#include <mailutils/nls.h>
#include <mailutils/vartab.h>
#include <mailutils/io.h>
+#include <mailutils/cctype.h>
#ifdef ENABLE_RADIUS
@@ -87,9 +88,8 @@ enum parse_state
int
parse_pairlist (grad_avp_t **plist, char *input)
{
- int rc;
- int i, argc;
- char **argv;
+ size_t i;
+ struct mu_wordsplit ws;
enum parse_state state;
grad_locus_t loc;
char *name;
@@ -98,34 +98,38 @@ parse_pairlist (grad_avp_t **plist, char *input)
if (!input)
return 1;
- if ((rc = mu_argcv_get (input, ",", NULL, &argc, &argv)))
+ ws.ws_delim = ",";
+ if (mu_wordsplit (input, &ws,
+ MU_WRDSF_DEFFLAGS|MU_WRDSF_DELIM|MU_WRDSF_RETURN_DELIMS))
{
- mu_error (_("cannot parse input `%s': %s"), input, mu_strerror (rc));
+ mu_error (_("cannot parse input `%s': %s"), input,
+ mu_wordsplit_strerror (&ws));
return 1;
}
loc.file = "<configuration>"; /*FIXME*/
loc.line = 0;
- for (i = 0, state = state_lhs; i < argc; i++)
+ for (i = 0, state = state_lhs; i < ws.ws_wordc; i++)
{
grad_avp_t *pair;
switch (state)
{
case state_lhs:
- name = argv[i];
+ name = ws.ws_wordv[i];
state = state_op;
break;
case state_op:
- op = argv[i];
+ op = ws.ws_wordv[i];
state = state_rhs;
break;
case state_rhs:
loc.line = i; /* Just to keep track of error location */
- pair = grad_create_pair (&loc, name, grad_operator_equal, argv[i]);
+ pair = grad_create_pair (&loc, name, grad_operator_equal,
+ ws.ws_wordv[i]);
if (!pair)
{
mu_error (_("cannot create radius A/V pair `%s'"), name);
@@ -136,22 +140,22 @@ parse_pairlist (grad_avp_t **plist, char *input)
break;
case state_delim:
- if (strcmp (argv[i], ","))
+ if (strcmp (ws.ws_wordv[i], ","))
{
- mu_error (_("expected `,' but found `%s'"), argv[i]);
+ mu_error (_("expected `,' but found `%s'"), ws.ws_wordv[i]);
return 1;
}
state = state_lhs;
}
}
-
+ mu_wordsplit_free (&ws);
+
if (state != state_delim && state != state_delim)
{
mu_error (_("malformed radius A/V list"));
return 1;
}
- mu_argcv_free (argc, argv);
return 0;
}
diff --git a/libmu_sieve/sieve.l b/libmu_sieve/sieve.l
index 2f60e1384..27a92d42e 100644
--- a/libmu_sieve/sieve.l
+++ b/libmu_sieve/sieve.l
@@ -31,7 +31,7 @@
#include <errno.h>
#include <string.h>
#include <mailutils/cctype.h>
-#include <mailutils/argcv.h>
+#include <mailutils/wordsplit.h>
#include <sieve-priv.h>
#include <sieve-gram.h>
@@ -640,7 +640,7 @@ str_unescape (char *text, size_t len)
{
char *str = mu_sieve_alloc (len);
memcpy (str, text, len - 2);
- str[len - 2] = mu_argcv_unquote_char (text[len - 1]);
+ str[len - 2] = mu_wordsplit_c_unquote_char (text[len - 1]);
str[len - 1] = 0;
return str;
}
diff --git a/libproto/mailer/mbox.c b/libproto/mailer/mbox.c
index 1353d42fc..132e3d8df 100644
--- a/libproto/mailer/mbox.c
+++ b/libproto/mailer/mbox.c
@@ -29,7 +29,7 @@
#include <mailutils/mailer.h>
#include <mailutils/url.h>
#include <mailutils/util.h>
-#include <mailutils/argcv.h>
+#include <mailutils/wordsplit.h>
#include <mailutils/message.h>
#include <mailutils/envelope.h>
#include <mailutils/header.h>
@@ -124,8 +124,8 @@ static int
parse_received (mu_header_t hdr, char **sptr)
{
const char *recv;
- int wc, i;
- char **ws;
+ size_t i;
+ struct mu_wordsplit ws;
enum { rcv_init, rcv_from, rcv_by, rcv_for } state;
int status;
char *s;
@@ -134,27 +134,26 @@ parse_received (mu_header_t hdr, char **sptr)
status = mu_header_sget_value (hdr, MU_HEADER_RECEIVED, &recv);
if (status)
return status;
- status = mu_argcv_get (recv, NULL, NULL, &wc, &ws);
- if (status)
+ if (mu_wordsplit (recv, &ws, MU_WRDSF_DEFFLAGS))
return status;
state = rcv_init;
- for (i = 0; i < wc && state != rcv_for; i++)
+ for (i = 0; i < ws.ws_wordc && state != rcv_for; i++)
{
switch (state)
{
case rcv_init:
- if (strcmp (ws[i], "from") == 0)
+ if (strcmp (ws.ws_wordv[i], "from") == 0)
state = rcv_from;
break;
case rcv_from:
- if (strcmp (ws[i], "by") == 0)
+ if (strcmp (ws.ws_wordv[i], "by") == 0)
state = rcv_by;
break;
case rcv_by:
- if (strcmp (ws[i], "for") == 0)
+ if (strcmp (ws.ws_wordv[i], "for") == 0)
state = rcv_for;
break;
@@ -163,10 +162,10 @@ parse_received (mu_header_t hdr, char **sptr)
}
}
- if (state != rcv_for || ws[i] == NULL)
+ if (state != rcv_for || ws.ws_wordv[i] == NULL)
return MU_ERR_NOENT;
- s = ws[i];
+ s = ws.ws_wordv[i];
len = strlen (s);
if (s[len - 1] == ';')
len--;
@@ -183,7 +182,7 @@ parse_received (mu_header_t hdr, char **sptr)
memcpy (*sptr, s, len);
(*sptr)[len - 1] = 0;
}
- mu_argcv_free (wc, ws);
+ mu_wordsplit_free (&ws);
return status;
}
@@ -262,6 +261,7 @@ remote_mbox_append_message (mu_mailbox_t mbox, mu_message_t msg)
const char *hstr;
int hc;
char **hv;
+ struct mu_wordsplit ws;
if (mu_url_sget_param (mbox->url, "recipient-headers", &hstr) == 0)
{
@@ -272,10 +272,12 @@ remote_mbox_append_message (mu_mailbox_t mbox, mu_message_t msg)
}
else
{
- status = mu_argcv_get_np (hstr, strlen (hstr), ",", NULL, 0,
- &hc, &hv, NULL);
- if (status)
- return status;
+ ws.ws_delim = ",";
+ if (mu_wordsplit (hstr, &ws,
+ MU_WRDSF_DEFFLAGS|MU_WRDSF_DELIM|MU_WRDSF_WS))
+ return errno;
+ hc = 1;
+ hv = ws.ws_wordv;
}
}
else
@@ -286,7 +288,7 @@ remote_mbox_append_message (mu_mailbox_t mbox, mu_message_t msg)
status = guess_message_recipient (msg, hv, &rcpt);
if (hc)
- mu_argcv_free (hc, hv);
+ mu_wordsplit_free (&ws);
}
if (status != MU_ERR_NOENT)
diff --git a/libproto/mailer/smtp.c b/libproto/mailer/smtp.c
index 7196288f6..d4c5879d0 100644
--- a/libproto/mailer/smtp.c
+++ b/libproto/mailer/smtp.c
@@ -31,8 +31,9 @@
#include <string.h>
#include <unistd.h>
+#include <mailutils/nls.h>
#include <mailutils/address.h>
-#include <mailutils/argcv.h>
+#include <mailutils/wordsplit.h>
#include <mailutils/debug.h>
#include <mailutils/errno.h>
#include <mailutils/header.h>
@@ -95,18 +96,19 @@ struct _smtp_mailer
static void
smtp_mailer_add_auth_mech (struct _smtp_mailer *smtp_mailer, const char *str)
{
- int mc, i, rc;
- char **mv;
-
- rc = mu_argcv_get_np (str, strlen (str),
- ",", NULL,
- 0,
- &mc, &mv, NULL);
- if (rc == 0)
- for (i = 0; i < mc; i++)
- mu_smtp_add_auth_mech (smtp_mailer->smtp, mv[i]);
-
- free (mv);
+ struct mu_wordsplit ws;
+
+ ws.ws_delim = ",";
+ if (mu_wordsplit (str, &ws, MU_WRDSF_DEFFLAGS|MU_WRDSF_DELIM|MU_WRDSF_WS))
+ mu_error (_("cannot split line `%s': %s"), str,
+ mu_wordsplit_strerror (&ws));
+ else
+ {
+ size_t i;
+ for (i = 0; i < ws.ws_wordc; i++)
+ mu_smtp_add_auth_mech (smtp_mailer->smtp, ws.ws_wordv[i]);
+ mu_wordsplit_free (&ws);
+ }
}
static int
diff --git a/libproto/mailer/smtp_gsasl.c b/libproto/mailer/smtp_gsasl.c
index b8e26382f..ccf1a7ff2 100644
--- a/libproto/mailer/smtp_gsasl.c
+++ b/libproto/mailer/smtp_gsasl.c
@@ -21,7 +21,8 @@
#include <errno.h>
#include <stdlib.h>
#include <string.h>
-#include <mailutils/argcv.h>
+#include <mailutils/nls.h>
+#include <mailutils/wordsplit.h>
#include <mailutils/diag.h>
#include <mailutils/errno.h>
#include <mailutils/cctype.h>
@@ -39,9 +40,8 @@ get_implemented_mechs (Gsasl *ctx, mu_list_t *plist)
char *listmech;
mu_list_t supp = NULL;
int rc;
- int mechc;
- char **mechv;
-
+ struct mu_wordsplit ws;
+
rc = gsasl_server_mechlist (ctx, &listmech);
if (rc != GSASL_OK)
{
@@ -51,19 +51,26 @@ get_implemented_mechs (Gsasl *ctx, mu_list_t *plist)
return 1;
}
- rc = mu_argcv_get (listmech, "", NULL, &mechc, &mechv);
- if (rc == 0)
+ if (mu_wordsplit (listmech, &ws, MU_WRDSF_DEFFLAGS))
{
- int i;
-
+ mu_error (_("cannot split line `%s': %s"), listmech,
+ mu_wordsplit_strerror (&ws));
+ rc = errno;
+ }
+ else
+ {
+ size_t i;
+
rc = mu_list_create (&supp);
if (rc == 0)
{
mu_list_set_destroy_item (supp, mu_list_free_item);
- for (i = 0; i < mechc; i++)
- mu_list_append (supp, mechv[i]);
+ for (i = 0; i < ws.ws_wordc; i++)
+ mu_list_append (supp, ws.ws_wordv[i]);
}
- free (mechv);
+ ws.ws_wordc = 0;
+ ws.ws_wordv = NULL;
+ mu_wordsplit_free (&ws);
}
free (listmech);
*plist = supp;
diff --git a/mail/mail.h b/mail/mail.h
index 3b33a521b..0c344ea85 100644
--- a/mail/mail.h
+++ b/mail/mail.h
@@ -77,6 +77,7 @@
#include <mailutils/nls.h>
#include <mailutils/tls.h>
#include <mailutils/argcv.h>
+#include <mailutils/wordsplit.h>
#include <mailutils/cctype.h>
#include <mailutils/cstr.h>
#include <mailutils/io.h>
diff --git a/mail/mailline.c b/mail/mailline.c
index 95e32433d..c420757e4 100644
--- a/mail/mailline.c
+++ b/mail/mailline.c
@@ -230,32 +230,38 @@ ml_reread (const char *prompt, char **text)
char **
ml_command_completion (char *cmd, int start, int end)
{
- int argc;
- char **argv;
char **ret;
char *p;
-
+ struct mu_wordsplit ws;
+
for (p = rl_line_buffer; p < rl_line_buffer + start && mu_isblank (*p); p++)
;
-
- if (mu_argcv_get_n (p, end, NULL, NULL, &argc, &argv))
- return NULL;
+
+ if (mu_wordsplit_len (p, end, &ws, MU_WRDSF_DEFFLAGS))
+ {
+ mu_error (_("mu_wordsplit_len failed: %s"),
+ mu_wordsplit_strerror (&ws));
+ return NULL;
+ }
rl_completion_append_character = ' ';
- if (argc == 0 || (argc == 1 && strlen (argv[0]) <= end - start))
+ if (ws.ws_wordc == 0 ||
+ (ws.ws_wordc == 1 && strlen (ws.ws_wordv[0]) <= end - start))
{
ret = rl_completion_matches (cmd, ml_command_generator);
rl_attempted_completion_over = 1;
}
else
{
- const struct mail_command_entry *entry = mail_find_command (argv[0]);
+ const struct mail_command_entry *entry =
+ mail_find_command (ws.ws_wordv[0]);
if (entry && entry->command_completion)
- ret = entry->command_completion (argc, argv, start == end);
+ ret = entry->command_completion (ws.ws_wordc, ws.ws_wordv,
+ start == end);
else
ret = NULL;
}
- mu_argcv_free (argc, argv);
+ mu_wordsplit_free (&ws);
return ret;
}
diff --git a/mail/mailvar.c b/mail/mailvar.c
index 7f163ae9b..4980d4c9b 100644
--- a/mail/mailvar.c
+++ b/mail/mailvar.c
@@ -579,9 +579,7 @@ set_mailbox_debug_level (mu_log_level_t level)
static void
set_debug (struct mailvar_variable *var)
{
- int rc;
- int argc;
- char **argv;
+ struct mu_wordsplit ws;
int i;
mu_debug_t dbg;
@@ -600,19 +598,25 @@ set_debug (struct mailvar_variable *var)
}
mu_diag_get_debug (&dbg);
-
- rc = mu_argcv_get (var->value.string, ";", NULL, &argc, &argv);
- if (rc)
+
+ ws.ws_delim = ";";
+
+ if (mu_wordsplit (var->value.string, &ws,
+ MU_WRDSF_NOCMD | MU_WRDSF_NOVAR |
+ MU_WRDSF_SQUEEZE_DELIMS |
+ MU_WRDSF_DELIM | MU_WRDSF_WS |
+ MU_WRDSF_ERROR))
{
- mu_error (_("Cannot parse string: %s"), mu_strerror (rc));
+ mu_error (_("%s failed: %s"), "mu_wordsplit",
+ mu_wordsplit_strerror (&ws));
return;
}
- for (i = 0; i < argc; i++)
+ for (i = 0; i < ws.ws_wordc; i++)
{
char *p;
mu_log_level_t level = MU_DEBUG_INHERIT;
- char *object_name = argv[i];
+ char *object_name = ws.ws_wordv[i];
for (p = object_name; *p && *p != '='; p++)
;
@@ -629,6 +633,7 @@ set_debug (struct mailvar_variable *var)
set_mailbox_debug_level (level);
mu_global_debug_set_level (object_name, level);
}
+ mu_wordsplit_free (&ws);
}
diff --git a/mail/send.c b/mail/send.c
index 618f6a8b8..4594309ab 100644
--- a/mail/send.c
+++ b/mail/send.c
@@ -504,32 +504,33 @@ mail_send0 (compose_env_t * env, int save_to)
}
else
{
- int argc;
- char **argv;
+ struct mu_wordsplit ws;
int status;
ofile = env->file;
- if (mu_argcv_get (buf + 1, "", NULL, &argc, &argv) == 0)
+ if (mu_wordsplit (buf + 1, &ws, MU_WRDSF_DEFFLAGS) == 0)
{
- if (argc > 0)
+ if (ws.ws_wordc > 0)
{
const struct mail_escape_entry *entry =
- mail_find_escape (argv[0]);
+ mail_find_escape (ws.ws_wordv[0]);
if (entry)
- status = (*entry->escfunc) (argc, argv, env);
+ status = (*entry->escfunc) (ws.ws_wordc, ws.ws_wordv,
+ env);
else
- util_error (_("Unknown escape %s"), argv[0]);
+ util_error (_("Unknown escape %s"), ws.ws_wordv[0]);
}
else
util_error (_("Unfinished escape"));
+ mu_wordsplit_free (&ws);
}
else
{
- util_error (_("Cannot parse escape sequence"));
+ util_error (_("Cannot parse escape sequence: %s"),
+ mu_wordsplit_strerror (&ws));
}
- mu_argcv_free (argc, argv);
ofile = env->ofile;
}
diff --git a/mail/util.c b/mail/util.c
index f337fe7d3..393504ac1 100644
--- a/mail/util.c
+++ b/mail/util.c
@@ -40,8 +40,9 @@
int
util_do_command (const char *fmt, ...)
{
- int argc = 0;
- char **argv = NULL;
+ struct mu_wordsplit ws;
+ int argc;
+ char **argv;
int status = 0;
const struct mail_command_entry *entry = NULL;
char *cmd = NULL;
@@ -76,19 +77,29 @@ util_do_command (const char *fmt, ...)
return 0;
}
- if (mu_argcv_get (cmd, NULL, NULL, &argc, &argv) == 0 && argc > 0)
+ ws.ws_offs = 1; /* Keep one extra slot in case we need it
+ for expansion (see below) */
+ if (mu_wordsplit (cmd, &ws, MU_WRDSF_DEFFLAGS|MU_WRDSF_DOOFFS))
+ {
+ mu_error (_("%s failed: %s"), "mu_wordsplit",
+ mu_wordsplit_strerror (&ws));
+ }
+ else
{
char *p;
+ argc = ws.ws_wordc;
+ argv = ws.ws_wordv + 1;
+
/* Special case: a number alone implies "print" */
if (argc == 1
&& ((strtoul (argv[0], &p, 10) > 0 && *p == 0)
|| (argv[0][1] == 0 && strchr("^$", argv[0][0]))))
{
- mu_asprintf (&p, "print %s", argv[0]);
- mu_argcv_free (argc, argv);
- mu_argcv_get (p, NULL, NULL, &argc, &argv);
- free (p);
+ /* Use the extra slot for "print" command */
+ argc++;
+ argv--;
+ argv[0] = "print";
}
entry = mail_find_command (argv[0]);
@@ -114,12 +125,16 @@ util_do_command (const char *fmt, ...)
if (strlen (p))
{
+ /* Expand contracted form. That's what we have kept an extra
+ ws slot for. */
argc++;
- argv = xrealloc (argv, (argc + 1)*sizeof argv[0]);
- if (argc > 2)
- memmove (argv + 2, argv + 1, (argc - 2)*sizeof argv[0]);
+ argv--;
+ argv[0] = argv[1];
argv[1] = xstrdup (p);
*p = 0;
+ /* Register the new entry in WS */
+ ws.ws_wordc++;
+ ws.ws_offs = 0;
}
entry = mail_find_command (argv[0]);
@@ -140,7 +155,7 @@ util_do_command (const char *fmt, ...)
status = 1;
}
- mu_argcv_free (argc, argv);
+ mu_wordsplit_free (&ws);
return status;
}
diff --git a/mh/folder.c b/mh/folder.c
index 6175594ef..5dba885aa 100644
--- a/mh/folder.c
+++ b/mh/folder.c
@@ -519,18 +519,27 @@ action_list ()
static void
get_stack (int *pc, char ***pv)
{
- int status;
+ struct mu_wordsplit ws;
const char *stack = mh_global_context_get ("Folder-Stack", NULL);
if (!stack)
{
*pc = 0;
*pv = NULL;
}
- else if ((status = mu_argcv_get (stack, NULL, "#", pc, pv)) != 0)
+ else if (mu_wordsplit (stack, &ws, MU_WRDSF_DEFFLAGS))
{
- mu_diag_funcall (MU_DIAG_ERROR, "mu_argcv_get", stack, status);
+ mu_error (_("cannot split line `%s': %s"), stack,
+ mu_wordsplit_strerror (&ws));
exit (1);
}
+ else
+ {
+ *pc = ws.ws_wordc;
+ *pv = ws.ws_wordv;
+ ws.ws_wordc = 0;
+ ws.ws_wordv = NULL;
+ mu_wordsplit_free (&ws);
+ }
}
static void
@@ -762,26 +771,32 @@ pack_xlate (struct pack_tab *pack_tab, size_t count, size_t n)
static int
_fixup (const char *name, const char *value, struct fixup_data *fd, int flags)
{
- int i, j, argc;
- char **argv;
+ size_t i, j;
+ struct mu_wordsplit ws;
mh_msgset_t msgset;
if (verbose)
fprintf (stderr, "Sequence `%s'...\n", name);
-
- if (mu_argcv_get (value, "", NULL, &argc, &argv))
- return 0;
- msgset.list = xcalloc (argc, sizeof msgset.list[0]);
- for (i = j = 0; i < argc; i++)
+ if (mu_wordsplit (value, &ws, MU_WRDSF_DEFFLAGS))
+ {
+ mu_error (_("cannot split line `%s': %s"), value,
+ mu_wordsplit_strerror (&ws));
+ return 0;
+ }
+
+ msgset.list = xcalloc (ws.ws_wordc, sizeof msgset.list[0]);
+ for (i = j = 0; i < ws.ws_wordc; i++)
{
size_t n = pack_xlate (fd->pack_tab, fd->count,
- strtoul (argv[i], NULL, 0));
+ strtoul (ws.ws_wordv[i], NULL, 0));
if (n)
msgset.list[j++] = n;
}
msgset.count = j;
+ mu_wordsplit_free (&ws);
+
mh_seq_add (name, &msgset, flags | SEQ_ZERO);
free (msgset.list);
diff --git a/mh/mh.h b/mh/mh.h
index 0ed009c89..17289c0c3 100644
--- a/mh/mh.h
+++ b/mh/mh.h
@@ -49,6 +49,7 @@
#include <mailutils/errno.h>
#include <mailutils/nls.h>
#include <mailutils/argcv.h>
+#include <mailutils/wordsplit.h>
#include <mailutils/debug.h>
#include <mailutils/mailer.h>
#include <mailutils/envelope.h>
diff --git a/mh/mh_alias.y b/mh/mh_alias.y
index e34509cf6..d89f24abb 100644
--- a/mh/mh_alias.y
+++ b/mh/mh_alias.y
@@ -496,16 +496,20 @@ mh_read_aliases ()
p = mh_global_profile_get ("Aliasfile", NULL);
if (p)
{
- int argc;
- char **argv;
- int rc = mu_argcv_get (p, NULL, NULL, &argc, &argv);
- if (rc == 0)
+ struct mu_wordsplit ws;
+
+ if (mu_wordsplit (p, &ws, MU_WRDSF_DEFFLAGS))
+ {
+ mu_error (_("cannot split line `%s': %s"), p,
+ mu_wordsplit_strerror (&ws));
+ }
+ else
{
- int i;
- for (i = 0; i < argc; i++)
- mh_alias_read (argv[i], 1);
+ size_t i;
+ for (i = 0; i < ws.ws_wordc; i++)
+ mh_alias_read (ws.ws_wordv[i], 1);
+ mu_wordsplit_free (&ws);
}
- mu_argcv_free (argc, argv);
}
mh_alias_read (DEFAULT_ALIAS_FILE, 0);
return 0;
diff --git a/mh/mh_argp.c b/mh/mh_argp.c
index 8978d4c15..dff019b47 100644
--- a/mh/mh_argp.c
+++ b/mh/mh_argp.c
@@ -219,24 +219,31 @@ mh_argp_parse (int *pargc, char **pargv[],
{
int argc;
char **argv;
- int xargc;
- char **xargv;
int i, j;
+ struct mu_wordsplit ws;
- mu_argcv_get (val, "", NULL, &xargc, &xargv);
+ if (mu_wordsplit (val, &ws, MU_WRDSF_DEFFLAGS))
+ {
+ mu_error (_("cannot split line `%s': %s"), val,
+ mu_wordsplit_strerror (&ws));
+ exit (1);
+ }
- argc = *pargc + xargc;
- argv = calloc (argc+1, sizeof *argv);
+ argc = *pargc + ws.ws_wordc;
+ argv = calloc (argc + 1, sizeof *argv);
if (!argv)
mh_err_memory (1);
i = 0;
argv[i++] = (*pargv)[0];
- for (j = 0; j < xargc; i++, j++)
- argv[i] = xargv[j];
+ for (j = 0; j < ws.ws_wordc; i++, j++)
+ argv[i] = ws.ws_wordv[j];
for (j = 1; i < argc; i++, j++)
argv[i] = (*pargv)[j];
argv[i] = NULL;
+
+ ws.ws_wordc = 0;
+ mu_wordsplit_free (&ws);
mh_argv_preproc (argc, argv, &data);
@@ -246,7 +253,6 @@ mh_argp_parse (int *pargc, char **pargv[],
*pargc = argc;
*pargv = argv;
- free (xargv);
}
else
{
diff --git a/mh/mh_init.c b/mh/mh_init.c
index 1f64cc3aa..8fc0bda87 100644
--- a/mh/mh_init.c
+++ b/mh/mh_init.c
@@ -539,33 +539,36 @@ mh_iterate (mu_mailbox_t mbox, mh_msgset_t *msgset,
int
mh_spawnp (const char *prog, const char *file)
{
- int argc, i, rc, status;
- char **argv, **xargv;
+ struct mu_wordsplit ws;
+ size_t i;
+ int rc, status;
+ char **xargv;
- if ((rc = mu_argcv_get (prog, "", "#", &argc, &argv)) != 0)
+ ws.ws_comment = "#";
+ if (mu_wordsplit (prog, &ws, MU_WRDSF_DEFFLAGS | MU_WRDSF_COMMENT))
{
- mu_diag_funcall (MU_DIAG_ERROR, "mu_argcv_get", prog, rc);
- mu_argcv_free (argc, argv);
+ mu_error (_("cannot split line `%s': %s"), prog,
+ mu_wordsplit_strerror (&ws));
return 1;
}
- xargv = calloc (argc + 2, sizeof (*xargv));
+ xargv = calloc (ws.ws_wordc + 2, sizeof (*xargv));
if (!xargv)
{
mh_err_memory (0);
- mu_argcv_free (argc, argv);
+ mu_wordsplit_free (&ws);
return 1;
}
- for (i = 0; i < argc; i++)
- xargv[i] = argv[i];
+ for (i = 0; i < ws.ws_wordc; i++)
+ xargv[i] = ws.ws_wordv[i];
xargv[i++] = (char*) file;
xargv[i++] = NULL;
-
+
rc = mu_spawnvp (xargv[0], xargv, &status);
free (xargv);
- mu_argcv_free (argc, argv);
+ mu_wordsplit_free (&ws);
return rc;
}
diff --git a/mh/mh_list.c b/mh/mh_list.c
index a414574b3..86b3c9604 100644
--- a/mh/mh_list.c
+++ b/mh/mh_list.c
@@ -149,42 +149,45 @@ parse_component (locus_t *loc, mu_list_t formlist, char *compname, char *str)
static void
parse_variable (locus_t *loc, mu_list_t formlist, char *str)
{
- int i, rc;
- int argc;
- char **argv;
+ size_t i;
+ struct mu_wordsplit ws;
mh_format_t fmt;
-
- if ((rc = mu_argcv_get (str, ",=", NULL, &argc, &argv)) != 0)
+
+ ws.ws_delim = ",=";
+ if (mu_wordsplit (str, &ws,
+ MU_WRDSF_DEFFLAGS|MU_WRDSF_DELIM|
+ MU_WRDSF_WS|MU_WRDSF_RETURN_DELIMS))
{
- mu_error ("%s:%d: mu_argcv_get(%s): %s",
+ mu_error ("%s:%d: mu_wordsplit(%s): %s",
loc->filename,
loc->line,
str,
- mu_strerror (rc));
+ mu_wordsplit_strerror (&ws));
exit (1);
}
- for (i = 0; i < argc; i++)
+ for (i = 0; i < ws.ws_wordc; i++)
{
- mhl_stmt_t *stmt = stmt_alloc (stmt_variable);
- char *name = argv[i];
+ mhl_stmt_t *stmt;
+ char *name = ws.ws_wordv[i];
char *value = NULL;
mhl_variable_t *var;
-
+
+ stmt = stmt_alloc (stmt_variable);
var = variable_lookup (name);
if (!var)
{
mu_error (_("%s:%d: unknown variable: %s"),
loc->filename,
loc->line,
- argv[i]);
+ name);
exit (1);
}
- if (i + 1 < argc && argv[i+1][0] == '=')
+ if (i + 1 < ws.ws_wordc && ws.ws_wordv[i+1][0] == '=')
{
i++;
- value = argv[++i];
+ value = ws.ws_wordv[++i];
}
if ((var->type == dt_flag && value)
@@ -227,14 +230,13 @@ parse_variable (locus_t *loc, mu_list_t formlist, char *str)
mu_list_append (formlist, stmt);
i++;
- if (i < argc && argv[i][0] != ',')
+ if (i < ws.ws_wordc && ws.ws_wordv[i][0] != ',')
{
mu_error (_("%s:%d: syntax error"), loc->filename, loc->line);
exit (1);
}
}
-
- mu_argcv_free (argc, argv);
+ mu_wordsplit_free (&ws);
}
static int
diff --git a/mh/mh_msgset.c b/mh/mh_msgset.c
index fdf5df28c..41eb03629 100644
--- a/mh/mh_msgset.c
+++ b/mh/mh_msgset.c
@@ -235,8 +235,7 @@ static int _mh_msgset_parse (mu_mailbox_t mbox, mh_msgset_t *msgset,
int
expand_user_seq (mu_mailbox_t mbox, mh_msgset_t *msgset, char *arg)
{
- int argc;
- char **argv;
+ struct mu_wordsplit ws;
char *p;
const char *listp;
int rc = 1;
@@ -260,10 +259,18 @@ expand_user_seq (mu_mailbox_t mbox, mh_msgset_t *msgset, char *arg)
if (!listp)
return 1;
}
+
+ if (mu_wordsplit (listp, &ws, MU_WRDSF_DEFFLAGS))
+ {
+ mu_error (_("cannot split line `%s': %s"), listp,
+ mu_wordsplit_strerror (&ws));
+ }
+ else
+ {
+ rc = _mh_msgset_parse (mbox, msgset, ws.ws_wordc, ws.ws_wordv);
+ mu_wordsplit_free (&ws);
+ }
- if (mu_argcv_get (listp, "", NULL, &argc, &argv) == 0)
- rc = _mh_msgset_parse (mbox, msgset, argc, argv);
- mu_argcv_free (argc, argv);
if (rc)
return rc;
diff --git a/mh/mh_sequence.c b/mh/mh_sequence.c
index 737461a51..f80b85549 100644
--- a/mh/mh_sequence.c
+++ b/mh/mh_sequence.c
@@ -124,19 +124,23 @@ mh_seq_delete (const char *name, mh_msgset_t *mset, int flags)
const char *value = mh_seq_read (name, flags);
char *new_val;
char *p;
- int argc, i, count;
- char **argv;
+ size_t i, count;
+ struct mu_wordsplit ws;
if (!value)
return 0;
- if (mu_argcv_get (value, "", NULL, &argc, &argv))
- return 0;
+ if (mu_wordsplit (value, &ws, MU_WRDSF_DEFFLAGS))
+ {
+ mu_error (_("cannot split line `%s': %s"), value,
+ mu_wordsplit_strerror (&ws));
+ return 0;
+ }
- for (i = 0; i < argc; i++)
+ for (i = 0; i < ws.ws_wordc; i++)
{
char *p;
- size_t num = strtoul (argv[i], &p, 10);
+ size_t num = strtoul (ws.ws_wordv[i], &p, 10);
if (*p)
continue;
@@ -144,19 +148,19 @@ mh_seq_delete (const char *name, mh_msgset_t *mset, int flags)
if (bsearch (&num, mset->list, mset->count, sizeof (mset->list[0]),
cmp_msgnum))
{
- free (argv[i]);
- argv[i] = NULL;
+ free (ws.ws_wordv[i]);
+ ws.ws_wordv[i] = NULL;
}
}
new_val = xstrdup (value);
p = new_val;
count = 0;
- for (i = 0; i < argc; i++)
+ for (i = 0; i < ws.ws_wordc; i++)
{
- if (argv[i])
+ if (ws.ws_wordv[i])
{
- strcpy (p, argv[i]);
+ strcpy (p, ws.ws_wordv[i]);
p += strlen (p);
*p++ = ' ';
count++;
@@ -164,7 +168,7 @@ mh_seq_delete (const char *name, mh_msgset_t *mset, int flags)
}
*p = 0;
write_sequence (name, count > 0 ? new_val : NULL, flags & SEQ_PRIVATE);
- mu_argcv_free (argc, argv);
+ mu_wordsplit_free (&ws);
free (new_val);
return 0;
diff --git a/mh/mh_whatnow.c b/mh/mh_whatnow.c
index 672481083..6582fd8b3 100644
--- a/mh/mh_whatnow.c
+++ b/mh/mh_whatnow.c
@@ -328,28 +328,30 @@ _whatnow (struct mh_whatnow_env *wh, struct action_tab *tab)
{
char *line = NULL;
size_t size = 0;
- int argc;
- char **argv;
+ struct mu_wordsplit ws;
handler_fp fun;
printf ("%s ", wh->prompt);
getline (&line, &size, stdin);
if (!line)
continue;
- rc = mu_argcv_get (line, "", "#", &argc, &argv);
+
+ ws.ws_comment = "#";
+ rc = mu_wordsplit (line, &ws, MU_WRDSF_DEFFLAGS|MU_WRDSF_COMMENT);
free (line);
if (rc)
{
- mu_argcv_free (argc, argv);
+ mu_error (_("cannot split line `%s': %s"), line,
+ mu_wordsplit_strerror (&ws));
break;
}
- fun = func (tab, argv[0]);
+ fun = func (tab, ws.ws_wordv[0]);
if (fun)
- rc = fun (wh, argc, argv, &status);
+ rc = fun (wh, ws.ws_wordc, ws.ws_wordv, &status);
else
rc = 0;
- mu_argcv_free (argc, argv);
+ mu_wordsplit_free (&ws);
}
while (rc == 0);
return status;
diff --git a/mh/mhn.c b/mh/mhn.c
index 5aef07ff5..bc240cbde 100644
--- a/mh/mhn.c
+++ b/mh/mhn.c
@@ -881,26 +881,24 @@ mhn_store_command (mu_message_t msg, msg_part_t part, char *name)
static void
split_args (char *argstr, int *pargc, char ***pargv)
{
- int argc;
- char **argv;
+ struct mu_wordsplit ws;
- if (mu_argcv_get (argstr, ";", NULL, &argc, &argv) == 0)
+ ws.ws_delim = ";";
+ if (mu_wordsplit (argstr, &ws,
+ MU_WRDSF_DEFFLAGS | MU_WRDSF_DELIM | MU_WRDSF_WS))
{
- int i, j;
-
- for (i = j = 0; i < argc; i++)
- {
- if (argv[i][0] != ';')
- argv[j++] = argv[i];
- }
- argv[j] = NULL;
- *pargc = j;
- *pargv = argv;
+ mu_error (_("cannot split line `%s': %s"), argstr,
+ mu_wordsplit_strerror (&ws));
+ *pargc = 0;
+ *pargv = NULL;
}
else
{
- *pargc = 0;
- *pargv = NULL;
+ *pargc = ws.ws_wordc;
+ *pargv = ws.ws_wordv;
+ ws.ws_wordc = 0;
+ ws.ws_wordv = NULL;
+ mu_wordsplit_free (&ws);
}
}
@@ -1303,13 +1301,14 @@ mhn_run_command (mu_message_t msg, msg_part_t part,
{
/* pass content via a tempfile */
int status;
- int argc;
- char **argv;
mu_stream_t tmp;
-
- if (mu_argcv_get (cmd, "", "#", &argc, &argv))
+ struct mu_wordsplit ws;
+
+ ws.ws_comment = "#";
+ if (mu_wordsplit (cmd, &ws, MU_WRDSF_DEFFLAGS | MU_WRDSF_COMMENT))
{
- mu_error (_("cannot parse command line `%s'"), cmd);
+ mu_error (_("cannot parse command line `%s': %s"), cmd,
+ mu_wordsplit_strerror (&ws));
return ENOSYS;
}
@@ -1318,15 +1317,15 @@ mhn_run_command (mu_message_t msg, msg_part_t part,
{
mu_error (_("cannot create temporary stream (file %s): %s"),
tempfile, mu_strerror (rc));
- mu_argcv_free (argc, argv);
+ mu_wordsplit_free (&ws);
return rc;
}
show_internal (msg, part, encoding, tmp);
mu_stream_destroy (&tmp);
- rc = mu_spawnvp (argv[0], argv, &status);
+ rc = mu_spawnvp (ws.ws_wordv[0], ws.ws_wordv, &status);
if (status)
rc = status;
- mu_argcv_free (argc, argv);
+ mu_wordsplit_free (&ws);
}
else
rc = exec_internal (msg, part, encoding, cmd, flags);
@@ -2044,8 +2043,8 @@ edit_forw (char *cmd, struct compose_env *env, mu_message_t *pmsg, int level)
{
char *sp, *id = NULL, *descr = NULL;
int stop = 0, status = 0;
- int i, argc;
- char **argv;
+ size_t i;
+ struct mu_wordsplit ws;
mu_header_t hdr;
mu_mime_t mime;
mu_message_t msg;
@@ -2090,18 +2089,21 @@ edit_forw (char *cmd, struct compose_env *env, mu_message_t *pmsg, int level)
if (status)
return status;
- if (mu_argcv_get (cmd, "\n", NULL, &argc, &argv))
+ ws.ws_delim = "\n";
+ if (mu_wordsplit (cmd, &ws,
+ MU_WRDSF_DEFFLAGS | MU_WRDSF_DELIM | MU_WRDSF_WS))
{
- mu_error (_("%s:%lu: syntax error"),
+ mu_error (_("%s:%lu: cannot split line: %s"),
input_file,
- (unsigned long) mhn_error_loc (env));
+ (unsigned long) mhn_error_loc (env),
+ mu_wordsplit_strerror (&ws));
return 1;
}
mu_mime_create (&mime, NULL, 0);
- mbox = mh_open_folder (argv[0], 0);
- for (i = 1; i < argc; i++)
+ mbox = mh_open_folder (ws.ws_wordv[0], 0);
+ for (i = 1; i < ws.ws_wordc; i++)
{
mu_message_t input_msg;
if (mh_get_message (mbox, i, &input_msg) == 0)
@@ -2117,7 +2119,7 @@ edit_forw (char *cmd, struct compose_env *env, mu_message_t *pmsg, int level)
break;
mu_mime_add_part (mime, msg);
}
- mu_argcv_free (argc, argv);
+ mu_wordsplit_free (&ws);
if (*pmsg)
{
diff --git a/mh/send.c b/mh/send.c
index ef39d8403..faece4ef9 100644
--- a/mh/send.c
+++ b/mh/send.c
@@ -497,49 +497,53 @@ fix_fcc (mu_message_t msg)
mu_message_get_header (msg, &hdr);
if (mu_header_aget_value (hdr, MU_HEADER_FCC, &fcc) == 0)
{
- int i, argc;
- char **argv;
+ struct mu_wordsplit ws;
int need_fixup = 0;
size_t fixup_len = 0;
-
- mu_argcv_get (fcc, ",", NULL, &argc, &argv);
- for (i = 0; i < argc; i += 2)
+
+ ws.ws_delim = ",";
+ if (mu_wordsplit (fcc, &ws,
+ MU_WRDSF_DEFFLAGS | MU_WRDSF_DELIM | MU_WRDSF_WS))
{
- if (strchr ("+%~/=", argv[i][0]) == NULL)
- {
- need_fixup++;
- fixup_len ++;
- }
- fixup_len += strlen (argv[i]);
+ mu_error (_("cannot split line `%s': %s"), fcc,
+ mu_wordsplit_strerror (&ws));
}
-
- if (need_fixup)
+ else
{
- char *p;
-
- /* the new fcc string contains: folder names - fixup_len characters
- long, (argc - 2)/2 comma-space pairs and a terminating
- nul */
- fcc = realloc (fcc, fixup_len + argc - 2 + 1);
- for (i = 0, p = fcc; i < argc; i++)
+ size_t i;
+
+ for (i = 0; i < ws.ws_wordc; i += 2)
{
- if (i % 2 == 0)
+ if (strchr ("+%~/=", ws.ws_wordv[i][0]) == NULL)
{
- if (strchr ("+%~/=", argv[i][0]) == NULL)
- *p++ = '+';
- strcpy (p, argv[i]);
- p += strlen (argv[i]);
+ need_fixup++;
+ fixup_len ++;
}
- else
+ fixup_len += strlen (ws.ws_wordv[i]);
+ }
+
+ if (need_fixup)
+ {
+ char *p;
+
+ /* the new fcc string contains: folder names - fixup_len
+ characters, ws.ws_wordc - 1 comma-space pairs and a
+ terminating nul */
+ fcc = realloc (fcc, fixup_len + ws.ws_wordc - 1 + 1);
+ for (i = 0, p = fcc; i < ws.ws_wordc; i++)
{
+ if (strchr ("+%~/=", ws.ws_wordv[i][0]) == NULL)
+ *p++ = '+';
+ strcpy (p, ws.ws_wordv[i]);
+ p += strlen (p);
*p++ = ',';
*p++ = ' ';
}
+ *p = 0;
}
- *p = 0;
}
- mu_argcv_free (argc, argv);
+ mu_wordsplit_free (&ws);
if (need_fixup)
{
diff --git a/movemail/movemail.c b/movemail/movemail.c
index d03082895..61daad6c5 100644
--- a/movemail/movemail.c
+++ b/movemail/movemail.c
@@ -267,23 +267,21 @@ cb_mailbox_ownership (mu_debug_t debug, void *data, mu_config_value_t *val)
return _cb_mailbox_ownership (debug, str);
else
{
- int argc;
- char **argv;
+ struct mu_wordsplit ws;
- if (mu_argcv_get_np (str, strlen (str), ",", NULL, 0,
- &argc, &argv, NULL))
+ ws.ws_delim = ",";
+ if (mu_wordsplit (str, &ws, MU_WRDSF_DEFFLAGS|MU_WRDSF_DELIM))
{
mu_cfg_format_error (debug, MU_DEBUG_ERROR,
- _("cannot parse %s"),
- str);
+ _("cannot parse %s: %s"),
+ str, mu_wordsplit_strerror (&ws));
return 1;
}
- for (i = 0; i < argc; i++)
- if (_cb_mailbox_ownership (debug, argv[i]))
+ for (i = 0; i < ws.ws_wordc; i++)
+ if (_cb_mailbox_ownership (debug, ws.ws_wordv[i]))
return 1;
-
- mu_argcv_free (argc, argv);
+ mu_wordsplit_free (&ws);
return 0;
}
}
diff --git a/mu/shell.c b/mu/shell.c
index 9497b3d02..910a13a32 100644
--- a/mu/shell.c
+++ b/mu/shell.c
@@ -238,13 +238,12 @@ shell_help (int argc, char **argv)
static int
shell_prompt (int argc, char **argv)
{
- int quote;
size_t size;
free (mutool_shell_prompt);
- size = mu_argcv_quoted_length (argv[1], &quote);
+ size = strlen (argv[1]);
mutool_shell_prompt = xmalloc (size + 1);
- mu_argcv_unquote_copy (mutool_shell_prompt, argv[1], size);
+ mu_wordsplit_c_unquote_copy (mutool_shell_prompt, argv[1], size);
return 0;
}
@@ -460,16 +459,22 @@ add_history (const char *s MU_ARG_UNUSED)
int
execute_line (char *line)
{
+ struct mu_wordsplit ws;
int argc;
char **argv;
int status = 0;
- if (mu_argcv_get (line, NULL, "#", &argc, &argv))
+ ws.ws_comment = "#";
+ ws.ws_offs = 1; /* Keep extra slot for expansion in case when argmin == -1 */
+ if (mu_wordsplit (line, &ws,
+ MU_WRDSF_DEFFLAGS|MU_WRDSF_COMMENT|MU_WRDSF_DOOFFS))
{
- mu_error("cannot parse input line");
+ mu_error("cannot parse input line: %s", mu_wordsplit_strerror (&ws));
return 0;
}
-
+ argc = ws.ws_wordc;
+ argv = ws.ws_wordv + 1;
+
if (argc >= 0)
{
struct mutool_command *cmd = find_command (argv[0]);
@@ -484,6 +489,7 @@ execute_line (char *line)
{
if (cmd->argmin <= 0 && argc != 2)
{
+ size_t i;
char *word = mu_str_skip_class (line, MU_CTYPE_SPACE);
char *arg = mu_str_skip_class_comp (word, MU_CTYPE_SPACE);
if (*arg)
@@ -491,18 +497,19 @@ execute_line (char *line)
*arg++ = 0;
arg = mu_str_skip_class (arg, MU_CTYPE_SPACE);
}
-
- mu_argcv_free (argc, argv);
- argc = 2;
- argv = xcalloc (argc + 1, sizeof (argv[0]));
- argv[0] = xstrdup (word);
- argv[1] = xstrdup (arg);
- argv[2] = NULL;
+ for (i = 0; i < ws.ws_wordc; i++)
+ free (ws.ws_wordv[i + 1]);
+ ws.ws_wordv[0] = xstrdup (word);
+ ws.ws_wordv[1] = xstrdup (arg);
+ ws.ws_wordv[2] = NULL;
+ ws.ws_wordc = 2;
+ argc = ws.ws_wordc;
+ argv = ws.ws_wordv;
}
status = cmd->func (argc, argv);
}
}
- mu_argcv_free (argc, argv);
+ mu_wordsplit_free (&ws);
return status;
}
diff --git a/po/POTFILES.in b/po/POTFILES.in
index fc1e8b14b..2201ad13d 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -129,7 +129,10 @@ libmailutils/diag/diag.c
libmailutils/diag/errors
libmailutils/diag/gdebug.c
+libmailutils/server/acl.c
+
libmailutils/stream/file_stream.c
+libmailutils/stream/prog_stream.c
libmailutils/filter/filter_iconv.c
@@ -137,6 +140,9 @@ libmailutils/server/ipsrv.c
libmailutils/server/msrv.c
libmailutils/mailbox/message.c
+libmailutils/mailer/mailer.c
+libmailutils/mailer/smtp.c
+libmailutils/mailer/smtp_gsasl.c
libmailutils/auth/mu_auth.c
diff --git a/pop3d/popauth.c b/pop3d/popauth.c
index b22cb66a8..2c9d75e0a 100644
--- a/pop3d/popauth.c
+++ b/pop3d/popauth.c
@@ -16,7 +16,6 @@
along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
#include "pop3d.h"
-#include <mailutils/argcv.h>
#include <xalloc.h>
#include "mailutils/libargp.h"
@@ -30,6 +29,7 @@ int db_make (char *input_name, char *output_name);
#define ACT_CHPASS 4
static int permissions = 0600;
+static int compatibility_option = 0;
struct action_data {
int action;
@@ -60,6 +60,8 @@ static error_t popauth_parse_opt (int key, char *arg,
void popauth_version (FILE *stream, struct argp_state *state);
+#define COMPATIBILITY_OPTION 256
+
static struct argp_option options[] =
{
{ NULL, 0, NULL, 0, N_("Actions are:"), 1 },
@@ -80,6 +82,8 @@ static struct argp_option options[] =
{ "password", 'p', N_("STRING"), 0, N_("specify user's password"), 3 },
{ "user", 'u', N_("USERNAME"), 0, N_("specify user name"), 3 },
{ "permissions", 'P', N_("PERM"), 0, N_("force given permissions on the database"), 3 },
+ { "compatibility", COMPATIBILITY_OPTION, NULL, 0,
+ N_("backward compatibility mode") },
{ NULL, }
};
@@ -171,7 +175,11 @@ popauth_parse_opt (int key, char *arg, struct argp_state *astate)
case 'P':
set_db_perms (astate, arg, &permissions);
break;
-
+
+ case COMPATIBILITY_OPTION:
+ compatibility_option = 1;
+ break;
+
case ARGP_KEY_FINI:
if (ap->action == -1)
{
@@ -269,6 +277,23 @@ check_user_perm (int action, struct action_data *ap)
return 1;
}
+static void
+print_entry (FILE *fp, DBM_DATUM key, DBM_DATUM contents)
+{
+ if (compatibility_option)
+ fprintf (fp, "%.*s: %.*s\n",
+ (int) MU_DATUM_SIZE (key),
+ (char*) MU_DATUM_PTR (key),
+ (int) MU_DATUM_SIZE (contents),
+ (char*) MU_DATUM_PTR (contents));
+ else
+ fprintf (fp, "%.*s %.*s\n",
+ (int) MU_DATUM_SIZE (key),
+ (char*) MU_DATUM_PTR (key),
+ (int) MU_DATUM_SIZE (contents),
+ (char*) MU_DATUM_PTR (contents));
+}
+
int
action_list (struct action_data *ap)
{
@@ -309,11 +334,7 @@ action_list (struct action_data *ap)
}
else
{
- fprintf (fp, "%.*s: %.*s\n",
- (int) MU_DATUM_SIZE (key),
- (char*) MU_DATUM_PTR (key),
- (int) MU_DATUM_SIZE (contents),
- (char*) MU_DATUM_PTR (contents));
+ print_entry (fp, key, contents);
mu_dbm_datum_free (&contents);
}
}
@@ -324,11 +345,7 @@ action_list (struct action_data *ap)
{
memset (&contents, 0, sizeof contents);
mu_dbm_fetch (db, key, &contents);
- fprintf (fp, "%.*s: %.*s\n",
- (int) MU_DATUM_SIZE (key),
- (char*) MU_DATUM_PTR (key),
- (int) MU_DATUM_SIZE (contents),
- (char*) MU_DATUM_PTR (contents));
+ print_entry (fp, key, contents);
mu_dbm_datum_free (&contents);
}
}
@@ -341,85 +358,89 @@ action_list (struct action_data *ap)
int
action_create (struct action_data *ap)
{
- FILE *fp;
+ int rc;
+ mu_stream_t in;
DBM_FILE db;
DBM_DATUM key;
DBM_DATUM contents;
- char buf[256];
+ char *buf = NULL;
+ size_t size = 0, len;
int line = 0;
-
+
/* Make sure we have proper privileges if popauth is setuid */
setuid (getuid ());
if (ap->input_name)
{
- fp = fopen (ap->input_name, "r");
- if (!fp)
+ rc = mu_file_stream_create (&in, ap->input_name, MU_STREAM_READ);
+ if (rc)
{
mu_error (_("cannot open file %s: %s"),
- ap->input_name, mu_strerror (errno));
+ ap->input_name, mu_strerror (rc));
return 1;
}
}
else
{
ap->input_name = "";
- fp = stdin;
+ rc = mu_stdio_stream_create (&in, MU_STDIN_FD, MU_STREAM_READ);
+ if (rc)
+ {
+ mu_error (_("cannot open standard input: %s"),
+ mu_strerror (rc));
+ return 1;
+ }
}
if (!ap->output_name)
ap->output_name = APOP_PASSFILE;
if (mu_dbm_open (ap->output_name, &db, MU_STREAM_CREAT, permissions))
{
- mu_error (_("cannot create database %s: %s"), ap->output_name, mu_strerror (errno));
+ mu_error (_("cannot create database %s: %s"),
+ ap->output_name, mu_strerror (errno));
return 1;
}
line = 0;
- while (fgets (buf, sizeof buf - 1, fp))
+ while ((rc = mu_stream_getline (in, &buf, &size, &len)) == 0
+ && len > 0)
{
- int len;
- int argc;
- char **argv;
+ char *str, *pass;
- len = strlen (buf);
- if (buf[len-1] == '\n')
- buf[--len] = 0;
-
line++;
- if (mu_argcv_get (buf, ":", NULL, &argc, &argv))
- {
- mu_argcv_free (argc, argv);
- continue;
- }
-
- if (argc == 0 || argv[0][0] == '#')
+ str = mu_str_stripws (buf);
+ if (*str == 0 || *str == '#')
+ continue;
+ pass = mu_str_skip_class_comp (str, MU_CTYPE_SPACE);
+ if (*pass == 0)
{
- mu_argcv_free (argc, argv);
+ mu_error (_("%s:%d: malformed line"), ap->input_name, line);
continue;
}
-
- if (argc != 3 || argv[1][0] != ':' || argv[1][1] != 0)
+ /* Strip trailing semicolon, when in compatibility mode. */
+ if (compatibility_option && pass > str && pass[-1] == ':')
+ pass[-1] = 0;
+ *pass++ = 0;
+ pass = mu_str_skip_class (pass, MU_CTYPE_SPACE);
+ if (*pass == 0)
{
mu_error (_("%s:%d: malformed line"), ap->input_name, line);
- mu_argcv_free (argc, argv);
continue;
}
-
+
memset (&key, 0, sizeof key);
memset (&contents, 0, sizeof contents);
- MU_DATUM_PTR (key) = argv[0];
- MU_DATUM_SIZE (key) = strlen (argv[0]);
- MU_DATUM_PTR (contents) = argv[2];
- MU_DATUM_SIZE (contents) = strlen (argv[2]);
+ MU_DATUM_PTR (key) = str;
+ MU_DATUM_SIZE (key) = strlen (str);
+ MU_DATUM_PTR (contents) = pass;
+ MU_DATUM_SIZE (contents) = strlen (pass);
if (mu_dbm_insert (db, key, contents, 1))
mu_error (_("%s:%d: cannot store datum"), ap->input_name, line);
-
- mu_argcv_free (argc, argv);
}
+ free (buf);
mu_dbm_close (db);
- fclose (fp);
+ mu_stream_destroy (&in);
return 0;
}
diff --git a/readmsg/readmsg.c b/readmsg/readmsg.c
index db603291d..a354070ed 100644
--- a/readmsg/readmsg.c
+++ b/readmsg/readmsg.c
@@ -297,6 +297,7 @@ main (int argc, char **argv)
int i;
int index;
mu_mailbox_t mbox = NULL;
+ struct mu_wordsplit ws;
char **weedv;
int weedc;
int unix_header = 0;
@@ -351,27 +352,32 @@ main (int argc, char **argv)
if (weedlist == NULL)
weedlist = "Date To Cc Subject From Apparently-";
- status = mu_argcv_get (weedlist, WEEDLIST_SEPARATOR, NULL,
- &weedc, &weedv);
+ ws.ws_delim = WEEDLIST_SEPARATOR;
+ status = mu_wordsplit (weedlist, &ws, MU_WRDSF_DEFFLAGS | MU_WRDSF_DELIM);
if (status)
{
- mu_error (_("cannot parse weedlist: %s"), mu_strerror (status));
+ mu_error (_("cannot parse weedlist: %s"), mu_wordsplit_strerror (&ws));
exit (2);
}
- for (i = 0; i < weedc; i++)
+ if (ws.ws_wordc)
{
- if (mu_c_strcasecmp (weedv[i], "From_") == 0)
+ for (i = 0; i < ws.ws_wordc; i++)
{
- int j;
- unix_header = 1;
- free (weedv[i]);
- for (j = i; j < weedc; j++)
- weedv[j] = weedv[j+1];
- weedc--;
- if (weedc == 0 && !all_header)
- no_header = 1;
+ if (mu_c_strcasecmp (ws.ws_wordv[i], "From_") == 0)
+ {
+ int j;
+ unix_header = 1;
+ free (ws.ws_wordv[i]);
+ for (j = i; j < ws.ws_wordc; j++)
+ ws.ws_wordv[j] = ws.ws_wordv[j+1];
+ ws.ws_wordc--;
+ if (ws.ws_wordc == 0 && !all_header)
+ no_header = 1;
+ }
}
+ weedc = ws.ws_wordc;
+ weedv = ws.ws_wordv;
}
if (all_header)
diff --git a/readmsg/readmsg.h b/readmsg/readmsg.h
index e0fde21b1..1fc97dafc 100644
--- a/readmsg/readmsg.h
+++ b/readmsg/readmsg.h
@@ -48,7 +48,7 @@
#include <mailutils/tls.h>
#include <mailutils/error.h>
#include <mailutils/envelope.h>
-#include <mailutils/argcv.h>
+#include <mailutils/wordsplit.h>
#include <mailutils/util.h>
int msglist (mu_mailbox_t mbox, int show_all, int argc, char **argv, int **set, int *n);
diff --git a/testsuite/smtpsend.c b/testsuite/smtpsend.c
index a716c3d64..c77e7037d 100644
--- a/testsuite/smtpsend.c
+++ b/testsuite/smtpsend.c
@@ -51,8 +51,8 @@ send_rcpt_command (void *item, void *data)
static void
update_list (mu_list_t *plist, const char *arg)
{
- int mc, j;
- char **mv;
+ size_t j;
+ struct mu_wordsplit ws;
mu_list_t list = *plist;
if (!list)
@@ -61,13 +61,16 @@ update_list (mu_list_t *plist, const char *arg)
*plist = list;
}
- MU_ASSERT (mu_argcv_get_np (arg, strlen (arg),
- ",", NULL,
- 0,
- &mc, &mv, NULL));
- for (j = 0; j < mc; j++)
- MU_ASSERT (mu_list_append (list, mv[j]));
- free (mv);
+ ws.ws_delim = ",";
+ if (mu_wordsplit (arg, &ws, MU_WRDSF_DEFFLAGS | MU_WRDSF_DELIM))
+ {
+ mu_error ("mu_wordsplit: %s", mu_wordsplit_strerror (&ws));
+ exit (1);
+ }
+ for (j = 0; j < ws.ws_wordc; j++)
+ MU_ASSERT (mu_list_append (list, ws.ws_wordv[j]));
+ ws.ws_wordc = 0;
+ mu_wordsplit_free (&ws);
}
static int

Return to:

Send suggestions and report system problems to the System administrator.