THANKS: Coverity.com (overdue)
[s-mailx.git] / src / mx / tty-prompts.c
blobbc5044102a8aada2fb0b96e059413ac834ad4a99
1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ Implementation of tty.h -- creating prompt, and asking questions.
4 * Copyright (c) 2012 - 2020 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
5 * SPDX-License-Identifier: ISC
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #undef su_FILE
20 #define su_FILE tty_prompts
21 #define mx_SOURCE
23 #ifndef mx_HAVE_AMALGAMATION
24 # include "mx/nail.h"
25 #endif
27 #include <su/mem.h>
29 #include "mx/cmd.h"
30 #include "mx/file-streams.h"
31 #include "mx/sigs.h"
32 #include "mx/termios.h"
33 #include "mx/ui-str.h"
35 #ifdef mx_HAVE_COLOUR
36 # include "mx/colour.h"
37 #endif
39 #include "mx/tty.h"
40 #include "su/code-in.h"
42 boole
43 mx_tty_yesorno(char const * volatile prompt, boole noninteract_default){
44 boole rv;
45 NYD_IN;
47 if(!(n_psonce & n_PSO_INTERACTIVE) || (n_pstate & n_PS_ROBOT))
48 rv = noninteract_default;
49 else{
50 uz lsize;
51 char *ldat;
52 char const *quest;
54 rv = FAL0;
56 quest = noninteract_default ? _("[yes]/no? ") : _("[no]/yes? ");
57 if(prompt == NIL)
58 prompt = _("Continue");
59 prompt = savecatsep(prompt, ' ', quest);
61 mx_fs_linepool_aquire(&ldat, &lsize);
62 while(n_go_input(n_GO_INPUT_CTX_DEFAULT | n_GO_INPUT_NL_ESC, prompt,
63 &ldat, &lsize, NIL,NIL) >= 0){
64 boole x;
66 x = n_boolify(ldat, UZ_MAX, noninteract_default);
67 if(x >= FAL0){
68 rv = x;
69 break;
72 mx_fs_linepool_release(ldat, lsize);
75 NYD_OU;
76 return rv;
79 #ifdef mx_HAVE_NET
80 char *
81 mx_tty_getuser(char const * volatile query) /* TODO v15-compat obsolete */
83 uz lsize;
84 char *ldat, *user;
85 NYD_IN;
87 if (query == NULL)
88 query = _("User: ");
90 mx_fs_linepool_aquire(&ldat, &lsize);
91 if(n_go_input(n_GO_INPUT_CTX_DEFAULT | n_GO_INPUT_NL_ESC, query,
92 &ldat, &lsize, NIL, NIL) >= 0)
93 user = savestr(ldat);
94 else
95 user = NIL;
96 mx_fs_linepool_release(ldat, lsize);
98 NYD_OU;
99 return user;
102 char *
103 mx_tty_getpass(char const *query){
104 uz lsize;
105 char *ldat, *pass;
106 NYD_IN;
108 pass = NIL;
110 if(n_psonce & n_PSO_TTYANY){
111 if(query == NIL)
112 query = _("Password: ");
114 mx_termios_cmdx(mx_TERMIOS_CMD_PUSH | mx_TERMIOS_CMD_PASSWORD);
116 fputs(query, mx_tty_fp);
117 fflush(mx_tty_fp);
119 mx_fs_linepool_aquire(&ldat, &lsize);
120 if(readline_restart(mx_tty_fp, &ldat, &lsize, 0) >= 0)
121 pass = savestr(ldat);
122 mx_fs_linepool_release(ldat, lsize);
124 mx_termios_cmdx(mx_TERMIOS_CMD_POP | mx_TERMIOS_CMD_PASSWORD);
126 putc('\n', mx_tty_fp);
129 NYD_OU;
130 return pass;
132 #endif /* mx_HAVE_NET */
134 boole
135 mx_tty_getfilename(struct n_string *store,
136 BITENUM_IS(u32,n_go_input_flags) gif,
137 char const *prompt_or_nil, char const *init_content_or_nil){
138 char const *cp;
139 boole rv;
140 NYD_IN;
142 if((n_psonce & (n_PSO_INTERACTIVE | n_PSO_GETFILENAME_QUOTE_NOTED)
143 ) == n_PSO_INTERACTIVE){
144 n_psonce |= n_PSO_GETFILENAME_QUOTE_NOTED;
145 fprintf(n_stdout,
146 _("# All file names need to be sh(1)ell-style quoted, everywhere\n"));
149 store = n_string_trunc(store, 0);
150 if((cp = n_go_input_cp(gif, prompt_or_nil, init_content_or_nil)) != NIL)
151 rv = n_shexp_unquote_one(store, cp);
152 else
153 rv = TRU2;
155 NYD_OU;
156 return rv;
160 mx_tty_create_prompt(struct n_string *store, char const *xprompt,
161 BITENUM_IS(u32,n_go_input_flags) gif){
162 struct n_visual_info_ctx vic;
163 struct str in, out;
164 u32 pwidth, poff;
165 char const *cp;
166 NYD2_IN;
167 ASSERT(n_psonce & n_PSO_INTERACTIVE);
169 #ifdef mx_HAVE_ERRORS
170 if(!(n_psonce & n_PSO_ERRORS_NOTED) && n_pstate_err_cnt > 0){
171 n_psonce |= n_PSO_ERRORS_NOTED;
172 n_err(_("There are messages in the error ring, "
173 "manageable via `errors' command\n"));
175 #endif
177 jredo:
178 n_string_trunc(store, 0);
180 if(gif & n_GO_INPUT_PROMPT_NONE){
181 pwidth = poff = 0;
182 goto jleave;
185 if(!(gif & n_GO_INPUT_NL_FOLLOW)){
186 boole x;
188 if((x = n_cnd_if_exists())){
189 if(store->s_len != 0)
190 store = n_string_push_c(store, '#');
191 if(x == TRUM1)
192 store = n_string_push_cp(store, _("WHITEOUT#"));
193 store = n_string_push_cp(store, _("NEED `endif'"));
197 if((poff = store->s_len) != 0){
198 ++poff;
199 store = n_string_push_c(store, '#');
200 store = n_string_push_c(store, ' ');
203 cp = (gif & n_GO_INPUT_PROMPT_EVAL)
204 ? (gif & n_GO_INPUT_NL_FOLLOW ? ok_vlook(prompt2) : ok_vlook(prompt))
205 : xprompt;
206 if(cp != NIL && *cp != '\0'){
207 BITENUM_IS(u32,n_shexp_state) shs;
209 store = n_string_push_cp(store, cp);
210 in.s = n_string_cp(store);
211 in.l = store->s_len;
212 out = in;
213 store = n_string_drop_ownership(store);
215 shs = n_shexp_parse_token((n_SHEXP_PARSE_LOG |
216 n_SHEXP_PARSE_IGNORE_EMPTY | n_SHEXP_PARSE_QUOTE_AUTO_FIXED |
217 n_SHEXP_PARSE_QUOTE_AUTO_DSQ), store, &in, NIL);
218 if((shs & n_SHEXP_STATE_ERR_MASK) || !(shs & n_SHEXP_STATE_STOP)){
219 store = n_string_clear(store);
220 store = n_string_take_ownership(store, out.s, out.l +1, out.l);
221 jeeval:
222 n_err(_("*prompt2?* evaluation failed, actively unsetting it\n"));
223 if(gif & n_GO_INPUT_NL_FOLLOW)
224 ok_vclear(prompt2);
225 else
226 ok_vclear(prompt);
227 goto jredo;
230 if(!store->s_auto)
231 n_free(out.s);
234 /* Make all printable TODO not know, we want to pass through ESC/CSI! */
235 #if 0
236 in.s = n_string_cp(store);
237 in.l = store->s_len;
238 makeprint(&in, &out);
239 store = n_string_assign_buf(store, out.s, out.l);
240 n_free(out.s);
241 #endif
243 /* We need the visual width.. */
244 su_mem_set(&vic, 0, sizeof vic);
245 vic.vic_indat = n_string_cp(store);
246 vic.vic_inlen = store->s_len;
247 for(pwidth = 0; vic.vic_inlen > 0;){
248 /* but \[ .. \] is not taken into account */
249 if(vic.vic_indat[0] == '\\' && vic.vic_inlen > 1 &&
250 vic.vic_indat[1] == '['){
251 uz i;
253 i = P2UZ(vic.vic_indat - store->s_dat);
254 store = n_string_cut(store, i, 2);
255 cp = &n_string_cp(store)[i];
256 i = store->s_len - i;
257 for(;; ++cp, --i){
258 if(i < 2){
259 n_err(_("Open \\[ sequence not closed in *prompt2?*\n"));
260 goto jeeval;
262 if(cp[0] == '\\' && cp[1] == ']')
263 break;
265 i = P2UZ(cp - store->s_dat);
266 store = n_string_cut(store, i, 2);
267 vic.vic_indat = &n_string_cp(store)[i];
268 vic.vic_inlen = store->s_len - i;
269 }else if(!n_visual_info(&vic, n_VISUAL_INFO_WIDTH_QUERY |
270 n_VISUAL_INFO_ONE_CHAR)){
271 n_err(_("Character set error in evaluation of *prompt2?*\n"));
272 goto jeeval;
273 }else{
274 pwidth += S(u32,vic.vic_vi_width);
275 vic.vic_indat = vic.vic_oudat;
276 vic.vic_inlen = vic.vic_oulen;
280 /* And there may be colour support, too */
281 #ifdef mx_HAVE_COLOUR
282 if(mx_COLOUR_IS_ACTIVE()){
283 struct mx_colour_pen *ccp;
284 struct str const *rsp, *psp, *esp;
286 psp = NIL;
287 if((rsp = mx_colour_reset_to_str()) != NIL &&
288 (ccp = mx_colour_pen_create(mx_COLOUR_ID_MLE_PROMPT, NIL)) != NIL &&
289 (psp = mx_colour_pen_to_str(ccp)) != NIL){
290 store = n_string_insert_buf(store, poff, psp->s, psp->l);
291 store = n_string_push_buf(store, rsp->s, rsp->l);
294 if(poff > 0 && rsp != NIL &&
295 (((ccp = mx_colour_pen_create(mx_COLOUR_ID_MLE_ERROR, NIL)
296 ) != NIL &&
297 (esp = mx_colour_pen_to_str(ccp)) != NIL) || (esp = psp) != NIL)){
298 store = n_string_insert_buf(store, poff, rsp->s, rsp->l);
299 store = n_string_unshift_buf(store, esp->s, esp->l);
302 #endif /* mx_HAVE_COLOUR */
304 jleave:
305 NYD2_OU;
306 return pwidth;
309 #include "su/code-ou.h"
310 /* s-it-mode */