File: | cli/src/cli-rl.c |
Location: | line 240, column 15 |
Description: | Null pointer passed as an argument to a 'nonnull' parameter |
1 | /* | |||
2 | Copyright (c) 2010-2012 Red Hat, Inc. <http://www.redhat.com> | |||
3 | This file is part of GlusterFS. | |||
4 | ||||
5 | This file is licensed to you under your choice of the GNU Lesser | |||
6 | General Public License, version 3 or any later version (LGPLv3 or | |||
7 | later), or the GNU General Public License, version 2 (GPLv2), in all | |||
8 | cases as published by the Free Software Foundation. | |||
9 | */ | |||
10 | #include <stdio.h> | |||
11 | #include <string.h> | |||
12 | #include <stdlib.h> | |||
13 | #include <stdint.h> | |||
14 | #include <pthread.h> | |||
15 | ||||
16 | #ifndef _CONFIG_H | |||
17 | #define _CONFIG_H | |||
18 | #include "config.h" | |||
19 | #endif | |||
20 | ||||
21 | #include "cli.h" | |||
22 | #include "cli-cmd.h" | |||
23 | #include "cli-mem-types.h" | |||
24 | ||||
25 | #include "event.h" | |||
26 | ||||
27 | #include <fnmatch.h> | |||
28 | ||||
29 | #ifdef HAVE_READLINE1 | |||
30 | ||||
31 | #include <stdio.h> | |||
32 | #include <readline/readline.h> | |||
33 | #include <readline/history.h> | |||
34 | ||||
35 | ||||
36 | int | |||
37 | cli_rl_out (struct cli_state *state, const char *fmt, va_list ap) | |||
38 | { | |||
39 | int tmp_rl_point = rl_point; | |||
40 | int n = rl_end; | |||
41 | int ret = 0; | |||
42 | ||||
43 | if (rl_end >= 0 ) { | |||
44 | rl_kill_text (0, rl_end); | |||
45 | rl_redisplay (); | |||
46 | } | |||
47 | ||||
48 | printf ("\r%*s\r", (int)strlen (state->prompt), ""); | |||
49 | ||||
50 | ret = vprintf (fmt, ap); | |||
51 | ||||
52 | printf ("\n"); | |||
53 | fflush(stdoutstdout); | |||
54 | ||||
55 | if (n) { | |||
56 | rl_do_undo (); | |||
57 | rl_point = tmp_rl_point; | |||
58 | rl_reset_line_state (); | |||
59 | } | |||
60 | ||||
61 | return ret; | |||
62 | } | |||
63 | ||||
64 | int | |||
65 | cli_rl_err (struct cli_state *state, const char *fmt, va_list ap) | |||
66 | { | |||
67 | int tmp_rl_point = rl_point; | |||
68 | int n = rl_end; | |||
69 | int ret = 0; | |||
70 | ||||
71 | if (rl_end >= 0 ) { | |||
72 | rl_kill_text (0, rl_end); | |||
73 | rl_redisplay (); | |||
74 | } | |||
75 | ||||
76 | fprintf (stderrstderr, "\r%*s\r", (int)strlen (state->prompt), ""); | |||
77 | ||||
78 | ret = vfprintf (stderrstderr, fmt, ap); | |||
79 | ||||
80 | fprintf (stderrstderr, "\n"); | |||
81 | fflush(stderrstderr); | |||
82 | ||||
83 | if (n) { | |||
84 | rl_do_undo (); | |||
85 | rl_point = tmp_rl_point; | |||
86 | rl_reset_line_state (); | |||
87 | } | |||
88 | ||||
89 | return ret; | |||
90 | } | |||
91 | ||||
92 | ||||
93 | void | |||
94 | cli_rl_process_line (char *line) | |||
95 | { | |||
96 | struct cli_state *state = NULL((void*)0); | |||
97 | int ret = 0; | |||
98 | ||||
99 | state = global_state; | |||
100 | ||||
101 | state->rl_processing = 1; | |||
102 | { | |||
103 | ret = cli_cmd_process_line (state, line); | |||
104 | if (ret) | |||
105 | gf_log (THIS->name, GF_LOG_WARNING,do { do { if (0) printf ("failed to process line"); } while ( 0); _gf_log ((*__glusterfs_this_location())->name, "cli-rl.c" , __FUNCTION__, 106, GF_LOG_WARNING, "failed to process line" ); } while (0) | |||
106 | "failed to process line")do { do { if (0) printf ("failed to process line"); } while ( 0); _gf_log ((*__glusterfs_this_location())->name, "cli-rl.c" , __FUNCTION__, 106, GF_LOG_WARNING, "failed to process line" ); } while (0); | |||
107 | ||||
108 | add_history (line); | |||
109 | } | |||
110 | state->rl_processing = 0; | |||
111 | ||||
112 | } | |||
113 | ||||
114 | ||||
115 | int | |||
116 | cli_rl_stdin (int fd, int idx, void *data, | |||
117 | int poll_out, int poll_in, int poll_err) | |||
118 | { | |||
119 | rl_callback_read_char (); | |||
120 | ||||
121 | return 0; | |||
122 | } | |||
123 | ||||
124 | ||||
125 | char * | |||
126 | cli_rl_autocomplete_entry (const char *text, int times) | |||
127 | { | |||
128 | struct cli_state *state = NULL((void*)0); | |||
129 | char *retp = NULL((void*)0); | |||
130 | ||||
131 | state = global_state; | |||
132 | ||||
133 | if (!state->matchesp) | |||
134 | return NULL((void*)0); | |||
135 | ||||
136 | retp = *state->matchesp; | |||
137 | ||||
138 | state->matchesp++; | |||
139 | ||||
140 | return retp ? strdup (retp) : NULL((void*)0); | |||
141 | } | |||
142 | ||||
143 | ||||
144 | int | |||
145 | cli_rl_token_count (const char *text) | |||
146 | { | |||
147 | int count = 0; | |||
148 | const char *trav = NULL((void*)0); | |||
149 | int is_spc = 1; | |||
150 | ||||
151 | for (trav = text; *trav; trav++) { | |||
152 | if (*trav == ' ') { | |||
153 | is_spc = 1; | |||
154 | } else { | |||
155 | if (is_spc) { | |||
156 | count++; | |||
157 | is_spc = 0; | |||
158 | } | |||
159 | } | |||
160 | } | |||
161 | ||||
162 | if (is_spc) | |||
163 | /* what needs to be autocompleted is a full | |||
164 | new word, and not extend the last word | |||
165 | */ | |||
166 | count++; | |||
167 | ||||
168 | return count; | |||
169 | } | |||
170 | ||||
171 | ||||
172 | char ** | |||
173 | cli_rl_tokenize (const char *text) | |||
174 | { | |||
175 | int count = 0; | |||
176 | char **tokens = NULL((void*)0); | |||
177 | char **tokenp = NULL((void*)0); | |||
178 | char *token = NULL((void*)0); | |||
179 | char *copy = NULL((void*)0); | |||
180 | char *saveptr = NULL((void*)0); | |||
181 | int i = 0; | |||
182 | ||||
183 | count = cli_rl_token_count (text); | |||
184 | ||||
185 | tokens = calloc (count + 1, sizeof (*tokens)); | |||
186 | if (!tokens) | |||
187 | return NULL((void*)0); | |||
188 | ||||
189 | copy = strdup (text); | |||
190 | if (!copy) | |||
191 | goto out; | |||
192 | ||||
193 | tokenp = tokens; | |||
194 | ||||
195 | for (token = strtok_r (copy, " \t\r\n", &saveptr); token; | |||
196 | token = strtok_r (NULL((void*)0), " \t\r\n", &saveptr)) { | |||
197 | *tokenp = strdup (token); | |||
198 | ||||
199 | if (!*tokenp) | |||
200 | goto out; | |||
201 | tokenp++; | |||
202 | i++; | |||
203 | ||||
204 | } | |||
205 | ||||
206 | if (i < count) { | |||
207 | /* symbolize that what needs to be autocompleted is | |||
208 | the full set of possible nextwords, and not extend | |||
209 | the last word | |||
210 | */ | |||
211 | *tokenp = strdup (""); | |||
212 | if (!*tokenp) | |||
213 | goto out; | |||
214 | tokenp++; | |||
215 | i++; | |||
216 | } | |||
217 | ||||
218 | out: | |||
219 | free (copy); | |||
220 | ||||
221 | if (i < count) { | |||
222 | cli_cmd_tokens_destroy (tokens); | |||
223 | tokens = NULL((void*)0); | |||
224 | } | |||
225 | ||||
226 | return tokens; | |||
227 | } | |||
228 | ||||
229 | ||||
230 | char ** | |||
231 | cli_rl_get_matches (struct cli_state *state, struct cli_cmd_word *word, | |||
232 | const char *text) | |||
233 | { | |||
234 | char **matches = NULL((void*)0); | |||
235 | char **matchesp = NULL((void*)0); | |||
236 | struct cli_cmd_word **next = NULL((void*)0); | |||
237 | int count = 0; | |||
238 | int len = 0; | |||
239 | ||||
240 | len = strlen (text); | |||
| ||||
241 | ||||
242 | if (!word->nextwords) | |||
243 | return NULL((void*)0); | |||
244 | ||||
245 | for (next = word->nextwords; *next; next++) | |||
246 | count++; | |||
247 | ||||
248 | matches = calloc (count + 1, sizeof (*matches)); | |||
249 | matchesp = matches; | |||
250 | ||||
251 | for (next = word->nextwords; *next; next++) { | |||
252 | if ((*next)->match) { | |||
253 | continue; | |||
254 | } | |||
255 | ||||
256 | if (strncmp ((*next)->word, text, len) == 0) { | |||
257 | *matchesp = strdup ((*next)->word); | |||
258 | matchesp++; | |||
259 | } | |||
260 | } | |||
261 | ||||
262 | return matches; | |||
263 | } | |||
264 | ||||
265 | ||||
266 | int | |||
267 | cli_rl_autocomplete_prepare (struct cli_state *state, const char *text) | |||
268 | { | |||
269 | struct cli_cmd_word *word = NULL((void*)0); | |||
270 | struct cli_cmd_word *next = NULL((void*)0); | |||
271 | char **tokens = NULL((void*)0); | |||
272 | char **tokenp = NULL((void*)0); | |||
273 | char *token = NULL((void*)0); | |||
274 | char **matches = NULL((void*)0); | |||
275 | ||||
276 | tokens = cli_rl_tokenize (text); | |||
277 | if (!tokens) | |||
278 | return 0; | |||
279 | ||||
280 | word = &state->tree.root; | |||
281 | ||||
282 | for (tokenp = tokens; (token = *tokenp); tokenp++) { | |||
283 | if (!*(tokenp+1)) { | |||
284 | /* last word */ | |||
285 | break; | |||
286 | } | |||
287 | ||||
288 | next = cli_cmd_nextword (word, token); | |||
289 | word = next; | |||
290 | if (!word) | |||
291 | break; | |||
292 | } | |||
293 | ||||
294 | if (!word) | |||
295 | goto out; | |||
296 | ||||
297 | matches = cli_rl_get_matches (state, word, token); | |||
298 | ||||
299 | state->matches = matches; | |||
300 | state->matchesp = matches; | |||
301 | ||||
302 | out: | |||
303 | cli_cmd_tokens_destroy (tokens); | |||
304 | return 0; | |||
305 | } | |||
306 | ||||
307 | ||||
308 | int | |||
309 | cli_rl_autocomplete_cleanup (struct cli_state *state) | |||
310 | { | |||
311 | if (state->matches) | |||
312 | cli_cmd_tokens_destroy (state->matches); | |||
313 | ||||
314 | state->matches = NULL((void*)0); | |||
315 | state->matchesp = NULL((void*)0); | |||
316 | ||||
317 | return 0; | |||
318 | } | |||
319 | ||||
320 | ||||
321 | char ** | |||
322 | cli_rl_autocomplete (const char *text, int start, int end) | |||
323 | { | |||
324 | struct cli_state *state = NULL((void*)0); | |||
325 | char **matches = NULL((void*)0); | |||
326 | char save = 0; | |||
327 | ||||
328 | state = global_state; | |||
329 | ||||
330 | /* hack to make the autocompletion code neater */ | |||
331 | /* fake it as though the cursor is at the end of line */ | |||
332 | ||||
333 | save = rl_line_buffer[rl_point]; | |||
334 | rl_line_buffer[rl_point] = 0; | |||
335 | ||||
336 | cli_rl_autocomplete_prepare (state, rl_line_buffer); | |||
| ||||
337 | ||||
338 | matches = rl_completion_matches (text, cli_rl_autocomplete_entry); | |||
339 | ||||
340 | cli_rl_autocomplete_cleanup (state); | |||
341 | ||||
342 | rl_line_buffer[rl_point] = save; | |||
343 | ||||
344 | return matches; | |||
345 | } | |||
346 | ||||
347 | ||||
348 | static char * | |||
349 | complete_none (const char *txt, int times) | |||
350 | { | |||
351 | return NULL((void*)0); | |||
352 | } | |||
353 | ||||
354 | ||||
355 | void * | |||
356 | cli_rl_input (void *_data) | |||
357 | { | |||
358 | struct cli_state *state = NULL((void*)0); | |||
359 | char *line = NULL((void*)0); | |||
360 | ||||
361 | state = _data; | |||
362 | ||||
363 | for (;;) { | |||
364 | line = readline (state->prompt); | |||
365 | if (!line) | |||
366 | exit(0); //break; | |||
367 | ||||
368 | if (*line) | |||
369 | cli_rl_process_line (line); | |||
370 | ||||
371 | free (line); | |||
372 | } | |||
373 | ||||
374 | return NULL((void*)0); | |||
375 | } | |||
376 | ||||
377 | ||||
378 | int | |||
379 | cli_rl_enable (struct cli_state *state) | |||
380 | { | |||
381 | int ret = 0; | |||
382 | ||||
383 | rl_pre_input_hook = NULL((void*)0); | |||
384 | rl_attempted_completion_function = cli_rl_autocomplete; | |||
385 | rl_completion_entry_function = complete_none; | |||
386 | ||||
387 | if (!state->rl_async) { | |||
388 | ret = pthread_create (&state->input, NULL((void*)0), | |||
389 | cli_rl_input, state); | |||
390 | if (ret == 0) | |||
391 | state->rl_enabled = 1; | |||
392 | goto out; | |||
393 | } | |||
394 | ||||
395 | ret = event_register (state->ctx->event_pool, 0, cli_rl_stdin, state, | |||
396 | 1, 0); | |||
397 | if (ret == -1) | |||
398 | goto out; | |||
399 | ||||
400 | state->rl_enabled = 1; | |||
401 | rl_callback_handler_install (state->prompt, cli_rl_process_line); | |||
402 | ||||
403 | out: | |||
404 | return state->rl_enabled; | |||
405 | } | |||
406 | ||||
407 | #else /* HAVE_READLINE */ | |||
408 | ||||
409 | int | |||
410 | cli_rl_enable (struct cli_state *state) | |||
411 | { | |||
412 | return 0; | |||
413 | } | |||
414 | ||||
415 | #endif /* HAVE_READLINE */ |