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