[package] kernel: Move CONFIG_CRYPTO_HW to crypto-core
[openwrt.git] / package / busybox / patches / 000-upstream-lineedit.patch
1 --- a/libbb/lineedit.c
2 +++ b/libbb/lineedit.c
3 @@ -156,7 +156,6 @@ struct lineedit_statics {
4  
5         /* Formerly these were big buffers on stack: */
6  #if ENABLE_FEATURE_TAB_COMPLETION
7 -       char exe_n_cwd_tab_completion__dirbuf[MAX_LINELEN];
8         char input_tab__matchBuf[MAX_LINELEN];
9         int16_t find_match__int_buf[MAX_LINELEN + 1]; /* need to have 9 bits at least */
10         int16_t find_match__pos_buf[MAX_LINELEN + 1];
11 @@ -235,6 +234,8 @@ static unsigned save_string(char *dst, u
12         while (dstpos < maxsize) {
13                 wchar_t wc;
14                 int n = srcpos;
15 +
16 +               /* Convert up to 1st invalid byte (or up to end) */
17                 while ((wc = command_ps[srcpos]) != 0
18                     && !unicode_is_raw_byte(wc)
19                 ) {
20 @@ -247,6 +248,7 @@ static unsigned save_string(char *dst, u
21                 dstpos += n;
22                 if (wc == 0) /* usually is */
23                         break;
24 +
25                 /* We do have invalid byte here! */
26                 command_ps[srcpos] = wc; /* restore it */
27                 srcpos++;
28 @@ -608,53 +610,56 @@ static void add_match(char *matched)
29  }
30  
31  #if ENABLE_FEATURE_USERNAME_COMPLETION
32 -static void username_tab_completion(char *ud, char *with_shash_flg)
33 +/* Replace "~user/..." with "/homedir/...".
34 + * The parameter is malloced, free it or return it
35 + * unchanged if no user is matched.
36 + */
37 +static char *username_path_completion(char *ud)
38  {
39         struct passwd *entry;
40 +       char *tilde_name = ud;
41 +       char *home = NULL;
42 +
43 +       ud++; /* skip ~ */
44 +       if (*ud == '/') {       /* "~/..." */
45 +               home = home_pwd_buf;
46 +       } else {
47 +               /* "~user/..." */
48 +               ud = strchr(ud, '/');
49 +               *ud = '\0';           /* "~user" */
50 +               entry = getpwnam(tilde_name + 1);
51 +               *ud = '/';            /* restore "~user/..." */
52 +               if (entry)
53 +                       home = entry->pw_dir;
54 +       }
55 +       if (home) {
56 +               ud = concat_path_file(home, ud);
57 +               free(tilde_name);
58 +               tilde_name = ud;
59 +       }
60 +       return tilde_name;
61 +}
62 +
63 +/* ~use<tab> - find all users with this prefix */
64 +static NOINLINE void username_completion(const char *ud)
65 +{
66 +       /* Using _r function to avoid pulling in static buffers */
67 +       char line_buff[256];
68 +       struct passwd pwd;
69 +       struct passwd *result;
70         int userlen;
71  
72 -       ud++;                           /* ~user/... to user/... */
73 +       ud++; /* skip ~ */
74         userlen = strlen(ud);
75  
76 -       if (with_shash_flg) {           /* "~/..." or "~user/..." */
77 -               char *sav_ud = ud - 1;
78 -               char *home = NULL;
79 -
80 -               if (*ud == '/') {       /* "~/..."     */
81 -                       home = home_pwd_buf;
82 -               } else {
83 -                       /* "~user/..." */
84 -                       char *temp;
85 -                       temp = strchr(ud, '/');
86 -                       *temp = '\0';           /* ~user\0 */
87 -                       entry = getpwnam(ud);
88 -                       *temp = '/';            /* restore ~user/... */
89 -                       ud = temp;
90 -                       if (entry)
91 -                               home = entry->pw_dir;
92 -               }
93 -               if (home) {
94 -                       if ((userlen + strlen(home) + 1) < MAX_LINELEN) {
95 -                               /* /home/user/... */
96 -                               sprintf(sav_ud, "%s%s", home, ud);
97 -                       }
98 +       setpwent();
99 +       while (!getpwent_r(&pwd, line_buff, sizeof(line_buff), &result)) {
100 +               /* Null usernames should result in all users as possible completions. */
101 +               if (/*!userlen || */ strncmp(ud, pwd.pw_name, userlen) == 0) {
102 +                       add_match(xasprintf("~%s/", pwd.pw_name));
103                 }
104 -       } else {
105 -               /* "~[^/]*" */
106 -               /* Using _r function to avoid pulling in static buffers */
107 -               char line_buff[256];
108 -               struct passwd pwd;
109 -               struct passwd *result;
110 -
111 -               setpwent();
112 -               while (!getpwent_r(&pwd, line_buff, sizeof(line_buff), &result)) {
113 -                       /* Null usernames should result in all users as possible completions. */
114 -                       if (/*!userlen || */ strncmp(ud, pwd.pw_name, userlen) == 0) {
115 -                               add_match(xasprintf("~%s/", pwd.pw_name));
116 -                       }
117 -               }
118 -               endpwent();
119         }
120 +       endpwent();
121  }
122  #endif  /* FEATURE_COMMAND_USERNAME_COMPLETION */
123  
124 @@ -664,22 +669,19 @@ enum {
125         FIND_FILE_ONLY = 2,
126  };
127  
128 -static int path_parse(char ***p, int flags)
129 +static int path_parse(char ***p)
130  {
131         int npth;
132         const char *pth;
133         char *tmp;
134         char **res;
135  
136 -       /* if not setenv PATH variable, to search cur dir "." */
137 -       if (flags != FIND_EXE_ONLY)
138 -               return 1;
139 -
140         if (state->flags & WITH_PATH_LOOKUP)
141                 pth = state->path_lookup;
142         else
143                 pth = getenv("PATH");
144 -       /* PATH=<empty> or PATH=:<empty> */
145 +
146 +       /* PATH="" or PATH=":"? */
147         if (!pth || !pth[0] || LONE_CHAR(pth, ':'))
148                 return 1;
149  
150 @@ -689,12 +691,13 @@ static int path_parse(char ***p, int fla
151                 tmp = strchr(tmp, ':');
152                 if (!tmp)
153                         break;
154 -               if (*++tmp == '\0')
155 +               tmp++;
156 +               if (*tmp == '\0')
157                         break;  /* :<empty> */
158                 npth++;
159         }
160  
161 -       res = xmalloc(npth * sizeof(char*));
162 +       *p = res = xmalloc(npth * sizeof(res[0]));
163         res[0] = tmp = xstrdup(pth);
164         npth = 1;
165         while (1) {
166 @@ -706,100 +709,96 @@ static int path_parse(char ***p, int fla
167                         break; /* :<empty> */
168                 res[npth++] = tmp;
169         }
170 -       *p = res;
171         return npth;
172  }
173  
174  static void exe_n_cwd_tab_completion(char *command, int type)
175  {
176 -       DIR *dir;
177 -       struct dirent *next;
178 -       struct stat st;
179         char *path1[1];
180         char **paths = path1;
181         int npaths;
182         int i;
183 -       char *found;
184 -       char *pfind = strrchr(command, '/');
185 -/*     char dirbuf[MAX_LINELEN]; */
186 -#define dirbuf (S.exe_n_cwd_tab_completion__dirbuf)
187 +       char *pfind;
188 +       char *dirbuf = NULL;
189  
190         npaths = 1;
191         path1[0] = (char*)".";
192  
193 -       if (pfind == NULL) {
194 -               /* no dir, if flags==EXE_ONLY - get paths, else "." */
195 -               npaths = path_parse(&paths, type);
196 +       pfind = strrchr(command, '/');
197 +       if (!pfind) {
198 +               if (type == FIND_EXE_ONLY)
199 +                       npaths = path_parse(&paths);
200                 pfind = command;
201         } else {
202 +               /* point to 'l' in "..../last_component" */
203 +               pfind++;
204                 /* dirbuf = ".../.../.../" */
205 -               safe_strncpy(dirbuf, command, (pfind - command) + 2);
206 +               dirbuf = xstrndup(command, pfind - command);
207  #if ENABLE_FEATURE_USERNAME_COMPLETION
208                 if (dirbuf[0] == '~')   /* ~/... or ~user/... */
209 -                       username_tab_completion(dirbuf, dirbuf);
210 +                       dirbuf = username_path_completion(dirbuf);
211  #endif
212 -               paths[0] = dirbuf;
213 -               /* point to 'l' in "..../last_component" */
214 -               pfind++;
215 +               path1[0] = dirbuf;
216         }
217  
218         for (i = 0; i < npaths; i++) {
219 +               DIR *dir;
220 +               struct dirent *next;
221 +               struct stat st;
222 +               char *found;
223 +
224                 dir = opendir(paths[i]);
225                 if (!dir)
226                         continue; /* don't print an error */
227  
228                 while ((next = readdir(dir)) != NULL) {
229 -                       int len1;
230 -                       const char *str_found = next->d_name;
231 +                       const char *name_found = next->d_name;
232  
233 -                       /* matched? */
234 -                       if (strncmp(str_found, pfind, strlen(pfind)))
235 +                       /* .../<tab>: bash 3.2.0 shows dotfiles, but not . and .. */
236 +                       if (!pfind[0] && DOT_OR_DOTDOT(name_found))
237                                 continue;
238 -                       /* not see .name without .match */
239 -                       if (*str_found == '.' && *pfind == '\0') {
240 -                               if (NOT_LONE_CHAR(paths[i], '/') || str_found[1])
241 -                                       continue;
242 -                               str_found = ""; /* only "/" */
243 -                       }
244 -                       found = concat_path_file(paths[i], str_found);
245 -                       /* hmm, remove in progress? */
246 +                       /* match? */
247 +                       if (strncmp(name_found, pfind, strlen(pfind)) != 0)
248 +                               continue; /* no */
249 +
250 +                       found = concat_path_file(paths[i], name_found);
251                         /* NB: stat() first so that we see is it a directory;
252                          * but if that fails, use lstat() so that
253                          * we still match dangling links */
254                         if (stat(found, &st) && lstat(found, &st))
255 -                               goto cont;
256 -                       /* find with dirs? */
257 -                       if (paths[i] != dirbuf)
258 -                               strcpy(found, next->d_name); /* only name */
259 +                               goto cont; /* hmm, remove in progress? */
260  
261 -                       len1 = strlen(found);
262 -                       found = xrealloc(found, len1 + 2);
263 -                       found[len1] = '\0';
264 -                       found[len1+1] = '\0';
265 +                       /* save only name if we scan PATH */
266 +                       if (paths[i] != dirbuf)
267 +                               strcpy(found, name_found);
268  
269                         if (S_ISDIR(st.st_mode)) {
270 +                               unsigned len1 = strlen(found);
271                                 /* name is a directory */
272                                 if (found[len1-1] != '/') {
273 +                                       found = xrealloc(found, len1 + 2);
274                                         found[len1] = '/';
275 +                                       found[len1 + 1] = '\0';
276                                 }
277                         } else {
278 -                               /* not put found file if search only dirs for cd */
279 +                               /* skip files if looking for dirs only (example: cd) */
280                                 if (type == FIND_DIR_ONLY)
281                                         goto cont;
282                         }
283 -                       /* Add it to the list */
284 +                       /* add it to the list */
285                         add_match(found);
286                         continue;
287   cont:
288                         free(found);
289                 }
290                 closedir(dir);
291 -       }
292 +       } /* for every path */
293 +
294         if (paths != path1) {
295                 free(paths[0]); /* allocated memory is only in first member */
296                 free(paths);
297         }
298 -#undef dirbuf
299 +       free(dirbuf);
300  }
301  
302  /* QUOT is used on elements of int_buf[], which are bytes,
303 @@ -812,15 +811,20 @@ static void exe_n_cwd_tab_completion(cha
304  /* is must be <= in */
305  static void collapse_pos(int is, int in)
306  {
307 -       memmove(int_buf+is, int_buf+in, (MAX_LINELEN+1-in)*sizeof(int_buf[0]));
308 -       memmove(pos_buf+is, pos_buf+in, (MAX_LINELEN+1-in)*sizeof(pos_buf[0]));
309 +       memmove(int_buf+is, int_buf+in, (MAX_LINELEN+1-in) * sizeof(int_buf[0]));
310 +       memmove(pos_buf+is, pos_buf+in, (MAX_LINELEN+1-in) * sizeof(pos_buf[0]));
311  }
312 -static NOINLINE int find_match(char *matchBuf, int *len_with_quotes)
313 +/* On entry, matchBuf contains everything up to cursor at the moment <tab>
314 + * was pressed. This function looks at it, figures out what part of it
315 + * constitutes the command/file/directory prefix to use for completion,
316 + * and rewrites matchBuf to contain only that part.
317 + */
318 +static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes)
319  {
320         int i, j;
321         int command_mode;
322         int c, c2;
323 -/*     Were local, but it uses too much stack */
324 +/*     Were local, but it used too much stack */
325  /*     int16_t int_buf[MAX_LINELEN + 1]; */
326  /*     int16_t pos_buf[MAX_LINELEN + 1]; */
327  
328 @@ -860,22 +864,23 @@ static NOINLINE int find_match(char *mat
329         }
330  
331         /* skip commands with arguments if line has commands delimiters */
332 -       /* ';' ';;' '&' '|' '&&' '||' but `>&' `<&' `>|' */
333 +       /* ';' ';;' '&' '|' '&&' '||' but '>&' '<&' '>|' */
334         for (i = 0; int_buf[i]; i++) {
335 +               int n;
336                 c = int_buf[i];
337                 c2 = int_buf[i + 1];
338                 j = i ? int_buf[i - 1] : -1;
339 -               command_mode = 0;
340 +               n = 0;
341                 if (c == ';' || c == '&' || c == '|') {
342 -                       command_mode = 1 + (c == c2);
343 +                       n = 1 + (c == c2);
344                         if (c == '&') {
345                                 if (j == '>' || j == '<')
346 -                                       command_mode = 0;
347 +                                       n = 0;
348                         } else if (c == '|' && j == '>')
349 -                               command_mode = 0;
350 +                               n = 0;
351                 }
352 -               if (command_mode) {
353 -                       collapse_pos(0, i + command_mode);
354 +               if (n) {
355 +                       collapse_pos(0, i + n);
356                         i = -1;  /* hack incremet */
357                 }
358         }
359 @@ -943,8 +948,8 @@ static NOINLINE int find_match(char *mat
360                         }
361                 }
362         }
363 -       for (i = 0; int_buf[i]; i++)
364 -               /* "strlen" */;
365 +       for (i = 0; int_buf[i]; i++) /* quasi-strlen(int_buf) */
366 +               continue;
367         /* find last word */
368         for (--i; i >= 0; i--) {
369                 c = int_buf[i];
370 @@ -955,7 +960,7 @@ static NOINLINE int find_match(char *mat
371         }
372         /* skip first not quoted '\'' or '"' */
373         for (i = 0; int_buf[i] == '\'' || int_buf[i] == '"'; i++)
374 -               /*skip*/;
375 +               continue;
376         /* collapse quote or unquote // or /~ */
377         while ((int_buf[i] & ~QUOT) == '/'
378          && ((int_buf[i+1] & ~QUOT) == '/' || (int_buf[i+1] & ~QUOT) == '~')
379 @@ -1058,13 +1063,20 @@ static void input_tab(smallint *lastWasT
380  
381                 /* Make a local copy of the string --
382                  * up to the position of the cursor */
383 +#if !ENABLE_UNICODE_SUPPORT
384                 save_string(matchBuf, cursor + 1);
385 -#if ENABLE_UNICODE_SUPPORT
386 -               cursor_mb = strlen(matchBuf);
387 +#else
388 +               {
389 +                       CHAR_T wc = command_ps[cursor];
390 +                       command_ps[cursor] = 0;
391 +                       save_string(matchBuf, MAX_LINELEN);
392 +                       command_ps[cursor] = wc;
393 +                       cursor_mb = strlen(matchBuf);
394 +               }
395  #endif
396                 tmp = matchBuf;
397  
398 -               find_type = find_match(matchBuf, &recalc_pos);
399 +               find_type = build_match_prefix(matchBuf, &recalc_pos);
400  
401                 /* Free up any memory already allocated */
402                 free_tab_completion_data();
403 @@ -1074,7 +1086,7 @@ static void input_tab(smallint *lastWasT
404                  * then try completing this word as a username. */
405                 if (state->flags & USERNAME_COMPLETION)
406                         if (matchBuf[0] == '~' && strchr(matchBuf, '/') == NULL)
407 -                               username_tab_completion(matchBuf, NULL);
408 +                               username_completion(matchBuf);
409  #endif
410                 /* Try to match any executable in our path and everything
411                  * in the current working directory */
412 @@ -1083,7 +1095,7 @@ static void input_tab(smallint *lastWasT
413                 /* Sort, then remove any duplicates found */
414                 if (matches) {
415                         unsigned i;
416 -                       int n = 0;
417 +                       unsigned n = 0;
418                         qsort_string_vector(matches, num_matches);
419                         for (i = 0; i < num_matches - 1; ++i) {
420                                 if (matches[i] && matches[i+1]) { /* paranoia */
421 @@ -1095,14 +1107,14 @@ static void input_tab(smallint *lastWasT
422                                         }
423                                 }
424                         }
425 -                       matches[n] = matches[i];
426 -                       num_matches = n + 1;
427 +                       matches[n++] = matches[i];
428 +                       num_matches = n;
429                 }
430                 /* Did we find exactly one match? */
431 -               if (!matches || num_matches > 1) { /* no */
432 +               if (num_matches != 1) { /* no */
433                         beep();
434                         if (!matches)
435 -                               return;         /* not found */
436 +                               return; /* no matches at all */
437                         /* find minimal match */
438                         tmp1 = xstrdup(matches[0]);
439                         for (tmp = tmp1; *tmp; tmp++) {
440 @@ -1113,13 +1125,14 @@ static void input_tab(smallint *lastWasT
441                                         }
442                                 }
443                         }
444 -                       if (*tmp1 == '\0') {        /* have unique */
445 -                               free(tmp1);
446 +                       if (*tmp1 == '\0') { /* have unique pfx? */
447 +                               free(tmp1); /* no */
448                                 return;
449                         }
450                         tmp = add_quote_for_spec_chars(tmp1);
451                         free(tmp1);
452 -               } else {                        /* one match */
453 +                       len_found = strlen(tmp);
454 +               } else {                        /* exactly one match */
455                         tmp = add_quote_for_spec_chars(matches[0]);
456                         /* for next completion current found */
457                         *lastWasTab = FALSE;
458 @@ -1127,11 +1140,10 @@ static void input_tab(smallint *lastWasT
459                         len_found = strlen(tmp);
460                         if (tmp[len_found-1] != '/') {
461                                 tmp[len_found] = ' ';
462 -                               tmp[len_found+1] = '\0';
463 +                               tmp[++len_found] = '\0';
464                         }
465                 }
466  
467 -               len_found = strlen(tmp);
468  #if !ENABLE_UNICODE_SUPPORT
469                 /* have space to place the match? */
470                 /* The result consists of three parts with these lengths: */
471 @@ -1164,7 +1176,10 @@ static void input_tab(smallint *lastWasT
472                                 sprintf(&command[cursor_mb - recalc_pos], "%s%s", tmp, matchBuf);
473                                 command_len = load_string(command, S.maxsize);
474                                 /* write out the matched command */
475 -                               redraw(cmdedit_y, command_len - len);
476 +                               /* paranoia: load_string can return 0 on conv error,
477 +                                * prevent passing len = (0 - 12) to redraw */
478 +                               len = command_len - len;
479 +                               redraw(cmdedit_y, len >= 0 ? len : 0);
480                         }
481                 }
482  #endif
483 --- a/libbb/unicode.c
484 +++ b/libbb/unicode.c
485 @@ -131,7 +131,7 @@ size_t FAST_FUNC wcstombs(char *dest, co
486                 size_t len = wcrtomb_internal(tbuf, wc);
487  
488                 if (len > n)
489 -                       len = n;
490 +                       break;
491                 memcpy(dest, tbuf, len);
492                 if (wc == L'\0')
493                         return org_n - n;