fish-shell/src/common.h

873 lines
32 KiB
C
Raw Normal View History

// Prototypes for various functions, mostly string utilities, that are used by most parts of fish.
#ifndef FISH_COMMON_H
#define FISH_COMMON_H
#include "config.h"
#include <errno.h>
#include <pthread.h>
#include <stdarg.h> // IWYU pragma: keep
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <wchar.h>
#include <memory>
#include <sstream>
#include <string>
2017-02-11 02:47:02 +00:00
#include <type_traits>
#include <vector>
#include "fallback.h" // IWYU pragma: keep
#include "signal.h" // IWYU pragma: keep
// Define a symbol we can use elsewhere in our code to determine if we're being built on MS Windows
// under Cygwin.
#if defined(_WIN32) || defined(_WIN64) || defined(WIN32) || defined(__CYGWIN__) || \
defined(__WIN32__)
#define OS_IS_CYGWIN
#endif
// Common string type.
typedef std::wstring wcstring;
2011-12-27 08:06:07 +00:00
typedef std::vector<wcstring> wcstring_list_t;
// Maximum number of bytes used by a single utf-8 character.
#define MAX_UTF8_BYTES 6
// Highest legal ASCII value.
#define ASCII_MAX 127u
// Highest legal 16-bit Unicode value.
#define UCS2_MAX 0xFFFFu
// Highest legal byte value.
#define BYTE_MAX 0xFFu
// Unicode BOM value.
#define UTF8_BOM_WCHAR 0xFEFFu
// Unicode replacement character.
#define REPLACEMENT_WCHAR 0xFFFDu
// Use Unicode "noncharacters" for internal characters as much as we can. This
// gives us 32 "characters" for internal use that we can guarantee should not
// appear in our input stream. See http://www.unicode.org/faq/private_use.html.
#define RESERVED_CHAR_BASE (wchar_t)0xFDD0
#define RESERVED_CHAR_END (wchar_t)0xFDF0
// Split the available noncharacter values into two ranges to ensure there are
// no conflicts among the places we use these special characters.
#define EXPAND_RESERVED_BASE RESERVED_CHAR_BASE
#define EXPAND_RESERVED_END (EXPAND_RESERVED_BASE + 16)
#define WILDCARD_RESERVED_BASE EXPAND_RESERVED_END
#define WILDCARD_RESERVED_END (WILDCARD_RESERVED_BASE + 16)
// Make sure the ranges defined above don't exceed the range for noncharacters.
// This is to make sure we didn't do something stupid in subdividing the
// Unicode range for our needs.
//#if WILDCARD_RESERVED_END > RESERVED_CHAR_END
//#error
//#endif
// These are in the Unicode private-use range. We really shouldn't use this
// range but have little choice in the matter given how our lexer/parser works.
// We can't use non-characters for these two ranges because there are only 66 of
// them and we need at least 256 + 64.
//
// If sizeof(wchar_t))==4 we could avoid using private-use chars; however, that
// would result in fish having different behavior on machines with 16 versus 32
// bit wchar_t. It's better that fish behave the same on both types of systems.
//
// Note: We don't use the highest 8 bit range (0xF800 - 0xF8FF) because we know
// of at least one use of a codepoint in that range: the Apple symbol (0xF8FF)
// on Mac OS X. See http://www.unicode.org/faq/private_use.html.
#define ENCODE_DIRECT_BASE (wchar_t)0xF600
#define ENCODE_DIRECT_END (ENCODE_DIRECT_BASE + 256)
#define INPUT_COMMON_BASE (wchar_t)0xF700
#define INPUT_COMMON_END (INPUT_COMMON_BASE + 64)
// Flags for unescape_string functions.
enum {
UNESCAPE_DEFAULT = 0, // default behavior
UNESCAPE_SPECIAL = 1 << 0, // escape special fish syntax characters like the semicolon
UNESCAPE_INCOMPLETE = 1 << 1 // allow incomplete escape sequences
};
typedef unsigned int unescape_flags_t;
// Flags for the escape_string() and escape_string() functions.
enum {
/// Escape all characters, including magic characters like the semicolon.
ESCAPE_ALL = 1 << 0,
/// Do not try to use 'simplified' quoted escapes, and do not use empty quotes as the empty
/// string.
ESCAPE_NO_QUOTED = 1 << 1,
/// Do not escape tildes.
ESCAPE_NO_TILDE = 1 << 2
};
typedef unsigned int escape_flags_t;
// Directions.
enum selection_direction_t {
// Visual directions.
direction_north,
direction_east,
direction_south,
direction_west,
2015-03-02 21:08:29 +00:00
direction_page_north,
direction_page_south,
2014-03-31 17:01:39 +00:00
// Logical directions.
direction_next,
direction_prev,
2014-03-31 17:01:39 +00:00
// Special value that means deselect.
direction_deselect
};
/// Issue a debug message with printf-style string formating and automatic line breaking. The string
/// will begin with the string \c program_name, followed by a colon and a whitespace.
///
/// Because debug is often called to tell the user about an error, before using wperror to give a
/// specific error message, debug will never ever modify the value of errno.
///
/// \param level the priority of the message. Lower number means higher priority. Messages with a
/// priority_number higher than \c debug_level will be ignored..
/// \param msg the message format string.
///
/// Example:
///
/// <code>debug( 1, L"Pi = %.3f", M_PI );</code>
///
/// will print the string 'fish: Pi = 3.141', given that debug_level is 1 or higher, and that
/// program_name is 'fish'.
void __attribute__((noinline)) debug(int level, const char *msg, ...)
__attribute__((format(printf, 2, 3)));
void __attribute__((noinline)) debug(int level, const wchar_t *msg, ...);
/// Exits without invoking destructors (via _exit), useful for code after fork.
[[noreturn]] void exit_without_destructors(int code);
/// Save the shell mode on startup so we can restore them on exit.
extern struct termios shell_modes;
/// The character to use where the text has been truncated. Is an ellipsis on unicode system and a $
/// on other systems.
2012-11-05 08:05:42 +00:00
extern wchar_t ellipsis_char;
/// Character representing an omitted newline at the end of text.
extern wchar_t omitted_newline_char;
/// The verbosity level of fish. If a call to debug has a severity level higher than \c debug_level,
/// it will not be printed.
extern int debug_level;
/// How many stack frames to show when a debug() call is made.
extern int debug_stack_frames;
/// Profiling flag. True if commands should be profiled.
extern bool g_profiling_active;
/// Name of the current program. Should be set at startup. Used by the debug function.
extern const wchar_t *program_name;
// Variants of read() and write() that ignores return values, defeating a warning.
2014-04-28 01:27:34 +00:00
void read_ignore(int fd, void *buff, size_t count);
void write_ignore(int fd, const void *buff, size_t count);
/// Set to false at run-time if it's been determined we can't trust the last modified timestamp on
/// the tty.
extern bool has_working_tty_timestamps;
/// This macro is used to check that an argument is true. It is a bit like a non-fatal form of
/// assert. Instead of exiting on failure, the current function is ended at once. The second
/// parameter is the return value of the current function on failure.
#define CHECK(arg, retval) \
if (!(arg)) { \
debug(0, "function %s called with false value for argument %s", __func__, #arg); \
bugreport(); \
show_stackframe(L'E'); \
return retval; \
}
// Pause for input, then exit the program. If supported, print a backtrace first.
// The `return` will never be run but silences oclint warnings. Especially when this is called
// from within a `switch` block. As of the time I'm writing this oclint doesn't recognize the
// `__attribute__((noreturn))` on the exit_without_destructors() function.
// TODO: we use C++11 [[noreturn]] now, does that change things?
#define FATAL_EXIT() \
{ \
char exit_read_buff; \
show_stackframe(L'E'); \
read_ignore(0, &exit_read_buff, 1); \
exit_without_destructors(1); \
}
/// Exit the program at once after emitting an error message and stack trace if possible.
/// We use our own private implementation of `assert()` for two reasons. First, some implementations
/// are subtly broken. For example, using `printf()` which can cause problems when mixed with wide
/// stdio functions and should be writing the message to stderr rather than stdout. Second, if
/// possible it is useful to provide additional context such as a stack backtrace.
#undef assert
#undef __assert
//#define assert(e) do {(void)((e) ? ((void)0) : __assert(#e, __FILE__, __LINE__)); } while(false)
#define assert(e) (e) ? ((void)0) : __assert(#e, __FILE__, __LINE__, 0)
#define assert_with_errno(e) (e) ? ((void)0) : __assert(#e, __FILE__, __LINE__, errno)
#define DIE(msg) __assert(msg, __FILE__, __LINE__, 0)
#define DIE_WITH_ERRNO(msg) __assert(msg, __FILE__, __LINE__, errno)
/// This macro is meant to be used with functions that return zero on success otherwise return an
/// errno value. Most notably the pthread family of functions which we never expect to fail.
#define DIE_ON_FAILURE(e) \
do { \
int status = e; \
if (status != 0) { \
__assert(#e, __FILE__, __LINE__, status); \
} \
} while (0)
[[noreturn]] void __assert(const char *msg, const char *file, size_t line, int error);
/// Check if signals are blocked. If so, print an error message and return from the function
/// performing this check.
#define CHECK_BLOCK(retval)
#if 0
#define CHECK_BLOCK(retval) \
if (signal_is_blocked()) { \
debug(0, "function %s called while blocking signals. ", __func__); \
bugreport(); \
show_stackframe(L'E'); \
return retval; \
}
#endif
/// Shorthand for wgettext call in situations where a C-style string is needed (e.g., fwprintf()).
#define _(wstr) wgettext(wstr).c_str()
/// Noop, used to tell xgettext that a string should be translated. Use this when a string cannot be
/// passed through wgettext() at the point where it is used. For example, when initializing a
/// static array or structure. You must pass the string through wgettext() when it is used.
/// See https://developer.gnome.org/glib/stable/glib-I18N.html#N-:CAPS
#define N_(wstr) wstr
/// Check if the specified string element is a part of the specified string list.
#define contains(str, ...) contains_internal(str, 0, __VA_ARGS__, NULL)
/// Print a stack trace to stderr.
2016-10-21 01:53:31 +00:00
void show_stackframe(const wchar_t msg_level, int frame_count = 100, int skip_levels = 0);
/// Read a line from the stream f into the string. Returns the number of bytes read or -1 on
/// failure.
///
/// If the carriage return character is encountered, it is ignored. fgetws() considers the line to
/// end if reading the file results in either a newline (L'\n') character, the null (L'\\0')
/// character or the end of file (WEOF) character.
int fgetws2(wcstring *s, FILE *f);
/// Returns a wide character string equivalent of the specified multibyte character string.
///
/// This function encodes illegal character sequences in a reversible way using the private use
/// area.
wcstring str2wcstring(const char *in);
2012-12-19 21:31:06 +00:00
wcstring str2wcstring(const char *in, size_t len);
wcstring str2wcstring(const std::string &in);
/// Returns a newly allocated multibyte character string equivalent of the specified wide character
/// string.
///
/// This function decodes illegal character sequences in a reversible way using the private use
/// area.
char *wcs2str(const wchar_t *in);
char *wcs2str(const wcstring &in);
std::string wcs2string(const wcstring &input);
/// Test if a string prefixes another. Returns true if a is a prefix of b.
bool string_prefixes_string(const wcstring &proposed_prefix, const wcstring &value);
bool string_prefixes_string(const wchar_t *proposed_prefix, const wcstring &value);
/// Test if a string is a suffix of another.
bool string_suffixes_string(const wcstring &proposed_suffix, const wcstring &value);
bool string_suffixes_string(const wchar_t *proposed_suffix, const wcstring &value);
/// Test if a string prefixes another without regard to case. Returns true if a is a prefix of b.
bool string_prefixes_string_case_insensitive(const wcstring &proposed_prefix,
const wcstring &value);
enum fuzzy_match_type_t {
// We match the string exactly: FOOBAR matches FOOBAR.
fuzzy_match_exact = 0,
2013-06-02 08:14:26 +00:00
// We match a prefix of the string: FO matches FOOBAR.
fuzzy_match_prefix,
2013-06-02 08:14:26 +00:00
// We match the string exactly, but in a case insensitive way: foobar matches FOOBAR.
fuzzy_match_case_insensitive,
2013-06-02 08:14:26 +00:00
// We match a prefix of the string, in a case insensitive way: foo matches FOOBAR.
fuzzy_match_prefix_case_insensitive,
2013-06-02 08:14:26 +00:00
// We match a substring of the string: OOBA matches FOOBAR.
fuzzy_match_substring,
2013-06-02 08:14:26 +00:00
// A subsequence match with insertions only: FBR matches FOOBAR.
fuzzy_match_subsequence_insertions_only,
2013-06-02 08:14:26 +00:00
// We don't match the string.
fuzzy_match_none
};
/// Indicates where a match type requires replacing the entire token.
static inline bool match_type_requires_full_replacement(fuzzy_match_type_t t) {
switch (t) {
case fuzzy_match_exact:
case fuzzy_match_prefix: {
return false;
}
default: { return true; }
}
}
/// Indicates where a match shares a prefix with the string it matches.
static inline bool match_type_shares_prefix(fuzzy_match_type_t t) {
switch (t) {
case fuzzy_match_exact:
case fuzzy_match_prefix:
case fuzzy_match_case_insensitive:
case fuzzy_match_prefix_case_insensitive: {
return true;
}
default: { return false; }
}
}
/// Test if string is a fuzzy match to another.
struct string_fuzzy_match_t {
enum fuzzy_match_type_t type;
2013-06-02 08:14:26 +00:00
// Strength of the match. The value depends on the type. Lower is stronger.
size_t match_distance_first;
size_t match_distance_second;
2013-06-02 08:14:26 +00:00
// Constructor.
explicit string_fuzzy_match_t(enum fuzzy_match_type_t t, size_t distance_first = 0,
size_t distance_second = 0);
2013-06-02 08:14:26 +00:00
// Return -1, 0, 1 if this match is (respectively) better than, equal to, or worse than rhs.
int compare(const string_fuzzy_match_t &rhs) const;
};
/// Compute a fuzzy match for a string. If maximum_match is not fuzzy_match_none, limit the type to
/// matches at or below that type.
string_fuzzy_match_t string_fuzzy_match_string(const wcstring &string,
const wcstring &match_against,
fuzzy_match_type_t limit_type = fuzzy_match_none);
/// Test if a list contains a string using a linear search.
bool list_contains_string(const wcstring_list_t &list, const wcstring &str);
// Check if we are running in the test mode, where we should suppress error output
#define TESTS_PROGRAM_NAME L"(ignore)"
bool should_suppress_stderr_for_tests();
void assert_is_main_thread(const char *who);
#define ASSERT_IS_MAIN_THREAD_TRAMPOLINE(x) assert_is_main_thread(x)
#define ASSERT_IS_MAIN_THREAD() ASSERT_IS_MAIN_THREAD_TRAMPOLINE(__FUNCTION__)
void assert_is_background_thread(const char *who);
#define ASSERT_IS_BACKGROUND_THREAD_TRAMPOLINE(x) assert_is_background_thread(x)
#define ASSERT_IS_BACKGROUND_THREAD() ASSERT_IS_BACKGROUND_THREAD_TRAMPOLINE(__FUNCTION__)
/// Useful macro for asserting that a lock is locked. This doesn't check whether this thread locked
/// it, which it would be nice if it did, but here it is anyways.
void assert_is_locked(void *mutex, const char *who, const char *caller);
#define ASSERT_IS_LOCKED(x) assert_is_locked((void *)(&x), #x, __FUNCTION__)
/// 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);
/// Our crappier versions of debug which is guaranteed to not allocate any memory, or do anything
/// other than call write(). This is useful after a call to fork() with threads.
void debug_safe(int level, const char *msg, const char *param1 = NULL, const char *param2 = NULL,
const char *param3 = NULL, const char *param4 = NULL, const char *param5 = NULL,
const char *param6 = NULL, const char *param7 = NULL, const char *param8 = NULL,
const char *param9 = NULL, const char *param10 = NULL, const char *param11 = NULL,
const char *param12 = NULL);
/// Writes out a long safely.
void format_long_safe(char buff[64], long val);
void format_long_safe(wchar_t buff[64], long val);
/// "Narrows" a wide character string. This just grabs any ASCII characters and trunactes.
void narrow_string_safe(char buff[64], const wchar_t *s);
template <typename T>
T from_string(const wcstring &x) {
T result;
std::wstringstream stream(x);
stream >> result;
return result;
}
template <typename T>
T from_string(const std::string &x) {
2012-03-05 18:44:08 +00:00
T result = T();
std::stringstream stream(x);
stream >> result;
return result;
}
template <typename T>
wcstring to_string(const T &x) {
2012-02-02 00:27:14 +00:00
std::wstringstream stream;
stream << x;
return stream.str();
}
// wstringstream is a huge memory pig. Let's provide some specializations where we can.
template <>
inline wcstring to_string(const long &x) {
wchar_t buff[128];
format_long_safe(buff, x);
return wcstring(buff);
}
template <>
inline bool from_string(const std::string &x) {
return !x.empty() && strchr("YTyt1", x.at(0));
2012-03-05 18:44:08 +00:00
}
template <>
inline bool from_string(const wcstring &x) {
return !x.empty() && wcschr(L"YTyt1", x.at(0));
2012-03-05 18:44:08 +00:00
}
template <>
inline wcstring to_string(const int &x) {
return to_string(static_cast<long>(x));
}
wchar_t **make_null_terminated_array(const wcstring_list_t &lst);
char **make_null_terminated_array(const std::vector<std::string> &lst);
// Helper class for managing a null-terminated array of null-terminated strings (of some char type).
template <typename CharType_t>
class null_terminated_array_t {
CharType_t **array;
// No assignment or copying.
void operator=(null_terminated_array_t rhs);
null_terminated_array_t(const null_terminated_array_t &);
typedef std::vector<std::basic_string<CharType_t> > string_list_t;
size_t size() const {
size_t len = 0;
if (array != NULL) {
while (array[len] != NULL) {
len++;
}
}
return len;
}
void free(void) {
::free((void *)array);
array = NULL;
}
public:
null_terminated_array_t() : array(NULL) {}
explicit null_terminated_array_t(const string_list_t &argv)
: array(make_null_terminated_array(argv)) {}
~null_terminated_array_t() { this->free(); }
void set(const string_list_t &argv) {
this->free();
this->array = make_null_terminated_array(argv);
}
const CharType_t *const *get() const { return array; }
void clear() { this->free(); }
};
// Helper function to convert from a null_terminated_array_t<wchar_t> to a
// null_terminated_array_t<char_t>.
void convert_wide_array_to_narrow(const null_terminated_array_t<wchar_t> &arr,
null_terminated_array_t<char> *output);
class mutex_lock_t {
public:
pthread_mutex_t mutex;
mutex_lock_t() { DIE_ON_FAILURE(pthread_mutex_init(&mutex, NULL)); }
~mutex_lock_t() { DIE_ON_FAILURE(pthread_mutex_destroy(&mutex)); }
};
// Basic scoped lock class.
class scoped_lock {
pthread_mutex_t *lock_obj;
bool locked;
// No copying.
scoped_lock &operator=(const scoped_lock &) = delete;
2017-02-08 05:52:35 +00:00
scoped_lock(const scoped_lock &) = delete;
public:
scoped_lock(scoped_lock &&rhs) : lock_obj(rhs.lock_obj), locked(rhs.locked) {
// we acquire any locked state
// ensure the rhs doesn't try to unlock
rhs.locked = false;
}
void lock(void);
void unlock(void);
explicit scoped_lock(pthread_mutex_t &mutex);
explicit scoped_lock(mutex_lock_t &lock);
~scoped_lock();
};
class rwlock_t {
public:
pthread_rwlock_t rwlock;
rwlock_t() { DIE_ON_FAILURE(pthread_rwlock_init(&rwlock, NULL)); }
~rwlock_t() { DIE_ON_FAILURE(pthread_rwlock_destroy(&rwlock)); }
rwlock_t &operator=(const rwlock_t &) = delete;
2017-02-08 05:52:35 +00:00
rwlock_t(const rwlock_t &) = delete;
};
// Scoped lock class for rwlocks.
class scoped_rwlock {
pthread_rwlock_t *rwlock_obj;
bool locked;
bool locked_shared;
// No copying.
scoped_rwlock &operator=(const scoped_lock &) = delete;
explicit scoped_rwlock(const scoped_lock &) = delete;
public:
void lock(void);
void unlock(void);
void lock_shared(void);
void unlock_shared(void);
// Upgrade shared lock to exclusive. Equivalent to `lock.unlock_shared(); lock.lock();`.
void upgrade(void);
explicit scoped_rwlock(pthread_rwlock_t &rwlock, bool shared = false);
explicit scoped_rwlock(rwlock_t &rwlock, bool shared = false);
~scoped_rwlock();
};
// An object wrapping a scoped lock and a value
// This is returned from owning_lock.acquire()
// Sample usage:
// owning_lock<string> locked_name;
// acquired_lock<string> name = name.acquire();
// name.value = "derp"
//
// Or for simple cases:
// name.acquire().value = "derp"
//
2017-02-08 05:52:35 +00:00
template <typename DATA>
class acquired_lock {
scoped_lock lock;
2017-02-08 05:52:35 +00:00
acquired_lock(mutex_lock_t &lk, DATA *v) : lock(lk), value(*v) {}
2017-02-08 05:52:35 +00:00
template <typename T>
friend class owning_lock;
2017-02-08 05:52:35 +00:00
public:
// No copying, move only
acquired_lock &operator=(const acquired_lock &) = delete;
acquired_lock(const acquired_lock &) = delete;
acquired_lock(acquired_lock &&) = default;
acquired_lock &operator=(acquired_lock &&) = default;
DATA &value;
};
// A lock that owns a piece of data
// Access to the data is only provided by taking the lock
2017-02-08 05:52:35 +00:00
template <typename DATA>
class owning_lock {
// No copying
owning_lock &operator=(const scoped_lock &) = delete;
owning_lock(const scoped_lock &) = delete;
owning_lock(owning_lock &&) = default;
owning_lock &operator=(owning_lock &&) = default;
mutex_lock_t lock;
DATA data;
2017-02-08 05:52:35 +00:00
public:
2017-02-14 02:48:59 +00:00
owning_lock(DATA &&d) : data(std::move(d)) {}
owning_lock() : data() {}
2017-02-08 05:52:35 +00:00
acquired_lock<DATA> acquire() { return {lock, &data}; }
};
/// A scoped manager to save the current value of some variable, and optionally set it to a new
/// value. On destruction it restores the variable to its old value.
///
/// This can be handy when there are multiple code paths to exit a block.
template <typename T>
class scoped_push {
T *const ref;
T saved_value;
bool restored;
public:
explicit scoped_push(T *r) : ref(r), saved_value(*r), restored(false) {}
scoped_push(T *r, T new_value) : ref(r), restored(false) {
saved_value = std::move(*ref);
*ref = std::move(new_value);
}
~scoped_push() { restore(); }
void restore() {
if (!restored) {
*ref = std::move(saved_value);
restored = true;
}
}
};
/// Wrapper around wcstok.
class wcstokenizer {
wchar_t *buffer, *str, *state;
const wcstring sep;
// No copying.
wcstokenizer &operator=(const wcstokenizer &);
wcstokenizer(const wcstokenizer &);
public:
wcstokenizer(const wcstring &s, const wcstring &separator);
bool next(wcstring &result);
~wcstokenizer();
};
/// Appends a path component, with a / if necessary.
void append_path_component(wcstring &path, const wcstring &component);
wcstring format_string(const wchar_t *format, ...);
wcstring vformat_string(const wchar_t *format, va_list va_orig);
void append_format(wcstring &str, const wchar_t *format, ...);
void append_formatv(wcstring &str, const wchar_t *format, va_list ap);
#ifdef __cpp_lib_make_unique
using std::make_unique;
#else
/// make_unique implementation
template <typename T, typename... Args>
std::unique_ptr<T> make_unique(Args &&... args) {
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
#endif
/// This functions returns the end of the quoted substring beginning at \c in. The type of quoting
/// character is detemrined by examining \c in. Returns 0 on error.
///
/// \param in the position of the opening quote.
wchar_t *quote_end(const wchar_t *in);
/// A call to this function will reset the error counter. Some functions print out non-critical
/// error messages. These should check the error_count before, and skip printing the message if
/// MAX_ERROR_COUNT messages have been printed. The error_reset() should be called after each
/// interactive command executes, to allow new messages to be printed.
void error_reset();
/// This function should be called after calling `setlocale()` to perform fish specific locale
/// initialization.
void fish_setlocale();
/// Checks if \c needle is included in the list of strings specified. A warning is printed if needle
/// is zero.
///
/// \param needle the string to search for in the list.
///
/// \return zero if needle is not found, of if needle is null, non-zero otherwise.
__sentinel bool contains_internal(const wchar_t *needle, int vararg_handle, ...);
__sentinel bool contains_internal(const wcstring &needle, int vararg_handle, ...);
/// Call read while blocking the SIGCHLD signal. Should only be called if you _know_ there is data
/// available for reading, or the program will hang until there is data.
long read_blocked(int fd, void *buf, size_t count);
/// Loop a write request while failure is non-critical. Return -1 and set errno in case of critical
/// 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
/// \param flags Flags to control the escaping
/// \return The escaped string
wcstring escape_string(const wchar_t *in, escape_flags_t flags);
wcstring escape_string(const wcstring &in, escape_flags_t flags);
/// 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 0 on error.
size_t read_unquoted_escape(const wchar_t *input, wcstring *result, bool allow_incomplete,
bool unescape_special);
Merge new string builtin This adds the new builtin 'string' which supports various string manipulation and matching algorithms, including PCRE based regular expressions. Fixes #2296 Squashed commit of the following: commit 4c3eaeb6e57d76463e9683c327142b0aeafb92b8 Author: ridiculousfish <corydoras@ridiculousfish.com> Date: Sat Sep 12 12:51:30 2015 -0700 Remove testdata and doc dirs from pcre2 source commit b2a8b4b50f2398b204fb72cfe4b5ba77ece2e1ab Merge: 11c8a47 7974aab Author: ridiculousfish <corydoras@ridiculousfish.com> Date: Sat Sep 12 12:32:40 2015 -0700 Merge branch 'string' of git://github.com/msteed/fish-shell into string-test commit 7974aab6d367f999f1140ab34c2535cef5cf3b00 Author: Michael Steed <msteed@saltstack.com> Date: Fri Sep 11 13:00:02 2015 -0600 build pcre2 lib only, no docs commit eb20b43d2d96b7e6d24618158ce71078de83c40b Merge: 1a09e70 5f519cb Author: Michael Steed <msteed68@gmail.com> Date: Thu Sep 10 20:00:47 2015 -0600 Merge branch 'string' of github.com:msteed/fish-shell into string commit 1a09e709d028393c9e9e6dc9a84278f399a15f3d Author: Michael Steed <msteed68@gmail.com> Date: Thu Sep 10 19:58:24 2015 -0600 rebase on master & address the fallout commit a0ec9772cd1a0a548a501a7633be05dab4e5ee46 Author: Michael Steed <msteed68@gmail.com> Date: Thu Sep 10 19:26:45 2015 -0600 use fish's wildcard_match() for glob matching commit 64c25a01e3f7234f220ba13545cf658a7492b1a4 Author: Michael Steed <msteed68@gmail.com> Date: Thu Aug 27 08:19:23 2015 -0600 some fixes from review - string_get_arg_stdin(): simplify and don't discard the argument when the trailing newline is absent - fix calls to pcre2 for e.g. string match -r -a 'a*' 'b' - correct test for args coming from stdin commit ece7f35ec5f4093763627d68d671b6c0c876896d Author: Michael Steed <msteed68@gmail.com> Date: Sat Aug 22 19:35:56 2015 -0600 fixes from review - Makefile.in: restore iwyu target - regex_replacer_t::replace_matches(): correct size passed to realloc() commit 9ff7477a926c4572e26171cab3cd42f8086be678 Author: Michael Steed <msteed68@gmail.com> Date: Thu Aug 20 13:08:33 2015 -0600 Minor doc improvements commit baf4e096b22dde3063b85b833795eb570d660ba7 Author: Michael Steed <msteed68@gmail.com> Date: Wed Aug 19 18:29:02 2015 -0600 another attempt to fix the ci build commit 896a2c2b279a419747bea26102229fbe84534a6f Author: Michael Steed <msteed68@gmail.com> Date: Wed Aug 19 18:03:49 2015 -0600 Updates after review comments - make match/replace without -a operate on the first match on each argument - use different exit codes for "no operation performed" and errors, as grep does - refactor regex compile code - use human-friendly error messages from pcre2 - improve error handling & reporting elsewhere - add a few tests - make some doc fixes - some simplification & cleanup - fix ci build failure (I hope) commit efd47dcbda2ca247d58bee56a7774cd75a1062fd Author: Michael Steed <msteed68@gmail.com> Date: Wed Aug 12 00:26:07 2015 -0600 fix dependencies for parallel make commit ed0850e2db467362066a3d94e3ececd17c1756cd Author: Michael Steed <msteed68@gmail.com> Date: Tue Aug 11 23:37:22 2015 -0600 Add missing pcre2 files + .gitignore commit 9492e7a7e929c03554336be1ddf80ca6b37f53c5 Author: Michael Steed <msteed68@gmail.com> Date: Tue Aug 11 22:44:05 2015 -0600 add pcre2-10.20 and update license.hdr commit 1a60b933718feb20c0bf7c9e257b8e495014ea1b Author: Michael Steed <msteed68@gmail.com> Date: Tue Aug 11 22:41:19 2015 -0600 add string builtin files - string builtin source, tests, & docs - changes to configure.ac & Makefile.in commit 5f519cb2a2c05213e0a88a7add7af288bc1c1352 Author: Michael Steed <msteed68@gmail.com> Date: Thu Sep 10 19:26:45 2015 -0600 use fish's wildcard_match() for glob matching commit 2ecd24f79500879e2de5bdf1b4c19dd44fc6ac85 Author: Michael Steed <msteed68@gmail.com> Date: Thu Aug 27 08:19:23 2015 -0600 some fixes from review - string_get_arg_stdin(): simplify and don't discard the argument when the trailing newline is absent - fix calls to pcre2 for e.g. string match -r -a 'a*' 'b' - correct test for args coming from stdin commit 45b777e4dc85c05cd4a186f4bdcae543c21aaf08 Author: Michael Steed <msteed68@gmail.com> Date: Sat Aug 22 19:35:56 2015 -0600 fixes from review - Makefile.in: restore iwyu target - regex_replacer_t::replace_matches(): correct size passed to realloc() commit 981cbb6ddf742a5fe8881af916e7b870b7e6422a Author: Michael Steed <msteed68@gmail.com> Date: Thu Aug 20 13:08:33 2015 -0600 Minor doc improvements commit ddb6a2a8fdb6aa31aad41e80d5481bb32c6ed8ff Author: Michael Steed <msteed68@gmail.com> Date: Wed Aug 19 18:29:02 2015 -0600 another attempt to fix the ci build commit 1e34e3191b028162863d263e9868052f75194aa5 Author: Michael Steed <msteed68@gmail.com> Date: Wed Aug 19 18:03:49 2015 -0600 Updates after review comments - make match/replace without -a operate on the first match on each argument - use different exit codes for "no operation performed" and errors, as grep does - refactor regex compile code - use human-friendly error messages from pcre2 - improve error handling & reporting elsewhere - add a few tests - make some doc fixes - some simplification & cleanup - fix ci build failure (I hope) commit 34232e152df17a3cfbf0a094dd51d148a4f04e6f Author: Michael Steed <msteed68@gmail.com> Date: Wed Aug 12 00:26:07 2015 -0600 fix dependencies for parallel make commit 00d7e781697f53454beb91c1d0fc4b2d28d6e034 Author: Michael Steed <msteed68@gmail.com> Date: Tue Aug 11 23:37:22 2015 -0600 Add missing pcre2 files + .gitignore commit 4498aa5f576e09634f7f619443e74d2f33c108e4 Author: Michael Steed <msteed68@gmail.com> Date: Tue Aug 11 22:44:05 2015 -0600 add pcre2-10.20 and update license.hdr commit 290c58c72e22db644ccf6fa9088051644980ed0a Author: Michael Steed <msteed68@gmail.com> Date: Tue Aug 11 22:41:19 2015 -0600 add string builtin files - string builtin source, tests, & docs - changes to configure.ac & Makefile.in
2015-09-12 19:59:40 +00:00
/// Unescapes a string in-place. A true result indicates the string was unescaped, a false result
/// indicates the string was unmodified.
bool unescape_string_in_place(wcstring *str, unescape_flags_t escape_special);
/// Unescapes a string, returning the unescaped value by reference. On failure, the output is set to
/// an empty string.
bool unescape_string(const wchar_t *input, wcstring *output, unescape_flags_t escape_special);
bool unescape_string(const wcstring &input, wcstring *output, unescape_flags_t escape_special);
/// Returns the width of the terminal window, so that not all functions that use these values
/// continually have to keep track of it separately.
///
/// Only works if common_handle_winch is registered to handle winch signals.
int common_get_width();
/// Returns the height of the terminal window, so that not all functions that use these values
/// continually have to keep track of it separatly.
///
/// Only works if common_handle_winch is registered to handle winch signals.
int common_get_height();
/// Handle a window change event by looking up the new window size and saving it in an internal
/// variable used by common_get_wisth and common_get_height().
void common_handle_winch(int signal);
/// Write the given paragraph of output, redoing linebreaks to fit the current screen.
wcstring reformat_for_screen(const wcstring &msg);
/// Tokenize the specified string into the specified wcstring_list_t.
///
/// \param val the input string. The contents of this string is not changed.
/// \param out the list in which to place the elements.
void tokenize_variable_array(const wcstring &val, wcstring_list_t &out);
/// Make sure the specified direcotry exists. If needed, try to create it and any currently not
/// existing parent directories.
///
/// \return 0 if, at the time of function return the directory exists, -1 otherwise.
int create_directory(const wcstring &d);
/// Print a short message about how to file a bug report to stderr.
void bugreport();
/// 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.
double timef();
/// Call the following function early in main to set the main thread. This is our replacement for
/// pthread_main_np().
void set_main_thread();
bool is_main_thread();
/// Configures thread assertions for testing.
void configure_thread_assertions_for_testing();
/// Set up a guard to complain if we try to do certain things (like take a lock) after calling fork.
void setup_fork_guards(void);
/// Save the value of tcgetpgrp so we can restore it on exit.
void save_term_foreground_process_group(void);
void restore_term_foreground_process_group(void);
/// Return whether we are the child of a fork.
bool is_forked_child(void);
void assert_is_not_forked_child(const char *who);
#define ASSERT_IS_NOT_FORKED_CHILD_TRAMPOLINE(x) assert_is_not_forked_child(x)
#define ASSERT_IS_NOT_FORKED_CHILD() ASSERT_IS_NOT_FORKED_CHILD_TRAMPOLINE(__FUNCTION__)
extern "C" {
__attribute__((noinline)) void debug_thread_error(void);
}
/// Converts from wide char to digit in the specified base. If d is not a valid digit in the
/// specified base, return -1.
long convert_digit(wchar_t d, int base);
/// This is a macro that can be used to silence "unused parameter" warnings from the compiler for
/// functions which need to accept parameters they do not use because they need to be compatible
/// with an interface. It's similar to the Python idiom of doing `_ = expr` at the top of a
/// function in the same situation.
#define UNUSED(expr) \
do { \
(void)(expr); \
} while (0)
// Return true if the character is in a range reserved for fish's private use.
bool fish_reserved_codepoint(wchar_t c);
/// Used for constructing mappings between enums and strings. The resulting array must be sorted
/// according to the `str` member since str_to_enum() does a binary search. Also the last entry must
/// have NULL for the `str` member and the default value for `val` to be returned if the string
/// isn't found.
template <typename T>
struct enum_map {
T val;
const wchar_t *const str;
};
/// Given a string return the matching enum. Return the sentinal enum if no match is made. The map
/// must be sorted by the `str` member. A binary search is twice as fast as a linear search with 16
/// elements in the map.
template <typename T>
static T str_to_enum(const wchar_t *name, const enum_map<T> map[], int len) {
// Ignore the sentinel value when searching as it is the "not found" value.
size_t left = 0, right = len - 1;
while (left < right) {
size_t mid = left + (right - left) / 2;
int cmp = wcscmp(name, map[mid].str);
if (cmp < 0) {
right = mid; // name was smaller than mid
} else if (cmp > 0) {
left = mid + 1; // name was larger than mid
} else {
return map[mid].val; // found it
}
}
return map[len - 1].val; // return the sentinel value
}
/// Given an enum return the matching string.
template <typename T>
static const wchar_t *enum_to_str(T enum_val, const enum_map<T> map[]) {
for (const enum_map<T> *entry = map; entry->str; entry++) {
if (enum_val == entry->val) {
return entry->str;
}
}
return NULL;
};
void redirect_tty_output();
// Minimum allowed terminal size and default size if the detected size is not reasonable.
#define MIN_TERM_COL 20
#define MIN_TERM_ROW 2
#define DFLT_TERM_COL 80
#define DFLT_TERM_ROW 24
#define DFLT_TERM_COL_STR L"80"
#define DFLT_TERM_ROW_STR L"24"
void invalidate_termsize(bool invalidate_vars = false);
struct winsize get_current_winsize();
#endif