mirror of
https://github.com/fish-shell/fish-shell.git
synced 2024-11-22 13:18:59 +08:00
drop unused functions and configure checks
Remove the following C++ functions/methods, which have no callers: common.cpp: - read_loop - narrow_string_safe - escape_string_for_double_quotes - read_unquoted_escape - format_size - format_size_safe - valid_func_name - get_executable_path env.cpp: - env_stack_t::set_empty - env_stack_t::set_argv fallback.cpp: - fish_mkstemp_cloexec - flock proc_util.cpp: - parse_util_slice_length - parse_util_argument_is_help path.cpp: - path_get_path - path_as_implicit_cd - path_apply_working_directory - path_emit_config_directory_messages - path_get_data_remoteness - path_get_config_remoteness - path_is_valid - paths_are_same_file wcstringutil.cpp: - split_string_tok wutil.cpp: - wgetcwd - wunlink - wrealpath - wrename - file_id_for_path - fish_wcstoull Also drop unused configure checks/defines: - HAVE_FLOCK
This commit is contained in:
parent
f773697bc1
commit
f2f41c6eec
|
@ -118,7 +118,6 @@ check_cxx_symbol_exists(ctermid_r stdio.h HAVE_CTERMID_R)
|
|||
check_struct_has_member("struct dirent" d_type dirent.h HAVE_STRUCT_DIRENT_D_TYPE LANGUAGE CXX)
|
||||
check_cxx_symbol_exists(dirfd "sys/types.h;dirent.h" HAVE_DIRFD)
|
||||
check_include_file_cxx(execinfo.h HAVE_EXECINFO_H)
|
||||
check_cxx_symbol_exists(flock sys/file.h HAVE_FLOCK)
|
||||
check_cxx_symbol_exists(getpwent pwd.h HAVE_GETPWENT)
|
||||
check_cxx_symbol_exists(getrusage sys/resource.h HAVE_GETRUSAGE)
|
||||
check_cxx_symbol_exists(gettext libintl.h HAVE_GETTEXT)
|
||||
|
|
|
@ -16,9 +16,6 @@
|
|||
/* Define to 1 if you have the <execinfo.h> header file. */
|
||||
#cmakedefine HAVE_EXECINFO_H 1
|
||||
|
||||
/* Define to 1 if you have the `flock' function. */
|
||||
#cmakedefine HAVE_FLOCK 1
|
||||
|
||||
/* Define to 1 if you have the `getpwent' function. */
|
||||
#cmakedefine HAVE_GETPWENT 1
|
||||
|
||||
|
|
|
@ -231,36 +231,6 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH RE
|
|||
|
||||
----
|
||||
|
||||
**License for flock**
|
||||
|
||||
``fish`` also contains small amounts of code from NetBSD, namely the ``flock`` fallback function. This code is copyright 2001 The NetBSD Foundation, Inc., and derived from software contributed to The NetBSD Foundation by Todd Vierling.
|
||||
|
||||
The NetBSD license follows.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----
|
||||
|
||||
**MIT License**
|
||||
|
||||
``fish`` includes a copy of Alpine.js, which is copyright 2019-2021 Caleb Porzio and contributors, and licensed under the MIT License. It also includes the Dracula theme, which is copyright 2018 Dracula Team, and is licensed under the same license.
|
||||
|
|
376
src/common.cpp
376
src/common.cpp
|
@ -572,14 +572,6 @@ ssize_t write_loop(int fd, const char *buff, size_t count) {
|
|||
return static_cast<ssize_t>(out_cum);
|
||||
}
|
||||
|
||||
ssize_t read_loop(int fd, void *buff, size_t count) {
|
||||
ssize_t result;
|
||||
do {
|
||||
result = read(fd, buff, count);
|
||||
} while (result < 0 && (errno == EAGAIN || errno == EINTR));
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Hack to not print error messages in the tests. Do not call this from functions in this module
|
||||
/// like `debug()`. It is only intended to suppress diagnostic noise from testing things like the
|
||||
/// fish parser where we expect a lot of diagnostic messages due to testing error conditions.
|
||||
|
@ -645,20 +637,6 @@ void format_ullong_safe(wchar_t buff[64], unsigned long long val) {
|
|||
return format_safe_impl(buff, 64, val);
|
||||
}
|
||||
|
||||
void narrow_string_safe(char buff[64], const wchar_t *s) {
|
||||
size_t idx = 0;
|
||||
for (size_t widx = 0; s[widx] != L'\0'; widx++) {
|
||||
wchar_t c = s[widx];
|
||||
if (c <= 127) {
|
||||
buff[idx++] = char(c);
|
||||
if (idx + 1 == 64) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
buff[idx] = '\0';
|
||||
}
|
||||
|
||||
/// Escape a string in a fashion suitable for using as a URL. Store the result in out_str.
|
||||
static void escape_string_url(const wcstring &in, wcstring &out) {
|
||||
auto result = escape_string_url(in.c_str(), in.size());
|
||||
|
@ -675,22 +653,6 @@ static void escape_string_var(const wcstring &in, wcstring &out) {
|
|||
}
|
||||
}
|
||||
|
||||
wcstring escape_string_for_double_quotes(wcstring in) {
|
||||
// We need to escape backslashes, double quotes, and dollars only.
|
||||
wcstring result = std::move(in);
|
||||
size_t idx = result.size();
|
||||
while (idx--) {
|
||||
switch (result[idx]) {
|
||||
case L'\\':
|
||||
case L'$':
|
||||
case L'"':
|
||||
result.insert(idx, 1, L'\\');
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Escape a string in a fashion suitable for using in fish script. Store the result in out_str.
|
||||
static void escape_string_script(const wchar_t *orig_in, size_t in_len, wcstring &out,
|
||||
escape_flags_t flags) {
|
||||
|
@ -785,228 +747,6 @@ wcstring escape_string(const wcstring &in, escape_flags_t flags, escape_string_s
|
|||
return result;
|
||||
}
|
||||
|
||||
/// Given a null terminated string starting with a backslash, read the escape as if it is unquoted,
|
||||
/// appending to result. Return the number of characters consumed, or none on error.
|
||||
maybe_t<size_t> read_unquoted_escape(const wchar_t *input, wcstring *result, bool allow_incomplete,
|
||||
bool unescape_special) {
|
||||
assert(input[0] == L'\\' && "Not an escape");
|
||||
|
||||
// Here's the character we'll ultimately append, or none. Note that L'\0' is a
|
||||
// valid thing to append.
|
||||
maybe_t<wchar_t> result_char_or_none = none();
|
||||
|
||||
bool errored = false;
|
||||
size_t in_pos = 1; // in_pos always tracks the next character to read (and therefore the number
|
||||
// of characters read so far)
|
||||
|
||||
// For multibyte \X sequences.
|
||||
std::string byte_buff;
|
||||
while (true) {
|
||||
const wchar_t c = input[in_pos++];
|
||||
switch (c) {
|
||||
// A null character after a backslash is an error.
|
||||
case L'\0': {
|
||||
// Adjust in_pos to only include the backslash.
|
||||
assert(in_pos > 0);
|
||||
in_pos--;
|
||||
|
||||
// It's an error, unless we're allowing incomplete escapes.
|
||||
if (!allow_incomplete) errored = true;
|
||||
break;
|
||||
}
|
||||
// Numeric escape sequences. No prefix means octal escape, otherwise hexadecimal.
|
||||
case L'0':
|
||||
case L'1':
|
||||
case L'2':
|
||||
case L'3':
|
||||
case L'4':
|
||||
case L'5':
|
||||
case L'6':
|
||||
case L'7':
|
||||
case L'u':
|
||||
case L'U':
|
||||
case L'x':
|
||||
case L'X': {
|
||||
long long res = 0;
|
||||
size_t chars = 2;
|
||||
int base = 16;
|
||||
bool byte_literal = false;
|
||||
wchar_t max_val = ASCII_MAX;
|
||||
|
||||
switch (c) {
|
||||
case L'u': {
|
||||
chars = 4;
|
||||
max_val = UCS2_MAX;
|
||||
break;
|
||||
}
|
||||
case L'U': {
|
||||
chars = 8;
|
||||
max_val = WCHAR_MAX;
|
||||
|
||||
// Don't exceed the largest Unicode code point - see #1107.
|
||||
if (0x10FFFF < max_val) max_val = static_cast<wchar_t>(0x10FFFF);
|
||||
break;
|
||||
}
|
||||
case L'x':
|
||||
case L'X': {
|
||||
byte_literal = true;
|
||||
max_val = BYTE_MAX;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
base = 8;
|
||||
chars = 3;
|
||||
// Note that in_pos currently is just after the first post-backslash
|
||||
// character; we want to start our escape from there.
|
||||
assert(in_pos > 0);
|
||||
in_pos--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < chars; i++) {
|
||||
long d = convert_digit(input[in_pos], base);
|
||||
if (d < 0) {
|
||||
// If we have no digit, this is a tokenizer error.
|
||||
if (i == 0) errored = true;
|
||||
break;
|
||||
}
|
||||
|
||||
res = (res * base) + d;
|
||||
in_pos++;
|
||||
}
|
||||
|
||||
if (!errored && res <= max_val) {
|
||||
if (byte_literal) {
|
||||
// Multibyte encodings necessitate that we keep adjacent byte escapes.
|
||||
// - `\Xc3\Xb6` is "ö", but only together.
|
||||
// (this assumes a valid codepoint can't consist of multiple bytes
|
||||
// that are valid on their own, which is true for UTF-8)
|
||||
byte_buff.push_back(static_cast<char>(res));
|
||||
result_char_or_none = none();
|
||||
if (input[in_pos] == L'\\' &&
|
||||
(input[in_pos + 1] == L'X' || input[in_pos + 1] == L'x')) {
|
||||
in_pos++;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
result_char_or_none = static_cast<wchar_t>(res);
|
||||
}
|
||||
} else {
|
||||
errored = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
// \a means bell (alert).
|
||||
case L'a': {
|
||||
result_char_or_none = L'\a';
|
||||
break;
|
||||
}
|
||||
// \b means backspace.
|
||||
case L'b': {
|
||||
result_char_or_none = L'\b';
|
||||
break;
|
||||
}
|
||||
// \cX means control sequence X.
|
||||
case L'c': {
|
||||
const wchar_t sequence_char = input[in_pos++];
|
||||
if (sequence_char >= L'a' && sequence_char <= (L'a' + 32)) {
|
||||
result_char_or_none = sequence_char - L'a' + 1;
|
||||
} else if (sequence_char >= L'A' && sequence_char <= (L'A' + 32)) {
|
||||
result_char_or_none = sequence_char - L'A' + 1;
|
||||
} else {
|
||||
errored = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// \x1B means escape.
|
||||
case L'e': {
|
||||
result_char_or_none = L'\x1B';
|
||||
break;
|
||||
}
|
||||
// \f means form feed.
|
||||
case L'f': {
|
||||
result_char_or_none = L'\f';
|
||||
break;
|
||||
}
|
||||
// \n means newline.
|
||||
case L'n': {
|
||||
result_char_or_none = L'\n';
|
||||
break;
|
||||
}
|
||||
// \r means carriage return.
|
||||
case L'r': {
|
||||
result_char_or_none = L'\r';
|
||||
break;
|
||||
}
|
||||
// \t means tab.
|
||||
case L't': {
|
||||
result_char_or_none = L'\t';
|
||||
break;
|
||||
}
|
||||
// \v means vertical tab.
|
||||
case L'v': {
|
||||
result_char_or_none = L'\v';
|
||||
break;
|
||||
}
|
||||
// If a backslash is followed by an actual newline, swallow them both.
|
||||
case L'\n': {
|
||||
result_char_or_none = none();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if (unescape_special) result->push_back(INTERNAL_SEPARATOR);
|
||||
result_char_or_none = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (errored) return none();
|
||||
|
||||
if (!byte_buff.empty()) {
|
||||
result->append(str2wcstring(byte_buff));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (result_char_or_none.has_value()) {
|
||||
result->push_back(*result_char_or_none);
|
||||
}
|
||||
|
||||
return in_pos;
|
||||
}
|
||||
|
||||
wcstring format_size(long long sz) {
|
||||
wcstring result;
|
||||
const wchar_t *sz_name[] = {L"kB", L"MB", L"GB", L"TB", L"PB", L"EB", L"ZB", L"YB", nullptr};
|
||||
|
||||
if (sz < 0) {
|
||||
result.append(L"unknown");
|
||||
} else if (sz < 1) {
|
||||
result.append(_(L"empty"));
|
||||
} else if (sz < 1024) {
|
||||
result.append(format_string(L"%lldB", sz));
|
||||
} else {
|
||||
int i;
|
||||
|
||||
for (i = 0; sz_name[i]; i++) {
|
||||
if (sz < (1024 * 1024) || !sz_name[i + 1]) {
|
||||
long isz = (static_cast<long>(sz)) / 1024;
|
||||
if (isz > 9)
|
||||
result.append(format_string(L"%ld%ls", isz, sz_name[i]));
|
||||
else
|
||||
result.append(
|
||||
format_string(L"%.1f%ls", static_cast<double>(sz) / 1024, sz_name[i]));
|
||||
break;
|
||||
}
|
||||
sz /= 1024;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Crappy function to extract the most significant digit of an unsigned long long value.
|
||||
static char extract_most_significant_digit(unsigned long long *xp) {
|
||||
unsigned long long place_value = 1;
|
||||
|
@ -1019,53 +759,6 @@ static char extract_most_significant_digit(unsigned long long *xp) {
|
|||
return x + '0';
|
||||
}
|
||||
|
||||
static void append_ull(char *buff, unsigned long long val, size_t *inout_idx, size_t max_len) {
|
||||
size_t idx = *inout_idx;
|
||||
while (val > 0 && idx < max_len) buff[idx++] = extract_most_significant_digit(&val);
|
||||
*inout_idx = idx;
|
||||
}
|
||||
|
||||
static void append_str(char *buff, const char *str, size_t *inout_idx, size_t max_len) {
|
||||
size_t idx = *inout_idx;
|
||||
while (*str && idx < max_len) buff[idx++] = *str++;
|
||||
*inout_idx = idx;
|
||||
}
|
||||
|
||||
void format_size_safe(char buff[128], unsigned long long sz) {
|
||||
const size_t buff_size = 128;
|
||||
const size_t max_len = buff_size - 1; // need to leave room for a null terminator
|
||||
std::memset(buff, 0, buff_size);
|
||||
size_t idx = 0;
|
||||
const char *const sz_name[] = {"kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB", nullptr};
|
||||
if (sz < 1) {
|
||||
strcpy(buff, "empty");
|
||||
} else if (sz < 1024) {
|
||||
append_ull(buff, sz, &idx, max_len);
|
||||
append_str(buff, "B", &idx, max_len);
|
||||
} else {
|
||||
for (size_t i = 0; sz_name[i]; i++) {
|
||||
if (sz < (1024 * 1024) || !sz_name[i + 1]) {
|
||||
unsigned long long isz = sz / 1024;
|
||||
if (isz > 9) {
|
||||
append_ull(buff, isz, &idx, max_len);
|
||||
} else {
|
||||
append_ull(buff, isz, &idx, max_len);
|
||||
|
||||
// Maybe append a single fraction digit.
|
||||
unsigned long long remainder = sz % 1024;
|
||||
if (remainder > 0) {
|
||||
char tmp[3] = {'.', extract_most_significant_digit(&remainder), 0};
|
||||
append_str(buff, tmp, &idx, max_len);
|
||||
}
|
||||
}
|
||||
append_str(buff, sz_name[i], &idx, max_len);
|
||||
break;
|
||||
}
|
||||
sz /= 1024;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double timef() {
|
||||
struct timeval tv;
|
||||
assert_with_errno(gettimeofday(&tv, nullptr) != -1);
|
||||
|
@ -1148,75 +841,6 @@ bool valid_var_name(const wchar_t *str) {
|
|||
return true;
|
||||
}
|
||||
|
||||
/// Test if the string is a valid function name.
|
||||
bool valid_func_name(const wcstring &str) {
|
||||
if (str.empty()) return false;
|
||||
if (str.at(0) == L'-') return false;
|
||||
// A function name needs to be a valid path, so no / and no NULL.
|
||||
if (str.find_first_of(L'/') != wcstring::npos) return false;
|
||||
if (str.find_first_of(L'\0') != wcstring::npos) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Return the path to the current executable. This needs to be realpath'd.
|
||||
std::string get_executable_path(const char *argv0) {
|
||||
char buff[PATH_MAX];
|
||||
|
||||
#ifdef __APPLE__
|
||||
// On OS X use it's proprietary API to get the path to the executable.
|
||||
// This is basically grabbing exec_path after argc, argv, envp, ...: for us
|
||||
// https://opensource.apple.com/source/adv_cmds/adv_cmds-163/ps/print.c
|
||||
uint32_t buffSize = sizeof buff;
|
||||
if (_NSGetExecutablePath(buff, &buffSize) == 0) return std::string(buff);
|
||||
#elif defined(__BSD__) && defined(KERN_PROC_PATHNAME)
|
||||
// BSDs do not have /proc by default, (although it can be mounted as procfs via the Linux
|
||||
// compatibility layer). We can use sysctl instead: per sysctl(3), passing in a process ID of -1
|
||||
// returns the value for the current process.
|
||||
size_t buff_size = sizeof buff;
|
||||
#if defined(__NetBSD__)
|
||||
int name[] = {CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_PATHNAME};
|
||||
#else
|
||||
int name[] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
|
||||
#endif
|
||||
int result = sysctl(name, sizeof(name) / sizeof(int), buff, &buff_size, nullptr, 0);
|
||||
if (result != 0) {
|
||||
wperror(L"sysctl KERN_PROC_PATHNAME");
|
||||
} else {
|
||||
return std::string(buff);
|
||||
}
|
||||
#else
|
||||
// On other unixes, fall back to the Linux-ish /proc/ directory
|
||||
ssize_t len;
|
||||
len = readlink("/proc/self/exe", buff, sizeof buff - 1); // Linux
|
||||
if (len == -1) {
|
||||
len = readlink("/proc/curproc/file", buff, sizeof buff - 1); // other BSDs
|
||||
if (len == -1) {
|
||||
len = readlink("/proc/self/path/a.out", buff, sizeof buff - 1); // Solaris
|
||||
}
|
||||
}
|
||||
if (len > 0) {
|
||||
buff[len] = '\0';
|
||||
// When /proc/self/exe points to a file that was deleted (or overwritten on update!)
|
||||
// then linux adds a " (deleted)" suffix.
|
||||
// If that's not a valid path, let's remove that awkward suffix.
|
||||
std::string buffstr{buff};
|
||||
if (access(buff, F_OK)) {
|
||||
auto dellen = const_strlen(" (deleted)");
|
||||
if (buffstr.size() > dellen &&
|
||||
buffstr.compare(buffstr.size() - dellen, dellen, " (deleted)") == 0) {
|
||||
buffstr = buffstr.substr(0, buffstr.size() - dellen);
|
||||
}
|
||||
}
|
||||
return buffstr;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Just return argv0, which probably won't work (i.e. it's not an absolute path or a path
|
||||
// relative to the working directory, but instead something the caller found via $PATH). We'll
|
||||
// eventually fall back to the compile time paths.
|
||||
return std::string(argv0 ? argv0 : "");
|
||||
}
|
||||
|
||||
/// Return a path to a directory where we can store temporary files.
|
||||
std::string get_path_to_tmp_dir() {
|
||||
char *env_tmpdir = getenv("TMPDIR");
|
||||
|
|
26
src/common.h
26
src/common.h
|
@ -321,21 +321,12 @@ bool should_suppress_stderr_for_tests();
|
|||
#define likely(x) __builtin_expect(bool(x), 1)
|
||||
#define unlikely(x) __builtin_expect(bool(x), 0)
|
||||
|
||||
/// Format the specified size (in bytes, kilobytes, etc.) into the specified stringbuffer.
|
||||
wcstring format_size(long long sz);
|
||||
|
||||
/// Version of format_size that does not allocate memory.
|
||||
void format_size_safe(char buff[128], unsigned long long sz);
|
||||
|
||||
/// Writes out a long safely.
|
||||
void format_long_safe(char buff[64], long val);
|
||||
void format_long_safe(wchar_t buff[64], long val);
|
||||
void format_llong_safe(wchar_t buff[64], long long val);
|
||||
void format_ullong_safe(wchar_t buff[64], unsigned long long val);
|
||||
|
||||
/// "Narrows" a wide character string. This just grabs any ASCII characters and truncates.
|
||||
void narrow_string_safe(char buff[64], const wchar_t *s);
|
||||
|
||||
/// Stored in blocks to reference the file which created the block.
|
||||
using filename_ref_t = std::shared_ptr<wcstring>;
|
||||
|
||||
|
@ -475,10 +466,6 @@ long read_blocked(int fd, void *buf, size_t count);
|
|||
/// error.
|
||||
ssize_t write_loop(int fd, const char *buff, size_t count);
|
||||
|
||||
/// Loop a read request while failure is non-critical. Return -1 and set errno in case of critical
|
||||
/// error.
|
||||
ssize_t read_loop(int fd, void *buff, size_t count);
|
||||
|
||||
/// Replace special characters with backslash escape sequences. Newline is replaced with \n, etc.
|
||||
///
|
||||
/// \param in The string to be escaped
|
||||
|
@ -489,19 +476,10 @@ wcstring escape_string(const wchar_t *in, escape_flags_t flags = 0,
|
|||
wcstring escape_string(const wcstring &in, escape_flags_t flags = 0,
|
||||
escape_string_style_t style = STRING_STYLE_SCRIPT);
|
||||
|
||||
/// Escape a string so that it may be inserted into a double-quoted string.
|
||||
/// This permits ownership transfer.
|
||||
wcstring escape_string_for_double_quotes(wcstring in);
|
||||
|
||||
/// Expand backslashed escapes and substitute them with their unescaped counterparts. Also
|
||||
/// optionally change the wildcards, the tilde character and a few more into constants which are
|
||||
/// defined in a private use area of Unicode. This assumes wchar_t is a unicode character set.
|
||||
|
||||
/// Given a null terminated string starting with a backslash, read the escape as if it is unquoted,
|
||||
/// appending to result. Return the number of characters consumed, or none() on error.
|
||||
maybe_t<size_t> read_unquoted_escape(const wchar_t *input, wcstring *result, bool allow_incomplete,
|
||||
bool unescape_special);
|
||||
|
||||
/// Return the number of seconds from the UNIX epoch, with subsecond precision. This function uses
|
||||
/// the gettimeofday function and will have the same precision as that function.
|
||||
using timepoint_t = double;
|
||||
|
@ -552,7 +530,6 @@ std::string get_path_to_tmp_dir();
|
|||
bool valid_var_name_char(wchar_t chr);
|
||||
bool valid_var_name(const wcstring &str);
|
||||
bool valid_var_name(const wchar_t *str);
|
||||
bool valid_func_name(const wcstring &str);
|
||||
|
||||
// Return values (`$status` values for fish scripts) for various situations.
|
||||
enum {
|
||||
|
@ -610,9 +587,6 @@ struct hash<const wcstring> {
|
|||
} // namespace std
|
||||
#endif
|
||||
|
||||
/// Get the absolute path to the fish executable itself
|
||||
std::string get_executable_path(const char *argv0);
|
||||
|
||||
/// A RAII wrapper for resources that don't recur, so we don't have to create a separate RAII
|
||||
/// wrapper for each function. Avoids needing to call "return cleanup()" or similar / everywhere.
|
||||
struct cleanup_t {
|
||||
|
|
|
@ -177,10 +177,6 @@ int env_stack_t::set_one(const wcstring &key, env_mode_flags_t mode, wcstring va
|
|||
return set(key, mode, std::move(vals));
|
||||
}
|
||||
|
||||
int env_stack_t::set_empty(const wcstring &key, env_mode_flags_t mode) {
|
||||
return set(key, mode, {});
|
||||
}
|
||||
|
||||
int env_stack_t::remove(const wcstring &key, int mode) {
|
||||
return static_cast<int>(impl_->remove(key, mode));
|
||||
}
|
||||
|
@ -203,8 +199,6 @@ std::shared_ptr<environment_t> env_stack_t::snapshot() const {
|
|||
return std::static_pointer_cast<environment_t>(res);
|
||||
}
|
||||
|
||||
void env_stack_t::set_argv(std::vector<wcstring> argv) { set(L"argv", ENV_LOCAL, std::move(argv)); }
|
||||
|
||||
wcstring env_stack_t::get_pwd_slash() const {
|
||||
std::unique_ptr<wcstring> res = impl_->get_pwd_slash();
|
||||
return std::move(*res);
|
||||
|
|
|
@ -221,8 +221,6 @@ class env_stack_t final : public environment_t {
|
|||
int set_one(const wcstring &key, env_mode_flags_t mode, wcstring val);
|
||||
|
||||
/// Sets the variable with the specified name to no values.
|
||||
int set_empty(const wcstring &key, env_mode_flags_t mode);
|
||||
|
||||
/// Update the PWD variable based on the result of getcwd.
|
||||
void set_pwd_from_getcwd();
|
||||
|
||||
|
@ -248,9 +246,6 @@ class env_stack_t final : public environment_t {
|
|||
/// you want to read from another thread.
|
||||
std::shared_ptr<environment_t> snapshot() const;
|
||||
|
||||
/// Sets up argv as the given list of strings.
|
||||
void set_argv(std::vector<wcstring> argv);
|
||||
|
||||
/// Slightly optimized implementation.
|
||||
wcstring get_pwd_slash() const override;
|
||||
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
// We need the sys/file.h for the flock() declaration on Linux but not OS X.
|
||||
#include <sys/file.h> // IWYU pragma: keep
|
||||
// We need the ioctl.h header so we can check if SIOCGIFHWADDR is defined by it so we know if we're
|
||||
// on a Linux system.
|
||||
#include <netinet/in.h> // IWYU pragma: keep
|
||||
|
|
|
@ -43,20 +43,6 @@ char *tparm_solaris_kludge(char *str, long p1, long p2, long p3, long p4, long p
|
|||
}
|
||||
#endif
|
||||
|
||||
int fish_mkstemp_cloexec(char *name_template) {
|
||||
#if HAVE_MKOSTEMP
|
||||
// null check because mkostemp may be a weak symbol
|
||||
if (&mkostemp != nullptr) {
|
||||
return mkostemp(name_template, O_CLOEXEC);
|
||||
}
|
||||
#endif
|
||||
int result_fd = mkstemp(name_template);
|
||||
if (result_fd != -1) {
|
||||
fcntl(result_fd, F_SETFD, FD_CLOEXEC);
|
||||
}
|
||||
return result_fd;
|
||||
}
|
||||
|
||||
/// Fallback implementations of wcsncasecmp and wcscasecmp. On systems where these are not needed
|
||||
/// (e.g. building on Linux) these should end up just being stripped, as they are static functions
|
||||
/// that are not referenced in this file.
|
||||
|
@ -193,72 +179,3 @@ int fish_wcswidth(const wchar_t *str, size_t n) {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifndef HAVE_FLOCK
|
||||
/* $NetBSD: flock.c,v 1.6 2008/04/28 20:24:12 martin Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2001 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Todd Vierling.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Emulate flock() with fcntl().
|
||||
*/
|
||||
|
||||
int flock(int fd, int op) {
|
||||
int rc = 0;
|
||||
|
||||
struct flock fl = {0};
|
||||
|
||||
switch (op & (LOCK_EX | LOCK_SH | LOCK_UN)) {
|
||||
case LOCK_EX:
|
||||
fl.l_type = F_WRLCK;
|
||||
break;
|
||||
|
||||
case LOCK_SH:
|
||||
fl.l_type = F_RDLCK;
|
||||
break;
|
||||
|
||||
case LOCK_UN:
|
||||
fl.l_type = F_UNLCK;
|
||||
break;
|
||||
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
fl.l_whence = SEEK_SET;
|
||||
rc = fcntl(fd, op & LOCK_NB ? F_SETLK : F_SETLKW, &fl);
|
||||
|
||||
if (rc && (errno == EAGAIN)) errno = EWOULDBLOCK;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif // HAVE_FLOCK
|
||||
|
|
|
@ -23,11 +23,6 @@ extern int32_t FISH_EMOJI_WIDTH;
|
|||
int fish_wcwidth(wchar_t wc);
|
||||
int fish_wcswidth(const wchar_t *str, size_t n);
|
||||
|
||||
// Replacement for mkostemp(str, O_CLOEXEC)
|
||||
// This uses mkostemp if available,
|
||||
// otherwise it uses mkstemp followed by fcntl
|
||||
int fish_mkstemp_cloexec(char *);
|
||||
|
||||
/// thread_local support.
|
||||
#if HAVE_CX11_THREAD_LOCAL
|
||||
#define FISH_THREAD_LOCAL thread_local
|
||||
|
@ -115,16 +110,4 @@ char *fish_textdomain(const char *domainname);
|
|||
int killpg(int pgr, int sig);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_FLOCK
|
||||
/// Fallback implementation of flock in terms of fcntl.
|
||||
/// Danger! The semantics of flock and fcntl locking are very different.
|
||||
/// Use with caution.
|
||||
int flock(int fd, int op);
|
||||
|
||||
#define LOCK_SH 1 // Shared lock.
|
||||
#define LOCK_EX 2 // Exclusive lock.
|
||||
#define LOCK_UN 8 // Unlock.
|
||||
#define LOCK_NB 4 // Don't block when locking.
|
||||
#endif
|
||||
|
||||
#endif // FISH_FALLBACK_H
|
||||
|
|
|
@ -204,48 +204,6 @@ static int parse_util_locate_cmdsub(const wchar_t *in, const wchar_t **begin, co
|
|||
return 1;
|
||||
}
|
||||
|
||||
long parse_util_slice_length(const wchar_t *in) {
|
||||
assert(in && "null parameter");
|
||||
const wchar_t openc = L'[';
|
||||
const wchar_t closec = L']';
|
||||
bool escaped = false;
|
||||
|
||||
// Check for initial opening [
|
||||
if (*in != openc) return 0;
|
||||
int bracket_count = 1;
|
||||
|
||||
assert(in && "null parameter");
|
||||
for (const wchar_t *pos = in + 1; *pos; pos++) {
|
||||
if (!escaped) {
|
||||
if (*pos == L'\'' || *pos == L'"') {
|
||||
const wchar_t *q_end = quote_end(pos, *pos);
|
||||
if (q_end && *q_end) {
|
||||
pos = q_end;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (*pos == openc) {
|
||||
bracket_count++;
|
||||
} else if (*pos == closec) {
|
||||
bracket_count--;
|
||||
if (bracket_count == 0) {
|
||||
// pos points at the closing ], so add 1.
|
||||
return pos - in + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (*pos == '\\') {
|
||||
escaped = !escaped;
|
||||
} else {
|
||||
escaped = false;
|
||||
}
|
||||
}
|
||||
assert(bracket_count > 0 && "Should have unclosed brackets");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int parse_util_locate_cmdsubst_range(const wcstring &str, size_t *inout_cursor_offset,
|
||||
wcstring *out_contents, size_t *out_start, size_t *out_end,
|
||||
bool accept_incomplete, bool *inout_is_quoted,
|
||||
|
@ -612,8 +570,6 @@ static bool append_syntax_error(parse_error_list_t *errors, size_t source_locati
|
|||
return true;
|
||||
}
|
||||
|
||||
bool parse_util_argument_is_help(const wcstring &s) { return s == L"-h" || s == L"--help"; }
|
||||
|
||||
// \return a pointer to the first argument node of an argument_or_redirection_list_t, or nullptr if
|
||||
// there are no arguments.
|
||||
static const ast::argument_t *get_first_arg(const ast::argument_or_redirection_list_t &list) {
|
||||
|
|
|
@ -18,11 +18,6 @@
|
|||
struct Tok;
|
||||
using tok_t = Tok;
|
||||
|
||||
/// Handles slices: the square brackets in an expression like $foo[5..4]
|
||||
/// \return the length of the slice starting at \p in, or 0 if there is no slice, or -1 on error.
|
||||
/// This never accepts incomplete slices.
|
||||
long parse_util_slice_length(const wchar_t *in);
|
||||
|
||||
/// Alternative API. Iterate over command substitutions.
|
||||
///
|
||||
/// \param str the string to search for subshells
|
||||
|
@ -101,9 +96,6 @@ size_t parse_util_get_offset(const wcstring &str, int line, long line_offset);
|
|||
/// transformation.
|
||||
wcstring parse_util_unescape_wildcards(const wcstring &str);
|
||||
|
||||
/// Checks if the specified string is a help option.
|
||||
bool parse_util_argument_is_help(const wcstring &s);
|
||||
|
||||
/// Calculates information on the parameter at the specified index.
|
||||
///
|
||||
/// \param cmd The command to be analyzed
|
||||
|
|
141
src/path.cpp
141
src/path.cpp
|
@ -83,15 +83,6 @@ static get_path_result_t path_get_path_core(const wcstring &cmd,
|
|||
return best;
|
||||
}
|
||||
|
||||
maybe_t<wcstring> path_get_path(const wcstring &cmd, const environment_t &vars) {
|
||||
auto result = path_try_get_path(cmd, vars);
|
||||
if (result.err != 0) {
|
||||
return none();
|
||||
}
|
||||
wcstring path = std::move(result.path);
|
||||
return path;
|
||||
}
|
||||
|
||||
get_path_result_t path_try_get_path(const wcstring &cmd, const environment_t &vars) {
|
||||
auto pathvar = vars.get(L"PATH");
|
||||
return path_get_path_core(cmd, pathvar ? pathvar->as_list() : kDefaultPath);
|
||||
|
@ -196,81 +187,6 @@ maybe_t<wcstring> path_get_cdpath(const wcstring &dir, const wcstring &wd,
|
|||
return none();
|
||||
}
|
||||
|
||||
maybe_t<wcstring> path_as_implicit_cd(const wcstring &path, const wcstring &wd,
|
||||
// todo!("should be environment_t")
|
||||
const env_stack_t &vars) {
|
||||
wcstring exp_path = path;
|
||||
expand_tilde(exp_path, vars);
|
||||
if (string_prefixes_string(L"/", exp_path) || string_prefixes_string(L"./", exp_path) ||
|
||||
string_prefixes_string(L"../", exp_path) || string_suffixes_string(L"/", exp_path) ||
|
||||
exp_path == L"..") {
|
||||
// These paths can be implicit cd, so see if you cd to the path. Note that a single period
|
||||
// cannot (that's used for sourcing files anyways).
|
||||
return path_get_cdpath(exp_path, wd, vars);
|
||||
}
|
||||
return none();
|
||||
}
|
||||
|
||||
// If the given path looks like it's relative to the working directory, then prepend that working
|
||||
// directory. This operates on unescaped paths only (so a ~ means a literal ~).
|
||||
wcstring path_apply_working_directory(const wcstring &path, const wcstring &working_directory) {
|
||||
if (path.empty() || working_directory.empty()) return path;
|
||||
|
||||
// We're going to make sure that if we want to prepend the wd, that the string has no leading
|
||||
// "/".
|
||||
bool prepend_wd = path.at(0) != L'/' && path.at(0) != HOME_DIRECTORY;
|
||||
if (!prepend_wd) {
|
||||
// No need to prepend the wd, so just return the path we were given.
|
||||
return path;
|
||||
}
|
||||
|
||||
// Remove up to one "./".
|
||||
wcstring path_component = path;
|
||||
if (string_prefixes_string(L"./", path_component)) {
|
||||
path_component.erase(0, 2);
|
||||
}
|
||||
|
||||
// Removing leading /s.
|
||||
while (string_prefixes_string(L"/", path_component)) {
|
||||
path_component.erase(0, 1);
|
||||
}
|
||||
|
||||
// Construct and return a new path.
|
||||
wcstring new_path = working_directory;
|
||||
append_path_component(new_path, path_component);
|
||||
return new_path;
|
||||
}
|
||||
|
||||
/// We separate this from path_create() for two reasons. First it's only caused if there is a
|
||||
/// problem, and thus is not central to the behavior of that function. Second, we only want to issue
|
||||
/// the message once. If the current shell starts a new fish shell (e.g., by running `fish -c` from
|
||||
/// a function) we don't want that subshell to issue the same warnings.
|
||||
static void maybe_issue_path_warning(const wcstring &which_dir, const wcstring &custom_error_msg,
|
||||
bool using_xdg, const wcstring &xdg_var, const wcstring &path,
|
||||
int saved_errno, env_stack_t &vars) {
|
||||
wcstring warning_var_name = L"_FISH_WARNED_" + which_dir;
|
||||
if (vars.get(warning_var_name, ENV_GLOBAL | ENV_EXPORT)) {
|
||||
return;
|
||||
}
|
||||
vars.set_one(warning_var_name, ENV_GLOBAL | ENV_EXPORT, L"1");
|
||||
|
||||
FLOG(error, custom_error_msg.c_str());
|
||||
if (path.empty()) {
|
||||
FLOGF(warning_path, _(L"Unable to locate the %ls directory."), which_dir.c_str());
|
||||
FLOGF(warning_path,
|
||||
_(L"Please set the %ls or HOME environment variable before starting fish."),
|
||||
xdg_var.c_str());
|
||||
} else {
|
||||
const wchar_t *env_var = using_xdg ? xdg_var.c_str() : L"HOME";
|
||||
FLOGF(warning_path, _(L"Unable to locate %ls directory derived from $%ls: '%ls'."),
|
||||
which_dir.c_str(), env_var, path.c_str());
|
||||
FLOGF(warning_path, _(L"The error was '%s'."), std::strerror(saved_errno));
|
||||
FLOGF(warning_path, _(L"Please set $%ls to a directory where you have write access."),
|
||||
env_var);
|
||||
}
|
||||
ignore_result(write(STDERR_FILENO, "\n", 1));
|
||||
}
|
||||
|
||||
/// Make sure the specified directory exists. If needed, try to create it and any currently not
|
||||
/// existing parent directories, like mkdir -p,.
|
||||
///
|
||||
|
@ -350,27 +266,6 @@ static const base_directory_t &get_config_directory() {
|
|||
return s_dir;
|
||||
}
|
||||
|
||||
void path_emit_config_directory_messages(env_stack_t &vars) {
|
||||
const auto &data = get_data_directory();
|
||||
if (!data.success()) {
|
||||
maybe_issue_path_warning(L"data", _(L"can not save history"), data.used_xdg,
|
||||
L"XDG_DATA_HOME", data.path, data.err, vars);
|
||||
}
|
||||
if (data.remoteness == dir_remoteness_t::remote) {
|
||||
FLOG(path, "data path appears to be on a network volume");
|
||||
}
|
||||
|
||||
const auto &config = get_config_directory();
|
||||
if (!config.success()) {
|
||||
maybe_issue_path_warning(L"config", _(L"can not save universal variables or functions"),
|
||||
config.used_xdg, L"XDG_CONFIG_HOME", config.path, config.err,
|
||||
vars);
|
||||
}
|
||||
if (config.remoteness == dir_remoteness_t::remote) {
|
||||
FLOG(path, "config path appears to be on a network volume");
|
||||
}
|
||||
}
|
||||
|
||||
bool path_get_config(wcstring &path) {
|
||||
const auto &dir = get_config_directory();
|
||||
path = dir.success() ? dir.path : L"";
|
||||
|
@ -383,10 +278,6 @@ bool path_get_data(wcstring &path) {
|
|||
return dir.success();
|
||||
}
|
||||
|
||||
dir_remoteness_t path_get_data_remoteness() { return get_data_directory().remoteness; }
|
||||
|
||||
dir_remoteness_t path_get_config_remoteness() { return get_config_directory().remoteness; }
|
||||
|
||||
bool paths_are_equivalent(const wcstring &p1, const wcstring &p2) {
|
||||
if (p1 == p2) return true;
|
||||
|
||||
|
@ -417,38 +308,6 @@ bool paths_are_equivalent(const wcstring &p1, const wcstring &p2) {
|
|||
return idx1 == len1 && idx2 == len2;
|
||||
}
|
||||
|
||||
bool path_is_valid(const wcstring &path, const wcstring &working_directory) {
|
||||
bool path_is_valid;
|
||||
// Some special paths are always valid.
|
||||
if (path.empty()) {
|
||||
path_is_valid = false;
|
||||
} else if (path == L"." || path == L"./") {
|
||||
path_is_valid = true;
|
||||
} else if (path == L".." || path == L"../") {
|
||||
path_is_valid = (!working_directory.empty() && working_directory != L"/");
|
||||
} else if (path.at(0) != '/') {
|
||||
// Prepend the working directory. Note that we know path is not empty here.
|
||||
wcstring tmp = working_directory;
|
||||
tmp.append(path);
|
||||
path_is_valid = (0 == waccess(tmp, F_OK));
|
||||
} else {
|
||||
// Simple check.
|
||||
path_is_valid = (0 == waccess(path, F_OK));
|
||||
}
|
||||
return path_is_valid;
|
||||
}
|
||||
|
||||
bool paths_are_same_file(const wcstring &path1, const wcstring &path2) {
|
||||
if (paths_are_equivalent(path1, path2)) return true;
|
||||
|
||||
struct stat s1, s2;
|
||||
if (wstat(path1, &s1) == 0 && wstat(path2, &s2) == 0) {
|
||||
return s1.st_ino == s2.st_ino && s1.st_dev == s2.st_dev;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void append_path_component(wcstring &path, const wcstring &component) {
|
||||
if (path.empty() || component.empty()) {
|
||||
path.append(component);
|
||||
|
|
29
src/path.h
29
src/path.h
|
@ -35,21 +35,6 @@ enum class dir_remoteness_t {
|
|||
remote, // directory is known remote
|
||||
};
|
||||
|
||||
/// \return the remoteness of the fish data directory.
|
||||
/// This will be remote for filesystems like NFS, SMB, etc.
|
||||
dir_remoteness_t path_get_data_remoteness();
|
||||
|
||||
/// Like path_get_data_remoteness but for the config directory.
|
||||
dir_remoteness_t path_get_config_remoteness();
|
||||
|
||||
/// Emit any errors if config directories are missing.
|
||||
/// Use the given environment stack to ensure this only occurs once.
|
||||
void path_emit_config_directory_messages(env_stack_t &vars);
|
||||
|
||||
/// Finds the path of an executable named \p cmd, by looking in $PATH taken from \p vars.
|
||||
/// \returns the path if found, none if not.
|
||||
maybe_t<wcstring> path_get_path(const wcstring &cmd, const environment_t &vars);
|
||||
|
||||
/// Finds the path of an executable named \p cmd, by looking in $PATH taken from \p vars.
|
||||
/// On success, err will be 0 and the path is returned.
|
||||
/// On failure, we return the "best path" with err set appropriately.
|
||||
|
@ -81,24 +66,10 @@ maybe_t<wcstring> path_get_cdpath(const wcstring &dir, const wcstring &wd,
|
|||
std::vector<wcstring> path_apply_cdpath(const wcstring &dir, const wcstring &wd,
|
||||
const env_stack_t &env_vars);
|
||||
|
||||
/// Returns the path resolved as an implicit cd command, or none() if none. This requires it to
|
||||
/// start with one of the allowed prefixes (., .., ~) and resolve to a directory.
|
||||
maybe_t<wcstring> path_as_implicit_cd(const wcstring &path, const wcstring &wd,
|
||||
const env_stack_t &vars);
|
||||
|
||||
/// Check if two paths are equivalent, which means to ignore runs of multiple slashes (or trailing
|
||||
/// slashes).
|
||||
bool paths_are_equivalent(const wcstring &p1, const wcstring &p2);
|
||||
|
||||
bool path_is_valid(const wcstring &path, const wcstring &working_directory);
|
||||
|
||||
/// Returns whether the two paths refer to the same file.
|
||||
bool paths_are_same_file(const wcstring &path1, const wcstring &path2);
|
||||
|
||||
/// If the given path looks like it's relative to the working directory, then prepend that working
|
||||
/// directory. This operates on unescaped paths only (so a ~ means a literal ~).
|
||||
wcstring path_apply_working_directory(const wcstring &path, const wcstring &working_directory);
|
||||
|
||||
/// Appends a path component, with a / if necessary.
|
||||
void append_path_component(wcstring &path, const wcstring &component);
|
||||
|
||||
|
|
|
@ -259,34 +259,6 @@ std::vector<wcstring> split_string(const wcstring &val, wchar_t sep) {
|
|||
return out;
|
||||
}
|
||||
|
||||
std::vector<wcstring> split_string_tok(const wcstring &val, const wcstring &seps,
|
||||
size_t max_results) {
|
||||
std::vector<wcstring> out;
|
||||
size_t end = val.size();
|
||||
size_t pos = 0;
|
||||
while (pos < end && out.size() + 1 < max_results) {
|
||||
// Skip leading seps.
|
||||
pos = val.find_first_not_of(seps, pos);
|
||||
if (pos == wcstring::npos) break;
|
||||
|
||||
// Find next sep.
|
||||
size_t next_sep = val.find_first_of(seps, pos);
|
||||
if (next_sep == wcstring::npos) {
|
||||
next_sep = end;
|
||||
}
|
||||
out.emplace_back(val, pos, next_sep - pos);
|
||||
// Note we skip exactly one sep here. This is because on the last iteration we retain all
|
||||
// but the first leading separators. This is historical.
|
||||
pos = next_sep + 1;
|
||||
}
|
||||
if (pos < end && max_results > 0) {
|
||||
assert(out.size() + 1 == max_results && "Should have split the max");
|
||||
out.emplace_back(val, pos);
|
||||
}
|
||||
assert(out.size() <= max_results && "Got too many results");
|
||||
return out;
|
||||
}
|
||||
|
||||
static wcstring join_strings_impl(const std::vector<wcstring> &vals, const wchar_t *sep,
|
||||
size_t seplen) {
|
||||
if (vals.empty()) return wcstring{};
|
||||
|
|
|
@ -130,16 +130,6 @@ inline maybe_t<string_fuzzy_match_t> string_fuzzy_match_string(const wcstring &s
|
|||
/// Split a string by a separator character.
|
||||
std::vector<wcstring> split_string(const wcstring &val, wchar_t sep);
|
||||
|
||||
/// Split a string by runs of any of the separator characters provided in \p seps.
|
||||
/// Note the delimiters are the characters in \p seps, not \p seps itself.
|
||||
/// \p seps may contain the NUL character.
|
||||
/// Do not output more than \p max_results results. If we are to output exactly that much,
|
||||
/// the last output is the the remainder of the input, including leading delimiters,
|
||||
/// except for the first. This is historical behavior.
|
||||
/// Example: split_string_tok(" a b c ", " ", 3) -> {"a", "b", " c "}
|
||||
std::vector<wcstring> split_string_tok(const wcstring &val, const wcstring &seps,
|
||||
size_t max_results = std::numeric_limits<size_t>::max());
|
||||
|
||||
/// Join a list of strings by a separator character or string.
|
||||
wcstring join_strings(const std::vector<wcstring> &vals, wchar_t sep);
|
||||
wcstring join_strings(const std::vector<wcstring> &vals, const wchar_t *sep);
|
||||
|
|
|
@ -45,17 +45,6 @@ wcstring_list_ffi_t::~wcstring_list_ffi_t() = default;
|
|||
/// Map used as cache by wgettext.
|
||||
static owning_lock<std::unordered_map<wcstring, wcstring>> wgettext_map;
|
||||
|
||||
wcstring wgetcwd() {
|
||||
char cwd[PATH_MAX];
|
||||
char *res = getcwd(cwd, sizeof(cwd));
|
||||
if (res) {
|
||||
return str2wcstring(res);
|
||||
}
|
||||
|
||||
FLOGF(error, _(L"getcwd() failed with errno %d/%s"), errno, std::strerror(errno));
|
||||
return wcstring();
|
||||
}
|
||||
|
||||
DIR *wopendir(const wcstring &name) {
|
||||
const cstring tmp = wcs2zstring(name);
|
||||
return opendir(tmp.c_str());
|
||||
|
@ -261,11 +250,6 @@ int waccess(const wcstring &file_name, int mode) {
|
|||
return access(tmp.c_str(), mode);
|
||||
}
|
||||
|
||||
int wunlink(const wcstring &file_name) {
|
||||
const cstring tmp = wcs2zstring(file_name);
|
||||
return unlink(tmp.c_str());
|
||||
}
|
||||
|
||||
void wperror(wcharz_t s) {
|
||||
int e = errno;
|
||||
if (s.str[0] != L'\0') {
|
||||
|
@ -294,59 +278,6 @@ int make_fd_blocking(int fd) {
|
|||
return err == -1 ? errno : 0;
|
||||
}
|
||||
|
||||
/// Wide character realpath. The last path component does not need to be valid. If an error occurs,
|
||||
/// wrealpath() returns none() and errno is likely set.
|
||||
maybe_t<wcstring> wrealpath(const wcstring &pathname) {
|
||||
if (pathname.empty()) return none();
|
||||
|
||||
cstring real_path;
|
||||
cstring narrow_path = wcs2zstring(pathname);
|
||||
|
||||
// Strip trailing slashes. This is treats "/a//" as equivalent to "/a" if /a is a non-directory.
|
||||
while (narrow_path.size() > 1 && narrow_path.at(narrow_path.size() - 1) == '/') {
|
||||
narrow_path.erase(narrow_path.size() - 1, 1);
|
||||
}
|
||||
|
||||
char tmpbuf[PATH_MAX];
|
||||
char *narrow_res = realpath(narrow_path.c_str(), tmpbuf);
|
||||
|
||||
if (narrow_res) {
|
||||
real_path.append(narrow_res);
|
||||
} else {
|
||||
// Check if everything up to the last path component is valid.
|
||||
size_t pathsep_idx = narrow_path.rfind('/');
|
||||
|
||||
if (pathsep_idx == 0) {
|
||||
// If the only pathsep is the first character then it's an absolute path with a
|
||||
// single path component and thus doesn't need conversion.
|
||||
real_path = narrow_path;
|
||||
} else {
|
||||
// Only call realpath() on the portion up to the last component.
|
||||
errno = 0;
|
||||
|
||||
if (pathsep_idx == cstring::npos) {
|
||||
// If there is no "/", this is a file in $PWD, so give the realpath to that.
|
||||
narrow_res = realpath(".", tmpbuf);
|
||||
} else {
|
||||
errno = 0;
|
||||
// Only call realpath() on the portion up to the last component.
|
||||
narrow_res = realpath(narrow_path.substr(0, pathsep_idx).c_str(), tmpbuf);
|
||||
}
|
||||
|
||||
if (!narrow_res) return none();
|
||||
|
||||
pathsep_idx++;
|
||||
real_path.append(narrow_res);
|
||||
|
||||
// This test is to deal with cases such as /../../x => //x.
|
||||
if (real_path.size() > 1) real_path.append("/");
|
||||
|
||||
real_path.append(narrow_path.substr(pathsep_idx, cstring::npos));
|
||||
}
|
||||
}
|
||||
return str2wcstring(real_path);
|
||||
}
|
||||
|
||||
wcstring normalize_path(const wcstring &path, bool allow_leading_double_slashes) {
|
||||
// Count the leading slashes.
|
||||
const wchar_t sep = L'/';
|
||||
|
@ -514,12 +445,6 @@ int wmkdir(const wcstring &name, int mode) {
|
|||
return mkdir(name_narrow.c_str(), mode);
|
||||
}
|
||||
|
||||
int wrename(const wcstring &old, const wcstring &newv) {
|
||||
cstring old_narrow = wcs2zstring(old);
|
||||
cstring new_narrow = wcs2zstring(newv);
|
||||
return rename(old_narrow.c_str(), new_narrow.c_str());
|
||||
}
|
||||
|
||||
ssize_t wwrite_to_fd(const wchar_t *input, size_t input_len, int fd) {
|
||||
// Accumulate data in a local buffer.
|
||||
char accum[512];
|
||||
|
@ -740,24 +665,6 @@ file_id_t file_id_for_fd(int fd) {
|
|||
|
||||
file_id_t file_id_for_fd(const autoclose_fd_t &fd) { return file_id_for_fd(fd.fd()); }
|
||||
|
||||
file_id_t file_id_for_path(const wcstring &path) {
|
||||
file_id_t result = kInvalidFileID;
|
||||
struct stat buf = {};
|
||||
if (0 == wstat(path, &buf)) {
|
||||
result = file_id_t::from_stat(buf);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
file_id_t file_id_for_path(const std::string &path) {
|
||||
file_id_t result = kInvalidFileID;
|
||||
struct stat buf = {};
|
||||
if (0 == stat(path.c_str(), &buf)) {
|
||||
result = file_id_t::from_stat(buf);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool file_id_t::operator==(const file_id_t &rhs) const { return this->compare_file_id(rhs) == 0; }
|
||||
|
||||
bool file_id_t::operator!=(const file_id_t &rhs) const { return !(*this == rhs); }
|
||||
|
|
15
src/wutil.h
15
src/wutil.h
|
@ -89,19 +89,9 @@ int lwstat(const wcstring &file_name, struct stat *buf);
|
|||
/// Wide character version of access().
|
||||
int waccess(const wcstring &file_name, int mode);
|
||||
|
||||
/// Wide character version of unlink().
|
||||
int wunlink(const wcstring &file_name);
|
||||
|
||||
/// Wide character version of perror().
|
||||
void wperror(wcharz_t s);
|
||||
|
||||
/// Wide character version of getcwd().
|
||||
wcstring wgetcwd();
|
||||
|
||||
/// Wide character version of realpath function.
|
||||
/// \returns the canonicalized path, or none if the path is invalid.
|
||||
maybe_t<wcstring> wrealpath(const wcstring &pathname);
|
||||
|
||||
/// Given an input path, "normalize" it:
|
||||
/// 1. Collapse multiple /s into a single /, except maybe at the beginning.
|
||||
/// 2. .. goes up a level.
|
||||
|
@ -130,9 +120,6 @@ const wchar_t *wgettext_ptr(const wchar_t *in);
|
|||
/// Wide character version of mkdir.
|
||||
int wmkdir(const wcstring &name, int mode);
|
||||
|
||||
/// Wide character version of rename.
|
||||
int wrename(const wcstring &oldName, const wcstring &newv);
|
||||
|
||||
/// Write a wide string to a file descriptor. This avoids doing any additional allocation.
|
||||
/// This does NOT retry on EINTR or EAGAIN, it simply returns.
|
||||
/// \return -1 on error in which case errno will have been set. In this event, the number of bytes
|
||||
|
@ -317,8 +304,6 @@ struct hash<file_id_t> {
|
|||
|
||||
file_id_t file_id_for_fd(int fd);
|
||||
file_id_t file_id_for_fd(const autoclose_fd_t &fd);
|
||||
file_id_t file_id_for_path(const wcstring &path);
|
||||
file_id_t file_id_for_path(const std::string &path);
|
||||
|
||||
extern const file_id_t kInvalidFileID;
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user