void parser_t::get_backtrace(const wcstring &src, const parse_error_list_t &errors, wcstring *output) const { assert(output != NULL); if (! errors.empty()) { const parse_error_t &err = errors.at(0); const bool is_interactive = get_is_interactive(); // Determine if we want to try to print a caret to point at the source error // The err.source_start <= src.size() check is due to the nasty way that slices work, // which is by rewriting the source (!) size_t which_line = 0; bool skip_caret = true; if (err.source_start != SOURCE_LOCATION_UNKNOWN && err.source_start <= src.size()) { // Determine which line we're on which_line = 1 + std::count(src.begin(), src.begin() + err.source_start, L'\n'); // Don't include the caret if we're interactive, this is the first line of text, and our source is at its beginning, because then it's obvious skip_caret = (is_interactive && which_line == 1 && err.source_start == 0); } wcstring prefix; const wchar_t *filename = this->current_filename(); if (filename) { if (which_line > 0) { prefix = format_string(_(L"%ls (line %lu): "), user_presentable_path(filename).c_str(), which_line); } else { prefix = format_string(_(L"%ls: "), user_presentable_path(filename).c_str()); } } else { prefix = L"fish: "; } const wcstring description = err.describe_with_prefix(src, prefix, is_interactive, skip_caret); if (! description.empty()) { output->append(description); output->push_back(L'\n'); } output->append(this->stack_trace()); } }
/** Attempts tilde expansion of the string specified, modifying it in place. */ static void expand_home_directory(wcstring &input) { const wchar_t * const in = input.c_str(); if (in[0] == HOME_DIRECTORY) { int tilde_error = 0; size_t tail_idx; wcstring home; if (in[1] == '/' || in[1] == '\0') { /* Current users home directory */ home = env_get_string(L"HOME"); tail_idx = 1; } else { /* Some other users home directory */ const wchar_t *name_end = wcschr(in, L'/'); if (name_end) { tail_idx = name_end - in; } else { tail_idx = wcslen(in); } wcstring name_str = input.substr(1, tail_idx - 1); std::string name_cstr = wcs2string(name_str); struct passwd *userinfo = getpwnam(name_cstr.c_str()); if (userinfo == NULL) { tilde_error = 1; input[0] = L'~'; } else { home = str2wcstring(userinfo->pw_dir); } } if (! tilde_error) { input.replace(input.begin(), input.begin() + tail_idx, home); } } }
bool unescape_string(wcstring &str, int escape_special) { bool success = false; wchar_t *result = unescape(str.c_str(), escape_special); if (result) { str.replace(str.begin(), str.end(), result); free(result); success = true; } return success; }
/** Remove any internal separators. Also optionally convert wildcard characters to regular equivalents. This is done to support EXPAND_SKIP_WILDCARDS. */ static void remove_internal_separator(wcstring &str, bool conv) { /* Remove all instances of INTERNAL_SEPARATOR */ str.erase(std::remove(str.begin(), str.end(), (wchar_t)INTERNAL_SEPARATOR), str.end()); /* If conv is true, replace all instances of ANY_CHAR with '?', ANY_STRING with '*', ANY_STRING_RECURSIVE with '*' */ if (conv) { for (size_t idx = 0; idx < str.size(); idx++) { switch (str.at(idx)) { case ANY_CHAR: str.at(idx) = L'?'; break; case ANY_STRING: case ANY_STRING_RECURSIVE: str.at(idx) = L'*'; break; } } } }