1 /* csv - process a line of csv data and populate an indexed array with the
5 Copyright (C) 2020 Free Software Foundation, Inc.
7 Bush is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 Bush is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Bush. If not, see <http://www.gnu.org/licenses/>.
21 /* See Makefile for compilation details. */
25 #if defined (HAVE_UNISTD_H)
31 #include "loadables.h"
33 #define CSV_ARRAY_DEFAULT "CSV"
38 /* Split LINE into comma-separated fields, storing each field into a separate
39 element of array variable CSV, starting at index 0. The format of LINE is
40 as described in RFC 4180. */
47 char *field
, *prev
, *buf
, *xbuf
;
60 xbuf
= xmalloc (strlen (prev
) + 1);
64 for (field
= ++prev
; *field
; field
++)
66 if (qstate
== DQUOTE
&& *field
== '"' && field
[1] == '"')
67 buf
[b
++] = *field
++; /* skip double quote */
68 else if (qstate
== DQUOTE
&& *field
== '"')
70 else if (qstate
== NQUOTE
&& *field
== ',')
73 /* This copies any text between a closing double quote and the
74 delimiter. If you want to change that, make sure to do the
75 copy only if qstate == DQUOTE. */
83 field
= prev
+ strcspn (prev
, ",");
89 bind_array_element (csv
, ind
, buf
, 0);
102 return (rval
= ind
); /* number of fields */
110 char *array_name
, *csvstring
;
114 rval
= EXECUTION_SUCCESS
;
116 reset_internal_getopt ();
117 while ((opt
= internal_getopt (list
, "a:")) != -1)
122 array_name
= list_optarg
;
133 array_name
= CSV_ARRAY_DEFAULT
;
135 if (legal_identifier (array_name
) == 0)
137 sh_invalidid (array_name
);
138 return (EXECUTION_FAILURE
);
143 builtin_error ("csv string argument required");
147 v
= find_or_make_array_variable (array_name
, 1);
148 if (v
== 0 || readonly_p (v
) || noassign_p (v
))
150 if (v
&& readonly_p (v
))
151 err_readonly (array_name
);
152 return (EXECUTION_FAILURE
);
154 else if (array_p (v
) == 0)
156 builtin_error ("%s: not an indexed array", array_name
);
157 return (EXECUTION_FAILURE
);
160 VUNSETATTR (v
, att_invisible
);
161 array_flush (array_cell (v
));
163 csvstring
= list
->word
->word
;
165 if (csvstring
== 0 || *csvstring
== 0)
166 return (EXECUTION_SUCCESS
);
168 opt
= csvsplit (v
, csvstring
);
169 /* Maybe do something with OPT here, it's the number of fields */
174 /* Called when builtin is enabled and loaded from the shared object. If this
175 function returns 0, the load fails. */
177 csv_builtin_load (name
)
183 /* Called when builtin is disabled. */
185 csv_builtin_unload (name
)
191 "Read comma-separated fields from a string.",
193 "Parse STRING, a line of comma-separated values, into individual fields,",
194 "and store them into the indexed array ARRAYNAME starting at index 0.",
195 "If ARRAYNAME is not supplied, \"CSV\" is the default array name.",
199 struct builtin csv_struct
= {
200 "csv", /* builtin name */
201 csv_builtin
, /* function implementing the builtin */
202 BUILTIN_ENABLED
, /* initial flags for builtin */
203 csv_doc
, /* array of long documentation strings. */
204 "csv [-a ARRAY] string", /* usage synopsis; becomes short_doc */
205 0 /* reserved for internal use */