readarray.c
来自「bash debugger. You can use this tool to 」· C语言 代码 · 共 389 行
C
389 行
/* $Id: readarray.c,v 1.21 2006/09/06 04:20:43 myamato Exp $ Copyright (C) 2005, 2006 Rocky Bernstein rockyb@users.sf.net 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 2, 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; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.*//* readarray - copy file into an array. We need to do this because reading line by line is very slow.*/#include "builtins.h"#include "posixstat.h"#if defined (HAVE_UNISTD_H)# include <unistd.h>#endif#include "bashansi.h"#include <stdio.h>#include <errno.h>#include "bashintl.h"#include "shell.h"#include "common.h"#include "bashgetopt.h"#if !defined (errno)extern int errno;#endif/* The value specifying how frequently `readarray' calls the callback. */#define DEFAULT_PROGRESS_QUANTUM 5000/* Initial memory allocation for automatic growing buffer in zreadlinec */#define GET_LINE_INITIAL_ALLOCATION 16/* Derived from GNU libc's getline. The behavior is almost the same as getline. See man getline. The differences are (1) using file descriptor instead of FILE*, (2) the order of arguments; the file descriptor comes the first, and (3) the addtion of thired argument, UNBUFFERED_READ; this argument controls whether get_line uses buffering or not to get a byte data from FD. get_line uses zreadc if UNBUFFERED_READ is zero; and uses zread if unbuFFERED_READ is non-zero. */static ssize_tget_line (int fd, char **lineptr, size_t *n, int unbuffered_read){ int n_read; char *line; if (lineptr == NULL) { builtin_error ("internal error zreadlinec#1; lineptr is NULL"); return -1; } if (n == NULL) { builtin_error ("internal error zreadlinec#2; n is NULL"); return -1; } if (*lineptr == NULL && *n != 0) { builtin_error ("internal error zreadlinec#3; lineptr and n are not consistent"); return -1; } n_read = 0; line = *lineptr; while (1) { char c; int retval; if (unbuffered_read) retval = zread (fd, &c, 1); else retval = zreadc(fd, &c); if (retval <= 0) { if (n_read > 0) line[n_read] = '\0'; break; } if (n_read + 2 >= *n) { size_t new_size; if (*n == 0) new_size = GET_LINE_INITIAL_ALLOCATION; else new_size = *n * 2; if (*n >= new_size) /* Overflowed size_t */ line = NULL; else line = *lineptr ? xrealloc (*lineptr, new_size) : xmalloc (new_size); if (line) { *lineptr = line; *n = new_size; } else { if (*n > 0) { (*lineptr)[*n - 1] = '\0'; n_read = *n - 2; } break; } } line[n_read] = c; n_read++; if (c == '\n') { line[n_read] = '\0'; break; } } return n_read - 1;}static intrun_callback(const char * callback, unsigned int current_index){ unsigned int execlen; char *execstr; /* # define INT_MAX "2147483647" */ execlen = strlen(callback)+ 10; /* A `1' is for space between %s and %d, another `1' is for the last nul char for C string. */ execlen += (1 + 1); execstr = xmalloc(execlen); snprintf(execstr, execlen, "%s %d", callback, current_index); return parse_and_execute(execstr, NULL, 0);}static voiddo_chop(char * line){ int length; length = strlen(line); if (length && '\n' == line[length-1]) line[length-1] = '\0';}static intread_array (int fd, long int line_count_goal, long int origin, long int chop, long int callback_quantum, char *callback, char *array_name){ char *line; size_t line_length; unsigned int array_index; unsigned int line_count; SHELL_VAR *entry; int unbuffered_read; line = NULL; line_length = 0; unbuffered_read = 0; /* Following check is also done in `bind_array_variable'. However, it should be done before reading lines. */ entry = var_lookup (array_name, shell_variables); if (entry && (readonly_p (entry) || noassign_p (entry))) { if (readonly_p (entry)) err_readonly (array_name); return (EX_USAGE); }#ifndef __CYGWIN__ unbuffered_read = (lseek (fd, 0L, SEEK_CUR) < 0) && (errno == ESPIPE);#else unbuffered_read = 1;#endif /* Reset the buffer for bash own stream */ for (array_index = origin, line_count = 0; -1 != get_line(fd, &line, &line_length, unbuffered_read); 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 (chop) do_chop(line); /* Has a callback been registered and if so is it time to call it? */ if (callback && line_count && 0 == (line_count % callback_quantum)) { run_callback(callback, array_index); /* Reset the buffer for bash own stream. */ if (!unbuffered_read) zsyncfd (fd); } bind_array_variable(array_name, array_index, line, 0); } xfree(line); if (!unbuffered_read) zsyncfd (fd); return EXECUTION_SUCCESS;}intreadarray_builtin (WORD_LIST *list){ int opt; int code; intmax_t intval; long int lines; long int origin; long int chop; long int callback_quantum; char *callback; int fd; char *array_name; fd = lines = origin = chop = 0; callback_quantum = DEFAULT_PROGRESS_QUANTUM; callback = NULL; reset_internal_getopt (); while ((opt = internal_getopt (list, "u:n:O:tC:c:")) != -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: bad line count specification"), 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: bad array origin"), list_optarg); return (EXECUTION_FAILURE); } else origin = intval; break; case 't': chop = 1; 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: bad callback quantum"), list_optarg); return (EXECUTION_FAILURE); } else { callback_quantum = intval; } break; default: builtin_usage (); return (EX_USAGE); } } list = loptend; if (!list) { builtin_error (_("missing array variable name")); return (EX_USAGE); } else if (!list->word) { builtin_error ("internal error readarray_builtin#1 in getting variable name"); return (EXECUTION_FAILURE); } else if (!list->word->word) { builtin_error ("internal error readarray_builtin#2 in getting variable name"); return (EXECUTION_FAILURE); } else if (list->word->word[0] == '\0') { builtin_error (_("array variable name is empty")); 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 read_array (fd, lines, origin, chop, callback_quantum, callback, array_name);}char *readarray_doc[] = { "Multiple lines are read from the standard input into ARRAY_VARIABLE,", "or from file descriptor FD if the -u option is supplied. ", "", "Use the `-n' option to specify COUNT number of lines to copy.", "If -n is missing or 0 is given as the number all lines are copied.", "", "Use the `-O' option to specify an index ORIGIN to start the array.", "If -O is missing the origin will be 0.", "", "Use -t to chop trailing newlines (\\n) from lines.", "", "Use the `-C' option to specify CALLBACK which is evaluated according to ", "progression of reading lines. The evaluation is done each time", "QUANTUM number of lines are read as specified via the -c option;", "5000 is the default.", "", "The -C and -c options may be useful in implementing a progress bar.", "", "Note: this routine does not clear any previously existing array values.", " It will however overwrite existing indices.", NULL};struct builtin readarray_struct = { "readarray", /* builtin name */ readarray_builtin, /* function implementing the builtin */ BUILTIN_ENABLED, /* initial flags for builtin */ readarray_doc, /* array of long documentation strings. */ "readarray [-u fd] [-n count] [-O origin] [-t] [-C callback] [-c quantum] array_variable", /* usage synopsis; becomes short_doc */ 0 /* reserved for internal use */};
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?