Commits

JanKanis committed 4428212 Merge

Merge remote-tracking branch 'origin/master'

  • Participants
  • Parent commits 30392bf, d5af389

Comments (0)

Files changed (26)

 Makefile
 autom4te.cache/
 command_list.txt
+confdefs.h
 config.h
 config.h.in
 config.log
 by running the command 'make uninstall' in the source directory of
 your previous fish installation.
 
-Next, if you have downloaded a fresh copy of the darcs repository of
+Next, if you have downloaded a fresh copy of the git repository of
 fish, you need to run the 'autoconf' command.
 
 Then, use following commands to compile fish:
 Local install procedure
 =======================
 
-If you have downloaded the darcs repository of fish, you need to run
+If you have downloaded the git repository of fish, you need to run
 autoconf to generate the configure script.
 
 To install fish in your own home directory (typically as non-root),
 
 	3). Create a file doc_src/NAME.txt, containing the manual for the builtin in Doxygen-format. Check the other builtin manuals for proper syntax.
 
-	4). Use 'darcs add doc_src/NAME.txt' to start tracking changes to the documentation file.
+	4). Use 'git add doc_src/NAME.txt' to start tracking changes to the documentation file.
 
 */
 
         stderr_buffer.append(L": ");
     }
     char *err = strerror(errno);
-    wchar_t *werr = str2wcs(err);
-    if (werr)
+    if (err)
     {
+        const wcstring werr = str2wcstring(err);
         stderr_buffer.append(werr);
         stderr_buffer.push_back(L'\n');
-        free(werr);
     }
 }
 
             return STATUS_BUILTIN_ERROR;
         }
 
-        fn = wrealpath(argv[1], 0);
+        fn = wrealpath(argv[1], NULL);
 
         if (!fn)
         {
 #include "fallback.cpp"
 
 
+static wchar_t *str2wcs_internal(const char *in, const size_t in_len, wchar_t *out);
 
 struct termios shell_modes;
 
 
         c = getwc(f);
 
-        if (errno == EILSEQ)
+        if (errno == EILSEQ || errno == EINTR)
         {
             continue;
         }
     }
 }
 
-wchar_t *str2wcs(const char *in)
+static wchar_t *str2wcs(const char *in)
 {
-    wchar_t *out;
     size_t len = strlen(in);
-
-    out = (wchar_t *)malloc(sizeof(wchar_t)*(len+1));
-
+    wchar_t *out = (wchar_t *)malloc(sizeof(wchar_t)*(len+1));
     if (!out)
     {
         DIE_MEM();
     }
 
-    return str2wcs_internal(in, out);
+    return str2wcs_internal(in, strlen(in), out);
+}
+
+wcstring str2wcstring(const char *in, size_t len)
+{
+    assert(in != NULL);
+    std::string tmp_str(in, len);
+    wchar_t *tmp = str2wcs(tmp_str.c_str());
+    wcstring result = tmp;
+    free(tmp);
+    return result;
 }
 
 wcstring str2wcstring(const char *in)
 {
+    assert(in != NULL);
     wchar_t *tmp = str2wcs(in);
     wcstring result = tmp;
     free(tmp);
     return result;
 }
 
-wchar_t *str2wcs_internal(const char *in, wchar_t *out)
+/**
+   Converts the narrow character string \c in into it's wide
+   equivalent, stored in \c out. \c out must have enough space to fit
+   the entire string.
+
+   The string may contain embedded nulls.
+
+   This function encodes illegal character sequences in a reversible
+   way using the private use area.
+*/
+static wchar_t *str2wcs_internal(const char *in, const size_t in_len, wchar_t *out)
 {
     size_t res=0;
     size_t in_pos=0;
     size_t out_pos = 0;
     mbstate_t state;
-    size_t len;
 
     CHECK(in, 0);
     CHECK(out, 0);
 
-    len = strlen(in);
-
     memset(&state, 0, sizeof(state));
 
     while (in[in_pos])
     {
-        res = mbrtowc(&out[out_pos], &in[in_pos], len-in_pos, &state);
+        res = mbrtowc(&out[out_pos], &in[in_pos], in_len-in_pos, &state);
 
         if (((out[out_pos] >= ENCODE_DIRECT_BASE) &&
                 (out[out_pos] < ENCODE_DIRECT_BASE+256)) ||
 {
     std::string result;
     result.reserve(input.size());
-    
+
     mbstate_t state;
     memset(&state, 0, sizeof(state));
-    
+
     char converted[MB_LEN_MAX + 1];
-    
+
     for (size_t i=0; i < input.size(); i++)
     {
         wchar_t wc = input[i];
             }
         }
     }
-    
+
     return result;
 }
 
 */
 int fgetws2(wcstring *s, FILE *f);
 
-/**
-   Returns a newly allocated 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.
-*/
-wchar_t *str2wcs(const char *in);
 
 /**
- Returns a newly allocated wide character string equivalent of the
+ 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);
+wcstring str2wcstring(const char *in, size_t len);
 wcstring str2wcstring(const std::string &in);
 
 /**
-   Converts the narrow character string \c in into it's wide
-   equivalent, stored in \c out. \c out must have enough space to fit
-   the entire string.
-
-   This function encodes illegal character sequences in a reversible
-   way using the private use area.
-*/
-wchar_t *str2wcs_internal(const char *in, wchar_t *out);
-
-/**
    Returns a newly allocated multibyte character string equivalent of
    the specified wide character string
 

File complete.cpp

             while ((pw=getpwent()) != 0)
             {
                 double current_time = timef();
-                wchar_t *pw_name;
 
                 if (current_time - start_time > 0.2)
                 {
                     return 1;
                 }
 
-                pw_name = str2wcs(pw->pw_name);
-
-                if (pw_name)
+                if (pw->pw_name)
                 {
+                    const wcstring pw_name_str = str2wcstring(pw->pw_name);
+                    const wchar_t *pw_name = pw_name_str.c_str();
                     if (wcsncmp(user_name, pw_name, name_len)==0)
                     {
                         wcstring desc = format_string(COMPLETE_USER_DESC, pw_name);
                                           COMPLETE_NO_CASE | COMPLETE_DONT_ESCAPE | COMPLETE_NO_SPACE);
                         res=1;
                     }
-                    free(pw_name);
                 }
             }
             endpwent();
     if (env_get_string(L"USER").missing())
     {
         struct passwd *pw = getpwuid(getuid());
-        wchar_t *unam = str2wcs(pw->pw_name);
-        env_set(L"USER", unam, ENV_GLOBAL);
-        free(unam);
+        if (pw->pw_name != NULL)
+        {
+            const wcstring wide_name = str2wcstring(pw->pw_name);
+            env_set(L"USER", NULL, ENV_GLOBAL);
+        }
     }
 
     if (env_get_string(L"HOME").missing())
         const env_var_t unam = env_get_string(L"USER");
         char *unam_narrow = wcs2str(unam.c_str());
         struct passwd *pw = getpwnam(unam_narrow);
-        wchar_t *dir = str2wcs(pw->pw_dir);
-        env_set(L"HOME", dir, ENV_GLOBAL);
-        free(dir);
+        if (pw->pw_dir != NULL)
+        {
+            const wcstring dir = str2wcstring(pw->pw_dir);
+            env_set(L"HOME", dir.c_str(), ENV_GLOBAL);
+        }
         free(unam_narrow);
     }
 
 }
 
 // Some variables should not be arrays. This used to be handled by a startup script, but we'd like to get down to 0 forks for startup, so handle it here.
-static bool variable_can_be_array(const wchar_t *key)
+static bool variable_can_be_array(const wcstring &key)
 {
-    if (! wcscmp(key, L"DISPLAY"))
+    if (key == L"DISPLAY")
     {
         return false;
     }
 void env_init(const struct config_paths_t *paths /* or NULL */)
 {
     char **p;
-    struct passwd *pw;
-    wchar_t *uname;
-    wchar_t *version;
 
     /*
       env_read_only variables can not be altered directly by the user
     */
     for (p=environ?environ:__environ; p && *p; p++)
     {
-        wchar_t *key, *val;
-
-        key = str2wcs(*p);
-
-        if (!key)
+        const wcstring key_and_val = str2wcstring(*p); //like foo=bar
+        size_t eql = key_and_val.find(L'=');
+        if (eql == wcstring::npos)
         {
-            continue;
-        }
-
-        val = wcschr(key, L'=');
-
-        if (val == 0)
-        {
-            env_set(key, L"", ENV_EXPORT);
+            // no equals found
+            env_set(key_and_val, L"", ENV_EXPORT);
         }
         else
         {
-            *val = L'\0';
-            val++;
-
-            //fwprintf( stderr, L"Set $%ls to %ls\n", key, val );
+            wcstring key = key_and_val.substr(0, eql);
+            wcstring val = key_and_val.substr(eql + 1);
             if (variable_can_be_array(val))
             {
-                for (size_t i=0; val[i] != L'\0'; i++)
-                {
-                    if (val[i] == L':')
-                    {
-                        val[i] = ARRAY_SEP;
-                    }
-                }
+                std::replace(val.begin(), val.end(), L':', ARRAY_SEP);
             }
 
-            env_set(key, val, ENV_EXPORT | ENV_GLOBAL);
+            env_set(key, val.c_str(), ENV_EXPORT | ENV_GLOBAL);
         }
-        free(key);
     }
 
     /* Set the given paths in the environment, if we have any */
     /*
       Set up the USER variable
     */
-    pw = getpwuid(getuid());
-    if (pw)
+    const struct passwd *pw = getpwuid(getuid());
+    if (pw && pw->pw_name)
     {
-        uname = str2wcs(pw->pw_name);
-        env_set(L"USER", uname, ENV_GLOBAL | ENV_EXPORT);
-        free(uname);
+        const wcstring uname = str2wcstring(pw->pw_name);
+        env_set(L"USER", uname.c_str(), ENV_GLOBAL | ENV_EXPORT);
     }
 
     /*
       Set up the version variables
     */
-    version = str2wcs(PACKAGE_VERSION);
-    env_set(L"version", version, ENV_GLOBAL);
-    env_set(L"FISH_VERSION", version, ENV_GLOBAL);
-    free(version);
+    wcstring version = str2wcstring(PACKAGE_VERSION);
+    env_set(L"version", version.c_str(), ENV_GLOBAL);
+    env_set(L"FISH_VERSION", version.c_str(), ENV_GLOBAL);
 
     const env_var_t fishd_dir_wstr = env_get_string(L"FISHD_SOCKET_DIR");
     const env_var_t user_dir_wstr = env_get_string(L"USER");
   Functions for executing a program.
 
   Some of the code in this file is based on code from the Glibc
-  manual, though I the changes performed have been massive.
+  manual, though the changes performed have been massive.
 */
 
 #include "config.h"
                                 /*
                                   FIXME:
 
-                                  When
-                                  requesting
-                                  that
-                                  stdin
-                                  be
-                                  closed,
-                                  we
-                                  really
-                                  don't
-                                  do
-                                  anything. How
-                                  should
-                                  this
-                                  be
+                                  When requesting that stdin be closed, we
+                                  really don't do anything. How should this be
                                   handled?
                                  */
                                 builtin_stdin = -1;
 
                 /* Get the strings we'll write before we fork (since they call malloc) */
                 const wcstring &out = get_stdout_buffer(), &err = get_stderr_buffer();
-                
+
                 /* These strings may contain embedded nulls, so don't treat them as C strings */
                 const std::string outbuff_str = wcs2string(out);
                 const char *outbuff = outbuff_str.data();
                 size_t outbuff_len = outbuff_str.size();
-                
+
                 const std::string errbuff_str = wcs2string(err);
                 const char *errbuff = errbuff_str.data();
                 size_t errbuff_len = errbuff_str.size();
 static int exec_subshell_internal(const wcstring &cmd, wcstring_list_t *lst)
 {
     ASSERT_IS_MAIN_THREAD();
-    char *begin, *end;
-    char z=0;
     int prev_subshell = is_subshell;
     int status, prev_status;
     io_data_t *io_buffer;
     proc_set_last_status(prev_status);
 
     is_subshell = prev_subshell;
-
-    io_buffer->out_buffer_append(&z, 1);
-
-    begin=end=io_buffer->out_buffer_ptr();
-
-    if (lst)
+    
+    if (lst != NULL)
     {
-        while (1)
+        const char *begin = io_buffer->out_buffer_ptr();
+        const char *end = begin + io_buffer->out_buffer_size();
+        const char *cursor = begin;
+        while (cursor < end)
         {
-            if (*end == 0)
+            // Look for the next separator
+            const char *stop = (const char *)memchr(cursor, sep, end - cursor);
+            bool hit_separator = (stop != NULL);
+            if (! hit_separator)
             {
-                if (begin != end)
-                {
-                    wchar_t *el = str2wcs(begin);
-                    if (el)
-                    {
-                        lst->push_back(el);
-
-                        free(el);
-                    }
-                    else
-                    {
-                        debug(2, L"Got null string on line %d of file %s", __LINE__, __FILE__);
-                    }
-                }
-                io_buffer_destroy(io_buffer);
-
-                return status;
-            }
-            else if (*end == sep)
-            {
-                wchar_t *el;
-                *end=0;
-                el = str2wcs(begin);
-                if (el)
-                {
-                    lst->push_back(el);
-
-                    free(el);
-                }
-                else
-                {
-                    debug(2, L"Got null string on line %d of file %s", __LINE__, __FILE__);
-                }
-                begin = end+1;
+                // If it's not found, just use the end
+                stop = end;
             }
-            end++;
+            // Stop now points at the first character we do not want to copy)
+            const wcstring wc = str2wcstring(cursor, stop - cursor);
+            lst->push_back(wc);
+            
+            // If we hit a separator, skip over it; otherwise we're at the end
+            cursor = stop + (hit_separator ? 1 : 0);
         }
     }
-
+    
     io_buffer_destroy(io_buffer);
-
     return status;
 }
 
         if ((cmdfile=wfopen(path + L"/cmdline", "r")))
         {
             wcstring full_command_line;
-            signal_block();
             fgetws2(&full_command_line, cmdfile);
-            signal_unblock();
 
             /* The command line needs to be escaped */
             cmd = tok_first(full_command_line.c_str());
 };
 
 /** Character for separating two array elements. We use 30, i.e. the ascii record separator since that seems logical. */
-#define ARRAY_SEP 0x1e
+#define ARRAY_SEP ((wchar_t)(0x1e))
 
 /** String containing the character for separating two array elements */
 #define ARRAY_SEP_STR L"\x1e"
     const io_chain_t empty_ios;
     if (read_init(paths))
     {
-        if (cmd != 0)
+        if (cmd != NULL)
         {
-            wchar_t *cmd_wcs = str2wcs(cmd);
+            const wcstring cmd_wcs = str2wcstring(cmd);
             res = parser.eval(cmd_wcs, empty_ios, TOP);
-            free(cmd_wcs);
             reader_exit(0, 0);
         }
         else
                 char *file = *(argv+(my_optind++));
                 int i;
                 int fd;
-                wchar_t *rel_filename, *abs_filename;
 
 
                 if ((fd = open(file, O_RDONLY)) == -1)
                     env_set(L"argv", sb.c_str(), 0);
                 }
 
-                rel_filename = str2wcs(file);
-                abs_filename = wrealpath(rel_filename, 0);
+                const wcstring rel_filename = str2wcstring(file);
+                const wchar_t *abs_filename = wrealpath(rel_filename, NULL);
 
                 if (!abs_filename)
                 {
-                    abs_filename = wcsdup(rel_filename);
+                    abs_filename = wcsdup(rel_filename.c_str());
                 }
 
                 reader_push_current_filename(intern(abs_filename));
-                free(rel_filename);
-                free(abs_filename);
+                free((void *)abs_filename);
 
                 res = reader_read(fd, empty_ios);
 

File fish_pager.cpp

                              int *width,
                              int row_start,
                              int row_stop,
-                             wchar_t *prefix,
+                             const wchar_t *prefix,
                              int is_quoted,
                              const std::vector<comp_t *> &lst)
 {
 */
 
 static int completion_try_print(int cols,
-                                wchar_t *prefix,
+                                const wchar_t *prefix,
                                 int is_quoted,
                                 std::vector<comp_t *> &lst)
 {
     term = getenv("TERM");
     if (term)
     {
-        wchar_t *wterm = str2wcs(term);
+        wcstring wterm = str2wcstring(term);
         output_set_term(wterm);
-        free(wterm);
     }
 
     /* Infer term256 support */
 {
     std::vector<char> buffer;
     int c;
-    wchar_t *wcs;
 
     while (!feof(file))
     {
         if (! buffer.empty())
         {
             buffer.push_back(0);
-
-            wcs = str2wcs(&buffer.at(0));
-            if (wcs)
+            wcstring wcs = str2wcstring(&buffer.at(0));
+            if (unescape_string(wcs, false))
             {
-                wcstring tmp = wcs;
-                if (unescape_string(tmp, 0))
-                {
-                    comp.push_back(tmp);
-                }
-                free(wcs);
+                comp.push_back(wcs);
             }
         }
     }
     int i;
     int is_quoted=0;
     wcstring_list_t comp;
-    wchar_t *prefix = 0;
+    wcstring prefix;
 
     int mangle_descriptors = 0;
     int result_fd = -1;
 
                 case 'p':
                 {
-                    prefix = str2wcs(optarg);
+                    prefix = str2wcstring(optarg);
                     break;
                 }
 
             exit(1);
         }
 
-        if (!prefix)
-        {
-            prefix = wcsdup(L"");
-        }
-
-
     }
     else
     {
         {
             mangle_descriptors = 1;
 
-            prefix = str2wcs(argv[2]);
+            prefix = str2wcstring(argv[2]);
             is_quoted = strcmp("1", argv[1])==0;
 
             if (argc > 3)
 
     mangle_descriptions(comp);
 
-    if (wcscmp(prefix, L"-") == 0)
+    if (prefix == L"-")
         join_completions(comp);
 
-    std::vector<comp_t *> completions = mangle_completions(comp, prefix);
+    std::vector<comp_t *> completions = mangle_completions(comp, prefix.c_str());
 
     /**
        Try to print the completions. Start by trying to print the
     */
     for (i = PAGER_MAX_COLS; i>0; i--)
     {
-        switch (completion_try_print(i, prefix, is_quoted, completions))
+        switch (completion_try_print(i, prefix.c_str(), is_quoted, completions))
         {
 
             case PAGER_RETRY:
         }
     }
 
-    free(prefix);
-
     fwprintf(out_file, L"%ls", out_buff.c_str());
     if (is_ca_mode)
     {

File fish_tests.cpp

 
     for (i=0; i<ESCAPE_TEST_COUNT; i++)
     {
-        wchar_t *w;
         const char *o, *n;
 
         char c;
         sb.push_back(c);
 
         o = &sb.at(0);
-        w = str2wcs(o);
-        n = wcs2str(w);
+        const wcstring w = str2wcstring(o);
+        n = wcs2str(w.c_str());
 
-        if (!o || !w || !n)
+        if (!o || !n)
         {
-            err(L"Line %d - Conversion cycle of string %s produced null pointer on %s", __LINE__, o, w?L"str2wcs":L"wcs2str");
+            err(L"Line %d - Conversion cycle of string %s produced null pointer on %s", __LINE__, o, L"wcs2str");
         }
 
         if (strcmp(o, n))
         {
             err(L"Line %d - %d: Conversion cycle of string %s produced different string %s", __LINE__, i, o, n);
         }
-        free(w);
         free((void *)n);
 
     }
+}
+
+/* Verify correct behavior with embedded nulls */
+static void test_convert_nulls(void)
+{
+    return;
+    say(L"Testing embedded nulls in string conversion");
+    const wchar_t in[] = L"AAA\0BBB";
+    const size_t in_len = (sizeof in / sizeof *in) - 1;
+    const wcstring in_str = wcstring(in, in_len);
+    std::string out_str = wcs2string(in_str);
+    if (out_str.size() != in_len)
+    {
+        err(L"Embedded nulls mishandled in wcs2string");
+    }
+    for (size_t i=0; i < in_len; i++)
+    {
+        if (in[i] != out_str.at(i))
+        {
+            err(L"Embedded nulls mishandled in wcs2string at index %lu", (unsigned long)i);
+        }
+    }
+
+    wcstring out_wstr = str2wcstring(out_str);
+    if (out_wstr.size() != in_len)
+    {
+        err(L"Embedded nulls mishandled in str2wcstring");
+    }
+    for (size_t i=0; i < in_len; i++)
+    {
+        if (in[i] != out_wstr.at(i))
+        {
+            err(L"Embedded nulls mishandled in str2wcstring at index %lu", (unsigned long)i);
+        }
+    }
 
 }
 
     test_format();
     test_escape();
     test_convert();
+    test_convert_nulls();
     test_tok();
     test_fork();
     test_parser();
     free(nkey);
     if (nres)
     {
-        return str2wcs(nres);
+        wcstring tmp = str2wcstring(nres);
+        return wcsdup(tmp.c_str());
     }
     else
     {
     }
     const env_var_t term = env_get_string(L"TERM");
     assert(! term.missing());
-    output_set_term(term.c_str());
+    output_set_term(term);
 
     input_terminfo_init();
 
     return result;
 }
 
-void output_set_term(const wchar_t *term)
+void output_set_term(const wcstring &term)
 {
-    current_term = term;
+    current_term.assign(term);
 }
 
 const wchar_t *output_get_term()
 int (*output_get_writer())(char) ;
 
 /** Set the terminal name */
-void output_set_term(const wchar_t *term);
+void output_set_term(const wcstring &term);
 
 /** Return the terminal name */
 const wchar_t *output_get_term();
    Print error message to string if an error has occured while parsing
 
    \param target the buffer to write to
-   \param prefix: The string token to prefix the ech line with. Usually the name of the command trying to parse something.
+   \param prefix: The string token to prefix the each line with. Usually the name of the command trying to parse something.
 */
 void parser_t::print_errors(wcstring &target, const wchar_t *prefix)
 {
         buff.append(L"\n");
 
         /*
-          Stop recursing at event handler. No reason to belive that
+          Stop recursing at event handler. No reason to believe that
           any other code is relevant.
 
           It might make sense in the future to continue printing the
 /**
    Calculates the on-screen width of the specified substring of the
    specified string. This function takes into account the width and
-   allignment of the tab character, but other wise behaves like
+   alignment of the tab character, but other wise behaves like
    repeatedly calling wcwidth.
 */
 static int printed_width(const wchar_t *str, int len)
                 tok_next(tok);
 
                 /*
-                  Don't do anything on failiure. parse_job will notice
+                  Don't do anything on failure. parse_job will notice
                   the error flag and report any errors for us
                 */
                 parse_job(p->next, j, tok);
                         job_t *j,
                         tokenizer_t *tok)
 {
-    std::vector<completion_t> args; // The list that will become the argc array for the program
+    std::vector<completion_t> args; // The list that will become the argv array for the program
     int use_function = 1;   // May functions be considered when checking what action this command represents
     int use_builtin = 1;    // May builtins be considered when checking what action this command represents
     int use_command = 1;    // May commands be considered when checking what action this command represents
 
    \param j the job to test
 
-   \return 1 if buffers were avaialble, zero otherwise
+   \return 1 if buffers were available, zero otherwise
 */
 static int select_try(job_t *j)
 {
 }
 
 /**
-   Returns contol of the terminal to the shell, and saves the terminal
+   Returns control of the terminal to the shell, and saves the terminal
    attribute state to the job, so that we can restore the terminal
    ownership to the job at a later time .
 */
 last search position. All search results are saved in the list
 'search_prev'. When the user searches forward, i.e. presses Alt-down,
 the list is consulted for previous search result, and subsequent
-backwards searches are also handled by consultiung the list up until
+backwards searches are also handled by consulting the list up until
 the end of the list is reached, at which point regular searching will
 commence.
 
 /**
    The maximum number of characters to read from the keyboard without
    repainting. Note that this readahead will only occur if new
-   characters are avaialble for reading, fish will never block for
+   characters are available for reading, fish will never block for
    more input without repainting.
 */
 #define READAHEAD_MAX 256
  */
 #define NO_SEARCH 0
 /**
-   History search mode. This value means that we are perforing a line
+   History search mode. This value means that we are performing a line
    history search.
  */
 #define LINE_SEARCH 1
 /**
-   History search mode. This value means that we are perforing a token
+   History search mode. This value means that we are performing a token
    history search.
  */
 #define TOKEN_SEARCH 2
      */
     bool repaint_needed;
 
-    /** Whether the a screen reset is needed after a repaint. */
+    /** Whether a screen reset is needed after a repaint. */
     bool screen_reset_needed;
 
     /** Constructor */
 }
 
 
-/** Remove any duplicate completions in the list. This relies on the list first beeing sorted. */
+/** Remove any duplicate completions in the list. This relies on the list first being sorted. */
 static void remove_duplicates(std::vector<completion_t> &l)
 {
     l.erase(std::unique(l.begin(), l.end()), l.end());
       as that of a virtual terminal, we assume it supports setting the
       title. If we recognise it as that of a console, we assume it
       does not support setting the title. Otherwise we check the
-      ttyname and see if we belive it is a virtual terminal.
+      ttyname and see if we believe it is a virtual terminal.
 
       One situation in which this breaks down is with screen, since
       screen supports setting the terminal title if the underlying
     if (data->buff_pos <= 0)
         return;
 
-    /* Fake composed character sequences by continuning to delete until we delete a character of width at least 1. */
+    /* Fake composed character sequences by continuing to delete until we delete a character of width at least 1. */
     int width;
     do
     {
     int nil=0;
     out->out_buffer_append((char *)&nil, 1);
 
-    wchar_t *tmp;
-    wchar_t *str = str2wcs(out->out_buffer_ptr());
-
-    if (str)
+    const char *outbuff = out->out_buffer_ptr();
+    if (outbuff)
     {
-        for (tmp = str + wcslen(str)-1; tmp >= str; tmp--)
+        const wcstring str = str2wcstring(outbuff);
+        size_t idx = str.size();
+        while (idx--)
         {
-            input_unreadch(*tmp);
+            input_unreadch(str.at(idx));
         }
-        free(str);
     }
 
-
     io_buffer_destroy(out);
     io_buffer_destroy(in);
 }
     in_stream = fdopen(des, "r");
     if (in_stream != 0)
     {
-        wchar_t *str;
-        size_t acc_used;
-
         while (!feof(in_stream))
         {
             char buff[4096];
 
             acc.insert(acc.end(), buff, buff + c);
         }
-        acc.push_back(0);
-        acc_used = acc.size();
-        str = str2wcs(&acc.at(0));
+
+        const wcstring str = str2wcstring(&acc.at(0), acc.size());
         acc.clear();
 
         if (fclose(in_stream))
             res = 1;
         }
 
-        if (str)
+        wcstring sb;
+        if (! parser.test(str.c_str(), 0, &sb, L"fish"))
         {
-            wcstring sb;
-            if (! parser.test(str, 0, &sb, L"fish"))
-            {
-                parser.eval(str, io, TOP);
-            }
-            else
-            {
-                fwprintf(stderr, L"%ls", sb.c_str());
-                res = 1;
-            }
-            free(str);
+            parser.eval(str, io, TOP);
         }
         else
         {
-            if (acc_used > 1)
-            {
-                debug(1,
-                      _(L"Could not convert input. Read %d bytes."),
-                      acc_used-1);
-            }
-            else
-            {
-                debug(1,
-                      _(L"Could not read input stream"));
-            }
-            res=1;
+            fwprintf(stderr, L"%ls", sb.c_str());
+            res = 1;
         }
-
     }
     else
     {

File share/completions/bind.fish

 
-complete -c bind -s a -l all --description 'Show unavaliable key bindings/erase all bindings'
+complete -c bind -s a -l all --description 'Show unavailable key bindings/erase all bindings'
 complete -c bind -s e -l erase --description 'Erase mode'
 complete -c bind -s f -l function-names --description 'Print names of available functions'
 complete -c bind -s h -l help --description "Display help and exit"

File share/completions/help.fish

 #
 
 if test -f "$__fish_help_dir/commands.html"
-	for i in case (sed -n < $__fish_help_dir/commands.html -e "s/.*<h2><a class=\"anchor\" name=\"\([^\"]*\)\">.*/\1/p")
+        for i in case (sed -n < $__fish_help_dir/commands.html -e "s/.*<h[12]><a class=\"anchor\" name=\"\([^\"]*\)\">.*/\1/p")
 		complete -c help -x -a $i --description "Help for the specified command"
 	end
 end

File share/completions/yum.fish

 complete -c yum -n '__fish_use_subcommand' -xa 'update upgrade' --description "Update specified packages (defaults to all packages)"
 complete -c yum -n '__fish_use_subcommand' -xa check-update --description "Print list of available updates"
 complete -c yum -n '__fish_use_subcommand' -xa 'remove erase' --description "Remove the specified packages and packages that depend on them"
-complete -c yum -n '__fish_use_subcommand' -xa list --description "List avaialble packages"
-complete -c yum -n '__fish_use_subcommand' -xa info --description "Describe avaialble packages"
+complete -c yum -n '__fish_use_subcommand' -xa list --description "List available packages"
+complete -c yum -n '__fish_use_subcommand' -xa info --description "Describe available packages"
 complete -c yum -n '__fish_use_subcommand' -xa 'provides whatprovides' --description "Find package providing a feature or file"
 complete -c yum -n '__fish_use_subcommand' -xa search --description "find packages matching description regexp"
 complete -c yum -n '__fish_use_subcommand' -xa clean --description "Clean up cache directory"

File share/functions/__fish_complete_man.fish

 		set section $section"[^)]*"
 
 		# Do the actual search
-		apropos (commandline -ct) | sgrep \^(commandline -ct) | sed -n -e 's/\([^ ]*\).*(\('$section'\)) *- */\1'\t'\2: /p'
+		apropos (commandline -ct) ^/dev/null | sgrep \^(commandline -ct) | sed -n -e 's/\([^ ]*\).*(\('$section'\)) *- */\1'\t'\2: /p'
 	end
 end
 

File share/functions/help.fish

 		# documentation.  It's a bit of a hack, since it relies on the
 		# Doxygen markup format to never change.
 
-		case (sed -n 's/.*<h2><a class="anchor" \(id\|name\)="\([^"]*\)">.*/\2/p' $__fish_help_dir/commands.html)
+                case (sed -n 's/.*<h[12]><a class="anchor" \(id\|name\)="\([^"]*\)">.*/\2/p' $__fish_help_dir/commands.html)
 			set fish_help_page "commands.html\#$fish_help_item"
 		case $help_topics
 			set fish_help_page "index.html\#$fish_help_item"
 
 wchar_t *wrealpath(const wcstring &pathname, wchar_t *resolved_path)
 {
-    cstring tmp = wcs2string(pathname);
-    char *narrow_res = realpath(tmp.c_str(), 0);
-    wchar_t *res;
+    cstring narrow_path = wcs2string(pathname);
+    char *narrow_res = realpath(narrow_path.c_str(), NULL);
 
     if (!narrow_res)
-        return 0;
+        return NULL;
 
+    wchar_t *res;
+    wcstring wide_res = str2wcstring(narrow_res);
     if (resolved_path)
     {
-        wchar_t *tmp2 = str2wcs(narrow_res);
-        wcslcpy(resolved_path, tmp2, PATH_MAX);
-        free(tmp2);
+        wcslcpy(resolved_path, wide_res.c_str(), PATH_MAX);
         res = resolved_path;
     }
     else
     {
-        res = str2wcs(narrow_res);
+        res = wcsdup(wide_res.c_str());
     }
 
     free(narrow_res);