1 | /* $OpenBSD$ */ |
2 | |
3 | /* |
4 | * Copyright (c) 2008 Nicholas Marriott <[email protected]> |
5 | * |
6 | * Permission to use, copy, modify, and distribute this software for any |
7 | * purpose with or without fee is hereby granted, provided that the above |
8 | * copyright notice and this permission notice appear in all copies. |
9 | * |
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER |
15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING |
16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 | */ |
18 | |
19 | #include <sys/types.h> |
20 | |
21 | #include <ctype.h> |
22 | #include <stdlib.h> |
23 | #include <string.h> |
24 | #include <time.h> |
25 | |
26 | #include "tmux.h" |
27 | |
28 | /* |
29 | * Prompt for command in client. |
30 | */ |
31 | |
32 | static enum cmd_retval cmd_command_prompt_exec(struct cmd *, |
33 | struct cmdq_item *); |
34 | |
35 | static int cmd_command_prompt_callback(struct client *, void *, |
36 | const char *, int); |
37 | static void cmd_command_prompt_free(void *); |
38 | |
39 | const struct cmd_entry cmd_command_prompt_entry = { |
40 | .name = "command-prompt" , |
41 | .alias = NULL, |
42 | |
43 | .args = { "1kiI:Np:t:" , 0, 1 }, |
44 | .usage = "[-1kiN] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE " " |
45 | "[template]" , |
46 | |
47 | .flags = 0, |
48 | .exec = cmd_command_prompt_exec |
49 | }; |
50 | |
51 | struct cmd_command_prompt_cdata { |
52 | int flags; |
53 | |
54 | char *inputs; |
55 | char *next_input; |
56 | |
57 | char *prompts; |
58 | char *next_prompt; |
59 | |
60 | char *template; |
61 | int idx; |
62 | }; |
63 | |
64 | static enum cmd_retval |
65 | cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item) |
66 | { |
67 | struct args *args = self->args; |
68 | const char *inputs, *prompts; |
69 | struct cmd_command_prompt_cdata *cdata; |
70 | struct client *c; |
71 | char *prompt, *ptr, *input = NULL; |
72 | size_t n; |
73 | |
74 | if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL) |
75 | return (CMD_RETURN_ERROR); |
76 | |
77 | if (c->prompt_string != NULL) |
78 | return (CMD_RETURN_NORMAL); |
79 | |
80 | cdata = xcalloc(1, sizeof *cdata); |
81 | |
82 | cdata->inputs = NULL; |
83 | cdata->next_input = NULL; |
84 | |
85 | cdata->prompts = NULL; |
86 | cdata->next_prompt = NULL; |
87 | |
88 | cdata->template = NULL; |
89 | cdata->idx = 1; |
90 | |
91 | if (args->argc != 0) |
92 | cdata->template = xstrdup(args->argv[0]); |
93 | else |
94 | cdata->template = xstrdup("%1" ); |
95 | |
96 | if ((prompts = args_get(args, 'p')) != NULL) |
97 | cdata->prompts = xstrdup(prompts); |
98 | else if (args->argc != 0) { |
99 | n = strcspn(cdata->template, " ," ); |
100 | xasprintf(&cdata->prompts, "(%.*s) " , (int) n, cdata->template); |
101 | } else |
102 | cdata->prompts = xstrdup(":" ); |
103 | |
104 | /* Get first prompt. */ |
105 | cdata->next_prompt = cdata->prompts; |
106 | ptr = strsep(&cdata->next_prompt, "," ); |
107 | if (prompts == NULL) |
108 | prompt = xstrdup(ptr); |
109 | else |
110 | xasprintf(&prompt, "%s " , ptr); |
111 | |
112 | /* Get initial prompt input. */ |
113 | if ((inputs = args_get(args, 'I')) != NULL) { |
114 | cdata->inputs = xstrdup(inputs); |
115 | cdata->next_input = cdata->inputs; |
116 | input = strsep(&cdata->next_input, "," ); |
117 | } |
118 | |
119 | if (args_has(args, '1')) |
120 | cdata->flags |= PROMPT_SINGLE; |
121 | else if (args_has(args, 'N')) |
122 | cdata->flags |= PROMPT_NUMERIC; |
123 | else if (args_has(args, 'i')) |
124 | cdata->flags |= PROMPT_INCREMENTAL; |
125 | else if (args_has(args, 'k')) |
126 | cdata->flags |= PROMPT_KEY; |
127 | status_prompt_set(c, prompt, input, cmd_command_prompt_callback, |
128 | cmd_command_prompt_free, cdata, cdata->flags); |
129 | free(prompt); |
130 | |
131 | return (CMD_RETURN_NORMAL); |
132 | } |
133 | |
134 | static int |
135 | cmd_command_prompt_callback(struct client *c, void *data, const char *s, |
136 | int done) |
137 | { |
138 | struct cmd_command_prompt_cdata *cdata = data; |
139 | struct cmdq_item *new_item; |
140 | char *new_template, *prompt, *ptr; |
141 | char *input = NULL; |
142 | struct cmd_parse_result *pr; |
143 | |
144 | if (s == NULL) |
145 | return (0); |
146 | if (done && (cdata->flags & PROMPT_INCREMENTAL)) |
147 | return (0); |
148 | |
149 | new_template = cmd_template_replace(cdata->template, s, cdata->idx); |
150 | if (done) { |
151 | free(cdata->template); |
152 | cdata->template = new_template; |
153 | } |
154 | |
155 | /* |
156 | * Check if there are more prompts; if so, get its respective input |
157 | * and update the prompt data. |
158 | */ |
159 | if (done && (ptr = strsep(&cdata->next_prompt, "," )) != NULL) { |
160 | xasprintf(&prompt, "%s " , ptr); |
161 | input = strsep(&cdata->next_input, "," ); |
162 | status_prompt_update(c, prompt, input); |
163 | |
164 | free(prompt); |
165 | cdata->idx++; |
166 | return (1); |
167 | } |
168 | |
169 | pr = cmd_parse_from_string(new_template, NULL); |
170 | switch (pr->status) { |
171 | case CMD_PARSE_EMPTY: |
172 | new_item = NULL; |
173 | break; |
174 | case CMD_PARSE_ERROR: |
175 | new_item = cmdq_get_error(pr->error); |
176 | free(pr->error); |
177 | cmdq_append(c, new_item); |
178 | break; |
179 | case CMD_PARSE_SUCCESS: |
180 | new_item = cmdq_get_command(pr->cmdlist, NULL, NULL, 0); |
181 | cmd_list_free(pr->cmdlist); |
182 | cmdq_append(c, new_item); |
183 | break; |
184 | } |
185 | |
186 | if (!done) |
187 | free(new_template); |
188 | if (c->prompt_inputcb != cmd_command_prompt_callback) |
189 | return (1); |
190 | return (0); |
191 | } |
192 | |
193 | static void |
194 | cmd_command_prompt_free(void *data) |
195 | { |
196 | struct cmd_command_prompt_cdata *cdata = data; |
197 | |
198 | free(cdata->inputs); |
199 | free(cdata->prompts); |
200 | free(cdata->template); |
201 | free(cdata); |
202 | } |
203 | |