]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-3.8-20230406
authorWietse Venema <wietse@porcupine.org>
Thu, 6 Apr 2023 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <postfix-users@dukhovni.org>
Fri, 7 Apr 2023 04:41:09 +0000 (00:41 -0400)
13 files changed:
postfix/HISTORY
postfix/proto/stop.spell-cc
postfix/src/dns/dns_rr.c
postfix/src/global/mail_version.h
postfix/src/global/namadr_list.ref
postfix/src/postconf/Makefile.in
postfix/src/postconf/postconf_dbms.c
postfix/src/postconf/test71.ref [new file with mode: 0644]
postfix/src/util/Makefile.in
postfix/src/util/match_list.c
postfix/src/util/mystrtok.c
postfix/src/util/mystrtok.ref
postfix/src/util/stringops.h

index 56d7756d9749d8eed2d7308ec502a5d4001d600d..81d5e00d0bff64b75f335d3b7c6f34b54603db7c 100644 (file)
@@ -26990,11 +26990,13 @@ Apologies for any names omitted.
 20230330
 
        Safety: the long form { name = value } in import_environment
-       or export_environment is not documented, but accepted, and
-       it was stored in the process environment as the invalid
-       form "name = value" instead of the expected "name=value".
-       Found during code maintenance. Also refined an "empty name"
-       check. Files: clean_env.c, split_nameval.c.
+       or export_environment is not documented, but it is accepted,
+       and it was stored in the process environment as the invalid
+       form "name = value, thus not setting or overriding an entry
+       for "name". This form is now stored as the expected
+       "name=value". Found during code maintenance. Also refined
+       the "missing attribute name" detection. Files: clean_env.c,
+       split_nameval.c.
 
 20230402
 
@@ -27014,3 +27016,23 @@ Apologies for any names omitted.
        example, inline maps. Added Valgrind support to the namadr_list
        unit test. Files: util/match_list.c, global/namadr_list.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().
index c642c7a32e0cacb2f2d14d55b22a61bd92bc0310..3da66902586915dda2cc10fe71c18f20b4ffc765 100644 (file)
@@ -1800,3 +1800,4 @@ Stringify
 bitcount
 bytecount
 ipproto
+cw
index 44918b10c4d7a75eb009889d7930a1981f44883f..b84349267aac290be1be4a69929a6d347326f1da 100644 (file)
@@ -160,6 +160,9 @@ DNS_RR *dns_rr_create(const char *qname, const char *rname,
 {
     DNS_RR *rr;
 
+    /*
+     * Note: if this function is changed, update dns_rr_copy().
+     */
     rr = (DNS_RR *) mymalloc(sizeof(*rr));
     rr->qname = mystrdup(qname);
     rr->rname = mystrdup(rname);
@@ -200,16 +203,17 @@ void    dns_rr_free(DNS_RR *rr)
 
 DNS_RR *dns_rr_copy(DNS_RR *src)
 {
-    ssize_t len = sizeof(*src) + src->data_len - 1;
     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);
-    memcpy((void *) dst, (void *) src, len);
+    dst = (DNS_RR *) mymalloc(sizeof(*dst));
+    memcpy((void *) dst, (void *) src, sizeof(*dst));
     dst->qname = mystrdup(src->qname);
     dst->rname = mystrdup(src->rname);
+    if (dst->data)
+       dst->data = mymemdup(dst->data, dst->data_len);
     dst->next = 0;
     return (dst);
 }
index 8a382c3966fda43325eac9847b0fcfca63a74abf..dbcfba979af336d9117180650d1136f69e204005 100644 (file)
@@ -20,7 +20,7 @@
   * Patches change both the patchlevel and the release date. Snapshots have no
   * patchlevel; they change the release date only.
   */
-#define MAIL_RELEASE_DATE      "20230402"
+#define MAIL_RELEASE_DATE      "20230406"
 #define MAIL_VERSION_NUMBER    "3.8"
 
 #ifdef SNAPSHOT
index 77ab9bdc923dbd93dae0ee2e5fec4739a9941a81..b108786eb2972a59a4e4ab416a22cc50a511f136 100644 (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: command line: non-existent:/tmp/nosuchfile: table lookup problem
 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
-./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
 foo/1.2.3.4: YES
 bar/1.2.3.4: YES
index 665f36e8af1cb36afd0c379549f267d265f2c8bc..26e747c7bd4142dbd52e97cc52aa6861389ea7a5 100644 (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 \
        test42 test43 test44 test45 test46 test47 test48 test49 test50 test51 \
        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:
 
@@ -964,7 +964,24 @@ test70:    $(PROG) test70.ref
        touch -t 197101010000 main.cf
        $(HTABLE_FIX) $(SHLIB_ENV) $(VALGRIND) ./$(PROG) -nc . >test70.tmp 2>&1
        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)
        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_memcache.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_proxy.h
+postconf_dbms.o: ../../include/dict_regexp.h
 postconf_dbms.o: ../../include/dict_sqlite.h
 postconf_dbms.o: ../../include/htable.h
 postconf_dbms.o: ../../include/mac_expand.h
index d21cad18fb2a83ecd83b41d17608061b5f294865..622e7a01dc9599482e87583ebf1f46d93530d5a4 100644 (file)
@@ -48,6 +48,8 @@
 /*     Google, Inc.
 /*     111 8th Avenue
 /*     New York, NY 10011, USA
+/*
+/*     Wietse Venema
 /*--*/
 
 /* System library. */
@@ -77,6 +79,8 @@
 #include <dict_pgsql.h>
 #include <dict_sqlite.h>
 #include <dict_memcache.h>
+#include <dict_regexp.h>
+#include <dict_pcre.h>
 
 /* Application-specific. */
 
@@ -134,18 +138,31 @@ static const char *pcf_memcache_suffixes[] = {
   */
 typedef struct {
     const char *db_type;
+    int     db_class;
     const char **db_suffixes;
 } 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[] = {
-    DICT_TYPE_LDAP, pcf_ldap_suffixes,
-    DICT_TYPE_MYSQL, pcf_mysql_suffixes,
-    DICT_TYPE_PGSQL, pcf_pgsql_suffixes,
-    DICT_TYPE_SQLITE, pcf_sqlite_suffixes,
-    DICT_TYPE_MEMCACHE, pcf_memcache_suffixes,
-    0,
+    {DICT_TYPE_LDAP, PCF_DBMS_CLASS_CLIENT, pcf_ldap_suffixes},
+    {DICT_TYPE_MYSQL, PCF_DBMS_CLASS_CLIENT, pcf_mysql_suffixes},
+    {DICT_TYPE_PGSQL, PCF_DBMS_CLASS_CLIENT, pcf_pgsql_suffixes},
+    {DICT_TYPE_SQLITE, PCF_DBMS_CLASS_CLIENT, pcf_sqlite_suffixes},
+    {DICT_TYPE_MEMCACHE, PCF_DBMS_CLASS_CLIENT, pcf_memcache_suffixes},
+    {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 */
 
 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,
          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;
     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
      * 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 ((err = extpar(&db_type, CHARS_BRACE, EXTPAR_FLAG_NONE)) != 0) {
                /* 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);
                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;
        }
 
@@ -267,7 +288,8 @@ static void pcf_register_dbms_helper(char *str_value,
        if (*prefix == '/') {
            for (dp = pcf_dbms_info; dp->db_type != 0; dp++) {
                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;
                }
            }
@@ -282,6 +304,8 @@ static void pcf_register_dbms_helper(char *str_value,
         * local or global namespace.
         */
        if (*prefix != '.') {
+           int     next_recurse = recurse;
+
            if (*prefix == CHARS_BRACE[0]) {
                if ((err = extpar(&prefix, CHARS_BRACE, EXTPAR_FLAG_NONE)) != 0) {
                    /* 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);
                    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;
            } else {
                for (dp = pcf_dbms_info; dp->db_type != 0; dp++) {
                    if (strcmp(db_type, dp->db_type) == 0) {
-                       for (cpp = dp->db_suffixes; *cpp; cpp++) {
-                           vstring_sprintf(candidate ? candidate :
+                       if (dp->db_class == PCF_DBMS_CLASS_CLIENT) {
+                           for (cpp = dp->db_suffixes; *cpp; cpp++) {
+                               vstring_sprintf(candidate ? candidate :
                                            (candidate = vstring_alloc(30)),
-                                           "%s_%s", prefix, *cpp);
-                           flag_parameter(STR(candidate),
+                                               "%s_%s", prefix, *cpp);
+                               flag_parameter(STR(candidate),
                                  PCF_PARAM_FLAG_DBMS | PCF_PARAM_FLAG_USER,
-                                          local_scope);
+                                              local_scope);
+                           }
                        }
                        break;
                    }
@@ -332,7 +366,7 @@ void    pcf_register_dbms_parameters(const char *param_value,
        buffer = vstring_alloc(100);
     bufp = pcf_expand_parameter_value(buffer, PCF_SHOW_EVAL, param_value,
                                      local_scope);
-    pcf_register_dbms_helper(bufp, flag_parameter, local_scope);
+    pcf_register_dbms_helper(bufp, flag_parameter, local_scope, PCF_DBMS_RECURSE);
 }
 
 #endif
diff --git a/postfix/src/postconf/test71.ref b/postfix/src/postconf/test71.ref
new file mode 100644 (file)
index 0000000..1c4be0c
--- /dev/null
@@ -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 }
index 3ff78587583daf66923dc19c880eda3d8b0f8a2e..a3700f5681f0704fe15dc643dc35afa2d24aa370 100644 (file)
@@ -2419,6 +2419,7 @@ myrand.o: myrand.c
 myrand.o: myrand.h
 myrand.o: sys_defs.h
 mystrtok.o: check_arg.h
+mystrtok.o: msg.h
 mystrtok.o: mystrtok.c
 mystrtok.o: stringops.h
 mystrtok.o: sys_defs.h
index 924c6b4a82be813dfd2b11a5a29839fe22d8d5cb..f8f6b552090788681af169b9363740a9b91ca41d 100644 (file)
@@ -84,6 +84,8 @@
 /*     IBM T.J. Watson Research
 /*     P.O. Box 704
 /*     Yorktown Heights, NY 10598, USA
+/*
+/*     Wietse Venema
 /*--*/
 
 /* 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
      * pseudo table whose lookups fail with a warning message.
      */
-    while ((start = mystrtokq(&bp, delim, CHARS_BRACE)) != 0) {
-       if (*start == '#') {
-           msg_warn("%s: comment at end of line is not supported: %s %s",
-                    match_list->pname, start, bp);
-           break;
-       }
+    while ((start = mystrtokq_cw(&bp, delim, CHARS_BRACE,
+                                match_list->pname)) != 0) {
        for (match = init_match, item = start; *item == '!'; item++)
            match = !match;
        if (*item == 0)
index 85b15f3b3f1f433ad5b4a5cdfe1e2a1aef1da05d..432719c8fd7953830c4f9fef69b38cf966f8c114 100644 (file)
 /*     char    *mystrtokdq(bufp, delimiters)
 /*     char    **bufp;
 /*     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
 /*     mystrtok() splits a buffer on the specified \fIdelimiters\fR.
 /*     Tokens are delimited by runs of delimiters, so this routine
 /*
 /*     The result value is the next token, or a null pointer when the
 /*     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
 /* .ad
 /* .fi
 /*     Google, Inc.
 /*     111 8th Avenue
 /*     New York, NY 10011, USA
+/*
+/*     Wietse Venema
 /*--*/
 
 /* System library. */
 
-#include "sys_defs.h"
+#include <sys_defs.h>
 #include <string.h>
 
 /* Utility library. */
 
-#include "stringops.h"
+#include <msg.h>
+#include <stringops.h>
 
-/* mystrtok - safe tokenizer */
+/* 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 */
+
+char   *mystrtok_cw(char **src, const char *sep, const char *blame)
 {
     char   *start = *src;
     char   *end;
@@ -86,12 +128,28 @@ char   *mystrtok(char **src, const char *sep)
     if (*end != 0)
        *end++ = 0;
     *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)
+{
+    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;
     static char *cp;
@@ -121,12 +179,27 @@ char   *mystrtokq(char **src, const char *sep, const char *parens)
        }
     }
     *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)
+{
+    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   *start;
@@ -157,7 +230,13 @@ char   *mystrtokdq(char **src, const char *sep)
        }
     }
     *src = cp;
-    return (start);
+
+    if (blame && start && *start == '#') {
+       mystrtok_warn(start, *src, blame);
+       return (0);
+    } else {
+       return (start);
+    }
 }
 
 #ifdef TEST
@@ -195,6 +274,12 @@ static const struct testcase testcases[] = {
     {"mystrtokdq", "  foo\\ bar  ", {"foo\\ bar"}},
     {"mystrtokdq", "  foo \\\" bar", {"foo", "\\\"", "bar"}},
     {"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)
@@ -229,6 +314,12 @@ int     main(void)
                actual = mystrtokq(&cp, CHARS_SPACE, CHARS_BRACE);
            } else if (strcmp(tp->action, "mystrtokdq") == 0) {
                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 {
                msg_panic("invalid command: %s", tp->action);
            }
index 4f920f994d6964bd1693187e0b8657a28b02cc58..d0ca58a35d3d21bd7b73a822a860533ea02775cf 100644 (file)
@@ -28,3 +28,21 @@ unknown: RUN test case 13 mystrtokdq >  foo \" bar<
 unknown: PASS test 13
 unknown: RUN test case 14 mystrtokdq >  foo " bar baz"  <
 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
index 8ac177b9258c9a51eee7420dcafa225b6caf52d8..cd9b5753b7ddc348f27a60455865cec5552e7d76 100644 (file)
@@ -31,8 +31,15 @@ extern char *concatenate(const char *,...);
 extern char *mystrtok(char **, const char *);
 extern char *mystrtokq(char **, const 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 *);
 
+#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) \
        printable_except((string), (replacement), (char *) 0)
 
@@ -102,6 +109,8 @@ extern int strncasecmp_utf8x(int, const char *, const char *, ssize_t);
 /*     Google, Inc.
 /*     111 8th Avenue
 /*     New York, NY 10011, USA
+/*
+/*     Wietse Venema
 /*--*/
 
 #endif