1edf3f97aSBram Moolenaar /* vi:set ts=8 sts=4 sw=4 noet:
2071d4279SBram Moolenaar *
3071d4279SBram Moolenaar * VIM - Vi IMproved by Bram Moolenaar
4071d4279SBram Moolenaar *
5071d4279SBram Moolenaar * Do ":help uganda" in Vim to read copying and usage conditions.
6071d4279SBram Moolenaar * Do ":help credits" in Vim to see a list of people who contributed.
7071d4279SBram Moolenaar * See README.txt for an overview of the Vim source code.
8071d4279SBram Moolenaar */
9071d4279SBram Moolenaar
10071d4279SBram Moolenaar /*
11071d4279SBram Moolenaar * misc1.c: functions that didn't seem to fit elsewhere
12071d4279SBram Moolenaar */
13071d4279SBram Moolenaar
14071d4279SBram Moolenaar #include "vim.h"
15071d4279SBram Moolenaar #include "version.h"
16071d4279SBram Moolenaar
17b3f74069SBram Moolenaar #if defined(__HAIKU__)
18b3f74069SBram Moolenaar # include <storage/FindDirectory.h>
19b3f74069SBram Moolenaar #endif
20b3f74069SBram Moolenaar
210a52df50SBram Moolenaar #if defined(MSWIN)
22828c3d70SBram Moolenaar # include <lm.h>
23828c3d70SBram Moolenaar #endif
24828c3d70SBram Moolenaar
2585a2002aSBram Moolenaar #define URL_SLASH 1 // path_is_url() has found "://"
2685a2002aSBram Moolenaar #define URL_BACKSLASH 2 // path_is_url() has found ":\\"
275fd0f505SBram Moolenaar
280a52df50SBram Moolenaar // All user names (for ~user completion as done by shell).
2924305866SBram Moolenaar static garray_T ga_users;
3024305866SBram Moolenaar
31071d4279SBram Moolenaar /*
322c019c86SBram Moolenaar * get_leader_len() returns the length in bytes of the prefix of the given
332c019c86SBram Moolenaar * string which introduces a comment. If this string is not a comment then
342c019c86SBram Moolenaar * 0 is returned.
35071d4279SBram Moolenaar * When "flags" is not NULL, it is set to point to the flags of the recognized
36071d4279SBram Moolenaar * comment leader.
37071d4279SBram Moolenaar * "backward" must be true for the "O" command.
3881340397SBram Moolenaar * If "include_space" is set, include trailing whitespace while calculating the
3981340397SBram Moolenaar * length.
40071d4279SBram Moolenaar */
41071d4279SBram Moolenaar int
get_leader_len(char_u * line,char_u ** flags,int backward,int include_space)429b57814dSBram Moolenaar get_leader_len(
439b57814dSBram Moolenaar char_u *line,
449b57814dSBram Moolenaar char_u **flags,
459b57814dSBram Moolenaar int backward,
469b57814dSBram Moolenaar int include_space)
47071d4279SBram Moolenaar {
48071d4279SBram Moolenaar int i, j;
4981340397SBram Moolenaar int result;
50071d4279SBram Moolenaar int got_com = FALSE;
51071d4279SBram Moolenaar int found_one;
5285a2002aSBram Moolenaar char_u part_buf[COM_MAX_LEN]; // buffer for one option part
5385a2002aSBram Moolenaar char_u *string; // pointer to comment string
54071d4279SBram Moolenaar char_u *list;
55a4271d59SBram Moolenaar int middle_match_len = 0;
56a4271d59SBram Moolenaar char_u *prev_list;
5705da4284SBram Moolenaar char_u *saved_flags = NULL;
58071d4279SBram Moolenaar
5981340397SBram Moolenaar result = i = 0;
6085a2002aSBram Moolenaar while (VIM_ISWHITE(line[i])) // leading white space is ignored
61071d4279SBram Moolenaar ++i;
62071d4279SBram Moolenaar
63071d4279SBram Moolenaar /*
64071d4279SBram Moolenaar * Repeat to match several nested comment strings.
65071d4279SBram Moolenaar */
66a4271d59SBram Moolenaar while (line[i] != NUL)
67071d4279SBram Moolenaar {
68071d4279SBram Moolenaar /*
69071d4279SBram Moolenaar * scan through the 'comments' option for a match
70071d4279SBram Moolenaar */
71071d4279SBram Moolenaar found_one = FALSE;
72071d4279SBram Moolenaar for (list = curbuf->b_p_com; *list; )
73071d4279SBram Moolenaar {
7485a2002aSBram Moolenaar // Get one option part into part_buf[]. Advance "list" to next
7585a2002aSBram Moolenaar // one. Put "string" at start of string.
76a4271d59SBram Moolenaar if (!got_com && flags != NULL)
7785a2002aSBram Moolenaar *flags = list; // remember where flags started
78a4271d59SBram Moolenaar prev_list = list;
79071d4279SBram Moolenaar (void)copy_option_part(&list, part_buf, COM_MAX_LEN, ",");
80071d4279SBram Moolenaar string = vim_strchr(part_buf, ':');
8185a2002aSBram Moolenaar if (string == NULL) // missing ':', ignore this part
82071d4279SBram Moolenaar continue;
8385a2002aSBram Moolenaar *string++ = NUL; // isolate flags from string
84071d4279SBram Moolenaar
8585a2002aSBram Moolenaar // If we found a middle match previously, use that match when this
8685a2002aSBram Moolenaar // is not a middle or end.
87a4271d59SBram Moolenaar if (middle_match_len != 0
88a4271d59SBram Moolenaar && vim_strchr(part_buf, COM_MIDDLE) == NULL
89a4271d59SBram Moolenaar && vim_strchr(part_buf, COM_END) == NULL)
90a4271d59SBram Moolenaar break;
91a4271d59SBram Moolenaar
9285a2002aSBram Moolenaar // When we already found a nested comment, only accept further
9385a2002aSBram Moolenaar // nested comments.
94071d4279SBram Moolenaar if (got_com && vim_strchr(part_buf, COM_NEST) == NULL)
95071d4279SBram Moolenaar continue;
96071d4279SBram Moolenaar
9785a2002aSBram Moolenaar // When 'O' flag present and using "O" command skip this one.
98071d4279SBram Moolenaar if (backward && vim_strchr(part_buf, COM_NOBACK) != NULL)
99071d4279SBram Moolenaar continue;
100071d4279SBram Moolenaar
10185a2002aSBram Moolenaar // Line contents and string must match.
10285a2002aSBram Moolenaar // When string starts with white space, must have some white space
10385a2002aSBram Moolenaar // (but the amount does not need to match, there might be a mix of
10485a2002aSBram Moolenaar // TABs and spaces).
1051c465444SBram Moolenaar if (VIM_ISWHITE(string[0]))
106071d4279SBram Moolenaar {
1071c465444SBram Moolenaar if (i == 0 || !VIM_ISWHITE(line[i - 1]))
10885a2002aSBram Moolenaar continue; // missing white space
1091c465444SBram Moolenaar while (VIM_ISWHITE(string[0]))
110071d4279SBram Moolenaar ++string;
111071d4279SBram Moolenaar }
112071d4279SBram Moolenaar for (j = 0; string[j] != NUL && string[j] == line[i + j]; ++j)
113071d4279SBram Moolenaar ;
114071d4279SBram Moolenaar if (string[j] != NUL)
11585a2002aSBram Moolenaar continue; // string doesn't match
116071d4279SBram Moolenaar
11785a2002aSBram Moolenaar // When 'b' flag used, there must be white space or an
11885a2002aSBram Moolenaar // end-of-line after the string in the line.
119071d4279SBram Moolenaar if (vim_strchr(part_buf, COM_BLANK) != NULL
1201c465444SBram Moolenaar && !VIM_ISWHITE(line[i + j]) && line[i + j] != NUL)
121071d4279SBram Moolenaar continue;
122071d4279SBram Moolenaar
12385a2002aSBram Moolenaar // We have found a match, stop searching unless this is a middle
12485a2002aSBram Moolenaar // comment. The middle comment can be a substring of the end
12585a2002aSBram Moolenaar // comment in which case it's better to return the length of the
12685a2002aSBram Moolenaar // end comment and its flags. Thus we keep searching with middle
12785a2002aSBram Moolenaar // and end matches and use an end match if it matches better.
128a4271d59SBram Moolenaar if (vim_strchr(part_buf, COM_MIDDLE) != NULL)
129a4271d59SBram Moolenaar {
130a4271d59SBram Moolenaar if (middle_match_len == 0)
131a4271d59SBram Moolenaar {
132a4271d59SBram Moolenaar middle_match_len = j;
133a4271d59SBram Moolenaar saved_flags = prev_list;
134a4271d59SBram Moolenaar }
135a4271d59SBram Moolenaar continue;
136a4271d59SBram Moolenaar }
137a4271d59SBram Moolenaar if (middle_match_len != 0 && j > middle_match_len)
13885a2002aSBram Moolenaar // Use this match instead of the middle match, since it's a
13985a2002aSBram Moolenaar // longer thus better match.
140a4271d59SBram Moolenaar middle_match_len = 0;
141a4271d59SBram Moolenaar
142a4271d59SBram Moolenaar if (middle_match_len == 0)
143071d4279SBram Moolenaar i += j;
144071d4279SBram Moolenaar found_one = TRUE;
145071d4279SBram Moolenaar break;
146071d4279SBram Moolenaar }
147071d4279SBram Moolenaar
148a4271d59SBram Moolenaar if (middle_match_len != 0)
149a4271d59SBram Moolenaar {
15085a2002aSBram Moolenaar // Use the previously found middle match after failing to find a
15185a2002aSBram Moolenaar // match with an end.
152a4271d59SBram Moolenaar if (!got_com && flags != NULL)
153a4271d59SBram Moolenaar *flags = saved_flags;
154a4271d59SBram Moolenaar i += middle_match_len;
155a4271d59SBram Moolenaar found_one = TRUE;
156a4271d59SBram Moolenaar }
157a4271d59SBram Moolenaar
15885a2002aSBram Moolenaar // No match found, stop scanning.
159071d4279SBram Moolenaar if (!found_one)
160071d4279SBram Moolenaar break;
161071d4279SBram Moolenaar
16281340397SBram Moolenaar result = i;
16381340397SBram Moolenaar
16485a2002aSBram Moolenaar // Include any trailing white space.
1651c465444SBram Moolenaar while (VIM_ISWHITE(line[i]))
166071d4279SBram Moolenaar ++i;
167071d4279SBram Moolenaar
16881340397SBram Moolenaar if (include_space)
16981340397SBram Moolenaar result = i;
17081340397SBram Moolenaar
17185a2002aSBram Moolenaar // If this comment doesn't nest, stop here.
172a4271d59SBram Moolenaar got_com = TRUE;
173071d4279SBram Moolenaar if (vim_strchr(part_buf, COM_NEST) == NULL)
174071d4279SBram Moolenaar break;
175071d4279SBram Moolenaar }
17681340397SBram Moolenaar return result;
17781340397SBram Moolenaar }
178a4271d59SBram Moolenaar
17981340397SBram Moolenaar /*
18081340397SBram Moolenaar * Return the offset at which the last comment in line starts. If there is no
18181340397SBram Moolenaar * comment in the whole line, -1 is returned.
18281340397SBram Moolenaar *
18381340397SBram Moolenaar * When "flags" is not null, it is set to point to the flags describing the
18481340397SBram Moolenaar * recognized comment leader.
18581340397SBram Moolenaar */
18681340397SBram Moolenaar int
get_last_leader_offset(char_u * line,char_u ** flags)1879b57814dSBram Moolenaar get_last_leader_offset(char_u *line, char_u **flags)
18881340397SBram Moolenaar {
18981340397SBram Moolenaar int result = -1;
19081340397SBram Moolenaar int i, j;
19181340397SBram Moolenaar int lower_check_bound = 0;
19281340397SBram Moolenaar char_u *string;
19381340397SBram Moolenaar char_u *com_leader;
19481340397SBram Moolenaar char_u *com_flags;
19581340397SBram Moolenaar char_u *list;
19681340397SBram Moolenaar int found_one;
19785a2002aSBram Moolenaar char_u part_buf[COM_MAX_LEN]; // buffer for one option part
19881340397SBram Moolenaar
19981340397SBram Moolenaar /*
20081340397SBram Moolenaar * Repeat to match several nested comment strings.
20181340397SBram Moolenaar */
20281340397SBram Moolenaar i = (int)STRLEN(line);
20381340397SBram Moolenaar while (--i >= lower_check_bound)
20481340397SBram Moolenaar {
20581340397SBram Moolenaar /*
20681340397SBram Moolenaar * scan through the 'comments' option for a match
20781340397SBram Moolenaar */
20881340397SBram Moolenaar found_one = FALSE;
20981340397SBram Moolenaar for (list = curbuf->b_p_com; *list; )
21081340397SBram Moolenaar {
21181340397SBram Moolenaar char_u *flags_save = list;
21281340397SBram Moolenaar
21381340397SBram Moolenaar /*
21481340397SBram Moolenaar * Get one option part into part_buf[]. Advance list to next one.
21581340397SBram Moolenaar * put string at start of string.
21681340397SBram Moolenaar */
21781340397SBram Moolenaar (void)copy_option_part(&list, part_buf, COM_MAX_LEN, ",");
21881340397SBram Moolenaar string = vim_strchr(part_buf, ':');
21985a2002aSBram Moolenaar if (string == NULL) // If everything is fine, this cannot actually
22085a2002aSBram Moolenaar // happen.
22181340397SBram Moolenaar continue;
22285a2002aSBram Moolenaar *string++ = NUL; // Isolate flags from string.
22381340397SBram Moolenaar com_leader = string;
22481340397SBram Moolenaar
22581340397SBram Moolenaar /*
22681340397SBram Moolenaar * Line contents and string must match.
22781340397SBram Moolenaar * When string starts with white space, must have some white space
22881340397SBram Moolenaar * (but the amount does not need to match, there might be a mix of
22981340397SBram Moolenaar * TABs and spaces).
23081340397SBram Moolenaar */
2311c465444SBram Moolenaar if (VIM_ISWHITE(string[0]))
23281340397SBram Moolenaar {
2331c465444SBram Moolenaar if (i == 0 || !VIM_ISWHITE(line[i - 1]))
23481340397SBram Moolenaar continue;
23553932819SBram Moolenaar while (VIM_ISWHITE(*string))
23681340397SBram Moolenaar ++string;
23781340397SBram Moolenaar }
23881340397SBram Moolenaar for (j = 0; string[j] != NUL && string[j] == line[i + j]; ++j)
23981340397SBram Moolenaar /* do nothing */;
24081340397SBram Moolenaar if (string[j] != NUL)
24181340397SBram Moolenaar continue;
24281340397SBram Moolenaar
24381340397SBram Moolenaar /*
24481340397SBram Moolenaar * When 'b' flag used, there must be white space or an
24581340397SBram Moolenaar * end-of-line after the string in the line.
24681340397SBram Moolenaar */
24781340397SBram Moolenaar if (vim_strchr(part_buf, COM_BLANK) != NULL
2481c465444SBram Moolenaar && !VIM_ISWHITE(line[i + j]) && line[i + j] != NUL)
24953932819SBram Moolenaar continue;
25053932819SBram Moolenaar
2514af7259bSBram Moolenaar if (vim_strchr(part_buf, COM_MIDDLE) != NULL)
25281340397SBram Moolenaar {
2534af7259bSBram Moolenaar // For a middlepart comment, only consider it to match if
2544af7259bSBram Moolenaar // everything before the current position in the line is
2554af7259bSBram Moolenaar // whitespace. Otherwise we would think we are inside a
2564af7259bSBram Moolenaar // comment if the middle part appears somewhere in the middle
2574af7259bSBram Moolenaar // of the line. E.g. for C the "*" appears often.
25853932819SBram Moolenaar for (j = 0; VIM_ISWHITE(line[j]) && j <= i; j++)
25953932819SBram Moolenaar ;
26053932819SBram Moolenaar if (j < i)
26181340397SBram Moolenaar continue;
26281340397SBram Moolenaar }
26381340397SBram Moolenaar
26481340397SBram Moolenaar /*
26581340397SBram Moolenaar * We have found a match, stop searching.
26681340397SBram Moolenaar */
26781340397SBram Moolenaar found_one = TRUE;
26881340397SBram Moolenaar
26981340397SBram Moolenaar if (flags)
27081340397SBram Moolenaar *flags = flags_save;
27181340397SBram Moolenaar com_flags = flags_save;
27281340397SBram Moolenaar
27381340397SBram Moolenaar break;
27481340397SBram Moolenaar }
27581340397SBram Moolenaar
27681340397SBram Moolenaar if (found_one)
27781340397SBram Moolenaar {
27885a2002aSBram Moolenaar char_u part_buf2[COM_MAX_LEN]; // buffer for one option part
27981340397SBram Moolenaar int len1, len2, off;
28081340397SBram Moolenaar
28181340397SBram Moolenaar result = i;
28281340397SBram Moolenaar /*
28381340397SBram Moolenaar * If this comment nests, continue searching.
28481340397SBram Moolenaar */
28581340397SBram Moolenaar if (vim_strchr(part_buf, COM_NEST) != NULL)
28681340397SBram Moolenaar continue;
28781340397SBram Moolenaar
28881340397SBram Moolenaar lower_check_bound = i;
28981340397SBram Moolenaar
29085a2002aSBram Moolenaar // Let's verify whether the comment leader found is a substring
29185a2002aSBram Moolenaar // of other comment leaders. If it is, let's adjust the
29285a2002aSBram Moolenaar // lower_check_bound so that we make sure that we have determined
29385a2002aSBram Moolenaar // the comment leader correctly.
29481340397SBram Moolenaar
2951c465444SBram Moolenaar while (VIM_ISWHITE(*com_leader))
29681340397SBram Moolenaar ++com_leader;
29781340397SBram Moolenaar len1 = (int)STRLEN(com_leader);
29881340397SBram Moolenaar
29981340397SBram Moolenaar for (list = curbuf->b_p_com; *list; )
30081340397SBram Moolenaar {
30181340397SBram Moolenaar char_u *flags_save = list;
30281340397SBram Moolenaar
30381340397SBram Moolenaar (void)copy_option_part(&list, part_buf2, COM_MAX_LEN, ",");
30481340397SBram Moolenaar if (flags_save == com_flags)
30581340397SBram Moolenaar continue;
30681340397SBram Moolenaar string = vim_strchr(part_buf2, ':');
30781340397SBram Moolenaar ++string;
3081c465444SBram Moolenaar while (VIM_ISWHITE(*string))
30981340397SBram Moolenaar ++string;
31081340397SBram Moolenaar len2 = (int)STRLEN(string);
31181340397SBram Moolenaar if (len2 == 0)
31281340397SBram Moolenaar continue;
31381340397SBram Moolenaar
31485a2002aSBram Moolenaar // Now we have to verify whether string ends with a substring
31585a2002aSBram Moolenaar // beginning the com_leader.
31681340397SBram Moolenaar for (off = (len2 > i ? i : len2); off > 0 && off + len1 > len2;)
31781340397SBram Moolenaar {
31881340397SBram Moolenaar --off;
31981340397SBram Moolenaar if (!STRNCMP(string + off, com_leader, len2 - off))
32081340397SBram Moolenaar {
32181340397SBram Moolenaar if (i - off < lower_check_bound)
32281340397SBram Moolenaar lower_check_bound = i - off;
32381340397SBram Moolenaar }
32481340397SBram Moolenaar }
32581340397SBram Moolenaar }
32681340397SBram Moolenaar }
32781340397SBram Moolenaar }
32881340397SBram Moolenaar return result;
329071d4279SBram Moolenaar }
330071d4279SBram Moolenaar
331071d4279SBram Moolenaar /*
332071d4279SBram Moolenaar * Return the number of window lines occupied by buffer line "lnum".
333071d4279SBram Moolenaar */
334071d4279SBram Moolenaar int
plines(linenr_T lnum)3359b57814dSBram Moolenaar plines(linenr_T lnum)
336071d4279SBram Moolenaar {
337071d4279SBram Moolenaar return plines_win(curwin, lnum, TRUE);
338071d4279SBram Moolenaar }
339071d4279SBram Moolenaar
340071d4279SBram Moolenaar int
plines_win(win_T * wp,linenr_T lnum,int winheight)3419b57814dSBram Moolenaar plines_win(
3429b57814dSBram Moolenaar win_T *wp,
3439b57814dSBram Moolenaar linenr_T lnum,
34485a2002aSBram Moolenaar int winheight) // when TRUE limit to window height
345071d4279SBram Moolenaar {
346071d4279SBram Moolenaar #if defined(FEAT_DIFF) || defined(PROTO)
34785a2002aSBram Moolenaar // Check for filler lines above this buffer line. When folded the result
34885a2002aSBram Moolenaar // is one line anyway.
349071d4279SBram Moolenaar return plines_win_nofill(wp, lnum, winheight) + diff_check_fill(wp, lnum);
350071d4279SBram Moolenaar }
351071d4279SBram Moolenaar
352071d4279SBram Moolenaar int
plines_nofill(linenr_T lnum)3539b57814dSBram Moolenaar plines_nofill(linenr_T lnum)
354071d4279SBram Moolenaar {
355071d4279SBram Moolenaar return plines_win_nofill(curwin, lnum, TRUE);
356071d4279SBram Moolenaar }
357071d4279SBram Moolenaar
358071d4279SBram Moolenaar int
plines_win_nofill(win_T * wp,linenr_T lnum,int winheight)3599b57814dSBram Moolenaar plines_win_nofill(
3609b57814dSBram Moolenaar win_T *wp,
3619b57814dSBram Moolenaar linenr_T lnum,
36285a2002aSBram Moolenaar int winheight) // when TRUE limit to window height
363071d4279SBram Moolenaar {
364071d4279SBram Moolenaar #endif
365071d4279SBram Moolenaar int lines;
366071d4279SBram Moolenaar
367071d4279SBram Moolenaar if (!wp->w_p_wrap)
368071d4279SBram Moolenaar return 1;
369071d4279SBram Moolenaar
370071d4279SBram Moolenaar if (wp->w_width == 0)
371071d4279SBram Moolenaar return 1;
372071d4279SBram Moolenaar
373071d4279SBram Moolenaar #ifdef FEAT_FOLDING
37485a2002aSBram Moolenaar // A folded lines is handled just like an empty line.
37585a2002aSBram Moolenaar // NOTE: Caller must handle lines that are MAYBE folded.
376071d4279SBram Moolenaar if (lineFolded(wp, lnum) == TRUE)
377071d4279SBram Moolenaar return 1;
378071d4279SBram Moolenaar #endif
379071d4279SBram Moolenaar
380071d4279SBram Moolenaar lines = plines_win_nofold(wp, lnum);
381071d4279SBram Moolenaar if (winheight > 0 && lines > wp->w_height)
382071d4279SBram Moolenaar return (int)wp->w_height;
383071d4279SBram Moolenaar return lines;
384071d4279SBram Moolenaar }
385071d4279SBram Moolenaar
386071d4279SBram Moolenaar /*
387071d4279SBram Moolenaar * Return number of window lines physical line "lnum" will occupy in window
388071d4279SBram Moolenaar * "wp". Does not care about folding, 'wrap' or 'diff'.
389071d4279SBram Moolenaar */
390071d4279SBram Moolenaar int
plines_win_nofold(win_T * wp,linenr_T lnum)3919b57814dSBram Moolenaar plines_win_nofold(win_T *wp, linenr_T lnum)
392071d4279SBram Moolenaar {
393071d4279SBram Moolenaar char_u *s;
394071d4279SBram Moolenaar long col;
395071d4279SBram Moolenaar int width;
396071d4279SBram Moolenaar
397071d4279SBram Moolenaar s = ml_get_buf(wp->w_buffer, lnum, FALSE);
39885a2002aSBram Moolenaar if (*s == NUL) // empty line
399071d4279SBram Moolenaar return 1;
400071d4279SBram Moolenaar col = win_linetabsize(wp, s, (colnr_T)MAXCOL);
401071d4279SBram Moolenaar
402071d4279SBram Moolenaar /*
403071d4279SBram Moolenaar * If list mode is on, then the '$' at the end of the line may take up one
404071d4279SBram Moolenaar * extra column.
405071d4279SBram Moolenaar */
406eed9d462SBram Moolenaar if (wp->w_p_list && wp->w_lcs_chars.eol != NUL)
407071d4279SBram Moolenaar col += 1;
408071d4279SBram Moolenaar
409071d4279SBram Moolenaar /*
41064486671SBram Moolenaar * Add column offset for 'number', 'relativenumber' and 'foldcolumn'.
411071d4279SBram Moolenaar */
4120263146bSBram Moolenaar width = wp->w_width - win_col_off(wp);
413071d4279SBram Moolenaar if (width <= 0)
414071d4279SBram Moolenaar return 32000;
415071d4279SBram Moolenaar if (col <= width)
416071d4279SBram Moolenaar return 1;
417071d4279SBram Moolenaar col -= width;
418071d4279SBram Moolenaar width += win_col_off2(wp);
419071d4279SBram Moolenaar return (col + (width - 1)) / width + 1;
420071d4279SBram Moolenaar }
421071d4279SBram Moolenaar
422071d4279SBram Moolenaar /*
423071d4279SBram Moolenaar * Like plines_win(), but only reports the number of physical screen lines
424071d4279SBram Moolenaar * used from the start of the line to the given column number.
425071d4279SBram Moolenaar */
426071d4279SBram Moolenaar int
plines_win_col(win_T * wp,linenr_T lnum,long column)4279b57814dSBram Moolenaar plines_win_col(win_T *wp, linenr_T lnum, long column)
428071d4279SBram Moolenaar {
429071d4279SBram Moolenaar long col;
430071d4279SBram Moolenaar char_u *s;
431071d4279SBram Moolenaar int lines = 0;
432071d4279SBram Moolenaar int width;
433597a4224SBram Moolenaar char_u *line;
434071d4279SBram Moolenaar
435071d4279SBram Moolenaar #ifdef FEAT_DIFF
43685a2002aSBram Moolenaar // Check for filler lines above this buffer line. When folded the result
43785a2002aSBram Moolenaar // is one line anyway.
438071d4279SBram Moolenaar lines = diff_check_fill(wp, lnum);
439071d4279SBram Moolenaar #endif
440071d4279SBram Moolenaar
441071d4279SBram Moolenaar if (!wp->w_p_wrap)
442071d4279SBram Moolenaar return lines + 1;
443071d4279SBram Moolenaar
444071d4279SBram Moolenaar if (wp->w_width == 0)
445071d4279SBram Moolenaar return lines + 1;
446071d4279SBram Moolenaar
447597a4224SBram Moolenaar line = s = ml_get_buf(wp->w_buffer, lnum, FALSE);
448071d4279SBram Moolenaar
449071d4279SBram Moolenaar col = 0;
450071d4279SBram Moolenaar while (*s != NUL && --column >= 0)
451071d4279SBram Moolenaar {
452597a4224SBram Moolenaar col += win_lbr_chartabsize(wp, line, s, (colnr_T)col, NULL);
45391acfffcSBram Moolenaar MB_PTR_ADV(s);
454071d4279SBram Moolenaar }
455071d4279SBram Moolenaar
456071d4279SBram Moolenaar /*
457071d4279SBram Moolenaar * If *s is a TAB, and the TAB is not displayed as ^I, and we're not in
458071d4279SBram Moolenaar * INSERT mode, then col must be adjusted so that it represents the last
459071d4279SBram Moolenaar * screen position of the TAB. This only fixes an error when the TAB wraps
460071d4279SBram Moolenaar * from one screen line to the next (when 'columns' is not a multiple of
461071d4279SBram Moolenaar * 'ts') -- webb.
462071d4279SBram Moolenaar */
463eed9d462SBram Moolenaar if (*s == TAB && (State & NORMAL) && (!wp->w_p_list ||
464eed9d462SBram Moolenaar wp->w_lcs_chars.tab1))
465597a4224SBram Moolenaar col += win_lbr_chartabsize(wp, line, s, (colnr_T)col, NULL) - 1;
466071d4279SBram Moolenaar
467071d4279SBram Moolenaar /*
46864486671SBram Moolenaar * Add column offset for 'number', 'relativenumber', 'foldcolumn', etc.
469071d4279SBram Moolenaar */
4700263146bSBram Moolenaar width = wp->w_width - win_col_off(wp);
47126470639SBram Moolenaar if (width <= 0)
47226470639SBram Moolenaar return 9999;
47326470639SBram Moolenaar
474071d4279SBram Moolenaar lines += 1;
47526470639SBram Moolenaar if (col > width)
47626470639SBram Moolenaar lines += (col - width) / (width + win_col_off2(wp)) + 1;
477071d4279SBram Moolenaar return lines;
478071d4279SBram Moolenaar }
479071d4279SBram Moolenaar
480071d4279SBram Moolenaar int
plines_m_win(win_T * wp,linenr_T first,linenr_T last)4819b57814dSBram Moolenaar plines_m_win(win_T *wp, linenr_T first, linenr_T last)
482071d4279SBram Moolenaar {
483071d4279SBram Moolenaar int count = 0;
484071d4279SBram Moolenaar
485071d4279SBram Moolenaar while (first <= last)
486071d4279SBram Moolenaar {
487071d4279SBram Moolenaar #ifdef FEAT_FOLDING
488071d4279SBram Moolenaar int x;
489071d4279SBram Moolenaar
49085a2002aSBram Moolenaar // Check if there are any really folded lines, but also included lines
49185a2002aSBram Moolenaar // that are maybe folded.
492071d4279SBram Moolenaar x = foldedCount(wp, first, NULL);
493071d4279SBram Moolenaar if (x > 0)
494071d4279SBram Moolenaar {
49585a2002aSBram Moolenaar ++count; // count 1 for "+-- folded" line
496071d4279SBram Moolenaar first += x;
497071d4279SBram Moolenaar }
498071d4279SBram Moolenaar else
499071d4279SBram Moolenaar #endif
500071d4279SBram Moolenaar {
501071d4279SBram Moolenaar #ifdef FEAT_DIFF
502071d4279SBram Moolenaar if (first == wp->w_topline)
503071d4279SBram Moolenaar count += plines_win_nofill(wp, first, TRUE) + wp->w_topfill;
504071d4279SBram Moolenaar else
505071d4279SBram Moolenaar #endif
506071d4279SBram Moolenaar count += plines_win(wp, first, TRUE);
507071d4279SBram Moolenaar ++first;
508071d4279SBram Moolenaar }
509071d4279SBram Moolenaar }
510071d4279SBram Moolenaar return (count);
511071d4279SBram Moolenaar }
512071d4279SBram Moolenaar
513071d4279SBram Moolenaar int
gchar_pos(pos_T * pos)5149b57814dSBram Moolenaar gchar_pos(pos_T *pos)
515071d4279SBram Moolenaar {
5168ada6aa9SBram Moolenaar char_u *ptr;
517071d4279SBram Moolenaar
51885a2002aSBram Moolenaar // When searching columns is sometimes put at the end of a line.
5198ada6aa9SBram Moolenaar if (pos->col == MAXCOL)
5208ada6aa9SBram Moolenaar return NUL;
5218ada6aa9SBram Moolenaar ptr = ml_get_pos(pos);
522071d4279SBram Moolenaar if (has_mbyte)
523071d4279SBram Moolenaar return (*mb_ptr2char)(ptr);
524071d4279SBram Moolenaar return (int)*ptr;
525071d4279SBram Moolenaar }
526071d4279SBram Moolenaar
527071d4279SBram Moolenaar int
gchar_cursor(void)5289b57814dSBram Moolenaar gchar_cursor(void)
529071d4279SBram Moolenaar {
530071d4279SBram Moolenaar if (has_mbyte)
531071d4279SBram Moolenaar return (*mb_ptr2char)(ml_get_cursor());
532071d4279SBram Moolenaar return (int)*ml_get_cursor();
533071d4279SBram Moolenaar }
534071d4279SBram Moolenaar
535071d4279SBram Moolenaar /*
536071d4279SBram Moolenaar * Write a character at the current cursor position.
537071d4279SBram Moolenaar * It is directly written into the block.
538071d4279SBram Moolenaar */
539071d4279SBram Moolenaar void
pchar_cursor(int c)5409b57814dSBram Moolenaar pchar_cursor(int c)
541071d4279SBram Moolenaar {
542071d4279SBram Moolenaar *(ml_get_buf(curbuf, curwin->w_cursor.lnum, TRUE)
543071d4279SBram Moolenaar + curwin->w_cursor.col) = c;
544071d4279SBram Moolenaar }
545071d4279SBram Moolenaar
546071d4279SBram Moolenaar /*
547071d4279SBram Moolenaar * Skip to next part of an option argument: Skip space and comma.
548071d4279SBram Moolenaar */
549071d4279SBram Moolenaar char_u *
skip_to_option_part(char_u * p)5509b57814dSBram Moolenaar skip_to_option_part(char_u *p)
551071d4279SBram Moolenaar {
552071d4279SBram Moolenaar if (*p == ',')
553071d4279SBram Moolenaar ++p;
554071d4279SBram Moolenaar while (*p == ' ')
555071d4279SBram Moolenaar ++p;
556071d4279SBram Moolenaar return p;
557071d4279SBram Moolenaar }
558071d4279SBram Moolenaar
559071d4279SBram Moolenaar /*
560071d4279SBram Moolenaar * check_status: called when the status bars for the buffer 'buf'
561071d4279SBram Moolenaar * need to be updated
562071d4279SBram Moolenaar */
563071d4279SBram Moolenaar void
check_status(buf_T * buf)5649b57814dSBram Moolenaar check_status(buf_T *buf)
565071d4279SBram Moolenaar {
566071d4279SBram Moolenaar win_T *wp;
567071d4279SBram Moolenaar
56829323590SBram Moolenaar FOR_ALL_WINDOWS(wp)
569071d4279SBram Moolenaar if (wp->w_buffer == buf && wp->w_status_height)
570071d4279SBram Moolenaar {
571071d4279SBram Moolenaar wp->w_redr_status = TRUE;
572071d4279SBram Moolenaar if (must_redraw < VALID)
573071d4279SBram Moolenaar must_redraw = VALID;
574071d4279SBram Moolenaar }
575071d4279SBram Moolenaar }
576071d4279SBram Moolenaar
577071d4279SBram Moolenaar /*
578071d4279SBram Moolenaar * Ask for a reply from the user, a 'y' or a 'n'.
579071d4279SBram Moolenaar * No other characters are accepted, the message is repeated until a valid
580071d4279SBram Moolenaar * reply is entered or CTRL-C is hit.
581071d4279SBram Moolenaar * If direct is TRUE, don't use vgetc() but ui_inchar(), don't get characters
582071d4279SBram Moolenaar * from any buffers but directly from the user.
583071d4279SBram Moolenaar *
584071d4279SBram Moolenaar * return the 'y' or 'n'
585071d4279SBram Moolenaar */
586071d4279SBram Moolenaar int
ask_yesno(char_u * str,int direct)5879b57814dSBram Moolenaar ask_yesno(char_u *str, int direct)
588071d4279SBram Moolenaar {
589071d4279SBram Moolenaar int r = ' ';
590071d4279SBram Moolenaar int save_State = State;
591071d4279SBram Moolenaar
59285a2002aSBram Moolenaar if (exiting) // put terminal in raw mode for this question
593071d4279SBram Moolenaar settmode(TMODE_RAW);
594071d4279SBram Moolenaar ++no_wait_return;
595071d4279SBram Moolenaar #ifdef USE_ON_FLY_SCROLL
596b20b9e14SBram Moolenaar dont_scroll = TRUE; // disallow scrolling here
597071d4279SBram Moolenaar #endif
598b20b9e14SBram Moolenaar State = CONFIRM; // mouse behaves like with :confirm
599b20b9e14SBram Moolenaar setmouse(); // disables mouse for xterm
600071d4279SBram Moolenaar ++no_mapping;
601b20b9e14SBram Moolenaar ++allow_keys; // no mapping here, but recognize keys
602071d4279SBram Moolenaar
603071d4279SBram Moolenaar while (r != 'y' && r != 'n')
604071d4279SBram Moolenaar {
60585a2002aSBram Moolenaar // same highlighting as for wait_return
606f9e3e09fSBram Moolenaar smsg_attr(HL_ATTR(HLF_R), "%s (y/n)?", str);
607071d4279SBram Moolenaar if (direct)
608071d4279SBram Moolenaar r = get_keystroke();
609071d4279SBram Moolenaar else
610913626ceSBram Moolenaar r = plain_vgetc();
611071d4279SBram Moolenaar if (r == Ctrl_C || r == ESC)
612071d4279SBram Moolenaar r = 'n';
61385a2002aSBram Moolenaar msg_putchar(r); // show what you typed
614071d4279SBram Moolenaar out_flush();
615071d4279SBram Moolenaar }
616071d4279SBram Moolenaar --no_wait_return;
617071d4279SBram Moolenaar State = save_State;
618071d4279SBram Moolenaar setmouse();
619071d4279SBram Moolenaar --no_mapping;
620071d4279SBram Moolenaar --allow_keys;
621071d4279SBram Moolenaar
622071d4279SBram Moolenaar return r;
623071d4279SBram Moolenaar }
624071d4279SBram Moolenaar
6250e57dd85SBram Moolenaar #if defined(FEAT_EVAL) || defined(PROTO)
6260e57dd85SBram Moolenaar
6270e57dd85SBram Moolenaar /*
6280e57dd85SBram Moolenaar * "mode()" function
6290e57dd85SBram Moolenaar */
6300e57dd85SBram Moolenaar void
f_mode(typval_T * argvars,typval_T * rettv)6310e57dd85SBram Moolenaar f_mode(typval_T *argvars, typval_T *rettv)
6320e57dd85SBram Moolenaar {
633f1e8876fS=?UTF-8?q?Magnus=20Gro=C3=9F?= char_u buf[MODE_MAX_LENGTH];
6340e57dd85SBram Moolenaar
6354490ec4eSYegappan Lakshmanan if (in_vim9script() && check_for_opt_bool_arg(argvars, 0) == FAIL)
6364490ec4eSYegappan Lakshmanan return;
6374490ec4eSYegappan Lakshmanan
638a80faa89SBram Moolenaar CLEAR_FIELD(buf);
6390e57dd85SBram Moolenaar
6400e57dd85SBram Moolenaar if (time_for_testing == 93784)
6410e57dd85SBram Moolenaar {
64285a2002aSBram Moolenaar // Testing the two-character code.
6430e57dd85SBram Moolenaar buf[0] = 'x';
6440e57dd85SBram Moolenaar buf[1] = '!';
6450e57dd85SBram Moolenaar }
6460e57dd85SBram Moolenaar #ifdef FEAT_TERMINAL
6470e57dd85SBram Moolenaar else if (term_use_loop())
6480e57dd85SBram Moolenaar buf[0] = 't';
6490e57dd85SBram Moolenaar #endif
6500e57dd85SBram Moolenaar else if (VIsual_active)
6510e57dd85SBram Moolenaar {
6520e57dd85SBram Moolenaar if (VIsual_select)
6530e57dd85SBram Moolenaar buf[0] = VIsual_mode + 's' - 'v';
6540e57dd85SBram Moolenaar else
655eaf3f361Szeertzjq {
6560e57dd85SBram Moolenaar buf[0] = VIsual_mode;
657eaf3f361Szeertzjq if (restart_VIsual_select)
658eaf3f361Szeertzjq buf[1] = 's';
659eaf3f361Szeertzjq }
6600e57dd85SBram Moolenaar }
6610e57dd85SBram Moolenaar else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
6620e57dd85SBram Moolenaar || State == CONFIRM)
6630e57dd85SBram Moolenaar {
6640e57dd85SBram Moolenaar buf[0] = 'r';
6650e57dd85SBram Moolenaar if (State == ASKMORE)
6660e57dd85SBram Moolenaar buf[1] = 'm';
6670e57dd85SBram Moolenaar else if (State == CONFIRM)
6680e57dd85SBram Moolenaar buf[1] = '?';
6690e57dd85SBram Moolenaar }
6700e57dd85SBram Moolenaar else if (State == EXTERNCMD)
6710e57dd85SBram Moolenaar buf[0] = '!';
6720e57dd85SBram Moolenaar else if (State & INSERT)
6730e57dd85SBram Moolenaar {
6740e57dd85SBram Moolenaar if (State & VREPLACE_FLAG)
6750e57dd85SBram Moolenaar {
6760e57dd85SBram Moolenaar buf[0] = 'R';
6770e57dd85SBram Moolenaar buf[1] = 'v';
678cc8cd445Szeertzjq
679cc8cd445Szeertzjq if (ins_compl_active())
680cc8cd445Szeertzjq buf[2] = 'c';
681cc8cd445Szeertzjq else if (ctrl_x_mode_not_defined_yet())
682cc8cd445Szeertzjq buf[2] = 'x';
6830e57dd85SBram Moolenaar }
6840e57dd85SBram Moolenaar else
6850e57dd85SBram Moolenaar {
6860e57dd85SBram Moolenaar if (State & REPLACE_FLAG)
6870e57dd85SBram Moolenaar buf[0] = 'R';
6880e57dd85SBram Moolenaar else
6890e57dd85SBram Moolenaar buf[0] = 'i';
690cc8cd445Szeertzjq
6910e57dd85SBram Moolenaar if (ins_compl_active())
6920e57dd85SBram Moolenaar buf[1] = 'c';
6930e57dd85SBram Moolenaar else if (ctrl_x_mode_not_defined_yet())
6940e57dd85SBram Moolenaar buf[1] = 'x';
6950e57dd85SBram Moolenaar }
6960e57dd85SBram Moolenaar }
6970e57dd85SBram Moolenaar else if ((State & CMDLINE) || exmode_active)
6980e57dd85SBram Moolenaar {
6990e57dd85SBram Moolenaar buf[0] = 'c';
7000e57dd85SBram Moolenaar if (exmode_active == EXMODE_VIM)
7010e57dd85SBram Moolenaar buf[1] = 'v';
7020e57dd85SBram Moolenaar else if (exmode_active == EXMODE_NORMAL)
7030e57dd85SBram Moolenaar buf[1] = 'e';
7040e57dd85SBram Moolenaar }
7050e57dd85SBram Moolenaar else
7060e57dd85SBram Moolenaar {
7070e57dd85SBram Moolenaar buf[0] = 'n';
7080e57dd85SBram Moolenaar if (finish_op)
7090e57dd85SBram Moolenaar {
7100e57dd85SBram Moolenaar buf[1] = 'o';
711a2438132SYegappan Lakshmanan // to be able to detect force-linewise/blockwise/characterwise
712a2438132SYegappan Lakshmanan // operations
7130e57dd85SBram Moolenaar buf[2] = motion_force;
7140e57dd85SBram Moolenaar }
7150e57dd85SBram Moolenaar else if (restart_edit == 'I' || restart_edit == 'R'
7160e57dd85SBram Moolenaar || restart_edit == 'V')
7170e57dd85SBram Moolenaar {
7180e57dd85SBram Moolenaar buf[1] = 'i';
7190e57dd85SBram Moolenaar buf[2] = restart_edit;
7200e57dd85SBram Moolenaar }
72172406a4bSBram Moolenaar #ifdef FEAT_TERMINAL
72272406a4bSBram Moolenaar else if (term_in_normal_mode())
72372406a4bSBram Moolenaar buf[1] = 't';
72472406a4bSBram Moolenaar #endif
7250e57dd85SBram Moolenaar }
7260e57dd85SBram Moolenaar
72785a2002aSBram Moolenaar // Clear out the minor mode when the argument is not a non-zero number or
72885a2002aSBram Moolenaar // non-empty string.
7290e57dd85SBram Moolenaar if (!non_zero_arg(&argvars[0]))
7300e57dd85SBram Moolenaar buf[1] = NUL;
7310e57dd85SBram Moolenaar
7320e57dd85SBram Moolenaar rettv->vval.v_string = vim_strsave(buf);
7330e57dd85SBram Moolenaar rettv->v_type = VAR_STRING;
7340e57dd85SBram Moolenaar }
7350e57dd85SBram Moolenaar
7360e57dd85SBram Moolenaar static void
may_add_state_char(garray_T * gap,char_u * include,int c)7370e57dd85SBram Moolenaar may_add_state_char(garray_T *gap, char_u *include, int c)
7380e57dd85SBram Moolenaar {
7390e57dd85SBram Moolenaar if (include == NULL || vim_strchr(include, c) != NULL)
7400e57dd85SBram Moolenaar ga_append(gap, c);
7410e57dd85SBram Moolenaar }
7420e57dd85SBram Moolenaar
7430e57dd85SBram Moolenaar /*
7440e57dd85SBram Moolenaar * "state()" function
7450e57dd85SBram Moolenaar */
7460e57dd85SBram Moolenaar void
f_state(typval_T * argvars,typval_T * rettv)7470e57dd85SBram Moolenaar f_state(typval_T *argvars, typval_T *rettv)
7480e57dd85SBram Moolenaar {
7490e57dd85SBram Moolenaar garray_T ga;
7500e57dd85SBram Moolenaar char_u *include = NULL;
7510e57dd85SBram Moolenaar int i;
7520e57dd85SBram Moolenaar
7534490ec4eSYegappan Lakshmanan if (in_vim9script() && check_for_opt_string_arg(argvars, 0) == FAIL)
7544490ec4eSYegappan Lakshmanan return;
7554490ec4eSYegappan Lakshmanan
7560e57dd85SBram Moolenaar ga_init2(&ga, 1, 20);
7570e57dd85SBram Moolenaar if (argvars[0].v_type != VAR_UNKNOWN)
7580e57dd85SBram Moolenaar include = tv_get_string(&argvars[0]);
7590e57dd85SBram Moolenaar
7600e57dd85SBram Moolenaar if (!(stuff_empty() && typebuf.tb_len == 0 && scriptin[curscript] == NULL))
7610e57dd85SBram Moolenaar may_add_state_char(&ga, include, 'm');
7620e57dd85SBram Moolenaar if (op_pending())
7630e57dd85SBram Moolenaar may_add_state_char(&ga, include, 'o');
7640e57dd85SBram Moolenaar if (autocmd_busy)
7650e57dd85SBram Moolenaar may_add_state_char(&ga, include, 'x');
766c2585490SBram Moolenaar if (ins_compl_active())
7670e57dd85SBram Moolenaar may_add_state_char(&ga, include, 'a');
7680e57dd85SBram Moolenaar
7690e57dd85SBram Moolenaar # ifdef FEAT_JOB_CHANNEL
7700e57dd85SBram Moolenaar if (channel_in_blocking_wait())
7710e57dd85SBram Moolenaar may_add_state_char(&ga, include, 'w');
7720e57dd85SBram Moolenaar # endif
773b20b9e14SBram Moolenaar if (!get_was_safe_state())
774b20b9e14SBram Moolenaar may_add_state_char(&ga, include, 'S');
7750e57dd85SBram Moolenaar for (i = 0; i < get_callback_depth() && i < 3; ++i)
7760e57dd85SBram Moolenaar may_add_state_char(&ga, include, 'c');
7770e57dd85SBram Moolenaar if (msg_scrolled > 0)
7780e57dd85SBram Moolenaar may_add_state_char(&ga, include, 's');
7790e57dd85SBram Moolenaar
7800e57dd85SBram Moolenaar rettv->v_type = VAR_STRING;
7810e57dd85SBram Moolenaar rettv->vval.v_string = ga.ga_data;
7820e57dd85SBram Moolenaar }
7830e57dd85SBram Moolenaar
7840e57dd85SBram Moolenaar #endif // FEAT_EVAL
7850e57dd85SBram Moolenaar
786071d4279SBram Moolenaar /*
787071d4279SBram Moolenaar * Get a key stroke directly from the user.
788071d4279SBram Moolenaar * Ignores mouse clicks and scrollbar events, except a click for the left
789071d4279SBram Moolenaar * button (used at the more prompt).
790071d4279SBram Moolenaar * Doesn't use vgetc(), because it syncs undo and eats mapped characters.
791071d4279SBram Moolenaar * Disadvantage: typeahead is ignored.
792071d4279SBram Moolenaar * Translates the interrupt character for unix to ESC.
793071d4279SBram Moolenaar */
794071d4279SBram Moolenaar int
get_keystroke(void)7959b57814dSBram Moolenaar get_keystroke(void)
796071d4279SBram Moolenaar {
797a8c8a688SBram Moolenaar char_u *buf = NULL;
798a8c8a688SBram Moolenaar int buflen = 150;
799a8c8a688SBram Moolenaar int maxlen;
800071d4279SBram Moolenaar int len = 0;
801071d4279SBram Moolenaar int n;
802071d4279SBram Moolenaar int save_mapped_ctrl_c = mapped_ctrl_c;
8034395a71dSBram Moolenaar int waited = 0;
804071d4279SBram Moolenaar
80585a2002aSBram Moolenaar mapped_ctrl_c = FALSE; // mappings are not used here
806071d4279SBram Moolenaar for (;;)
807071d4279SBram Moolenaar {
808071d4279SBram Moolenaar cursor_on();
809071d4279SBram Moolenaar out_flush();
810071d4279SBram Moolenaar
81185a2002aSBram Moolenaar // Leave some room for check_termcode() to insert a key code into (max
81285a2002aSBram Moolenaar // 5 chars plus NUL). And fix_input_buffer() can triple the number of
81385a2002aSBram Moolenaar // bytes.
814a8c8a688SBram Moolenaar maxlen = (buflen - 6 - len) / 3;
815a8c8a688SBram Moolenaar if (buf == NULL)
816a8c8a688SBram Moolenaar buf = alloc(buflen);
817a8c8a688SBram Moolenaar else if (maxlen < 10)
818a8c8a688SBram Moolenaar {
8199abd5c65SBram Moolenaar char_u *t_buf = buf;
8209abd5c65SBram Moolenaar
82185a2002aSBram Moolenaar // Need some more space. This might happen when receiving a long
82285a2002aSBram Moolenaar // escape sequence.
823a8c8a688SBram Moolenaar buflen += 100;
824a8c8a688SBram Moolenaar buf = vim_realloc(buf, buflen);
8259abd5c65SBram Moolenaar if (buf == NULL)
8269abd5c65SBram Moolenaar vim_free(t_buf);
827a8c8a688SBram Moolenaar maxlen = (buflen - 6 - len) / 3;
828a8c8a688SBram Moolenaar }
829a8c8a688SBram Moolenaar if (buf == NULL)
830a8c8a688SBram Moolenaar {
831a8c8a688SBram Moolenaar do_outofmem_msg((long_u)buflen);
83285a2002aSBram Moolenaar return ESC; // panic!
833a8c8a688SBram Moolenaar }
834a8c8a688SBram Moolenaar
83585a2002aSBram Moolenaar // First time: blocking wait. Second time: wait up to 100ms for a
83685a2002aSBram Moolenaar // terminal code to complete.
837a8c8a688SBram Moolenaar n = ui_inchar(buf + len, maxlen, len == 0 ? -1L : 100L, 0);
838071d4279SBram Moolenaar if (n > 0)
839071d4279SBram Moolenaar {
84085a2002aSBram Moolenaar // Replace zero and CSI by a special key code.
8416bff02ebSBram Moolenaar n = fix_input_buffer(buf + len, n);
842071d4279SBram Moolenaar len += n;
8434395a71dSBram Moolenaar waited = 0;
844071d4279SBram Moolenaar }
8454395a71dSBram Moolenaar else if (len > 0)
84685a2002aSBram Moolenaar ++waited; // keep track of the waiting time
847071d4279SBram Moolenaar
84885a2002aSBram Moolenaar // Incomplete termcode and not timed out yet: get more characters
849a8c8a688SBram Moolenaar if ((n = check_termcode(1, buf, buflen, &len)) < 0
8504395a71dSBram Moolenaar && (!p_ttimeout || waited * 100L < (p_ttm < 0 ? p_tm : p_ttm)))
851071d4279SBram Moolenaar continue;
8524395a71dSBram Moolenaar
85385a2002aSBram Moolenaar if (n == KEYLEN_REMOVED) // key code removed
8546eb634efSBram Moolenaar {
855fd30cd41SBram Moolenaar if (must_redraw != 0 && !need_wait_return && (State & CMDLINE) == 0)
8566eb634efSBram Moolenaar {
85785a2002aSBram Moolenaar // Redrawing was postponed, do it now.
8586eb634efSBram Moolenaar update_screen(0);
85985a2002aSBram Moolenaar setcursor(); // put cursor back where it belongs
8606eb634efSBram Moolenaar }
861946ffd46SBram Moolenaar continue;
8626eb634efSBram Moolenaar }
86385a2002aSBram Moolenaar if (n > 0) // found a termcode: adjust length
864071d4279SBram Moolenaar len = n;
86585a2002aSBram Moolenaar if (len == 0) // nothing typed yet
866071d4279SBram Moolenaar continue;
867071d4279SBram Moolenaar
86885a2002aSBram Moolenaar // Handle modifier and/or special key code.
869071d4279SBram Moolenaar n = buf[0];
870071d4279SBram Moolenaar if (n == K_SPECIAL)
871071d4279SBram Moolenaar {
872071d4279SBram Moolenaar n = TO_SPECIAL(buf[1], buf[2]);
873071d4279SBram Moolenaar if (buf[1] == KS_MODIFIER
874071d4279SBram Moolenaar || n == K_IGNORE
8752526ef27SBram Moolenaar || (is_mouse_key(n) && n != K_LEFTMOUSE)
876071d4279SBram Moolenaar #ifdef FEAT_GUI
877071d4279SBram Moolenaar || n == K_VER_SCROLLBAR
878071d4279SBram Moolenaar || n == K_HOR_SCROLLBAR
879071d4279SBram Moolenaar #endif
880071d4279SBram Moolenaar )
881071d4279SBram Moolenaar {
882071d4279SBram Moolenaar if (buf[1] == KS_MODIFIER)
883071d4279SBram Moolenaar mod_mask = buf[2];
884071d4279SBram Moolenaar len -= 3;
885071d4279SBram Moolenaar if (len > 0)
886071d4279SBram Moolenaar mch_memmove(buf, buf + 3, (size_t)len);
887071d4279SBram Moolenaar continue;
888071d4279SBram Moolenaar }
8897fc904b6SBram Moolenaar break;
890071d4279SBram Moolenaar }
891071d4279SBram Moolenaar if (has_mbyte)
892071d4279SBram Moolenaar {
893071d4279SBram Moolenaar if (MB_BYTE2LEN(n) > len)
89485a2002aSBram Moolenaar continue; // more bytes to get
895a8c8a688SBram Moolenaar buf[len >= buflen ? buflen - 1 : len] = NUL;
896071d4279SBram Moolenaar n = (*mb_ptr2char)(buf);
897071d4279SBram Moolenaar }
898071d4279SBram Moolenaar #ifdef UNIX
899071d4279SBram Moolenaar if (n == intr_char)
900071d4279SBram Moolenaar n = ESC;
901071d4279SBram Moolenaar #endif
902071d4279SBram Moolenaar break;
903071d4279SBram Moolenaar }
904a8c8a688SBram Moolenaar vim_free(buf);
905071d4279SBram Moolenaar
906071d4279SBram Moolenaar mapped_ctrl_c = save_mapped_ctrl_c;
907071d4279SBram Moolenaar return n;
908071d4279SBram Moolenaar }
909071d4279SBram Moolenaar
910071d4279SBram Moolenaar /*
91124bbcfe8SBram Moolenaar * Get a number from the user.
91224bbcfe8SBram Moolenaar * When "mouse_used" is not NULL allow using the mouse.
913071d4279SBram Moolenaar */
914071d4279SBram Moolenaar int
get_number(int colon,int * mouse_used)9159b57814dSBram Moolenaar get_number(
91685a2002aSBram Moolenaar int colon, // allow colon to abort
9179b57814dSBram Moolenaar int *mouse_used)
918071d4279SBram Moolenaar {
919071d4279SBram Moolenaar int n = 0;
920071d4279SBram Moolenaar int c;
9213991dab8SBram Moolenaar int typed = 0;
922071d4279SBram Moolenaar
92324bbcfe8SBram Moolenaar if (mouse_used != NULL)
92424bbcfe8SBram Moolenaar *mouse_used = FALSE;
92524bbcfe8SBram Moolenaar
92685a2002aSBram Moolenaar // When not printing messages, the user won't know what to type, return a
92785a2002aSBram Moolenaar // zero (as if CR was hit).
928071d4279SBram Moolenaar if (msg_silent != 0)
929071d4279SBram Moolenaar return 0;
930071d4279SBram Moolenaar
931071d4279SBram Moolenaar #ifdef USE_ON_FLY_SCROLL
93285a2002aSBram Moolenaar dont_scroll = TRUE; // disallow scrolling here
933071d4279SBram Moolenaar #endif
934071d4279SBram Moolenaar ++no_mapping;
93585a2002aSBram Moolenaar ++allow_keys; // no mapping here, but recognize keys
936071d4279SBram Moolenaar for (;;)
937071d4279SBram Moolenaar {
938071d4279SBram Moolenaar windgoto(msg_row, msg_col);
939071d4279SBram Moolenaar c = safe_vgetc();
940071d4279SBram Moolenaar if (VIM_ISDIGIT(c))
941071d4279SBram Moolenaar {
942071d4279SBram Moolenaar n = n * 10 + c - '0';
943071d4279SBram Moolenaar msg_putchar(c);
9443991dab8SBram Moolenaar ++typed;
945071d4279SBram Moolenaar }
946071d4279SBram Moolenaar else if (c == K_DEL || c == K_KDEL || c == K_BS || c == Ctrl_H)
947071d4279SBram Moolenaar {
9483991dab8SBram Moolenaar if (typed > 0)
9493991dab8SBram Moolenaar {
95032526b3cSBram Moolenaar msg_puts("\b \b");
9513991dab8SBram Moolenaar --typed;
9523991dab8SBram Moolenaar }
9533991dab8SBram Moolenaar n /= 10;
954071d4279SBram Moolenaar }
95524bbcfe8SBram Moolenaar else if (mouse_used != NULL && c == K_LEFTMOUSE)
95624bbcfe8SBram Moolenaar {
95724bbcfe8SBram Moolenaar *mouse_used = TRUE;
95824bbcfe8SBram Moolenaar n = mouse_row + 1;
95924bbcfe8SBram Moolenaar break;
96024bbcfe8SBram Moolenaar }
961071d4279SBram Moolenaar else if (n == 0 && c == ':' && colon)
962071d4279SBram Moolenaar {
963071d4279SBram Moolenaar stuffcharReadbuff(':');
964071d4279SBram Moolenaar if (!exmode_active)
965071d4279SBram Moolenaar cmdline_row = msg_row;
96685a2002aSBram Moolenaar skip_redraw = TRUE; // skip redraw once
967071d4279SBram Moolenaar do_redraw = FALSE;
968071d4279SBram Moolenaar break;
969071d4279SBram Moolenaar }
9705cf94577S=?UTF-8?q?Luka=20Marku=C5=A1i=C4=87?= else if (c == Ctrl_C || c == ESC || c == 'q')
9715cf94577S=?UTF-8?q?Luka=20Marku=C5=A1i=C4=87?= {
9725cf94577S=?UTF-8?q?Luka=20Marku=C5=A1i=C4=87?= n = 0;
9735cf94577S=?UTF-8?q?Luka=20Marku=C5=A1i=C4=87?= break;
9745cf94577S=?UTF-8?q?Luka=20Marku=C5=A1i=C4=87?= }
9755cf94577S=?UTF-8?q?Luka=20Marku=C5=A1i=C4=87?= else if (c == CAR || c == NL )
976071d4279SBram Moolenaar break;
977071d4279SBram Moolenaar }
978071d4279SBram Moolenaar --no_mapping;
979071d4279SBram Moolenaar --allow_keys;
980071d4279SBram Moolenaar return n;
981071d4279SBram Moolenaar }
982071d4279SBram Moolenaar
9839ba0eb85SBram Moolenaar /*
9849ba0eb85SBram Moolenaar * Ask the user to enter a number.
98524bbcfe8SBram Moolenaar * When "mouse_used" is not NULL allow using the mouse and in that case return
98624bbcfe8SBram Moolenaar * the line number.
9879ba0eb85SBram Moolenaar */
9889ba0eb85SBram Moolenaar int
prompt_for_number(int * mouse_used)9899b57814dSBram Moolenaar prompt_for_number(int *mouse_used)
9909ba0eb85SBram Moolenaar {
9919ba0eb85SBram Moolenaar int i;
992d857f0e0SBram Moolenaar int save_cmdline_row;
993d857f0e0SBram Moolenaar int save_State;
9949ba0eb85SBram Moolenaar
99585a2002aSBram Moolenaar // When using ":silent" assume that <CR> was entered.
99642eeac35SBram Moolenaar if (mouse_used != NULL)
997eebd5557SBram Moolenaar msg_puts(_("Type number and <Enter> or click with the mouse (q or empty cancels): "));
99842eeac35SBram Moolenaar else
999eebd5557SBram Moolenaar msg_puts(_("Type number and <Enter> (q or empty cancels): "));
1000d857f0e0SBram Moolenaar
10014cbdf155SBram Moolenaar // Set the state such that text can be selected/copied/pasted and we still
10024cbdf155SBram Moolenaar // get mouse events. redraw_after_callback() will not redraw if cmdline_row
10034cbdf155SBram Moolenaar // is zero.
1004d857f0e0SBram Moolenaar save_cmdline_row = cmdline_row;
1005203335e4SBram Moolenaar cmdline_row = 0;
1006d857f0e0SBram Moolenaar save_State = State;
10074cbdf155SBram Moolenaar State = CMDLINE;
10084cbdf155SBram Moolenaar // May show different mouse shape.
100973658317SBram Moolenaar setmouse();
101073658317SBram Moolenaar
101124bbcfe8SBram Moolenaar i = get_number(TRUE, mouse_used);
101224bbcfe8SBram Moolenaar if (KeyTyped)
10139ba0eb85SBram Moolenaar {
1014954bb063SBram Moolenaar // don't call wait_return() now
1015954bb063SBram Moolenaar if (msg_row > 0)
10169ba0eb85SBram Moolenaar cmdline_row = msg_row - 1;
10179ba0eb85SBram Moolenaar need_wait_return = FALSE;
1018dc968e7aSBram Moolenaar msg_didany = FALSE;
1019dc968e7aSBram Moolenaar msg_didout = FALSE;
10209ba0eb85SBram Moolenaar }
1021d857f0e0SBram Moolenaar else
1022d857f0e0SBram Moolenaar cmdline_row = save_cmdline_row;
1023d857f0e0SBram Moolenaar State = save_State;
10244cbdf155SBram Moolenaar // May need to restore mouse shape.
102573658317SBram Moolenaar setmouse();
1026d857f0e0SBram Moolenaar
10279ba0eb85SBram Moolenaar return i;
10289ba0eb85SBram Moolenaar }
10299ba0eb85SBram Moolenaar
1030071d4279SBram Moolenaar void
msgmore(long n)10319b57814dSBram Moolenaar msgmore(long n)
1032071d4279SBram Moolenaar {
1033071d4279SBram Moolenaar long pn;
1034071d4279SBram Moolenaar
103585a2002aSBram Moolenaar if (global_busy // no messages now, wait until global is finished
103685a2002aSBram Moolenaar || !messaging()) // 'lazyredraw' set, don't do messages now
1037071d4279SBram Moolenaar return;
1038071d4279SBram Moolenaar
103985a2002aSBram Moolenaar // We don't want to overwrite another important message, but do overwrite
104085a2002aSBram Moolenaar // a previous "more lines" or "fewer lines" message, so that "5dd" and
104185a2002aSBram Moolenaar // then "put" reports the last action.
10427df2d662SBram Moolenaar if (keep_msg != NULL && !keep_msg_more)
10437df2d662SBram Moolenaar return;
10447df2d662SBram Moolenaar
1045071d4279SBram Moolenaar if (n > 0)
1046071d4279SBram Moolenaar pn = n;
1047071d4279SBram Moolenaar else
1048071d4279SBram Moolenaar pn = -n;
1049071d4279SBram Moolenaar
1050071d4279SBram Moolenaar if (pn > p_report)
1051071d4279SBram Moolenaar {
1052071d4279SBram Moolenaar if (n > 0)
105332526b3cSBram Moolenaar vim_snprintf(msg_buf, MSG_BUF_LEN,
1054da6e8919SBram Moolenaar NGETTEXT("%ld more line", "%ld more lines", pn), pn);
1055071d4279SBram Moolenaar else
105632526b3cSBram Moolenaar vim_snprintf(msg_buf, MSG_BUF_LEN,
1057da6e8919SBram Moolenaar NGETTEXT("%ld line less", "%ld fewer lines", pn), pn);
1058071d4279SBram Moolenaar if (got_int)
105932526b3cSBram Moolenaar vim_strcat((char_u *)msg_buf, (char_u *)_(" (Interrupted)"),
106032526b3cSBram Moolenaar MSG_BUF_LEN);
1061071d4279SBram Moolenaar if (msg(msg_buf))
1062071d4279SBram Moolenaar {
106332526b3cSBram Moolenaar set_keep_msg((char_u *)msg_buf, 0);
10647df2d662SBram Moolenaar keep_msg_more = TRUE;
1065071d4279SBram Moolenaar }
1066071d4279SBram Moolenaar }
1067071d4279SBram Moolenaar }
1068071d4279SBram Moolenaar
1069071d4279SBram Moolenaar /*
1070071d4279SBram Moolenaar * flush map and typeahead buffers and give a warning for an error
1071071d4279SBram Moolenaar */
1072071d4279SBram Moolenaar void
beep_flush(void)10739b57814dSBram Moolenaar beep_flush(void)
1074071d4279SBram Moolenaar {
1075071d4279SBram Moolenaar if (emsg_silent == 0)
1076071d4279SBram Moolenaar {
10776a2633b0SBram Moolenaar flush_buffers(FLUSH_MINIMAL);
1078165bc69dSBram Moolenaar vim_beep(BO_ERROR);
1079071d4279SBram Moolenaar }
1080071d4279SBram Moolenaar }
1081071d4279SBram Moolenaar
1082071d4279SBram Moolenaar /*
1083165bc69dSBram Moolenaar * Give a warning for an error.
1084071d4279SBram Moolenaar */
1085071d4279SBram Moolenaar void
vim_beep(unsigned val)10869b57814dSBram Moolenaar vim_beep(
108785a2002aSBram Moolenaar unsigned val) // one of the BO_ values, e.g., BO_OPER
1088071d4279SBram Moolenaar {
1089b48e96f6SBram Moolenaar #ifdef FEAT_EVAL
1090b48e96f6SBram Moolenaar called_vim_beep = TRUE;
1091b48e96f6SBram Moolenaar #endif
1092b48e96f6SBram Moolenaar
109328ee892aSBram Moolenaar if (emsg_silent == 0 && !in_assert_fails)
1094071d4279SBram Moolenaar {
1095165bc69dSBram Moolenaar if (!((bo_flags & val) || (bo_flags & BO_ALL)))
1096165bc69dSBram Moolenaar {
10972e147caaSBram Moolenaar #ifdef ELAPSED_FUNC
10982e147caaSBram Moolenaar static int did_init = FALSE;
10991ac56c2dSBram Moolenaar static elapsed_T start_tv;
11002e147caaSBram Moolenaar
110185a2002aSBram Moolenaar // Only beep once per half a second, otherwise a sequence of beeps
110285a2002aSBram Moolenaar // would freeze Vim.
11032e147caaSBram Moolenaar if (!did_init || ELAPSED_FUNC(start_tv) > 500)
11042e147caaSBram Moolenaar {
11052e147caaSBram Moolenaar did_init = TRUE;
11062e147caaSBram Moolenaar ELAPSED_INIT(start_tv);
11072e147caaSBram Moolenaar #endif
1108071d4279SBram Moolenaar if (p_vb
1109071d4279SBram Moolenaar #ifdef FEAT_GUI
111085a2002aSBram Moolenaar // While the GUI is starting up the termcap is set for
111185a2002aSBram Moolenaar // the GUI but the output still goes to a terminal.
1112071d4279SBram Moolenaar && !(gui.in_use && gui.starting)
1113071d4279SBram Moolenaar #endif
1114071d4279SBram Moolenaar )
1115cafafb38SBram Moolenaar {
11162e147caaSBram Moolenaar out_str_cf(T_VB);
1117cafafb38SBram Moolenaar #ifdef FEAT_VTP
111885a2002aSBram Moolenaar // No restore color information, refresh the screen.
1119cafafb38SBram Moolenaar if (has_vtp_working() != 0
1120cafafb38SBram Moolenaar # ifdef FEAT_TERMGUICOLORS
1121c5cd8855SBram Moolenaar && (p_tgc || (!p_tgc && t_colors >= 256))
1122cafafb38SBram Moolenaar # endif
1123cafafb38SBram Moolenaar )
1124cafafb38SBram Moolenaar {
1125cafafb38SBram Moolenaar redraw_later(CLEAR);
1126cafafb38SBram Moolenaar update_screen(0);
1127cafafb38SBram Moolenaar redrawcmd();
1128cafafb38SBram Moolenaar }
1129cafafb38SBram Moolenaar #endif
1130cafafb38SBram Moolenaar }
1131071d4279SBram Moolenaar else
1132071d4279SBram Moolenaar out_char(BELL);
11332e147caaSBram Moolenaar #ifdef ELAPSED_FUNC
11342e147caaSBram Moolenaar }
11352e147caaSBram Moolenaar #endif
1136165bc69dSBram Moolenaar }
11375313dcb7SBram Moolenaar
113885a2002aSBram Moolenaar // When 'debug' contains "beep" produce a message. If we are sourcing
113985a2002aSBram Moolenaar // a script or executing a function give the user a hint where the beep
114085a2002aSBram Moolenaar // comes from.
11415313dcb7SBram Moolenaar if (vim_strchr(p_debug, 'e') != NULL)
11425313dcb7SBram Moolenaar {
11438820b486SBram Moolenaar msg_source(HL_ATTR(HLF_W));
114432526b3cSBram Moolenaar msg_attr(_("Beep!"), HL_ATTR(HLF_W));
11455313dcb7SBram Moolenaar }
1146071d4279SBram Moolenaar }
1147071d4279SBram Moolenaar }
1148071d4279SBram Moolenaar
1149071d4279SBram Moolenaar /*
1150071d4279SBram Moolenaar * To get the "real" home directory:
1151071d4279SBram Moolenaar * - get value of $HOME
1152071d4279SBram Moolenaar * For Unix:
1153071d4279SBram Moolenaar * - go to that directory
1154071d4279SBram Moolenaar * - do mch_dirname() to get the real name of that directory.
1155071d4279SBram Moolenaar * This also works with mounts and links.
1156071d4279SBram Moolenaar * Don't do this for MS-DOS, it will change the "current dir" for a drive.
115725a494ceSBram Moolenaar * For Windows:
115825a494ceSBram Moolenaar * This code is duplicated in init_homedir() in dosinst.c. Keep in sync!
1159071d4279SBram Moolenaar */
1160071d4279SBram Moolenaar void
init_homedir(void)11619b57814dSBram Moolenaar init_homedir(void)
1162071d4279SBram Moolenaar {
1163071d4279SBram Moolenaar char_u *var;
1164071d4279SBram Moolenaar
116585a2002aSBram Moolenaar // In case we are called a second time (when 'encoding' changes).
1166d23a8236SBram Moolenaar VIM_CLEAR(homedir);
116705159a0cSBram Moolenaar
1168071d4279SBram Moolenaar #ifdef VMS
1169071d4279SBram Moolenaar var = mch_getenv((char_u *)"SYS$LOGIN");
1170071d4279SBram Moolenaar #else
1171071d4279SBram Moolenaar var = mch_getenv((char_u *)"HOME");
1172071d4279SBram Moolenaar #endif
1173071d4279SBram Moolenaar
11744f97475dSBram Moolenaar #ifdef MSWIN
1175071d4279SBram Moolenaar /*
117648340b62SBram Moolenaar * Typically, $HOME is not defined on Windows, unless the user has
117748340b62SBram Moolenaar * specifically defined it for Vim's sake. However, on Windows NT
117848340b62SBram Moolenaar * platforms, $HOMEDRIVE and $HOMEPATH are automatically defined for
117948340b62SBram Moolenaar * each user. Try constructing $HOME from these.
118048340b62SBram Moolenaar */
1181b47a2597SBram Moolenaar if (var == NULL || *var == NUL)
118248340b62SBram Moolenaar {
118348340b62SBram Moolenaar char_u *homedrive, *homepath;
118448340b62SBram Moolenaar
118548340b62SBram Moolenaar homedrive = mch_getenv((char_u *)"HOMEDRIVE");
118648340b62SBram Moolenaar homepath = mch_getenv((char_u *)"HOMEPATH");
118748340b62SBram Moolenaar if (homepath == NULL || *homepath == NUL)
118848340b62SBram Moolenaar homepath = (char_u *)"\\";
118948340b62SBram Moolenaar if (homedrive != NULL
119048340b62SBram Moolenaar && STRLEN(homedrive) + STRLEN(homepath) < MAXPATHL)
119148340b62SBram Moolenaar {
119248340b62SBram Moolenaar sprintf((char *)NameBuff, "%s%s", homedrive, homepath);
119348340b62SBram Moolenaar if (NameBuff[0] != NUL)
119448340b62SBram Moolenaar var = NameBuff;
119548340b62SBram Moolenaar }
119648340b62SBram Moolenaar }
119748340b62SBram Moolenaar
119848340b62SBram Moolenaar if (var == NULL)
119948340b62SBram Moolenaar var = mch_getenv((char_u *)"USERPROFILE");
120048340b62SBram Moolenaar
120148340b62SBram Moolenaar /*
1202071d4279SBram Moolenaar * Weird but true: $HOME may contain an indirect reference to another
1203071d4279SBram Moolenaar * variable, esp. "%USERPROFILE%". Happens when $USERPROFILE isn't set
1204071d4279SBram Moolenaar * when $HOME is being set.
1205071d4279SBram Moolenaar */
1206071d4279SBram Moolenaar if (var != NULL && *var == '%')
1207071d4279SBram Moolenaar {
1208071d4279SBram Moolenaar char_u *p;
1209071d4279SBram Moolenaar char_u *exp;
1210071d4279SBram Moolenaar
1211071d4279SBram Moolenaar p = vim_strchr(var + 1, '%');
1212071d4279SBram Moolenaar if (p != NULL)
1213071d4279SBram Moolenaar {
1214ce0842a6SBram Moolenaar vim_strncpy(NameBuff, var + 1, p - (var + 1));
1215071d4279SBram Moolenaar exp = mch_getenv(NameBuff);
1216071d4279SBram Moolenaar if (exp != NULL && *exp != NUL
1217071d4279SBram Moolenaar && STRLEN(exp) + STRLEN(p) < MAXPATHL)
1218071d4279SBram Moolenaar {
1219555b280fSBram Moolenaar vim_snprintf((char *)NameBuff, MAXPATHL, "%s%s", exp, p + 1);
1220071d4279SBram Moolenaar var = NameBuff;
1221071d4279SBram Moolenaar }
1222071d4279SBram Moolenaar }
1223071d4279SBram Moolenaar }
1224071d4279SBram Moolenaar
122585a2002aSBram Moolenaar if (var != NULL && *var == NUL) // empty is same as not set
122648340b62SBram Moolenaar var = NULL;
1227071d4279SBram Moolenaar
122805159a0cSBram Moolenaar if (enc_utf8 && var != NULL)
122905159a0cSBram Moolenaar {
123005159a0cSBram Moolenaar int len;
1231b453a53bSBram Moolenaar char_u *pp = NULL;
123205159a0cSBram Moolenaar
123385a2002aSBram Moolenaar // Convert from active codepage to UTF-8. Other conversions are
123485a2002aSBram Moolenaar // not done, because they would fail for non-ASCII characters.
1235a93fa7eeSBram Moolenaar acp_to_enc(var, (int)STRLEN(var), &pp, &len);
123605159a0cSBram Moolenaar if (pp != NULL)
123705159a0cSBram Moolenaar {
123805159a0cSBram Moolenaar homedir = pp;
123905159a0cSBram Moolenaar return;
124005159a0cSBram Moolenaar }
124105159a0cSBram Moolenaar }
1242071d4279SBram Moolenaar
1243071d4279SBram Moolenaar /*
1244071d4279SBram Moolenaar * Default home dir is C:/
1245071d4279SBram Moolenaar * Best assumption we can make in such a situation.
1246071d4279SBram Moolenaar */
1247071d4279SBram Moolenaar if (var == NULL)
12486aa2cd4bSBram Moolenaar var = (char_u *)"C:/";
1249071d4279SBram Moolenaar #endif
125048340b62SBram Moolenaar
1251071d4279SBram Moolenaar if (var != NULL)
1252071d4279SBram Moolenaar {
1253071d4279SBram Moolenaar #ifdef UNIX
1254071d4279SBram Moolenaar /*
1255071d4279SBram Moolenaar * Change to the directory and get the actual path. This resolves
1256071d4279SBram Moolenaar * links. Don't do it when we can't return.
1257071d4279SBram Moolenaar */
1258071d4279SBram Moolenaar if (mch_dirname(NameBuff, MAXPATHL) == OK
1259071d4279SBram Moolenaar && mch_chdir((char *)NameBuff) == 0)
1260071d4279SBram Moolenaar {
1261071d4279SBram Moolenaar if (!mch_chdir((char *)var) && mch_dirname(IObuff, IOSIZE) == OK)
1262071d4279SBram Moolenaar var = IObuff;
1263071d4279SBram Moolenaar if (mch_chdir((char *)NameBuff) != 0)
1264f9e3e09fSBram Moolenaar emsg(_(e_prev_dir));
1265071d4279SBram Moolenaar }
1266071d4279SBram Moolenaar #endif
1267071d4279SBram Moolenaar homedir = vim_strsave(var);
1268071d4279SBram Moolenaar }
1269071d4279SBram Moolenaar }
1270071d4279SBram Moolenaar
1271f461c8e7SBram Moolenaar #if defined(EXITFREE) || defined(PROTO)
1272f461c8e7SBram Moolenaar void
free_homedir(void)12739b57814dSBram Moolenaar free_homedir(void)
1274f461c8e7SBram Moolenaar {
1275f461c8e7SBram Moolenaar vim_free(homedir);
1276f461c8e7SBram Moolenaar }
127724305866SBram Moolenaar
127824305866SBram Moolenaar void
free_users(void)12799b57814dSBram Moolenaar free_users(void)
128024305866SBram Moolenaar {
128124305866SBram Moolenaar ga_clear_strings(&ga_users);
128224305866SBram Moolenaar }
128324305866SBram Moolenaar #endif
1284f461c8e7SBram Moolenaar
1285071d4279SBram Moolenaar /*
12869f0545d6SBram Moolenaar * Call expand_env() and store the result in an allocated string.
12879f0545d6SBram Moolenaar * This is not very memory efficient, this expects the result to be freed
12889f0545d6SBram Moolenaar * again soon.
12899f0545d6SBram Moolenaar */
12909f0545d6SBram Moolenaar char_u *
expand_env_save(char_u * src)12919b57814dSBram Moolenaar expand_env_save(char_u *src)
12929f0545d6SBram Moolenaar {
12939f0545d6SBram Moolenaar return expand_env_save_opt(src, FALSE);
12949f0545d6SBram Moolenaar }
12959f0545d6SBram Moolenaar
12969f0545d6SBram Moolenaar /*
12979f0545d6SBram Moolenaar * Idem, but when "one" is TRUE handle the string as one file name, only
12989f0545d6SBram Moolenaar * expand "~" at the start.
12999f0545d6SBram Moolenaar */
13009f0545d6SBram Moolenaar char_u *
expand_env_save_opt(char_u * src,int one)13019b57814dSBram Moolenaar expand_env_save_opt(char_u *src, int one)
13029f0545d6SBram Moolenaar {
13039f0545d6SBram Moolenaar char_u *p;
13049f0545d6SBram Moolenaar
13059f0545d6SBram Moolenaar p = alloc(MAXPATHL);
13069f0545d6SBram Moolenaar if (p != NULL)
13079f0545d6SBram Moolenaar expand_env_esc(src, p, MAXPATHL, FALSE, one, NULL);
13089f0545d6SBram Moolenaar return p;
13099f0545d6SBram Moolenaar }
13109f0545d6SBram Moolenaar
13119f0545d6SBram Moolenaar /*
1312071d4279SBram Moolenaar * Expand environment variable with path name.
1313071d4279SBram Moolenaar * "~/" is also expanded, using $HOME. For Unix "~user/" is expanded.
13149f0545d6SBram Moolenaar * Skips over "\ ", "\~" and "\$" (not for Win32 though).
1315071d4279SBram Moolenaar * If anything fails no expansion is done and dst equals src.
1316071d4279SBram Moolenaar */
1317071d4279SBram Moolenaar void
expand_env(char_u * src,char_u * dst,int dstlen)13189b57814dSBram Moolenaar expand_env(
131985a2002aSBram Moolenaar char_u *src, // input string e.g. "$HOME/vim.hlp"
132085a2002aSBram Moolenaar char_u *dst, // where to put the result
132185a2002aSBram Moolenaar int dstlen) // maximum length of the result
1322071d4279SBram Moolenaar {
13239f0545d6SBram Moolenaar expand_env_esc(src, dst, dstlen, FALSE, FALSE, NULL);
1324071d4279SBram Moolenaar }
1325071d4279SBram Moolenaar
1326071d4279SBram Moolenaar void
expand_env_esc(char_u * srcp,char_u * dst,int dstlen,int esc,int one,char_u * startstr)13279b57814dSBram Moolenaar expand_env_esc(
132885a2002aSBram Moolenaar char_u *srcp, // input string e.g. "$HOME/vim.hlp"
132985a2002aSBram Moolenaar char_u *dst, // where to put the result
133085a2002aSBram Moolenaar int dstlen, // maximum length of the result
133185a2002aSBram Moolenaar int esc, // escape spaces in expanded variables
133285a2002aSBram Moolenaar int one, // "srcp" is one file name
133385a2002aSBram Moolenaar char_u *startstr) // start again after this (can be NULL)
1334071d4279SBram Moolenaar {
133524bbcfe8SBram Moolenaar char_u *src;
1336071d4279SBram Moolenaar char_u *tail;
1337071d4279SBram Moolenaar int c;
1338071d4279SBram Moolenaar char_u *var;
1339071d4279SBram Moolenaar int copy_char;
134085a2002aSBram Moolenaar int mustfree; // var was allocated, need to free it later
134185a2002aSBram Moolenaar int at_start = TRUE; // at start of a name
134224bbcfe8SBram Moolenaar int startstr_len = 0;
1343071d4279SBram Moolenaar
134424bbcfe8SBram Moolenaar if (startstr != NULL)
1345a93fa7eeSBram Moolenaar startstr_len = (int)STRLEN(startstr);
134624bbcfe8SBram Moolenaar
134724bbcfe8SBram Moolenaar src = skipwhite(srcp);
134885a2002aSBram Moolenaar --dstlen; // leave one char space for "\,"
1349071d4279SBram Moolenaar while (*src && dstlen > 0)
1350071d4279SBram Moolenaar {
1351be83b73dSBram Moolenaar #ifdef FEAT_EVAL
135285a2002aSBram Moolenaar // Skip over `=expr`.
1353be83b73dSBram Moolenaar if (src[0] == '`' && src[1] == '=')
1354be83b73dSBram Moolenaar {
1355be83b73dSBram Moolenaar size_t len;
1356be83b73dSBram Moolenaar
1357be83b73dSBram Moolenaar var = src;
1358be83b73dSBram Moolenaar src += 2;
1359683581ebSBram Moolenaar (void)skip_expr(&src, NULL);
1360be83b73dSBram Moolenaar if (*src == '`')
1361be83b73dSBram Moolenaar ++src;
1362be83b73dSBram Moolenaar len = src - var;
1363be83b73dSBram Moolenaar if (len > (size_t)dstlen)
1364be83b73dSBram Moolenaar len = dstlen;
1365be83b73dSBram Moolenaar vim_strncpy(dst, var, len);
1366be83b73dSBram Moolenaar dst += len;
13675df1ed2dSBram Moolenaar dstlen -= (int)len;
1368be83b73dSBram Moolenaar continue;
1369be83b73dSBram Moolenaar }
1370be83b73dSBram Moolenaar #endif
1371071d4279SBram Moolenaar copy_char = TRUE;
1372d4755bb0SBram Moolenaar if ((*src == '$'
1373d4755bb0SBram Moolenaar #ifdef VMS
1374d4755bb0SBram Moolenaar && at_start
1375d4755bb0SBram Moolenaar #endif
1376d4755bb0SBram Moolenaar )
137748e330afSBram Moolenaar #if defined(MSWIN)
1378071d4279SBram Moolenaar || *src == '%'
1379071d4279SBram Moolenaar #endif
1380071d4279SBram Moolenaar || (*src == '~' && at_start))
1381071d4279SBram Moolenaar {
1382071d4279SBram Moolenaar mustfree = FALSE;
1383071d4279SBram Moolenaar
1384071d4279SBram Moolenaar /*
1385071d4279SBram Moolenaar * The variable name is copied into dst temporarily, because it may
1386071d4279SBram Moolenaar * be a string in read-only memory and a NUL needs to be appended.
1387071d4279SBram Moolenaar */
138885a2002aSBram Moolenaar if (*src != '~') // environment var
1389071d4279SBram Moolenaar {
1390071d4279SBram Moolenaar tail = src + 1;
1391071d4279SBram Moolenaar var = dst;
1392071d4279SBram Moolenaar c = dstlen - 1;
1393071d4279SBram Moolenaar
1394071d4279SBram Moolenaar #ifdef UNIX
139585a2002aSBram Moolenaar // Unix has ${var-name} type environment vars
1396071d4279SBram Moolenaar if (*tail == '{' && !vim_isIDc('{'))
1397071d4279SBram Moolenaar {
139885a2002aSBram Moolenaar tail++; // ignore '{'
1399071d4279SBram Moolenaar while (c-- > 0 && *tail && *tail != '}')
1400071d4279SBram Moolenaar *var++ = *tail++;
1401071d4279SBram Moolenaar }
1402071d4279SBram Moolenaar else
1403071d4279SBram Moolenaar #endif
1404071d4279SBram Moolenaar {
1405071d4279SBram Moolenaar while (c-- > 0 && *tail != NUL && ((vim_isIDc(*tail))
140648e330afSBram Moolenaar #if defined(MSWIN)
1407071d4279SBram Moolenaar || (*src == '%' && *tail != '%')
1408071d4279SBram Moolenaar #endif
1409071d4279SBram Moolenaar ))
1410071d4279SBram Moolenaar *var++ = *tail++;
1411071d4279SBram Moolenaar }
1412071d4279SBram Moolenaar
141348e330afSBram Moolenaar #if defined(MSWIN) || defined(UNIX)
1414071d4279SBram Moolenaar # ifdef UNIX
1415071d4279SBram Moolenaar if (src[1] == '{' && *tail != '}')
1416071d4279SBram Moolenaar # else
1417071d4279SBram Moolenaar if (*src == '%' && *tail != '%')
1418071d4279SBram Moolenaar # endif
1419071d4279SBram Moolenaar var = NULL;
1420071d4279SBram Moolenaar else
1421071d4279SBram Moolenaar {
1422071d4279SBram Moolenaar # ifdef UNIX
1423071d4279SBram Moolenaar if (src[1] == '{')
1424071d4279SBram Moolenaar # else
1425071d4279SBram Moolenaar if (*src == '%')
1426071d4279SBram Moolenaar #endif
1427071d4279SBram Moolenaar ++tail;
1428071d4279SBram Moolenaar #endif
1429071d4279SBram Moolenaar *var = NUL;
1430071d4279SBram Moolenaar var = vim_getenv(dst, &mustfree);
143148e330afSBram Moolenaar #if defined(MSWIN) || defined(UNIX)
1432071d4279SBram Moolenaar }
1433071d4279SBram Moolenaar #endif
1434071d4279SBram Moolenaar }
143585a2002aSBram Moolenaar // home directory
1436071d4279SBram Moolenaar else if ( src[1] == NUL
1437071d4279SBram Moolenaar || vim_ispathsep(src[1])
1438071d4279SBram Moolenaar || vim_strchr((char_u *)" ,\t\n", src[1]) != NULL)
1439071d4279SBram Moolenaar {
1440071d4279SBram Moolenaar var = homedir;
1441071d4279SBram Moolenaar tail = src + 1;
1442071d4279SBram Moolenaar }
144385a2002aSBram Moolenaar else // user directory
1444071d4279SBram Moolenaar {
1445071d4279SBram Moolenaar #if defined(UNIX) || (defined(VMS) && defined(USER_HOME))
1446071d4279SBram Moolenaar /*
1447071d4279SBram Moolenaar * Copy ~user to dst[], so we can put a NUL after it.
1448071d4279SBram Moolenaar */
1449071d4279SBram Moolenaar tail = src;
1450071d4279SBram Moolenaar var = dst;
1451071d4279SBram Moolenaar c = dstlen - 1;
1452071d4279SBram Moolenaar while ( c-- > 0
1453071d4279SBram Moolenaar && *tail
1454071d4279SBram Moolenaar && vim_isfilec(*tail)
1455071d4279SBram Moolenaar && !vim_ispathsep(*tail))
1456071d4279SBram Moolenaar *var++ = *tail++;
1457071d4279SBram Moolenaar *var = NUL;
1458071d4279SBram Moolenaar # ifdef UNIX
1459071d4279SBram Moolenaar /*
1460071d4279SBram Moolenaar * If the system supports getpwnam(), use it.
1461071d4279SBram Moolenaar * Otherwise, or if getpwnam() fails, the shell is used to
1462071d4279SBram Moolenaar * expand ~user. This is slower and may fail if the shell
1463071d4279SBram Moolenaar * does not support ~user (old versions of /bin/sh).
1464071d4279SBram Moolenaar */
1465071d4279SBram Moolenaar # if defined(HAVE_GETPWNAM) && defined(HAVE_PWD_H)
1466071d4279SBram Moolenaar {
146785a2002aSBram Moolenaar // Note: memory allocated by getpwnam() is never freed.
146885a2002aSBram Moolenaar // Calling endpwent() apparently doesn't help.
1469187a4f28SBram Moolenaar struct passwd *pw = (*dst == NUL)
1470187a4f28SBram Moolenaar ? NULL : getpwnam((char *)dst + 1);
1471187a4f28SBram Moolenaar
1472187a4f28SBram Moolenaar var = (pw == NULL) ? NULL : (char_u *)pw->pw_dir;
1473071d4279SBram Moolenaar }
1474071d4279SBram Moolenaar if (var == NULL)
1475071d4279SBram Moolenaar # endif
1476071d4279SBram Moolenaar {
1477071d4279SBram Moolenaar expand_T xpc;
1478071d4279SBram Moolenaar
1479071d4279SBram Moolenaar ExpandInit(&xpc);
1480071d4279SBram Moolenaar xpc.xp_context = EXPAND_FILES;
1481071d4279SBram Moolenaar var = ExpandOne(&xpc, dst, NULL,
1482071d4279SBram Moolenaar WILD_ADD_SLASH|WILD_SILENT, WILD_EXPAND_FREE);
1483071d4279SBram Moolenaar mustfree = TRUE;
1484071d4279SBram Moolenaar }
1485071d4279SBram Moolenaar
148685a2002aSBram Moolenaar # else // !UNIX, thus VMS
1487071d4279SBram Moolenaar /*
1488071d4279SBram Moolenaar * USER_HOME is a comma-separated list of
1489071d4279SBram Moolenaar * directories to search for the user account in.
1490071d4279SBram Moolenaar */
1491071d4279SBram Moolenaar {
1492071d4279SBram Moolenaar char_u test[MAXPATHL], paths[MAXPATHL];
1493071d4279SBram Moolenaar char_u *path, *next_path, *ptr;
14948767f52fSBram Moolenaar stat_T st;
1495071d4279SBram Moolenaar
1496071d4279SBram Moolenaar STRCPY(paths, USER_HOME);
1497071d4279SBram Moolenaar next_path = paths;
1498071d4279SBram Moolenaar while (*next_path)
1499071d4279SBram Moolenaar {
1500071d4279SBram Moolenaar for (path = next_path; *next_path && *next_path != ',';
1501071d4279SBram Moolenaar next_path++);
1502071d4279SBram Moolenaar if (*next_path)
1503071d4279SBram Moolenaar *next_path++ = NUL;
1504071d4279SBram Moolenaar STRCPY(test, path);
1505071d4279SBram Moolenaar STRCAT(test, "/");
1506071d4279SBram Moolenaar STRCAT(test, dst + 1);
1507071d4279SBram Moolenaar if (mch_stat(test, &st) == 0)
1508071d4279SBram Moolenaar {
1509071d4279SBram Moolenaar var = alloc(STRLEN(test) + 1);
1510071d4279SBram Moolenaar STRCPY(var, test);
1511071d4279SBram Moolenaar mustfree = TRUE;
1512071d4279SBram Moolenaar break;
1513071d4279SBram Moolenaar }
1514071d4279SBram Moolenaar }
1515071d4279SBram Moolenaar }
151685a2002aSBram Moolenaar # endif // UNIX
1517071d4279SBram Moolenaar #else
151885a2002aSBram Moolenaar // cannot expand user's home directory, so don't try
1519071d4279SBram Moolenaar var = NULL;
152085a2002aSBram Moolenaar tail = (char_u *)""; // for gcc
152185a2002aSBram Moolenaar #endif // UNIX || VMS
1522071d4279SBram Moolenaar }
1523071d4279SBram Moolenaar
1524071d4279SBram Moolenaar #ifdef BACKSLASH_IN_FILENAME
152585a2002aSBram Moolenaar // If 'shellslash' is set change backslashes to forward slashes.
152685a2002aSBram Moolenaar // Can't use slash_adjust(), p_ssl may be set temporarily.
1527071d4279SBram Moolenaar if (p_ssl && var != NULL && vim_strchr(var, '\\') != NULL)
1528071d4279SBram Moolenaar {
1529071d4279SBram Moolenaar char_u *p = vim_strsave(var);
1530071d4279SBram Moolenaar
1531071d4279SBram Moolenaar if (p != NULL)
1532071d4279SBram Moolenaar {
1533071d4279SBram Moolenaar if (mustfree)
1534071d4279SBram Moolenaar vim_free(var);
1535071d4279SBram Moolenaar var = p;
1536071d4279SBram Moolenaar mustfree = TRUE;
1537071d4279SBram Moolenaar forward_slash(var);
1538071d4279SBram Moolenaar }
1539071d4279SBram Moolenaar }
1540071d4279SBram Moolenaar #endif
1541071d4279SBram Moolenaar
154285a2002aSBram Moolenaar // If "var" contains white space, escape it with a backslash.
154385a2002aSBram Moolenaar // Required for ":e ~/tt" when $HOME includes a space.
1544071d4279SBram Moolenaar if (esc && var != NULL && vim_strpbrk(var, (char_u *)" \t") != NULL)
1545071d4279SBram Moolenaar {
1546071d4279SBram Moolenaar char_u *p = vim_strsave_escaped(var, (char_u *)" \t");
1547071d4279SBram Moolenaar
1548071d4279SBram Moolenaar if (p != NULL)
1549071d4279SBram Moolenaar {
1550071d4279SBram Moolenaar if (mustfree)
1551071d4279SBram Moolenaar vim_free(var);
1552071d4279SBram Moolenaar var = p;
1553071d4279SBram Moolenaar mustfree = TRUE;
1554071d4279SBram Moolenaar }
1555071d4279SBram Moolenaar }
1556071d4279SBram Moolenaar
1557071d4279SBram Moolenaar if (var != NULL && *var != NUL
1558071d4279SBram Moolenaar && (STRLEN(var) + STRLEN(tail) + 1 < (unsigned)dstlen))
1559071d4279SBram Moolenaar {
1560071d4279SBram Moolenaar STRCPY(dst, var);
1561071d4279SBram Moolenaar dstlen -= (int)STRLEN(var);
1562a93fa7eeSBram Moolenaar c = (int)STRLEN(var);
156385a2002aSBram Moolenaar // if var[] ends in a path separator and tail[] starts
156485a2002aSBram Moolenaar // with it, skip a character
15651cd871b5SBram Moolenaar if (*var != NUL && after_pathsep(dst, dst + c)
1566071d4279SBram Moolenaar #if defined(BACKSLASH_IN_FILENAME) || defined(AMIGA)
1567071d4279SBram Moolenaar && dst[-1] != ':'
1568071d4279SBram Moolenaar #endif
1569071d4279SBram Moolenaar && vim_ispathsep(*tail))
1570071d4279SBram Moolenaar ++tail;
15711cd871b5SBram Moolenaar dst += c;
1572071d4279SBram Moolenaar src = tail;
1573071d4279SBram Moolenaar copy_char = FALSE;
1574071d4279SBram Moolenaar }
1575071d4279SBram Moolenaar if (mustfree)
1576071d4279SBram Moolenaar vim_free(var);
1577071d4279SBram Moolenaar }
1578071d4279SBram Moolenaar
157985a2002aSBram Moolenaar if (copy_char) // copy at least one char
1580071d4279SBram Moolenaar {
1581071d4279SBram Moolenaar /*
158225394022SBram Moolenaar * Recognize the start of a new name, for '~'.
15839f0545d6SBram Moolenaar * Don't do this when "one" is TRUE, to avoid expanding "~" in
15849f0545d6SBram Moolenaar * ":edit foo ~ foo".
1585071d4279SBram Moolenaar */
1586071d4279SBram Moolenaar at_start = FALSE;
1587071d4279SBram Moolenaar if (src[0] == '\\' && src[1] != NUL)
1588071d4279SBram Moolenaar {
1589071d4279SBram Moolenaar *dst++ = *src++;
1590071d4279SBram Moolenaar --dstlen;
1591071d4279SBram Moolenaar }
15929f0545d6SBram Moolenaar else if ((src[0] == ' ' || src[0] == ',') && !one)
1593071d4279SBram Moolenaar at_start = TRUE;
15941c864093SBram Moolenaar if (dstlen > 0)
15951c864093SBram Moolenaar {
1596071d4279SBram Moolenaar *dst++ = *src++;
1597071d4279SBram Moolenaar --dstlen;
159824bbcfe8SBram Moolenaar
159924bbcfe8SBram Moolenaar if (startstr != NULL && src - startstr_len >= srcp
16001c864093SBram Moolenaar && STRNCMP(src - startstr_len, startstr,
16011c864093SBram Moolenaar startstr_len) == 0)
160224bbcfe8SBram Moolenaar at_start = TRUE;
1603071d4279SBram Moolenaar }
1604071d4279SBram Moolenaar }
16051c864093SBram Moolenaar
16061c864093SBram Moolenaar }
1607071d4279SBram Moolenaar *dst = NUL;
1608071d4279SBram Moolenaar }
1609071d4279SBram Moolenaar
1610071d4279SBram Moolenaar /*
161126262f87SBram Moolenaar * If the string between "p" and "pend" ends in "name/", return "pend" minus
161226262f87SBram Moolenaar * the length of "name/". Otherwise return "pend".
161326262f87SBram Moolenaar */
161426262f87SBram Moolenaar static char_u *
remove_tail(char_u * p,char_u * pend,char_u * name)161526262f87SBram Moolenaar remove_tail(char_u *p, char_u *pend, char_u *name)
161626262f87SBram Moolenaar {
161726262f87SBram Moolenaar int len = (int)STRLEN(name) + 1;
161826262f87SBram Moolenaar char_u *newend = pend - len;
161926262f87SBram Moolenaar
162026262f87SBram Moolenaar if (newend >= p
162126262f87SBram Moolenaar && fnamencmp(newend, name, len - 1) == 0
162226262f87SBram Moolenaar && (newend == p || after_pathsep(p, newend)))
162326262f87SBram Moolenaar return newend;
162426262f87SBram Moolenaar return pend;
162526262f87SBram Moolenaar }
162626262f87SBram Moolenaar
162726262f87SBram Moolenaar /*
162826262f87SBram Moolenaar * Check if the directory "vimdir/<version>" or "vimdir/runtime" exists.
162926262f87SBram Moolenaar * Return NULL if not, return its name in allocated memory otherwise.
163026262f87SBram Moolenaar */
163126262f87SBram Moolenaar static char_u *
vim_version_dir(char_u * vimdir)163226262f87SBram Moolenaar vim_version_dir(char_u *vimdir)
163326262f87SBram Moolenaar {
163426262f87SBram Moolenaar char_u *p;
163526262f87SBram Moolenaar
163626262f87SBram Moolenaar if (vimdir == NULL || *vimdir == NUL)
163726262f87SBram Moolenaar return NULL;
163826262f87SBram Moolenaar p = concat_fnames(vimdir, (char_u *)VIM_VERSION_NODOT, TRUE);
163926262f87SBram Moolenaar if (p != NULL && mch_isdir(p))
164026262f87SBram Moolenaar return p;
164126262f87SBram Moolenaar vim_free(p);
164226262f87SBram Moolenaar p = concat_fnames(vimdir, (char_u *)RUNTIME_DIRNAME, TRUE);
164326262f87SBram Moolenaar if (p != NULL && mch_isdir(p))
164426262f87SBram Moolenaar return p;
164526262f87SBram Moolenaar vim_free(p);
164626262f87SBram Moolenaar return NULL;
164726262f87SBram Moolenaar }
164826262f87SBram Moolenaar
164926262f87SBram Moolenaar /*
1650071d4279SBram Moolenaar * Vim's version of getenv().
1651071d4279SBram Moolenaar * Special handling of $HOME, $VIM and $VIMRUNTIME.
16522f6b0b8fSBram Moolenaar * Also does ACP to 'enc' conversion for Win32.
1653b453a53bSBram Moolenaar * "mustfree" is set to TRUE when returned is allocated, it must be
1654b453a53bSBram Moolenaar * initialized to FALSE by the caller.
1655071d4279SBram Moolenaar */
1656071d4279SBram Moolenaar char_u *
vim_getenv(char_u * name,int * mustfree)16579b57814dSBram Moolenaar vim_getenv(char_u *name, int *mustfree)
1658071d4279SBram Moolenaar {
1659f0908e6fSBram Moolenaar char_u *p = NULL;
1660071d4279SBram Moolenaar char_u *pend;
1661071d4279SBram Moolenaar int vimruntime;
1662f0908e6fSBram Moolenaar #ifdef MSWIN
1663f0908e6fSBram Moolenaar WCHAR *wn, *wp;
1664071d4279SBram Moolenaar
1665f0908e6fSBram Moolenaar // use "C:/" when $HOME is not set
1666071d4279SBram Moolenaar if (STRCMP(name, "HOME") == 0)
1667071d4279SBram Moolenaar return homedir;
1668071d4279SBram Moolenaar
1669f0908e6fSBram Moolenaar // Use Wide function
1670f0908e6fSBram Moolenaar wn = enc_to_utf16(name, NULL);
1671f0908e6fSBram Moolenaar if (wn == NULL)
1672f0908e6fSBram Moolenaar return NULL;
1673f0908e6fSBram Moolenaar
1674f0908e6fSBram Moolenaar wp = _wgetenv(wn);
1675f0908e6fSBram Moolenaar vim_free(wn);
1676f0908e6fSBram Moolenaar
1677f0908e6fSBram Moolenaar if (wp != NULL && *wp == NUL) // empty is the same as not set
1678f0908e6fSBram Moolenaar wp = NULL;
1679f0908e6fSBram Moolenaar
1680f0908e6fSBram Moolenaar if (wp != NULL)
1681f0908e6fSBram Moolenaar {
1682f0908e6fSBram Moolenaar p = utf16_to_enc(wp, NULL);
1683f0908e6fSBram Moolenaar if (p == NULL)
1684f0908e6fSBram Moolenaar return NULL;
1685f0908e6fSBram Moolenaar
1686f0908e6fSBram Moolenaar *mustfree = TRUE;
1687f0908e6fSBram Moolenaar return p;
1688f0908e6fSBram Moolenaar }
1689f0908e6fSBram Moolenaar #else
1690071d4279SBram Moolenaar p = mch_getenv(name);
1691f0908e6fSBram Moolenaar if (p != NULL && *p == NUL) // empty is the same as not set
1692071d4279SBram Moolenaar p = NULL;
1693071d4279SBram Moolenaar
1694071d4279SBram Moolenaar if (p != NULL)
1695071d4279SBram Moolenaar return p;
169680a8d388SBram Moolenaar
169780a8d388SBram Moolenaar # ifdef __HAIKU__
169880a8d388SBram Moolenaar // special handling for user settings directory...
169980a8d388SBram Moolenaar if (STRCMP(name, "BE_USER_SETTINGS") == 0)
170080a8d388SBram Moolenaar {
170180a8d388SBram Moolenaar static char userSettingsPath[MAXPATHL];
170280a8d388SBram Moolenaar
170380a8d388SBram Moolenaar if (find_directory(B_USER_SETTINGS_DIRECTORY, 0, false,
170480a8d388SBram Moolenaar userSettingsPath, MAXPATHL) == B_OK)
170580a8d388SBram Moolenaar return (char_u *)userSettingsPath;
170680a8d388SBram Moolenaar else
170780a8d388SBram Moolenaar return NULL;
170880a8d388SBram Moolenaar }
170980a8d388SBram Moolenaar # endif
1710f0908e6fSBram Moolenaar #endif
1711071d4279SBram Moolenaar
1712f0908e6fSBram Moolenaar // handling $VIMRUNTIME and $VIM is below, bail out if it's another name.
1713071d4279SBram Moolenaar vimruntime = (STRCMP(name, "VIMRUNTIME") == 0);
1714071d4279SBram Moolenaar if (!vimruntime && STRCMP(name, "VIM") != 0)
1715071d4279SBram Moolenaar return NULL;
1716071d4279SBram Moolenaar
1717071d4279SBram Moolenaar /*
1718071d4279SBram Moolenaar * When expanding $VIMRUNTIME fails, try using $VIM/vim<version> or $VIM.
1719071d4279SBram Moolenaar * Don't do this when default_vimruntime_dir is non-empty.
1720071d4279SBram Moolenaar */
1721071d4279SBram Moolenaar if (vimruntime
1722071d4279SBram Moolenaar #ifdef HAVE_PATHDEF
1723071d4279SBram Moolenaar && *default_vimruntime_dir == NUL
1724071d4279SBram Moolenaar #endif
1725071d4279SBram Moolenaar )
1726071d4279SBram Moolenaar {
1727f0908e6fSBram Moolenaar #ifdef MSWIN
1728f0908e6fSBram Moolenaar // Use Wide function
1729f0908e6fSBram Moolenaar wp = _wgetenv(L"VIM");
1730f0908e6fSBram Moolenaar if (wp != NULL && *wp == NUL) // empty is the same as not set
1731f0908e6fSBram Moolenaar wp = NULL;
1732f0908e6fSBram Moolenaar if (wp != NULL)
1733f0908e6fSBram Moolenaar {
1734f0908e6fSBram Moolenaar char_u *q = utf16_to_enc(wp, NULL);
1735f0908e6fSBram Moolenaar if (q != NULL)
1736f0908e6fSBram Moolenaar {
1737f0908e6fSBram Moolenaar p = vim_version_dir(q);
1738f0908e6fSBram Moolenaar *mustfree = TRUE;
1739f0908e6fSBram Moolenaar if (p == NULL)
1740f0908e6fSBram Moolenaar p = q;
1741f0908e6fSBram Moolenaar }
1742f0908e6fSBram Moolenaar }
1743f0908e6fSBram Moolenaar #else
1744071d4279SBram Moolenaar p = mch_getenv((char_u *)"VIM");
1745f0908e6fSBram Moolenaar if (p != NULL && *p == NUL) // empty is the same as not set
1746071d4279SBram Moolenaar p = NULL;
1747071d4279SBram Moolenaar if (p != NULL)
1748071d4279SBram Moolenaar {
1749071d4279SBram Moolenaar p = vim_version_dir(p);
1750071d4279SBram Moolenaar if (p != NULL)
1751071d4279SBram Moolenaar *mustfree = TRUE;
1752071d4279SBram Moolenaar else
1753071d4279SBram Moolenaar p = mch_getenv((char_u *)"VIM");
175405159a0cSBram Moolenaar }
175505159a0cSBram Moolenaar #endif
1756071d4279SBram Moolenaar }
1757071d4279SBram Moolenaar
1758071d4279SBram Moolenaar /*
1759071d4279SBram Moolenaar * When expanding $VIM or $VIMRUNTIME fails, try using:
1760071d4279SBram Moolenaar * - the directory name from 'helpfile' (unless it contains '$')
1761071d4279SBram Moolenaar * - the executable name from argv[0]
1762071d4279SBram Moolenaar */
1763071d4279SBram Moolenaar if (p == NULL)
1764071d4279SBram Moolenaar {
1765071d4279SBram Moolenaar if (p_hf != NULL && vim_strchr(p_hf, '$') == NULL)
1766071d4279SBram Moolenaar p = p_hf;
1767071d4279SBram Moolenaar #ifdef USE_EXE_NAME
1768071d4279SBram Moolenaar /*
1769071d4279SBram Moolenaar * Use the name of the executable, obtained from argv[0].
1770071d4279SBram Moolenaar */
1771071d4279SBram Moolenaar else
1772071d4279SBram Moolenaar p = exe_name;
1773071d4279SBram Moolenaar #endif
1774071d4279SBram Moolenaar if (p != NULL)
1775071d4279SBram Moolenaar {
177685a2002aSBram Moolenaar // remove the file name
1777071d4279SBram Moolenaar pend = gettail(p);
1778071d4279SBram Moolenaar
177985a2002aSBram Moolenaar // remove "doc/" from 'helpfile', if present
1780071d4279SBram Moolenaar if (p == p_hf)
1781071d4279SBram Moolenaar pend = remove_tail(p, pend, (char_u *)"doc");
1782071d4279SBram Moolenaar
1783071d4279SBram Moolenaar #ifdef USE_EXE_NAME
1784071d4279SBram Moolenaar # ifdef MACOS_X
178585a2002aSBram Moolenaar // remove "MacOS" from exe_name and add "Resources/vim"
1786071d4279SBram Moolenaar if (p == exe_name)
1787071d4279SBram Moolenaar {
1788071d4279SBram Moolenaar char_u *pend1;
178995e9b495SBram Moolenaar char_u *pnew;
1790071d4279SBram Moolenaar
179195e9b495SBram Moolenaar pend1 = remove_tail(p, pend, (char_u *)"MacOS");
179295e9b495SBram Moolenaar if (pend1 != pend)
179395e9b495SBram Moolenaar {
1794964b3746SBram Moolenaar pnew = alloc(pend1 - p + 15);
179595e9b495SBram Moolenaar if (pnew != NULL)
179695e9b495SBram Moolenaar {
179795e9b495SBram Moolenaar STRNCPY(pnew, p, (pend1 - p));
179895e9b495SBram Moolenaar STRCPY(pnew + (pend1 - p), "Resources/vim");
179995e9b495SBram Moolenaar p = pnew;
180095e9b495SBram Moolenaar pend = p + STRLEN(p);
180195e9b495SBram Moolenaar }
180295e9b495SBram Moolenaar }
1803071d4279SBram Moolenaar }
1804071d4279SBram Moolenaar # endif
180585a2002aSBram Moolenaar // remove "src/" from exe_name, if present
1806071d4279SBram Moolenaar if (p == exe_name)
1807071d4279SBram Moolenaar pend = remove_tail(p, pend, (char_u *)"src");
1808071d4279SBram Moolenaar #endif
1809071d4279SBram Moolenaar
181085a2002aSBram Moolenaar // for $VIM, remove "runtime/" or "vim54/", if present
1811071d4279SBram Moolenaar if (!vimruntime)
1812071d4279SBram Moolenaar {
1813071d4279SBram Moolenaar pend = remove_tail(p, pend, (char_u *)RUNTIME_DIRNAME);
1814071d4279SBram Moolenaar pend = remove_tail(p, pend, (char_u *)VIM_VERSION_NODOT);
1815071d4279SBram Moolenaar }
1816071d4279SBram Moolenaar
181785a2002aSBram Moolenaar // remove trailing path separator
18181cd871b5SBram Moolenaar if (pend > p && after_pathsep(p, pend))
1819071d4279SBram Moolenaar --pend;
1820071d4279SBram Moolenaar
182195e9b495SBram Moolenaar #ifdef MACOS_X
182295e9b495SBram Moolenaar if (p == exe_name || p == p_hf)
182395e9b495SBram Moolenaar #endif
182485a2002aSBram Moolenaar // check that the result is a directory name
182571ccd03eSBram Moolenaar p = vim_strnsave(p, pend - p);
1826071d4279SBram Moolenaar
1827071d4279SBram Moolenaar if (p != NULL && !mch_isdir(p))
1828d23a8236SBram Moolenaar VIM_CLEAR(p);
1829071d4279SBram Moolenaar else
1830071d4279SBram Moolenaar {
1831071d4279SBram Moolenaar #ifdef USE_EXE_NAME
183285a2002aSBram Moolenaar // may add "/vim54" or "/runtime" if it exists
1833071d4279SBram Moolenaar if (vimruntime && (pend = vim_version_dir(p)) != NULL)
1834071d4279SBram Moolenaar {
1835071d4279SBram Moolenaar vim_free(p);
1836071d4279SBram Moolenaar p = pend;
1837071d4279SBram Moolenaar }
1838071d4279SBram Moolenaar #endif
1839071d4279SBram Moolenaar *mustfree = TRUE;
1840071d4279SBram Moolenaar }
1841071d4279SBram Moolenaar }
1842071d4279SBram Moolenaar }
1843071d4279SBram Moolenaar
1844071d4279SBram Moolenaar #ifdef HAVE_PATHDEF
184585a2002aSBram Moolenaar // When there is a pathdef.c file we can use default_vim_dir and
184685a2002aSBram Moolenaar // default_vimruntime_dir
1847071d4279SBram Moolenaar if (p == NULL)
1848071d4279SBram Moolenaar {
184985a2002aSBram Moolenaar // Only use default_vimruntime_dir when it is not empty
1850071d4279SBram Moolenaar if (vimruntime && *default_vimruntime_dir != NUL)
1851071d4279SBram Moolenaar {
1852071d4279SBram Moolenaar p = default_vimruntime_dir;
1853071d4279SBram Moolenaar *mustfree = FALSE;
1854071d4279SBram Moolenaar }
1855071d4279SBram Moolenaar else if (*default_vim_dir != NUL)
1856071d4279SBram Moolenaar {
1857071d4279SBram Moolenaar if (vimruntime && (p = vim_version_dir(default_vim_dir)) != NULL)
1858071d4279SBram Moolenaar *mustfree = TRUE;
1859071d4279SBram Moolenaar else
1860071d4279SBram Moolenaar {
1861071d4279SBram Moolenaar p = default_vim_dir;
1862071d4279SBram Moolenaar *mustfree = FALSE;
1863071d4279SBram Moolenaar }
1864071d4279SBram Moolenaar }
1865071d4279SBram Moolenaar }
1866071d4279SBram Moolenaar #endif
1867071d4279SBram Moolenaar
1868071d4279SBram Moolenaar /*
1869071d4279SBram Moolenaar * Set the environment variable, so that the new value can be found fast
1870071d4279SBram Moolenaar * next time, and others can also use it (e.g. Perl).
1871071d4279SBram Moolenaar */
1872071d4279SBram Moolenaar if (p != NULL)
1873071d4279SBram Moolenaar {
1874071d4279SBram Moolenaar if (vimruntime)
1875071d4279SBram Moolenaar {
1876071d4279SBram Moolenaar vim_setenv((char_u *)"VIMRUNTIME", p);
1877071d4279SBram Moolenaar didset_vimruntime = TRUE;
1878071d4279SBram Moolenaar }
1879071d4279SBram Moolenaar else
1880071d4279SBram Moolenaar {
1881071d4279SBram Moolenaar vim_setenv((char_u *)"VIM", p);
1882071d4279SBram Moolenaar didset_vim = TRUE;
1883071d4279SBram Moolenaar }
1884071d4279SBram Moolenaar }
1885071d4279SBram Moolenaar return p;
1886071d4279SBram Moolenaar }
1887071d4279SBram Moolenaar
1888113e1072SBram Moolenaar #if defined(FEAT_EVAL) || defined(PROTO)
1889137374fdSBram Moolenaar void
vim_unsetenv(char_u * var)1890137374fdSBram Moolenaar vim_unsetenv(char_u *var)
1891137374fdSBram Moolenaar {
1892137374fdSBram Moolenaar #ifdef HAVE_UNSETENV
1893137374fdSBram Moolenaar unsetenv((char *)var);
1894137374fdSBram Moolenaar #else
18951af6a4b8SBram Moolenaar vim_setenv(var, (char_u *)"");
1896137374fdSBram Moolenaar #endif
1897137374fdSBram Moolenaar }
1898113e1072SBram Moolenaar #endif
1899137374fdSBram Moolenaar
1900137374fdSBram Moolenaar
1901071d4279SBram Moolenaar /*
1902b283a8a6SBram Moolenaar * Set environment variable "name" and take care of side effects.
1903b283a8a6SBram Moolenaar */
1904b283a8a6SBram Moolenaar void
vim_setenv_ext(char_u * name,char_u * val)1905b283a8a6SBram Moolenaar vim_setenv_ext(char_u *name, char_u *val)
1906b283a8a6SBram Moolenaar {
1907b283a8a6SBram Moolenaar vim_setenv(name, val);
1908b283a8a6SBram Moolenaar if (STRICMP(name, "HOME") == 0)
1909b283a8a6SBram Moolenaar init_homedir();
1910b283a8a6SBram Moolenaar else if (didset_vim && STRICMP(name, "VIM") == 0)
1911b283a8a6SBram Moolenaar didset_vim = FALSE;
1912b283a8a6SBram Moolenaar else if (didset_vimruntime
1913b283a8a6SBram Moolenaar && STRICMP(name, "VIMRUNTIME") == 0)
1914b283a8a6SBram Moolenaar didset_vimruntime = FALSE;
1915b283a8a6SBram Moolenaar }
1916b283a8a6SBram Moolenaar
1917b283a8a6SBram Moolenaar /*
1918071d4279SBram Moolenaar * Our portable version of setenv.
1919071d4279SBram Moolenaar */
1920071d4279SBram Moolenaar void
vim_setenv(char_u * name,char_u * val)19219b57814dSBram Moolenaar vim_setenv(char_u *name, char_u *val)
1922071d4279SBram Moolenaar {
1923071d4279SBram Moolenaar #ifdef HAVE_SETENV
1924071d4279SBram Moolenaar mch_setenv((char *)name, (char *)val, 1);
1925071d4279SBram Moolenaar #else
1926071d4279SBram Moolenaar char_u *envbuf;
1927071d4279SBram Moolenaar
1928071d4279SBram Moolenaar /*
1929071d4279SBram Moolenaar * Putenv does not copy the string, it has to remain
1930071d4279SBram Moolenaar * valid. The allocated memory will never be freed.
1931071d4279SBram Moolenaar */
1932964b3746SBram Moolenaar envbuf = alloc(STRLEN(name) + STRLEN(val) + 2);
1933071d4279SBram Moolenaar if (envbuf != NULL)
1934071d4279SBram Moolenaar {
1935071d4279SBram Moolenaar sprintf((char *)envbuf, "%s=%s", name, val);
1936071d4279SBram Moolenaar putenv((char *)envbuf);
1937071d4279SBram Moolenaar }
1938071d4279SBram Moolenaar #endif
1939011a34d7SBram Moolenaar #ifdef FEAT_GETTEXT
1940011a34d7SBram Moolenaar /*
1941011a34d7SBram Moolenaar * When setting $VIMRUNTIME adjust the directory to find message
1942011a34d7SBram Moolenaar * translations to $VIMRUNTIME/lang.
1943011a34d7SBram Moolenaar */
1944011a34d7SBram Moolenaar if (*val != NUL && STRICMP(name, "VIMRUNTIME") == 0)
1945011a34d7SBram Moolenaar {
1946011a34d7SBram Moolenaar char_u *buf = concat_str(val, (char_u *)"/lang");
1947011a34d7SBram Moolenaar
1948011a34d7SBram Moolenaar if (buf != NULL)
1949011a34d7SBram Moolenaar {
1950011a34d7SBram Moolenaar bindtextdomain(VIMPACKAGE, (char *)buf);
1951011a34d7SBram Moolenaar vim_free(buf);
1952011a34d7SBram Moolenaar }
1953011a34d7SBram Moolenaar }
1954011a34d7SBram Moolenaar #endif
1955071d4279SBram Moolenaar }
1956071d4279SBram Moolenaar
1957071d4279SBram Moolenaar /*
1958071d4279SBram Moolenaar * Function given to ExpandGeneric() to obtain an environment variable name.
1959071d4279SBram Moolenaar */
1960071d4279SBram Moolenaar char_u *
get_env_name(expand_T * xp UNUSED,int idx)19619b57814dSBram Moolenaar get_env_name(
19629b57814dSBram Moolenaar expand_T *xp UNUSED,
19639b57814dSBram Moolenaar int idx)
1964071d4279SBram Moolenaar {
1965d057301bSBram Moolenaar # if defined(AMIGA)
1966071d4279SBram Moolenaar /*
1967d057301bSBram Moolenaar * No environ[] on the Amiga.
1968071d4279SBram Moolenaar */
1969071d4279SBram Moolenaar return NULL;
1970071d4279SBram Moolenaar # else
1971071d4279SBram Moolenaar # ifndef __WIN32__
197285a2002aSBram Moolenaar // Borland C++ 5.2 has this in a header file.
1973071d4279SBram Moolenaar extern char **environ;
1974071d4279SBram Moolenaar # endif
197521cf823aSBram Moolenaar # define ENVNAMELEN 100
197621cf823aSBram Moolenaar static char_u name[ENVNAMELEN];
1977071d4279SBram Moolenaar char_u *str;
1978071d4279SBram Moolenaar int n;
1979071d4279SBram Moolenaar
1980071d4279SBram Moolenaar str = (char_u *)environ[idx];
1981071d4279SBram Moolenaar if (str == NULL)
1982071d4279SBram Moolenaar return NULL;
1983071d4279SBram Moolenaar
198421cf823aSBram Moolenaar for (n = 0; n < ENVNAMELEN - 1; ++n)
1985071d4279SBram Moolenaar {
1986071d4279SBram Moolenaar if (str[n] == '=' || str[n] == NUL)
1987071d4279SBram Moolenaar break;
1988071d4279SBram Moolenaar name[n] = str[n];
1989071d4279SBram Moolenaar }
1990071d4279SBram Moolenaar name[n] = NUL;
1991071d4279SBram Moolenaar return name;
1992071d4279SBram Moolenaar # endif
1993071d4279SBram Moolenaar }
199424305866SBram Moolenaar
199524305866SBram Moolenaar /*
19966b0b83f7SBram Moolenaar * Add a user name to the list of users in ga_users.
19976b0b83f7SBram Moolenaar * Do nothing if user name is NULL or empty.
19986b0b83f7SBram Moolenaar */
19996b0b83f7SBram Moolenaar static void
add_user(char_u * user,int need_copy)20006b0b83f7SBram Moolenaar add_user(char_u *user, int need_copy)
20016b0b83f7SBram Moolenaar {
20026b0b83f7SBram Moolenaar char_u *user_copy = (user != NULL && need_copy)
20036b0b83f7SBram Moolenaar ? vim_strsave(user) : user;
20046b0b83f7SBram Moolenaar
20056b0b83f7SBram Moolenaar if (user_copy == NULL || *user_copy == NUL || ga_grow(&ga_users, 1) == FAIL)
20066b0b83f7SBram Moolenaar {
20076b0b83f7SBram Moolenaar if (need_copy)
20086b0b83f7SBram Moolenaar vim_free(user);
20096b0b83f7SBram Moolenaar return;
20106b0b83f7SBram Moolenaar }
20116b0b83f7SBram Moolenaar ((char_u **)(ga_users.ga_data))[ga_users.ga_len++] = user_copy;
20126b0b83f7SBram Moolenaar }
20136b0b83f7SBram Moolenaar
20146b0b83f7SBram Moolenaar /*
201524305866SBram Moolenaar * Find all user names for user completion.
201624305866SBram Moolenaar * Done only once and then cached.
201724305866SBram Moolenaar */
201824305866SBram Moolenaar static void
init_users(void)20199b57814dSBram Moolenaar init_users(void)
202001b626c2SBram Moolenaar {
202124305866SBram Moolenaar static int lazy_init_done = FALSE;
202224305866SBram Moolenaar
202324305866SBram Moolenaar if (lazy_init_done)
202424305866SBram Moolenaar return;
202524305866SBram Moolenaar
202624305866SBram Moolenaar lazy_init_done = TRUE;
202724305866SBram Moolenaar ga_init2(&ga_users, sizeof(char_u *), 20);
202824305866SBram Moolenaar
202924305866SBram Moolenaar # if defined(HAVE_GETPWENT) && defined(HAVE_PWD_H)
203024305866SBram Moolenaar {
203124305866SBram Moolenaar struct passwd* pw;
203224305866SBram Moolenaar
203324305866SBram Moolenaar setpwent();
203424305866SBram Moolenaar while ((pw = getpwent()) != NULL)
20356b0b83f7SBram Moolenaar add_user((char_u *)pw->pw_name, TRUE);
203624305866SBram Moolenaar endpwent();
203724305866SBram Moolenaar }
20384f97475dSBram Moolenaar # elif defined(MSWIN)
2039828c3d70SBram Moolenaar {
2040828c3d70SBram Moolenaar DWORD nusers = 0, ntotal = 0, i;
2041828c3d70SBram Moolenaar PUSER_INFO_0 uinfo;
2042828c3d70SBram Moolenaar
2043828c3d70SBram Moolenaar if (NetUserEnum(NULL, 0, 0, (LPBYTE *) &uinfo, MAX_PREFERRED_LENGTH,
2044828c3d70SBram Moolenaar &nusers, &ntotal, NULL) == NERR_Success)
2045828c3d70SBram Moolenaar {
2046828c3d70SBram Moolenaar for (i = 0; i < nusers; i++)
20476b0b83f7SBram Moolenaar add_user(utf16_to_enc(uinfo[i].usri0_name, NULL), FALSE);
2048828c3d70SBram Moolenaar
2049828c3d70SBram Moolenaar NetApiBufferFree(uinfo);
2050828c3d70SBram Moolenaar }
2051828c3d70SBram Moolenaar }
205224305866SBram Moolenaar # endif
20536b0b83f7SBram Moolenaar # if defined(HAVE_GETPWNAM)
20546b0b83f7SBram Moolenaar {
20556b0b83f7SBram Moolenaar char_u *user_env = mch_getenv((char_u *)"USER");
20566b0b83f7SBram Moolenaar
20576b0b83f7SBram Moolenaar // The $USER environment variable may be a valid remote user name (NIS,
20586b0b83f7SBram Moolenaar // LDAP) not already listed by getpwent(), as getpwent() only lists
20596b0b83f7SBram Moolenaar // local user names. If $USER is not already listed, check whether it
20606b0b83f7SBram Moolenaar // is a valid remote user name using getpwnam() and if it is, add it to
20616b0b83f7SBram Moolenaar // the list of user names.
20626b0b83f7SBram Moolenaar
20636b0b83f7SBram Moolenaar if (user_env != NULL && *user_env != NUL)
20646b0b83f7SBram Moolenaar {
20656b0b83f7SBram Moolenaar int i;
20666b0b83f7SBram Moolenaar
20676b0b83f7SBram Moolenaar for (i = 0; i < ga_users.ga_len; i++)
20686b0b83f7SBram Moolenaar {
20696b0b83f7SBram Moolenaar char_u *local_user = ((char_u **)ga_users.ga_data)[i];
20706b0b83f7SBram Moolenaar
20716b0b83f7SBram Moolenaar if (STRCMP(local_user, user_env) == 0)
20726b0b83f7SBram Moolenaar break;
20736b0b83f7SBram Moolenaar }
20746b0b83f7SBram Moolenaar
20756b0b83f7SBram Moolenaar if (i == ga_users.ga_len)
20766b0b83f7SBram Moolenaar {
20776b0b83f7SBram Moolenaar struct passwd *pw = getpwnam((char *)user_env);
20786b0b83f7SBram Moolenaar
20796b0b83f7SBram Moolenaar if (pw != NULL)
20806b0b83f7SBram Moolenaar add_user((char_u *)pw->pw_name, TRUE);
20816b0b83f7SBram Moolenaar }
20826b0b83f7SBram Moolenaar }
20836b0b83f7SBram Moolenaar }
20846b0b83f7SBram Moolenaar # endif
208524305866SBram Moolenaar }
208624305866SBram Moolenaar
208724305866SBram Moolenaar /*
208824305866SBram Moolenaar * Function given to ExpandGeneric() to obtain an user names.
208924305866SBram Moolenaar */
209024305866SBram Moolenaar char_u*
get_users(expand_T * xp UNUSED,int idx)20919b57814dSBram Moolenaar get_users(expand_T *xp UNUSED, int idx)
209224305866SBram Moolenaar {
209324305866SBram Moolenaar init_users();
209424305866SBram Moolenaar if (idx < ga_users.ga_len)
209524305866SBram Moolenaar return ((char_u **)ga_users.ga_data)[idx];
209624305866SBram Moolenaar return NULL;
209724305866SBram Moolenaar }
209824305866SBram Moolenaar
209924305866SBram Moolenaar /*
210024305866SBram Moolenaar * Check whether name matches a user name. Return:
210124305866SBram Moolenaar * 0 if name does not match any user name.
210224305866SBram Moolenaar * 1 if name partially matches the beginning of a user name.
210324305866SBram Moolenaar * 2 is name fully matches a user name.
210424305866SBram Moolenaar */
21056c5d1043SBram Moolenaar int
match_user(char_u * name)21066c5d1043SBram Moolenaar match_user(char_u *name)
210724305866SBram Moolenaar {
210824305866SBram Moolenaar int i;
210924305866SBram Moolenaar int n = (int)STRLEN(name);
211024305866SBram Moolenaar int result = 0;
211124305866SBram Moolenaar
211224305866SBram Moolenaar init_users();
211324305866SBram Moolenaar for (i = 0; i < ga_users.ga_len; i++)
211424305866SBram Moolenaar {
211524305866SBram Moolenaar if (STRCMP(((char_u **)ga_users.ga_data)[i], name) == 0)
211685a2002aSBram Moolenaar return 2; // full match
211724305866SBram Moolenaar if (STRNCMP(((char_u **)ga_users.ga_data)[i], name, n) == 0)
211885a2002aSBram Moolenaar result = 1; // partial match
211924305866SBram Moolenaar }
212024305866SBram Moolenaar return result;
212124305866SBram Moolenaar }
2122071d4279SBram Moolenaar
21235843f5f3SBram Moolenaar static void
prepare_to_exit(void)21249b57814dSBram Moolenaar prepare_to_exit(void)
2125071d4279SBram Moolenaar {
21261cd871b5SBram Moolenaar #if defined(SIGHUP) && defined(SIG_IGN)
212785a2002aSBram Moolenaar // Ignore SIGHUP, because a dropped connection causes a read error, which
212885a2002aSBram Moolenaar // makes Vim exit and then handling SIGHUP causes various reentrance
212985a2002aSBram Moolenaar // problems.
2130293ee4d4SBram Moolenaar signal(SIGHUP, SIG_IGN);
2131293ee4d4SBram Moolenaar #endif
2132293ee4d4SBram Moolenaar
2133071d4279SBram Moolenaar #ifdef FEAT_GUI
2134071d4279SBram Moolenaar if (gui.in_use)
2135071d4279SBram Moolenaar {
2136071d4279SBram Moolenaar gui.dying = TRUE;
213785a2002aSBram Moolenaar out_trash(); // trash any pending output
2138071d4279SBram Moolenaar }
2139071d4279SBram Moolenaar else
2140071d4279SBram Moolenaar #endif
2141071d4279SBram Moolenaar {
2142071d4279SBram Moolenaar windgoto((int)Rows - 1, 0);
2143071d4279SBram Moolenaar
2144071d4279SBram Moolenaar /*
2145071d4279SBram Moolenaar * Switch terminal mode back now, so messages end up on the "normal"
2146071d4279SBram Moolenaar * screen (if there are two screens).
2147071d4279SBram Moolenaar */
2148071d4279SBram Moolenaar settmode(TMODE_COOK);
2149071d4279SBram Moolenaar stoptermcap();
2150071d4279SBram Moolenaar out_flush();
2151071d4279SBram Moolenaar }
2152071d4279SBram Moolenaar }
2153071d4279SBram Moolenaar
2154071d4279SBram Moolenaar /*
2155071d4279SBram Moolenaar * Preserve files and exit.
2156071d4279SBram Moolenaar * When called IObuff must contain a message.
2157bec9c208SBram Moolenaar * NOTE: This may be called from deathtrap() in a signal handler, avoid unsafe
2158bec9c208SBram Moolenaar * functions, such as allocating memory.
2159071d4279SBram Moolenaar */
2160071d4279SBram Moolenaar void
preserve_exit(void)21619b57814dSBram Moolenaar preserve_exit(void)
2162071d4279SBram Moolenaar {
2163071d4279SBram Moolenaar buf_T *buf;
2164071d4279SBram Moolenaar
2165071d4279SBram Moolenaar prepare_to_exit();
2166071d4279SBram Moolenaar
216785a2002aSBram Moolenaar // Setting this will prevent free() calls. That avoids calling free()
216885a2002aSBram Moolenaar // recursively when free() was invoked with a bad pointer.
21694770d09aSBram Moolenaar really_exiting = TRUE;
21704770d09aSBram Moolenaar
2171071d4279SBram Moolenaar out_str(IObuff);
217285a2002aSBram Moolenaar screen_start(); // don't know where cursor is now
2173071d4279SBram Moolenaar out_flush();
2174071d4279SBram Moolenaar
217585a2002aSBram Moolenaar ml_close_notmod(); // close all not-modified buffers
2176071d4279SBram Moolenaar
217729323590SBram Moolenaar FOR_ALL_BUFFERS(buf)
2178071d4279SBram Moolenaar {
2179071d4279SBram Moolenaar if (buf->b_ml.ml_mfp != NULL && buf->b_ml.ml_mfp->mf_fname != NULL)
2180071d4279SBram Moolenaar {
218169212b11SBram Moolenaar OUT_STR("Vim: preserving files...\r\n");
218285a2002aSBram Moolenaar screen_start(); // don't know where cursor is now
2183071d4279SBram Moolenaar out_flush();
218485a2002aSBram Moolenaar ml_sync_all(FALSE, FALSE); // preserve all swap files
2185071d4279SBram Moolenaar break;
2186071d4279SBram Moolenaar }
2187071d4279SBram Moolenaar }
2188071d4279SBram Moolenaar
218985a2002aSBram Moolenaar ml_close_all(FALSE); // close all memfiles, without deleting
2190071d4279SBram Moolenaar
219169212b11SBram Moolenaar OUT_STR("Vim: Finished.\r\n");
2192071d4279SBram Moolenaar
2193071d4279SBram Moolenaar getout(1);
2194071d4279SBram Moolenaar }
2195071d4279SBram Moolenaar
2196071d4279SBram Moolenaar /*
2197071d4279SBram Moolenaar * Check for CTRL-C pressed, but only once in a while.
2198071d4279SBram Moolenaar * Should be used instead of ui_breakcheck() for functions that check for
2199071d4279SBram Moolenaar * each line in the file. Calling ui_breakcheck() each time takes too much
2200071d4279SBram Moolenaar * time, because it can be a system call.
2201071d4279SBram Moolenaar */
2202071d4279SBram Moolenaar
2203071d4279SBram Moolenaar #ifndef BREAKCHECK_SKIP
2204b4fe0eb4SBram Moolenaar # define BREAKCHECK_SKIP 1000
2205071d4279SBram Moolenaar #endif
2206071d4279SBram Moolenaar
2207071d4279SBram Moolenaar static int breakcheck_count = 0;
2208071d4279SBram Moolenaar
2209071d4279SBram Moolenaar void
line_breakcheck(void)22109b57814dSBram Moolenaar line_breakcheck(void)
2211071d4279SBram Moolenaar {
2212071d4279SBram Moolenaar if (++breakcheck_count >= BREAKCHECK_SKIP)
2213071d4279SBram Moolenaar {
2214071d4279SBram Moolenaar breakcheck_count = 0;
2215071d4279SBram Moolenaar ui_breakcheck();
2216071d4279SBram Moolenaar }
2217071d4279SBram Moolenaar }
2218071d4279SBram Moolenaar
2219071d4279SBram Moolenaar /*
2220071d4279SBram Moolenaar * Like line_breakcheck() but check 10 times less often.
2221071d4279SBram Moolenaar */
2222071d4279SBram Moolenaar void
fast_breakcheck(void)22239b57814dSBram Moolenaar fast_breakcheck(void)
2224071d4279SBram Moolenaar {
2225071d4279SBram Moolenaar if (++breakcheck_count >= BREAKCHECK_SKIP * 10)
2226071d4279SBram Moolenaar {
2227071d4279SBram Moolenaar breakcheck_count = 0;
2228071d4279SBram Moolenaar ui_breakcheck();
2229071d4279SBram Moolenaar }
2230071d4279SBram Moolenaar }
2231071d4279SBram Moolenaar
2232f1ec378bSBram Moolenaar /*
2233f1ec378bSBram Moolenaar * Like line_breakcheck() but check 100 times less often.
2234f1ec378bSBram Moolenaar */
2235f1ec378bSBram Moolenaar void
veryfast_breakcheck(void)2236f1ec378bSBram Moolenaar veryfast_breakcheck(void)
2237f1ec378bSBram Moolenaar {
2238f1ec378bSBram Moolenaar if (++breakcheck_count >= BREAKCHECK_SKIP * 100)
2239f1ec378bSBram Moolenaar {
2240f1ec378bSBram Moolenaar breakcheck_count = 0;
2241f1ec378bSBram Moolenaar ui_breakcheck();
2242f1ec378bSBram Moolenaar }
2243f1ec378bSBram Moolenaar }
2244f1ec378bSBram Moolenaar
22450a52df50SBram Moolenaar #if defined(VIM_BACKTICK) || defined(FEAT_EVAL) \
22460a52df50SBram Moolenaar || (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
22470a52df50SBram Moolenaar || defined(PROTO)
2248071d4279SBram Moolenaar
2249071d4279SBram Moolenaar #ifndef SEEK_SET
2250071d4279SBram Moolenaar # define SEEK_SET 0
2251071d4279SBram Moolenaar #endif
2252071d4279SBram Moolenaar #ifndef SEEK_END
2253071d4279SBram Moolenaar # define SEEK_END 2
2254071d4279SBram Moolenaar #endif
2255071d4279SBram Moolenaar
2256071d4279SBram Moolenaar /*
2257071d4279SBram Moolenaar * Get the stdout of an external command.
225839c29ed5SBram Moolenaar * If "ret_len" is NULL replace NUL characters with NL. When "ret_len" is not
225939c29ed5SBram Moolenaar * NULL store the length there.
2260071d4279SBram Moolenaar * Returns an allocated string, or NULL for error.
2261071d4279SBram Moolenaar */
2262071d4279SBram Moolenaar char_u *
get_cmd_output(char_u * cmd,char_u * infile,int flags,int * ret_len)22639b57814dSBram Moolenaar get_cmd_output(
22649b57814dSBram Moolenaar char_u *cmd,
226585a2002aSBram Moolenaar char_u *infile, // optional input file name
226685a2002aSBram Moolenaar int flags, // can be SHELL_SILENT
22679b57814dSBram Moolenaar int *ret_len)
2268071d4279SBram Moolenaar {
2269071d4279SBram Moolenaar char_u *tempname;
2270071d4279SBram Moolenaar char_u *command;
2271071d4279SBram Moolenaar char_u *buffer = NULL;
2272071d4279SBram Moolenaar int len;
2273071d4279SBram Moolenaar int i = 0;
2274071d4279SBram Moolenaar FILE *fd;
2275071d4279SBram Moolenaar
2276071d4279SBram Moolenaar if (check_restricted() || check_secure())
2277071d4279SBram Moolenaar return NULL;
2278071d4279SBram Moolenaar
227985a2002aSBram Moolenaar // get a name for the temp file
2280e5c421cfSBram Moolenaar if ((tempname = vim_tempname('o', FALSE)) == NULL)
2281071d4279SBram Moolenaar {
2282f9e3e09fSBram Moolenaar emsg(_(e_notmp));
2283071d4279SBram Moolenaar return NULL;
2284071d4279SBram Moolenaar }
2285071d4279SBram Moolenaar
228685a2002aSBram Moolenaar // Add the redirection stuff
2287c0197e28SBram Moolenaar command = make_filter_cmd(cmd, infile, tempname);
2288071d4279SBram Moolenaar if (command == NULL)
2289071d4279SBram Moolenaar goto done;
2290071d4279SBram Moolenaar
2291071d4279SBram Moolenaar /*
2292071d4279SBram Moolenaar * Call the shell to execute the command (errors are ignored).
2293071d4279SBram Moolenaar * Don't check timestamps here.
2294071d4279SBram Moolenaar */
2295071d4279SBram Moolenaar ++no_check_timestamps;
2296071d4279SBram Moolenaar call_shell(command, SHELL_DOOUT | SHELL_EXPAND | flags);
2297071d4279SBram Moolenaar --no_check_timestamps;
2298071d4279SBram Moolenaar
2299071d4279SBram Moolenaar vim_free(command);
2300071d4279SBram Moolenaar
2301071d4279SBram Moolenaar /*
2302071d4279SBram Moolenaar * read the names from the file into memory
2303071d4279SBram Moolenaar */
2304071d4279SBram Moolenaar # ifdef VMS
230585a2002aSBram Moolenaar // created temporary file is not always readable as binary
2306071d4279SBram Moolenaar fd = mch_fopen((char *)tempname, "r");
2307071d4279SBram Moolenaar # else
2308071d4279SBram Moolenaar fd = mch_fopen((char *)tempname, READBIN);
2309071d4279SBram Moolenaar # endif
2310071d4279SBram Moolenaar
2311071d4279SBram Moolenaar if (fd == NULL)
2312071d4279SBram Moolenaar {
2313f9e3e09fSBram Moolenaar semsg(_(e_notopen), tempname);
2314071d4279SBram Moolenaar goto done;
2315071d4279SBram Moolenaar }
2316071d4279SBram Moolenaar
2317071d4279SBram Moolenaar fseek(fd, 0L, SEEK_END);
231885a2002aSBram Moolenaar len = ftell(fd); // get size of temp file
2319071d4279SBram Moolenaar fseek(fd, 0L, SEEK_SET);
2320071d4279SBram Moolenaar
2321071d4279SBram Moolenaar buffer = alloc(len + 1);
2322071d4279SBram Moolenaar if (buffer != NULL)
2323071d4279SBram Moolenaar i = (int)fread((char *)buffer, (size_t)1, (size_t)len, fd);
2324071d4279SBram Moolenaar fclose(fd);
2325071d4279SBram Moolenaar mch_remove(tempname);
2326071d4279SBram Moolenaar if (buffer == NULL)
2327071d4279SBram Moolenaar goto done;
2328071d4279SBram Moolenaar #ifdef VMS
232985a2002aSBram Moolenaar len = i; // VMS doesn't give us what we asked for...
2330071d4279SBram Moolenaar #endif
2331071d4279SBram Moolenaar if (i != len)
2332071d4279SBram Moolenaar {
2333f9e3e09fSBram Moolenaar semsg(_(e_notread), tempname);
2334d23a8236SBram Moolenaar VIM_CLEAR(buffer);
2335071d4279SBram Moolenaar }
233639c29ed5SBram Moolenaar else if (ret_len == NULL)
2337fb332a2bSBram Moolenaar {
233885a2002aSBram Moolenaar // Change NUL into SOH, otherwise the string is truncated.
2339fb332a2bSBram Moolenaar for (i = 0; i < len; ++i)
2340f40f4ab8SBram Moolenaar if (buffer[i] == NUL)
2341f40f4ab8SBram Moolenaar buffer[i] = 1;
2342fb332a2bSBram Moolenaar
234385a2002aSBram Moolenaar buffer[len] = NUL; // make sure the buffer is terminated
2344fb332a2bSBram Moolenaar }
234539c29ed5SBram Moolenaar else
234639c29ed5SBram Moolenaar *ret_len = len;
2347071d4279SBram Moolenaar
2348071d4279SBram Moolenaar done:
2349071d4279SBram Moolenaar vim_free(tempname);
2350071d4279SBram Moolenaar return buffer;
2351071d4279SBram Moolenaar }
235226262f87SBram Moolenaar
235326262f87SBram Moolenaar # if defined(FEAT_EVAL) || defined(PROTO)
235426262f87SBram Moolenaar
2355840d16fdSBram Moolenaar static void
get_cmd_output_as_rettv(typval_T * argvars,typval_T * rettv,int retlist)235626262f87SBram Moolenaar get_cmd_output_as_rettv(
235726262f87SBram Moolenaar typval_T *argvars,
235826262f87SBram Moolenaar typval_T *rettv,
235926262f87SBram Moolenaar int retlist)
236026262f87SBram Moolenaar {
236126262f87SBram Moolenaar char_u *res = NULL;
236226262f87SBram Moolenaar char_u *p;
236326262f87SBram Moolenaar char_u *infile = NULL;
236426262f87SBram Moolenaar int err = FALSE;
236526262f87SBram Moolenaar FILE *fd;
236626262f87SBram Moolenaar list_T *list = NULL;
236726262f87SBram Moolenaar int flags = SHELL_SILENT;
236826262f87SBram Moolenaar
236926262f87SBram Moolenaar rettv->v_type = VAR_STRING;
237026262f87SBram Moolenaar rettv->vval.v_string = NULL;
237126262f87SBram Moolenaar if (check_restricted() || check_secure())
237226262f87SBram Moolenaar goto errret;
237326262f87SBram Moolenaar
23740ad871dcSYegappan Lakshmanan if (in_vim9script()
23750ad871dcSYegappan Lakshmanan && (check_for_string_arg(argvars, 0) == FAIL
23767e6a2a64SYegappan Lakshmanan || check_for_opt_string_or_number_or_list_arg(argvars, 1) == FAIL))
23770ad871dcSYegappan Lakshmanan return;
23780ad871dcSYegappan Lakshmanan
237926262f87SBram Moolenaar if (argvars[1].v_type != VAR_UNKNOWN)
238026262f87SBram Moolenaar {
238126262f87SBram Moolenaar /*
238226262f87SBram Moolenaar * Write the text to a temp file, to be used for input of the shell
238326262f87SBram Moolenaar * command.
238426262f87SBram Moolenaar */
238526262f87SBram Moolenaar if ((infile = vim_tempname('i', TRUE)) == NULL)
238626262f87SBram Moolenaar {
238726262f87SBram Moolenaar emsg(_(e_notmp));
238826262f87SBram Moolenaar goto errret;
238926262f87SBram Moolenaar }
239026262f87SBram Moolenaar
239126262f87SBram Moolenaar fd = mch_fopen((char *)infile, WRITEBIN);
239226262f87SBram Moolenaar if (fd == NULL)
239326262f87SBram Moolenaar {
239426262f87SBram Moolenaar semsg(_(e_notopen), infile);
239526262f87SBram Moolenaar goto errret;
239626262f87SBram Moolenaar }
239726262f87SBram Moolenaar if (argvars[1].v_type == VAR_NUMBER)
239826262f87SBram Moolenaar {
239926262f87SBram Moolenaar linenr_T lnum;
240026262f87SBram Moolenaar buf_T *buf;
240126262f87SBram Moolenaar
240226262f87SBram Moolenaar buf = buflist_findnr(argvars[1].vval.v_number);
240326262f87SBram Moolenaar if (buf == NULL)
240426262f87SBram Moolenaar {
240526262f87SBram Moolenaar semsg(_(e_nobufnr), argvars[1].vval.v_number);
240626262f87SBram Moolenaar fclose(fd);
240726262f87SBram Moolenaar goto errret;
240826262f87SBram Moolenaar }
240926262f87SBram Moolenaar
241026262f87SBram Moolenaar for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
241126262f87SBram Moolenaar {
241226262f87SBram Moolenaar for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
241326262f87SBram Moolenaar if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
241426262f87SBram Moolenaar {
241526262f87SBram Moolenaar err = TRUE;
241626262f87SBram Moolenaar break;
241726262f87SBram Moolenaar }
241826262f87SBram Moolenaar if (putc(NL, fd) == EOF)
241926262f87SBram Moolenaar {
242026262f87SBram Moolenaar err = TRUE;
242126262f87SBram Moolenaar break;
242226262f87SBram Moolenaar }
242326262f87SBram Moolenaar }
242426262f87SBram Moolenaar }
242526262f87SBram Moolenaar else if (argvars[1].v_type == VAR_LIST)
242626262f87SBram Moolenaar {
242726262f87SBram Moolenaar if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
242826262f87SBram Moolenaar err = TRUE;
242926262f87SBram Moolenaar }
243026262f87SBram Moolenaar else
243126262f87SBram Moolenaar {
243226262f87SBram Moolenaar size_t len;
243326262f87SBram Moolenaar char_u buf[NUMBUFLEN];
243426262f87SBram Moolenaar
243526262f87SBram Moolenaar p = tv_get_string_buf_chk(&argvars[1], buf);
243626262f87SBram Moolenaar if (p == NULL)
243726262f87SBram Moolenaar {
243826262f87SBram Moolenaar fclose(fd);
243985a2002aSBram Moolenaar goto errret; // type error; errmsg already given
244026262f87SBram Moolenaar }
244126262f87SBram Moolenaar len = STRLEN(p);
244226262f87SBram Moolenaar if (len > 0 && fwrite(p, len, 1, fd) != 1)
244326262f87SBram Moolenaar err = TRUE;
244426262f87SBram Moolenaar }
244526262f87SBram Moolenaar if (fclose(fd) != 0)
244626262f87SBram Moolenaar err = TRUE;
244726262f87SBram Moolenaar if (err)
244826262f87SBram Moolenaar {
244926262f87SBram Moolenaar emsg(_("E677: Error writing temp file"));
245026262f87SBram Moolenaar goto errret;
245126262f87SBram Moolenaar }
245226262f87SBram Moolenaar }
245326262f87SBram Moolenaar
245485a2002aSBram Moolenaar // Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
245585a2002aSBram Moolenaar // echoes typeahead, that messes up the display.
245626262f87SBram Moolenaar if (!msg_silent)
245726262f87SBram Moolenaar flags += SHELL_COOKED;
245826262f87SBram Moolenaar
245926262f87SBram Moolenaar if (retlist)
246026262f87SBram Moolenaar {
246126262f87SBram Moolenaar int len;
246226262f87SBram Moolenaar listitem_T *li;
246326262f87SBram Moolenaar char_u *s = NULL;
246426262f87SBram Moolenaar char_u *start;
246526262f87SBram Moolenaar char_u *end;
246626262f87SBram Moolenaar int i;
246726262f87SBram Moolenaar
246826262f87SBram Moolenaar res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, &len);
246926262f87SBram Moolenaar if (res == NULL)
247026262f87SBram Moolenaar goto errret;
247126262f87SBram Moolenaar
247226262f87SBram Moolenaar list = list_alloc();
247326262f87SBram Moolenaar if (list == NULL)
247426262f87SBram Moolenaar goto errret;
247526262f87SBram Moolenaar
247626262f87SBram Moolenaar for (i = 0; i < len; ++i)
247726262f87SBram Moolenaar {
247826262f87SBram Moolenaar start = res + i;
247926262f87SBram Moolenaar while (i < len && res[i] != NL)
248026262f87SBram Moolenaar ++i;
248126262f87SBram Moolenaar end = res + i;
248226262f87SBram Moolenaar
248326262f87SBram Moolenaar s = alloc(end - start + 1);
248426262f87SBram Moolenaar if (s == NULL)
248526262f87SBram Moolenaar goto errret;
248626262f87SBram Moolenaar
248726262f87SBram Moolenaar for (p = s; start < end; ++p, ++start)
248826262f87SBram Moolenaar *p = *start == NUL ? NL : *start;
248926262f87SBram Moolenaar *p = NUL;
249026262f87SBram Moolenaar
249126262f87SBram Moolenaar li = listitem_alloc();
249226262f87SBram Moolenaar if (li == NULL)
249326262f87SBram Moolenaar {
249426262f87SBram Moolenaar vim_free(s);
249526262f87SBram Moolenaar goto errret;
249626262f87SBram Moolenaar }
249726262f87SBram Moolenaar li->li_tv.v_type = VAR_STRING;
249826262f87SBram Moolenaar li->li_tv.v_lock = 0;
249926262f87SBram Moolenaar li->li_tv.vval.v_string = s;
250026262f87SBram Moolenaar list_append(list, li);
250126262f87SBram Moolenaar }
250226262f87SBram Moolenaar
250326262f87SBram Moolenaar rettv_list_set(rettv, list);
250426262f87SBram Moolenaar list = NULL;
250526262f87SBram Moolenaar }
250626262f87SBram Moolenaar else
250726262f87SBram Moolenaar {
250826262f87SBram Moolenaar res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, NULL);
250926262f87SBram Moolenaar #ifdef USE_CRNL
251085a2002aSBram Moolenaar // translate <CR><NL> into <NL>
251126262f87SBram Moolenaar if (res != NULL)
251226262f87SBram Moolenaar {
251326262f87SBram Moolenaar char_u *s, *d;
251426262f87SBram Moolenaar
251526262f87SBram Moolenaar d = res;
251626262f87SBram Moolenaar for (s = res; *s; ++s)
251726262f87SBram Moolenaar {
251826262f87SBram Moolenaar if (s[0] == CAR && s[1] == NL)
251926262f87SBram Moolenaar ++s;
252026262f87SBram Moolenaar *d++ = *s;
252126262f87SBram Moolenaar }
252226262f87SBram Moolenaar *d = NUL;
252326262f87SBram Moolenaar }
2524071d4279SBram Moolenaar #endif
252526262f87SBram Moolenaar rettv->vval.v_string = res;
252626262f87SBram Moolenaar res = NULL;
252726262f87SBram Moolenaar }
252826262f87SBram Moolenaar
252926262f87SBram Moolenaar errret:
253026262f87SBram Moolenaar if (infile != NULL)
253126262f87SBram Moolenaar {
253226262f87SBram Moolenaar mch_remove(infile);
253326262f87SBram Moolenaar vim_free(infile);
253426262f87SBram Moolenaar }
253526262f87SBram Moolenaar if (res != NULL)
253626262f87SBram Moolenaar vim_free(res);
253726262f87SBram Moolenaar if (list != NULL)
253826262f87SBram Moolenaar list_free(list);
253926262f87SBram Moolenaar }
2540071d4279SBram Moolenaar
2541071d4279SBram Moolenaar /*
254226262f87SBram Moolenaar * "system()" function
2543071d4279SBram Moolenaar */
2544071d4279SBram Moolenaar void
f_system(typval_T * argvars,typval_T * rettv)254526262f87SBram Moolenaar f_system(typval_T *argvars, typval_T *rettv)
2546071d4279SBram Moolenaar {
254726262f87SBram Moolenaar get_cmd_output_as_rettv(argvars, rettv, FALSE);
2548071d4279SBram Moolenaar }
2549071d4279SBram Moolenaar
2550071d4279SBram Moolenaar /*
255126262f87SBram Moolenaar * "systemlist()" function
255226262f87SBram Moolenaar */
255326262f87SBram Moolenaar void
f_systemlist(typval_T * argvars,typval_T * rettv)255426262f87SBram Moolenaar f_systemlist(typval_T *argvars, typval_T *rettv)
255526262f87SBram Moolenaar {
255626262f87SBram Moolenaar get_cmd_output_as_rettv(argvars, rettv, TRUE);
255726262f87SBram Moolenaar }
255826262f87SBram Moolenaar # endif // FEAT_EVAL
255926262f87SBram Moolenaar
256026262f87SBram Moolenaar #endif
256126262f87SBram Moolenaar
256226262f87SBram Moolenaar /*
2563a9dc3757SBram Moolenaar * Return TRUE when need to go to Insert mode because of 'insertmode'.
2564071d4279SBram Moolenaar * Don't do this when still processing a command or a mapping.
2565071d4279SBram Moolenaar * Don't do this when inside a ":normal" command.
2566071d4279SBram Moolenaar */
2567071d4279SBram Moolenaar int
goto_im(void)25689b57814dSBram Moolenaar goto_im(void)
2569071d4279SBram Moolenaar {
2570071d4279SBram Moolenaar return (p_im && stuff_empty() && typebuf_typed());
257175a8d74cSBram Moolenaar }
257275a8d74cSBram Moolenaar
257375a8d74cSBram Moolenaar /*
2574050fe7ebSBram Moolenaar * Returns the isolated name of the shell in allocated memory:
257575a8d74cSBram Moolenaar * - Skip beyond any path. E.g., "/usr/bin/csh -f" -> "csh -f".
257675a8d74cSBram Moolenaar * - Remove any argument. E.g., "csh -f" -> "csh".
257775a8d74cSBram Moolenaar * But don't allow a space in the path, so that this works:
257875a8d74cSBram Moolenaar * "/usr/bin/csh --rcfile ~/.cshrc"
257975a8d74cSBram Moolenaar * But don't do that for Windows, it's common to have a space in the path.
258028ee892aSBram Moolenaar * Returns NULL when out of memory.
258175a8d74cSBram Moolenaar */
258275a8d74cSBram Moolenaar char_u *
get_isolated_shell_name(void)25839b57814dSBram Moolenaar get_isolated_shell_name(void)
258475a8d74cSBram Moolenaar {
258575a8d74cSBram Moolenaar char_u *p;
258675a8d74cSBram Moolenaar
25874f97475dSBram Moolenaar #ifdef MSWIN
258875a8d74cSBram Moolenaar p = gettail(p_sh);
258971ccd03eSBram Moolenaar p = vim_strnsave(p, skiptowhite(p) - p);
259075a8d74cSBram Moolenaar #else
259175a8d74cSBram Moolenaar p = skiptowhite(p_sh);
259275a8d74cSBram Moolenaar if (*p == NUL)
259375a8d74cSBram Moolenaar {
259485a2002aSBram Moolenaar // No white space, use the tail.
259575a8d74cSBram Moolenaar p = vim_strsave(gettail(p_sh));
259675a8d74cSBram Moolenaar }
259775a8d74cSBram Moolenaar else
259875a8d74cSBram Moolenaar {
259975a8d74cSBram Moolenaar char_u *p1, *p2;
260075a8d74cSBram Moolenaar
260185a2002aSBram Moolenaar // Find the last path separator before the space.
260275a8d74cSBram Moolenaar p1 = p_sh;
260391acfffcSBram Moolenaar for (p2 = p_sh; p2 < p; MB_PTR_ADV(p2))
260475a8d74cSBram Moolenaar if (vim_ispathsep(*p2))
260575a8d74cSBram Moolenaar p1 = p2 + 1;
260671ccd03eSBram Moolenaar p = vim_strnsave(p1, p - p1);
260775a8d74cSBram Moolenaar }
260875a8d74cSBram Moolenaar #endif
260975a8d74cSBram Moolenaar return p;
2610071d4279SBram Moolenaar }
26115fd0f505SBram Moolenaar
26125fd0f505SBram Moolenaar /*
26135fd0f505SBram Moolenaar * Check if the "://" of a URL is at the pointer, return URL_SLASH.
26145fd0f505SBram Moolenaar * Also check for ":\\", which MS Internet Explorer accepts, return
26155fd0f505SBram Moolenaar * URL_BACKSLASH.
26165fd0f505SBram Moolenaar */
26175fd0f505SBram Moolenaar int
path_is_url(char_u * p)26185fd0f505SBram Moolenaar path_is_url(char_u *p)
26195fd0f505SBram Moolenaar {
26205fd0f505SBram Moolenaar if (STRNCMP(p, "://", (size_t)3) == 0)
26215fd0f505SBram Moolenaar return URL_SLASH;
26225fd0f505SBram Moolenaar else if (STRNCMP(p, ":\\\\", (size_t)3) == 0)
26235fd0f505SBram Moolenaar return URL_BACKSLASH;
26245fd0f505SBram Moolenaar return 0;
26255fd0f505SBram Moolenaar }
26265fd0f505SBram Moolenaar
26275fd0f505SBram Moolenaar /*
26287b7a118eSTsuyoshi CHO * Check if "fname" starts with "name://" or "name:\\".
26297b7a118eSTsuyoshi CHO * Return URL_SLASH for "name://", URL_BACKSLASH for "name:\\".
26305fd0f505SBram Moolenaar * Return zero otherwise.
26315fd0f505SBram Moolenaar */
26325fd0f505SBram Moolenaar int
path_with_url(char_u * fname)26335fd0f505SBram Moolenaar path_with_url(char_u *fname)
26345fd0f505SBram Moolenaar {
26355fd0f505SBram Moolenaar char_u *p;
26365fd0f505SBram Moolenaar
26377b7a118eSTsuyoshi CHO // We accept alphabetic characters and a dash in scheme part.
26387b7a118eSTsuyoshi CHO // RFC 3986 allows for more, but it increases the risk of matching
26397b7a118eSTsuyoshi CHO // non-URL text.
26407b7a118eSTsuyoshi CHO
26417b7a118eSTsuyoshi CHO // first character must be alpha
26427b7a118eSTsuyoshi CHO if (!isalpha(*fname))
26437b7a118eSTsuyoshi CHO return 0;
26447b7a118eSTsuyoshi CHO
26457b7a118eSTsuyoshi CHO // check body: alpha or dash
264694e7d345Sitchyny for (p = fname + 1; (isalpha(*p) || (*p == '-')); ++p)
26475fd0f505SBram Moolenaar ;
26487b7a118eSTsuyoshi CHO
26497b7a118eSTsuyoshi CHO // check last char is not a dash
26507b7a118eSTsuyoshi CHO if (p[-1] == '-')
26517b7a118eSTsuyoshi CHO return 0;
26527b7a118eSTsuyoshi CHO
26537b7a118eSTsuyoshi CHO // "://" or ":\\" must follow
26545fd0f505SBram Moolenaar return path_is_url(p);
26555fd0f505SBram Moolenaar }
2656f1e8876fS=?UTF-8?q?Magnus=20Gro=C3=9F?=
2657*3075a455SBram Moolenaar #if defined(FEAT_EVAL) || defined(PROTO)
2658*3075a455SBram Moolenaar /*
2659*3075a455SBram Moolenaar * Return the dictionary of v:event.
2660*3075a455SBram Moolenaar * Save and clear the value in case it already has items.
2661*3075a455SBram Moolenaar */
2662*3075a455SBram Moolenaar dict_T *
get_v_event(save_v_event_T * sve)2663*3075a455SBram Moolenaar get_v_event(save_v_event_T *sve)
2664*3075a455SBram Moolenaar {
2665*3075a455SBram Moolenaar dict_T *v_event = get_vim_var_dict(VV_EVENT);
2666*3075a455SBram Moolenaar
2667*3075a455SBram Moolenaar if (v_event->dv_hashtab.ht_used > 0)
2668*3075a455SBram Moolenaar {
2669*3075a455SBram Moolenaar // recursive use of v:event, save, make empty and restore later
2670*3075a455SBram Moolenaar sve->sve_did_save = TRUE;
2671*3075a455SBram Moolenaar sve->sve_hashtab = v_event->dv_hashtab;
2672*3075a455SBram Moolenaar hash_init(&v_event->dv_hashtab);
2673*3075a455SBram Moolenaar }
2674*3075a455SBram Moolenaar else
2675*3075a455SBram Moolenaar sve->sve_did_save = FALSE;
2676*3075a455SBram Moolenaar return v_event;
2677*3075a455SBram Moolenaar }
2678*3075a455SBram Moolenaar
2679*3075a455SBram Moolenaar void
restore_v_event(dict_T * v_event,save_v_event_T * sve)2680*3075a455SBram Moolenaar restore_v_event(dict_T *v_event, save_v_event_T *sve)
2681*3075a455SBram Moolenaar {
2682*3075a455SBram Moolenaar dict_free_contents(v_event);
2683*3075a455SBram Moolenaar if (sve->sve_did_save)
2684*3075a455SBram Moolenaar v_event->dv_hashtab = sve->sve_hashtab;
2685*3075a455SBram Moolenaar else
2686*3075a455SBram Moolenaar hash_init(&v_event->dv_hashtab);
2687*3075a455SBram Moolenaar }
2688*3075a455SBram Moolenaar #endif
2689*3075a455SBram Moolenaar
2690f1e8876fS=?UTF-8?q?Magnus=20Gro=C3=9F?= /*
2691f1e8876fS=?UTF-8?q?Magnus=20Gro=C3=9F?= * Fires a ModeChanged autocmd
2692f1e8876fS=?UTF-8?q?Magnus=20Gro=C3=9F?= */
2693f1e8876fS=?UTF-8?q?Magnus=20Gro=C3=9F?= void
trigger_modechanged()2694f1e8876fS=?UTF-8?q?Magnus=20Gro=C3=9F?= trigger_modechanged()
2695f1e8876fS=?UTF-8?q?Magnus=20Gro=C3=9F?= {
2696*3075a455SBram Moolenaar #ifdef FEAT_EVAL
2697f1e8876fS=?UTF-8?q?Magnus=20Gro=C3=9F?= dict_T *v_event;
2698f1e8876fS=?UTF-8?q?Magnus=20Gro=C3=9F?= typval_T rettv;
2699d85931e6SBram Moolenaar typval_T tv[2];
2700f1e8876fS=?UTF-8?q?Magnus=20Gro=C3=9F?= char_u *pat_pre;
2701f1e8876fS=?UTF-8?q?Magnus=20Gro=C3=9F?= char_u *pat;
2702*3075a455SBram Moolenaar save_v_event_T save_v_event;
2703f1e8876fS=?UTF-8?q?Magnus=20Gro=C3=9F?=
2704f1e8876fS=?UTF-8?q?Magnus=20Gro=C3=9F?= if (!has_modechanged())
2705f1e8876fS=?UTF-8?q?Magnus=20Gro=C3=9F?= return;
2706f1e8876fS=?UTF-8?q?Magnus=20Gro=C3=9F?=
2707d85931e6SBram Moolenaar tv[0].v_type = VAR_NUMBER;
2708d85931e6SBram Moolenaar tv[0].vval.v_number = 1; // get full mode
2709d85931e6SBram Moolenaar tv[1].v_type = VAR_UNKNOWN;
2710d85931e6SBram Moolenaar f_mode(tv, &rettv);
271125def2c8S=?UTF-8?q?Magnus=20Gro=C3=9F?= if (STRCMP(rettv.vval.v_string, last_mode) == 0)
271225def2c8S=?UTF-8?q?Magnus=20Gro=C3=9F?= {
271325def2c8S=?UTF-8?q?Magnus=20Gro=C3=9F?= vim_free(rettv.vval.v_string);
271425def2c8S=?UTF-8?q?Magnus=20Gro=C3=9F?= return;
271525def2c8S=?UTF-8?q?Magnus=20Gro=C3=9F?= }
271625def2c8S=?UTF-8?q?Magnus=20Gro=C3=9F?=
2717*3075a455SBram Moolenaar v_event = get_v_event(&save_v_event);
2718f1e8876fS=?UTF-8?q?Magnus=20Gro=C3=9F?= (void)dict_add_string(v_event, "new_mode", rettv.vval.v_string);
2719f1e8876fS=?UTF-8?q?Magnus=20Gro=C3=9F?= (void)dict_add_string(v_event, "old_mode", last_mode);
2720f1e8876fS=?UTF-8?q?Magnus=20Gro=C3=9F?= dict_set_items_ro(v_event);
2721f1e8876fS=?UTF-8?q?Magnus=20Gro=C3=9F?=
2722f1e8876fS=?UTF-8?q?Magnus=20Gro=C3=9F?= // concatenate modes in format "old_mode:new_mode"
2723f1e8876fS=?UTF-8?q?Magnus=20Gro=C3=9F?= pat_pre = concat_str(last_mode, (char_u*)":");
2724f1e8876fS=?UTF-8?q?Magnus=20Gro=C3=9F?= pat = concat_str(pat_pre, rettv.vval.v_string);
2725f1e8876fS=?UTF-8?q?Magnus=20Gro=C3=9F?= vim_free(pat_pre);
2726f1e8876fS=?UTF-8?q?Magnus=20Gro=C3=9F?=
2727f1e8876fS=?UTF-8?q?Magnus=20Gro=C3=9F?= apply_autocmds(EVENT_MODECHANGED, pat, NULL, FALSE, curbuf);
2728f1e8876fS=?UTF-8?q?Magnus=20Gro=C3=9F?= STRCPY(last_mode, rettv.vval.v_string);
2729f1e8876fS=?UTF-8?q?Magnus=20Gro=C3=9F?=
2730f1e8876fS=?UTF-8?q?Magnus=20Gro=C3=9F?= vim_free(pat);
2731*3075a455SBram Moolenaar restore_v_event(v_event, &save_v_event);
273225def2c8S=?UTF-8?q?Magnus=20Gro=C3=9F?= vim_free(rettv.vval.v_string);
2733f1e8876fS=?UTF-8?q?Magnus=20Gro=C3=9F?= #endif
2734f1e8876fS=?UTF-8?q?Magnus=20Gro=C3=9F?= }
2735