]> git.ipfire.org Git - thirdparty/bash.git/blob - builtins/mapfile.def
Bash-4.3 distribution sources and documentation
[thirdparty/bash.git] / builtins / mapfile.def
1 This file is mapfile.def, from which is created mapfile.c.
2 It implements the builtin "mapfile" in Bash.
3
4 Copyright (C) 2005-2006 Rocky Bernstein for Free Software Foundation, Inc.
5 Copyright (C) 2008-2012 Free Software Foundation, Inc.
6
7 This file is part of GNU Bash, the Bourne Again SHell.
8
9 Bash is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 Bash is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along 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]
27 Read lines from the standard input into an indexed array variable.
28
29 Read lines from the standard input into the indexed array variable ARRAY, or
30 from file descriptor FD if the -u option is supplied. The variable MAPFILE
31 is the default ARRAY.
32
33 Options:
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
42 Arguments:
43 ARRAY Array variable name to use for file data.
44
45 If -C is supplied without -c, the default quantum is 5000. When
46 CALLBACK is evaluated, it is supplied the index of the next array
47 element to be assigned and the line to be assigned to that element
48 as additional arguments.
49
50 If not supplied with an explicit origin, mapfile will clear ARRAY before
51 assigning to it.
52
53 Exit Status:
54 Returns success unless an invalid option is given or ARRAY is readonly or
55 not an indexed array.
56 $END
57
58 $BUILTIN readarray
59 $FUNCTION mapfile_builtin
60 $SHORT_DOC readarray [-n count] [-O origin] [-s count] [-t] [-u fd] [-C callback] [-c quantum] [array]
61 Read lines from a file into an array variable.
62
63 A synonym for `mapfile'.
64 $END
65
66 #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"
76 #include "bashintl.h"
77
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
86 #if !defined (errno)
87 extern int errno;
88 #endif
89
90 #if defined (ARRAY_VARS)
91
92 static int run_callback __P((const char *, unsigned int, const char *));
93
94 #define DEFAULT_ARRAY_NAME "MAPFILE"
95 #define DEFAULT_VARIABLE_NAME "MAPLINE" /* not used right now */
96
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
104 static int
105 run_callback (callback, curindex, curline)
106 const char *callback;
107 unsigned int curindex;
108 const char *curline;
109 {
110 unsigned int execlen;
111 char *execstr, *qline;
112 int flags;
113
114 qline = sh_single_quote (curline);
115 execlen = strlen (callback) + strlen (qline) + 10;
116 /* 1 for each space between %s and %d,
117 another 1 for the last nul char for C string. */
118 execlen += 3;
119 execstr = xmalloc (execlen);
120
121 flags = SEVAL_NOHIST;
122 #if 0
123 if (interactive)
124 flags |= SEVAL_INTERACT;
125 #endif
126 snprintf (execstr, execlen, "%s %d %s", callback, curindex, qline);
127 free (qline);
128 return evalstring (execstr, NULL, flags);
129 }
130
131 static void
132 do_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
142 static int
143 mapfile (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);
163 if (entry == 0 || readonly_p (entry) || noassign_p (entry))
164 {
165 if (entry && readonly_p (entry))
166 err_readonly (array_name);
167
168 return (EXECUTION_FAILURE);
169 }
170 else if (array_p (entry) == 0)
171 {
172 builtin_error (_("%s: not an indexed array"), array_name);
173 return (EXECUTION_FAILURE);
174 }
175 else if (invisible_p (entry))
176 VUNSETATTR (entry, att_invisible); /* no longer invisible */
177
178 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
187 zreset ();
188
189 /* Skip any lines at beginning of file? */
190 for (line_count = 0; line_count < nskip; line_count++)
191 if (zgetline (fd, &line, &line_length, unbuffered_read) < 0)
192 break;
193
194 line = 0;
195 line_length = 0;
196
197 /* Reset the buffer for bash own stream */
198 for (array_index = origin, line_count = 1;
199 zgetline (fd, &line, &line_length, unbuffered_read) != -1;
200 array_index++)
201 {
202 /* 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 {
209 run_callback (callback, array_index, line);
210
211 /* Reset the buffer for bash own stream. */
212 if (unbuffered_read == 0)
213 zsyncfd (fd);
214 }
215
216 /* XXX - bad things can happen if the callback modifies ENTRY, e.g.,
217 unsetting it or changing it to a non-indexed-array type. */
218 bind_array_element (entry, array_index, line, 0);
219
220 /* Have we exceeded # of lines to store? */
221 line_count++;
222 if (line_count_goal != 0 && line_count > line_count_goal)
223 break;
224 }
225
226 xfree (line);
227
228 if (unbuffered_read == 0)
229 zsyncfd (fd);
230
231 return EXECUTION_SUCCESS;
232 }
233
234 int
235 mapfile_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);
302 if (code == 0 || intval <= 0 || intval != (unsigned)intval)
303 {
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
353 int
354 mapfile_builtin (list)
355 WORD_LIST *list;
356 {
357 builtin_error (_("array variable support required"));
358 return (EXECUTION_FAILURE);
359 }
360
361 #endif /* ARRAY_VARS */