Raw
1 #define USE_THE_REPOSITORY_VARIABLE
2
3 #include "git-compat-util.h"
4 #include "alias.h"
5 #include "config.h"
6 #include "gettext.h"
7 #include "strbuf.h"
8 #include "string-list.h"
9
10 struct config_alias_data {
11 const char *alias;
12 char *v;
13 struct string_list *list;
14 };
15
16 static int config_alias_cb(const char *var, const char *value,
17 const struct config_context *ctx UNUSED, void *d)
18 {
19 struct config_alias_data *data = d;
20 const char *subsection, *key;
21 size_t subsection_len;
22
23 if (parse_config_key(var, "alias", &subsection, &subsection_len,
24 &key) < 0)
25 return 0;
26
27 /*
28 * Two config syntaxes:
29 * - alias.name = value (without subsection, case-insensitive)
30 * - [alias "name"]
31 * command = value (with subsection, case-sensitive)
32 */
33 /* Treat [alias ""] (empty subsection) the same as plain [alias]. */
34 if (subsection && !subsection_len)
35 subsection = NULL;
36
37 if (subsection && strcmp(key, "command")) {
38 /*
39 * We have historically supported the "alias.name" form when
40 * "name" happens to contain dots (e.g., alias.foo.bar to allow
41 * "git foo.bar". But our parsing above would split that into
42 * subsection "foo".
43 *
44 * If we do not understand the final key in a subsection-style
45 * variable, fall back to treating it as a two-level alias.
46 */
47 key = var + strlen("alias.");
48 subsection = NULL;
49 subsection_len = 0;
50 }
51
52 if (data->alias) {
53 int match;
54
55 if (subsection)
56 match = (strlen(data->alias) == subsection_len &&
57 !strncmp(data->alias, subsection,
58 subsection_len));
59 else
60 match = !strcasecmp(data->alias, key);
61
62 if (match) {
63 FREE_AND_NULL(data->v);
64 return git_config_string(&data->v,
65 var, value);
66 }
67 } else if (data->list) {
68 struct string_list_item *item;
69
70 if (!value)
71 return config_error_nonbool(var);
72
73 if (subsection)
74 item = string_list_append_nodup(data->list,
75 xmemdupz(subsection, subsection_len));
76 else
77 item = string_list_append(data->list, key);
78 item->util = xstrdup(value);
79 }
80
81 return 0;
82 }
83
84 char *alias_lookup(const char *alias)
85 {
86 struct config_alias_data data = { alias, NULL };
87
88 read_early_config(the_repository, config_alias_cb, &data);
89
90 return data.v;
91 }
92
93 void list_aliases(struct string_list *list)
94 {
95 struct config_alias_data data = { NULL, NULL, list };
96
97 read_early_config(the_repository, config_alias_cb, &data);
98 }
99
100 void quote_cmdline(struct strbuf *buf, const char **argv)
101 {
102 for (const char **argp = argv; *argp; argp++) {
103 if (argp != argv)
104 strbuf_addch(buf, ' ');
105 strbuf_addch(buf, '"');
106 for (const char *p = *argp; *p; p++) {
107 const char c = *p;
108
109 if (c == '"' || c =='\\')
110 strbuf_addch(buf, '\\');
111 strbuf_addch(buf, c);
112 }
113 strbuf_addch(buf, '"');
114 }
115 }
116
117 #define SPLIT_CMDLINE_BAD_ENDING 1
118 #define SPLIT_CMDLINE_UNCLOSED_QUOTE 2
119 #define SPLIT_CMDLINE_ARGC_OVERFLOW 3
120 static const char *split_cmdline_errors[] = {
121 N_("cmdline ends with \\"),
122 N_("unclosed quote"),
123 N_("too many arguments"),
124 };
125
126 int split_cmdline(char *cmdline, const char ***argv)
127 {
128 size_t src, dst, count = 0, size = 16;
129 char quoted = 0;
130
131 ALLOC_ARRAY(*argv, size);
132
133 /* split alias_string */
134 (*argv)[count++] = cmdline;
135 for (src = dst = 0; cmdline[src];) {
136 char c = cmdline[src];
137 if (!quoted && isspace(c)) {
138 cmdline[dst++] = 0;
139 while (cmdline[++src]
140 && isspace(cmdline[src]))
141 ; /* skip */
142 ALLOC_GROW(*argv, count + 1, size);
143 (*argv)[count++] = cmdline + dst;
144 } else if (!quoted && (c == '\'' || c == '"')) {
145 quoted = c;
146 src++;
147 } else if (c == quoted) {
148 quoted = 0;
149 src++;
150 } else {
151 if (c == '\\' && quoted != '\'') {
152 src++;
153 c = cmdline[src];
154 if (!c) {
155 FREE_AND_NULL(*argv);
156 return -SPLIT_CMDLINE_BAD_ENDING;
157 }
158 }
159 cmdline[dst++] = c;
160 src++;
161 }
162 }
163
164 cmdline[dst] = 0;
165
166 if (quoted) {
167 FREE_AND_NULL(*argv);
168 return -SPLIT_CMDLINE_UNCLOSED_QUOTE;
169 }
170
171 if (count >= INT_MAX) {
172 FREE_AND_NULL(*argv);
173 return -SPLIT_CMDLINE_ARGC_OVERFLOW;
174 }
175
176 ALLOC_GROW(*argv, count + 1, size);
177 (*argv)[count] = NULL;
178
179 return count;
180 }
181
182 const char *split_cmdline_strerror(int split_cmdline_errno)
183 {
184 return split_cmdline_errors[-split_cmdline_errno - 1];
185 }