blob: f640ed4bc171397a44ac92c6464ad8bc18308bb4 [file] [log] [blame]
Jari Aalto31859422009-01-12 13:36:28 +00001This file is mapfile.def, from which is created mapfile.c.
2It implements the builtin "mapfile" in Bash.
3
4Copyright (C) 2005-2006 Rocky Bernstein for Free Software Foundation, Inc.
Chet Rameyac50fba2014-02-26 09:36:43 -05005Copyright (C) 2008-2012 Free Software Foundation, Inc.
Jari Aalto31859422009-01-12 13:36:28 +00006
7This file is part of GNU Bash, the Bourne Again SHell.
8
9Bash is free software: you can redistribute it and/or modify
10it under the terms of the GNU General Public License as published by
11the Free Software Foundation, either version 3 of the License, or
12(at your option) any later version.
13
14Bash is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with Bash. If not, see <http://www.gnu.org/licenses/>.
21
22$PRODUCES mapfile.c
23
24$BUILTIN mapfile
25$FUNCTION mapfile_builtin
26$SHORT_DOC mapfile [-n count] [-O origin] [-s count] [-t] [-u fd] [-C callback] [-c quantum] [array]
Chet Ramey00018032011-11-21 20:51:19 -050027Read lines from the standard input into an indexed array variable.
Jari Aalto31859422009-01-12 13:36:28 +000028
Chet Ramey00018032011-11-21 20:51:19 -050029Read lines from the standard input into the indexed array variable ARRAY, or
30from file descriptor FD if the -u option is supplied. The variable MAPFILE
31is the default ARRAY.
Jari Aalto31859422009-01-12 13:36:28 +000032
33Options:
34 -n count Copy at most COUNT lines. If COUNT is 0, all lines are copied.
35 -O origin Begin assigning to ARRAY at index ORIGIN. The default index is 0.
36 -s count Discard the first COUNT lines read.
37 -t Remove a trailing newline from each line read.
38 -u fd Read lines from file descriptor FD instead of the standard input.
39 -C callback Evaluate CALLBACK each time QUANTUM lines are read.
40 -c quantum Specify the number of lines read between each call to CALLBACK.
41
42Arguments:
43 ARRAY Array variable name to use for file data.
44
Jari Aalto17345e52009-02-19 22:21:29 +000045If -C is supplied without -c, the default quantum is 5000. When
46CALLBACK is evaluated, it is supplied the index of the next array
Chet Ramey495aee42011-11-22 19:11:26 -050047element to be assigned and the line to be assigned to that element
48as additional arguments.
Jari Aalto31859422009-01-12 13:36:28 +000049
50If not supplied with an explicit origin, mapfile will clear ARRAY before
51assigning to it.
52
53Exit Status:
Chet Ramey00018032011-11-21 20:51:19 -050054Returns success unless an invalid option is given or ARRAY is readonly or
55not an indexed array.
Jari Aalto31859422009-01-12 13:36:28 +000056$END
57
Jari Aalto17345e52009-02-19 22:21:29 +000058$BUILTIN readarray
59$FUNCTION mapfile_builtin
60$SHORT_DOC readarray [-n count] [-O origin] [-s count] [-t] [-u fd] [-C callback] [-c quantum] [array]
61Read lines from a file into an array variable.
62
63A synonym for `mapfile'.
64$END
65
Jari Aalto31859422009-01-12 13:36:28 +000066#include <config.h>
67
68#include "builtins.h"
69#include "posixstat.h"
70
71#if defined (HAVE_UNISTD_H)
72# include <unistd.h>
73#endif
74
75#include "bashansi.h"
Chet Ramey00018032011-11-21 20:51:19 -050076#include "bashintl.h"
Jari Aalto31859422009-01-12 13:36:28 +000077
78#include <stdio.h>
79#include <errno.h>
80
81#include "../bashintl.h"
82#include "../shell.h"
83#include "common.h"
84#include "bashgetopt.h"
85
Jari Aalto31859422009-01-12 13:36:28 +000086#if !defined (errno)
Ricardo Cerqueiraa02fbff2013-07-25 22:35:34 +010087#include <errno.h>
Jari Aalto31859422009-01-12 13:36:28 +000088#endif
89
90#if defined (ARRAY_VARS)
91
Chet Ramey495aee42011-11-22 19:11:26 -050092static int run_callback __P((const char *, unsigned int, const char *));
93
Jari Aalto31859422009-01-12 13:36:28 +000094#define DEFAULT_ARRAY_NAME "MAPFILE"
Chet Ramey495aee42011-11-22 19:11:26 -050095#define DEFAULT_VARIABLE_NAME "MAPLINE" /* not used right now */
Jari Aalto31859422009-01-12 13:36:28 +000096
97/* The value specifying how frequently `mapfile' calls the callback. */
98#define DEFAULT_QUANTUM 5000
99
100/* Values for FLAGS */
101#define MAPF_CLEARARRAY 0x01
102#define MAPF_CHOP 0x02
103
104static int
Chet Ramey495aee42011-11-22 19:11:26 -0500105run_callback (callback, curindex, curline)
Jari Aalto31859422009-01-12 13:36:28 +0000106 const char *callback;
Chet Ramey495aee42011-11-22 19:11:26 -0500107 unsigned int curindex;
108 const char *curline;
Jari Aalto31859422009-01-12 13:36:28 +0000109{
110 unsigned int execlen;
Chet Ramey495aee42011-11-22 19:11:26 -0500111 char *execstr, *qline;
Jari Aalto17345e52009-02-19 22:21:29 +0000112 int flags;
Jari Aalto31859422009-01-12 13:36:28 +0000113
Chet Ramey495aee42011-11-22 19:11:26 -0500114 qline = sh_single_quote (curline);
115 execlen = strlen (callback) + strlen (qline) + 10;
116 /* 1 for each space between %s and %d,
Jari Aalto31859422009-01-12 13:36:28 +0000117 another 1 for the last nul char for C string. */
Chet Ramey495aee42011-11-22 19:11:26 -0500118 execlen += 3;
Jari Aalto31859422009-01-12 13:36:28 +0000119 execstr = xmalloc (execlen);
120
Chet Ramey00018032011-11-21 20:51:19 -0500121 flags = SEVAL_NOHIST;
Jari Aalto17345e52009-02-19 22:21:29 +0000122#if 0
123 if (interactive)
Chet Ramey00018032011-11-21 20:51:19 -0500124 flags |= SEVAL_INTERACT;
Jari Aalto17345e52009-02-19 22:21:29 +0000125#endif
Chet Ramey495aee42011-11-22 19:11:26 -0500126 snprintf (execstr, execlen, "%s %d %s", callback, curindex, qline);
127 free (qline);
Chet Rameyac50fba2014-02-26 09:36:43 -0500128 return evalstring (execstr, NULL, flags);
Jari Aalto31859422009-01-12 13:36:28 +0000129}
130
131static void
132do_chop(line)
133 char * line;
134{
135 int length;
136
137 length = strlen (line);
138 if (length && line[length-1] == '\n')
139 line[length-1] = '\0';
140}
141
142static int
143mapfile (fd, line_count_goal, origin, nskip, callback_quantum, callback, array_name, flags)
144 int fd;
145 long line_count_goal, origin, nskip, callback_quantum;
146 char *callback, *array_name;
147 int flags;
148{
149 char *line;
150 size_t line_length;
151 unsigned int array_index, line_count;
152 SHELL_VAR *entry;
153 int unbuffered_read;
154
155 line = NULL;
156 line_length = 0;
157 unbuffered_read = 0;
158
159 /* The following check should be done before reading any lines. Doing it
160 here allows us to call bind_array_element instead of bind_array_variable
161 and skip the variable lookup on every call. */
162 entry = find_or_make_array_variable (array_name, 1);
Jari Aalto17345e52009-02-19 22:21:29 +0000163 if (entry == 0 || readonly_p (entry) || noassign_p (entry))
164 {
Chet Ramey00018032011-11-21 20:51:19 -0500165 if (entry && readonly_p (entry))
Jari Aalto17345e52009-02-19 22:21:29 +0000166 err_readonly (array_name);
167
168 return (EXECUTION_FAILURE);
169 }
Chet Ramey00018032011-11-21 20:51:19 -0500170 else if (array_p (entry) == 0)
171 {
172 builtin_error (_("%s: not an indexed array"), array_name);
173 return (EXECUTION_FAILURE);
174 }
Chet Rameyac50fba2014-02-26 09:36:43 -0500175 else if (invisible_p (entry))
176 VUNSETATTR (entry, att_invisible); /* no longer invisible */
Chet Ramey00018032011-11-21 20:51:19 -0500177
Jari Aalto31859422009-01-12 13:36:28 +0000178 if (flags & MAPF_CLEARARRAY)
179 array_flush (array_cell (entry));
180
181#ifndef __CYGWIN__
182 unbuffered_read = (lseek (fd, 0L, SEEK_CUR) < 0) && (errno == ESPIPE);
183#else
184 unbuffered_read = 1;
185#endif
186
Jari Aalto17345e52009-02-19 22:21:29 +0000187 zreset ();
188
Jari Aalto31859422009-01-12 13:36:28 +0000189 /* Skip any lines at beginning of file? */
190 for (line_count = 0; line_count < nskip; line_count++)
Jari Aalto17345e52009-02-19 22:21:29 +0000191 if (zgetline (fd, &line, &line_length, unbuffered_read) < 0)
192 break;
193
Jari Aalto31859422009-01-12 13:36:28 +0000194 line = 0;
195 line_length = 0;
196
197 /* Reset the buffer for bash own stream */
Jari Aalto17345e52009-02-19 22:21:29 +0000198 for (array_index = origin, line_count = 1;
Chet Ramey8e9dc912012-07-10 09:44:43 -0400199 zgetline (fd, &line, &line_length, unbuffered_read) != -1;
200 array_index++)
Jari Aalto31859422009-01-12 13:36:28 +0000201 {
Jari Aalto31859422009-01-12 13:36:28 +0000202 /* Remove trailing newlines? */
203 if (flags & MAPF_CHOP)
204 do_chop (line);
205
206 /* Has a callback been registered and if so is it time to call it? */
207 if (callback && line_count && (line_count % callback_quantum) == 0)
208 {
Chet Ramey495aee42011-11-22 19:11:26 -0500209 run_callback (callback, array_index, line);
Jari Aalto31859422009-01-12 13:36:28 +0000210
211 /* Reset the buffer for bash own stream. */
212 if (unbuffered_read == 0)
213 zsyncfd (fd);
214 }
215
Chet Rameyac50fba2014-02-26 09:36:43 -0500216 /* XXX - bad things can happen if the callback modifies ENTRY, e.g.,
217 unsetting it or changing it to a non-indexed-array type. */
Jari Aalto31859422009-01-12 13:36:28 +0000218 bind_array_element (entry, array_index, line, 0);
Chet Ramey8e9dc912012-07-10 09:44:43 -0400219
220 /* Have we exceeded # of lines to store? */
221 line_count++;
222 if (line_count_goal != 0 && line_count > line_count_goal)
223 break;
Jari Aalto31859422009-01-12 13:36:28 +0000224 }
225
226 xfree (line);
227
228 if (unbuffered_read == 0)
229 zsyncfd (fd);
230
Jari Aalto31859422009-01-12 13:36:28 +0000231 return EXECUTION_SUCCESS;
232}
233
234int
235mapfile_builtin (list)
236 WORD_LIST *list;
237{
238 int opt, code, fd, clear_array, flags;
239 intmax_t intval;
240 long lines, origin, nskip, callback_quantum;
241 char *array_name, *callback;
242
243 clear_array = 1;
244 fd = 0;
245 lines = origin = nskip = 0;
246 flags = MAPF_CLEARARRAY;
247 callback_quantum = DEFAULT_QUANTUM;
248 callback = 0;
249
250 reset_internal_getopt ();
251 while ((opt = internal_getopt (list, "u:n:O:tC:c:s:")) != -1)
252 {
253 switch (opt)
254 {
255 case 'u':
256 code = legal_number (list_optarg, &intval);
257 if (code == 0 || intval < 0 || intval != (int)intval)
258 {
259 builtin_error (_("%s: invalid file descriptor specification"), list_optarg);
260 return (EXECUTION_FAILURE);
261 }
262 else
263 fd = intval;
264
265 if (sh_validfd (fd) == 0)
266 {
267 builtin_error (_("%d: invalid file descriptor: %s"), fd, strerror (errno));
268 return (EXECUTION_FAILURE);
269 }
270 break;
271
272 case 'n':
273 code = legal_number (list_optarg, &intval);
274 if (code == 0 || intval < 0 || intval != (unsigned)intval)
275 {
276 builtin_error (_("%s: invalid line count"), list_optarg);
277 return (EXECUTION_FAILURE);
278 }
279 else
280 lines = intval;
281 break;
282
283 case 'O':
284 code = legal_number (list_optarg, &intval);
285 if (code == 0 || intval < 0 || intval != (unsigned)intval)
286 {
287 builtin_error (_("%s: invalid array origin"), list_optarg);
288 return (EXECUTION_FAILURE);
289 }
290 else
291 origin = intval;
292 flags &= ~MAPF_CLEARARRAY;
293 break;
294 case 't':
295 flags |= MAPF_CHOP;
296 break;
297 case 'C':
298 callback = list_optarg;
299 break;
300 case 'c':
301 code = legal_number (list_optarg, &intval);
Chet Ramey00018032011-11-21 20:51:19 -0500302 if (code == 0 || intval <= 0 || intval != (unsigned)intval)
Jari Aalto31859422009-01-12 13:36:28 +0000303 {
304 builtin_error (_("%s: invalid callback quantum"), list_optarg);
305 return (EXECUTION_FAILURE);
306 }
307 else
308 callback_quantum = intval;
309 break;
310 case 's':
311 code = legal_number (list_optarg, &intval);
312 if (code == 0 || intval < 0 || intval != (unsigned)intval)
313 {
314 builtin_error (_("%s: invalid line count"), list_optarg);
315 return (EXECUTION_FAILURE);
316 }
317 else
318 nskip = intval;
319 break;
320 default:
321 builtin_usage ();
322 return (EX_USAGE);
323 }
324 }
325 list = loptend;
326
327 if (list == 0)
328 array_name = DEFAULT_ARRAY_NAME;
329 else if (list->word == 0 || list->word->word == 0)
330 {
331 builtin_error ("internal error: getting variable name");
332 return (EXECUTION_FAILURE);
333 }
334 else if (list->word->word[0] == '\0')
335 {
336 builtin_error (_("empty array variable name"));
337 return (EX_USAGE);
338 }
339 else
340 array_name = list->word->word;
341
342 if (legal_identifier (array_name) == 0 && valid_array_reference (array_name) == 0)
343 {
344 sh_invalidid (array_name);
345 return (EXECUTION_FAILURE);
346 }
347
348 return mapfile (fd, lines, origin, nskip, callback_quantum, callback, array_name, flags);
349}
350
351#else
352
353int
354mapfile_builtin (list)
355 WORD_LIST *list;
356{
357 builtin_error (_("array variable support required"));
358 return (EXECUTION_FAILURE);
359}
360
361#endif /* ARRAY_VARS */