From 011c1d1c0766c65517ebd495465c99e86edb63ec Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 11 Oct 2010 14:49:26 -0700 Subject: Update to bash-4.1 --- builtins/mapfile.def | 351 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 351 insertions(+) create mode 100644 builtins/mapfile.def (limited to 'builtins/mapfile.def') diff --git a/builtins/mapfile.def b/builtins/mapfile.def new file mode 100644 index 0000000..0946de3 --- /dev/null +++ b/builtins/mapfile.def @@ -0,0 +1,351 @@ +This file is mapfile.def, from which is created mapfile.c. +It implements the builtin "mapfile" in Bash. + +Copyright (C) 2005-2006 Rocky Bernstein for Free Software Foundation, Inc. +Copyright (C) 2008,2009 Free Software Foundation, Inc. + +This file is part of GNU Bash, the Bourne Again SHell. + +Bash is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Bash is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Bash. If not, see . + +$PRODUCES mapfile.c + +$BUILTIN mapfile +$FUNCTION mapfile_builtin +$SHORT_DOC mapfile [-n count] [-O origin] [-s count] [-t] [-u fd] [-C callback] [-c quantum] [array] +Read lines from the standard input into an indexed array variable. + +Read lines from the standard input into the indexed array variable ARRAY, or +from file descriptor FD if the -u option is supplied. The variable MAPFILE +is the default ARRAY. + +Options: + -n count Copy at most COUNT lines. If COUNT is 0, all lines are copied. + -O origin Begin assigning to ARRAY at index ORIGIN. The default index is 0. + -s count Discard the first COUNT lines read. + -t Remove a trailing newline from each line read. + -u fd Read lines from file descriptor FD instead of the standard input. + -C callback Evaluate CALLBACK each time QUANTUM lines are read. + -c quantum Specify the number of lines read between each call to CALLBACK. + +Arguments: + ARRAY Array variable name to use for file data. + +If -C is supplied without -c, the default quantum is 5000. When +CALLBACK is evaluated, it is supplied the index of the next array +element to be assigned as an additional argument. + +If not supplied with an explicit origin, mapfile will clear ARRAY before +assigning to it. + +Exit Status: +Returns success unless an invalid option is given or ARRAY is readonly or +not an indexed array. +$END + +$BUILTIN readarray +$FUNCTION mapfile_builtin +$SHORT_DOC readarray [-n count] [-O origin] [-s count] [-t] [-u fd] [-C callback] [-c quantum] [array] +Read lines from a file into an array variable. + +A synonym for `mapfile'. +$END + +#include + +#include "builtins.h" +#include "posixstat.h" + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "bashansi.h" +#include "bashintl.h" + +#include +#include + +#include "../bashintl.h" +#include "../shell.h" +#include "common.h" +#include "bashgetopt.h" + +#if !defined (errno) +extern int errno; +#endif + +#if defined (ARRAY_VARS) + +#define DEFAULT_ARRAY_NAME "MAPFILE" + +/* The value specifying how frequently `mapfile' calls the callback. */ +#define DEFAULT_QUANTUM 5000 + +/* Values for FLAGS */ +#define MAPF_CLEARARRAY 0x01 +#define MAPF_CHOP 0x02 + +static int +run_callback(callback, current_index) + const char *callback; + unsigned int current_index; +{ + unsigned int execlen; + char *execstr; + int flags; + + execlen = strlen (callback) + 10; + /* 1 for space between %s and %d, + another 1 for the last nul char for C string. */ + execlen += 2; + execstr = xmalloc (execlen); + + flags = SEVAL_NOHIST; +#if 0 + if (interactive) + flags |= SEVAL_INTERACT; +#endif + snprintf (execstr, execlen, "%s %d", callback, current_index); + return parse_and_execute(execstr, NULL, flags); +} + +static void +do_chop(line) + char * line; +{ + int length; + + length = strlen (line); + if (length && line[length-1] == '\n') + line[length-1] = '\0'; +} + +static int +mapfile (fd, line_count_goal, origin, nskip, callback_quantum, callback, array_name, flags) + int fd; + long line_count_goal, origin, nskip, callback_quantum; + char *callback, *array_name; + int flags; +{ + char *line; + size_t line_length; + unsigned int array_index, line_count; + SHELL_VAR *entry; + int unbuffered_read; + + line = NULL; + line_length = 0; + unbuffered_read = 0; + + /* The following check should be done before reading any lines. Doing it + here allows us to call bind_array_element instead of bind_array_variable + and skip the variable lookup on every call. */ + entry = find_or_make_array_variable (array_name, 1); + if (entry == 0 || readonly_p (entry) || noassign_p (entry)) + { + if (entry && readonly_p (entry)) + err_readonly (array_name); + + return (EXECUTION_FAILURE); + } + else if (array_p (entry) == 0) + { + builtin_error (_("%s: not an indexed array"), array_name); + return (EXECUTION_FAILURE); + } + + if (flags & MAPF_CLEARARRAY) + array_flush (array_cell (entry)); + +#ifndef __CYGWIN__ + unbuffered_read = (lseek (fd, 0L, SEEK_CUR) < 0) && (errno == ESPIPE); +#else + unbuffered_read = 1; +#endif + + zreset (); + + /* Skip any lines at beginning of file? */ + for (line_count = 0; line_count < nskip; line_count++) + if (zgetline (fd, &line, &line_length, unbuffered_read) < 0) + break; + + line = 0; + line_length = 0; + + /* Reset the buffer for bash own stream */ + interrupt_immediately++; + for (array_index = origin, line_count = 1; + zgetline (fd, &line, &line_length, unbuffered_read) != -1; + array_index++, line_count++) + { + /* Have we exceeded # of lines to store? */ + if (line_count_goal != 0 && line_count > line_count_goal) + break; + + /* Remove trailing newlines? */ + if (flags & MAPF_CHOP) + do_chop (line); + + /* Has a callback been registered and if so is it time to call it? */ + if (callback && line_count && (line_count % callback_quantum) == 0) + { + run_callback (callback, array_index); + + /* Reset the buffer for bash own stream. */ + if (unbuffered_read == 0) + zsyncfd (fd); + } + + bind_array_element (entry, array_index, line, 0); + } + + xfree (line); + + if (unbuffered_read == 0) + zsyncfd (fd); + + interrupt_immediately--; + return EXECUTION_SUCCESS; +} + +int +mapfile_builtin (list) + WORD_LIST *list; +{ + int opt, code, fd, clear_array, flags; + intmax_t intval; + long lines, origin, nskip, callback_quantum; + char *array_name, *callback; + + clear_array = 1; + fd = 0; + lines = origin = nskip = 0; + flags = MAPF_CLEARARRAY; + callback_quantum = DEFAULT_QUANTUM; + callback = 0; + + reset_internal_getopt (); + while ((opt = internal_getopt (list, "u:n:O:tC:c:s:")) != -1) + { + switch (opt) + { + case 'u': + code = legal_number (list_optarg, &intval); + if (code == 0 || intval < 0 || intval != (int)intval) + { + builtin_error (_("%s: invalid file descriptor specification"), list_optarg); + return (EXECUTION_FAILURE); + } + else + fd = intval; + + if (sh_validfd (fd) == 0) + { + builtin_error (_("%d: invalid file descriptor: %s"), fd, strerror (errno)); + return (EXECUTION_FAILURE); + } + break; + + case 'n': + code = legal_number (list_optarg, &intval); + if (code == 0 || intval < 0 || intval != (unsigned)intval) + { + builtin_error (_("%s: invalid line count"), list_optarg); + return (EXECUTION_FAILURE); + } + else + lines = intval; + break; + + case 'O': + code = legal_number (list_optarg, &intval); + if (code == 0 || intval < 0 || intval != (unsigned)intval) + { + builtin_error (_("%s: invalid array origin"), list_optarg); + return (EXECUTION_FAILURE); + } + else + origin = intval; + flags &= ~MAPF_CLEARARRAY; + break; + case 't': + flags |= MAPF_CHOP; + break; + case 'C': + callback = list_optarg; + break; + case 'c': + code = legal_number (list_optarg, &intval); + if (code == 0 || intval <= 0 || intval != (unsigned)intval) + { + builtin_error (_("%s: invalid callback quantum"), list_optarg); + return (EXECUTION_FAILURE); + } + else + callback_quantum = intval; + break; + case 's': + code = legal_number (list_optarg, &intval); + if (code == 0 || intval < 0 || intval != (unsigned)intval) + { + builtin_error (_("%s: invalid line count"), list_optarg); + return (EXECUTION_FAILURE); + } + else + nskip = intval; + break; + default: + builtin_usage (); + return (EX_USAGE); + } + } + list = loptend; + + if (list == 0) + array_name = DEFAULT_ARRAY_NAME; + else if (list->word == 0 || list->word->word == 0) + { + builtin_error ("internal error: getting variable name"); + return (EXECUTION_FAILURE); + } + else if (list->word->word[0] == '\0') + { + builtin_error (_("empty array variable name")); + return (EX_USAGE); + } + else + array_name = list->word->word; + + if (legal_identifier (array_name) == 0 && valid_array_reference (array_name) == 0) + { + sh_invalidid (array_name); + return (EXECUTION_FAILURE); + } + + return mapfile (fd, lines, origin, nskip, callback_quantum, callback, array_name, flags); +} + +#else + +int +mapfile_builtin (list) + WORD_LIST *list; +{ + builtin_error (_("array variable support required")); + return (EXECUTION_FAILURE); +} + +#endif /* ARRAY_VARS */ -- cgit v1.2.3