blob: 3a51a687f6ce8c17d0de6c9c393ea2dbb681d3bb [file] [log] [blame]
Dan Pasanenc6e37862014-10-02 14:08:59 -05001/* mapfile.c, created from mapfile.def. */
2#line 23 "./mapfile.def"
3
4#line 57 "./mapfile.def"
5
6#line 65 "./mapfile.def"
7
8#include <config.h>
9
10#include "builtins.h"
11#include "posixstat.h"
12
13#if defined (HAVE_UNISTD_H)
14# include <unistd.h>
15#endif
16
17#include "bashansi.h"
18#include "bashintl.h"
19
20#include <stdio.h>
21#include <errno.h>
22
23#include "../bashintl.h"
24#include "../shell.h"
25#include "common.h"
26#include "bashgetopt.h"
27
28#if !defined (errno)
Ricardo Cerqueiraa02fbff2013-07-25 22:35:34 +010029#include <errno.h>
Dan Pasanenc6e37862014-10-02 14:08:59 -050030#endif
31
32#if defined (ARRAY_VARS)
33
34static int run_callback __P((const char *, unsigned int, const char *));
35
36#define DEFAULT_ARRAY_NAME "MAPFILE"
37#define DEFAULT_VARIABLE_NAME "MAPLINE" /* not used right now */
38
39/* The value specifying how frequently `mapfile' calls the callback. */
40#define DEFAULT_QUANTUM 5000
41
42/* Values for FLAGS */
43#define MAPF_CLEARARRAY 0x01
44#define MAPF_CHOP 0x02
45
46static int
47run_callback (callback, curindex, curline)
48 const char *callback;
49 unsigned int curindex;
50 const char *curline;
51{
52 unsigned int execlen;
53 char *execstr, *qline;
54 int flags;
55
56 qline = sh_single_quote (curline);
57 execlen = strlen (callback) + strlen (qline) + 10;
58 /* 1 for each space between %s and %d,
59 another 1 for the last nul char for C string. */
60 execlen += 3;
61 execstr = xmalloc (execlen);
62
63 flags = SEVAL_NOHIST;
64#if 0
65 if (interactive)
66 flags |= SEVAL_INTERACT;
67#endif
68 snprintf (execstr, execlen, "%s %d %s", callback, curindex, qline);
69 free (qline);
70 return evalstring (execstr, NULL, flags);
71}
72
73static void
74do_chop(line)
75 char * line;
76{
77 int length;
78
79 length = strlen (line);
80 if (length && line[length-1] == '\n')
81 line[length-1] = '\0';
82}
83
84static int
85mapfile (fd, line_count_goal, origin, nskip, callback_quantum, callback, array_name, flags)
86 int fd;
87 long line_count_goal, origin, nskip, callback_quantum;
88 char *callback, *array_name;
89 int flags;
90{
91 char *line;
92 size_t line_length;
93 unsigned int array_index, line_count;
94 SHELL_VAR *entry;
95 int unbuffered_read;
96
97 line = NULL;
98 line_length = 0;
99 unbuffered_read = 0;
100
101 /* The following check should be done before reading any lines. Doing it
102 here allows us to call bind_array_element instead of bind_array_variable
103 and skip the variable lookup on every call. */
104 entry = find_or_make_array_variable (array_name, 1);
105 if (entry == 0 || readonly_p (entry) || noassign_p (entry))
106 {
107 if (entry && readonly_p (entry))
108 err_readonly (array_name);
109
110 return (EXECUTION_FAILURE);
111 }
112 else if (array_p (entry) == 0)
113 {
114 builtin_error (_("%s: not an indexed array"), array_name);
115 return (EXECUTION_FAILURE);
116 }
117 else if (invisible_p (entry))
118 VUNSETATTR (entry, att_invisible); /* no longer invisible */
119
120 if (flags & MAPF_CLEARARRAY)
121 array_flush (array_cell (entry));
122
123#ifndef __CYGWIN__
124 unbuffered_read = (lseek (fd, 0L, SEEK_CUR) < 0) && (errno == ESPIPE);
125#else
126 unbuffered_read = 1;
127#endif
128
129 zreset ();
130
131 /* Skip any lines at beginning of file? */
132 for (line_count = 0; line_count < nskip; line_count++)
133 if (zgetline (fd, &line, &line_length, unbuffered_read) < 0)
134 break;
135
136 line = 0;
137 line_length = 0;
138
139 /* Reset the buffer for bash own stream */
140 for (array_index = origin, line_count = 1;
141 zgetline (fd, &line, &line_length, unbuffered_read) != -1;
142 array_index++)
143 {
144 /* Remove trailing newlines? */
145 if (flags & MAPF_CHOP)
146 do_chop (line);
147
148 /* Has a callback been registered and if so is it time to call it? */
149 if (callback && line_count && (line_count % callback_quantum) == 0)
150 {
151 run_callback (callback, array_index, line);
152
153 /* Reset the buffer for bash own stream. */
154 if (unbuffered_read == 0)
155 zsyncfd (fd);
156 }
157
158 /* XXX - bad things can happen if the callback modifies ENTRY, e.g.,
159 unsetting it or changing it to a non-indexed-array type. */
160 bind_array_element (entry, array_index, line, 0);
161
162 /* Have we exceeded # of lines to store? */
163 line_count++;
164 if (line_count_goal != 0 && line_count > line_count_goal)
165 break;
166 }
167
168 xfree (line);
169
170 if (unbuffered_read == 0)
171 zsyncfd (fd);
172
173 return EXECUTION_SUCCESS;
174}
175
176int
177mapfile_builtin (list)
178 WORD_LIST *list;
179{
180 int opt, code, fd, clear_array, flags;
181 intmax_t intval;
182 long lines, origin, nskip, callback_quantum;
183 char *array_name, *callback;
184
185 clear_array = 1;
186 fd = 0;
187 lines = origin = nskip = 0;
188 flags = MAPF_CLEARARRAY;
189 callback_quantum = DEFAULT_QUANTUM;
190 callback = 0;
191
192 reset_internal_getopt ();
193 while ((opt = internal_getopt (list, "u:n:O:tC:c:s:")) != -1)
194 {
195 switch (opt)
196 {
197 case 'u':
198 code = legal_number (list_optarg, &intval);
199 if (code == 0 || intval < 0 || intval != (int)intval)
200 {
201 builtin_error (_("%s: invalid file descriptor specification"), list_optarg);
202 return (EXECUTION_FAILURE);
203 }
204 else
205 fd = intval;
206
207 if (sh_validfd (fd) == 0)
208 {
209 builtin_error (_("%d: invalid file descriptor: %s"), fd, strerror (errno));
210 return (EXECUTION_FAILURE);
211 }
212 break;
213
214 case 'n':
215 code = legal_number (list_optarg, &intval);
216 if (code == 0 || intval < 0 || intval != (unsigned)intval)
217 {
218 builtin_error (_("%s: invalid line count"), list_optarg);
219 return (EXECUTION_FAILURE);
220 }
221 else
222 lines = intval;
223 break;
224
225 case 'O':
226 code = legal_number (list_optarg, &intval);
227 if (code == 0 || intval < 0 || intval != (unsigned)intval)
228 {
229 builtin_error (_("%s: invalid array origin"), list_optarg);
230 return (EXECUTION_FAILURE);
231 }
232 else
233 origin = intval;
234 flags &= ~MAPF_CLEARARRAY;
235 break;
236 case 't':
237 flags |= MAPF_CHOP;
238 break;
239 case 'C':
240 callback = list_optarg;
241 break;
242 case 'c':
243 code = legal_number (list_optarg, &intval);
244 if (code == 0 || intval <= 0 || intval != (unsigned)intval)
245 {
246 builtin_error (_("%s: invalid callback quantum"), list_optarg);
247 return (EXECUTION_FAILURE);
248 }
249 else
250 callback_quantum = intval;
251 break;
252 case 's':
253 code = legal_number (list_optarg, &intval);
254 if (code == 0 || intval < 0 || intval != (unsigned)intval)
255 {
256 builtin_error (_("%s: invalid line count"), list_optarg);
257 return (EXECUTION_FAILURE);
258 }
259 else
260 nskip = intval;
261 break;
262 default:
263 builtin_usage ();
264 return (EX_USAGE);
265 }
266 }
267 list = loptend;
268
269 if (list == 0)
270 array_name = DEFAULT_ARRAY_NAME;
271 else if (list->word == 0 || list->word->word == 0)
272 {
273 builtin_error ("internal error: getting variable name");
274 return (EXECUTION_FAILURE);
275 }
276 else if (list->word->word[0] == '\0')
277 {
278 builtin_error (_("empty array variable name"));
279 return (EX_USAGE);
280 }
281 else
282 array_name = list->word->word;
283
284 if (legal_identifier (array_name) == 0 && valid_array_reference (array_name) == 0)
285 {
286 sh_invalidid (array_name);
287 return (EXECUTION_FAILURE);
288 }
289
290 return mapfile (fd, lines, origin, nskip, callback_quantum, callback, array_name, flags);
291}
292
293#else
294
295int
296mapfile_builtin (list)
297 WORD_LIST *list;
298{
299 builtin_error (_("array variable support required"));
300 return (EXECUTION_FAILURE);
301}
302
303#endif /* ARRAY_VARS */