Bash-4.3 patch 23
[platform/upstream/bash.git] / bracecomp.c
1 /* bracecomp.c -- Complete a filename with the possible completions enclosed
2    in csh-style braces such that the list of completions is available to the
3    shell. */
4
5 /* Original version by tromey@cns.caltech.edu,  Fri Feb  7 1992. */
6
7 /* Copyright (C) 1993-2009 Free Software Foundation, Inc.
8
9    This file is part of GNU Bash, the Bourne Again SHell.
10
11    Bash is free software: you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation, either version 3 of the License, or
14    (at your option) any later version.
15
16    Bash is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20
21    You should have received a copy of the GNU General Public License
22    along with Bash.  If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 #include "config.h"
26
27 #if defined (BRACE_EXPANSION) && defined (READLINE)
28
29 #include <stdio.h>
30
31 #if defined (HAVE_UNISTD_H)
32 #  ifdef _MINIX
33 #    include <sys/types.h>
34 #  endif
35 #  include <unistd.h>
36 #endif
37
38 #include "bashansi.h"
39 #include "shmbutil.h"
40
41 #include "shell.h"
42 #include <readline/readline.h>
43
44 static int _strcompare __P((char **, char **));
45
46 /* Find greatest common prefix of two strings. */
47 static int
48 string_gcd (s1, s2)
49      char *s1, *s2;
50 {
51   register int i;
52
53   if (s1 == NULL || s2 == NULL)
54     return (0);
55
56   for (i = 0; *s1 && *s2; ++s1, ++s2, ++i)
57     {
58       if (*s1 != *s2)
59         break;
60     }
61
62   return (i);
63 }
64
65 static char *
66 really_munge_braces (array, real_start, real_end, gcd_zero)
67      char **array;
68      int real_start, real_end, gcd_zero;
69 {
70   int start, end, gcd;
71   char *result, *subterm, *x;
72   int result_size, flag, tlen;
73
74   flag = 0;
75
76   if (real_start == real_end)
77     {
78       x = array[real_start] ? sh_backslash_quote (array[real_start] + gcd_zero, 0, 0)
79                             : sh_backslash_quote (array[0], 0, 0);
80       return x;
81     }
82
83   result = (char *)xmalloc (result_size = 16);
84   *result = '\0';
85
86   for (start = real_start; start < real_end; start = end + 1)
87     {
88       gcd = strlen (array[start]);
89       for (end = start + 1; end < real_end; end++)
90         {
91           int temp;
92
93           temp = string_gcd (array[start], array[end]);
94
95           if (temp <= gcd_zero)
96             break;
97
98           gcd = temp;
99         }
100       end--;
101
102       if (gcd_zero == 0 && start == real_start && end != (real_end - 1))
103         {
104           /* In this case, add in a leading '{', because we are at
105              top level, and there isn't a consistent prefix. */
106           result_size += 1;
107           result = (char *)xrealloc (result, result_size);
108           result[0] = '{'; result[1] = '\0';
109           flag++;
110         }
111
112       /* Make sure we backslash quote every substring we insert into the
113          resultant brace expression.  This is so the default filename
114          quoting function won't inappropriately quote the braces. */
115       if (start == end)
116         {
117           x = savestring (array[start] + gcd_zero);
118           subterm = sh_backslash_quote (x, 0, 0);
119           free (x);
120         }
121       else
122         {
123           /* If there is more than one element in the subarray,
124              insert the (quoted) prefix and an opening brace. */
125           tlen = gcd - gcd_zero;
126           x = (char *)xmalloc (tlen + 1);
127           strncpy (x, array[start] + gcd_zero, tlen);
128           x[tlen] = '\0';
129           subterm = sh_backslash_quote (x, 0, 0);
130           free (x);
131           result_size += strlen (subterm) + 1;
132           result = (char *)xrealloc (result, result_size);
133           strcat (result, subterm);
134           free (subterm);
135           strcat (result, "{");
136           subterm = really_munge_braces (array, start, end + 1, gcd);
137           subterm[strlen (subterm) - 1] = '}';
138         }
139
140       result_size += strlen (subterm) + 1;
141       result = (char *)xrealloc (result, result_size);
142       strcat (result, subterm);
143       strcat (result, ",");
144       free (subterm);
145     }
146
147   if (gcd_zero == 0)
148     result[strlen (result) - 1] = flag ? '}' : '\0';
149   return (result);
150 }
151
152 static int
153 _strcompare (s1, s2)
154      char **s1, **s2;
155 {
156   int result;
157
158   result = **s1 - **s2;
159   if (result == 0)
160     result = strcmp (*s1, *s2);
161
162   return result;
163 }
164
165 static int
166 hack_braces_completion (names)
167      char **names;
168 {
169   register int i;
170   char *temp;
171
172   i = strvec_len (names);
173   if (MB_CUR_MAX > 1 && i > 2)
174     qsort (names+1, i-1, sizeof (char *), (QSFUNC *)_strcompare);
175       
176   temp = really_munge_braces (names, 1, i, 0);
177
178   for (i = 0; names[i]; ++i)
179     {
180       free (names[i]);
181       names[i] = NULL;
182     }
183   names[0] = temp;
184   return 0;
185 }
186
187 /* We handle quoting ourselves within hack_braces_completion, so we turn off
188    rl_filename_quoting_desired and rl_filename_quoting_function. */
189 int
190 bash_brace_completion (count, ignore)
191      int count, ignore;
192 {
193   rl_compignore_func_t *orig_ignore_func;
194   rl_compentry_func_t *orig_entry_func;
195   rl_quote_func_t *orig_quoting_func;
196   rl_completion_func_t *orig_attempt_func;
197   int orig_quoting_desired, r;
198
199   orig_ignore_func = rl_ignore_some_completions_function;
200   orig_attempt_func = rl_attempted_completion_function;
201   orig_entry_func = rl_completion_entry_function;
202   orig_quoting_func = rl_filename_quoting_function;
203   orig_quoting_desired = rl_filename_quoting_desired;
204
205   rl_completion_entry_function = rl_filename_completion_function;
206   rl_attempted_completion_function = (rl_completion_func_t *)NULL;
207   rl_ignore_some_completions_function = hack_braces_completion;
208   rl_filename_quoting_function = (rl_quote_func_t *)NULL;
209   rl_filename_quoting_desired = 0;
210
211   r = rl_complete_internal (TAB);
212
213   rl_ignore_some_completions_function = orig_ignore_func;
214   rl_attempted_completion_function = orig_attempt_func;
215   rl_completion_entry_function = orig_entry_func;
216   rl_filename_quoting_function = orig_quoting_func;
217   rl_filename_quoting_desired = orig_quoting_desired;
218
219   return r;
220 }
221 #endif /* BRACE_EXPANSION && READLINE */