1// This is an open source non-commercial project. Dear PVS-Studio, please check
2// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
3
4/*
5 * misc1.c: functions that didn't seem to fit elsewhere
6 */
7
8#include <assert.h>
9#include <inttypes.h>
10#include <stdbool.h>
11#include <string.h>
12#include <limits.h>
13
14#include "nvim/vim.h"
15#include "nvim/ascii.h"
16#include "nvim/misc1.h"
17#include "nvim/charset.h"
18#include "nvim/cursor.h"
19#include "nvim/diff.h"
20#include "nvim/edit.h"
21#include "nvim/eval.h"
22#include "nvim/ex_cmds.h"
23#include "nvim/ex_docmd.h"
24#include "nvim/ex_getln.h"
25#include "nvim/fileio.h"
26#include "nvim/func_attr.h"
27#include "nvim/fold.h"
28#include "nvim/getchar.h"
29#include "nvim/indent.h"
30#include "nvim/indent_c.h"
31#include "nvim/buffer_updates.h"
32#include "nvim/main.h"
33#include "nvim/mark.h"
34#include "nvim/mbyte.h"
35#include "nvim/memline.h"
36#include "nvim/memory.h"
37#include "nvim/message.h"
38#include "nvim/garray.h"
39#include "nvim/move.h"
40#include "nvim/mouse.h"
41#include "nvim/option.h"
42#include "nvim/os_unix.h"
43#include "nvim/quickfix.h"
44#include "nvim/regexp.h"
45#include "nvim/screen.h"
46#include "nvim/search.h"
47#include "nvim/state.h"
48#include "nvim/strings.h"
49#include "nvim/tag.h"
50#include "nvim/ui.h"
51#include "nvim/undo.h"
52#include "nvim/window.h"
53#include "nvim/os/os.h"
54#include "nvim/os/shell.h"
55#include "nvim/os/signal.h"
56#include "nvim/os/input.h"
57#include "nvim/os/time.h"
58#include "nvim/event/stream.h"
59#include "nvim/buffer.h"
60
61#ifdef INCLUDE_GENERATED_DECLARATIONS
62# include "misc1.c.generated.h"
63#endif
64// All user names (for ~user completion as done by shell).
65static garray_T ga_users = GA_EMPTY_INIT_VALUE;
66
67/*
68 * get_leader_len() returns the length in bytes of the prefix of the given
69 * string which introduces a comment. If this string is not a comment then
70 * 0 is returned.
71 * When "flags" is not NULL, it is set to point to the flags of the recognized
72 * comment leader.
73 * "backward" must be true for the "O" command.
74 * If "include_space" is set, include trailing whitespace while calculating the
75 * length.
76 */
77int get_leader_len(char_u *line, char_u **flags, int backward, int include_space)
78{
79 int i, j;
80 int result;
81 int got_com = FALSE;
82 int found_one;
83 char_u part_buf[COM_MAX_LEN]; /* buffer for one option part */
84 char_u *string; /* pointer to comment string */
85 char_u *list;
86 int middle_match_len = 0;
87 char_u *prev_list;
88 char_u *saved_flags = NULL;
89
90 result = i = 0;
91 while (ascii_iswhite(line[i])) /* leading white space is ignored */
92 ++i;
93
94 /*
95 * Repeat to match several nested comment strings.
96 */
97 while (line[i] != NUL) {
98 /*
99 * scan through the 'comments' option for a match
100 */
101 found_one = FALSE;
102 for (list = curbuf->b_p_com; *list; ) {
103 /* Get one option part into part_buf[]. Advance "list" to next
104 * one. Put "string" at start of string. */
105 if (!got_com && flags != NULL)
106 *flags = list; /* remember where flags started */
107 prev_list = list;
108 (void)copy_option_part(&list, part_buf, COM_MAX_LEN, ",");
109 string = vim_strchr(part_buf, ':');
110 if (string == NULL) /* missing ':', ignore this part */
111 continue;
112 *string++ = NUL; /* isolate flags from string */
113
114 /* If we found a middle match previously, use that match when this
115 * is not a middle or end. */
116 if (middle_match_len != 0
117 && vim_strchr(part_buf, COM_MIDDLE) == NULL
118 && vim_strchr(part_buf, COM_END) == NULL)
119 break;
120
121 /* When we already found a nested comment, only accept further
122 * nested comments. */
123 if (got_com && vim_strchr(part_buf, COM_NEST) == NULL)
124 continue;
125
126 /* When 'O' flag present and using "O" command skip this one. */
127 if (backward && vim_strchr(part_buf, COM_NOBACK) != NULL)
128 continue;
129
130 /* Line contents and string must match.
131 * When string starts with white space, must have some white space
132 * (but the amount does not need to match, there might be a mix of
133 * TABs and spaces). */
134 if (ascii_iswhite(string[0])) {
135 if (i == 0 || !ascii_iswhite(line[i - 1]))
136 continue; /* missing white space */
137 while (ascii_iswhite(string[0]))
138 ++string;
139 }
140 for (j = 0; string[j] != NUL && string[j] == line[i + j]; ++j)
141 ;
142 if (string[j] != NUL)
143 continue; /* string doesn't match */
144
145 /* When 'b' flag used, there must be white space or an
146 * end-of-line after the string in the line. */
147 if (vim_strchr(part_buf, COM_BLANK) != NULL
148 && !ascii_iswhite(line[i + j]) && line[i + j] != NUL)
149 continue;
150
151 /* We have found a match, stop searching unless this is a middle
152 * comment. The middle comment can be a substring of the end
153 * comment in which case it's better to return the length of the
154 * end comment and its flags. Thus we keep searching with middle
155 * and end matches and use an end match if it matches better. */
156 if (vim_strchr(part_buf, COM_MIDDLE) != NULL) {
157 if (middle_match_len == 0) {
158 middle_match_len = j;
159 saved_flags = prev_list;
160 }
161 continue;
162 }
163 if (middle_match_len != 0 && j > middle_match_len)
164 /* Use this match instead of the middle match, since it's a
165 * longer thus better match. */
166 middle_match_len = 0;
167
168 if (middle_match_len == 0)
169 i += j;
170 found_one = TRUE;
171 break;
172 }
173
174 if (middle_match_len != 0) {
175 /* Use the previously found middle match after failing to find a
176 * match with an end. */
177 if (!got_com && flags != NULL)
178 *flags = saved_flags;
179 i += middle_match_len;
180 found_one = TRUE;
181 }
182
183 /* No match found, stop scanning. */
184 if (!found_one)
185 break;
186
187 result = i;
188
189 /* Include any trailing white space. */
190 while (ascii_iswhite(line[i]))
191 ++i;
192
193 if (include_space)
194 result = i;
195
196 /* If this comment doesn't nest, stop here. */
197 got_com = TRUE;
198 if (vim_strchr(part_buf, COM_NEST) == NULL)
199 break;
200 }
201 return result;
202}
203
204/*
205 * Return the offset at which the last comment in line starts. If there is no
206 * comment in the whole line, -1 is returned.
207 *
208 * When "flags" is not null, it is set to point to the flags describing the
209 * recognized comment leader.
210 */
211int get_last_leader_offset(char_u *line, char_u **flags)
212{
213 int result = -1;
214 int i, j;
215 int lower_check_bound = 0;
216 char_u *string;
217 char_u *com_leader;
218 char_u *com_flags;
219 char_u *list;
220 int found_one;
221 char_u part_buf[COM_MAX_LEN]; /* buffer for one option part */
222
223 /*
224 * Repeat to match several nested comment strings.
225 */
226 i = (int)STRLEN(line);
227 while (--i >= lower_check_bound) {
228 /*
229 * scan through the 'comments' option for a match
230 */
231 found_one = FALSE;
232 for (list = curbuf->b_p_com; *list; ) {
233 char_u *flags_save = list;
234
235 /*
236 * Get one option part into part_buf[]. Advance list to next one.
237 * put string at start of string.
238 */
239 (void)copy_option_part(&list, part_buf, COM_MAX_LEN, ",");
240 string = vim_strchr(part_buf, ':');
241 if (string == NULL) { /* If everything is fine, this cannot actually
242 * happen. */
243 continue;
244 }
245 *string++ = NUL; /* Isolate flags from string. */
246 com_leader = string;
247
248 /*
249 * Line contents and string must match.
250 * When string starts with white space, must have some white space
251 * (but the amount does not need to match, there might be a mix of
252 * TABs and spaces).
253 */
254 if (ascii_iswhite(string[0])) {
255 if (i == 0 || !ascii_iswhite(line[i - 1]))
256 continue;
257 while (ascii_iswhite(*string)) {
258 string++;
259 }
260 }
261 for (j = 0; string[j] != NUL && string[j] == line[i + j]; ++j)
262 /* do nothing */;
263 if (string[j] != NUL)
264 continue;
265
266 /*
267 * When 'b' flag used, there must be white space or an
268 * end-of-line after the string in the line.
269 */
270 if (vim_strchr(part_buf, COM_BLANK) != NULL
271 && !ascii_iswhite(line[i + j]) && line[i + j] != NUL) {
272 continue;
273 }
274
275 if (vim_strchr(part_buf, COM_MIDDLE) != NULL) {
276 // For a middlepart comment, only consider it to match if
277 // everything before the current position in the line is
278 // whitespace. Otherwise we would think we are inside a
279 // comment if the middle part appears somewhere in the middle
280 // of the line. E.g. for C the "*" appears often.
281 for (j = 0; ascii_iswhite(line[j]) && j <= i; j++) {
282 }
283 if (j < i) {
284 continue;
285 }
286 }
287
288 /*
289 * We have found a match, stop searching.
290 */
291 found_one = TRUE;
292
293 if (flags)
294 *flags = flags_save;
295 com_flags = flags_save;
296
297 break;
298 }
299
300 if (found_one) {
301 char_u part_buf2[COM_MAX_LEN]; /* buffer for one option part */
302 int len1, len2, off;
303
304 result = i;
305 /*
306 * If this comment nests, continue searching.
307 */
308 if (vim_strchr(part_buf, COM_NEST) != NULL)
309 continue;
310
311 lower_check_bound = i;
312
313 /* Let's verify whether the comment leader found is a substring
314 * of other comment leaders. If it is, let's adjust the
315 * lower_check_bound so that we make sure that we have determined
316 * the comment leader correctly.
317 */
318
319 while (ascii_iswhite(*com_leader))
320 ++com_leader;
321 len1 = (int)STRLEN(com_leader);
322
323 for (list = curbuf->b_p_com; *list; ) {
324 char_u *flags_save = list;
325
326 (void)copy_option_part(&list, part_buf2, COM_MAX_LEN, ",");
327 if (flags_save == com_flags)
328 continue;
329 string = vim_strchr(part_buf2, ':');
330 ++string;
331 while (ascii_iswhite(*string))
332 ++string;
333 len2 = (int)STRLEN(string);
334 if (len2 == 0)
335 continue;
336
337 /* Now we have to verify whether string ends with a substring
338 * beginning the com_leader. */
339 for (off = (len2 > i ? i : len2); off > 0 && off + len1 > len2; ) {
340 --off;
341 if (!STRNCMP(string + off, com_leader, len2 - off)) {
342 if (i - off < lower_check_bound)
343 lower_check_bound = i - off;
344 }
345 }
346 }
347 }
348 }
349 return result;
350}
351
352/*
353 * Return the number of window lines occupied by buffer line "lnum".
354 */
355int plines(const linenr_T lnum)
356{
357 return plines_win(curwin, lnum, true);
358}
359
360int plines_win(
361 win_T *const wp,
362 const linenr_T lnum,
363 const bool winheight // when true limit to window height
364)
365{
366 /* Check for filler lines above this buffer line. When folded the result
367 * is one line anyway. */
368 return plines_win_nofill(wp, lnum, winheight) + diff_check_fill(wp, lnum);
369}
370
371int plines_nofill(const linenr_T lnum)
372{
373 return plines_win_nofill(curwin, lnum, true);
374}
375
376int plines_win_nofill(
377 win_T *const wp,
378 const linenr_T lnum,
379 const bool winheight // when true limit to window height
380)
381{
382 if (!wp->w_p_wrap) {
383 return 1;
384 }
385
386 if (wp->w_width_inner == 0) {
387 return 1;
388 }
389
390 // A folded lines is handled just like an empty line.
391 if (lineFolded(wp, lnum)) {
392 return 1;
393 }
394
395 const int lines = plines_win_nofold(wp, lnum);
396 if (winheight && lines > wp->w_height_inner) {
397 return wp->w_height_inner;
398 }
399 return lines;
400}
401
402/*
403 * Return number of window lines physical line "lnum" will occupy in window
404 * "wp". Does not care about folding, 'wrap' or 'diff'.
405 */
406int plines_win_nofold(win_T *wp, linenr_T lnum)
407{
408 char_u *s;
409 unsigned int col;
410 int width;
411
412 s = ml_get_buf(wp->w_buffer, lnum, FALSE);
413 if (*s == NUL) /* empty line */
414 return 1;
415 col = win_linetabsize(wp, s, (colnr_T)MAXCOL);
416
417 // If list mode is on, then the '$' at the end of the line may take up one
418 // extra column.
419 if (wp->w_p_list && wp->w_p_lcs_chars.eol != NUL) {
420 col += 1;
421 }
422
423 /*
424 * Add column offset for 'number', 'relativenumber' and 'foldcolumn'.
425 */
426 width = wp->w_width_inner - win_col_off(wp);
427 if (width <= 0 || col > 32000) {
428 return 32000; // bigger than the number of screen columns
429 }
430 if (col <= (unsigned int)width) {
431 return 1;
432 }
433 col -= (unsigned int)width;
434 width += win_col_off2(wp);
435 assert(col <= INT_MAX && (int)col < INT_MAX - (width -1));
436 return ((int)col + (width - 1)) / width + 1;
437}
438
439/*
440 * Like plines_win(), but only reports the number of physical screen lines
441 * used from the start of the line to the given column number.
442 */
443int plines_win_col(win_T *wp, linenr_T lnum, long column)
444{
445 // Check for filler lines above this buffer line. When folded the result
446 // is one line anyway.
447 int lines = diff_check_fill(wp, lnum);
448
449 if (!wp->w_p_wrap)
450 return lines + 1;
451
452 if (wp->w_width_inner == 0) {
453 return lines + 1;
454 }
455
456 char_u *line = ml_get_buf(wp->w_buffer, lnum, false);
457 char_u *s = line;
458
459 colnr_T col = 0;
460 while (*s != NUL && --column >= 0) {
461 col += win_lbr_chartabsize(wp, line, s, col, NULL);
462 MB_PTR_ADV(s);
463 }
464
465 // If *s is a TAB, and the TAB is not displayed as ^I, and we're not in
466 // INSERT mode, then col must be adjusted so that it represents the last
467 // screen position of the TAB. This only fixes an error when the TAB wraps
468 // from one screen line to the next (when 'columns' is not a multiple of
469 // 'ts') -- webb.
470 if (*s == TAB && (State & NORMAL)
471 && (!wp->w_p_list || wp->w_p_lcs_chars.tab1)) {
472 col += win_lbr_chartabsize(wp, line, s, col, NULL) - 1;
473 }
474
475 // Add column offset for 'number', 'relativenumber', 'foldcolumn', etc.
476 int width = wp->w_width_inner - win_col_off(wp);
477 if (width <= 0) {
478 return 9999;
479 }
480
481 lines += 1;
482 if (col > width)
483 lines += (col - width) / (width + win_col_off2(wp)) + 1;
484 return lines;
485}
486
487int plines_m_win(win_T *wp, linenr_T first, linenr_T last)
488{
489 int count = 0;
490
491 while (first <= last) {
492 // Check if there are any really folded lines, but also included lines
493 // that are maybe folded.
494 linenr_T x = foldedCount(wp, first, NULL);
495 if (x > 0) {
496 ++count; /* count 1 for "+-- folded" line */
497 first += x;
498 } else {
499 if (first == wp->w_topline) {
500 count += plines_win_nofill(wp, first, true) + wp->w_topfill;
501 } else {
502 count += plines_win(wp, first, true);
503 }
504 first++;
505 }
506 }
507 return count;
508}
509
510int gchar_pos(pos_T *pos)
511 FUNC_ATTR_NONNULL_ARG(1)
512{
513 // When searching columns is sometimes put at the end of a line.
514 if (pos->col == MAXCOL) {
515 return NUL;
516 }
517 return utf_ptr2char(ml_get_pos(pos));
518}
519
520/*
521 * check_status: called when the status bars for the buffer 'buf'
522 * need to be updated
523 */
524void check_status(buf_T *buf)
525{
526 FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
527 if (wp->w_buffer == buf && wp->w_status_height) {
528 wp->w_redr_status = TRUE;
529 if (must_redraw < VALID) {
530 must_redraw = VALID;
531 }
532 }
533 }
534}
535
536/// Ask for a reply from the user, 'y' or 'n'
537///
538/// No other characters are accepted, the message is repeated until a valid
539/// reply is entered or <C-c> is hit.
540///
541/// @param[in] str Prompt: question to ask user. Is always followed by
542/// " (y/n)?".
543/// @param[in] direct Determines what function to use to get user input. If
544/// true then ui_inchar() will be used, otherwise vgetc().
545/// I.e. when direct is true then characters are obtained
546/// directly from the user without buffers involved.
547///
548/// @return 'y' or 'n'. Last is also what will be returned in case of interrupt.
549int ask_yesno(const char *const str, const bool direct)
550{
551 const int save_State = State;
552
553 no_wait_return++;
554 State = CONFIRM; // Mouse behaves like with :confirm.
555 setmouse(); // Disable mouse in xterm.
556 no_mapping++;
557
558 int r = ' ';
559 while (r != 'y' && r != 'n') {
560 // Same highlighting as for wait_return.
561 smsg_attr(HL_ATTR(HLF_R), "%s (y/n)?", str);
562 if (direct) {
563 r = get_keystroke(NULL);
564 } else {
565 r = plain_vgetc();
566 }
567 if (r == Ctrl_C || r == ESC) {
568 r = 'n';
569 }
570 msg_putchar(r); // Show what you typed.
571 ui_flush();
572 }
573 no_wait_return--;
574 State = save_State;
575 setmouse();
576 no_mapping--;
577
578 return r;
579}
580
581/*
582 * Return TRUE if "c" is a mouse key.
583 */
584int is_mouse_key(int c)
585{
586 return c == K_LEFTMOUSE
587 || c == K_LEFTMOUSE_NM
588 || c == K_LEFTDRAG
589 || c == K_LEFTRELEASE
590 || c == K_LEFTRELEASE_NM
591 || c == K_MIDDLEMOUSE
592 || c == K_MIDDLEDRAG
593 || c == K_MIDDLERELEASE
594 || c == K_RIGHTMOUSE
595 || c == K_RIGHTDRAG
596 || c == K_RIGHTRELEASE
597 || c == K_MOUSEDOWN
598 || c == K_MOUSEUP
599 || c == K_MOUSELEFT
600 || c == K_MOUSERIGHT
601 || c == K_X1MOUSE
602 || c == K_X1DRAG
603 || c == K_X1RELEASE
604 || c == K_X2MOUSE
605 || c == K_X2DRAG
606 || c == K_X2RELEASE;
607}
608
609/*
610 * Get a key stroke directly from the user.
611 * Ignores mouse clicks and scrollbar events, except a click for the left
612 * button (used at the more prompt).
613 * Doesn't use vgetc(), because it syncs undo and eats mapped characters.
614 * Disadvantage: typeahead is ignored.
615 * Translates the interrupt character for unix to ESC.
616 */
617int get_keystroke(MultiQueue *events)
618{
619 char_u *buf = NULL;
620 int buflen = 150;
621 int maxlen;
622 int len = 0;
623 int n;
624 int save_mapped_ctrl_c = mapped_ctrl_c;
625 int waited = 0;
626
627 mapped_ctrl_c = 0; // mappings are not used here
628 for (;; ) {
629 // flush output before waiting
630 ui_flush();
631 /* Leave some room for check_termcode() to insert a key code into (max
632 * 5 chars plus NUL). And fix_input_buffer() can triple the number of
633 * bytes. */
634 maxlen = (buflen - 6 - len) / 3;
635 if (buf == NULL) {
636 buf = xmalloc((size_t)buflen);
637 } else if (maxlen < 10) {
638 // Need some more space. This might happen when receiving a long
639 // escape sequence.
640 buflen += 100;
641 buf = xrealloc(buf, (size_t)buflen);
642 maxlen = (buflen - 6 - len) / 3;
643 }
644
645 /* First time: blocking wait. Second time: wait up to 100ms for a
646 * terminal code to complete. */
647 n = os_inchar(buf + len, maxlen, len == 0 ? -1L : 100L, 0, events);
648 if (n > 0) {
649 // Replace zero and CSI by a special key code.
650 n = fix_input_buffer(buf + len, n);
651 len += n;
652 waited = 0;
653 } else if (len > 0)
654 ++waited; /* keep track of the waiting time */
655
656 if (n > 0) { // found a termcode: adjust length
657 len = n;
658 }
659 if (len == 0) { // nothing typed yet
660 continue;
661 }
662
663 /* Handle modifier and/or special key code. */
664 n = buf[0];
665 if (n == K_SPECIAL) {
666 n = TO_SPECIAL(buf[1], buf[2]);
667 if (buf[1] == KS_MODIFIER
668 || n == K_IGNORE
669 || (is_mouse_key(n) && n != K_LEFTMOUSE)
670 ) {
671 if (buf[1] == KS_MODIFIER)
672 mod_mask = buf[2];
673 len -= 3;
674 if (len > 0)
675 memmove(buf, buf + 3, (size_t)len);
676 continue;
677 }
678 break;
679 }
680 if (MB_BYTE2LEN(n) > len) {
681 // more bytes to get.
682 continue;
683 }
684 buf[len >= buflen ? buflen - 1 : len] = NUL;
685 n = utf_ptr2char(buf);
686 break;
687 }
688 xfree(buf);
689
690 mapped_ctrl_c = save_mapped_ctrl_c;
691 return n;
692}
693
694/*
695 * Get a number from the user.
696 * When "mouse_used" is not NULL allow using the mouse.
697 */
698int
699get_number (
700 int colon, /* allow colon to abort */
701 int *mouse_used
702)
703{
704 int n = 0;
705 int c;
706 int typed = 0;
707
708 if (mouse_used != NULL)
709 *mouse_used = FALSE;
710
711 /* When not printing messages, the user won't know what to type, return a
712 * zero (as if CR was hit). */
713 if (msg_silent != 0)
714 return 0;
715
716 no_mapping++;
717 for (;; ) {
718 ui_cursor_goto(msg_row, msg_col);
719 c = safe_vgetc();
720 if (ascii_isdigit(c)) {
721 n = n * 10 + c - '0';
722 msg_putchar(c);
723 ++typed;
724 } else if (c == K_DEL || c == K_KDEL || c == K_BS || c == Ctrl_H) {
725 if (typed > 0) {
726 MSG_PUTS("\b \b");
727 --typed;
728 }
729 n /= 10;
730 } else if (mouse_used != NULL && c == K_LEFTMOUSE) {
731 *mouse_used = TRUE;
732 n = mouse_row + 1;
733 break;
734 } else if (n == 0 && c == ':' && colon) {
735 stuffcharReadbuff(':');
736 if (!exmode_active)
737 cmdline_row = msg_row;
738 skip_redraw = TRUE; /* skip redraw once */
739 do_redraw = FALSE;
740 break;
741 } else if (c == CAR || c == NL || c == Ctrl_C || c == ESC)
742 break;
743 }
744 no_mapping--;
745 return n;
746}
747
748/*
749 * Ask the user to enter a number.
750 * When "mouse_used" is not NULL allow using the mouse and in that case return
751 * the line number.
752 */
753int prompt_for_number(int *mouse_used)
754{
755 int i;
756 int save_cmdline_row;
757 int save_State;
758
759 /* When using ":silent" assume that <CR> was entered. */
760 if (mouse_used != NULL)
761 MSG_PUTS(_("Type number and <Enter> or click with mouse (empty cancels): "));
762 else
763 MSG_PUTS(_("Type number and <Enter> (empty cancels): "));
764
765 /* Set the state such that text can be selected/copied/pasted and we still
766 * get mouse events. */
767 save_cmdline_row = cmdline_row;
768 cmdline_row = 0;
769 save_State = State;
770 State = ASKMORE; // prevents a screen update when using a timer
771 // May show different mouse shape.
772 setmouse();
773
774 i = get_number(TRUE, mouse_used);
775 if (KeyTyped) {
776 // don't call wait_return() now
777 if (msg_row > 0) {
778 cmdline_row = msg_row - 1;
779 }
780 need_wait_return = false;
781 msg_didany = false;
782 msg_didout = false;
783 } else {
784 cmdline_row = save_cmdline_row;
785 }
786 State = save_State;
787 // May need to restore mouse shape.
788 setmouse();
789
790 return i;
791}
792
793void msgmore(long n)
794{
795 long pn;
796
797 if (global_busy /* no messages now, wait until global is finished */
798 || !messaging()) /* 'lazyredraw' set, don't do messages now */
799 return;
800
801 /* We don't want to overwrite another important message, but do overwrite
802 * a previous "more lines" or "fewer lines" message, so that "5dd" and
803 * then "put" reports the last action. */
804 if (keep_msg != NULL && !keep_msg_more)
805 return;
806
807 if (n > 0)
808 pn = n;
809 else
810 pn = -n;
811
812 if (pn > p_report) {
813 if (pn == 1) {
814 if (n > 0)
815 STRLCPY(msg_buf, _("1 more line"), MSG_BUF_LEN);
816 else
817 STRLCPY(msg_buf, _("1 line less"), MSG_BUF_LEN);
818 } else {
819 if (n > 0)
820 vim_snprintf((char *)msg_buf, MSG_BUF_LEN,
821 _("%" PRId64 " more lines"), (int64_t)pn);
822 else
823 vim_snprintf((char *)msg_buf, MSG_BUF_LEN,
824 _("%" PRId64 " fewer lines"), (int64_t)pn);
825 }
826 if (got_int) {
827 xstrlcat((char *)msg_buf, _(" (Interrupted)"), MSG_BUF_LEN);
828 }
829 if (msg(msg_buf)) {
830 set_keep_msg(msg_buf, 0);
831 keep_msg_more = TRUE;
832 }
833 }
834}
835
836/*
837 * flush map and typeahead buffers and give a warning for an error
838 */
839void beep_flush(void)
840{
841 if (emsg_silent == 0) {
842 flush_buffers(FLUSH_MINIMAL);
843 vim_beep(BO_ERROR);
844 }
845}
846
847// Give a warning for an error
848// val is one of the BO_ values, e.g., BO_OPER
849void vim_beep(unsigned val)
850{
851 called_vim_beep = true;
852
853 if (emsg_silent == 0) {
854 if (!((bo_flags & val) || (bo_flags & BO_ALL))) {
855 static int beeps = 0;
856 static uint64_t start_time = 0;
857
858 // Only beep up to three times per half a second,
859 // otherwise a sequence of beeps would freeze Vim.
860 if (start_time == 0 || os_hrtime() - start_time > 500000000u) {
861 beeps = 0;
862 start_time = os_hrtime();
863 }
864 beeps++;
865 if (beeps <= 3) {
866 if (p_vb) {
867 ui_call_visual_bell();
868 } else {
869 ui_call_bell();
870 }
871 }
872 }
873
874 // When 'debug' contains "beep" produce a message. If we are sourcing
875 // a script or executing a function give the user a hint where the beep
876 // comes from.
877 if (vim_strchr(p_debug, 'e') != NULL) {
878 msg_source(HL_ATTR(HLF_W));
879 msg_attr(_("Beep!"), HL_ATTR(HLF_W));
880 }
881 }
882}
883
884#if defined(EXITFREE)
885
886void free_users(void)
887{
888 ga_clear_strings(&ga_users);
889}
890
891#endif
892
893/*
894 * Find all user names for user completion.
895 * Done only once and then cached.
896 */
897static void init_users(void)
898{
899 static int lazy_init_done = FALSE;
900
901 if (lazy_init_done) {
902 return;
903 }
904
905 lazy_init_done = TRUE;
906
907 os_get_usernames(&ga_users);
908}
909
910/*
911 * Function given to ExpandGeneric() to obtain an user names.
912 */
913char_u *get_users(expand_T *xp, int idx)
914{
915 init_users();
916 if (idx < ga_users.ga_len)
917 return ((char_u **)ga_users.ga_data)[idx];
918 return NULL;
919}
920
921/*
922 * Check whether name matches a user name. Return:
923 * 0 if name does not match any user name.
924 * 1 if name partially matches the beginning of a user name.
925 * 2 is name fully matches a user name.
926 */
927int match_user(char_u *name)
928{
929 int n = (int)STRLEN(name);
930 int result = 0;
931
932 init_users();
933 for (int i = 0; i < ga_users.ga_len; i++) {
934 if (STRCMP(((char_u **)ga_users.ga_data)[i], name) == 0)
935 return 2; /* full match */
936 if (STRNCMP(((char_u **)ga_users.ga_data)[i], name, n) == 0)
937 result = 1; /* partial match */
938 }
939 return result;
940}
941
942/// Preserve files and exit.
943/// @note IObuff must contain a message.
944/// @note This may be called from deadly_signal() in a signal handler, avoid
945/// unsafe functions, such as allocating memory.
946void preserve_exit(void)
947 FUNC_ATTR_NORETURN
948{
949 // 'true' when we are sure to exit, e.g., after a deadly signal
950 static bool really_exiting = false;
951
952 // Prevent repeated calls into this method.
953 if (really_exiting) {
954 if (input_global_fd() >= 0) {
955 // normalize stream (#2598)
956 stream_set_blocking(input_global_fd(), true);
957 }
958 exit(2);
959 }
960
961 really_exiting = true;
962 // Ignore SIGHUP while we are already exiting. #9274
963 signal_reject_deadly();
964 mch_errmsg(IObuff);
965 mch_errmsg("\n");
966 ui_flush();
967
968 ml_close_notmod(); // close all not-modified buffers
969
970 FOR_ALL_BUFFERS(buf) {
971 if (buf->b_ml.ml_mfp != NULL && buf->b_ml.ml_mfp->mf_fname != NULL) {
972 mch_errmsg((uint8_t *)"Vim: preserving files...\n");
973 ui_flush();
974 ml_sync_all(false, false, true); // preserve all swap files
975 break;
976 }
977 }
978
979 ml_close_all(false); // close all memfiles, without deleting
980
981 mch_errmsg("Vim: Finished.\n");
982
983 getout(1);
984}
985
986/*
987 * Check for CTRL-C pressed, but only once in a while.
988 * Should be used instead of os_breakcheck() for functions that check for
989 * each line in the file. Calling os_breakcheck() each time takes too much
990 * time, because it can be a system call.
991 */
992
993#ifndef BREAKCHECK_SKIP
994# define BREAKCHECK_SKIP 1000
995#endif
996
997static int breakcheck_count = 0;
998
999void line_breakcheck(void)
1000{
1001 if (++breakcheck_count >= BREAKCHECK_SKIP) {
1002 breakcheck_count = 0;
1003 os_breakcheck();
1004 }
1005}
1006
1007/*
1008 * Like line_breakcheck() but check 10 times less often.
1009 */
1010void fast_breakcheck(void)
1011{
1012 if (++breakcheck_count >= BREAKCHECK_SKIP * 10) {
1013 breakcheck_count = 0;
1014 os_breakcheck();
1015 }
1016}
1017
1018/// os_call_shell() wrapper. Handles 'verbose', :profile, and v:shell_error.
1019/// Invalidates cached tags.
1020///
1021/// @return shell command exit code
1022int call_shell(char_u *cmd, ShellOpts opts, char_u *extra_shell_arg)
1023{
1024 int retval;
1025 proftime_T wait_time;
1026
1027 if (p_verbose > 3) {
1028 verbose_enter();
1029 smsg(_("Executing command: \"%s\""), cmd == NULL ? p_sh : cmd);
1030 msg_putchar('\n');
1031 verbose_leave();
1032 }
1033
1034 if (do_profiling == PROF_YES) {
1035 prof_child_enter(&wait_time);
1036 }
1037
1038 if (*p_sh == NUL) {
1039 EMSG(_(e_shellempty));
1040 retval = -1;
1041 } else {
1042 // The external command may update a tags file, clear cached tags.
1043 tag_freematch();
1044
1045 retval = os_call_shell(cmd, opts, extra_shell_arg);
1046 }
1047
1048 set_vim_var_nr(VV_SHELL_ERROR, (varnumber_T)retval);
1049 if (do_profiling == PROF_YES) {
1050 prof_child_exit(&wait_time);
1051 }
1052
1053 return retval;
1054}
1055
1056/// Get the stdout of an external command.
1057/// If "ret_len" is NULL replace NUL characters with NL. When "ret_len" is not
1058/// NULL store the length there.
1059///
1060/// @param cmd command to execute
1061/// @param infile optional input file name
1062/// @param flags can be kShellOptSilent or 0
1063/// @param ret_len length of the stdout
1064///
1065/// @return an allocated string, or NULL for error.
1066char_u *get_cmd_output(char_u *cmd, char_u *infile, ShellOpts flags,
1067 size_t *ret_len)
1068{
1069 char_u *buffer = NULL;
1070
1071 if (check_restricted() || check_secure())
1072 return NULL;
1073
1074 // get a name for the temp file
1075 char_u *tempname = vim_tempname();
1076 if (tempname == NULL) {
1077 EMSG(_(e_notmp));
1078 return NULL;
1079 }
1080
1081 // Add the redirection stuff
1082 char_u *command = make_filter_cmd(cmd, infile, tempname);
1083
1084 /*
1085 * Call the shell to execute the command (errors are ignored).
1086 * Don't check timestamps here.
1087 */
1088 ++no_check_timestamps;
1089 call_shell(command, kShellOptDoOut | kShellOptExpand | flags, NULL);
1090 --no_check_timestamps;
1091
1092 xfree(command);
1093
1094 // read the names from the file into memory
1095 FILE *fd = os_fopen((char *)tempname, READBIN);
1096
1097 if (fd == NULL) {
1098 EMSG2(_(e_notopen), tempname);
1099 goto done;
1100 }
1101
1102 fseek(fd, 0L, SEEK_END);
1103 size_t len = (size_t)ftell(fd); // get size of temp file
1104 fseek(fd, 0L, SEEK_SET);
1105
1106 buffer = xmalloc(len + 1);
1107 size_t i = fread((char *)buffer, 1, len, fd);
1108 fclose(fd);
1109 os_remove((char *)tempname);
1110 if (i != len) {
1111 EMSG2(_(e_notread), tempname);
1112 XFREE_CLEAR(buffer);
1113 } else if (ret_len == NULL) {
1114 /* Change NUL into SOH, otherwise the string is truncated. */
1115 for (i = 0; i < len; ++i)
1116 if (buffer[i] == NUL)
1117 buffer[i] = 1;
1118
1119 buffer[len] = NUL; /* make sure the buffer is terminated */
1120 } else {
1121 *ret_len = len;
1122 }
1123
1124done:
1125 xfree(tempname);
1126 return buffer;
1127}
1128
1129/*
1130 * Free the list of files returned by expand_wildcards() or other expansion
1131 * functions.
1132 */
1133void FreeWild(int count, char_u **files)
1134{
1135 if (count <= 0 || files == NULL)
1136 return;
1137 while (count--)
1138 xfree(files[count]);
1139 xfree(files);
1140}
1141
1142/*
1143 * Return TRUE when need to go to Insert mode because of 'insertmode'.
1144 * Don't do this when still processing a command or a mapping.
1145 * Don't do this when inside a ":normal" command.
1146 */
1147int goto_im(void)
1148{
1149 return p_im && stuff_empty() && typebuf_typed();
1150}
1151