diff --git a/Makefile.in b/Makefile.in index 9320c8cee..b70dd6217 100644 --- a/Makefile.in +++ b/Makefile.in @@ -337,8 +337,7 @@ prof: user_doc: $(HDR_FILES_SRC) Doxyfile.user user_doc.head.html $(HELP_SRC) $(MAKE) doc.h $(HDR_FILES) - - doxygen Doxyfile.user - touch user_doc + - doxygen Doxyfile.user && touch user_doc # @@ -932,11 +931,12 @@ clean: rm -f $(GENERATED_INTERN_SCRIPT_FILES) rm -f tests/tmp.err tests/tmp.out tests/tmp.status tests/foo.txt rm -f $(PROGRAMS) fish_tests tokenizer_test key_reader + rm -f command_list.txt toc.txt rm -f share/config.fish etc/config.fish doc_src/index.hdr doc_src/commands.hdr rm -f fish-@PACKAGE_VERSION@.tar rm -f fish-@PACKAGE_VERSION@.tar.gz rm -f fish-@PACKAGE_VERSION@.tar.bz2 - rm -rf doc; + rm -rf doc user_doc share/man; rm -rf fish-@PACKAGE_VERSION@ rm -f $(TRANSLATIONS) test ! -d "$(XSEL)" || make -C $(XSEL) clean diff --git a/builtin_set.cpp b/builtin_set.cpp index d55421d8e..fae6e5014 100644 --- a/builtin_set.cpp +++ b/builtin_set.cpp @@ -627,7 +627,7 @@ static int builtin_set( parser_t &parser, wchar_t **argv ) if( erase ) { append_format(stderr_buffer, - _(L"%ls: Erase needs a variable name\n%ls\n"), + _(L"%ls: Erase needs a variable name\n"), argv[0] ); builtin_print_help( parser, argv[0], stderr_buffer ); diff --git a/common.cpp b/common.cpp index 0fec7fcf3..b6639e100 100644 --- a/common.cpp +++ b/common.cpp @@ -555,7 +555,7 @@ wcstring wsetlocale(int category, const wchar_t *locale) { char *lang = NULL; - if (locale && wcscmp(locale,L"")){ + if (locale){ lang = wcs2str( locale ); } char * res = setlocale(category,lang); @@ -1943,9 +1943,12 @@ void configure_thread_assertions_for_testing(void) { } /* Notice when we've forked */ -static pid_t initial_pid; +static pid_t initial_pid = 0; bool is_forked_child(void) { + /* Just bail if nobody's called setup_fork_guards - e.g. fishd */ + if (! initial_pid) return false; + bool is_child_of_fork = (getpid() != initial_pid); if (is_child_of_fork) { printf("Uh-oh: %d\n", getpid()); diff --git a/env.cpp b/env.cpp index dd44b33c5..6e6a8d741 100644 --- a/env.cpp +++ b/env.cpp @@ -901,8 +901,7 @@ int env_set(const wcstring &key, const wchar_t *val, int var_mode) } entry->val = val; - - node->env.insert(std::pair(key, entry)); + node->env[key] = entry; if( entry->exportv ) { @@ -1397,7 +1396,8 @@ static void get_exported( const env_node_t *n, std::map &h ) var_entry_t *val_entry = iter->second; if( val_entry->exportv && (val_entry->val != ENV_NULL ) ) { - h.insert(std::pair(key, val_entry->val)); + // Don't use std::map::insert here, since we need to overwrite existing values from previous scopes + h[key] = val_entry->val; } } } @@ -1455,12 +1455,11 @@ static void update_export_array_if_necessary(bool recalc) { const wcstring &key = uni.at(i); const wchar_t *val = env_universal_get( key.c_str() ); - std::map::iterator result = vals.find( key ); - if( wcscmp( val, ENV_NULL) && ( result == vals.end() ) ) - { + if (wcscmp( val, ENV_NULL)) { + // Note that std::map::insert does NOT overwrite a value already in the map, + // which we depend on here vals.insert(std::pair(key, val)); } - } std::vector local_export_buffer; diff --git a/env_universal_common.cpp b/env_universal_common.cpp index 8704cc70d..d80a4d0d1 100644 --- a/env_universal_common.cpp +++ b/env_universal_common.cpp @@ -555,7 +555,7 @@ void env_universal_common_set( const wchar_t *key, const wchar_t *val, int expor entry->val = val; env_universal_common_remove( key ); - env_universal_var.insert( std::pair(key, entry)); + env_universal_var[key] = entry; if( callback ) { callback( exportv?SET_EXPORT:SET, key, val ); diff --git a/highlight.cpp b/highlight.cpp index b74f52404..09a7666a3 100644 --- a/highlight.cpp +++ b/highlight.cpp @@ -103,6 +103,28 @@ static wcstring apply_working_directory(const wcstring &path, const wcstring &wo } } +/* Determine if the filesystem containing the given fd is case insensitive. */ +typedef std::map case_sensitivity_cache_t; +bool fs_is_case_insensitive(const wcstring &path, int fd, case_sensitivity_cache_t &case_sensitivity_cache) +{ + /* If _PC_CASE_SENSITIVE is not defined, assume case sensitive */ + bool result = false; +#ifdef _PC_CASE_SENSITIVE + /* Try the cache first */ + case_sensitivity_cache_t::iterator cache = case_sensitivity_cache.find(path); + if (cache != case_sensitivity_cache.end()) { + /* Use the cached value */ + result = cache->second; + } else { + /* Ask the system. A -1 value means error (so assume case sensitive), a 1 value means case sensitive, and a 0 value means case insensitive */ + long ret = fpathconf(fd, _PC_CASE_SENSITIVE); + result = (ret == 0); + case_sensitivity_cache[path] = result; + } +#endif + return result; +} + /* Tests whether the specified string cpath is the prefix of anything we could cd to. directories is a list of possible parent directories (typically either the working directory, or the cdpath). This does I/O! */ bool is_potential_path(const wcstring &const_path, const wcstring_list_t &directories, bool require_dir, wcstring *out_path) @@ -161,6 +183,9 @@ bool is_potential_path(const wcstring &const_path, const wcstring_list_t &direct /* Don't test the same path multiple times, which can happen if the path is absolute and the CDPATH contains multiple entries */ std::set checked_paths; + /* Keep a cache of which paths / filesystems are case sensitive */ + case_sensitivity_cache_t case_sensitivity_cache; + for (size_t wd_idx = 0; wd_idx < directories.size() && ! result; wd_idx++) { const wcstring &wd = directories.at(wd_idx); @@ -200,12 +225,23 @@ bool is_potential_path(const wcstring &const_path, const wcstring_list_t &direct // We opened the dir_name; look for a string where the base name prefixes it wcstring ent; + // Check if we're case insensitive + bool case_insensitive = fs_is_case_insensitive(dir_name, dirfd(dir), case_sensitivity_cache); + // Don't ask for the is_dir value unless we care, because it can cause extra filesystem acces */ bool is_dir = false; while (wreaddir_resolving(dir, dir_name, ent, require_dir ? &is_dir : NULL)) - { - // TODO: support doing the right thing on case-insensitive filesystems like HFS+ - if (string_prefixes_string(base_name, ent) && (! require_dir || is_dir)) + { + + /* Determine which function to call to check for prefixes */ + bool (*prefix_func)(const wcstring &, const wcstring &); + if (case_insensitive) { + prefix_func = string_prefixes_string_case_insensitive; + } else { + prefix_func = string_prefixes_string; + } + + if (prefix_func(base_name, ent) && (! require_dir || is_dir)) { result = true; if (out_path) { @@ -213,7 +249,9 @@ bool is_potential_path(const wcstring &const_path, const wcstring_list_t &direct out_path->clear(); const wcstring path_base = wdirname(const_path); - if (string_prefixes_string(path_base, const_path)) { + + + if (prefix_func(path_base, const_path)) { out_path->append(path_base); if (! string_suffixes_string(L"/", *out_path)) out_path->push_back(L'/'); diff --git a/reader.cpp b/reader.cpp index d23d8182e..62dacd15c 100644 --- a/reader.cpp +++ b/reader.cpp @@ -1089,7 +1089,7 @@ static void run_pager( const wcstring &prefix, int is_quoted, const std::vector< { prefix_esc = escape_string(prefix, 1); } - + wcstring cmd = format_string(L"fish_pager -c 3 -r 4 %ls -p %ls", // L"valgrind --track-fds=yes --log-file=pager.txt --leak-check=full ./fish_pager %d %ls", is_quoted?L"-q":L"", @@ -1607,7 +1607,7 @@ static int handle_completions( const std::vector &comp ) 0, 0 ); - len = &buff[data->buff_pos]-prefix_start+1; + len = &buff[data->buff_pos]-prefix_start; if( len <= PREFIX_MAX_LEN ) { diff --git a/screen.cpp b/screen.cpp index 2596c42ad..79b7b7d14 100644 --- a/screen.cpp +++ b/screen.cpp @@ -327,6 +327,10 @@ static int room_for_usec(struct stat *st) static void s_save_status( screen_t *s) { + // PCA Let's not do this futimes stuff, because sudo dumbly uses the + // tty's ctime as part of its tty_tickets feature + // Disabling this should fix https://github.com/fish-shell/fish-shell/issues/122 +#if 0 /* This futimes call tries to trick the system into using st_mtime as a tampering flag. This of course only works on systems where @@ -354,6 +358,7 @@ static void s_save_status( screen_t *s) */ futimes( 1, t ); futimes( 2, t ); +#endif fstat( 1, &s->prev_buff_1 ); fstat( 2, &s->prev_buff_2 ); diff --git a/share/functions/__fish_complete_command.fish b/share/functions/__fish_complete_command.fish index 8dc1d3114..983366db6 100644 --- a/share/functions/__fish_complete_command.fish +++ b/share/functions/__fish_complete_command.fish @@ -2,7 +2,11 @@ function __fish_complete_command --description 'Complete using all available com set -l ctoken (commandline -ct) switch $ctoken case '*=*' - set ctoken (echo $ctoken | sed 's/=/\n/') + # Some seds (e.g. on Mac OS X), don't support \n in the RHS + # Use a literal newline instead + # http://sed.sourceforge.net/sedfaq4.html#s4.1 + set ctoken (echo $ctoken | sed 's/=/\\ +/') printf '%s\n' $ctoken[1]=(complete -C$ctoken[2]) case '*' complete -C$ctoken diff --git a/share/functions/__fish_complete_lpr_option.fish b/share/functions/__fish_complete_lpr_option.fish index 287b13ebf..aa9d981f0 100644 --- a/share/functions/__fish_complete_lpr_option.fish +++ b/share/functions/__fish_complete_lpr_option.fish @@ -5,7 +5,11 @@ function __fish_complete_lpr_option --description 'Complete lpr option' set -l IFS = echo $optstr | read -l opt val set -l descr - for l in (lpoptions -l ^ /dev/null | grep $opt | sed 's+\(.*\)/\(.*\):\s*\(.*\)$+\2 \3+; s/ /\n/g;') + # Some seds (e.g. on Mac OS X), don't support \n in the RHS + # Use a literal newline instead + # http://sed.sourceforge.net/sedfaq4.html#s4.1 + for l in (lpoptions -l ^ /dev/null | grep $opt | sed 's+\(.*\)/\(.*\):\s*\(.*\)$+\2 \3+; s/ /\\ +/g;') if not set -q descr[1] set descr $l continue diff --git a/share/functions/__fish_print_help.fish b/share/functions/__fish_print_help.fish index b213c8811..08a70f72e 100644 --- a/share/functions/__fish_print_help.fish +++ b/share/functions/__fish_print_help.fish @@ -23,7 +23,7 @@ function __fish_print_help --description "Print help message for the specified f set -l sed_cmd -e $cmd1 -e $cmd2 -e $cmd3 # Render help output, save output into the variable 'help' - set -l help (nroff -man $__fish_datadir/man/$item.1) + set -l help (nroff -man $__fish_datadir/man/man1/$item.1) set -l lines (count $help) # Print an empty line first diff --git a/share/functions/__fish_print_make_targets.fish b/share/functions/__fish_print_make_targets.fish index c57e88713..bda806f46 100644 --- a/share/functions/__fish_print_make_targets.fish +++ b/share/functions/__fish_print_make_targets.fish @@ -1,4 +1,8 @@ function __fish_print_make_targets set files Makefile makefile GNUmakefile - sgrep -h -E '^[^#%=$[:space:]][^#%=$]*:([^=]|$)' $files | cut -d ":" -f 1 | sed -e 's/^ *//;s/ *$//;s/ */\n/g' ^/dev/null + # Some seds (e.g. on Mac OS X), don't support \n in the RHS + # Use a literal newline instead + # http://sed.sourceforge.net/sedfaq4.html#s4.1 + sgrep -h -E '^[^#%=$[:space:]][^#%=$]*:([^=]|$)' $files | cut -d ":" -f 1 | sed -e 's/^ *//;s/ *$//;s/ */\\ +/g' ^/dev/null end diff --git a/share/functions/alias.fish b/share/functions/alias.fish index cc5dab98a..25eec3ea0 100644 --- a/share/functions/alias.fish +++ b/share/functions/alias.fish @@ -17,7 +17,11 @@ function alias --description "Legacy function for creating shellscript functions echo "Fish implements aliases using functions. Use 'functions' builtin to see list of functions and 'functions function_name' to see function definition, type 'help alias' for more information." return 1 case 1 - set -l tmp (echo $argv|sed -e "s/\([^=]\)=/\1\n/") + # Some seds (e.g. on Mac OS X), don't support \n in the RHS + # Use a literal newline instead + # http://sed.sourceforge.net/sedfaq4.html#s4.1 + set -l tmp (echo $argv|sed -e "s/\([^=]\)=/\1\\ +/") set name $tmp[1] set body $tmp[2] diff --git a/share/tools/create_manpage_completions.py b/share/tools/create_manpage_completions.py index f0c814699..051a3a50c 100755 --- a/share/tools/create_manpage_completions.py +++ b/share/tools/create_manpage_completions.py @@ -753,7 +753,8 @@ def parse_and_output_man_pages(paths, output_directory, show_progress): # Pad on the right with spaces so we overwrite whatever we wrote last time padded_progress_str = progress_str.ljust(last_progress_string_length) last_progress_string_length = len(progress_str) - sys.stdout.write("\r\r{0} {1}".format(padded_progress_str, chr(27))) + sys.stdout.write("\r{0} {1}\r".format(padded_progress_str, chr(27))) + sys.stdout.flush(); try: if parse_manpage_at_path(manpage_path, output_directory): successful_count += 1