]> granicus.if.org Git - file/commitdiff
Kill -R and replace with -P param=value. Allow setting of 4 parameters:
authorChristos Zoulas <christos@zoulas.com>
Thu, 27 Nov 2014 23:42:58 +0000 (23:42 +0000)
committerChristos Zoulas <christos@zoulas.com>
Thu, 27 Nov 2014 23:42:58 +0000 (23:42 +0000)
    indir, name, shnum, phnum.

12 files changed:
ChangeLog
doc/file.man
doc/libmagic.man
src/apprentice.c
src/ascmagic.c
src/elfclass.h
src/file.c
src/file.h
src/funcs.c
src/magic.c
src/magic.h.in
src/softmagic.c

index e326bf31c407fd3b44819fad081ae253ea5b8f95..355e7ce041335a894d9c145d82862d60805671af 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2014-11-27  18:40  Christos Zoulas <christos@zoulas.com>
+
+       * Allow setting more parameters from the command line.
+       * Split name/use and indirect magic recursion limits.
+
 2014-11-27  11:12  Christos Zoulas <christos@zoulas.com>
 
        * Adjust ELF parameters and the default recursion
index 296cb1f2c3825eebfedc18ddbe5e9543c334cfdd..a9196529c4a821582b3d0e0dc73b47fc418352b3 100644 (file)
@@ -1,4 +1,4 @@
-.\" $File: file.man,v 1.107 2014/11/27 16:15:06 christos Exp $
+.\" $File: file.man,v 1.108 2014/11/27 23:42:58 christos Exp $
 .Dd November 27, 2014
 .Dt FILE __CSECTION__
 .Os
@@ -16,7 +16,7 @@
 .Op Fl F Ar separator
 .Op Fl f Ar namefile
 .Op Fl m Ar magicfiles
-.Op Fl R Ar maxrecursion
+.Op Fl P Ar name=value
 .Ar
 .Ek
 .Nm
@@ -304,16 +304,20 @@ or
 attempt to preserve the access time of files analyzed, to pretend that
 .Nm
 never read them.
+.It Fl P , Fl Fl parameter Ar name=value
+Set various parameter limits.
+.Bl -column "indir" "Default" "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" -offset indent
+.It Sy "Name" Ta Sy "Default" Ta Sy "Explanation"
+.It Li indir Ta 15 Ta recursion limit for indirect magic
+.It Li name Ta 40 Ta recursion limit for name/use magic
+.It Li phnum Ta 128 Ta max ELF program sections processed
+.It Li shnum Ta 32768 Ta max ELF sections processed
+.El
 .It Fl r , Fl Fl raw
 Don't translate unprintable characters to \eooo.
 Normally
 .Nm
 translates unprintable characters to their octal representation.
-.It Fl R , Fl Fl recursion Ar maxlevel
-Set the maximum recursion level for indirect type magic or name/use entry
-invocations.
-The default is
-.Dv 15 .
 .It Fl s , Fl Fl special-files
 Normally,
 .Nm
index 87d9f2ba3887a9cef2fd121ba9545f98e87e8af4..886f96951456accd558e6300f289fc7bcd012a1f 100644 (file)
@@ -1,4 +1,4 @@
-.\" $File: libmagic.man,v 1.30 2014/11/27 16:15:06 christos Exp $
+.\" $File: libmagic.man,v 1.31 2014/11/27 23:42:58 christos Exp $
 .\"
 .\" Copyright (c) Christos Zoulas 2003.
 .\" All Rights Reserved.
@@ -280,14 +280,31 @@ and
 .Fn magic_setparam
 allow getting and setting various limits related to the the magic
 library.
-.Bl -column "MAGIC_PARAM_MAX_RECURSION" "size_t" "Default" -offset indent
-.It Sy "Parameter" Ta Sy "Type" Ta Sy "Default
-.It Li MAGIC_PARAM_MAX_RECURSION Ta size_t Ta 15
+.Bl -column "MAGIC_PARAM_INDIR_RECURSION" "size_t" "Default" -offset indent
+.It Sy "Parameter" Ta Sy "Type" Ta Sy "Default"
+.It Li MAGIC_PARAM_INDIR_RECURSION Ta size_t Ta 15
+.It Li MAGIC_PARAM_NAME_RECURSION Ta size_t Ta 40
+.It Li MAGIC_PARAM_PHNUM_MAX Ta size_t Ta 128
+.It Li MAGIC_PARAM_SHNUM_MAX Ta size_t Ta 32768
 .El
+.Pp
+The
+.Dv MAGIC_PARAM_INDIR_RECURSION
+parameter controls how many levels of recursion will be followed for
+indirect magic entries.
+.Pp
 The
-.Dv MAGIC_PARAM_MAX_RECURSION
+.Dv MAGIC_PARAM_NAME_RECURSION
 parameter controls how many levels of recursion will be followed for
-indirect magic entries or for name/use calls.
+for name/use calls.
+.Pp
+The
+.Dv MAGIC_PARAM_PHNUM_MAX
+parameter controls how many elf program sections will be processed.
+.Pp
+The
+.Dv MAGIC_PARAM_SHNUM_MAX
+parameter controls how many elf sections will be processed.
 .Pp
 The
 .Fn magic_version
index 1b0ff5d7ef998a9d797d46fa6b8259002eaced24..f45081796f294660552045513a18055fdba8b91e 100644 (file)
@@ -32,7 +32,7 @@
 #include "file.h"
 
 #ifndef        lint
-FILE_RCSID("@(#)$File: apprentice.c,v 1.224 2014/11/27 15:40:36 christos Exp $")
+FILE_RCSID("@(#)$File: apprentice.c,v 1.225 2014/11/27 23:42:58 christos Exp $")
 #endif /* lint */
 
 #include "magic.h"
@@ -524,7 +524,10 @@ file_ms_alloc(int flags)
                ms->mlist[i] = NULL;
        ms->file = "unknown";
        ms->line = 0;
-       ms->max_recursion = FILE_MAX_RECURSION;
+       ms->indir_recursion = FILE_INDIR_RECURSION;
+       ms->name_recursion = FILE_NAME_RECURSION;
+       ms->shnum_max = FILE_ELF_SHNUM;
+       ms->phnum_max = FILE_ELF_PHNUM;
        return ms;
 free:
        free(ms);
index ca2666556872b2662cb1e61d3063db44d8cf9326..20173a961d418e393c021921b8cefd0726fcd8eb 100644 (file)
@@ -35,7 +35,7 @@
 #include "file.h"
 
 #ifndef        lint
-FILE_RCSID("@(#)$File: ascmagic.c,v 1.88 2014/02/12 23:20:53 christos Exp $")
+FILE_RCSID("@(#)$File: ascmagic.c,v 1.89 2014/11/27 23:42:58 christos Exp $")
 #endif /* lint */
 
 #include "magic.h"
@@ -147,7 +147,7 @@ file_ascmagic_with_encoding(struct magic_set *ms, const unsigned char *buf,
                    == NULL)
                        goto done;
                if ((rv = file_softmagic(ms, utf8_buf,
-                   (size_t)(utf8_end - utf8_buf), 0, TEXTTEST, text)) == 0)
+                   (size_t)(utf8_end - utf8_buf), 0, 0, TEXTTEST, text)) == 0)
                        rv = -1;
        }
 
index 0826ce3213a5c0e8a57d7673666232d038fdbd89..bda53b343e3191047d3f6550d035e54b1a0a73cf 100644 (file)
@@ -36,7 +36,7 @@
 #ifdef ELFCORE
        case ET_CORE:
                phnum = elf_getu16(swap, elfhdr.e_phnum);
-               if (phnum > MAX_PHNUM)
+               if (phnum > ms->phnum_max)
                        return toomany(ms, "program", phnum);
                flags |= FLAGS_IS_CORE;
                if (dophn_core(ms, clazz, swap, fd,
        case ET_EXEC:
        case ET_DYN:
                phnum = elf_getu16(swap, elfhdr.e_phnum);
-               if (phnum > MAX_PHNUM)
+               if (phnum > ms->phnum_max)
                        return toomany(ms, "program", phnum);
                shnum = elf_getu16(swap, elfhdr.e_shnum);
-               if (shnum > MAX_SHNUM)
+               if (shnum > ms->shnum_max)
                        return toomany(ms, "section", shnum);
                if (dophn_exec(ms, clazz, swap, fd,
                    (off_t)elf_getu(swap, elfhdr.e_phoff), phnum,
@@ -62,7 +62,7 @@
                /*FALLTHROUGH*/
        case ET_REL:
                shnum = elf_getu16(swap, elfhdr.e_shnum);
-               if (shnum > MAX_SHNUM)
+               if (shnum > ms->shnum_max)
                        return toomany(ms, "section", shnum);
                if (doshn(ms, clazz, swap, fd,
                    (off_t)elf_getu(swap, elfhdr.e_shoff), shnum,
index 74ad2aa40bc91a332701bca9357e0a00f86074a0..f7bc4082d37106d91837e37697ddb6319c5ebcb2 100644 (file)
@@ -32,7 +32,7 @@
 #include "file.h"
 
 #ifndef        lint
-FILE_RCSID("@(#)$File: file.c,v 1.156 2014/11/27 15:40:36 christos Exp $")
+FILE_RCSID("@(#)$File: file.c,v 1.157 2014/11/27 23:42:58 christos Exp $")
 #endif /* lint */
 
 #include "magic.h"
@@ -98,7 +98,7 @@ private const struct option long_options[] = {
 #undef OPT_LONGONLY
     {0, 0, NULL, 0}
 };
-#define OPTSTRING      "bcCde:Ef:F:hiklLm:nNprR:svz0"
+#define OPTSTRING      "bcCde:Ef:F:hiklLm:nNpP:rsvz0"
 
 private const struct {
        const char *name;
@@ -116,6 +116,17 @@ private const struct {
        { "tokens",     MAGIC_NO_CHECK_TOKENS }, /* OBSOLETE: ignored for backwards compatibility */
 };
 
+private struct {
+       const char *name;
+       int tag;
+       size_t value;
+} pm[] = {
+       { "indir",      MAGIC_PARAM_INDIR_RECURSION, 0 },
+       { "name",       MAGIC_PARAM_NAME_RECURSION, 0 },
+       { "phnum",      MAGIC_PARAM_PHNUM_MAX, 0 },
+       { "shnum",      MAGIC_PARAM_SHNUM_MAX, 0 },
+};
+
 private char *progname;                /* used throughout              */
 
 private void usage(void);
@@ -125,6 +136,8 @@ private void help(void);
 private int unwrap(struct magic_set *, const char *);
 private int process(struct magic_set *ms, const char *, int);
 private struct magic_set *load(const char *, int);
+private void setparam(const char *);
+private void applyparam(magic_t);
 
 
 /*
@@ -137,7 +150,6 @@ main(int argc, char *argv[])
        size_t i;
        int action = 0, didsomefiles = 0, errflg = 0;
        int flags = 0, e = 0;
-       size_t max_recursion = 0;
        struct magic_set *magic = NULL;
        int longindex;
        const char *magicfile = NULL;           /* where the magic is   */
@@ -243,11 +255,12 @@ main(int argc, char *argv[])
                        flags |= MAGIC_PRESERVE_ATIME;
                        break;
 #endif
+               case 'P':
+                       setparam(optarg);
+                       break;
                case 'r':
                        flags |= MAGIC_RAW;
                        break;
-               case 'R':
-                       max_recursion = atoi(optarg);
                        break;
                case 's':
                        flags |= MAGIC_DEVICES;
@@ -326,16 +339,7 @@ main(int argc, char *argv[])
                if (magic == NULL)
                        if ((magic = load(magicfile, flags)) == NULL)
                                return 1;
-               if (max_recursion) {
-                       if (magic_setparam(magic, MAGIC_PARAM_MAX_RECURSION,
-                           &max_recursion) == -1) {
-                               (void)fprintf(stderr,
-                                   "%s: Can't set recurision %s\n", progname,
-                                   strerror(errno));
-                               return 1;
-                       }
-               }
-               break;
+               applyparam(magic);
        }
 
        if (optind == argc) {
@@ -365,6 +369,41 @@ main(int argc, char *argv[])
        return e;
 }
 
+private void
+applyparam(magic_t magic)
+{
+       size_t i;
+
+       for (i = 0; i < __arraycount(pm); i++) {
+               if (pm[i].value == 0)
+                       continue;
+               if (magic_setparam(magic, pm[i].tag, &pm[i].value) == -1) {
+                       (void)fprintf(stderr, "%s: Can't set %s %s\n", progname,
+                               pm[i].name, strerror(errno));
+                       exit(1);
+               }
+       }
+}
+
+private void
+setparam(const char *p)
+{
+       size_t i;
+       char *s;
+
+       if ((s = strchr(p, '=')) == NULL)
+               goto badparm;
+
+       for (i = 0; i < __arraycount(pm); i++) {
+               if (strncmp(p, pm[i].name, s - p) != 0)
+                       continue;
+               pm[i].value = atoi(s + 1);
+               return;
+       }
+badparm:
+       (void)fprintf(stderr, "%s: Unknown param %s\n", progname, p);
+       exit(1);
+}
 
 private struct magic_set *
 /*ARGSUSED*/
index aca0e4d3f8c210445eeb7affef9d220f6d553753..196a3b28b934a094f4e3338ca1666f09ede4e77f 100644 (file)
@@ -27,7 +27,7 @@
  */
 /*
  * file.h - definitions for file(1) program
- * @(#)$File: file.h,v 1.157 2014/11/27 15:40:36 christos Exp $
+ * @(#)$File: file.h,v 1.158 2014/11/27 23:42:58 christos Exp $
  */
 
 #ifndef __file_h__
@@ -401,8 +401,14 @@ struct magic_set {
        /* FIXME: Make the string dynamically allocated so that e.g.
           strings matched in files can be longer than MAXstring */
        union VALUETYPE ms_value;       /* either number or string */
-       size_t max_recursion;
-#define        FILE_MAX_RECURSION      15
+       uint16_t indir_recursion;
+       uint16_t name_recursion;
+       uint16_t shnum_max;
+       uint16_t phnum_max;
+#define        FILE_INDIR_RECURSION    15
+#define        FILE_NAME_RECURSION     40
+#define FILE_ELF_SHNUM         32768
+#define FILE_ELF_PHNUM         128
 };
 
 /* Type for Unicode characters */
@@ -442,7 +448,7 @@ protected int file_encoding(struct magic_set *, const unsigned char *, size_t,
     unichar **, size_t *, const char **, const char **, const char **);
 protected int file_is_tar(struct magic_set *, const unsigned char *, size_t);
 protected int file_softmagic(struct magic_set *, const unsigned char *, size_t,
-    size_t, int, int);
+    uint16_t, uint16_t, int, int);
 protected int file_apprentice(struct magic_set *, const char *, int);
 protected int buffer_apprentice(struct magic_set *, struct magic **,
     size_t *, size_t);
index 407b2f1020e340a284bebacaa26cca56e20dcbc5..a46a4c3323a543d444e147602d3e0115dd46344b 100644 (file)
@@ -27,7 +27,7 @@
 #include "file.h"
 
 #ifndef        lint
-FILE_RCSID("@(#)$File: funcs.c,v 1.74 2014/11/23 13:54:27 christos Exp $")
+FILE_RCSID("@(#)$File: funcs.c,v 1.75 2014/11/27 23:42:58 christos Exp $")
 #endif /* lint */
 
 #include "magic.h"
@@ -227,7 +227,7 @@ file_buffer(struct magic_set *ms, int fd, const char *inname __attribute__ ((unu
 
        /* try soft magic tests */
        if ((ms->flags & MAGIC_NO_CHECK_SOFT) == 0)
-               if ((m = file_softmagic(ms, ubuf, nb, 0, BINTEST,
+               if ((m = file_softmagic(ms, ubuf, nb, 0, 0, BINTEST,
                    looks_text)) != 0) {
                        if ((ms->flags & MAGIC_DEBUG) != 0)
                                (void)fprintf(stderr, "softmagic %d\n", m);
index 39c4a2fbc9651abb3fb93b979ca58c8b9ca8baf8..5c8d54b9a1469ca9dfffe7cc91c067c537bb134c 100644 (file)
@@ -33,7 +33,7 @@
 #include "file.h"
 
 #ifndef        lint
-FILE_RCSID("@(#)$File: magic.c,v 1.86 2014/11/27 15:40:36 christos Exp $")
+FILE_RCSID("@(#)$File: magic.c,v 1.87 2014/11/27 23:42:58 christos Exp $")
 #endif /* lint */
 
 #include "magic.h"
@@ -541,8 +541,17 @@ public int
 magic_setparam(struct magic_set *ms, int param, const void *val)
 {
        switch (param) {
-       case MAGIC_PARAM_MAX_RECURSION:
-               ms->max_recursion = *(const size_t *)val;
+       case MAGIC_PARAM_INDIR_RECURSION:
+               ms->indir_recursion = *(const size_t *)val;
+               return 0;
+       case MAGIC_PARAM_NAME_RECURSION:
+               ms->name_recursion = *(const size_t *)val;
+               return 0;
+       case MAGIC_PARAM_PHNUM_MAX:
+               ms->phnum_max = *(const size_t *)val;
+               return 0;
+       case MAGIC_PARAM_SHNUM_MAX:
+               ms->shnum_max = *(const size_t *)val;
                return 0;
        default:
                errno = EINVAL;
@@ -554,8 +563,17 @@ public int
 magic_getparam(struct magic_set *ms, int param, void *val)
 {
        switch (param) {
-       case MAGIC_PARAM_MAX_RECURSION:
-               *(size_t *)val = ms->max_recursion;
+       case MAGIC_PARAM_INDIR_RECURSION:
+               *(size_t *)val = ms->indir_recursion;
+               return 0;
+       case MAGIC_PARAM_NAME_RECURSION:
+               *(size_t *)val = ms->name_recursion;
+               return 0;
+       case MAGIC_PARAM_PHNUM_MAX:
+               *(size_t *)val = ms->phnum_max;
+               return 0;
+       case MAGIC_PARAM_SHNUM_MAX:
+               *(size_t *)val = ms->shnum_max;
                return 0;
        default:
                errno = EINVAL;
index 9bf7d29015c5626d8e3dd40b621f4406a24956e8..ddd9253572e00a2e71918a80462329e306d7effb 100644 (file)
@@ -103,7 +103,11 @@ int magic_check(magic_t, const char *);
 int magic_list(magic_t, const char *);
 int magic_errno(magic_t);
 
-#define MAGIC_PARAM_MAX_RECURSION      0
+#define MAGIC_PARAM_INDIR_RECURSION    0
+#define MAGIC_PARAM_NAME_RECURSION     1
+#define MAGIC_PARAM_PHNUM_MAX          2
+#define MAGIC_PARAM_SHNUM_MAX          3
+
 int magic_setparam(magic_t, int, const void *);
 int magic_getparam(magic_t, int, void *);
 
index bbb82e60fbe622d13acd12856940ff833111000b..9d9c943a2ee49d8bde5db895fb0707c6e540b464 100644 (file)
@@ -32,7 +32,7 @@
 #include "file.h"
 
 #ifndef        lint
-FILE_RCSID("@(#)$File: softmagic.c,v 1.199 2014/11/27 15:40:36 christos Exp $")
+FILE_RCSID("@(#)$File: softmagic.c,v 1.200 2014/11/27 23:42:58 christos Exp $")
 #endif /* lint */
 
 #include "magic.h"
@@ -43,11 +43,11 @@ FILE_RCSID("@(#)$File: softmagic.c,v 1.199 2014/11/27 15:40:36 christos Exp $")
 #include <time.h>
 
 private int match(struct magic_set *, struct magic *, uint32_t,
-    const unsigned char *, size_t, size_t, int, int, int, size_t, int *, int *,
-    int *);
+    const unsigned char *, size_t, size_t, int, int, int, uint16_t, uint16_t,
+    int *, int *, int *);
 private int mget(struct magic_set *, const unsigned char *,
-    struct magic *, size_t, size_t, unsigned int, int, int, int, size_t, int *,
-    int *, int *);
+    struct magic *, size_t, size_t, unsigned int, int, int, int, uint16_t,
+    uint16_t, int *, int *, int *);
 private int magiccheck(struct magic_set *, struct magic *);
 private int32_t mprint(struct magic_set *, struct magic *);
 private int32_t moffset(struct magic_set *, struct magic *);
@@ -71,15 +71,15 @@ private void cvt_64(union VALUETYPE *, const struct magic *);
 /*ARGSUSED1*/          /* nbytes passed for regularity, maybe need later */
 protected int
 file_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes,
-    size_t level, int mode, int text)
+    uint16_t indir_level, uint16_t name_level, int mode, int text)
 {
        struct mlist *ml;
        int rv, printed_something = 0, need_separator = 0;
 
        for (ml = ms->mlist[0]->next; ml != ms->mlist[0]; ml = ml->next)
                if ((rv = match(ms, ml->magic, ml->nmagic, buf, nbytes, 0, mode,
-                   text, 0, level, &printed_something, &need_separator,
-                   NULL)) != 0)
+                   text, 0, indir_level, name_level, &printed_something,
+                   &need_separator, NULL)) != 0)
                        return rv;
 
        return 0;
@@ -134,7 +134,7 @@ file_fmtcheck(struct magic_set *ms, const struct magic *m, const char *def,
 private int
 match(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
     const unsigned char *s, size_t nbytes, size_t offset, int mode, int text,
-    int flip, size_t recursion_level, int *printed_something,
+    int flip, uint16_t indir_level, uint16_t name_level, int *printed_something,
     int *need_separator, int *returnval)
 {
        uint32_t magindex = 0;
@@ -172,7 +172,7 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
 
                /* if main entry matches, print it... */
                switch (mget(ms, s, m, nbytes, offset, cont_level, mode, text,
-                   flip, recursion_level + 1, printed_something,
+                   flip, indir_level, name_level, printed_something,
                    need_separator, returnval)) {
                case -1:
                        return -1;
@@ -261,8 +261,8 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
                        }
 #endif
                        switch (mget(ms, s, m, nbytes, offset, cont_level, mode,
-                           text, flip, recursion_level + 1, printed_something,
-                           need_separator, returnval)) {
+                           text, flip, indir_level, name_level,
+                           printed_something, need_separator, returnval)) {
                        case -1:
                                return -1;
                        case 0:
@@ -1215,7 +1215,7 @@ mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir,
 private int
 mget(struct magic_set *ms, const unsigned char *s, struct magic *m,
     size_t nbytes, size_t o, unsigned int cont_level, int mode, int text,
-    int flip, size_t recursion_level, int *printed_something,
+    int flip, uint16_t indir_level, uint16_t name_level, int *printed_something,
     int *need_separator, int *returnval)
 {
        uint32_t offset = ms->offset;
@@ -1226,9 +1226,15 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m,
        union VALUETYPE *p = &ms->ms_value;
        struct mlist ml;
 
-       if (recursion_level >= ms->max_recursion) {
-               file_error(ms, 0, "recursion nesting (%zu) exceeded",
-                   recursion_level);
+       if (indir_level >= ms->indir_recursion) {
+               file_error(ms, 0, "indirect recursion nesting (%hu) exceeded",
+                   indir_level);
+               return -1;
+       }
+
+       if (name_level >= ms->name_recursion) {
+               file_error(ms, 0, "name recursion nesting (%hu) exceeded",
+                   name_level);
                return -1;
        }
 
@@ -1680,7 +1686,7 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m,
                        return -1;
 
                rv = file_softmagic(ms, s + offset, nbytes - offset,
-                   recursion_level, BINTEST, text);
+                   indir_level + 1, name_level, BINTEST, text);
 
                if ((ms->flags & MAGIC_DEBUG) != 0)
                        fprintf(stderr, "indirect @offs=%u[%d]\n", offset, rv);
@@ -1720,8 +1726,8 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m,
                if (m->flag & NOSPACE)
                        *need_separator = 0;
                rv = match(ms, ml.magic, ml.nmagic, s, nbytes, offset + o,
-                   mode, text, flip, recursion_level, printed_something,
-                   need_separator, returnval);
+                   mode, text, flip, indir_level, name_level + 1,
+                   printed_something, need_separator, returnval);
                if (rv != 1)
                    *need_separator = oneed_separator;
                return rv;