2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-09-03 15:45:24 +00:00

postfix-3.8-20230406

This commit is contained in:
Wietse Venema
2023-04-06 00:00:00 -05:00
committed by Viktor Dukhovni
parent 7b4ef3b6e1
commit 8c9a1f419c
13 changed files with 250 additions and 45 deletions

View File

@@ -26990,11 +26990,13 @@ Apologies for any names omitted.
20230330 20230330
Safety: the long form { name = value } in import_environment Safety: the long form { name = value } in import_environment
or export_environment is not documented, but accepted, and or export_environment is not documented, but it is accepted,
it was stored in the process environment as the invalid and it was stored in the process environment as the invalid
form "name = value" instead of the expected "name=value". form "name = value, thus not setting or overriding an entry
Found during code maintenance. Also refined an "empty name" for "name". This form is now stored as the expected
check. Files: clean_env.c, split_nameval.c. "name=value". Found during code maintenance. Also refined
the "missing attribute name" detection. Files: clean_env.c,
split_nameval.c.
20230402 20230402
@@ -27014,3 +27016,23 @@ Apologies for any names omitted.
example, inline maps. Added Valgrind support to the namadr_list example, inline maps. Added Valgrind support to the namadr_list
unit test. Files: util/match_list.c, global/namadr_list.in, unit test. Files: util/match_list.c, global/namadr_list.in,
util/Makefile.in. util/Makefile.in.
20240406
Bugfix (introduced: 20230402): after a change in the DNS_RR
structure, the dns_rr_copy() function had not been updated,
causing the Postfix SMTP client to panic as it detected a
double-free() attempt. Reported by Florian Piekert. File:
dns/dns_rr.c.
Usability: Postfix does not support #comments after other
text, but people add them anyway, with unexpected results.
The postconf command now warns for trailing comments in
main.cf files. Similar warnings are planned for database
client configuration files. Files: util/mystrtok.c,
util/mystrtok.ref, util/match_list.c, global/namadr_list.ref,
postconf/postconf_dbms.c, postconf/test71.ref.
TODO: #comment after text in DB client configuration files.
TOIDO: test for dns_rr_copy() + dns_rr_free().

View File

@@ -1800,3 +1800,4 @@ Stringify
bitcount bitcount
bytecount bytecount
ipproto ipproto
cw

View File

@@ -160,6 +160,9 @@ DNS_RR *dns_rr_create(const char *qname, const char *rname,
{ {
DNS_RR *rr; DNS_RR *rr;
/*
* Note: if this function is changed, update dns_rr_copy().
*/
rr = (DNS_RR *) mymalloc(sizeof(*rr)); rr = (DNS_RR *) mymalloc(sizeof(*rr));
rr->qname = mystrdup(qname); rr->qname = mystrdup(qname);
rr->rname = mystrdup(rname); rr->rname = mystrdup(rname);
@@ -200,16 +203,17 @@ void dns_rr_free(DNS_RR *rr)
DNS_RR *dns_rr_copy(DNS_RR *src) DNS_RR *dns_rr_copy(DNS_RR *src)
{ {
ssize_t len = sizeof(*src) + src->data_len - 1;
DNS_RR *dst; DNS_RR *dst;
/* /*
* Combine struct assignment and data copy in one block copy operation. * Note: struct copy, because dns_rr_create() would not copy all fields.
*/ */
dst = (DNS_RR *) mymalloc(len); dst = (DNS_RR *) mymalloc(sizeof(*dst));
memcpy((void *) dst, (void *) src, len); memcpy((void *) dst, (void *) src, sizeof(*dst));
dst->qname = mystrdup(src->qname); dst->qname = mystrdup(src->qname);
dst->rname = mystrdup(src->rname); dst->rname = mystrdup(src->rname);
if (dst->data)
dst->data = mymemdup(dst->data, dst->data_len);
dst->next = 0; dst->next = 0;
return (dst); return (dst);
} }

View File

@@ -20,7 +20,7 @@
* Patches change both the patchlevel and the release date. Snapshots have no * Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only. * patchlevel; they change the release date only.
*/ */
#define MAIL_RELEASE_DATE "20230402" #define MAIL_RELEASE_DATE "20230406"
#define MAIL_VERSION_NUMBER "3.8" #define MAIL_VERSION_NUMBER "3.8"
#ifdef SNAPSHOT #ifdef SNAPSHOT

View File

@@ -51,9 +51,9 @@ bar/168.100.3.3: ERROR
./namadr_list: warning: non-existent:/tmp/nosuchfile is unavailable. open file /tmp/nosuchfile: No such file or directory ./namadr_list: warning: non-existent:/tmp/nosuchfile is unavailable. open file /tmp/nosuchfile: No such file or directory
./namadr_list: warning: command line: non-existent:/tmp/nosuchfile: table lookup problem ./namadr_list: warning: command line: non-existent:/tmp/nosuchfile: table lookup problem
bar/168.100.3.3: ERROR bar/168.100.3.3: ERROR
./namadr_list: warning: command line: comment at end of line is not supported: #text ./namadr_list: warning: command line: #comment after other text is not allowed: #text ...
foo/1.2.3.4: YES foo/1.2.3.4: YES
./namadr_list: warning: command line: comment at end of line is not supported: #text ./namadr_list: warning: command line: #comment after other text is not allowed: #text ...
fool/1.2.3.4: NO fool/1.2.3.4: NO
foo/1.2.3.4: YES foo/1.2.3.4: YES
bar/1.2.3.4: YES bar/1.2.3.4: YES

View File

@@ -55,7 +55,7 @@ tests: test1 test2 test3 test4 test5 test6 test7 test8 test9 test10 test11 \
test31 test32 test33 test34 test35 test36 test37 test39 test40 test41 \ test31 test32 test33 test34 test35 test36 test37 test39 test40 test41 \
test42 test43 test44 test45 test46 test47 test48 test49 test50 test51 \ test42 test43 test44 test45 test46 test47 test48 test49 test50 test51 \
test52 test53 test54 test55 test56 test57 test58 test59 test60 test61 \ test52 test53 test54 test55 test56 test57 test58 test59 test60 test61 \
test62 test63 test64 test65 test66 test67 test68 test69 test70 test62 test63 test64 test65 test66 test67 test68 test69 test70 test71
root_tests: root_tests:
@@ -964,7 +964,24 @@ test70: $(PROG) test70.ref
touch -t 197101010000 main.cf touch -t 197101010000 main.cf
$(HTABLE_FIX) $(SHLIB_ENV) $(VALGRIND) ./$(PROG) -nc . >test70.tmp 2>&1 $(HTABLE_FIX) $(SHLIB_ENV) $(VALGRIND) ./$(PROG) -nc . >test70.tmp 2>&1
diff test70.ref test70.tmp diff test70.ref test70.tmp
rm -f main.cf master.cf test70.tmp test70.cf rm -f main.cf master.cf test70.tmp
test71: $(PROG) test71.ref
rm -f main.cf master.cf
touch main.cf master.cf
echo "smtpd_client_restrictions = inline:{" >>main.cf
echo " { aaa0 = #aaa1 } #aaa2" >>main.cf
echo " }" >>main.cf
echo "smtpd_helo_restrictions = pcre:{" >>main.cf
echo " { /bbb0 #bbb1/ } #bbb2" >>main.cf
echo " }" >>main.cf
echo "smtpd_sender_restrictions = regexp:{" >>main.cf
echo " { /ccc0 #ccc1/ } #ccc2" >>main.cf
echo " }" >>main.cf
touch -t 197101010000 main.cf
$(HTABLE_FIX) $(SHLIB_ENV) $(VALGRIND) ./$(PROG) -nc . >test71.tmp 2>&1
diff test71.ref test71.tmp
rm -f main.cf master.cf test71.tmp
printfck: $(OBJS) $(PROG) printfck: $(OBJS) $(PROG)
rm -rf printfck rm -rf printfck
@@ -1072,8 +1089,10 @@ postconf_dbms.o: ../../include/dict_ht.h
postconf_dbms.o: ../../include/dict_ldap.h postconf_dbms.o: ../../include/dict_ldap.h
postconf_dbms.o: ../../include/dict_memcache.h postconf_dbms.o: ../../include/dict_memcache.h
postconf_dbms.o: ../../include/dict_mysql.h postconf_dbms.o: ../../include/dict_mysql.h
postconf_dbms.o: ../../include/dict_pcre.h
postconf_dbms.o: ../../include/dict_pgsql.h postconf_dbms.o: ../../include/dict_pgsql.h
postconf_dbms.o: ../../include/dict_proxy.h postconf_dbms.o: ../../include/dict_proxy.h
postconf_dbms.o: ../../include/dict_regexp.h
postconf_dbms.o: ../../include/dict_sqlite.h postconf_dbms.o: ../../include/dict_sqlite.h
postconf_dbms.o: ../../include/htable.h postconf_dbms.o: ../../include/htable.h
postconf_dbms.o: ../../include/mac_expand.h postconf_dbms.o: ../../include/mac_expand.h

View File

@@ -48,6 +48,8 @@
/* Google, Inc. /* Google, Inc.
/* 111 8th Avenue /* 111 8th Avenue
/* New York, NY 10011, USA /* New York, NY 10011, USA
/*
/* Wietse Venema
/*--*/ /*--*/
/* System library. */ /* System library. */
@@ -77,6 +79,8 @@
#include <dict_pgsql.h> #include <dict_pgsql.h>
#include <dict_sqlite.h> #include <dict_sqlite.h>
#include <dict_memcache.h> #include <dict_memcache.h>
#include <dict_regexp.h>
#include <dict_pcre.h>
/* Application-specific. */ /* Application-specific. */
@@ -134,18 +138,31 @@ static const char *pcf_memcache_suffixes[] = {
*/ */
typedef struct { typedef struct {
const char *db_type; const char *db_type;
int db_class;
const char **db_suffixes; const char **db_suffixes;
} PCF_DBMS_INFO; } PCF_DBMS_INFO;
#define PCF_DBMS_CLASS_CLIENT (1) /* DB name is client config path */
#define PCF_DBMS_CLASS_REGEX (2) /* DB name contains regex patterns */
static const PCF_DBMS_INFO pcf_dbms_info[] = { static const PCF_DBMS_INFO pcf_dbms_info[] = {
DICT_TYPE_LDAP, pcf_ldap_suffixes, {DICT_TYPE_LDAP, PCF_DBMS_CLASS_CLIENT, pcf_ldap_suffixes},
DICT_TYPE_MYSQL, pcf_mysql_suffixes, {DICT_TYPE_MYSQL, PCF_DBMS_CLASS_CLIENT, pcf_mysql_suffixes},
DICT_TYPE_PGSQL, pcf_pgsql_suffixes, {DICT_TYPE_PGSQL, PCF_DBMS_CLASS_CLIENT, pcf_pgsql_suffixes},
DICT_TYPE_SQLITE, pcf_sqlite_suffixes, {DICT_TYPE_SQLITE, PCF_DBMS_CLASS_CLIENT, pcf_sqlite_suffixes},
DICT_TYPE_MEMCACHE, pcf_memcache_suffixes, {DICT_TYPE_MEMCACHE, PCF_DBMS_CLASS_CLIENT, pcf_memcache_suffixes},
0, {DICT_TYPE_REGEXP, PCF_DBMS_CLASS_REGEX},
{DICT_TYPE_PCRE, PCF_DBMS_CLASS_REGEX},
{0},
}; };
/*
* Workaround to prevent a false warning about "#comment after other text",
* when an inline pcre or regexp pattern contains "#text".
*/
#define PCF_DBMS_RECURSE 1 /* Parse inline {map-entry} */
#define PCF_DBMS_NO_RECURSE 0 /* Don't parse inline {map-entry} */
/* pcf_check_dbms_client - look for unused names in client configuration */ /* pcf_check_dbms_client - look for unused names in client configuration */
static void pcf_check_dbms_client(const PCF_DBMS_INFO *dp, const char *cf_file) static void pcf_check_dbms_client(const PCF_DBMS_INFO *dp, const char *cf_file)
@@ -216,7 +233,8 @@ static void pcf_check_dbms_client(const PCF_DBMS_INFO *dp, const char *cf_file)
static void pcf_register_dbms_helper(char *str_value, static void pcf_register_dbms_helper(char *str_value,
const char *(flag_parameter) (const char *, int, PCF_MASTER_ENT *), const char *(flag_parameter) (const char *, int, PCF_MASTER_ENT *),
PCF_MASTER_ENT *local_scope) PCF_MASTER_ENT *local_scope,
int recurse)
{ {
const PCF_DBMS_INFO *dp; const PCF_DBMS_INFO *dp;
char *db_type; char *db_type;
@@ -229,7 +247,8 @@ static void pcf_register_dbms_helper(char *str_value,
* Naive parsing. We don't really know if this substring specifies a * Naive parsing. We don't really know if this substring specifies a
* database or some other text. * database or some other text.
*/ */
while ((db_type = mystrtokq(&str_value, CHARS_COMMA_SP, CHARS_BRACE)) != 0) { while ((db_type = mystrtokq_cw(&str_value, CHARS_COMMA_SP, CHARS_BRACE,
local_scope ? MASTER_CONF_FILE : MAIN_CONF_FILE)) != 0) {
if (*db_type == CHARS_BRACE[0]) { if (*db_type == CHARS_BRACE[0]) {
if ((err = extpar(&db_type, CHARS_BRACE, EXTPAR_FLAG_NONE)) != 0) { if ((err = extpar(&db_type, CHARS_BRACE, EXTPAR_FLAG_NONE)) != 0) {
/* XXX Encapsulate this in pcf_warn() function. */ /* XXX Encapsulate this in pcf_warn() function. */
@@ -240,7 +259,9 @@ static void pcf_register_dbms_helper(char *str_value,
msg_warn("%s: %s", MAIN_CONF_FILE, err); msg_warn("%s: %s", MAIN_CONF_FILE, err);
myfree(err); myfree(err);
} }
pcf_register_dbms_helper(db_type, flag_parameter, local_scope); if (recurse)
pcf_register_dbms_helper(db_type, flag_parameter, local_scope,
recurse);
continue; continue;
} }
@@ -267,7 +288,8 @@ static void pcf_register_dbms_helper(char *str_value,
if (*prefix == '/') { if (*prefix == '/') {
for (dp = pcf_dbms_info; dp->db_type != 0; dp++) { for (dp = pcf_dbms_info; dp->db_type != 0; dp++) {
if (strcmp(db_type, dp->db_type) == 0) { if (strcmp(db_type, dp->db_type) == 0) {
pcf_check_dbms_client(dp, prefix); if (dp->db_class == PCF_DBMS_CLASS_CLIENT)
pcf_check_dbms_client(dp, prefix);
break; break;
} }
} }
@@ -282,6 +304,8 @@ static void pcf_register_dbms_helper(char *str_value,
* local or global namespace. * local or global namespace.
*/ */
if (*prefix != '.') { if (*prefix != '.') {
int next_recurse = recurse;
if (*prefix == CHARS_BRACE[0]) { if (*prefix == CHARS_BRACE[0]) {
if ((err = extpar(&prefix, CHARS_BRACE, EXTPAR_FLAG_NONE)) != 0) { if ((err = extpar(&prefix, CHARS_BRACE, EXTPAR_FLAG_NONE)) != 0) {
/* XXX Encapsulate this in pcf_warn() function. */ /* XXX Encapsulate this in pcf_warn() function. */
@@ -293,18 +317,28 @@ static void pcf_register_dbms_helper(char *str_value,
msg_warn("%s: %s", MAIN_CONF_FILE, err); msg_warn("%s: %s", MAIN_CONF_FILE, err);
myfree(err); myfree(err);
} }
pcf_register_dbms_helper(prefix, flag_parameter, local_scope); for (dp = pcf_dbms_info; dp->db_type != 0; dp++) {
if (strcmp(db_type, dp->db_type) == 0) {
if (dp->db_class == PCF_DBMS_CLASS_REGEX)
next_recurse = PCF_DBMS_NO_RECURSE;
break;
}
}
pcf_register_dbms_helper(prefix, flag_parameter, local_scope,
next_recurse);
continue; continue;
} else { } else {
for (dp = pcf_dbms_info; dp->db_type != 0; dp++) { for (dp = pcf_dbms_info; dp->db_type != 0; dp++) {
if (strcmp(db_type, dp->db_type) == 0) { if (strcmp(db_type, dp->db_type) == 0) {
for (cpp = dp->db_suffixes; *cpp; cpp++) { if (dp->db_class == PCF_DBMS_CLASS_CLIENT) {
vstring_sprintf(candidate ? candidate : for (cpp = dp->db_suffixes; *cpp; cpp++) {
vstring_sprintf(candidate ? candidate :
(candidate = vstring_alloc(30)), (candidate = vstring_alloc(30)),
"%s_%s", prefix, *cpp); "%s_%s", prefix, *cpp);
flag_parameter(STR(candidate), flag_parameter(STR(candidate),
PCF_PARAM_FLAG_DBMS | PCF_PARAM_FLAG_USER, PCF_PARAM_FLAG_DBMS | PCF_PARAM_FLAG_USER,
local_scope); local_scope);
}
} }
break; break;
} }
@@ -332,7 +366,7 @@ void pcf_register_dbms_parameters(const char *param_value,
buffer = vstring_alloc(100); buffer = vstring_alloc(100);
bufp = pcf_expand_parameter_value(buffer, PCF_SHOW_EVAL, param_value, bufp = pcf_expand_parameter_value(buffer, PCF_SHOW_EVAL, param_value,
local_scope); local_scope);
pcf_register_dbms_helper(bufp, flag_parameter, local_scope); pcf_register_dbms_helper(bufp, flag_parameter, local_scope, PCF_DBMS_RECURSE);
} }
#endif #endif

View File

@@ -0,0 +1,8 @@
./postconf: warning: main.cf: #comment after other text is not allowed: #aaa1 ...
./postconf: warning: main.cf: #comment after other text is not allowed: #aaa2 ...
./postconf: warning: main.cf: #comment after other text is not allowed: #ccc2 ...
./postconf: warning: main.cf: #comment after other text is not allowed: #bbb2 ...
config_directory = .
smtpd_client_restrictions = inline:{ { aaa0 = #aaa1 } #aaa2 }
smtpd_helo_restrictions = pcre:{ { /bbb0 #bbb1/ } #bbb2 }
smtpd_sender_restrictions = regexp:{ { /ccc0 #ccc1/ } #ccc2 }

View File

@@ -2419,6 +2419,7 @@ myrand.o: myrand.c
myrand.o: myrand.h myrand.o: myrand.h
myrand.o: sys_defs.h myrand.o: sys_defs.h
mystrtok.o: check_arg.h mystrtok.o: check_arg.h
mystrtok.o: msg.h
mystrtok.o: mystrtok.c mystrtok.o: mystrtok.c
mystrtok.o: stringops.h mystrtok.o: stringops.h
mystrtok.o: sys_defs.h mystrtok.o: sys_defs.h

View File

@@ -84,6 +84,8 @@
/* IBM T.J. Watson Research /* IBM T.J. Watson Research
/* P.O. Box 704 /* P.O. Box 704
/* Yorktown Heights, NY 10598, USA /* Yorktown Heights, NY 10598, USA
/*
/* Wietse Venema
/*--*/ /*--*/
/* System library. */ /* System library. */
@@ -145,12 +147,8 @@ static ARGV *match_list_parse(MATCH_LIST *match_list, ARGV *pat_list,
* If there is an error, implement graceful degradation by inserting a * If there is an error, implement graceful degradation by inserting a
* pseudo table whose lookups fail with a warning message. * pseudo table whose lookups fail with a warning message.
*/ */
while ((start = mystrtokq(&bp, delim, CHARS_BRACE)) != 0) { while ((start = mystrtokq_cw(&bp, delim, CHARS_BRACE,
if (*start == '#') { match_list->pname)) != 0) {
msg_warn("%s: comment at end of line is not supported: %s %s",
match_list->pname, start, bp);
break;
}
for (match = init_match, item = start; *item == '!'; item++) for (match = init_match, item = start; *item == '!'; item++)
match = !match; match = !match;
if (*item == 0) if (*item == 0)

View File

@@ -18,6 +18,22 @@
/* char *mystrtokdq(bufp, delimiters) /* char *mystrtokdq(bufp, delimiters)
/* char **bufp; /* char **bufp;
/* const char *delimiters; /* const char *delimiters;
/*
/* char *mystrtok_cw(bufp, delimiters, blame)
/* char **bufp;
/* const char *delimiters;
/* const char *blame;
/*
/* char *mystrtokq_cw(bufp, delimiters, parens, blame)
/* char **bufp;
/* const char *delimiters;
/* const char *parens;
/* const char *blame;
/*
/* char *mystrtokdq_cw(bufp, delimiters, blame)
/* char **bufp;
/* const char *delimiters;
/* const char *blame;
/* DESCRIPTION /* DESCRIPTION
/* mystrtok() splits a buffer on the specified \fIdelimiters\fR. /* mystrtok() splits a buffer on the specified \fIdelimiters\fR.
/* Tokens are delimited by runs of delimiters, so this routine /* Tokens are delimited by runs of delimiters, so this routine
@@ -38,6 +54,12 @@
/* /*
/* The result value is the next token, or a null pointer when the /* The result value is the next token, or a null pointer when the
/* end of the buffer was reached. /* end of the buffer was reached.
/*
/* mystrtok_cw(), mystrtokq_cw(), and mystrtokdq_cw, log a
/* warning and return null when the result would look like
/* comment. The \fBblame\fR argument provides context for
/* warning messages. Specify a null pointer to disable the
/* comment check.
/* LICENSE /* LICENSE
/* .ad /* .ad
/* .fi /* .fi
@@ -52,20 +74,40 @@
/* Google, Inc. /* Google, Inc.
/* 111 8th Avenue /* 111 8th Avenue
/* New York, NY 10011, USA /* New York, NY 10011, USA
/*
/* Wietse Venema
/*--*/ /*--*/
/* System library. */ /* System library. */
#include "sys_defs.h" #include <sys_defs.h>
#include <string.h> #include <string.h>
/* Utility library. */ /* Utility library. */
#include "stringops.h" #include <msg.h>
#include <stringops.h>
/* mystrtok_warn - warn for #comment after other text */
static void mystrtok_warn(const char *start, const char *bufp, const char *blame)
{
msg_warn("%s: #comment after other text is not allowed: %s %.20s...",
blame, start, bufp);
}
/* mystrtok - ABI compatibility wrapper */
#undef mystrtok
char *mystrtok(char **src, const char *sep)
{
return (mystrtok_cw(src, sep, (char *) 0));
}
/* mystrtok - safe tokenizer */ /* mystrtok - safe tokenizer */
char *mystrtok(char **src, const char *sep) char *mystrtok_cw(char **src, const char *sep, const char *blame)
{ {
char *start = *src; char *start = *src;
char *end; char *end;
@@ -86,12 +128,28 @@ char *mystrtok(char **src, const char *sep)
if (*end != 0) if (*end != 0)
*end++ = 0; *end++ = 0;
*src = end; *src = end;
return (start);
if (blame && *start == '#') {
mystrtok_warn(start, *src, blame);
return (0);
} else {
return (start);
}
} }
/* mystrtokq - safe tokenizer with quoting support */ /* mystrtokq - ABI compatibility wrapper */
#undef mystrtokq
char *mystrtokq(char **src, const char *sep, const char *parens) char *mystrtokq(char **src, const char *sep, const char *parens)
{
return (mystrtokq_cw(src, sep, parens, (char *) 0));
}
/* mystrtokq_cw - safe tokenizer with quoting support */
char *mystrtokq_cw(char **src, const char *sep, const char *parens,
const char *blame)
{ {
char *start = *src; char *start = *src;
static char *cp; static char *cp;
@@ -121,12 +179,27 @@ char *mystrtokq(char **src, const char *sep, const char *parens)
} }
} }
*src = cp; *src = cp;
return (start);
if (blame && *start == '#') {
mystrtok_warn(start, *src, blame);
return (0);
} else {
return (start);
}
} }
/* mystrtokdq - safe tokenizer, double quote and backslash support */ /* mystrtokdq - ABI compatibility wrapper */
#undef mystrtokdq
char *mystrtokdq(char **src, const char *sep) char *mystrtokdq(char **src, const char *sep)
{
return (mystrtokdq_cw(src, sep, (char *) 0));
}
/* mystrtokdq_cw - safe tokenizer, double quote and backslash support */
char *mystrtokdq_cw(char **src, const char *sep, const char *blame)
{ {
char *cp = *src; char *cp = *src;
char *start; char *start;
@@ -157,7 +230,13 @@ char *mystrtokdq(char **src, const char *sep)
} }
} }
*src = cp; *src = cp;
return (start);
if (blame && start && *start == '#') {
mystrtok_warn(start, *src, blame);
return (0);
} else {
return (start);
}
} }
#ifdef TEST #ifdef TEST
@@ -195,6 +274,12 @@ static const struct testcase testcases[] = {
{"mystrtokdq", " foo\\ bar ", {"foo\\ bar"}}, {"mystrtokdq", " foo\\ bar ", {"foo\\ bar"}},
{"mystrtokdq", " foo \\\" bar", {"foo", "\\\"", "bar"}}, {"mystrtokdq", " foo \\\" bar", {"foo", "\\\"", "bar"}},
{"mystrtokdq", " foo \" bar baz\" ", {"foo", "\" bar baz\""}}, {"mystrtokdq", " foo \" bar baz\" ", {"foo", "\" bar baz\""}},
{"mystrtok_cw", "#after text"},
{"mystrtok_cw", "before-text #after text", {"before-text"}},
{"mystrtokq_cw", "#after text"},
{"mystrtokq_cw", "{ before text } #after text", "{ before text }"},
{"mystrtokdq_cw", "#after text"},
{"mystrtokdq_cw", "\"before text\" #after text", {"\"before text\""}},
}; };
int main(void) int main(void)
@@ -229,6 +314,12 @@ int main(void)
actual = mystrtokq(&cp, CHARS_SPACE, CHARS_BRACE); actual = mystrtokq(&cp, CHARS_SPACE, CHARS_BRACE);
} else if (strcmp(tp->action, "mystrtokdq") == 0) { } else if (strcmp(tp->action, "mystrtokdq") == 0) {
actual = mystrtokdq(&cp, CHARS_SPACE); actual = mystrtokdq(&cp, CHARS_SPACE);
} else if (strcmp(tp->action, "mystrtok_cw") == 0) {
actual = mystrtok_cw(&cp, CHARS_SPACE, "test");
} else if (strcmp(tp->action, "mystrtokq_cw") == 0) {
actual = mystrtokq_cw(&cp, CHARS_SPACE, CHARS_BRACE, "test");
} else if (strcmp(tp->action, "mystrtokdq_cw") == 0) {
actual = mystrtokdq_cw(&cp, CHARS_SPACE, "test");
} else { } else {
msg_panic("invalid command: %s", tp->action); msg_panic("invalid command: %s", tp->action);
} }

View File

@@ -28,3 +28,21 @@ unknown: RUN test case 13 mystrtokdq > foo \" bar<
unknown: PASS test 13 unknown: PASS test 13
unknown: RUN test case 14 mystrtokdq > foo " bar baz" < unknown: RUN test case 14 mystrtokdq > foo " bar baz" <
unknown: PASS test 14 unknown: PASS test 14
unknown: RUN test case 15 mystrtok_cw >#after text<
unknown: warning: test: #comment after other text is not allowed: #after text...
unknown: PASS test 15
unknown: RUN test case 16 mystrtok_cw >before-text #after text<
unknown: warning: test: #comment after other text is not allowed: #after text...
unknown: PASS test 16
unknown: RUN test case 17 mystrtokq_cw >#after text<
unknown: warning: test: #comment after other text is not allowed: #after text...
unknown: PASS test 17
unknown: RUN test case 18 mystrtokq_cw >{ before text } #after text<
unknown: warning: test: #comment after other text is not allowed: #after text...
unknown: PASS test 18
unknown: RUN test case 19 mystrtokdq_cw >#after text<
unknown: warning: test: #comment after other text is not allowed: #after text...
unknown: PASS test 19
unknown: RUN test case 20 mystrtokdq_cw >"before text" #after text<
unknown: warning: test: #comment after other text is not allowed: #after text...
unknown: PASS test 20

View File

@@ -31,8 +31,15 @@ extern char *concatenate(const char *,...);
extern char *mystrtok(char **, const char *); extern char *mystrtok(char **, const char *);
extern char *mystrtokq(char **, const char *, const char *); extern char *mystrtokq(char **, const char *, const char *);
extern char *mystrtokdq(char **, const char *); extern char *mystrtokdq(char **, const char *);
extern char *mystrtok_cw(char **, const char *, const char *);
extern char *mystrtokq_cw(char **, const char *, const char *, const char *);
extern char *mystrtokdq_cw(char **, const char *, const char *);
extern char *translit(char *, const char *, const char *); extern char *translit(char *, const char *, const char *);
#define mystrtok(cp, sp) mystrtok_cw((cp), (sp), (char *) 0)
#define mystrtokq(cp, sp, pp) mystrtokq_cw((cp), (sp), (pp), (char *) 0)
#define mystrtokdq(cp, sp) mystrtokdq_cw((cp), (sp), (char *) 0)
#define printable(string, replacement) \ #define printable(string, replacement) \
printable_except((string), (replacement), (char *) 0) printable_except((string), (replacement), (char *) 0)
@@ -102,6 +109,8 @@ extern int strncasecmp_utf8x(int, const char *, const char *, ssize_t);
/* Google, Inc. /* Google, Inc.
/* 111 8th Avenue /* 111 8th Avenue
/* New York, NY 10011, USA /* New York, NY 10011, USA
/*
/* Wietse Venema
/*--*/ /*--*/
#endif #endif