Bash-4.1 distribution source
[platform/upstream/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,2009 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 as an additional argument.
48
49 If not supplied with an explicit origin, mapfile will clear ARRAY before
50 assigning to it.
51
52 Exit Status:
53 Returns success unless an invalid option is given or ARRAY is readonly or
54 not an indexed array.
55 $END
56
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]
60 Read lines from a file into an array variable.
61
62 A synonym for `mapfile'.
63 $END
64
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"
75 #include "bashintl.h"
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
85 #if !defined (errno)
86 extern 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
100 static int
101 run_callback(callback, current_index)
102      const char *callback;
103      unsigned int current_index;
104 {
105   unsigned int execlen;
106   char  *execstr;
107   int flags;
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
115   flags = SEVAL_NOHIST;
116 #if 0
117   if (interactive)
118     flags |= SEVAL_INTERACT;
119 #endif
120   snprintf (execstr, execlen, "%s %d", callback, current_index);
121   return parse_and_execute(execstr, NULL, flags);
122 }
123
124 static void
125 do_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
135 static int
136 mapfile (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);
156   if (entry == 0 || readonly_p (entry) || noassign_p (entry))
157     {
158       if (entry && readonly_p (entry))
159         err_readonly (array_name);
160         
161       return (EXECUTION_FAILURE);
162     }
163   else if (array_p (entry) == 0)
164     {
165       builtin_error (_("%s: not an indexed array"), array_name);
166       return (EXECUTION_FAILURE);
167     }
168       
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
178   zreset ();
179
180   /* Skip any lines at beginning of file? */
181   for (line_count = 0; line_count < nskip; line_count++)
182     if (zgetline (fd, &line, &line_length, unbuffered_read) < 0)
183       break;
184
185   line = 0;
186   line_length = 0;    
187
188   /* Reset the buffer for bash own stream */
189   interrupt_immediately++;
190   for (array_index = origin, line_count = 1; 
191        zgetline (fd, &line, &line_length, unbuffered_read) != -1;
192        array_index++, line_count++) 
193     {
194       /* Have we exceeded # of lines to store? */
195       if (line_count_goal != 0 && line_count > line_count_goal) 
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
220   interrupt_immediately--;
221   return EXECUTION_SUCCESS;
222 }
223
224 int
225 mapfile_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);
292           if (code == 0 || intval <= 0 || intval != (unsigned)intval)
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
343 int
344 mapfile_builtin (list)
345      WORD_LIST *list;
346 {
347   builtin_error (_("array variable support required"));
348   return (EXECUTION_FAILURE);
349 }
350
351 #endif  /* ARRAY_VARS */