From 8f8c4cdd176fda4d93a2d1d4b0ae6321d5706e5f Mon Sep 17 00:00:00 2001 From: Kevin Ballard Date: Sun, 21 Sep 2014 19:18:56 -0700 Subject: [PATCH] Implement new `read --null` flag The `--null` flag to `read` makes it split incoming lines on NUL instead of newlines. This is intended for processing the output of a command that uses NUL separators (such as `find -print0`). Fixes #1694. --- Makefile.in | 14 ++++++--- builtin.cpp | 80 +++++++++++++++++++++++++----------------------- doc_src/read.txt | 2 ++ fish_tests.cpp | 33 ++++++++++++++++++++ tests/read.in | 25 +++++++++++++++ tests/read.out | 12 ++++++++ wcstringutil.cpp | 40 ++++++++++++++++++++++++ wcstringutil.h | 29 ++++++++++++++++++ 8 files changed, 192 insertions(+), 43 deletions(-) create mode 100644 wcstringutil.cpp create mode 100644 wcstringutil.h diff --git a/Makefile.in b/Makefile.in index fea9ae5bf..d6d1d09dc 100644 --- a/Makefile.in +++ b/Makefile.in @@ -91,7 +91,7 @@ FISH_OBJS := function.o builtin.o complete.o env.o exec.o expand.o \ signal.o io.o parse_util.o common.o screen.o path.o autoload.o \ parser_keywords.o iothread.o color.o postfork.o \ builtin_test.o parse_tree.o parse_productions.o parse_execution.o \ - pager.o utf8.o fish_version.o + pager.o utf8.o fish_version.o wcstringutil.o FISH_INDENT_OBJS := fish_indent.o print_help.o common.o \ parser_keywords.o wutil.o tokenizer.o fish_version.o @@ -843,9 +843,10 @@ builtin.o: io.h function.h event.h complete.h proc.h parse_tree.h tokenizer.h builtin.o: parse_constants.h parser.h reader.h highlight.h env.h color.h builtin.o: wgetopt.h sanity.h wildcard.h expand.h input_common.h input.h builtin.o: intern.h exec.h parse_util.h autoload.h lru.h parser_keywords.h -builtin.o: path.h history.h builtin_set.cpp builtin_commandline.cpp -builtin.o: builtin_complete.cpp builtin_ulimit.cpp builtin_jobs.cpp -builtin.o: builtin_set_color.cpp output.h screen.h builtin_printf.cpp +builtin.o: path.h history.h wcstringutil.h builtin_set.cpp +builtin.o: builtin_commandline.cpp builtin_complete.cpp builtin_ulimit.cpp +builtin.o: builtin_jobs.cpp builtin_set_color.cpp output.h screen.h +builtin.o: builtin_printf.cpp builtin_commandline.o: config.h signal.h fallback.h util.h wutil.h common.h builtin_commandline.o: builtin.h io.h wgetopt.h reader.h complete.h builtin_commandline.o: highlight.h env.h color.h proc.h parse_tree.h @@ -860,6 +861,7 @@ builtin_jobs.o: config.h fallback.h signal.h util.h wutil.h common.h builtin_jobs.o: builtin.h io.h proc.h parse_tree.h tokenizer.h builtin_jobs.o: parse_constants.h parser.h event.h function.h wgetopt.h builtin_printf.o: common.h util.h +builtin_scripts.o: builtin_scripts.h builtin_set.o: config.h signal.h fallback.h util.h wutil.h common.h builtin.h builtin_set.o: io.h env.h expand.h parse_constants.h wgetopt.h proc.h builtin_set.o: parse_tree.h tokenizer.h parser.h event.h function.h @@ -911,6 +913,7 @@ fish_tests.o: highlight.h env.h color.h builtin.h function.h event.h fish_tests.o: autoload.h lru.h wutil.h expand.h parser.h output.h screen.h fish_tests.o: exec.h path.h history.h iothread.h postfork.h parse_util.h fish_tests.o: pager.h input.h input_common.h utf8.h env_universal_common.h +fish_tests.o: wcstringutil.h fish_version.o: fish_version.h function.o: config.h signal.h wutil.h common.h util.h fallback.h function.h function.o: event.h proc.h io.h parse_tree.h tokenizer.h parse_constants.h @@ -930,7 +933,7 @@ input.o: complete.h highlight.h env.h color.h proc.h parse_tree.h tokenizer.h input.o: parse_constants.h sanity.h input_common.h input.h parser.h event.h input.o: function.h expand.h output.h screen.h intern.h input_common.o: config.h fallback.h signal.h util.h common.h wutil.h -input_common.o: input_common.h iothread.h +input_common.o: input_common.h env_universal_common.h env.h iothread.h intern.o: config.h fallback.h signal.h util.h wutil.h common.h intern.h io.o: config.h fallback.h signal.h util.h wutil.h common.h exec.h proc.h io.h io.o: parse_tree.h tokenizer.h parse_constants.h @@ -993,6 +996,7 @@ signal.o: parse_tree.h tokenizer.h parse_constants.h tokenizer.o: config.h fallback.h signal.h util.h wutil.h common.h tokenizer.h utf8.o: utf8.h util.o: config.h fallback.h signal.h util.h common.h wutil.h +wcstringutil.o: config.h wcstringutil.h common.h util.h wgetopt.o: config.h wgetopt.h wutil.h common.h util.h fallback.h signal.h wildcard.o: config.h fallback.h signal.h util.h wutil.h common.h complete.h wildcard.o: wildcard.h expand.h parse_constants.h reader.h io.h highlight.h diff --git a/builtin.cpp b/builtin.cpp index 3ab3bb486..4604190c3 100644 --- a/builtin.cpp +++ b/builtin.cpp @@ -65,6 +65,7 @@ #include "path.h" #include "history.h" #include "parse_tree.h" +#include "wcstringutil.h" /** The default prompt for the read command @@ -2305,10 +2306,9 @@ static int builtin_random(parser_t &parser, wchar_t **argv) */ static int builtin_read(parser_t &parser, wchar_t **argv) { - wchar_t *buff=0; + wcstring buff; int i, argc = builtin_count_args(argv); int place = ENV_USER; - wchar_t *nxt; const wchar_t *prompt = DEFAULT_READ_PROMPT; const wchar_t *commandline = L""; int exit_res=STATUS_BUILTIN_OK; @@ -2317,6 +2317,7 @@ static int builtin_read(parser_t &parser, wchar_t **argv) wchar_t *end; int shell = 0; int array = 0; + bool split_null = false; woptind=0; @@ -2369,6 +2370,10 @@ static int builtin_read(parser_t &parser, wchar_t **argv) L"array", no_argument, 0, 'a' } , + { + L"null", no_argument, 0, 'z' + } + , { L"help", no_argument, 0, 'h' } @@ -2383,7 +2388,7 @@ static int builtin_read(parser_t &parser, wchar_t **argv) int opt = wgetopt_long(argc, argv, - L"xglUup:c:hm:n:sa", + L"xglUup:c:hm:n:saz", long_options, &opt_index); if (opt == -1) @@ -2468,6 +2473,10 @@ static int builtin_read(parser_t &parser, wchar_t **argv) array = 1; break; + case L'z': + split_null = true; + break; + case 'h': builtin_print_help(parser, argv[0], stdout_buffer); return STATUS_BUILTIN_OK; @@ -2541,7 +2550,7 @@ static int builtin_read(parser_t &parser, wchar_t **argv) /* Check if we should read interactively using \c reader_readline() */ - if (isatty(0) && builtin_stdin == 0) + if (isatty(0) && builtin_stdin == 0 && !split_null) { const wchar_t *line; @@ -2572,13 +2581,11 @@ static int builtin_read(parser_t &parser, wchar_t **argv) // note: we're deliberately throwing away the tail of the commandline. // It shouldn't be unread because it was produced with `commandline -i`, // not typed. - buff = (wchar_t *)malloc(((size_t)nchars + 1) * sizeof(wchar_t)); - wmemcpy(buff, line, (size_t)nchars); - buff[nchars] = 0; + buff = wcstring(line, nchars); } else { - buff = wcsdup(line); + buff = wcstring(line); } } else @@ -2591,7 +2598,7 @@ static int builtin_read(parser_t &parser, wchar_t **argv) { int eof=0; - wcstring sb; + buff.clear(); while (1) { @@ -2621,7 +2628,6 @@ static int builtin_read(parser_t &parser, wchar_t **argv) case (size_t)(-2): break; case 0: - eof=1; finished = 1; break; @@ -2635,44 +2641,43 @@ static int builtin_read(parser_t &parser, wchar_t **argv) if (eof) break; - if (res == L'\n') + if (!split_null && res == L'\n') break; - sb.push_back(res); + if (split_null && res == L'\0') + break; - if (0 < nchars && (size_t)nchars <= sb.size()) + buff.push_back(res); + + if (0 < nchars && (size_t)nchars <= buff.size()) { break; } } - if (sb.size() < 2 && eof) + if (buff.size() < 2 && eof) { exit_res = 1; } - - buff = wcsdup(sb.c_str()); } if (i != argc && !exit_res) { - - wchar_t *state; - env_var_t ifs = env_get_string(L"IFS"); - if (ifs.missing_or_empty()) { /* Every character is a separate token */ - size_t bufflen = wcslen(buff); + size_t bufflen = buff.size(); if (array) { if (bufflen > 0) { wcstring chars(bufflen+(bufflen-1), ARRAY_SEP); - for (size_t j=0; j= str.size()) + { + return std::make_pair(wcstring::npos, wcstring::npos); + } + + if (needle.empty()) + { + return std::make_pair(pos, wcstring::npos); + } + + pos = str.find_first_not_of(needle, pos); + if (pos == wcstring::npos) return std::make_pair(wcstring::npos, wcstring::npos); + + size_type next_pos = str.find_first_of(needle, pos); + if (next_pos == wcstring::npos) + { + return std::make_pair(pos, wcstring::npos); + } + else + { + str[next_pos] = L'\0'; + return std::make_pair(pos, next_pos - pos); + } +} diff --git a/wcstringutil.h b/wcstringutil.h new file mode 100644 index 000000000..73ca7ac69 --- /dev/null +++ b/wcstringutil.h @@ -0,0 +1,29 @@ +/** \file wcstringutil.h + +Helper functions for working with wcstring +*/ + +#ifndef FISH_WCSTRINGUTIL_H +#define FISH_WCSTRINGUTIL_H + +#include +#include "common.h" + +/** + typedef that represents a range in a wcstring. + The first element is the location, the second is the count. +*/ +typedef std::pair wcstring_range; + +/** + wcstring equivalent of wcstok(). Supports NUL. + For convenience and wcstok() compatibility, the first character of each + token separator is replaced with NUL. + Returns a pair of (pos, count). + Returns (npos, npos) when it's done. + Returns (pos, npos) when the token is already known to be the final token. + Note that the final token may not necessarily return (pos, npos). +*/ +wcstring_range wcstring_tok(wcstring& str, const wcstring &needle, wcstring_range last = wcstring_range(0,0)); + +#endif