add string builtin files

- string builtin source, tests, & docs
- changes to configure.ac & Makefile.in
This commit is contained in:
Michael Steed 2015-08-11 22:41:19 -06:00
parent 9a2ac5fcb6
commit 1a60b93371
6 changed files with 1968 additions and 36 deletions

View File

@ -49,15 +49,28 @@ sysconfdir = @sysconfdir@
docdir = @docdir@
localedir = @localedir@
#
# pcre2
#
PCRE2_WIDTH = @WCHAR_T_BITS@
PCRE2_DIR = pcre2-10.20
PCRE2_CXXFLAGS = -I$(PCRE2_DIR)/src
PCRE2_LIBDIR = $(PCRE2_DIR)/.libs
PCRE2_LIB = $(PCRE2_LIBDIR)/libpcre2-$(PCRE2_WIDTH).a
PCRE2_CONFIG = --disable-pcre2-8 --enable-pcre2-$(PCRE2_WIDTH) --disable-shared
#
# Various flags
#
MACROS = -DLOCALEDIR=\"$(localedir)\" -DPREFIX=L\"$(prefix)\" -DDATADIR=L\"$(datadir)\" -DSYSCONFDIR=L\"$(sysconfdir)\" -DBINDIR=L\"$(bindir)\" -DDOCDIR=L\"$(docdir)\"
CXXFLAGS = @CXXFLAGS@ -iquote. -iquote./src/ $(MACROS) $(EXTRA_CXXFLAGS)
CXXFLAGS = @CXXFLAGS@ -iquote. -iquote./src/ $(MACROS) $(PCRE2_CXXFLAGS) $(EXTRA_CXXFLAGS)
CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
PCRE2 = pcre2-10.20
LIBS_PCRE2 = -L$(PCRE2_LIBDIR) -lpcre2-$(PCRE2_WIDTH)
LIBS = @LIBS@ $(LIBS_PCRE2)
LDFLAGS_FISH = ${LDFLAGS} @LDFLAGS_FISH@
#
@ -96,7 +109,7 @@ FISH_INDENT_OBJS := obj/fish_indent.o obj/print_help.o $(FISH_OBJS)
BUILTIN_FILES := src/builtin_set.cpp src/builtin_commandline.cpp \
src/builtin_ulimit.cpp src/builtin_complete.cpp \
src/builtin_jobs.cpp src/builtin_set_color.cpp \
src/builtin_printf.cpp
src/builtin_printf.cpp src/builtin_string.cpp
#
@ -778,9 +791,11 @@ obj:
# Build the fish program.
#
fish: $(FISH_OBJS) obj/fish.o
fish: $(FISH_OBJS) obj/fish.o $(PCRE2_LIB)
$(CXX) $(CXXFLAGS) $(LDFLAGS_FISH) $(FISH_OBJS) obj/fish.o $(LIBS) -o $@
$(PCRE2_LIB):
(cd $(PCRE2_DIR); ./configure $(PCRE2_CONFIG); make)
#
# Build the fish_tests program.
@ -828,13 +843,6 @@ depend:
./config.status
.PHONY: depend
# Include What You Use
iwyu:
# Requires the --keep-going flag as it always returns 1
# Can't set MAKEFLAGS on a target-specific basic
$(MAKE) -k _iwyu CXX=include-what-you-use
_iwyu: clean $(PROGRAMS)
.PHONY: iwyu _iwyu
#
# Cleanup targets
@ -889,6 +897,7 @@ obj/builtin.o: src/wcstringutil.h src/builtin_set.cpp src/util.h
obj/builtin.o: src/builtin_commandline.cpp src/builtin_complete.cpp
obj/builtin.o: src/builtin_ulimit.cpp src/builtin_jobs.cpp
obj/builtin.o: src/builtin_set_color.cpp src/output.h src/builtin_printf.cpp
obj/builtin.o: src/builtin_string.cpp
obj/builtin_test.o: config.h src/common.h src/fallback.h src/signal.h
obj/builtin_test.o: src/builtin.h src/io.h src/wutil.h src/proc.h
obj/builtin_test.o: src/parse_tree.h src/tokenizer.h src/parse_constants.h
@ -944,8 +953,8 @@ obj/fish_tests.o: src/builtin.h src/function.h src/event.h src/autoload.h
obj/fish_tests.o: src/lru.h src/wutil.h src/expand.h src/parser.h
obj/fish_tests.o: src/output.h src/exec.h src/path.h src/history.h
obj/fish_tests.o: src/iothread.h src/postfork.h src/parse_util.h src/pager.h
obj/fish_tests.o: src/screen.h src/input.h src/input_common.h src/utf8.h
obj/fish_tests.o: src/env_universal_common.h src/wcstringutil.h
obj/fish_tests.o: src/screen.h src/input.h src/input_common.h src/wildcard.h
obj/fish_tests.o: src/utf8.h src/env_universal_common.h src/wcstringutil.h
obj/fish_version.o: src/fish_version.h
obj/function.o: config.h src/wutil.h src/common.h src/fallback.h src/signal.h
obj/function.o: src/autoload.h src/lru.h src/function.h src/event.h src/env.h
@ -963,15 +972,15 @@ obj/history.o: src/io.h src/common.h src/complete.h src/highlight.h src/env.h
obj/history.o: src/color.h src/parse_constants.h src/parse_tree.h
obj/history.o: src/tokenizer.h src/wutil.h src/history.h src/path.h
obj/history.o: src/iothread.h src/lru.h
obj/input_common.o: config.h src/fallback.h src/signal.h src/util.h
obj/input_common.o: src/common.h src/input_common.h
obj/input_common.o: src/env_universal_common.h src/wutil.h src/env.h
obj/input_common.o: src/iothread.h
obj/input.o: config.h src/fallback.h src/signal.h src/wutil.h src/common.h
obj/input.o: src/reader.h src/io.h src/complete.h src/highlight.h src/env.h
obj/input.o: src/color.h src/parse_constants.h src/proc.h src/parse_tree.h
obj/input.o: src/tokenizer.h src/input_common.h src/input.h src/parser.h
obj/input.o: src/event.h src/output.h
obj/input_common.o: config.h src/fallback.h src/signal.h src/util.h
obj/input_common.o: src/common.h src/input_common.h
obj/input_common.o: src/env_universal_common.h src/wutil.h src/env.h
obj/input_common.o: src/iothread.h
obj/intern.o: config.h src/fallback.h src/signal.h src/common.h src/intern.h
obj/io.o: config.h src/fallback.h src/signal.h src/wutil.h src/common.h
obj/io.o: src/exec.h src/io.h
@ -998,14 +1007,6 @@ obj/parse_execution.o: src/builtin.h src/exec.h
obj/parse_productions.o: src/parse_productions.h src/common.h config.h
obj/parse_productions.o: src/fallback.h src/signal.h src/parse_constants.h
obj/parse_productions.o: src/parse_tree.h src/tokenizer.h
obj/parse_tree.o: src/common.h config.h src/fallback.h src/signal.h
obj/parse_tree.o: src/parse_constants.h src/parse_productions.h
obj/parse_tree.o: src/parse_tree.h src/tokenizer.h src/wutil.h src/proc.h
obj/parse_tree.o: src/io.h
obj/parse_util.o: config.h src/fallback.h src/signal.h src/util.h src/wutil.h
obj/parse_util.o: src/common.h src/tokenizer.h src/parse_util.h
obj/parse_util.o: src/parse_constants.h src/expand.h src/env.h src/wildcard.h
obj/parse_util.o: src/complete.h src/parse_tree.h src/builtin.h src/io.h
obj/parser.o: config.h src/fallback.h src/signal.h src/common.h src/wutil.h
obj/parser.o: src/proc.h src/io.h src/parse_tree.h src/tokenizer.h
obj/parser.o: src/parse_constants.h src/parser.h src/event.h src/function.h
@ -1014,6 +1015,14 @@ obj/parser.o: src/highlight.h src/color.h src/sanity.h src/intern.h
obj/parser.o: src/parse_util.h src/parse_execution.h
obj/parser_keywords.o: config.h src/fallback.h src/signal.h src/common.h
obj/parser_keywords.o: src/parser_keywords.h
obj/parse_tree.o: src/common.h config.h src/fallback.h src/signal.h
obj/parse_tree.o: src/parse_constants.h src/parse_productions.h
obj/parse_tree.o: src/parse_tree.h src/tokenizer.h src/wutil.h src/proc.h
obj/parse_tree.o: src/io.h
obj/parse_util.o: config.h src/fallback.h src/signal.h src/util.h src/wutil.h
obj/parse_util.o: src/common.h src/tokenizer.h src/parse_util.h
obj/parse_util.o: src/parse_constants.h src/expand.h src/env.h src/wildcard.h
obj/parse_util.o: src/complete.h src/parse_tree.h src/builtin.h src/io.h
obj/path.o: config.h src/fallback.h src/signal.h src/common.h src/env.h
obj/path.o: src/wutil.h src/path.h src/expand.h src/parse_constants.h
obj/postfork.o: src/signal.h src/common.h config.h src/fallback.h src/proc.h

View File

@ -24,6 +24,7 @@ conf_arg=$@
AC_SUBST(HAVE_GETTEXT)
AC_SUBST(HAVE_DOXYGEN)
AC_SUBST(LDFLAGS_FISH)
AC_SUBST(WCHAR_T_BITS)
#
@ -375,17 +376,16 @@ if test x$local_gettext != xno; then
AC_CHECK_HEADERS([libintl.h])
fi
AC_CHECK_HEADER(
[regex.h],
[
AC_DEFINE(
[HAVE_REGEX_H],
[1],
[Define to 1 if you have the <regex.h> header file.]
)
],
[AC_MSG_ERROR([Could not find the header regex.h, needed to build fish])]
)
#
# Get the size in bits of wchar_t, needed for configuring the pcre2 build
# and for code that #includes pcre2.h
#
AC_CHECK_SIZEOF(wchar_t)
WCHAR_T_BITS=`expr 8 \* $ac_cv_sizeof_wchar_t`
AC_DEFINE_UNQUOTED([WCHAR_T_BITS], [$WCHAR_T_BITS], [The size of wchar_t in bits.])
#
# On some platforms (Solaris 10) adding -std=c99 in turn requires that
@ -785,6 +785,7 @@ else
AC_MSG_RESULT(no)
fi
# Check for Solaris curses tputs having fixed length parameter list.
AC_MSG_CHECKING([if we are using non varargs tparm.])
AC_COMPILE_IFELSE(

200
doc_src/string.txt Normal file
View File

@ -0,0 +1,200 @@
\section string string - manipulate strings
\subsection string-synopsis Synopsis
\fish{synopsis}
string length [(-q | --quiet)] [STRING...]
string sub [(-s | --start) START] [(-l | --length) LENGTH]
[(-q | --quiet)] [STRING...]
string split [(-m | --max) MAX] [(-r | --right)] [(-q | --quiet)]
SEP [STRING...]
string join [(-q | --quiet)] SEP [STRING...]
string trim [(-l | --left)] [(-r | --right)] [(-c | --chars CHARS)]
[(-q | --quiet)] [STRING...]
string escape [(-n | --no-quoted)] [STRING...]
string match [(-a | --all)] [(-i | --ignore-case)] [(-r | --regex)]
[(-n | --index)] [(-q | --quiet)] PATTERN [STRING...]
string replace [(-a | --all)] [(-i | --ignore-case)] [(-r | --regex)]
[(-q | --quiet)] PATTERN REPLACEMENT [STRING...]
\endfish
\subsection string-description Description
`string` performs operations on strings.
STRING arguments are taken from the command line unless standard input is connected to a pipe or a file, in which case they are read from standard input. It is an error to supply STRING arguments on the command line and on standard input.
Arguments beginning with `-` are normally interpreted as switches; `--` causes the following arguments not to be treated as switches even if they begin with `-`. Switches and required arguments are recognized only on the command line.
Most subcommands accept a `-q` or `--quiet` switch, which suppresses the usual output but exits with the documented status.
The following subcommands are available:
- `length` reports the length of each string argument in characters. Exit status: 0 if at least one non-empty STRING was given, or 1 otherwise.
- `sub` prints a substring of each string argument. The start of the substring can be specified with `-s` or `--start` followed by a 1-based index value. Positive index values are relative to the start of the string and negative index values are relative to the end of the string. The default start value is 1. The length of the substring can be specified with `-l` or `--length`. If the length is not specified, the substring continues to the end of each STRING. Exit status: 0 if at least one substring operation was performed, 1 otherwise.
- `split` splits each STRING on the separator SEP, which can be an empty string. If `-m` or `--max` is specified, at most MAX splits are done. If `-r` or `--right` is given, splitting is performed right-to-left. This is useful in combination with `-m` or `--max`. Exit status: 0 if at least one split was performed, or 1 otherwise.
- `join` joins its STRING arguments into a single string separated by SEP, which can be an empty string. Exit status: 0 if at least one join was performed, or 1 otherwise.
- `trim` removes leading and trailing whitespace from each STRING. If `-l` or `--left` is given, only leading whitespace is removed. If `-r` or `--right` is given, only trailing whitespace is trimmed. The `-c` or `--chars` switch causes the characters in CHARS to be removed instead of whitespace. Exit status: 0 if at least one character was trimmed, or 1 otherwise.
- `escape` escapes each STRING such that it can be passed back to `eval` to produce the original argument again. By default, all special characters are escaped, and quotes are used to simplify the output when possible. If `-q` or `--no-quote` is given, the simplifying quoted format is not used. Exit status: 0 if at least one string was escaped, or 1 otherwise.
- `match` tests each STRING against a pattern and prints matching substrings. Only the first match is printed unless `-a` or `--all` is given, in which case all matches are reported. Matching can be made case-insensitive with `-i` or `--ignore-case`. If `-n` or `--index` is given, each match is reported as a 1-based start position, or 0 for no match. By default, PATTERN is interpreted as a glob pattern matched against each entire string argument. If `-r` or `--regex` is given, PATTERN is interpreted as a Perl-compatible regular expression. Note that for a regular expressions containing capturing groups, multiple items will be reported for each match, one for the entire match and one for each capturing group. Exit status: 0 if at least one match was found, or 1 otherwise.
- `replace` is similar to `match` but replaces non-overlapping matching substrings with a replacement string and prints the result. By default, PATTERN is treated as a literal substring to be matched by the literal string REPLACEMENT. If `-r` or `--regex` is given, PATTERN is interpreted as a Perl-compatible regular expression, and REPLACEMENT can refer to capturing groups by number or name as `$n` or `${n}`. Exit status: 0 if at least one replacement was performed, or 1 otherwise.
\subsection string-example Examples
\fish
string length 'hello, world'
# Output:
# 12
string length -q $str
# Equivalent to test -n $str
\endfish
\fish
string sub --length 2 abcde
# Output:
# ab
string sub -s 2 -l 2 abcde
# Output:
# bc
string sub --start=-2 abcde
# Output:
# de
\endfish
\fish
string split . example.com
# Output:
# example
# com
string split -r -m1 / /usr/local/bin/fish
# Output:
# /usr/local/bin
# fish
string split '' abc
# Output:
# a
# b
# c
\endfish
\fish
seq 3 | string join ...
# Output:
# 1...2...3
\endfish
\fish
string trim ' abc '
# Output:
# abc
string trim --right --chars=yz xyzzy zany
# Output:
# x
# zan
\endfish
\fish
echo \\x07 | string escape
# Output:
# \\cg
\endfish
\fish
# string match glob examples
string match '?' a
# Output:
# a
string match 'a*b' axxb
# Output:
# axxb
string match -i 'a??B' Axxb
# Output:
# Axxb
string match -a -i '[aeiou]' A B C D E
# Output:
# A
# E
string match '[^fb]*' foo bar baz qux
# Output:
# qux
echo 'ok?' | string match '*\\?'
# Output:
# ok?
# string match regex examples
string match -r 'cat|dog|fish' 'nice dog'
# Output:
# dog
string match -r '(\\d\\d?):(\\d\\d):(\\d\\d)' 2:34:56
# Output:
# 2:34:56
# 2
# 34
# 56
string match -r '^(\\w{2,4})\\g1$' papa mud murmur
# Output:
# papa
# pa
# murmur
# mur
string match -r -n at catch
# Output:
# 2
string match -r -i '0x[0-9a-f]{1,8}' 'int xyzzy = 0xBadC0de;'
# Output:
# 0xBadC0de
\endfish
\fish
# string replace literal examples
string replace is was 'blue is my favorite'
# Output:
# blue was my favorite
string replace 3rd last 1st 2nd 3rd
# Output:
# 1st
# 2nd
# last
string replace -a ' ' _ 'spaces to underscores'
# Output:
# spaces_to_underscores
# string replace regex examples
string replace -r -a '[^\\d.]+' ' ' '0 one two 3.14 four 5x'
# Output:
# 0 3.14 5
string replace -r '(\\w+)\\s+(\\w+)' '$1 $2 $1' 'left right'
# Output:
# left right left
\endfish

View File

@ -399,6 +399,7 @@ static void builtin_missing_argument(parser_t &parser, const wchar_t *cmd, const
#include "builtin_jobs.cpp"
#include "builtin_set_color.cpp"
#include "builtin_printf.cpp"
#include "builtin_string.cpp"
/* builtin_test lives in builtin_test.cpp */
int builtin_test(parser_t &parser, wchar_t **argv);
@ -4123,6 +4124,7 @@ static const builtin_data_t builtin_datas[]=
{ L"set_color", &builtin_set_color, N_(L"Set the terminal color") },
{ L"source", &builtin_source, N_(L"Evaluate contents of file") },
{ L"status", &builtin_status, N_(L"Return status information about fish") },
{ L"string", &builtin_string, N_(L"Manipulate strings") },
{ L"switch", &builtin_generic, N_(L"Conditionally execute a block of commands") },
{ L"test", &builtin_test, N_(L"Test a condition") },
{ L"true", &builtin_true, N_(L"Return a successful result") },

1438
src/builtin_string.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -4015,6 +4015,287 @@ static void test_wcstring_tok(void)
}
}
int builtin_string(parser_t &parser, wchar_t **argv);
extern wcstring stdout_buffer;
static void run_one_string_test(const wchar_t **argv, int expected_rc, const wchar_t *expected_out)
{
parser_t parser(PARSER_TYPE_GENERAL, true);
wcstring &out = stdout_buffer;
out.clear();
int rc = builtin_string(parser, const_cast<wchar_t**>(argv));
wcstring args;
for (int i = 0; argv[i] != 0; i++)
{
args += escape_string(argv[i], ESCAPE_ALL) + L' ';
}
args.resize(args.size() - 1);
if (rc != expected_rc)
{
err(L"Test failed on line %lu: [%ls]: expected return code %d but got %d",
__LINE__, args.c_str(), expected_rc, rc);
}
else if (out != expected_out)
{
err(L"Test failed on line %lu: [%ls]: expected [%ls] but got [%ls]",
__LINE__, args.c_str(),
escape_string(expected_out, ESCAPE_ALL).c_str(),
escape_string(out, ESCAPE_ALL).c_str());
}
}
static void test_string(void)
{
static struct string_test
{
const wchar_t *argv[15];
int expected_rc;
const wchar_t *expected_out;
}
string_tests[] =
{
{ {L"string", L"escape", 0}, 1, L"" },
{ {L"string", L"escape", L"", 0}, 0, L"''\n" },
{ {L"string", L"escape", L"-n", L"", 0}, 0, L"\n" },
{ {L"string", L"escape", L"a", 0}, 0, L"a\n" },
{ {L"string", L"escape", L"\x07", 0}, 0, L"\\cg\n" },
{ {L"string", L"escape", L"\"x\"", 0}, 0, L"'\"x\"'\n" },
{ {L"string", L"escape", L"hello world", 0}, 0, L"'hello world'\n" },
{ {L"string", L"escape", L"-n", L"hello world", 0}, 0, L"hello\\ world\n" },
{ {L"string", L"escape", L"hello", L"world", 0}, 0, L"hello\nworld\n" },
{ {L"string", L"escape", L"-n", L"~", 0}, 0, L"\\~\n" },
{ {L"string", L"join", 0}, 1, L"" },
{ {L"string", L"join", L"", 0}, 1, L"" },
{ {L"string", L"join", L"", L"", L"", L"", 0}, 0, L"\n" },
{ {L"string", L"join", L"", L"a", L"b", L"c", 0}, 0, L"abc\n" },
{ {L"string", L"join", L".", L"fishshell", L"com", 0}, 0, L"fishshell.com\n" },
{ {L"string", L"join", L"/", L"usr", 0}, 1, L"usr\n" },
{ {L"string", L"join", L"/", L"usr", L"local", L"bin", 0}, 0, L"usr/local/bin\n" },
{ {L"string", L"join", L"...", L"3", L"2", L"1", 0}, 0, L"3...2...1\n" },
{ {L"string", L"join", L"-q", 0}, 1, L"" },
{ {L"string", L"join", L"-q", L".", 0}, 1, L"" },
{ {L"string", L"join", L"-q", L".", L".", 0}, 1, L"" },
{ {L"string", L"length", 0}, 1, L"" },
{ {L"string", L"length", L"", 0}, 1, L"0\n" },
{ {L"string", L"length", L"", L"", L"", 0}, 1, L"0\n0\n0\n" },
{ {L"string", L"length", L"a", 0}, 0, L"1\n" },
{ {L"string", L"length", L"\U0002008A", 0}, 0, L"1\n" },
{ {L"string", L"length", L"um", L"dois", L"três", 0}, 0, L"2\n4\n4\n" },
{ {L"string", L"length", L"um", L"dois", L"três", 0}, 0, L"2\n4\n4\n" },
{ {L"string", L"length", L"-q", 0}, 1, L"" },
{ {L"string", L"length", L"-q", L"", 0}, 1, L"" },
{ {L"string", L"length", L"-q", L"a", 0}, 0, L"" },
{ {L"string", L"match", 0}, 1, L"" },
{ {L"string", L"match", L"", 0}, 1, L"" },
{ {L"string", L"match", L"", L"", 0}, 0, L"\n" },
{ {L"string", L"match", L"?", L"a", 0}, 0, L"a\n" },
{ {L"string", L"match", L"*", L"", 0}, 0, L"\n" },
{ {L"string", L"match", L"**", L"", 0}, 0, L"\n" },
{ {L"string", L"match", L"*", L"xyzzy", 0}, 0, L"xyzzy\n" },
{ {L"string", L"match", L"**", L"plugh", 0}, 0, L"plugh\n" },
{ {L"string", L"match", L"a*b", L"axxb", 0}, 0, L"axxb\n" },
{ {L"string", L"match", L"a??b", L"axxb", 0}, 0, L"axxb\n" },
{ {L"string", L"match", L"-i", L"a??B", L"axxb", 0}, 0, L"axxb\n" },
{ {L"string", L"match", L"a*", L"axxb", 0}, 0, L"axxb\n" },
{ {L"string", L"match", L"*a", L"xxa", 0}, 0, L"xxa\n" },
{ {L"string", L"match", L"*a*", L"axa", 0}, 0, L"axa\n" },
{ {L"string", L"match", L"*a*", L"xax", 0}, 0, L"xax\n" },
{ {L"string", L"match", L"*a*", L"bxa", 0}, 0, L"bxa\n" },
{ {L"string", L"match", L"*a", L"a", 0}, 0, L"a\n" },
{ {L"string", L"match", L"a*", L"a", 0}, 0, L"a\n" },
{ {L"string", L"match", L"a*b*c", L"axxbyyc", 0}, 0, L"axxbyyc\n" },
{ {L"string", L"match", L"a*b?c", L"axxbyc", 0}, 0, L"axxbyc\n" },
{ {L"string", L"match", L"*?", L"a", 0}, 0, L"a\n" },
{ {L"string", L"match", L"*?", L"ab", 0}, 0, L"ab\n" },
{ {L"string", L"match", L"?*", L"a", 0}, 0, L"a\n" },
{ {L"string", L"match", L"?*", L"ab", 0}, 0, L"ab\n" },
{ {L"string", L"match", L"[A-F][^A-F]", L"FG", 0}, 0, L"FG\n" },
{ {L"string", L"match", L"[A][B]", L"AB", 0}, 0, L"AB\n" },
{ {L"string", L"match", L"0x[0-9a-fA-F][0-9a-fA-F]", L"0x6a", 0}, 0, L"0x6a\n" },
{ {L"string", L"match", L"0x[0-9a-fA-F][0-9a-fA-F]", L"0xA6", 0}, 0, L"0xA6\n" },
{ {L"string", L"match", L"-i", L"0x[0-9a-f][0-9A-F]", L"0xAb", 0}, 0, L"0xAb\n" },
{ {L"string", L"match", L"\\*", L"*", 0}, 0, L"*\n" },
{ {L"string", L"match", L"a*\\", L"abc\\", 0}, 0, L"abc\\\n" },
{ {L"string", L"match", L"a*\\?", L"abc?", 0}, 0, L"abc?\n" },
{ {L"string", L"match", L"?", L"", 0}, 1, L"" },
{ {L"string", L"match", L"?", L"ab", 0}, 1, L"" },
{ {L"string", L"match", L"??", L"a", 0}, 1, L"" },
{ {L"string", L"match", L"?a", L"a", 0}, 1, L"" },
{ {L"string", L"match", L"a?", L"a", 0}, 1, L"" },
{ {L"string", L"match", L"a??B", L"axxb", 0}, 1, L"" },
{ {L"string", L"match", L"a*b", L"axxbc", 0}, 1, L"" },
{ {L"string", L"match", L"*b", L"bbba", 0}, 1, L"" },
{ {L"string", L"match", L"0x[0-9a-fA-F][0-9a-fA-F]", L"0xbad", 0}, 1, L"" },
{ {L"string", L"match", L"-a", L"*", L"ab", L"cde", 0}, 0, L"ab\ncde\n" },
{ {L"string", L"match", L"*", L"ab", L"cde", 0}, 0, L"ab\n" },
{ {L"string", L"match", L"-n", L"*d*", L"cde", 0}, 0, L"1\n" },
{ {L"string", L"match", L"-q", L"a*", L"b", L"c", 0}, 1, L"" },
{ {L"string", L"match", L"-q", L"a*", L"b", L"a", 0}, 0, L"" },
{ {L"string", L"match", L"-r", 0}, 1, L"" },
{ {L"string", L"match", L"-r", L"", 0}, 1, L"" },
{ {L"string", L"match", L"-r", L"", L"", 0}, 0, L"\n" },
{ {L"string", L"match", L"-r", L".", L"a", 0}, 0, L"a\n" },
{ {L"string", L"match", L"-r", L".*", L"", 0}, 0, L"\n" },
{ {L"string", L"match", L"-r", L"a*b", L"b", 0}, 0, L"b\n" },
{ {L"string", L"match", L"-r", L"a*b", L"aab", 0}, 0, L"aab\n" },
{ {L"string", L"match", L"-r", L"-i", L"a*b", L"Aab", 0}, 0, L"Aab\n" },
{ {L"string", L"match", L"-r", L"-a", L"a[bc]", L"abadac", 0}, 0, L"ab\nac\n" },
{ {L"string", L"match", L"-r", L"-a", L"a", L"x", L"a", L"x", L"a", 0}, 0, L"a\na\n" },
{ {L"string", L"match", L"-r", L"a", L"x", L"a", L"x", L"a", 0}, 0, L"a\n" },
{ {L"string", L"match", L"-r", L"a[bc]", L"abadac", 0}, 0, L"ab\n" },
{ {L"string", L"match", L"-r", L"-q", L"a[bc]", L"abadac", 0}, 0, L"" },
{ {L"string", L"match", L"-r", L"-q", L"a[bc]", L"ad", 0}, 1, L"" },
{ {L"string", L"match", L"-r", L"(a+)b(c)", L"aabc", 0}, 0, L"aabc\naa\nc\n" },
{ {L"string", L"match", L"-r", L"-a", L"(a)b(c)", L"abcabc", 0}, 0, L"abc\na\nc\nabc\na\nc\n" },
{ {L"string", L"match", L"-r", L"(a)b(c)", L"abcabc", 0}, 0, L"abc\na\nc\n" },
{ {L"string", L"match", L"-r", L"(a|(z))(bc)", L"abc", 0}, 0, L"abc\na\nbc\n" },
{ {L"string", L"match", L"-r", L"-n", L"a", L"a", 0}, 0, L"1\n" },
{ {L"string", L"match", L"-r", L"-n", L"-a", L"a", L"bacadae", 0}, 0, L"2\n4\n6\n" },
{ {L"string", L"match", L"-r", L"-n", L"(a).*(b)", L"a---b", 0}, 0, L"1\n1\n5\n" },
{ {L"string", L"match", L"-r", L"-n", L"(a)(b)", L"ab", 0}, 0, L"1\n1\n2\n" },
{ {L"string", L"match", L"-r", L"-n", L"(a)(b)", L"abab", 0}, 0, L"1\n1\n2\n" },
{ {L"string", L"match", L"-r", L"-n", L"-a", L"(a)(b)", L"abab", 0}, 0, L"1\n1\n2\n3\n3\n4\n" },
{ {L"string", L"match", L"-r", L"*", L"", 0}, 1, L"" },
{ {L"string", L"match", L"-r", L"foo\\Kbar", L"foobar", 0}, 0, L"bar\n" },
{ {L"string", L"match", L"-r", L"(foo)\\Kbar", L"foobar", 0}, 0, L"bar\nfoo\n" },
{ {L"string", L"match", L"-r", L"(?=ab\\K)", L"ab", 0}, 0, L"\n" },
{ {L"string", L"match", L"-r", L"(?=ab\\K)..(?=cd\\K)", L"abcd", 0}, 0, L"\n" },
{ {L"string", L"replace", 0}, 1, L"" },
{ {L"string", L"replace", L"", 0}, 1, L"" },
{ {L"string", L"replace", L"", L"", 0}, 1, L"" },
{ {L"string", L"replace", L"", L"", L"", 0}, 1, L"\n" },
{ {L"string", L"replace", L"", L"", L" ", 0}, 1, L" \n" },
{ {L"string", L"replace", L"a", L"b", L"", 0}, 1, L"\n" },
{ {L"string", L"replace", L"a", L"b", L"a", 0}, 0, L"b\n" },
{ {L"string", L"replace", L"a", L"b", L"xax", 0}, 0, L"xbx\n" },
{ {L"string", L"replace", L"bar", L"x", L"red barn", 0}, 0, L"red xn\n" },
{ {L"string", L"replace", L"x", L"bar", L"red xn", 0}, 0, L"red barn\n" },
{ {L"string", L"replace", L"--", L"x", L"-", L"xyz", 0}, 0, L"-yz\n" },
{ {L"string", L"replace", L"--", L"y", L"-", L"xyz", 0}, 0, L"x-z\n" },
{ {L"string", L"replace", L"--", L"z", L"-", L"xyz", 0}, 0, L"xy-\n" },
{ {L"string", L"replace", L"-i", L"z", L"X", L"_Z_", 0}, 0, L"_X_\n" },
{ {L"string", L"replace", L"-a", L"a", L"A", L"aaa", 0}, 0, L"AAA\n" },
{ {L"string", L"replace", L"-i", L"a", L"z", L"AAA", 0}, 0, L"zAA\n" },
{ {L"string", L"replace", L"-q", L"x", L">x<", L"x", 0}, 0, L"" },
{ {L"string", L"replace", L"-a", L"x", L"", L"xxx", 0}, 0, L"\n" },
{ {L"string", L"replace", L"-a", L"***", L"_", L"*****", 0}, 0, L"_**\n" },
{ {L"string", L"replace", L"-a", L"***", L"***", L"******", 0}, 0, L"******\n" },
{ {L"string", L"replace", L"-r", 0}, 1, L"" },
{ {L"string", L"replace", L"-r", L"", 0}, 1, L"" },
{ {L"string", L"replace", L"-r", L"", L"", 0}, 1, L"" },
{ {L"string", L"replace", L"-r", L"", L"", L"", 0}, 0, L"\n" }, // pcre2 behavior
{ {L"string", L"replace", L"-r", L"", L"", L" ", 0}, 0, L" \n" }, // pcre2 behavior
{ {L"string", L"replace", L"-r", L"a", L"b", L"", 0}, 1, L"\n" },
{ {L"string", L"replace", L"-r", L"a", L"b", L"a", 0}, 0, L"b\n" },
{ {L"string", L"replace", L"-r", L".", L"x", L"abc", 0}, 0, L"xbc\n" },
{ {L"string", L"replace", L"-r", L".", L"", L"abc", 0}, 0, L"bc\n" },
{ {L"string", L"replace", L"-r", L"(\\w)(\\w)", L"$2$1", L"ab", 0}, 0, L"ba\n" },
{ {L"string", L"replace", L"-r", L"(\\w)", L"$1$1", L"ab", 0}, 0, L"aab\n" },
{ {L"string", L"replace", L"-r", L"-a", L".", L"x", L"abc", 0}, 0, L"xxx\n" },
{ {L"string", L"replace", L"-r", L"-a", L"(\\w)", L"$1$1", L"ab", 0}, 0, L"aabb\n" },
{ {L"string", L"replace", L"-r", L"-a", L".", L"", L"abc", 0}, 0, L"\n" },
{ {L"string", L"replace", L"-r", L"a", L"x", L"bc", L"cd", L"de", 0}, 1, L"bc\ncd\nde\n" },
{ {L"string", L"replace", L"-r", L"a", L"x", L"bc", L"ca", L"ab", 0}, 0, L"bc\ncx\nab\n" },
{ {L"string", L"replace", L"-r", L"-a", L"a", L"x", L"bc", L"ca", L"ab", 0}, 0, L"bc\ncx\nxb\n" },
{ {L"string", L"replace", L"-r", L"-i", L"A", L"b", L"xax", 0}, 0, L"xbx\n" },
{ {L"string", L"replace", L"-r", L"-i", L"[a-z]", L".", L"1A2B", 0}, 0, L"1.2B\n" },
{ {L"string", L"replace", L"-r", L"A", L"b", L"xax", 0}, 1, L"xax\n" },
{ {L"string", L"replace", L"-r", L"a", L"$1", L"a", 0}, 1, L"" },
{ {L"string", L"replace", L"-r", L"(a)", L"$2", L"a", 0}, 1, L"" },
{ {L"string", L"replace", L"-r", L"*", L".", L"a", 0}, 1, L"" },
{ {L"string", L"split", 0}, 1, L"" },
{ {L"string", L"split", L":", 0}, 1, L"" },
{ {L"string", L"split", L".", L"www.ch.ic.ac.uk", 0}, 0, L"www\nch\nic\nac\nuk\n" },
{ {L"string", L"split", L"..", L"....", 0}, 0, L"\n\n\n" },
{ {L"string", L"split", L"-m1", L"..", L"....", 0}, 0, L"\n..\n" },
{ {L"string", L"split", L"-m0", L"/", L"/usr/local/bin/fish", 0}, 0, L"\nusr\nlocal\nbin\nfish\n" },
{ {L"string", L"split", L"-m2", L":", L"a:b", L"c:d", L"e:f", 0}, 0, L"a\nb\nc\nd\ne:f\n" },
{ {L"string", L"split", L"-m1", L"-r", L"/", L"/usr/local/bin/fish", 0}, 0, L"/usr/local/bin\nfish\n" },
{ {L"string", L"split", L"-r", L".", L"www.ch.ic.ac.uk", 0}, 0, L"www\nch\nic\nac\nuk\n" },
{ {L"string", L"split", L"--", L"--", L"a--b---c----d", 0}, 0, L"a\nb\n-c\n\nd\n" },
{ {L"string", L"split", L"-r", L"..", L"....", 0}, 0, L"\n\n\n" },
{ {L"string", L"split", L"-r", L"--", L"--", L"a--b---c----d", 0}, 0, L"a\nb-\nc\n\nd\n" },
{ {L"string", L"split", L"", L"", 0}, 1, L"\n" },
{ {L"string", L"split", L"", L"a", 0}, 1, L"a\n" },
{ {L"string", L"split", L"", L"ab", 0}, 0, L"a\nb\n" },
{ {L"string", L"split", L"", L"abc", 0}, 0, L"a\nb\nc\n" },
{ {L"string", L"split", L"-m1", L"", L"abc", 0}, 0, L"a\nbc\n" },
{ {L"string", L"split", L"-r", L"", L"", 0}, 1, L"\n" },
{ {L"string", L"split", L"-r", L"", L"a", 0}, 1, L"a\n" },
{ {L"string", L"split", L"-r", L"", L"ab", 0}, 0, L"a\nb\n" },
{ {L"string", L"split", L"-r", L"", L"abc", 0}, 0, L"a\nb\nc\n" },
{ {L"string", L"split", L"-r", L"-m1", L"", L"abc", 0}, 0, L"ab\nc\n" },
{ {L"string", L"split", L"-q", 0}, 1, L"" },
{ {L"string", L"split", L"-q", L":", 0}, 1, L"" },
{ {L"string", L"split", L"-q", L"x", L"axbxc", 0}, 0, L"" },
{ {L"string", L"sub", 0}, 1, L"" },
{ {L"string", L"sub", L"abcde", 0}, 0, L"abcde\n"},
{ {L"string", L"sub", L"-l0", L"abcde", 0}, 0, L"\n"},
{ {L"string", L"sub", L"-l2", L"abcde", 0}, 0, L"ab\n"},
{ {L"string", L"sub", L"-l5", L"abcde", 0}, 0, L"abcde\n"},
{ {L"string", L"sub", L"-l6", L"abcde", 0}, 0, L"abcde\n"},
{ {L"string", L"sub", L"-l-1", L"abcde", 0}, 1, L""},
{ {L"string", L"sub", L"-s0", L"abcde", 0}, 1, L""},
{ {L"string", L"sub", L"-s1", L"abcde", 0}, 0, L"abcde\n"},
{ {L"string", L"sub", L"-s5", L"abcde", 0}, 0, L"e\n"},
{ {L"string", L"sub", L"-s6", L"abcde", 0}, 0, L"\n"},
{ {L"string", L"sub", L"-s-1", L"abcde", 0}, 0, L"e\n"},
{ {L"string", L"sub", L"-s-5", L"abcde", 0}, 0, L"abcde\n"},
{ {L"string", L"sub", L"-s-6", L"abcde", 0}, 0, L"abcde\n"},
{ {L"string", L"sub", L"-s1", L"-l0", L"abcde", 0}, 0, L"\n"},
{ {L"string", L"sub", L"-s1", L"-l1", L"abcde", 0}, 0, L"a\n"},
{ {L"string", L"sub", L"-s2", L"-l2", L"abcde", 0}, 0, L"bc\n"},
{ {L"string", L"sub", L"-s-1", L"-l1", L"abcde", 0}, 0, L"e\n"},
{ {L"string", L"sub", L"-s-1", L"-l2", L"abcde", 0}, 0, L"e\n"},
{ {L"string", L"sub", L"-s-3", L"-l2", L"abcde", 0}, 0, L"cd\n"},
{ {L"string", L"sub", L"-s-3", L"-l4", L"abcde", 0}, 0, L"cde\n"},
{ {L"string", L"sub", L"-q", 0}, 1, L"" },
{ {L"string", L"sub", L"-q", L"abcde", 0}, 0, L""},
{ {L"string", L"trim", 0}, 1, L""},
{ {L"string", L"trim", L""}, 1, L"\n"},
{ {L"string", L"trim", L" "}, 0, L"\n"},
{ {L"string", L"trim", L" \f\n\r\t"}, 0, L"\n"},
{ {L"string", L"trim", L" a"}, 0, L"a\n"},
{ {L"string", L"trim", L"a "}, 0, L"a\n"},
{ {L"string", L"trim", L" a "}, 0, L"a\n"},
{ {L"string", L"trim", L"-l", L" a"}, 0, L"a\n"},
{ {L"string", L"trim", L"-l", L"a "}, 1, L"a \n"},
{ {L"string", L"trim", L"-l", L" a "}, 0, L"a \n"},
{ {L"string", L"trim", L"-r", L" a"}, 1, L" a\n"},
{ {L"string", L"trim", L"-r", L"a "}, 0, L"a\n"},
{ {L"string", L"trim", L"-r", L" a "}, 0, L" a\n"},
{ {L"string", L"trim", L"-c", L".", L" a"}, 1, L" a\n"},
{ {L"string", L"trim", L"-c", L".", L"a "}, 1, L"a \n"},
{ {L"string", L"trim", L"-c", L".", L" a "}, 1, L" a \n"},
{ {L"string", L"trim", L"-c", L".", L".a"}, 0, L"a\n"},
{ {L"string", L"trim", L"-c", L".", L"a."}, 0, L"a\n"},
{ {L"string", L"trim", L"-c", L".", L".a."}, 0, L"a\n"},
{ {L"string", L"trim", L"-c", L"\\/", L"/a\\"}, 0, L"a\n"},
{ {L"string", L"trim", L"-c", L"\\/", L"a/"}, 0, L"a\n"},
{ {L"string", L"trim", L"-c", L"\\/", L"\\a/"}, 0, L"a\n"},
{ {L"string", L"trim", L"-c", L"", L".a."}, 1, L".a.\n"},
{ {0}, 0, 0 }
};
struct string_test *t = string_tests;
while (t->argv[0] != 0)
{
run_one_string_test(t->argv, t->expected_rc, t->expected_out);
t++;
}
}
/**
Main test
*/
@ -4106,6 +4387,7 @@ int main(int argc, char **argv)
if (should_test_function("history_races")) history_tests_t::test_history_races();
if (should_test_function("history_formats")) history_tests_t::test_history_formats();
//history_tests_t::test_history_speed();
if (should_test_function("string")) test_string();
say(L"Encountered %d errors in low-level tests", err_count);
if (s_test_run_count == 0)