Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package csvprintf for openSUSE:Factory 
checked in at 2021-12-22 20:18:03
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/csvprintf (Old)
 and      /work/SRC/openSUSE:Factory/.csvprintf.new.2520 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "csvprintf"

Wed Dec 22 20:18:03 2021 rev:10 rq:941990 version:1.3.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/csvprintf/csvprintf.changes      2021-12-10 
21:52:41.674900777 +0100
+++ /work/SRC/openSUSE:Factory/.csvprintf.new.2520/csvprintf.changes    
2021-12-22 20:19:06.359876281 +0100
@@ -1,0 +2,10 @@
+Tue Dec 14 21:16:11 UTC 2021 - Archie Cobbs <archie.co...@gmail.com>
+
+- Update to release 1.3.1
+  + Added "-c" flag for explicit column names
+  + Added "-n" flag that only reads column names
+  + Added "-p" flag for prefixing names
+  + Omit special variable names in Bash mode
+  + Fixed build error on systems without 'u_char' defined
+
+-------------------------------------------------------------------

Old:
----
  csvprintf-1.3.0.obscpio

New:
----
  csvprintf-1.3.1.obscpio

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ csvprintf.spec ++++++
--- /var/tmp/diff_new_pack.89w0Za/_old  2021-12-22 20:19:06.807876491 +0100
+++ /var/tmp/diff_new_pack.89w0Za/_new  2021-12-22 20:19:06.811876493 +0100
@@ -17,7 +17,7 @@
 
 
 Name:           csvprintf
-Version:        1.3.0
+Version:        1.3.1
 Release:        0
 Summary:        Simple CSV file parser for the UNIX command line
 License:        Apache-2.0

++++++ _service ++++++
--- /var/tmp/diff_new_pack.89w0Za/_old  2021-12-22 20:19:06.839876506 +0100
+++ /var/tmp/diff_new_pack.89w0Za/_new  2021-12-22 20:19:06.843876508 +0100
@@ -2,8 +2,8 @@
     <service mode="localonly" name="obs_scm">
         <param name="scm">git</param>
         <param name="url">https://github.com/archiecobbs/csvprintf</param>
-        <param name="versionformat">1.3.0</param>
-        <param name="revision">1.3.0</param>
+        <param name="versionformat">1.3.1</param>
+        <param name="revision">1.3.1</param>
         <param name="filename">csvprintf</param>
     </service>
     <service mode="buildtime" name="tar"/>

++++++ csvprintf-1.3.0.obscpio -> csvprintf-1.3.1.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/csvprintf-1.3.0/CHANGES new/csvprintf-1.3.1/CHANGES
--- old/csvprintf-1.3.0/CHANGES 2021-12-09 20:47:36.000000000 +0100
+++ new/csvprintf-1.3.1/CHANGES 2021-12-14 22:11:31.000000000 +0100
@@ -1,3 +1,11 @@
+Version 1.3.1 released December 14, 2021
+
+    - Added "-c" flag for explicit column names
+    - Added "-n" flag that only reads column names
+    - Added "-p" flag for prefixing names
+    - Omit special variable names in Bash mode
+    - Fixed build error on systems without 'u_char' defined
+
 Version 1.3.0 released December 9, 2021
 
     - Added "-b" flag for new Bash output mode
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/csvprintf-1.3.0/Makefile.am 
new/csvprintf-1.3.1/Makefile.am
--- old/csvprintf-1.3.0/Makefile.am     2021-12-09 20:47:36.000000000 +0100
+++ new/csvprintf-1.3.1/Makefile.am     2021-12-14 22:11:31.000000000 +0100
@@ -30,7 +30,14 @@
 
 .PHONY:                        tests
 tests:                 csvprintf
-                       cd tests && ./run.sh
+                       @echo '************'
+                       @echo 'TEST SUITE 1'
+                       @echo '************'
+                       @cd tests && ./run.sh
+                       @echo '************'
+                       @echo 'TEST SUITE 2'
+                       @echo '************'
+                       @cd tests && ./run2.sh
 
 subst=                 sed \
                            -e 's|@PACKAGE[@]|$(PACKAGE)|g' \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/csvprintf-1.3.0/configure.ac 
new/csvprintf-1.3.1/configure.ac
--- old/csvprintf-1.3.0/configure.ac    2021-12-09 20:47:36.000000000 +0100
+++ new/csvprintf-1.3.1/configure.ac    2021-12-14 22:11:31.000000000 +0100
@@ -16,11 +16,11 @@
 # under the License.
 #
 
-AC_INIT([csvprintf - Simple CSV file parser for the UNIX command line], 
[1.3.0], [https://github.com/archiecobbs/csvprintf], [csvprintf])
+AC_INIT([csvprintf - Simple CSV file parser for the UNIX command 
line],[1.3.1],[https://github.com/archiecobbs/csvprintf],[csvprintf])
 AC_CONFIG_AUX_DIR(scripts)
 AM_INIT_AUTOMAKE
 dnl AM_MAINTAINER_MODE
-AC_PREREQ(2.59)
+AC_PREREQ([2.69])
 AC_REVISION($Id$)
 AC_PREFIX_DEFAULT(/usr)
 AC_PROG_MAKE_SET
@@ -57,28 +57,27 @@
     [if test `uname -o` = 'Cygwin' -a -f /usr/lib/libiconv.a; then 
LIBS="-liconv ${LIBS}"; else AC_MSG_ERROR([required function iconv_open 
missing]); fi])
 
 # Check for required header files
-AC_HEADER_STDC
 AC_CHECK_HEADERS(sys/wait.h assert.h ctype.h err.h errno.h stddef.h stdint.h 
stdio.h stdlib.h string.h unistd.h, [],
        [AC_MSG_ERROR([required header file '$ac_header' missing])])
 
 # Optional features
 AC_ARG_ENABLE(assertions,
-    AC_HELP_STRING([--enable-assertions],
+    AS_HELP_STRING([--enable-assertions],
         [enable debugging sanity checks (default NO)]),
     [test x"$enableval" = "xyes" || AC_DEFINE(NDEBUG, 1, [disable 
assertions])],
     [AC_DEFINE(NDEBUG, 1, [disable assertions])])
 AC_ARG_ENABLE(gprof,
-    AC_HELP_STRING([--enable-gprof],
+    AS_HELP_STRING([--enable-gprof],
         [Compile and link with gprof(1) support (default NO)]),
     [test x"$enableval" = "xyes" && CFLAGS="${CFLAGS} -pg"])
 AC_ARG_ENABLE(Werror,
-    AC_HELP_STRING([--enable-Werror],
+    AS_HELP_STRING([--enable-Werror],
         [enable compilation with -Werror flag (default NO)]),
     [test x"$enableval" = "xyes" && CFLAGS="${CFLAGS} -Werror"])
 
 # Generated files
 AC_CONFIG_FILES(Makefile)
-AM_CONFIG_HEADER(config.h)
+AC_CONFIG_HEADERS(config.h)
 
 # Go
 AC_OUTPUT
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/csvprintf-1.3.0/csvprintf.1.in 
new/csvprintf-1.3.1/csvprintf.1.in
--- old/csvprintf-1.3.0/csvprintf.1.in  2021-12-09 20:47:36.000000000 +0100
+++ new/csvprintf-1.3.1/csvprintf.1.in  2021-12-14 22:11:31.000000000 +0100
@@ -81,7 +81,7 @@
 specifier will print the number of columns in the record.
 .Pp
 When the
-.Fl i
+.Fl n
 flag is given, the first row is assumed to contain column names and is not 
output.
 This allows symbolic, instead of numeric, column accessors to be used.
 A symbolic column accessor is the column name enclosed in curly braces.
@@ -97,26 +97,22 @@
 so the use of symbolic column accessors adds an extra consistency check.
 .Sh XML Mode
 With
-.Fl x
-or
-.Fl X ,
+.Fl x ,
 the entire file is converted into an XML document.
 .Pp
 The document element is
 .Ar "<csv>" .
+.Pp
 Each CSV row becomes a
 .Ar "<row>"
 element containing its individual column values as sub-elements.
 .Pp
-With
-.Fl x ,
-the sub-elements are
+The column value sub-elements are named
 .Ar "<col1>" ,
 .Ar "<col2>" ,
-etc.
-.Pp
-With
-.Fl X
+etc.;
+with
+.Fl i ,
 the sub-elements use the column names read from the first row (with illegal 
characters replaced by underscores).
 .Pp
 In XML mode, a character encoding must be assumed; see
@@ -125,28 +121,25 @@
 The
 .Nm xml2csv
 command can convert XML documents generated by
-.Nm
-back into CSV files.
+.Nm "csvprintf -x"
+back into CSV.
 .Sh JSON Mode
 With
 .Fl j ,
 each row is converted into a JSON document.
 .Pp
-This form is described by RFC 7464 and consists of concatenated JSON documents,
-each framed by ASCII RS and LF control characters.
-This output is compatible with the
+This form is described by RFC 7464 and consists of concatenated JSON documents
+framed by ASCII RS and LF control characters, which is compatible with the
 .Xr jq 1
 utility's
 .Fl \-seq
 flag.
 .Pp
-Without
-.Fl i ,
-each row is written as a string array.
-With
+Normally each row is written as a string array;
+with
 .Fl i ,
-each row is written as an object, with a field for each column name.
-An error occurs if two CSV columns have the same name.
+each row is written as an object, using column names for fields.
+An error occurs if two columns have the same name.
 .Pp
 In JSON mode, a character encoding must be assumed; see
 .Fl e .
@@ -155,13 +148,11 @@
 .Fl b ,
 each row is converted into
 .Xr bash 1
-variable assignments which may be applied with the
+variable assignment(s) which may be applied with the
 .Xr eval 1
 command.
 .Pp
-Without
-.Fl i ,
-the output assigns
+Normally the output just assigns
 .Ar ROW
 as an array of values.
 The resulting output can be used like this:
@@ -177,7 +168,7 @@
 With
 .Fl i ,
 each column value is assigned to a separate variable whose name is the 
corresponding column name
-(with underscores replacing non-alphanumeric characters), and an error occurs 
if two CSV columns have the same name.
+(with underscores replacing non-alphanumeric characters), and an error occurs 
if two variables have the same name.
 .Pp
 So an input file like this:
 .Bd -literal -offset indent
@@ -188,13 +179,30 @@
 .Pp
 can be processed like this:
 .Bd -literal -offset indent
-cat input.csv | csvprintf -bi | while read LINE; do
+cat input.csv | csvprintf -bi -p ROW_ | while read LINE; do
     eval "${LINE}"
-    echo "First name: ${First_Name}"
-    echo "Last name: ${Last_Name}"
-    echo "Registered: ${Registered___}"
+    echo "First name: ${ROW_First_Name}"
+    echo "Last name: ${ROW_Last_Name}"
+    echo "Registered: ${ROW_Registered___}"
 done
 .Ed
+.Pp
+The
+.Fl i
+flag opens a potential security hole because Bash has several special 
variables like
+.Ar PATH ,
+.Ar TMPDIR ,
+etc., which could be overwritten by malicious input.
+To prevent this,
+.Nm
+omits known Bash variables.
+They can be explicitly white-listed using the
+.Fl c
+flag.
+.Pp
+In any case, use of the
+.Fl p
+flag is recommended in Bash Mode to help avoid namespace collisions.
 .Sh Input Encoding
 In all modes, lines must be terminated by LF bytes or CR+LF byte pairs, and 
the separator and quote characters must be recognizable as single byte values.
 This parsing behavior is compatible with ASCII, ISO-8859-1, UTF-8, etc., but 
not multi-byte encodings such as UTF-16, which must be re-encoded (e.g., to 
UTF-8) first.
@@ -211,6 +219,16 @@
 Convert each CSV row into a
 .Xr bash 1
 variable assignment line.
+.It Fl c Ar colname
+Specify a column to be included when using column names in XML, JSON, or Bash 
output.
+.Pp
+Without this flag, all columns are included.
+When this flag is used one or more times,
+only the specified columns are included.
+.Pp
+If any
+.Ar colname
+doesn't exist, an error occurs.
 .It Fl e
 Specify input character encoding for XML or JSON mode.
 .Pp
@@ -222,15 +240,16 @@
 .Nm
 reads from standard input.
 .It Fl i
-Assume the first CSV record contains column names and omit that record from 
the output.
+Use column names read from the first record in the output.
 .Pp
-In normal mode, enable symbolic column accessors.
-.Pp
-In XML mode, use column names for the inner-most XML elements.
+In normal mode, or when used with the
+.Fl x
+flag, this flag is equivalent to
+.Fl n .
 .Pp
 In JSON mode, output objects instead of arrays and use column names for the 
object fields.
 .Pp
-In Bash mode, output multiple variable assignments using column names instead 
of a single
+In Bash mode, output a variable for each column instead of a single
 .Ar ROW
 array variable.
 .Pp
@@ -240,9 +259,23 @@
 reverts to using
 .Ar col1 ,
 .Ar col2 ,
-etc.
+etc., for any extra columns.
+.Pp
+This flag implies
+.Fl n .
 .It Fl j
-Convert the CSV input into a JavaScript Object Notation (JSON) text sequence 
document.
+Convert the input into a JavaScript Object Notation (JSON) text sequence 
document.
+.It Fl n
+Assume the first CSV record contains column names and omit from the output.
+.Pp
+In normal mode, enable symbolic column accessors.
+.It Fl p
+Specify a common prefix (UTF-8 encoding) to use with all column names in the 
output.
+.Pp
+This flag is ignored unless
+.Fl i
+is specified.
+.Pp
 .It Fl q
 Specify an alternate CSV column quote character.
 The usual backslash escape sequences are accepted.
@@ -258,14 +291,12 @@
 .It Fl v
 Output version information and exit.
 .It Fl x
-Convert the CSV input into an XML document.
+Convert the input into an XML document.
 .It Fl X
-Same as
-.Fl x ,
-but it also causes the values in the first row to be used as the XML tag names 
for the corresponding columns.
+Convert the input into an XML document using column names for value 
sub-elements.
 .Pp
 This flag implies
-.Fl i .
+.Fl n .
 .El
 .Sh CSV FORMAT
 .Nm
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/csvprintf-1.3.0/main.c new/csvprintf-1.3.1/main.c
--- old/csvprintf-1.3.0/main.c  2021-12-09 20:47:36.000000000 +0100
+++ new/csvprintf-1.3.1/main.c  2021-12-14 22:11:31.000000000 +0100
@@ -36,9 +36,10 @@
 #define XML_OUTPUT_ENCODING     "UTF-8"
 
 #define MODE_NORMAL             0           // normal mode
-#define MODE_XML                1           // XML mode
-#define MODE_JSON               2           // JSON mode
-#define MODE_BASH               3           // bash mode
+#define MODE_XML_PLAIN          1           // plain XML mode
+#define MODE_XML_NAMES          2           // XML mode with names
+#define MODE_JSON               3           // JSON mode
+#define MODE_BASH               4           // bash mode
 
 struct col {
     char    *buf;
@@ -55,6 +56,21 @@
 static int quote = DEFAULT_QUOTE_CHAR;
 static int fsep = DEFAULT_FSEP_CHAR;
 
+static const char *bash_special_vars[] = {
+    "BASH", "BASHOPTS", "BASHPID", "BASH_ALIASES", "BASH_ARGC", "BASH_ARGV", 
"BASH_CMDS", "BASH_COMMAND",
+    "BASH_EXECUTION_STRING", "BASH_LINENO", "BASH_LOADABLES_PATH", 
"BASH_REMATCH", "BASH_SOURCE", "BASH_SUBSHELL",
+    "BASH_VERSINFO", "BASH_VERSION", "COMP_CWORD", "COMP_KEY", "COMP_LINE", 
"COMP_POINT", "COMP_TYPE", "COMP_WORDBREAKS",
+    "COMP_WORDS", "COPROC", "DIRSTACK", "EUID", "FUNCNAME", "GROUPS", 
"HISTCMD", "HOSTNAME", "HOSTTYPE", "LINENO",
+    "MACHTYPE", "MAPFILE", "OLDPWD", "OPTARG", "OPTIND", "OSTYPE", 
"PIPESTATUS", "PPID", "PWD", "RANDOM", "READLINE_LINE",
+    "READLINE_POINT", "REPLY", "SECONDS", "SHELLOPTS", "SHLVL", "UID", 
"BASH_COMPAT", "BASH_ENV", "BASH_XTRACEFD", "CDPATH",
+    "CHILD_MAX", "COLUMNS", "COMPREPLY", "EMACS", "ENV", "EXECIGNORE", 
"FCEDIT", "FIGNORE", "FUNCNEST", "GLOBIGNORE",
+    "HISTCONTROL", "HISTFILE", "HISTFILESIZE", "HISTIGNORE", "HISTSIZE", 
"HISTTIMEFORMAT", "HOME", "HOSTFILE", "IFS",
+    "IGNOREEOF", "INPUTRC", "LANG", "LC_ALL", "LC_COLLATE", "LC_CTYPE", 
"LC_MESSAGES", "LC_NUMERIC", "LC_TIME", "LINES",
+    "MAIL", "MAILCHECK", "MAILPATH", "OPTERR", "PATH", "POSIXLY_CORRECT", 
"PROMPT_COMMAND", "PROMPT_DIRTRIM", "PS0", "PS1",
+    "PS2", "PS3", "PS4", "SHELL", "TIMEFORMAT", "TMOUT", "TMPDIR", 
"auto_resume", "histchars"
+};
+#define NUM_BASH_SPECIAL_VARS   (sizeof(bash_special_vars) / 
sizeof(*bash_special_vars))
+
 static int parsechar(const char *str);
 static int parsefmt(char *fmt, const struct row *column_names, unsigned int 
**argsp);
 static int readcol(FILE *fp, struct row *row, int *linenum);
@@ -75,6 +91,10 @@
 static char *eataccessor(const char *fspec, const char *desc, const struct row 
*column_names,
     char *s, int *nargs, unsigned int *args);
 static void addcolumn(struct row *row, const struct col *col);
+static void addstring(struct row *row, const char *const string);
+static int findstring(struct row *row, const char *const string);
+static int findstring2(const char *const *list, size_t num, const char *const 
string);
+static void growrow(struct row *row);
 static void addchar(struct col *col, int ch);
 static void trim(struct col *col);
 static void usage(void);
@@ -85,33 +105,40 @@
 {
     const char *input = "-";
     const char *encoding = "ISO-8859-1";
+    const char *name_prefix = "";
     char *format = NULL;
     iconv_t icd = NULL;
     FILE *fp = NULL;
     struct row row;
     struct row column_names;
+    struct row allowed_column_names;
     unsigned int *args = NULL;
     int mode = -1;
-    int read_column_names = 0;
-    int column_name_tags = 0;
+    int read_column_names = 0;                  // strip off first row 
containing column names
+    int use_column_names = 0;                   // use column names from first 
row in output
     int first_row = 0;
     int nargs = 0;
     int file_done;
     int linenum;
+    int new_mode;
     int ch;
 
     // Initialize
     memset(&row, 0, sizeof(row));
     memset(&column_names, 0, sizeof(column_names));
+    memset(&allowed_column_names, 0, sizeof(allowed_column_names));
 
     // Parse command line
-    while ((ch = getopt(argc, argv, "be:f:hijq:s:vxX")) != -1) {
+    while ((ch = getopt(argc, argv, "bc:e:f:hijnp:q:s:vxX")) != -1) {
         switch (ch) {
         case 'b':
             if (mode != -1 && mode != MODE_BASH)
                 errx(1, "flag \"%c\" conflicts with previous mode flag", ch);
             mode = MODE_BASH;
             break;
+        case 'c':
+            addstring(&allowed_column_names, optarg);
+            break;
         case 'e':
             encoding = optarg;
             break;
@@ -120,23 +147,28 @@
             break;
         case 'i':
             read_column_names = 1;
+            use_column_names = 1;
+            break;
+        case 'n':
+            read_column_names = 1;
             break;
         case 'j':
             if (mode != -1 && mode != MODE_JSON)
                 errx(1, "flag \"%c\" conflicts with previous mode flag", ch);
             mode = MODE_JSON;
             break;
+        case 'X':
         case 'x':
-            if (mode != -1 && !(mode == MODE_XML && !column_name_tags))
+            new_mode = ch == 'X' ? MODE_XML_NAMES : MODE_XML_PLAIN;
+            if (mode != -1 && mode != new_mode)
                 errx(1, "flag \"%c\" conflicts with previous mode flag", ch);
-            mode = MODE_XML;
+            if ((mode = new_mode) == MODE_XML_NAMES) {
+                use_column_names = 1;
+                read_column_names = 1;
+            }
             break;
-        case 'X':
-            if (mode != -1 && !(mode == MODE_XML && column_name_tags))
-                errx(1, "flag \"%c\" conflicts with previous mode flag", ch);
-            mode = MODE_XML;
-            column_name_tags = 1;
-            read_column_names = 1;
+        case 'p':
+            name_prefix = optarg;
             break;
         case 'q':
             if ((quote = parsechar(optarg)) == -1)
@@ -167,9 +199,15 @@
         exit(1);
     }
 
+    // Backward compatbitility hack
+    if (mode == MODE_XML_PLAIN)
+        use_column_names = 0;
+
     // Sanity check
     if (quote == fsep)
         err(1, "quote and field separators cannot be the same character");
+    if (allowed_column_names.num > 0 && !read_column_names)
+        err(1, "\"-c\" flag requires \"-n\" flag");
 
     // Get and (maybe) parse format string (normal mode only)
     if (mode == MODE_NORMAL) {
@@ -188,7 +226,8 @@
 
     // Initialize iconv
     switch (mode) {
-    case MODE_XML:
+    case MODE_XML_PLAIN:
+    case MODE_XML_NAMES:
     case MODE_JSON:
         if ((icd = iconv_open(XML_OUTPUT_ENCODING, encoding)) == (iconv_t)-1)
             err(1, "%s", encoding);
@@ -198,7 +237,7 @@
     }
 
     // XML opening
-    if (mode == MODE_XML) {
+    if (mode == MODE_XML_PLAIN || mode == MODE_XML_NAMES) {
         printf("<?xml version=\"1.0\" encoding=\"%s\"?>\n", 
XML_OUTPUT_ENCODING);
         printf("<csv>\n");
     }
@@ -227,6 +266,7 @@
 
         // Gather column names from first row, if configured
         if (first_row && read_column_names) {
+            int i, j;
 
             // Convert to UTF-8 if needed
             if (icd != NULL)
@@ -240,12 +280,15 @@
             if (mode == MODE_NORMAL)
                 nargs = parsefmt(format, &column_names, &args);
 
+            // Check that all explicitly specified columns are actually present
+            for (i = 0; i < allowed_column_names.num; i++) {
+                if (!findstring(&column_names, allowed_column_names.fields[i]))
+                    errx(1, "column \"%s\" not found", 
allowed_column_names.fields[i]);
+            }
+
             // Check for illegal or duplicate column names
             switch (mode) {
             case MODE_JSON:
-              {
-                int i, j;
-
                 for (i = 0; i < column_names.num - 1; i++) {
                     for (j = i + 1; j < column_names.num; j++) {
                         if (strcmp(column_names.fields[i], 
column_names.fields[j]) == 0)
@@ -253,21 +296,21 @@
                     }
                 }
                 break;
-              }
             case MODE_BASH:
-              {
-                int i, j;
-
                 for (i = 0; i < column_names.num; i++) {
-                    const char *const namei = column_names.fields[i];
+                    char *namei;
 
+                    if (asprintf(&namei, "%s%s", name_prefix, 
column_names.fields[i]) == -1)
+                        err(1, "asprintf");
                     if (*namei == '\0')
                         errx(1, "illegal empty string column name");
                     for (j = i + 1; j < column_names.num; j++) {
-                        const char *const namej = column_names.fields[j];
+                        char *namej;
                         int same = 1;
                         int k;
 
+                        if (asprintf(&namej, "%s%s", name_prefix, 
column_names.fields[j]) == -1)
+                            err(1, "asprintf");
                         for (k = 0; namei[k] != '\0' || namej[k] != '\0'; k++) 
{
                             if (namei[k] == '\0' || namej[k] == '\0'
                               || bash_name_safe(namei[k], k == 0) != 
bash_name_safe(namej[k], k == 0)) {
@@ -277,10 +320,11 @@
                         }
                         if (same)
                             errx(1, "duplicate (bash variable) column names 
\"%s\" and \"%s\"", namei, namej);
+                        free(namej);
                     }
+                    free(namei);
                 }
                 break;
-              }
             default:
                 break;
             }
@@ -299,29 +343,42 @@
             convert_to_utf8(icd, &row, linenum);
 
             // Output row
-            printf("\x1e%c", read_column_names ? '{' : '[');
+            printf("\x1e%c", use_column_names ? '{' : '[');
             for (col = 0; col < row.num; col++) {
 
+                // Check whether column should be included
+                if (use_column_names
+                  && allowed_column_names.num > 0
+                  && col < column_names.num
+                  && !findstring(&allowed_column_names, 
column_names.fields[col]))
+                    continue;
+
                 // Add comma if needed
                 if (col > 0)
                     putchar(',');
 
                 // Add column name (if using object notation)
-                if (read_column_names) {
-                    if (col < column_names.num)
+                if (use_column_names) {
+                    if (col < column_names.num) {
+                        putchar('"');
+                        print_json_string(name_prefix, linenum);
                         print_json_string(column_names.fields[col], linenum);
-                    else
+                        putchar('"');
+                    } else
                         printf("\"col%d\"", col + 1);
                     putchar(':');
                 }
 
                 // Add column value
+                putchar('"');
                 print_json_string(row.fields[col], linenum);
+                putchar('"');
             }
-            printf("%c\n", read_column_names ? '}' : ']');
+            printf("%c\n", use_column_names ? '}' : ']');
             break;
           }
-        case MODE_XML:
+        case MODE_XML_PLAIN:
+        case MODE_XML_NAMES:
           {
             int col;
 
@@ -338,11 +395,19 @@
                 int uclen;
                 int i;
 
+                // Check whether column should be included
+                if (use_column_names
+                  && allowed_column_names.num > 0
+                  && col < column_names.num
+                  && !findstring(&allowed_column_names, 
column_names.fields[col]))
+                    continue;
+
                 // Open XML tag
                 printf("    <");
-                if (column_name_tags && col < column_names.num)
+                if (use_column_names && col < column_names.num) {
+                    print_xml_tag_name(name_prefix, linenum);
                     print_xml_tag_name(column_names.fields[col], linenum);
-                else
+                } else
                     printf("col%d", col + 1);
                 printf(">");
 
@@ -361,9 +426,10 @@
 
                 // Close XML tag
                 printf("</");
-                if (column_name_tags && col < column_names.num)
+                if (use_column_names && col < column_names.num) {
+                    print_xml_tag_name(name_prefix, linenum);
                     print_xml_tag_name(column_names.fields[col], linenum);
-                else
+                } else
                     printf("col%d", col + 1);
                 printf(">\n");
             }
@@ -372,24 +438,40 @@
           }
         case MODE_BASH:
           {
+            char bash_name_buf[64];         // buffer just needs to be be 
enough to hold any of the bash_special_vars[]
             int col;
 
             // Start array (if needed)
-            if (!read_column_names)
+            if (!use_column_names)
                 printf("ROW=(");
 
             // Output row
             for (col = 0; col < row.num; col++) {
 
+                // Check whether column should be included
+                if (use_column_names
+                  && allowed_column_names.num > 0
+                  && col < column_names.num
+                  && !findstring(&allowed_column_names, 
column_names.fields[col]))
+                    continue;
+
+                // Elide any BASH special variable names
+                if (use_column_names && col < column_names.num) {
+                    snprintf(bash_name_buf, sizeof(bash_name_buf), "%s%s", 
name_prefix, column_names.fields[col]);
+                    if (findstring2(bash_special_vars, NUM_BASH_SPECIAL_VARS, 
bash_name_buf))
+                        continue;
+                }
+
                 // Add space
-                if (col > 0 || !read_column_names)
+                if (col > 0 || !use_column_names)
                     putchar(' ');
 
                 // Add column name (if using column names)
-                if (read_column_names) {
-                    if (col < column_names.num)
+                if (use_column_names) {
+                    if (col < column_names.num) {
+                        print_bash_name(name_prefix);
                         print_bash_name(column_names.fields[col]);
-                    else
+                    } else
                         printf("col%d", col + 1);
                     putchar('=');
                 }
@@ -398,12 +480,12 @@
                 print_bash_value(row.fields[col]);
 
                 // Add separator
-                if (read_column_names)
+                if (use_column_names)
                     putchar(';');
             }
 
             // End array (if needed)
-            if (!read_column_names)
+            if (!use_column_names)
                 printf(" )");
 
             // End line
@@ -465,7 +547,7 @@
     }
 
     // XML closing
-    if (mode == MODE_XML)
+    if (mode == MODE_XML_PLAIN || mode == MODE_XML_NAMES)
         printf("</csv>\n");
 
     // Clean up iconv
@@ -559,7 +641,7 @@
 
     // See if plain single quotes will work
     for (i = 0; string[i] != '\0'; i++) {
-        if (string[i] == '\'' || !isprint((u_char)string[i])) {
+        if (string[i] == '\'' || !isprint((unsigned char)string[i])) {
             single_quotes = 0;
             break;
         }
@@ -597,10 +679,10 @@
                 printf("\\v");
                 break;
             default:
-                if (isprint((u_char)string[i]))
-                    putchar((u_char)string[i]);
+                if (isprint((unsigned char)string[i]))
+                    putchar((unsigned char)string[i]);
                 else
-                    printf("\\x%02x", (u_char)string[i]);
+                    printf("\\x%02x", (unsigned char)string[i]);
                 break;
             }
         }
@@ -611,9 +693,9 @@
 static char
 bash_name_safe(char ch, int first)
 {
-    if (isupper((u_char)ch) || islower((u_char)ch) || ch == '_')
+    if (isupper((unsigned char)ch) || islower((unsigned char)ch) || ch == '_')
         return ch;
-    if (!first && isdigit((u_char)ch))
+    if (!first && isdigit((unsigned char)ch))
         return ch;
     return '_';
 }
@@ -625,7 +707,6 @@
     int uchar;
     int uclen;
 
-    putchar('"');
     while (*string != '\0') {
         uchar = decode_utf8(string, strlen(string), &uclen, linenum);
         switch (uchar) {
@@ -659,7 +740,6 @@
         }
         string += uclen;
     }
-    putchar('"');
 }
 
 // Convert row columns to UTF-8 encoding
@@ -869,9 +949,9 @@
 {
     size_t skip;
 
-    while (col->len > 0 && isspace((u_char)col->buf[col->len - 1]))
+    while (col->len > 0 && isspace((unsigned char)col->buf[col->len - 1]))
         col->len--;
-    for (skip = 0; skip < col->len && isspace((u_char)col->buf[skip]); skip++)
+    for (skip = 0; skip < col->len && isspace((unsigned char)col->buf[skip]); 
skip++)
         ;
     col->len -= skip;
     memmove(col->buf, col->buf + skip, col->len);
@@ -902,20 +982,10 @@
 static void
 addcolumn(struct row *row, const struct col *col)
 {
-    if (row->alloc <= row->num) {
-        int new_alloc;
-        char **new_fields;
-
-        new_alloc = row->alloc == 0 ? 32 : row->alloc * 2;
-        if ((new_fields = realloc(row->fields, new_alloc * 
sizeof(*row->fields))) == NULL)
-            err(1, "realloc");
-        row->fields = new_fields;
-        row->alloc = new_alloc;
-    }
+    growrow(row);
     if (col->alloc >= col->len + 1) {
         col->buf[col->len] = '\0';
         row->fields[row->num] = col->buf;
-        memset(&col, 0, sizeof(col));
     } else {
         if ((row->fields[row->num] = malloc(col->len + 1)) == NULL)
             err(1, "malloc");
@@ -927,6 +997,49 @@
     row->num++;
 }
 
+// Copy given string and add to row
+static void
+addstring(struct row *row, const char *const string)
+{
+    growrow(row);
+    if ((row->fields[row->num++] = strdup(string)) == NULL)
+        err(1, "strdup");
+}
+
+static int
+findstring(struct row *row, const char *const string)
+{
+    return findstring2((const char *const *)row->fields, row->num, string);
+}
+
+static int
+findstring2(const char *const *list, size_t num, const char *const string)
+{
+    size_t i;
+
+    for (i = 0; i < num; i++) {
+        if (strcmp(list[i], string) == 0)
+            return 1;
+    }
+    return 0;
+}
+
+static void
+growrow(struct row *row)
+{
+    size_t new_alloc;
+    char **new_fields;
+
+    if (row->alloc > row->num)
+        return;
+    new_alloc = row->alloc == 0 ? 32 : row->alloc * 2;
+    if ((new_fields = realloc(row->fields, new_alloc * sizeof(*row->fields))) 
== NULL)
+        err(1, "realloc");
+    row->fields = new_fields;
+    row->alloc = new_alloc;
+    memset(row->fields + row->num, 0, (row->alloc - row->num) * 
sizeof(*row->fields));
+}
+
 static int
 parsefmt(char *fmt, const struct row *column_names, unsigned int **argsp)
 {
@@ -1034,7 +1147,7 @@
 {
     if (*s == '*')
         return eataccessor(fspec, desc, column_names, s + 1, nargs, args);
-    while (isdigit((u_char)*s))                                 // eat up 
numerical field width or precision
+    while (isdigit((unsigned char)*s))                          // eat up 
numerical field width or precision
         s++;
     return s;
 }
@@ -1073,7 +1186,7 @@
         }
         args[(*nargs)++] = argnum;
     } else {
-        while (isdigit((u_char)*s))
+        while (isdigit((unsigned char)*s))
             s++;
         if (s == start || *s++ != '$')
             errx(1, "missing required column accessor in %s starting at 
\"%.20s...\"", desc, fspec);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/csvprintf-1.3.0/tests/run2.sh 
new/csvprintf-1.3.1/tests/run2.sh
--- old/csvprintf-1.3.0/tests/run2.sh   1970-01-01 01:00:00.000000000 +0100
+++ new/csvprintf-1.3.1/tests/run2.sh   2021-12-14 22:11:31.000000000 +0100
@@ -0,0 +1,125 @@
+#!/bin/bash
+
+# Bail on error
+set -e
+
+# Setup temporary files
+TMP_STDOUT_EXPECTED='csvprintf-test-out-expected.tmp'
+TMP_STDERR_EXPECTED='csvprintf-test-err-expected.tmp'
+TMP_STDOUT_ACTUAL='csvprintf-test-out-actual.tmp'
+TMP_STDERR_ACTUAL='csvprintf-test-err-actual.tmp'
+TMP_SWAP_FILE=''csvprintf-test-hexdump.tmp
+trap "rm -f \
+    ${TMP_STDOUT_EXPECTED} \
+    ${TMP_STDERR_EXPECTED} \
+    ${TMP_STDOUT_ACTUAL} \
+    ${TMP_STDERR_ACTUAL} \
+    ${TMP_SWAP_FILE}" 0 2 3 5 10 13 15
+
+# Convert a file to hexdump version
+hexdumpify()
+{
+    FILE="${1}"
+    hexdump -C < "${FILE}" > "${TMP_SWAP_FILE}"
+    mv "${TMP_SWAP_FILE}" "${FILE}"
+}
+
+# Compare files, on failure set ${DIFF_FAIL}
+checkdiff()
+{
+    if [ "${1}" = '-h' ]; then
+        HEXDUMPIFY='true'
+        shift
+    else
+        HEXDUMPIFY='false'
+    fi
+    TESTFILE="${1}"
+    WHAT="${2}"
+    EXPECTED="${3}"
+    ACTUAL="${4}"
+    if diff -q "${EXPECTED}" "${ACTUAL}" >/dev/null; then
+        return 0
+    fi
+    echo "test: ${TESTFILE}: ${WHAT} mismatch"
+    echo '------------------------------------------------------'
+    if [ "${HEXDUMPIFY}" = 'true' ]; then
+        hexdumpify "${EXPECTED}"
+        hexdumpify "${ACTUAL}"
+    fi
+    diff -u "${EXPECTED}" "${ACTUAL}" || true
+    echo '------------------------------------------------------'
+    DIFF_FAIL='true'
+}
+
+# Execute one test, on failure set ${TEST_FAIL}
+runtest()
+{
+    # Read test data
+    unset FLAGS
+    unset STDIN
+    unset STDOUT
+    unset STDERR
+    unset EXITVAL
+    . "${TESTFILE}"
+    if [ -z "${FLAGS+x}" \
+      -o -z "${STDIN+x}" \
+      -o -z "${STDOUT+x}" \
+      -o -z "${STDERR+x}" \
+      -o -z "${EXITVAL+x}" ]; then
+        echo "test: ${TESTFILE}: invalid test file"
+        exit 1
+    fi
+
+    # Set up files
+    echo -en "${STDOUT}" > "${TMP_STDOUT_EXPECTED}"
+    echo -en "${STDERR}" > "${TMP_STDERR_EXPECTED}"
+    set +e
+    echo -en "${STDIN}" | ../csvprintf ${FLAGS} >"${TMP_STDOUT_ACTUAL}" 
2>"${TMP_STDERR_ACTUAL}"
+    ACTUAL_EXITVAL="$?"
+    set -e
+
+    # Special hacks
+    if [ "${STDERR}" = '!USAGE!' ]; then
+        ../csvprintf --help 2>"${TMP_STDERR_EXPECTED}"
+    fi
+
+    # Check result
+    DIFF_FAIL='false'
+    if [ "${STDOUT}" != '!IGNORE!' ]; then
+        checkdiff -h "${TESTFILE}" "standard output" "${TMP_STDOUT_EXPECTED}" 
"${TMP_STDOUT_ACTUAL}"
+    fi
+    checkdiff "${TESTFILE}" "standard error" "${TMP_STDERR_EXPECTED}" 
"${TMP_STDERR_ACTUAL}"
+    if [ "${DIFF_FAIL}" != 'false' ]; then
+        TEST_FAIL='true'
+    fi
+    if [ "${ACTUAL_EXITVAL}" -ne "${EXITVAL}" ]; then
+        echo "test: ${TESTFILE}: exit value ${ACTUAL_EXITVAL} != ${EXITVAL}"
+        TEST_FAIL='true'
+    fi
+
+    # Print success or if failure show params
+    if [ "${TEST_FAIL}" = 'false' ]; then
+        echo "test: ${TESTFILE}: success"
+    else
+        echo "******************************************************"
+        echo "test: ${TESTFILE} FAILED with:"
+        echo "  FLAGS='${FLAGS}'"
+        echo "  STDIN='${STDIN}'"
+        echo "******************************************************"
+    fi
+}
+
+# Find all tests and run them
+ANY_FAIL='false'
+for TESTFILE in `find . -maxdepth 1 -type f -name 'test-*.tst' | sort | sed 
's|^./||g'`; do
+    TEST_FAIL='false'
+    runtest "${TESTFILE}"
+    if [ "${TEST_FAIL}" != 'false' ]; then
+        ANY_FAIL='true'
+    fi
+done
+
+# Exit with error if any test failed
+if [ "${ANY_FAIL}" != 'false' ]; then
+    exit 1
+fi
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/csvprintf-1.3.0/tests/test-bash-omit1.tst 
new/csvprintf-1.3.1/tests/test-bash-omit1.tst
--- old/csvprintf-1.3.0/tests/test-bash-omit1.tst       1970-01-01 
01:00:00.000000000 +0100
+++ new/csvprintf-1.3.1/tests/test-bash-omit1.tst       2021-12-14 
22:11:31.000000000 +0100
@@ -0,0 +1,5 @@
+FLAGS='-bi'
+STDIN='aaa,PATH,ccc\n"a1","b1","c1"\n"a2","b2","c2"\n'
+STDOUT=$'aaa=\'a1\'; ccc=\'c1\';\naaa=\'a2\'; ccc=\'c2\';\n'
+STDERR=''
+EXITVAL='0'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/csvprintf-1.3.0/tests/test-bash-prefix1.tst 
new/csvprintf-1.3.1/tests/test-bash-prefix1.tst
--- old/csvprintf-1.3.0/tests/test-bash-prefix1.tst     1970-01-01 
01:00:00.000000000 +0100
+++ new/csvprintf-1.3.1/tests/test-bash-prefix1.tst     2021-12-14 
22:11:31.000000000 +0100
@@ -0,0 +1,5 @@
+FLAGS='-bi -p FOO_'
+STDIN='aaa,PATH,ccc\n"a1","b1","c1"\n"a2","b2","c2"\n'
+STDOUT=$'FOO_aaa=\'a1\'; FOO_PATH=\'b1\'; FOO_ccc=\'c1\';\nFOO_aaa=\'a2\'; 
FOO_PATH=\'b2\'; FOO_ccc=\'c2\';\n'
+STDERR=''
+EXITVAL='0'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/csvprintf-1.3.0/tests/test-bash-prefix2.tst 
new/csvprintf-1.3.1/tests/test-bash-prefix2.tst
--- old/csvprintf-1.3.0/tests/test-bash-prefix2.tst     1970-01-01 
01:00:00.000000000 +0100
+++ new/csvprintf-1.3.1/tests/test-bash-prefix2.tst     2021-12-14 
22:11:31.000000000 +0100
@@ -0,0 +1,5 @@
+FLAGS='-bi -p PA'
+STDIN='aaa,TH,ccc\n"a1","b1","c1"\n"a2","b2","c2"\n'
+STDOUT=$'PAaaa=\'a1\'; PAccc=\'c1\';\nPAaaa=\'a2\'; PAccc=\'c2\';\n'
+STDERR=''
+EXITVAL='0'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/csvprintf-1.3.0/tests/test-cflag-not-found.tst 
new/csvprintf-1.3.1/tests/test-cflag-not-found.tst
--- old/csvprintf-1.3.0/tests/test-cflag-not-found.tst  1970-01-01 
01:00:00.000000000 +0100
+++ new/csvprintf-1.3.1/tests/test-cflag-not-found.tst  2021-12-14 
22:11:31.000000000 +0100
@@ -0,0 +1,5 @@
+FLAGS='-X -c bbb -c zzz'
+STDIN='aaa,bbb,ccc\n"a1","b1","c1"\n"a2","b2","c2"\n'
+STDOUT='!IGNORE!'
+STDERR='csvprintf: column "zzz" not found\n'
+EXITVAL='1'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/csvprintf-1.3.0/tests/test-cflag-xml.tst 
new/csvprintf-1.3.1/tests/test-cflag-xml.tst
--- old/csvprintf-1.3.0/tests/test-cflag-xml.tst        1970-01-01 
01:00:00.000000000 +0100
+++ new/csvprintf-1.3.1/tests/test-cflag-xml.tst        2021-12-14 
22:11:31.000000000 +0100
@@ -0,0 +1,5 @@
+FLAGS='-X -c bbb'
+STDIN='aaa,bbb,ccc\n"a1","b1","c1"\n"a2","b2","c2"\n'
+STDOUT='<?xml version="1.0" encoding="UTF-8"?>\n<csv>\n  <row>\n    
<bbb>b1</bbb>\n  </row>\n  <row>\n    <bbb>b2</bbb>\n  </row>\n</csv>\n'
+STDERR=''
+EXITVAL='0'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/csvprintf-1.3.0/tests/test-json-skip1.tst 
new/csvprintf-1.3.1/tests/test-json-skip1.tst
--- old/csvprintf-1.3.0/tests/test-json-skip1.tst       1970-01-01 
01:00:00.000000000 +0100
+++ new/csvprintf-1.3.1/tests/test-json-skip1.tst       2021-12-14 
22:11:31.000000000 +0100
@@ -0,0 +1,5 @@
+FLAGS='-jn'
+STDIN='aaa,bbb\n"a1","b1"\n"a2","b2"\n'
+STDOUT='\x1e["a1","b1"]\n\x1e["a2","b2"]\n'
+STDERR=''
+EXITVAL='0'

++++++ csvprintf.obsinfo ++++++
--- /var/tmp/diff_new_pack.89w0Za/_old  2021-12-22 20:19:06.947876557 +0100
+++ /var/tmp/diff_new_pack.89w0Za/_new  2021-12-22 20:19:06.947876557 +0100
@@ -1,6 +1,6 @@
 name: csvprintf
-version: 1.3.0
-mtime: 1639079256
-commit: 57eae72333bf69be54b884e56bd8136d6abce19d
+version: 1.3.1
+mtime: 1639516291
+commit: 5d84b997c8ce5f1946a7df6c29cc4bc799e53f1b
 
 

Reply via email to