]> git.ipfire.org Git - thirdparty/bash.git/blame - builtins/mapfile.def
Bash-4.1 distribution source
[thirdparty/bash.git] / builtins / mapfile.def
CommitLineData
3185942a
JA
1This 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.
5Copyright (C) 2008,2009 Free Software Foundation, Inc.
6
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]
0001803f 27Read lines from the standard input into an indexed array variable.
3185942a 28
0001803f
CR
29Read 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.
3185942a
JA
32
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
17345e5a
JA
45If -C is supplied without -c, the default quantum is 5000. When
46CALLBACK is evaluated, it is supplied the index of the next array
47element to be assigned as an additional argument.
3185942a
JA
48
49If not supplied with an explicit origin, mapfile will clear ARRAY before
50assigning to it.
51
52Exit Status:
0001803f
CR
53Returns success unless an invalid option is given or ARRAY is readonly or
54not an indexed array.
3185942a
JA
55$END
56
17345e5a
JA
57$BUILTIN readarray
58$FUNCTION mapfile_builtin
59$SHORT_DOC readarray [-n count] [-O origin] [-s count] [-t] [-u fd] [-C callback] [-c quantum] [array]
60Read lines from a file into an array variable.
61
62A synonym for `mapfile'.
63$END
64
3185942a
JA
65#include <config.h>
66
67#include "builtins.h"
68#include "posixstat.h"
69
70#if defined (HAVE_UNISTD_H)
71# include <unistd.h>
72#endif
73
74#include "bashansi.h"
0001803f 75#include "bashintl.h"
3185942a
JA
76
77#include <stdio.h>
78#include <errno.h>
79
80#include "../bashintl.h"
81#include "../shell.h"
82#include "common.h"
83#include "bashgetopt.h"
84
3185942a
JA
85#if !defined (errno)
86extern int errno;
87#endif
88
89#if defined (ARRAY_VARS)
90
91#define DEFAULT_ARRAY_NAME "MAPFILE"
92
93/* The value specifying how frequently `mapfile' calls the callback. */
94#define DEFAULT_QUANTUM 5000
95
96/* Values for FLAGS */
97#define MAPF_CLEARARRAY 0x01
98#define MAPF_CHOP 0x02
99
100static int
101run_callback(callback, current_index)
102 const char *callback;
103 unsigned int current_index;
104{
105 unsigned int execlen;
106 char *execstr;
17345e5a 107 int flags;
3185942a
JA
108
109 execlen = strlen (callback) + 10;
110 /* 1 for space between %s and %d,
111 another 1 for the last nul char for C string. */
112 execlen += 2;
113 execstr = xmalloc (execlen);
114
0001803f 115 flags = SEVAL_NOHIST;
17345e5a
JA
116#if 0
117 if (interactive)
0001803f 118 flags |= SEVAL_INTERACT;
17345e5a 119#endif
3185942a 120 snprintf (execstr, execlen, "%s %d", callback, current_index);
17345e5a 121 return parse_and_execute(execstr, NULL, flags);
3185942a
JA
122}
123
124static void
125do_chop(line)
126 char * line;
127{
128 int length;
129
130 length = strlen (line);
131 if (length && line[length-1] == '\n')
132 line[length-1] = '\0';
133}
134
135static int
136mapfile (fd, line_count_goal, origin, nskip, callback_quantum, callback, array_name, flags)
137 int fd;
138 long line_count_goal, origin, nskip, callback_quantum;
139 char *callback, *array_name;
140 int flags;
141{
142 char *line;
143 size_t line_length;
144 unsigned int array_index, line_count;
145 SHELL_VAR *entry;
146 int unbuffered_read;
147
148 line = NULL;
149 line_length = 0;
150 unbuffered_read = 0;
151
152 /* The following check should be done before reading any lines. Doing it
153 here allows us to call bind_array_element instead of bind_array_variable
154 and skip the variable lookup on every call. */
155 entry = find_or_make_array_variable (array_name, 1);
17345e5a
JA
156 if (entry == 0 || readonly_p (entry) || noassign_p (entry))
157 {
0001803f 158 if (entry && readonly_p (entry))
17345e5a
JA
159 err_readonly (array_name);
160
161 return (EXECUTION_FAILURE);
162 }
0001803f
CR
163 else if (array_p (entry) == 0)
164 {
165 builtin_error (_("%s: not an indexed array"), array_name);
166 return (EXECUTION_FAILURE);
167 }
168
3185942a
JA
169 if (flags & MAPF_CLEARARRAY)
170 array_flush (array_cell (entry));
171
172#ifndef __CYGWIN__
173 unbuffered_read = (lseek (fd, 0L, SEEK_CUR) < 0) && (errno == ESPIPE);
174#else
175 unbuffered_read = 1;
176#endif
177
17345e5a
JA
178 zreset ();
179
3185942a
JA
180 /* Skip any lines at beginning of file? */
181 for (line_count = 0; line_count < nskip; line_count++)
17345e5a
JA
182 if (zgetline (fd, &line, &line_length, unbuffered_read) < 0)
183 break;
184
3185942a
JA
185 line = 0;
186 line_length = 0;
187
188 /* Reset the buffer for bash own stream */
17345e5a
JA
189 interrupt_immediately++;
190 for (array_index = origin, line_count = 1;
191 zgetline (fd, &line, &line_length, unbuffered_read) != -1;
3185942a
JA
192 array_index++, line_count++)
193 {
194 /* Have we exceeded # of lines to store? */
17345e5a 195 if (line_count_goal != 0 && line_count > line_count_goal)
3185942a
JA
196 break;
197
198 /* Remove trailing newlines? */
199 if (flags & MAPF_CHOP)
200 do_chop (line);
201
202 /* Has a callback been registered and if so is it time to call it? */
203 if (callback && line_count && (line_count % callback_quantum) == 0)
204 {
205 run_callback (callback, array_index);
206
207 /* Reset the buffer for bash own stream. */
208 if (unbuffered_read == 0)
209 zsyncfd (fd);
210 }
211
212 bind_array_element (entry, array_index, line, 0);
213 }
214
215 xfree (line);
216
217 if (unbuffered_read == 0)
218 zsyncfd (fd);
219
17345e5a 220 interrupt_immediately--;
3185942a
JA
221 return EXECUTION_SUCCESS;
222}
223
224int
225mapfile_builtin (list)
226 WORD_LIST *list;
227{
228 int opt, code, fd, clear_array, flags;
229 intmax_t intval;
230 long lines, origin, nskip, callback_quantum;
231 char *array_name, *callback;
232
233 clear_array = 1;
234 fd = 0;
235 lines = origin = nskip = 0;
236 flags = MAPF_CLEARARRAY;
237 callback_quantum = DEFAULT_QUANTUM;
238 callback = 0;
239
240 reset_internal_getopt ();
241 while ((opt = internal_getopt (list, "u:n:O:tC:c:s:")) != -1)
242 {
243 switch (opt)
244 {
245 case 'u':
246 code = legal_number (list_optarg, &intval);
247 if (code == 0 || intval < 0 || intval != (int)intval)
248 {
249 builtin_error (_("%s: invalid file descriptor specification"), list_optarg);
250 return (EXECUTION_FAILURE);
251 }
252 else
253 fd = intval;
254
255 if (sh_validfd (fd) == 0)
256 {
257 builtin_error (_("%d: invalid file descriptor: %s"), fd, strerror (errno));
258 return (EXECUTION_FAILURE);
259 }
260 break;
261
262 case 'n':
263 code = legal_number (list_optarg, &intval);
264 if (code == 0 || intval < 0 || intval != (unsigned)intval)
265 {
266 builtin_error (_("%s: invalid line count"), list_optarg);
267 return (EXECUTION_FAILURE);
268 }
269 else
270 lines = intval;
271 break;
272
273 case 'O':
274 code = legal_number (list_optarg, &intval);
275 if (code == 0 || intval < 0 || intval != (unsigned)intval)
276 {
277 builtin_error (_("%s: invalid array origin"), list_optarg);
278 return (EXECUTION_FAILURE);
279 }
280 else
281 origin = intval;
282 flags &= ~MAPF_CLEARARRAY;
283 break;
284 case 't':
285 flags |= MAPF_CHOP;
286 break;
287 case 'C':
288 callback = list_optarg;
289 break;
290 case 'c':
291 code = legal_number (list_optarg, &intval);
0001803f 292 if (code == 0 || intval <= 0 || intval != (unsigned)intval)
3185942a
JA
293 {
294 builtin_error (_("%s: invalid callback quantum"), list_optarg);
295 return (EXECUTION_FAILURE);
296 }
297 else
298 callback_quantum = intval;
299 break;
300 case 's':
301 code = legal_number (list_optarg, &intval);
302 if (code == 0 || intval < 0 || intval != (unsigned)intval)
303 {
304 builtin_error (_("%s: invalid line count"), list_optarg);
305 return (EXECUTION_FAILURE);
306 }
307 else
308 nskip = intval;
309 break;
310 default:
311 builtin_usage ();
312 return (EX_USAGE);
313 }
314 }
315 list = loptend;
316
317 if (list == 0)
318 array_name = DEFAULT_ARRAY_NAME;
319 else if (list->word == 0 || list->word->word == 0)
320 {
321 builtin_error ("internal error: getting variable name");
322 return (EXECUTION_FAILURE);
323 }
324 else if (list->word->word[0] == '\0')
325 {
326 builtin_error (_("empty array variable name"));
327 return (EX_USAGE);
328 }
329 else
330 array_name = list->word->word;
331
332 if (legal_identifier (array_name) == 0 && valid_array_reference (array_name) == 0)
333 {
334 sh_invalidid (array_name);
335 return (EXECUTION_FAILURE);
336 }
337
338 return mapfile (fd, lines, origin, nskip, callback_quantum, callback, array_name, flags);
339}
340
341#else
342
343int
344mapfile_builtin (list)
345 WORD_LIST *list;
346{
347 builtin_error (_("array variable support required"));
348 return (EXECUTION_FAILURE);
349}
350
351#endif /* ARRAY_VARS */