xref: /vim-8.2.3635/src/indent.c (revision 94688b8a)
1 /* vi:set ts=8 sts=4 sw=4 noet:
2  *
3  * VIM - Vi IMproved	by Bram Moolenaar
4  *
5  * Do ":help uganda"  in Vim to read copying and usage conditions.
6  * Do ":help credits" in Vim to see a list of people who contributed.
7  * See README.txt for an overview of the Vim source code.
8  */
9 
10 /*
11  * indent.c: Indentation related functions
12  */
13 
14 #include "vim.h"
15 
16 #if defined(FEAT_CINDENT) || defined(FEAT_SMARTINDENT)
17 
18 /*
19  * Return TRUE if the string "line" starts with a word from 'cinwords'.
20  */
21     int
22 cin_is_cinword(char_u *line)
23 {
24     char_u	*cinw;
25     char_u	*cinw_buf;
26     int		cinw_len;
27     int		retval = FALSE;
28     int		len;
29 
30     cinw_len = (int)STRLEN(curbuf->b_p_cinw) + 1;
31     cinw_buf = alloc((unsigned)cinw_len);
32     if (cinw_buf != NULL)
33     {
34 	line = skipwhite(line);
35 	for (cinw = curbuf->b_p_cinw; *cinw; )
36 	{
37 	    len = copy_option_part(&cinw, cinw_buf, cinw_len, ",");
38 	    if (STRNCMP(line, cinw_buf, len) == 0
39 		    && (!vim_iswordc(line[len]) || !vim_iswordc(line[len - 1])))
40 	    {
41 		retval = TRUE;
42 		break;
43 	    }
44 	}
45 	vim_free(cinw_buf);
46     }
47     return retval;
48 }
49 #endif
50 
51 #if defined(FEAT_CINDENT) || defined(FEAT_SYN_HL)
52 
53 static char_u	*skip_string(char_u *p);
54 static pos_T *find_start_rawstring(int ind_maxcomment);
55 
56 /*
57  * Find the start of a comment, not knowing if we are in a comment right now.
58  * Search starts at w_cursor.lnum and goes backwards.
59  * Return NULL when not inside a comment.
60  */
61     static pos_T *
62 ind_find_start_comment(void)	    // XXX
63 {
64     return find_start_comment(curbuf->b_ind_maxcomment);
65 }
66 
67     pos_T *
68 find_start_comment(int ind_maxcomment)	// XXX
69 {
70     pos_T	*pos;
71     char_u	*line;
72     char_u	*p;
73     int		cur_maxcomment = ind_maxcomment;
74 
75     for (;;)
76     {
77 	pos = findmatchlimit(NULL, '*', FM_BACKWARD, cur_maxcomment);
78 	if (pos == NULL)
79 	    break;
80 
81 	// Check if the comment start we found is inside a string.
82 	// If it is then restrict the search to below this line and try again.
83 	line = ml_get(pos->lnum);
84 	for (p = line; *p && (colnr_T)(p - line) < pos->col; ++p)
85 	    p = skip_string(p);
86 	if ((colnr_T)(p - line) <= pos->col)
87 	    break;
88 	cur_maxcomment = curwin->w_cursor.lnum - pos->lnum - 1;
89 	if (cur_maxcomment <= 0)
90 	{
91 	    pos = NULL;
92 	    break;
93 	}
94     }
95     return pos;
96 }
97 
98 /*
99  * Find the start of a comment or raw string, not knowing if we are in a
100  * comment or raw string right now.
101  * Search starts at w_cursor.lnum and goes backwards.
102  * If is_raw is given and returns start of raw_string, sets it to true.
103  * Return NULL when not inside a comment or raw string.
104  * "CORS" -> Comment Or Raw String
105  */
106     static pos_T *
107 ind_find_start_CORS(linenr_T *is_raw)	    // XXX
108 {
109     static pos_T comment_pos_copy;
110     pos_T	*comment_pos;
111     pos_T	*rs_pos;
112 
113     comment_pos = find_start_comment(curbuf->b_ind_maxcomment);
114     if (comment_pos != NULL)
115     {
116 	// Need to make a copy of the static pos in findmatchlimit(),
117 	// calling find_start_rawstring() may change it.
118 	comment_pos_copy = *comment_pos;
119 	comment_pos = &comment_pos_copy;
120     }
121     rs_pos = find_start_rawstring(curbuf->b_ind_maxcomment);
122 
123     // If comment_pos is before rs_pos the raw string is inside the comment.
124     // If rs_pos is before comment_pos the comment is inside the raw string.
125     if (comment_pos == NULL || (rs_pos != NULL
126 					     && LT_POS(*rs_pos, *comment_pos)))
127     {
128 	if (is_raw != NULL && rs_pos != NULL)
129 	    *is_raw = rs_pos->lnum;
130 	return rs_pos;
131     }
132     return comment_pos;
133 }
134 
135 /*
136  * Find the start of a raw string, not knowing if we are in one right now.
137  * Search starts at w_cursor.lnum and goes backwards.
138  * Return NULL when not inside a raw string.
139  */
140     static pos_T *
141 find_start_rawstring(int ind_maxcomment)	// XXX
142 {
143     pos_T	*pos;
144     char_u	*line;
145     char_u	*p;
146     int		cur_maxcomment = ind_maxcomment;
147 
148     for (;;)
149     {
150 	pos = findmatchlimit(NULL, 'R', FM_BACKWARD, cur_maxcomment);
151 	if (pos == NULL)
152 	    break;
153 
154 	// Check if the raw string start we found is inside a string.
155 	// If it is then restrict the search to below this line and try again.
156 	line = ml_get(pos->lnum);
157 	for (p = line; *p && (colnr_T)(p - line) < pos->col; ++p)
158 	    p = skip_string(p);
159 	if ((colnr_T)(p - line) <= pos->col)
160 	    break;
161 	cur_maxcomment = curwin->w_cursor.lnum - pos->lnum - 1;
162 	if (cur_maxcomment <= 0)
163 	{
164 	    pos = NULL;
165 	    break;
166 	}
167     }
168     return pos;
169 }
170 
171 /*
172  * Skip to the end of a "string" and a 'c' character.
173  * If there is no string or character, return argument unmodified.
174  */
175     static char_u *
176 skip_string(char_u *p)
177 {
178     int	    i;
179 
180     // We loop, because strings may be concatenated: "date""time".
181     for ( ; ; ++p)
182     {
183 	if (p[0] == '\'')		    // 'c' or '\n' or '\000'
184 	{
185 	    if (!p[1])			    // ' at end of line
186 		break;
187 	    i = 2;
188 	    if (p[1] == '\\')		    // '\n' or '\000'
189 	    {
190 		++i;
191 		while (vim_isdigit(p[i - 1]))   // '\000'
192 		    ++i;
193 	    }
194 	    if (p[i] == '\'')		    // check for trailing '
195 	    {
196 		p += i;
197 		continue;
198 	    }
199 	}
200 	else if (p[0] == '"')		    // start of string
201 	{
202 	    for (++p; p[0]; ++p)
203 	    {
204 		if (p[0] == '\\' && p[1] != NUL)
205 		    ++p;
206 		else if (p[0] == '"')	    // end of string
207 		    break;
208 	    }
209 	    if (p[0] == '"')
210 		continue; // continue for another string
211 	}
212 	else if (p[0] == 'R' && p[1] == '"')
213 	{
214 	    // Raw string: R"[delim](...)[delim]"
215 	    char_u *delim = p + 2;
216 	    char_u *paren = vim_strchr(delim, '(');
217 
218 	    if (paren != NULL)
219 	    {
220 		size_t delim_len = paren - delim;
221 
222 		for (p += 3; *p; ++p)
223 		    if (p[0] == ')' && STRNCMP(p + 1, delim, delim_len) == 0
224 			    && p[delim_len + 1] == '"')
225 		    {
226 			p += delim_len + 1;
227 			break;
228 		    }
229 		if (p[0] == '"')
230 		    continue; // continue for another string
231 	    }
232 	}
233 	break;				    // no string found
234     }
235     if (!*p)
236 	--p;				    // backup from NUL
237     return p;
238 }
239 #endif // FEAT_CINDENT || FEAT_SYN_HL
240 
241 #if defined(FEAT_CINDENT) || defined(PROTO)
242 
243 /*
244  * Return TRUE if C-indenting is on.
245  */
246     int
247 cindent_on(void)
248 {
249     return (!p_paste && (curbuf->b_p_cin
250 # ifdef FEAT_EVAL
251 		    || *curbuf->b_p_inde != NUL
252 # endif
253 		    ));
254 }
255 
256 // Find result cache for cpp_baseclass
257 typedef struct {
258     int	    found;
259     lpos_T  lpos;
260 } cpp_baseclass_cache_T;
261 
262 /*
263  * Functions for C-indenting.
264  * Most of this originally comes from Eric Fischer.
265  */
266 /*
267  * Below "XXX" means that this function may unlock the current line.
268  */
269 
270 static int	cin_isdefault(char_u *);
271 static int	cin_ispreproc(char_u *);
272 static int	cin_iscomment(char_u *);
273 static int	cin_islinecomment(char_u *);
274 static int	cin_isterminated(char_u *, int, int);
275 static int	cin_iselse(char_u *);
276 static int	cin_ends_in(char_u *, char_u *, char_u *);
277 static int	cin_starts_with(char_u *s, char *word);
278 static pos_T	*find_match_paren(int);
279 static pos_T	*find_match_char(int c, int ind_maxparen);
280 static int	find_last_paren(char_u *l, int start, int end);
281 static int	find_match(int lookfor, linenr_T ourscope);
282 
283 /*
284  * Skip over white space and C comments within the line.
285  * Also skip over Perl/shell comments if desired.
286  */
287     static char_u *
288 cin_skipcomment(char_u *s)
289 {
290     while (*s)
291     {
292 	char_u *prev_s = s;
293 
294 	s = skipwhite(s);
295 
296 	// Perl/shell # comment comment continues until eol.  Require a space
297 	// before # to avoid recognizing $#array.
298 	if (curbuf->b_ind_hash_comment != 0 && s != prev_s && *s == '#')
299 	{
300 	    s += STRLEN(s);
301 	    break;
302 	}
303 	if (*s != '/')
304 	    break;
305 	++s;
306 	if (*s == '/')		// slash-slash comment continues till eol
307 	{
308 	    s += STRLEN(s);
309 	    break;
310 	}
311 	if (*s != '*')
312 	    break;
313 	for (++s; *s; ++s)	// skip slash-star comment
314 	    if (s[0] == '*' && s[1] == '/')
315 	    {
316 		s += 2;
317 		break;
318 	    }
319     }
320     return s;
321 }
322 
323 /*
324  * Return TRUE if there is no code at *s.  White space and comments are
325  * not considered code.
326  */
327     static int
328 cin_nocode(char_u *s)
329 {
330     return *cin_skipcomment(s) == NUL;
331 }
332 
333 /*
334  * Check previous lines for a "//" line comment, skipping over blank lines.
335  */
336     static pos_T *
337 find_line_comment(void) // XXX
338 {
339     static pos_T pos;
340     char_u	 *line;
341     char_u	 *p;
342 
343     pos = curwin->w_cursor;
344     while (--pos.lnum > 0)
345     {
346 	line = ml_get(pos.lnum);
347 	p = skipwhite(line);
348 	if (cin_islinecomment(p))
349 	{
350 	    pos.col = (int)(p - line);
351 	    return &pos;
352 	}
353 	if (*p != NUL)
354 	    break;
355     }
356     return NULL;
357 }
358 
359 /*
360  * Return TRUE if "text" starts with "key:".
361  */
362     static int
363 cin_has_js_key(char_u *text)
364 {
365     char_u *s = skipwhite(text);
366     int	    quote = -1;
367 
368     if (*s == '\'' || *s == '"')
369     {
370 	// can be 'key': or "key":
371 	quote = *s;
372 	++s;
373     }
374     if (!vim_isIDc(*s))	    // need at least one ID character
375 	return FALSE;
376 
377     while (vim_isIDc(*s))
378 	++s;
379     if (*s == quote)
380 	++s;
381 
382     s = cin_skipcomment(s);
383 
384     // "::" is not a label, it's C++
385     return (*s == ':' && s[1] != ':');
386 }
387 
388 /*
389  * Check if string matches "label:"; move to character after ':' if true.
390  * "*s" must point to the start of the label, if there is one.
391  */
392     static int
393 cin_islabel_skip(char_u **s)
394 {
395     if (!vim_isIDc(**s))	    // need at least one ID character
396 	return FALSE;
397 
398     while (vim_isIDc(**s))
399 	(*s)++;
400 
401     *s = cin_skipcomment(*s);
402 
403     // "::" is not a label, it's C++
404     return (**s == ':' && *++*s != ':');
405 }
406 
407 /*
408  * Recognize a label: "label:".
409  * Note: curwin->w_cursor must be where we are looking for the label.
410  */
411     int
412 cin_islabel(void)		// XXX
413 {
414     char_u	*s;
415 
416     s = cin_skipcomment(ml_get_curline());
417 
418     // Exclude "default" from labels, since it should be indented
419     // like a switch label.  Same for C++ scope declarations.
420     if (cin_isdefault(s))
421 	return FALSE;
422     if (cin_isscopedecl(s))
423 	return FALSE;
424 
425     if (cin_islabel_skip(&s))
426     {
427 	// Only accept a label if the previous line is terminated or is a case
428 	// label.
429 	pos_T	cursor_save;
430 	pos_T	*trypos;
431 	char_u	*line;
432 
433 	cursor_save = curwin->w_cursor;
434 	while (curwin->w_cursor.lnum > 1)
435 	{
436 	    --curwin->w_cursor.lnum;
437 
438 	    // If we're in a comment or raw string now, skip to the start of
439 	    // it.
440 	    curwin->w_cursor.col = 0;
441 	    if ((trypos = ind_find_start_CORS(NULL)) != NULL) // XXX
442 		curwin->w_cursor = *trypos;
443 
444 	    line = ml_get_curline();
445 	    if (cin_ispreproc(line))	// ignore #defines, #if, etc.
446 		continue;
447 	    if (*(line = cin_skipcomment(line)) == NUL)
448 		continue;
449 
450 	    curwin->w_cursor = cursor_save;
451 	    if (cin_isterminated(line, TRUE, FALSE)
452 		    || cin_isscopedecl(line)
453 		    || cin_iscase(line, TRUE)
454 		    || (cin_islabel_skip(&line) && cin_nocode(line)))
455 		return TRUE;
456 	    return FALSE;
457 	}
458 	curwin->w_cursor = cursor_save;
459 	return TRUE;		// label at start of file???
460     }
461     return FALSE;
462 }
463 
464 /*
465  * Recognize structure initialization and enumerations:
466  * "[typedef] [static|public|protected|private] enum"
467  * "[typedef] [static|public|protected|private] = {"
468  */
469     static int
470 cin_isinit(void)
471 {
472     char_u	*s;
473     static char *skip[] = {"static", "public", "protected", "private"};
474 
475     s = cin_skipcomment(ml_get_curline());
476 
477     if (cin_starts_with(s, "typedef"))
478 	s = cin_skipcomment(s + 7);
479 
480     for (;;)
481     {
482 	int i, l;
483 
484 	for (i = 0; i < (int)(sizeof(skip) / sizeof(char *)); ++i)
485 	{
486 	    l = (int)strlen(skip[i]);
487 	    if (cin_starts_with(s, skip[i]))
488 	    {
489 		s = cin_skipcomment(s + l);
490 		l = 0;
491 		break;
492 	    }
493 	}
494 	if (l != 0)
495 	    break;
496     }
497 
498     if (cin_starts_with(s, "enum"))
499 	return TRUE;
500 
501     if (cin_ends_in(s, (char_u *)"=", (char_u *)"{"))
502 	return TRUE;
503 
504     return FALSE;
505 }
506 
507 /*
508  * Recognize a switch label: "case .*:" or "default:".
509  */
510      int
511 cin_iscase(
512     char_u *s,
513     int strict) // Allow relaxed check of case statement for JS
514 {
515     s = cin_skipcomment(s);
516     if (cin_starts_with(s, "case"))
517     {
518 	for (s += 4; *s; ++s)
519 	{
520 	    s = cin_skipcomment(s);
521 	    if (*s == ':')
522 	    {
523 		if (s[1] == ':')	// skip over "::" for C++
524 		    ++s;
525 		else
526 		    return TRUE;
527 	    }
528 	    if (*s == '\'' && s[1] && s[2] == '\'')
529 		s += 2;			// skip over ':'
530 	    else if (*s == '/' && (s[1] == '*' || s[1] == '/'))
531 		return FALSE;		// stop at comment
532 	    else if (*s == '"')
533 	    {
534 		// JS etc.
535 		if (strict)
536 		    return FALSE;		// stop at string
537 		else
538 		    return TRUE;
539 	    }
540 	}
541 	return FALSE;
542     }
543 
544     if (cin_isdefault(s))
545 	return TRUE;
546     return FALSE;
547 }
548 
549 /*
550  * Recognize a "default" switch label.
551  */
552     static int
553 cin_isdefault(char_u *s)
554 {
555     return (STRNCMP(s, "default", 7) == 0
556 	    && *(s = cin_skipcomment(s + 7)) == ':'
557 	    && s[1] != ':');
558 }
559 
560 /*
561  * Recognize a "public/private/protected" scope declaration label.
562  */
563     int
564 cin_isscopedecl(char_u *s)
565 {
566     int		i;
567 
568     s = cin_skipcomment(s);
569     if (STRNCMP(s, "public", 6) == 0)
570 	i = 6;
571     else if (STRNCMP(s, "protected", 9) == 0)
572 	i = 9;
573     else if (STRNCMP(s, "private", 7) == 0)
574 	i = 7;
575     else
576 	return FALSE;
577     return (*(s = cin_skipcomment(s + i)) == ':' && s[1] != ':');
578 }
579 
580 // Maximum number of lines to search back for a "namespace" line.
581 #define FIND_NAMESPACE_LIM 20
582 
583 /*
584  * Recognize a "namespace" scope declaration.
585  */
586     static int
587 cin_is_cpp_namespace(char_u *s)
588 {
589     char_u	*p;
590     int		has_name = FALSE;
591     int		has_name_start = FALSE;
592 
593     s = cin_skipcomment(s);
594     if (STRNCMP(s, "namespace", 9) == 0 && (s[9] == NUL || !vim_iswordc(s[9])))
595     {
596 	p = cin_skipcomment(skipwhite(s + 9));
597 	while (*p != NUL)
598 	{
599 	    if (VIM_ISWHITE(*p))
600 	    {
601 		has_name = TRUE; // found end of a name
602 		p = cin_skipcomment(skipwhite(p));
603 	    }
604 	    else if (*p == '{')
605 	    {
606 		break;
607 	    }
608 	    else if (vim_iswordc(*p))
609 	    {
610 		has_name_start = TRUE;
611 		if (has_name)
612 		    return FALSE; // word character after skipping past name
613 		++p;
614 	    }
615 	    else if (p[0] == ':' && p[1] == ':' && vim_iswordc(p[2]))
616 	    {
617 		if (!has_name_start || has_name)
618 		    return FALSE;
619 		// C++ 17 nested namespace
620 		p += 3;
621 	    }
622 	    else
623 	    {
624 		return FALSE;
625 	    }
626 	}
627 	return TRUE;
628     }
629     return FALSE;
630 }
631 
632 /*
633  * Recognize a `extern "C"` or `extern "C++"` linkage specifications.
634  */
635     static int
636 cin_is_cpp_extern_c(char_u *s)
637 {
638     char_u	*p;
639     int		has_string_literal = FALSE;
640 
641     s = cin_skipcomment(s);
642     if (STRNCMP(s, "extern", 6) == 0 && (s[6] == NUL || !vim_iswordc(s[6])))
643     {
644 	p = cin_skipcomment(skipwhite(s + 6));
645 	while (*p != NUL)
646 	{
647 	    if (VIM_ISWHITE(*p))
648 	    {
649 		p = cin_skipcomment(skipwhite(p));
650 	    }
651 	    else if (*p == '{')
652 	    {
653 		break;
654 	    }
655 	    else if (p[0] == '"' && p[1] == 'C' && p[2] == '"')
656 	    {
657 		if (has_string_literal)
658 		    return FALSE;
659 		has_string_literal = TRUE;
660 		p += 3;
661 	    }
662 	    else if (p[0] == '"' && p[1] == 'C' && p[2] == '+' && p[3] == '+'
663 		    && p[4] == '"')
664 	    {
665 		if (has_string_literal)
666 		    return FALSE;
667 		has_string_literal = TRUE;
668 		p += 5;
669 	    }
670 	    else
671 	    {
672 		return FALSE;
673 	    }
674 	}
675 	return has_string_literal ? TRUE : FALSE;
676     }
677     return FALSE;
678 }
679 
680 /*
681  * Return a pointer to the first non-empty non-comment character after a ':'.
682  * Return NULL if not found.
683  *	  case 234:    a = b;
684  *		       ^
685  */
686     static char_u *
687 after_label(char_u *l)
688 {
689     for ( ; *l; ++l)
690     {
691 	if (*l == ':')
692 	{
693 	    if (l[1] == ':')	    // skip over "::" for C++
694 		++l;
695 	    else if (!cin_iscase(l + 1, FALSE))
696 		break;
697 	}
698 	else if (*l == '\'' && l[1] && l[2] == '\'')
699 	    l += 2;		    // skip over 'x'
700     }
701     if (*l == NUL)
702 	return NULL;
703     l = cin_skipcomment(l + 1);
704     if (*l == NUL)
705 	return NULL;
706     return l;
707 }
708 
709 /*
710  * Get indent of line "lnum", skipping a label.
711  * Return 0 if there is nothing after the label.
712  */
713     static int
714 get_indent_nolabel (linenr_T lnum)	// XXX
715 {
716     char_u	*l;
717     pos_T	fp;
718     colnr_T	col;
719     char_u	*p;
720 
721     l = ml_get(lnum);
722     p = after_label(l);
723     if (p == NULL)
724 	return 0;
725 
726     fp.col = (colnr_T)(p - l);
727     fp.lnum = lnum;
728     getvcol(curwin, &fp, &col, NULL, NULL);
729     return (int)col;
730 }
731 
732 /*
733  * Find indent for line "lnum", ignoring any case or jump label.
734  * Also return a pointer to the text (after the label) in "pp".
735  *   label:	if (asdf && asdfasdf)
736  *		^
737  */
738     static int
739 skip_label(linenr_T lnum, char_u **pp)
740 {
741     char_u	*l;
742     int		amount;
743     pos_T	cursor_save;
744 
745     cursor_save = curwin->w_cursor;
746     curwin->w_cursor.lnum = lnum;
747     l = ml_get_curline();
748 				    // XXX
749     if (cin_iscase(l, FALSE) || cin_isscopedecl(l) || cin_islabel())
750     {
751 	amount = get_indent_nolabel(lnum);
752 	l = after_label(ml_get_curline());
753 	if (l == NULL)		// just in case
754 	    l = ml_get_curline();
755     }
756     else
757     {
758 	amount = get_indent();
759 	l = ml_get_curline();
760     }
761     *pp = l;
762 
763     curwin->w_cursor = cursor_save;
764     return amount;
765 }
766 
767 /*
768  * Return the indent of the first variable name after a type in a declaration.
769  *  int	    a,			indent of "a"
770  *  static struct foo    b,	indent of "b"
771  *  enum bla    c,		indent of "c"
772  * Returns zero when it doesn't look like a declaration.
773  */
774     static int
775 cin_first_id_amount(void)
776 {
777     char_u	*line, *p, *s;
778     int		len;
779     pos_T	fp;
780     colnr_T	col;
781 
782     line = ml_get_curline();
783     p = skipwhite(line);
784     len = (int)(skiptowhite(p) - p);
785     if (len == 6 && STRNCMP(p, "static", 6) == 0)
786     {
787 	p = skipwhite(p + 6);
788 	len = (int)(skiptowhite(p) - p);
789     }
790     if (len == 6 && STRNCMP(p, "struct", 6) == 0)
791 	p = skipwhite(p + 6);
792     else if (len == 4 && STRNCMP(p, "enum", 4) == 0)
793 	p = skipwhite(p + 4);
794     else if ((len == 8 && STRNCMP(p, "unsigned", 8) == 0)
795 	    || (len == 6 && STRNCMP(p, "signed", 6) == 0))
796     {
797 	s = skipwhite(p + len);
798 	if ((STRNCMP(s, "int", 3) == 0 && VIM_ISWHITE(s[3]))
799 		|| (STRNCMP(s, "long", 4) == 0 && VIM_ISWHITE(s[4]))
800 		|| (STRNCMP(s, "short", 5) == 0 && VIM_ISWHITE(s[5]))
801 		|| (STRNCMP(s, "char", 4) == 0 && VIM_ISWHITE(s[4])))
802 	    p = s;
803     }
804     for (len = 0; vim_isIDc(p[len]); ++len)
805 	;
806     if (len == 0 || !VIM_ISWHITE(p[len]) || cin_nocode(p))
807 	return 0;
808 
809     p = skipwhite(p + len);
810     fp.lnum = curwin->w_cursor.lnum;
811     fp.col = (colnr_T)(p - line);
812     getvcol(curwin, &fp, &col, NULL, NULL);
813     return (int)col;
814 }
815 
816 /*
817  * Return the indent of the first non-blank after an equal sign.
818  *       char *foo = "here";
819  * Return zero if no (useful) equal sign found.
820  * Return -1 if the line above "lnum" ends in a backslash.
821  *      foo = "asdf\
822  *	       asdf\
823  *	       here";
824  */
825     static int
826 cin_get_equal_amount(linenr_T lnum)
827 {
828     char_u	*line;
829     char_u	*s;
830     colnr_T	col;
831     pos_T	fp;
832 
833     if (lnum > 1)
834     {
835 	line = ml_get(lnum - 1);
836 	if (*line != NUL && line[STRLEN(line) - 1] == '\\')
837 	    return -1;
838     }
839 
840     line = s = ml_get(lnum);
841     while (*s != NUL && vim_strchr((char_u *)"=;{}\"'", *s) == NULL)
842     {
843 	if (cin_iscomment(s))	// ignore comments
844 	    s = cin_skipcomment(s);
845 	else
846 	    ++s;
847     }
848     if (*s != '=')
849 	return 0;
850 
851     s = skipwhite(s + 1);
852     if (cin_nocode(s))
853 	return 0;
854 
855     if (*s == '"')	// nice alignment for continued strings
856 	++s;
857 
858     fp.lnum = lnum;
859     fp.col = (colnr_T)(s - line);
860     getvcol(curwin, &fp, &col, NULL, NULL);
861     return (int)col;
862 }
863 
864 /*
865  * Recognize a preprocessor statement: Any line that starts with '#'.
866  */
867     static int
868 cin_ispreproc(char_u *s)
869 {
870     if (*skipwhite(s) == '#')
871 	return TRUE;
872     return FALSE;
873 }
874 
875 /*
876  * Return TRUE if line "*pp" at "*lnump" is a preprocessor statement or a
877  * continuation line of a preprocessor statement.  Decrease "*lnump" to the
878  * start and return the line in "*pp".
879  * Put the amount of indent in "*amount".
880  */
881     static int
882 cin_ispreproc_cont(char_u **pp, linenr_T *lnump, int *amount)
883 {
884     char_u	*line = *pp;
885     linenr_T	lnum = *lnump;
886     int		retval = FALSE;
887     int		candidate_amount = *amount;
888 
889     if (*line != NUL && line[STRLEN(line) - 1] == '\\')
890 	candidate_amount = get_indent_lnum(lnum);
891 
892     for (;;)
893     {
894 	if (cin_ispreproc(line))
895 	{
896 	    retval = TRUE;
897 	    *lnump = lnum;
898 	    break;
899 	}
900 	if (lnum == 1)
901 	    break;
902 	line = ml_get(--lnum);
903 	if (*line == NUL || line[STRLEN(line) - 1] != '\\')
904 	    break;
905     }
906 
907     if (lnum != *lnump)
908 	*pp = ml_get(*lnump);
909     if (retval)
910 	*amount = candidate_amount;
911     return retval;
912 }
913 
914 /*
915  * Recognize the start of a C or C++ comment.
916  */
917     static int
918 cin_iscomment(char_u *p)
919 {
920     return (p[0] == '/' && (p[1] == '*' || p[1] == '/'));
921 }
922 
923 /*
924  * Recognize the start of a "//" comment.
925  */
926     static int
927 cin_islinecomment(char_u *p)
928 {
929     return (p[0] == '/' && p[1] == '/');
930 }
931 
932 /*
933  * Recognize a line that starts with '{' or '}', or ends with ';', ',', '{' or
934  * '}'.
935  * Don't consider "} else" a terminated line.
936  * If a line begins with an "else", only consider it terminated if no unmatched
937  * opening braces follow (handle "else { foo();" correctly).
938  * Return the character terminating the line (ending char's have precedence if
939  * both apply in order to determine initializations).
940  */
941     static int
942 cin_isterminated(
943     char_u	*s,
944     int		incl_open,	// include '{' at the end as terminator
945     int		incl_comma)	// recognize a trailing comma
946 {
947     char_u	found_start = 0;
948     unsigned	n_open = 0;
949     int		is_else = FALSE;
950 
951     s = cin_skipcomment(s);
952 
953     if (*s == '{' || (*s == '}' && !cin_iselse(s)))
954 	found_start = *s;
955 
956     if (!found_start)
957 	is_else = cin_iselse(s);
958 
959     while (*s)
960     {
961 	// skip over comments, "" strings and 'c'haracters
962 	s = skip_string(cin_skipcomment(s));
963 	if (*s == '}' && n_open > 0)
964 	    --n_open;
965 	if ((!is_else || n_open == 0)
966 		&& (*s == ';' || *s == '}' || (incl_comma && *s == ','))
967 		&& cin_nocode(s + 1))
968 	    return *s;
969 	else if (*s == '{')
970 	{
971 	    if (incl_open && cin_nocode(s + 1))
972 		return *s;
973 	    else
974 		++n_open;
975 	}
976 
977 	if (*s)
978 	    s++;
979     }
980     return found_start;
981 }
982 
983 /*
984  * Recognize the basic picture of a function declaration -- it needs to
985  * have an open paren somewhere and a close paren at the end of the line and
986  * no semicolons anywhere.
987  * When a line ends in a comma we continue looking in the next line.
988  * "sp" points to a string with the line.  When looking at other lines it must
989  * be restored to the line.  When it's NULL fetch lines here.
990  * "first_lnum" is where we start looking.
991  * "min_lnum" is the line before which we will not be looking.
992  */
993     static int
994 cin_isfuncdecl(
995     char_u	**sp,
996     linenr_T	first_lnum,
997     linenr_T	min_lnum)
998 {
999     char_u	*s;
1000     linenr_T	lnum = first_lnum;
1001     linenr_T	save_lnum = curwin->w_cursor.lnum;
1002     int		retval = FALSE;
1003     pos_T	*trypos;
1004     int		just_started = TRUE;
1005 
1006     if (sp == NULL)
1007 	s = ml_get(lnum);
1008     else
1009 	s = *sp;
1010 
1011     curwin->w_cursor.lnum = lnum;
1012     if (find_last_paren(s, '(', ')')
1013 	&& (trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL)
1014     {
1015 	lnum = trypos->lnum;
1016 	if (lnum < min_lnum)
1017 	{
1018 	    curwin->w_cursor.lnum = save_lnum;
1019 	    return FALSE;
1020 	}
1021 
1022 	s = ml_get(lnum);
1023     }
1024     curwin->w_cursor.lnum = save_lnum;
1025 
1026     // Ignore line starting with #.
1027     if (cin_ispreproc(s))
1028 	return FALSE;
1029 
1030     while (*s && *s != '(' && *s != ';' && *s != '\'' && *s != '"')
1031     {
1032 	if (cin_iscomment(s))	// ignore comments
1033 	    s = cin_skipcomment(s);
1034 	else if (*s == ':')
1035 	{
1036 	    if (*(s + 1) == ':')
1037 		s += 2;
1038 	    else
1039 		// To avoid a mistake in the following situation:
1040 		// A::A(int a, int b)
1041 		//     : a(0)  // <--not a function decl
1042 		//     , b(0)
1043 		// {...
1044 		return FALSE;
1045 	}
1046 	else
1047 	    ++s;
1048     }
1049     if (*s != '(')
1050 	return FALSE;		// ';', ' or "  before any () or no '('
1051 
1052     while (*s && *s != ';' && *s != '\'' && *s != '"')
1053     {
1054 	if (*s == ')' && cin_nocode(s + 1))
1055 	{
1056 	    /*
1057 	     * ')' at the end: may have found a match
1058 	     * Check for he previous line not to end in a backslash:
1059 	     *       #if defined(x) && \
1060 	     *		 defined(y)
1061 	     */
1062 	    lnum = first_lnum - 1;
1063 	    s = ml_get(lnum);
1064 	    if (*s == NUL || s[STRLEN(s) - 1] != '\\')
1065 		retval = TRUE;
1066 	    goto done;
1067 	}
1068 	if ((*s == ',' && cin_nocode(s + 1)) || s[1] == NUL || cin_nocode(s))
1069 	{
1070 	    int comma = (*s == ',');
1071 
1072 	    // ',' at the end: continue looking in the next line.
1073 	    // At the end: check for ',' in the next line, for this style:
1074 	    // func(arg1
1075 	    //       , arg2)
1076 	    for (;;)
1077 	    {
1078 		if (lnum >= curbuf->b_ml.ml_line_count)
1079 		    break;
1080 		s = ml_get(++lnum);
1081 		if (!cin_ispreproc(s))
1082 		    break;
1083 	    }
1084 	    if (lnum >= curbuf->b_ml.ml_line_count)
1085 		break;
1086 	    // Require a comma at end of the line or a comma or ')' at the
1087 	    // start of next line.
1088 	    s = skipwhite(s);
1089 	    if (!just_started && (!comma && *s != ',' && *s != ')'))
1090 		break;
1091 	    just_started = FALSE;
1092 	}
1093 	else if (cin_iscomment(s))	// ignore comments
1094 	    s = cin_skipcomment(s);
1095 	else
1096 	{
1097 	    ++s;
1098 	    just_started = FALSE;
1099 	}
1100     }
1101 
1102 done:
1103     if (lnum != first_lnum && sp != NULL)
1104 	*sp = ml_get(first_lnum);
1105 
1106     return retval;
1107 }
1108 
1109     static int
1110 cin_isif(char_u *p)
1111 {
1112  return (STRNCMP(p, "if", 2) == 0 && !vim_isIDc(p[2]));
1113 }
1114 
1115     static int
1116 cin_iselse(
1117     char_u  *p)
1118 {
1119     if (*p == '}')	    // accept "} else"
1120 	p = cin_skipcomment(p + 1);
1121     return (STRNCMP(p, "else", 4) == 0 && !vim_isIDc(p[4]));
1122 }
1123 
1124     static int
1125 cin_isdo(char_u *p)
1126 {
1127     return (STRNCMP(p, "do", 2) == 0 && !vim_isIDc(p[2]));
1128 }
1129 
1130 /*
1131  * Check if this is a "while" that should have a matching "do".
1132  * We only accept a "while (condition) ;", with only white space between the
1133  * ')' and ';'. The condition may be spread over several lines.
1134  */
1135     static int
1136 cin_iswhileofdo (char_u *p, linenr_T lnum)	// XXX
1137 {
1138     pos_T	cursor_save;
1139     pos_T	*trypos;
1140     int		retval = FALSE;
1141 
1142     p = cin_skipcomment(p);
1143     if (*p == '}')		// accept "} while (cond);"
1144 	p = cin_skipcomment(p + 1);
1145     if (cin_starts_with(p, "while"))
1146     {
1147 	cursor_save = curwin->w_cursor;
1148 	curwin->w_cursor.lnum = lnum;
1149 	curwin->w_cursor.col = 0;
1150 	p = ml_get_curline();
1151 	while (*p && *p != 'w')	// skip any '}', until the 'w' of the "while"
1152 	{
1153 	    ++p;
1154 	    ++curwin->w_cursor.col;
1155 	}
1156 	if ((trypos = findmatchlimit(NULL, 0, 0,
1157 					      curbuf->b_ind_maxparen)) != NULL
1158 		&& *cin_skipcomment(ml_get_pos(trypos) + 1) == ';')
1159 	    retval = TRUE;
1160 	curwin->w_cursor = cursor_save;
1161     }
1162     return retval;
1163 }
1164 
1165 /*
1166  * Check whether in "p" there is an "if", "for" or "while" before "*poffset".
1167  * Return 0 if there is none.
1168  * Otherwise return !0 and update "*poffset" to point to the place where the
1169  * string was found.
1170  */
1171     static int
1172 cin_is_if_for_while_before_offset(char_u *line, int *poffset)
1173 {
1174     int offset = *poffset;
1175 
1176     if (offset-- < 2)
1177 	return 0;
1178     while (offset > 2 && VIM_ISWHITE(line[offset]))
1179 	--offset;
1180 
1181     offset -= 1;
1182     if (!STRNCMP(line + offset, "if", 2))
1183 	goto probablyFound;
1184 
1185     if (offset >= 1)
1186     {
1187 	offset -= 1;
1188 	if (!STRNCMP(line + offset, "for", 3))
1189 	    goto probablyFound;
1190 
1191 	if (offset >= 2)
1192 	{
1193 	    offset -= 2;
1194 	    if (!STRNCMP(line + offset, "while", 5))
1195 		goto probablyFound;
1196 	}
1197     }
1198     return 0;
1199 
1200 probablyFound:
1201     if (!offset || !vim_isIDc(line[offset - 1]))
1202     {
1203 	*poffset = offset;
1204 	return 1;
1205     }
1206     return 0;
1207 }
1208 
1209 /*
1210  * Return TRUE if we are at the end of a do-while.
1211  *    do
1212  *       nothing;
1213  *    while (foo
1214  *	       && bar);  <-- here
1215  * Adjust the cursor to the line with "while".
1216  */
1217     static int
1218 cin_iswhileofdo_end(int terminated)
1219 {
1220     char_u	*line;
1221     char_u	*p;
1222     char_u	*s;
1223     pos_T	*trypos;
1224     int		i;
1225 
1226     if (terminated != ';')	// there must be a ';' at the end
1227 	return FALSE;
1228 
1229     p = line = ml_get_curline();
1230     while (*p != NUL)
1231     {
1232 	p = cin_skipcomment(p);
1233 	if (*p == ')')
1234 	{
1235 	    s = skipwhite(p + 1);
1236 	    if (*s == ';' && cin_nocode(s + 1))
1237 	    {
1238 		// Found ");" at end of the line, now check there is "while"
1239 		// before the matching '('.  XXX
1240 		i = (int)(p - line);
1241 		curwin->w_cursor.col = i;
1242 		trypos = find_match_paren(curbuf->b_ind_maxparen);
1243 		if (trypos != NULL)
1244 		{
1245 		    s = cin_skipcomment(ml_get(trypos->lnum));
1246 		    if (*s == '}')		// accept "} while (cond);"
1247 			s = cin_skipcomment(s + 1);
1248 		    if (cin_starts_with(s, "while"))
1249 		    {
1250 			curwin->w_cursor.lnum = trypos->lnum;
1251 			return TRUE;
1252 		    }
1253 		}
1254 
1255 		// Searching may have made "line" invalid, get it again.
1256 		line = ml_get_curline();
1257 		p = line + i;
1258 	    }
1259 	}
1260 	if (*p != NUL)
1261 	    ++p;
1262     }
1263     return FALSE;
1264 }
1265 
1266     static int
1267 cin_isbreak(char_u *p)
1268 {
1269     return (STRNCMP(p, "break", 5) == 0 && !vim_isIDc(p[5]));
1270 }
1271 
1272 /*
1273  * Find the position of a C++ base-class declaration or
1274  * constructor-initialization. eg:
1275  *
1276  * class MyClass :
1277  *	baseClass		<-- here
1278  * class MyClass : public baseClass,
1279  *	anotherBaseClass	<-- here (should probably lineup ??)
1280  * MyClass::MyClass(...) :
1281  *	baseClass(...)		<-- here (constructor-initialization)
1282  *
1283  * This is a lot of guessing.  Watch out for "cond ? func() : foo".
1284  */
1285     static int
1286 cin_is_cpp_baseclass(
1287     cpp_baseclass_cache_T *cached) // input and output
1288 {
1289     lpos_T	*pos = &cached->lpos;	    // find position
1290     char_u	*s;
1291     int		class_or_struct, lookfor_ctor_init, cpp_base_class;
1292     linenr_T	lnum = curwin->w_cursor.lnum;
1293     char_u	*line = ml_get_curline();
1294 
1295     if (pos->lnum <= lnum)
1296 	return cached->found;	// Use the cached result
1297 
1298     pos->col = 0;
1299 
1300     s = skipwhite(line);
1301     if (*s == '#')		// skip #define FOO x ? (x) : x
1302 	return FALSE;
1303     s = cin_skipcomment(s);
1304     if (*s == NUL)
1305 	return FALSE;
1306 
1307     cpp_base_class = lookfor_ctor_init = class_or_struct = FALSE;
1308 
1309     // Search for a line starting with '#', empty, ending in ';' or containing
1310     // '{' or '}' and start below it.  This handles the following situations:
1311     //	a = cond ?
1312     //	      func() :
1313     //		   asdf;
1314     //	func::foo()
1315     //	      : something
1316     //	{}
1317     //	Foo::Foo (int one, int two)
1318     //		: something(4),
1319     //		somethingelse(3)
1320     //	{}
1321     while (lnum > 1)
1322     {
1323 	line = ml_get(lnum - 1);
1324 	s = skipwhite(line);
1325 	if (*s == '#' || *s == NUL)
1326 	    break;
1327 	while (*s != NUL)
1328 	{
1329 	    s = cin_skipcomment(s);
1330 	    if (*s == '{' || *s == '}'
1331 		    || (*s == ';' && cin_nocode(s + 1)))
1332 		break;
1333 	    if (*s != NUL)
1334 		++s;
1335 	}
1336 	if (*s != NUL)
1337 	    break;
1338 	--lnum;
1339     }
1340 
1341     pos->lnum = lnum;
1342     line = ml_get(lnum);
1343     s = line;
1344     for (;;)
1345     {
1346 	if (*s == NUL)
1347 	{
1348 	    if (lnum == curwin->w_cursor.lnum)
1349 		break;
1350 	    // Continue in the cursor line.
1351 	    line = ml_get(++lnum);
1352 	    s = line;
1353 	}
1354 	if (s == line)
1355 	{
1356 	    // don't recognize "case (foo):" as a baseclass
1357 	    if (cin_iscase(s, FALSE))
1358 		break;
1359 	    s = cin_skipcomment(line);
1360 	    if (*s == NUL)
1361 		continue;
1362 	}
1363 
1364 	if (s[0] == '"' || (s[0] == 'R' && s[1] == '"'))
1365 	    s = skip_string(s) + 1;
1366 	else if (s[0] == ':')
1367 	{
1368 	    if (s[1] == ':')
1369 	    {
1370 		// skip double colon. It can't be a constructor
1371 		// initialization any more
1372 		lookfor_ctor_init = FALSE;
1373 		s = cin_skipcomment(s + 2);
1374 	    }
1375 	    else if (lookfor_ctor_init || class_or_struct)
1376 	    {
1377 		// we have something found, that looks like the start of
1378 		// cpp-base-class-declaration or constructor-initialization
1379 		cpp_base_class = TRUE;
1380 		lookfor_ctor_init = class_or_struct = FALSE;
1381 		pos->col = 0;
1382 		s = cin_skipcomment(s + 1);
1383 	    }
1384 	    else
1385 		s = cin_skipcomment(s + 1);
1386 	}
1387 	else if ((STRNCMP(s, "class", 5) == 0 && !vim_isIDc(s[5]))
1388 		|| (STRNCMP(s, "struct", 6) == 0 && !vim_isIDc(s[6])))
1389 	{
1390 	    class_or_struct = TRUE;
1391 	    lookfor_ctor_init = FALSE;
1392 
1393 	    if (*s == 'c')
1394 		s = cin_skipcomment(s + 5);
1395 	    else
1396 		s = cin_skipcomment(s + 6);
1397 	}
1398 	else
1399 	{
1400 	    if (s[0] == '{' || s[0] == '}' || s[0] == ';')
1401 	    {
1402 		cpp_base_class = lookfor_ctor_init = class_or_struct = FALSE;
1403 	    }
1404 	    else if (s[0] == ')')
1405 	    {
1406 		// Constructor-initialization is assumed if we come across
1407 		// something like "):"
1408 		class_or_struct = FALSE;
1409 		lookfor_ctor_init = TRUE;
1410 	    }
1411 	    else if (s[0] == '?')
1412 	    {
1413 		// Avoid seeing '() :' after '?' as constructor init.
1414 		return FALSE;
1415 	    }
1416 	    else if (!vim_isIDc(s[0]))
1417 	    {
1418 		// if it is not an identifier, we are wrong
1419 		class_or_struct = FALSE;
1420 		lookfor_ctor_init = FALSE;
1421 	    }
1422 	    else if (pos->col == 0)
1423 	    {
1424 		// it can't be a constructor-initialization any more
1425 		lookfor_ctor_init = FALSE;
1426 
1427 		// the first statement starts here: lineup with this one...
1428 		if (cpp_base_class)
1429 		    pos->col = (colnr_T)(s - line);
1430 	    }
1431 
1432 	    // When the line ends in a comma don't align with it.
1433 	    if (lnum == curwin->w_cursor.lnum && *s == ',' && cin_nocode(s + 1))
1434 		pos->col = 0;
1435 
1436 	    s = cin_skipcomment(s + 1);
1437 	}
1438     }
1439 
1440     cached->found = cpp_base_class;
1441     if (cpp_base_class)
1442 	pos->lnum = lnum;
1443     return cpp_base_class;
1444 }
1445 
1446     static int
1447 get_baseclass_amount(int col)
1448 {
1449     int		amount;
1450     colnr_T	vcol;
1451     pos_T	*trypos;
1452 
1453     if (col == 0)
1454     {
1455 	amount = get_indent();
1456 	if (find_last_paren(ml_get_curline(), '(', ')')
1457 		&& (trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL)
1458 	    amount = get_indent_lnum(trypos->lnum); // XXX
1459 	if (!cin_ends_in(ml_get_curline(), (char_u *)",", NULL))
1460 	    amount += curbuf->b_ind_cpp_baseclass;
1461     }
1462     else
1463     {
1464 	curwin->w_cursor.col = col;
1465 	getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL);
1466 	amount = (int)vcol;
1467     }
1468     if (amount < curbuf->b_ind_cpp_baseclass)
1469 	amount = curbuf->b_ind_cpp_baseclass;
1470     return amount;
1471 }
1472 
1473 /*
1474  * Return TRUE if string "s" ends with the string "find", possibly followed by
1475  * white space and comments.  Skip strings and comments.
1476  * Ignore "ignore" after "find" if it's not NULL.
1477  */
1478     static int
1479 cin_ends_in(char_u *s, char_u *find, char_u *ignore)
1480 {
1481     char_u	*p = s;
1482     char_u	*r;
1483     int		len = (int)STRLEN(find);
1484 
1485     while (*p != NUL)
1486     {
1487 	p = cin_skipcomment(p);
1488 	if (STRNCMP(p, find, len) == 0)
1489 	{
1490 	    r = skipwhite(p + len);
1491 	    if (ignore != NULL && STRNCMP(r, ignore, STRLEN(ignore)) == 0)
1492 		r = skipwhite(r + STRLEN(ignore));
1493 	    if (cin_nocode(r))
1494 		return TRUE;
1495 	}
1496 	if (*p != NUL)
1497 	    ++p;
1498     }
1499     return FALSE;
1500 }
1501 
1502 /*
1503  * Return TRUE when "s" starts with "word" and then a non-ID character.
1504  */
1505     static int
1506 cin_starts_with(char_u *s, char *word)
1507 {
1508     int l = (int)STRLEN(word);
1509 
1510     return (STRNCMP(s, word, l) == 0 && !vim_isIDc(s[l]));
1511 }
1512 
1513 /*
1514  * Skip strings, chars and comments until at or past "trypos".
1515  * Return the column found.
1516  */
1517     static int
1518 cin_skip2pos(pos_T *trypos)
1519 {
1520     char_u	*line;
1521     char_u	*p;
1522     char_u	*new_p;
1523 
1524     p = line = ml_get(trypos->lnum);
1525     while (*p && (colnr_T)(p - line) < trypos->col)
1526     {
1527 	if (cin_iscomment(p))
1528 	    p = cin_skipcomment(p);
1529 	else
1530 	{
1531 	    new_p = skip_string(p);
1532 	    if (new_p == p)
1533 		++p;
1534 	    else
1535 		p = new_p;
1536 	}
1537     }
1538     return (int)(p - line);
1539 }
1540 
1541 /*
1542  * Find the '{' at the start of the block we are in.
1543  * Return NULL if no match found.
1544  * Ignore a '{' that is in a comment, makes indenting the next three lines
1545  * work.
1546  */
1547 /* foo()    */
1548 /* {	    */
1549 /* }	    */
1550 
1551     static pos_T *
1552 find_start_brace(void)	    // XXX
1553 {
1554     pos_T	cursor_save;
1555     pos_T	*trypos;
1556     pos_T	*pos;
1557     static pos_T	pos_copy;
1558 
1559     cursor_save = curwin->w_cursor;
1560     while ((trypos = findmatchlimit(NULL, '{', FM_BLOCKSTOP, 0)) != NULL)
1561     {
1562 	pos_copy = *trypos;	// copy pos_T, next findmatch will change it
1563 	trypos = &pos_copy;
1564 	curwin->w_cursor = *trypos;
1565 	pos = NULL;
1566 	// ignore the { if it's in a // or / *  * / comment
1567 	if ((colnr_T)cin_skip2pos(trypos) == trypos->col
1568 		       && (pos = ind_find_start_CORS(NULL)) == NULL) // XXX
1569 	    break;
1570 	if (pos != NULL)
1571 	    curwin->w_cursor.lnum = pos->lnum;
1572     }
1573     curwin->w_cursor = cursor_save;
1574     return trypos;
1575 }
1576 
1577 /*
1578  * Find the matching '(', ignoring it if it is in a comment.
1579  * Return NULL if no match found.
1580  */
1581     static pos_T *
1582 find_match_paren(int ind_maxparen)	// XXX
1583 {
1584     return find_match_char('(', ind_maxparen);
1585 }
1586 
1587     static pos_T *
1588 find_match_char(int c, int ind_maxparen)	// XXX
1589 {
1590     pos_T	cursor_save;
1591     pos_T	*trypos;
1592     static pos_T pos_copy;
1593     int		ind_maxp_wk;
1594 
1595     cursor_save = curwin->w_cursor;
1596     ind_maxp_wk = ind_maxparen;
1597 retry:
1598     if ((trypos = findmatchlimit(NULL, c, 0, ind_maxp_wk)) != NULL)
1599     {
1600 	// check if the ( is in a // comment
1601 	if ((colnr_T)cin_skip2pos(trypos) > trypos->col)
1602 	{
1603 	    ind_maxp_wk = ind_maxparen - (int)(cursor_save.lnum - trypos->lnum);
1604 	    if (ind_maxp_wk > 0)
1605 	    {
1606 		curwin->w_cursor = *trypos;
1607 		curwin->w_cursor.col = 0;	// XXX
1608 		goto retry;
1609 	    }
1610 	    trypos = NULL;
1611 	}
1612 	else
1613 	{
1614 	    pos_T	*trypos_wk;
1615 
1616 	    pos_copy = *trypos;	    // copy trypos, findmatch will change it
1617 	    trypos = &pos_copy;
1618 	    curwin->w_cursor = *trypos;
1619 	    if ((trypos_wk = ind_find_start_CORS(NULL)) != NULL) // XXX
1620 	    {
1621 		ind_maxp_wk = ind_maxparen - (int)(cursor_save.lnum
1622 			- trypos_wk->lnum);
1623 		if (ind_maxp_wk > 0)
1624 		{
1625 		    curwin->w_cursor = *trypos_wk;
1626 		    goto retry;
1627 		}
1628 		trypos = NULL;
1629 	    }
1630 	}
1631     }
1632     curwin->w_cursor = cursor_save;
1633     return trypos;
1634 }
1635 
1636 /*
1637  * Find the matching '(', ignoring it if it is in a comment or before an
1638  * unmatched {.
1639  * Return NULL if no match found.
1640  */
1641     static pos_T *
1642 find_match_paren_after_brace (int ind_maxparen)	    // XXX
1643 {
1644     pos_T	*trypos = find_match_paren(ind_maxparen);
1645 
1646     if (trypos != NULL)
1647     {
1648 	pos_T	*tryposBrace = find_start_brace();
1649 
1650 	// If both an unmatched '(' and '{' is found.  Ignore the '('
1651 	// position if the '{' is further down.
1652 	if (tryposBrace != NULL
1653 		&& (trypos->lnum != tryposBrace->lnum
1654 		    ? trypos->lnum < tryposBrace->lnum
1655 		    : trypos->col < tryposBrace->col))
1656 	    trypos = NULL;
1657     }
1658     return trypos;
1659 }
1660 
1661 /*
1662  * Return ind_maxparen corrected for the difference in line number between the
1663  * cursor position and "startpos".  This makes sure that searching for a
1664  * matching paren above the cursor line doesn't find a match because of
1665  * looking a few lines further.
1666  */
1667     static int
1668 corr_ind_maxparen(pos_T *startpos)
1669 {
1670     long	n = (long)startpos->lnum - (long)curwin->w_cursor.lnum;
1671 
1672     if (n > 0 && n < curbuf->b_ind_maxparen / 2)
1673 	return curbuf->b_ind_maxparen - (int)n;
1674     return curbuf->b_ind_maxparen;
1675 }
1676 
1677 /*
1678  * Set w_cursor.col to the column number of the last unmatched ')' or '{' in
1679  * line "l".  "l" must point to the start of the line.
1680  */
1681     static int
1682 find_last_paren(char_u *l, int start, int end)
1683 {
1684     int		i;
1685     int		retval = FALSE;
1686     int		open_count = 0;
1687 
1688     curwin->w_cursor.col = 0;		    // default is start of line
1689 
1690     for (i = 0; l[i] != NUL; i++)
1691     {
1692 	i = (int)(cin_skipcomment(l + i) - l); // ignore parens in comments
1693 	i = (int)(skip_string(l + i) - l);    // ignore parens in quotes
1694 	if (l[i] == start)
1695 	    ++open_count;
1696 	else if (l[i] == end)
1697 	{
1698 	    if (open_count > 0)
1699 		--open_count;
1700 	    else
1701 	    {
1702 		curwin->w_cursor.col = i;
1703 		retval = TRUE;
1704 	    }
1705 	}
1706     }
1707     return retval;
1708 }
1709 
1710 /*
1711  * Parse 'cinoptions' and set the values in "curbuf".
1712  * Must be called when 'cinoptions', 'shiftwidth' and/or 'tabstop' changes.
1713  */
1714     void
1715 parse_cino(buf_T *buf)
1716 {
1717     char_u	*p;
1718     char_u	*l;
1719     char_u	*digits;
1720     int		n;
1721     int		divider;
1722     int		fraction = 0;
1723     int		sw = (int)get_sw_value(buf);
1724 
1725     // Set the default values.
1726 
1727     // Spaces from a block's opening brace the prevailing indent for that
1728     // block should be.
1729     buf->b_ind_level = sw;
1730 
1731     // Spaces from the edge of the line an open brace that's at the end of a
1732     // line is imagined to be.
1733     buf->b_ind_open_imag = 0;
1734 
1735     // Spaces from the prevailing indent for a line that is not preceded by
1736     // an opening brace.
1737     buf->b_ind_no_brace = 0;
1738 
1739     // Column where the first { of a function should be located }.
1740     buf->b_ind_first_open = 0;
1741 
1742     // Spaces from the prevailing indent a leftmost open brace should be
1743     // located.
1744     buf->b_ind_open_extra = 0;
1745 
1746     // Spaces from the matching open brace (real location for one at the left
1747     // edge; imaginary location from one that ends a line) the matching close
1748     // brace should be located.
1749     buf->b_ind_close_extra = 0;
1750 
1751     // Spaces from the edge of the line an open brace sitting in the leftmost
1752     // column is imagined to be.
1753     buf->b_ind_open_left_imag = 0;
1754 
1755     // Spaces jump labels should be shifted to the left if N is non-negative,
1756     // otherwise the jump label will be put to column 1.
1757     buf->b_ind_jump_label = -1;
1758 
1759     // Spaces from the switch() indent a "case xx" label should be located.
1760     buf->b_ind_case = sw;
1761 
1762     // Spaces from the "case xx:" code after a switch() should be located.
1763     buf->b_ind_case_code = sw;
1764 
1765     // Lineup break at end of case in switch() with case label.
1766     buf->b_ind_case_break = 0;
1767 
1768     // Spaces from the class declaration indent a scope declaration label
1769     // should be located.
1770     buf->b_ind_scopedecl = sw;
1771 
1772     // Spaces from the scope declaration label code should be located.
1773     buf->b_ind_scopedecl_code = sw;
1774 
1775     // Amount K&R-style parameters should be indented.
1776     buf->b_ind_param = sw;
1777 
1778     // Amount a function type spec should be indented.
1779     buf->b_ind_func_type = sw;
1780 
1781     // Amount a cpp base class declaration or constructor initialization
1782     // should be indented.
1783     buf->b_ind_cpp_baseclass = sw;
1784 
1785     // additional spaces beyond the prevailing indent a continuation line
1786     // should be located.
1787     buf->b_ind_continuation = sw;
1788 
1789     // Spaces from the indent of the line with an unclosed parentheses.
1790     buf->b_ind_unclosed = sw * 2;
1791 
1792     // Spaces from the indent of the line with an unclosed parentheses, which
1793     // itself is also unclosed.
1794     buf->b_ind_unclosed2 = sw;
1795 
1796     // Suppress ignoring spaces from the indent of a line starting with an
1797     // unclosed parentheses.
1798     buf->b_ind_unclosed_noignore = 0;
1799 
1800     // If the opening paren is the last nonwhite character on the line, and
1801     // b_ind_unclosed_wrapped is nonzero, use this indent relative to the outer
1802     // context (for very long lines).
1803     buf->b_ind_unclosed_wrapped = 0;
1804 
1805     // Suppress ignoring white space when lining up with the character after
1806     // an unclosed parentheses.
1807     buf->b_ind_unclosed_whiteok = 0;
1808 
1809     // Indent a closing parentheses under the line start of the matching
1810     // opening parentheses.
1811     buf->b_ind_matching_paren = 0;
1812 
1813     // Indent a closing parentheses under the previous line.
1814     buf->b_ind_paren_prev = 0;
1815 
1816     // Extra indent for comments.
1817     buf->b_ind_comment = 0;
1818 
1819     // Spaces from the comment opener when there is nothing after it.
1820     buf->b_ind_in_comment = 3;
1821 
1822     // Boolean: if non-zero, use b_ind_in_comment even if there is something
1823     // after the comment opener.
1824     buf->b_ind_in_comment2 = 0;
1825 
1826     // Max lines to search for an open paren.
1827     buf->b_ind_maxparen = 20;
1828 
1829     // Max lines to search for an open comment.
1830     buf->b_ind_maxcomment = 70;
1831 
1832     // Handle braces for java code.
1833     buf->b_ind_java = 0;
1834 
1835     // Not to confuse JS object properties with labels.
1836     buf->b_ind_js = 0;
1837 
1838     // Handle blocked cases correctly.
1839     buf->b_ind_keep_case_label = 0;
1840 
1841     // Handle C++ namespace.
1842     buf->b_ind_cpp_namespace = 0;
1843 
1844     // Handle continuation lines containing conditions of if(), for() and
1845     // while().
1846     buf->b_ind_if_for_while = 0;
1847 
1848     // indentation for # comments
1849     buf->b_ind_hash_comment = 0;
1850 
1851     // Handle C++ extern "C" or "C++"
1852     buf->b_ind_cpp_extern_c = 0;
1853 
1854     for (p = buf->b_p_cino; *p; )
1855     {
1856 	l = p++;
1857 	if (*p == '-')
1858 	    ++p;
1859 	digits = p;	    // remember where the digits start
1860 	n = getdigits(&p);
1861 	divider = 0;
1862 	if (*p == '.')	    // ".5s" means a fraction
1863 	{
1864 	    fraction = atol((char *)++p);
1865 	    while (VIM_ISDIGIT(*p))
1866 	    {
1867 		++p;
1868 		if (divider)
1869 		    divider *= 10;
1870 		else
1871 		    divider = 10;
1872 	    }
1873 	}
1874 	if (*p == 's')	    // "2s" means two times 'shiftwidth'
1875 	{
1876 	    if (p == digits)
1877 		n = sw;	// just "s" is one 'shiftwidth'
1878 	    else
1879 	    {
1880 		n *= sw;
1881 		if (divider)
1882 		    n += (sw * fraction + divider / 2) / divider;
1883 	    }
1884 	    ++p;
1885 	}
1886 	if (l[1] == '-')
1887 	    n = -n;
1888 
1889 	// When adding an entry here, also update the default 'cinoptions' in
1890 	// doc/indent.txt, and add explanation for it!
1891 	switch (*l)
1892 	{
1893 	    case '>': buf->b_ind_level = n; break;
1894 	    case 'e': buf->b_ind_open_imag = n; break;
1895 	    case 'n': buf->b_ind_no_brace = n; break;
1896 	    case 'f': buf->b_ind_first_open = n; break;
1897 	    case '{': buf->b_ind_open_extra = n; break;
1898 	    case '}': buf->b_ind_close_extra = n; break;
1899 	    case '^': buf->b_ind_open_left_imag = n; break;
1900 	    case 'L': buf->b_ind_jump_label = n; break;
1901 	    case ':': buf->b_ind_case = n; break;
1902 	    case '=': buf->b_ind_case_code = n; break;
1903 	    case 'b': buf->b_ind_case_break = n; break;
1904 	    case 'p': buf->b_ind_param = n; break;
1905 	    case 't': buf->b_ind_func_type = n; break;
1906 	    case '/': buf->b_ind_comment = n; break;
1907 	    case 'c': buf->b_ind_in_comment = n; break;
1908 	    case 'C': buf->b_ind_in_comment2 = n; break;
1909 	    case 'i': buf->b_ind_cpp_baseclass = n; break;
1910 	    case '+': buf->b_ind_continuation = n; break;
1911 	    case '(': buf->b_ind_unclosed = n; break;
1912 	    case 'u': buf->b_ind_unclosed2 = n; break;
1913 	    case 'U': buf->b_ind_unclosed_noignore = n; break;
1914 	    case 'W': buf->b_ind_unclosed_wrapped = n; break;
1915 	    case 'w': buf->b_ind_unclosed_whiteok = n; break;
1916 	    case 'm': buf->b_ind_matching_paren = n; break;
1917 	    case 'M': buf->b_ind_paren_prev = n; break;
1918 	    case ')': buf->b_ind_maxparen = n; break;
1919 	    case '*': buf->b_ind_maxcomment = n; break;
1920 	    case 'g': buf->b_ind_scopedecl = n; break;
1921 	    case 'h': buf->b_ind_scopedecl_code = n; break;
1922 	    case 'j': buf->b_ind_java = n; break;
1923 	    case 'J': buf->b_ind_js = n; break;
1924 	    case 'l': buf->b_ind_keep_case_label = n; break;
1925 	    case '#': buf->b_ind_hash_comment = n; break;
1926 	    case 'N': buf->b_ind_cpp_namespace = n; break;
1927 	    case 'k': buf->b_ind_if_for_while = n; break;
1928 	    case 'E': buf->b_ind_cpp_extern_c = n; break;
1929 	}
1930 	if (*p == ',')
1931 	    ++p;
1932     }
1933 }
1934 
1935 /*
1936  * Return the desired indent for C code.
1937  * Return -1 if the indent should be left alone (inside a raw string).
1938  */
1939     int
1940 get_c_indent(void)
1941 {
1942     pos_T	cur_curpos;
1943     int		amount;
1944     int		scope_amount;
1945     int		cur_amount = MAXCOL;
1946     colnr_T	col;
1947     char_u	*theline;
1948     char_u	*linecopy;
1949     pos_T	*trypos;
1950     pos_T	*comment_pos;
1951     pos_T	*tryposBrace = NULL;
1952     pos_T	tryposCopy;
1953     pos_T	our_paren_pos;
1954     char_u	*start;
1955     int		start_brace;
1956 #define BRACE_IN_COL0		1	    // '{' is in column 0
1957 #define BRACE_AT_START		2	    // '{' is at start of line
1958 #define BRACE_AT_END		3	    // '{' is at end of line
1959     linenr_T	ourscope;
1960     char_u	*l;
1961     char_u	*look;
1962     char_u	terminated;
1963     int		lookfor;
1964 #define LOOKFOR_INITIAL		0
1965 #define LOOKFOR_IF		1
1966 #define LOOKFOR_DO		2
1967 #define LOOKFOR_CASE		3
1968 #define LOOKFOR_ANY		4
1969 #define LOOKFOR_TERM		5
1970 #define LOOKFOR_UNTERM		6
1971 #define LOOKFOR_SCOPEDECL	7
1972 #define LOOKFOR_NOBREAK		8
1973 #define LOOKFOR_CPP_BASECLASS	9
1974 #define LOOKFOR_ENUM_OR_INIT	10
1975 #define LOOKFOR_JS_KEY		11
1976 #define LOOKFOR_COMMA		12
1977 
1978     int		whilelevel;
1979     linenr_T	lnum;
1980     int		n;
1981     int		iscase;
1982     int		lookfor_break;
1983     int		lookfor_cpp_namespace = FALSE;
1984     int		cont_amount = 0;    // amount for continuation line
1985     int		original_line_islabel;
1986     int		added_to_amount = 0;
1987     int		js_cur_has_key = 0;
1988     linenr_T	raw_string_start = 0;
1989     cpp_baseclass_cache_T cache_cpp_baseclass = { FALSE, { MAXLNUM, 0 } };
1990 
1991     // make a copy, value is changed below
1992     int		ind_continuation = curbuf->b_ind_continuation;
1993 
1994     // remember where the cursor was when we started
1995     cur_curpos = curwin->w_cursor;
1996 
1997     // if we are at line 1 zero indent is fine, right?
1998     if (cur_curpos.lnum == 1)
1999 	return 0;
2000 
2001     // Get a copy of the current contents of the line.
2002     // This is required, because only the most recent line obtained with
2003     // ml_get is valid!
2004     linecopy = vim_strsave(ml_get(cur_curpos.lnum));
2005     if (linecopy == NULL)
2006 	return 0;
2007 
2008     // In insert mode and the cursor is on a ')' truncate the line at the
2009     // cursor position.  We don't want to line up with the matching '(' when
2010     // inserting new stuff.
2011     // For unknown reasons the cursor might be past the end of the line, thus
2012     // check for that.
2013     if ((State & INSERT)
2014 	    && curwin->w_cursor.col < (colnr_T)STRLEN(linecopy)
2015 	    && linecopy[curwin->w_cursor.col] == ')')
2016 	linecopy[curwin->w_cursor.col] = NUL;
2017 
2018     theline = skipwhite(linecopy);
2019 
2020     // move the cursor to the start of the line
2021 
2022     curwin->w_cursor.col = 0;
2023 
2024     original_line_islabel = cin_islabel();  // XXX
2025 
2026     // If we are inside a raw string don't change the indent.
2027     // Ignore a raw string inside a comment.
2028     comment_pos = ind_find_start_comment();
2029     if (comment_pos != NULL)
2030     {
2031 	// findmatchlimit() static pos is overwritten, make a copy
2032 	tryposCopy = *comment_pos;
2033 	comment_pos = &tryposCopy;
2034     }
2035     trypos = find_start_rawstring(curbuf->b_ind_maxcomment);
2036     if (trypos != NULL && (comment_pos == NULL
2037 					     || LT_POS(*trypos, *comment_pos)))
2038     {
2039 	amount = -1;
2040 	goto laterend;
2041     }
2042 
2043     // #defines and so on always go at the left when included in 'cinkeys'.
2044     if (*theline == '#' && (*linecopy == '#' || in_cinkeys('#', ' ', TRUE)))
2045     {
2046 	amount = curbuf->b_ind_hash_comment;
2047 	goto theend;
2048     }
2049 
2050     // Is it a non-case label?	Then that goes at the left margin too unless:
2051     //  - JS flag is set.
2052     //  - 'L' item has a positive value.
2053     if (original_line_islabel && !curbuf->b_ind_js
2054 					      && curbuf->b_ind_jump_label < 0)
2055     {
2056 	amount = 0;
2057 	goto theend;
2058     }
2059 
2060     // If we're inside a "//" comment and there is a "//" comment in a
2061     // previous line, lineup with that one.
2062     if (cin_islinecomment(theline)
2063 	    && (trypos = find_line_comment()) != NULL) // XXX
2064     {
2065 	// find how indented the line beginning the comment is
2066 	getvcol(curwin, trypos, &col, NULL, NULL);
2067 	amount = col;
2068 	goto theend;
2069     }
2070 
2071     // If we're inside a comment and not looking at the start of the
2072     // comment, try using the 'comments' option.
2073     if (!cin_iscomment(theline) && comment_pos != NULL) // XXX
2074     {
2075 	int	lead_start_len = 2;
2076 	int	lead_middle_len = 1;
2077 	char_u	lead_start[COM_MAX_LEN];	// start-comment string
2078 	char_u	lead_middle[COM_MAX_LEN];	// middle-comment string
2079 	char_u	lead_end[COM_MAX_LEN];		// end-comment string
2080 	char_u	*p;
2081 	int	start_align = 0;
2082 	int	start_off = 0;
2083 	int	done = FALSE;
2084 
2085 	// find how indented the line beginning the comment is
2086 	getvcol(curwin, comment_pos, &col, NULL, NULL);
2087 	amount = col;
2088 	*lead_start = NUL;
2089 	*lead_middle = NUL;
2090 
2091 	p = curbuf->b_p_com;
2092 	while (*p != NUL)
2093 	{
2094 	    int	align = 0;
2095 	    int	off = 0;
2096 	    int what = 0;
2097 
2098 	    while (*p != NUL && *p != ':')
2099 	    {
2100 		if (*p == COM_START || *p == COM_END || *p == COM_MIDDLE)
2101 		    what = *p++;
2102 		else if (*p == COM_LEFT || *p == COM_RIGHT)
2103 		    align = *p++;
2104 		else if (VIM_ISDIGIT(*p) || *p == '-')
2105 		    off = getdigits(&p);
2106 		else
2107 		    ++p;
2108 	    }
2109 
2110 	    if (*p == ':')
2111 		++p;
2112 	    (void)copy_option_part(&p, lead_end, COM_MAX_LEN, ",");
2113 	    if (what == COM_START)
2114 	    {
2115 		STRCPY(lead_start, lead_end);
2116 		lead_start_len = (int)STRLEN(lead_start);
2117 		start_off = off;
2118 		start_align = align;
2119 	    }
2120 	    else if (what == COM_MIDDLE)
2121 	    {
2122 		STRCPY(lead_middle, lead_end);
2123 		lead_middle_len = (int)STRLEN(lead_middle);
2124 	    }
2125 	    else if (what == COM_END)
2126 	    {
2127 		// If our line starts with the middle comment string, line it
2128 		// up with the comment opener per the 'comments' option.
2129 		if (STRNCMP(theline, lead_middle, lead_middle_len) == 0
2130 			&& STRNCMP(theline, lead_end, STRLEN(lead_end)) != 0)
2131 		{
2132 		    done = TRUE;
2133 		    if (curwin->w_cursor.lnum > 1)
2134 		    {
2135 			// If the start comment string matches in the previous
2136 			// line, use the indent of that line plus offset.  If
2137 			// the middle comment string matches in the previous
2138 			// line, use the indent of that line.  XXX
2139 			look = skipwhite(ml_get(curwin->w_cursor.lnum - 1));
2140 			if (STRNCMP(look, lead_start, lead_start_len) == 0)
2141 			    amount = get_indent_lnum(curwin->w_cursor.lnum - 1);
2142 			else if (STRNCMP(look, lead_middle,
2143 							lead_middle_len) == 0)
2144 			{
2145 			    amount = get_indent_lnum(curwin->w_cursor.lnum - 1);
2146 			    break;
2147 			}
2148 			// If the start comment string doesn't match with the
2149 			// start of the comment, skip this entry.  XXX
2150 			else if (STRNCMP(ml_get(comment_pos->lnum) + comment_pos->col,
2151 					     lead_start, lead_start_len) != 0)
2152 			    continue;
2153 		    }
2154 		    if (start_off != 0)
2155 			amount += start_off;
2156 		    else if (start_align == COM_RIGHT)
2157 			amount += vim_strsize(lead_start)
2158 						   - vim_strsize(lead_middle);
2159 		    break;
2160 		}
2161 
2162 		// If our line starts with the end comment string, line it up
2163 		// with the middle comment
2164 		if (STRNCMP(theline, lead_middle, lead_middle_len) != 0
2165 			&& STRNCMP(theline, lead_end, STRLEN(lead_end)) == 0)
2166 		{
2167 		    amount = get_indent_lnum(curwin->w_cursor.lnum - 1);
2168 								     // XXX
2169 		    if (off != 0)
2170 			amount += off;
2171 		    else if (align == COM_RIGHT)
2172 			amount += vim_strsize(lead_start)
2173 						   - vim_strsize(lead_middle);
2174 		    done = TRUE;
2175 		    break;
2176 		}
2177 	    }
2178 	}
2179 
2180 	// If our line starts with an asterisk, line up with the
2181 	// asterisk in the comment opener; otherwise, line up
2182 	// with the first character of the comment text.
2183 	if (done)
2184 	    ;
2185 	else if (theline[0] == '*')
2186 	    amount += 1;
2187 	else
2188 	{
2189 	    // If we are more than one line away from the comment opener, take
2190 	    // the indent of the previous non-empty line.  If 'cino' has "CO"
2191 	    // and we are just below the comment opener and there are any
2192 	    // white characters after it line up with the text after it;
2193 	    // otherwise, add the amount specified by "c" in 'cino'
2194 	    amount = -1;
2195 	    for (lnum = cur_curpos.lnum - 1; lnum > comment_pos->lnum; --lnum)
2196 	    {
2197 		if (linewhite(lnum))		    // skip blank lines
2198 		    continue;
2199 		amount = get_indent_lnum(lnum);	    // XXX
2200 		break;
2201 	    }
2202 	    if (amount == -1)			    // use the comment opener
2203 	    {
2204 		if (!curbuf->b_ind_in_comment2)
2205 		{
2206 		    start = ml_get(comment_pos->lnum);
2207 		    look = start + comment_pos->col + 2; // skip / and *
2208 		    if (*look != NUL)		    // if something after it
2209 			comment_pos->col = (colnr_T)(skipwhite(look) - start);
2210 		}
2211 		getvcol(curwin, comment_pos, &col, NULL, NULL);
2212 		amount = col;
2213 		if (curbuf->b_ind_in_comment2 || *look == NUL)
2214 		    amount += curbuf->b_ind_in_comment;
2215 	    }
2216 	}
2217 	goto theend;
2218     }
2219 
2220     // Are we looking at a ']' that has a match?
2221     if (*skipwhite(theline) == ']'
2222 	    && (trypos = find_match_char('[', curbuf->b_ind_maxparen)) != NULL)
2223     {
2224 	// align with the line containing the '['.
2225 	amount = get_indent_lnum(trypos->lnum);
2226 	goto theend;
2227     }
2228 
2229     // Are we inside parentheses or braces?  XXX
2230     if (((trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL
2231 		&& curbuf->b_ind_java == 0)
2232 	    || (tryposBrace = find_start_brace()) != NULL
2233 	    || trypos != NULL)
2234     {
2235       if (trypos != NULL && tryposBrace != NULL)
2236       {
2237 	  // Both an unmatched '(' and '{' is found.  Use the one which is
2238 	  // closer to the current cursor position, set the other to NULL.
2239 	  if (trypos->lnum != tryposBrace->lnum
2240 		  ? trypos->lnum < tryposBrace->lnum
2241 		  : trypos->col < tryposBrace->col)
2242 	      trypos = NULL;
2243 	  else
2244 	      tryposBrace = NULL;
2245       }
2246 
2247       if (trypos != NULL)
2248       {
2249 	// If the matching paren is more than one line away, use the indent of
2250 	// a previous non-empty line that matches the same paren.
2251 	if (theline[0] == ')' && curbuf->b_ind_paren_prev)
2252 	{
2253 	    // Line up with the start of the matching paren line.
2254 	    amount = get_indent_lnum(curwin->w_cursor.lnum - 1);  // XXX
2255 	}
2256 	else
2257 	{
2258 	    amount = -1;
2259 	    our_paren_pos = *trypos;
2260 	    for (lnum = cur_curpos.lnum - 1; lnum > our_paren_pos.lnum; --lnum)
2261 	    {
2262 		l = skipwhite(ml_get(lnum));
2263 		if (cin_nocode(l))		// skip comment lines
2264 		    continue;
2265 		if (cin_ispreproc_cont(&l, &lnum, &amount))
2266 		    continue;			// ignore #define, #if, etc.
2267 		curwin->w_cursor.lnum = lnum;
2268 
2269 		// Skip a comment or raw string.  XXX
2270 		if ((trypos = ind_find_start_CORS(NULL)) != NULL)
2271 		{
2272 		    lnum = trypos->lnum + 1;
2273 		    continue;
2274 		}
2275 
2276 		// XXX
2277 		if ((trypos = find_match_paren(
2278 			corr_ind_maxparen(&cur_curpos))) != NULL
2279 			&& trypos->lnum == our_paren_pos.lnum
2280 			&& trypos->col == our_paren_pos.col)
2281 		{
2282 			amount = get_indent_lnum(lnum);	// XXX
2283 
2284 			if (theline[0] == ')')
2285 			{
2286 			    if (our_paren_pos.lnum != lnum
2287 						       && cur_amount > amount)
2288 				cur_amount = amount;
2289 			    amount = -1;
2290 			}
2291 		    break;
2292 		}
2293 	    }
2294 	}
2295 
2296 	// Line up with line where the matching paren is. XXX
2297 	// If the line starts with a '(' or the indent for unclosed
2298 	// parentheses is zero, line up with the unclosed parentheses.
2299 	if (amount == -1)
2300 	{
2301 	    int	    ignore_paren_col = 0;
2302 	    int	    is_if_for_while = 0;
2303 
2304 	    if (curbuf->b_ind_if_for_while)
2305 	    {
2306 		// Look for the outermost opening parenthesis on this line
2307 		// and check whether it belongs to an "if", "for" or "while".
2308 
2309 		pos_T	    cursor_save = curwin->w_cursor;
2310 		pos_T	    outermost;
2311 		char_u	    *line;
2312 
2313 		trypos = &our_paren_pos;
2314 		do {
2315 		    outermost = *trypos;
2316 		    curwin->w_cursor.lnum = outermost.lnum;
2317 		    curwin->w_cursor.col = outermost.col;
2318 
2319 		    trypos = find_match_paren(curbuf->b_ind_maxparen);
2320 		} while (trypos && trypos->lnum == outermost.lnum);
2321 
2322 		curwin->w_cursor = cursor_save;
2323 
2324 		line = ml_get(outermost.lnum);
2325 
2326 		is_if_for_while =
2327 		    cin_is_if_for_while_before_offset(line, &outermost.col);
2328 	    }
2329 
2330 	    amount = skip_label(our_paren_pos.lnum, &look);
2331 	    look = skipwhite(look);
2332 	    if (*look == '(')
2333 	    {
2334 		linenr_T    save_lnum = curwin->w_cursor.lnum;
2335 		char_u	    *line;
2336 		int	    look_col;
2337 
2338 		// Ignore a '(' in front of the line that has a match before
2339 		// our matching '('.
2340 		curwin->w_cursor.lnum = our_paren_pos.lnum;
2341 		line = ml_get_curline();
2342 		look_col = (int)(look - line);
2343 		curwin->w_cursor.col = look_col + 1;
2344 		if ((trypos = findmatchlimit(NULL, ')', 0,
2345 						      curbuf->b_ind_maxparen))
2346 								      != NULL
2347 			  && trypos->lnum == our_paren_pos.lnum
2348 			  && trypos->col < our_paren_pos.col)
2349 		    ignore_paren_col = trypos->col + 1;
2350 
2351 		curwin->w_cursor.lnum = save_lnum;
2352 		look = ml_get(our_paren_pos.lnum) + look_col;
2353 	    }
2354 	    if (theline[0] == ')' || (curbuf->b_ind_unclosed == 0
2355 						      && is_if_for_while == 0)
2356 		    || (!curbuf->b_ind_unclosed_noignore && *look == '('
2357 						    && ignore_paren_col == 0))
2358 	    {
2359 		// If we're looking at a close paren, line up right there;
2360 		// otherwise, line up with the next (non-white) character.
2361 		// When b_ind_unclosed_wrapped is set and the matching paren is
2362 		// the last nonwhite character of the line, use either the
2363 		// indent of the current line or the indentation of the next
2364 		// outer paren and add b_ind_unclosed_wrapped (for very long
2365 		// lines).
2366 		if (theline[0] != ')')
2367 		{
2368 		    cur_amount = MAXCOL;
2369 		    l = ml_get(our_paren_pos.lnum);
2370 		    if (curbuf->b_ind_unclosed_wrapped
2371 				       && cin_ends_in(l, (char_u *)"(", NULL))
2372 		    {
2373 			// look for opening unmatched paren, indent one level
2374 			// for each additional level
2375 			n = 1;
2376 			for (col = 0; col < our_paren_pos.col; ++col)
2377 			{
2378 			    switch (l[col])
2379 			    {
2380 				case '(':
2381 				case '{': ++n;
2382 					  break;
2383 
2384 				case ')':
2385 				case '}': if (n > 1)
2386 					      --n;
2387 					  break;
2388 			    }
2389 			}
2390 
2391 			our_paren_pos.col = 0;
2392 			amount += n * curbuf->b_ind_unclosed_wrapped;
2393 		    }
2394 		    else if (curbuf->b_ind_unclosed_whiteok)
2395 			our_paren_pos.col++;
2396 		    else
2397 		    {
2398 			col = our_paren_pos.col + 1;
2399 			while (VIM_ISWHITE(l[col]))
2400 			    col++;
2401 			if (l[col] != NUL)	// In case of trailing space
2402 			    our_paren_pos.col = col;
2403 			else
2404 			    our_paren_pos.col++;
2405 		    }
2406 		}
2407 
2408 		// Find how indented the paren is, or the character after it
2409 		// if we did the above "if".
2410 		if (our_paren_pos.col > 0)
2411 		{
2412 		    getvcol(curwin, &our_paren_pos, &col, NULL, NULL);
2413 		    if (cur_amount > (int)col)
2414 			cur_amount = col;
2415 		}
2416 	    }
2417 
2418 	    if (theline[0] == ')' && curbuf->b_ind_matching_paren)
2419 	    {
2420 		// Line up with the start of the matching paren line.
2421 	    }
2422 	    else if ((curbuf->b_ind_unclosed == 0 && is_if_for_while == 0)
2423 		     || (!curbuf->b_ind_unclosed_noignore
2424 				    && *look == '(' && ignore_paren_col == 0))
2425 	    {
2426 		if (cur_amount != MAXCOL)
2427 		    amount = cur_amount;
2428 	    }
2429 	    else
2430 	    {
2431 		// Add b_ind_unclosed2 for each '(' before our matching one,
2432 		// but ignore (void) before the line (ignore_paren_col).
2433 		col = our_paren_pos.col;
2434 		while ((int)our_paren_pos.col > ignore_paren_col)
2435 		{
2436 		    --our_paren_pos.col;
2437 		    switch (*ml_get_pos(&our_paren_pos))
2438 		    {
2439 			case '(': amount += curbuf->b_ind_unclosed2;
2440 				  col = our_paren_pos.col;
2441 				  break;
2442 			case ')': amount -= curbuf->b_ind_unclosed2;
2443 				  col = MAXCOL;
2444 				  break;
2445 		    }
2446 		}
2447 
2448 		// Use b_ind_unclosed once, when the first '(' is not inside
2449 		// braces
2450 		if (col == MAXCOL)
2451 		    amount += curbuf->b_ind_unclosed;
2452 		else
2453 		{
2454 		    curwin->w_cursor.lnum = our_paren_pos.lnum;
2455 		    curwin->w_cursor.col = col;
2456 		    if (find_match_paren_after_brace(curbuf->b_ind_maxparen)
2457 								      != NULL)
2458 			amount += curbuf->b_ind_unclosed2;
2459 		    else
2460 		    {
2461 			if (is_if_for_while)
2462 			    amount += curbuf->b_ind_if_for_while;
2463 			else
2464 			    amount += curbuf->b_ind_unclosed;
2465 		    }
2466 		}
2467 		// For a line starting with ')' use the minimum of the two
2468 		// positions, to avoid giving it more indent than the previous
2469 		// lines:
2470 		//  func_long_name(		    if (x
2471 		//	arg				    && yy
2472 		//	)	  ^ not here	       )    ^ not here
2473 		if (cur_amount < amount)
2474 		    amount = cur_amount;
2475 	    }
2476 	}
2477 
2478 	// add extra indent for a comment
2479 	if (cin_iscomment(theline))
2480 	    amount += curbuf->b_ind_comment;
2481       }
2482       else
2483       {
2484 	// We are inside braces, there is a { before this line at the position
2485 	// stored in tryposBrace.
2486 	// Make a copy of tryposBrace, it may point to pos_copy inside
2487 	// find_start_brace(), which may be changed somewhere.
2488 	tryposCopy = *tryposBrace;
2489 	tryposBrace = &tryposCopy;
2490 	trypos = tryposBrace;
2491 	ourscope = trypos->lnum;
2492 	start = ml_get(ourscope);
2493 
2494 	// Now figure out how indented the line is in general.
2495 	// If the brace was at the start of the line, we use that;
2496 	// otherwise, check out the indentation of the line as
2497 	// a whole and then add the "imaginary indent" to that.
2498 	look = skipwhite(start);
2499 	if (*look == '{')
2500 	{
2501 	    getvcol(curwin, trypos, &col, NULL, NULL);
2502 	    amount = col;
2503 	    if (*start == '{')
2504 		start_brace = BRACE_IN_COL0;
2505 	    else
2506 		start_brace = BRACE_AT_START;
2507 	}
2508 	else
2509 	{
2510 	    // That opening brace might have been on a continuation
2511 	    // line.  if so, find the start of the line.
2512 	    curwin->w_cursor.lnum = ourscope;
2513 
2514 	    // Position the cursor over the rightmost paren, so that
2515 	    // matching it will take us back to the start of the line.
2516 	    lnum = ourscope;
2517 	    if (find_last_paren(start, '(', ')')
2518 			&& (trypos = find_match_paren(curbuf->b_ind_maxparen))
2519 								      != NULL)
2520 		lnum = trypos->lnum;
2521 
2522 	    // It could have been something like
2523 	    //	   case 1: if (asdf &&
2524 	    //			ldfd) {
2525 	    //		    }
2526 	    if ((curbuf->b_ind_js || curbuf->b_ind_keep_case_label)
2527 			   && cin_iscase(skipwhite(ml_get_curline()), FALSE))
2528 		amount = get_indent();
2529 	    else if (curbuf->b_ind_js)
2530 		amount = get_indent_lnum(lnum);
2531 	    else
2532 		amount = skip_label(lnum, &l);
2533 
2534 	    start_brace = BRACE_AT_END;
2535 	}
2536 
2537 	// For Javascript check if the line starts with "key:".
2538 	if (curbuf->b_ind_js)
2539 	    js_cur_has_key = cin_has_js_key(theline);
2540 
2541 	// If we're looking at a closing brace, that's where
2542 	// we want to be.  otherwise, add the amount of room
2543 	// that an indent is supposed to be.
2544 	if (theline[0] == '}')
2545 	{
2546 	    // they may want closing braces to line up with something
2547 	    // other than the open brace.  indulge them, if so.
2548 	    amount += curbuf->b_ind_close_extra;
2549 	}
2550 	else
2551 	{
2552 	    // If we're looking at an "else", try to find an "if"
2553 	    // to match it with.
2554 	    // If we're looking at a "while", try to find a "do"
2555 	    // to match it with.
2556 	    lookfor = LOOKFOR_INITIAL;
2557 	    if (cin_iselse(theline))
2558 		lookfor = LOOKFOR_IF;
2559 	    else if (cin_iswhileofdo(theline, cur_curpos.lnum)) // XXX
2560 		lookfor = LOOKFOR_DO;
2561 	    if (lookfor != LOOKFOR_INITIAL)
2562 	    {
2563 		curwin->w_cursor.lnum = cur_curpos.lnum;
2564 		if (find_match(lookfor, ourscope) == OK)
2565 		{
2566 		    amount = get_indent();	// XXX
2567 		    goto theend;
2568 		}
2569 	    }
2570 
2571 	    // We get here if we are not on an "while-of-do" or "else" (or
2572 	    // failed to find a matching "if").
2573 	    // Search backwards for something to line up with.
2574 	    // First set amount for when we don't find anything.
2575 
2576 	    // if the '{' is  _really_ at the left margin, use the imaginary
2577 	    // location of a left-margin brace.  Otherwise, correct the
2578 	    // location for b_ind_open_extra.
2579 
2580 	    if (start_brace == BRACE_IN_COL0)	    // '{' is in column 0
2581 	    {
2582 		amount = curbuf->b_ind_open_left_imag;
2583 		lookfor_cpp_namespace = TRUE;
2584 	    }
2585 	    else if (start_brace == BRACE_AT_START &&
2586 		    lookfor_cpp_namespace)	  // '{' is at start
2587 	    {
2588 
2589 		lookfor_cpp_namespace = TRUE;
2590 	    }
2591 	    else
2592 	    {
2593 		if (start_brace == BRACE_AT_END)    // '{' is at end of line
2594 		{
2595 		    amount += curbuf->b_ind_open_imag;
2596 
2597 		    l = skipwhite(ml_get_curline());
2598 		    if (cin_is_cpp_namespace(l))
2599 			amount += curbuf->b_ind_cpp_namespace;
2600 		    else if (cin_is_cpp_extern_c(l))
2601 			amount += curbuf->b_ind_cpp_extern_c;
2602 		}
2603 		else
2604 		{
2605 		    // Compensate for adding b_ind_open_extra later.
2606 		    amount -= curbuf->b_ind_open_extra;
2607 		    if (amount < 0)
2608 			amount = 0;
2609 		}
2610 	    }
2611 
2612 	    lookfor_break = FALSE;
2613 
2614 	    if (cin_iscase(theline, FALSE))	// it's a switch() label
2615 	    {
2616 		lookfor = LOOKFOR_CASE;	// find a previous switch() label
2617 		amount += curbuf->b_ind_case;
2618 	    }
2619 	    else if (cin_isscopedecl(theline))	// private:, ...
2620 	    {
2621 		lookfor = LOOKFOR_SCOPEDECL;	// class decl is this block
2622 		amount += curbuf->b_ind_scopedecl;
2623 	    }
2624 	    else
2625 	    {
2626 		if (curbuf->b_ind_case_break && cin_isbreak(theline))
2627 		    // break; ...
2628 		    lookfor_break = TRUE;
2629 
2630 		lookfor = LOOKFOR_INITIAL;
2631 		// b_ind_level from start of block
2632 		amount += curbuf->b_ind_level;
2633 	    }
2634 	    scope_amount = amount;
2635 	    whilelevel = 0;
2636 
2637 	    // Search backwards.  If we find something we recognize, line up
2638 	    // with that.
2639 	    //
2640 	    // If we're looking at an open brace, indent
2641 	    // the usual amount relative to the conditional
2642 	    // that opens the block.
2643 	    curwin->w_cursor = cur_curpos;
2644 	    for (;;)
2645 	    {
2646 		curwin->w_cursor.lnum--;
2647 		curwin->w_cursor.col = 0;
2648 
2649 		// If we went all the way back to the start of our scope, line
2650 		// up with it.
2651 		if (curwin->w_cursor.lnum <= ourscope)
2652 		{
2653 		    // We reached end of scope:
2654 		    // If looking for a enum or structure initialization
2655 		    // go further back:
2656 		    // If it is an initializer (enum xxx or xxx =), then
2657 		    // don't add ind_continuation, otherwise it is a variable
2658 		    // declaration:
2659 		    // int x,
2660 		    //     here; <-- add ind_continuation
2661 		    if (lookfor == LOOKFOR_ENUM_OR_INIT)
2662 		    {
2663 			if (curwin->w_cursor.lnum == 0
2664 				|| curwin->w_cursor.lnum
2665 					  < ourscope - curbuf->b_ind_maxparen)
2666 			{
2667 			    // nothing found (abuse curbuf->b_ind_maxparen as
2668 			    // limit) assume terminated line (i.e. a variable
2669 			    // initialization)
2670 			    if (cont_amount > 0)
2671 				amount = cont_amount;
2672 			    else if (!curbuf->b_ind_js)
2673 				amount += ind_continuation;
2674 			    break;
2675 			}
2676 
2677 			l = ml_get_curline();
2678 
2679 			// If we're in a comment or raw string now, skip to
2680 			// the start of it.
2681 			trypos = ind_find_start_CORS(NULL);
2682 			if (trypos != NULL)
2683 			{
2684 			    curwin->w_cursor.lnum = trypos->lnum + 1;
2685 			    curwin->w_cursor.col = 0;
2686 			    continue;
2687 			}
2688 
2689 			// Skip preprocessor directives and blank lines.
2690 			if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum,
2691 								    &amount))
2692 			    continue;
2693 
2694 			if (cin_nocode(l))
2695 			    continue;
2696 
2697 			terminated = cin_isterminated(l, FALSE, TRUE);
2698 
2699 			// If we are at top level and the line looks like a
2700 			// function declaration, we are done
2701 			// (it's a variable declaration).
2702 			if (start_brace != BRACE_IN_COL0
2703 			     || !cin_isfuncdecl(&l, curwin->w_cursor.lnum, 0))
2704 			{
2705 			    // if the line is terminated with another ','
2706 			    // it is a continued variable initialization.
2707 			    // don't add extra indent.
2708 			    // TODO: does not work, if  a function
2709 			    // declaration is split over multiple lines:
2710 			    // cin_isfuncdecl returns FALSE then.
2711 			    if (terminated == ',')
2712 				break;
2713 
2714 			    // if it es a enum declaration or an assignment,
2715 			    // we are done.
2716 			    if (terminated != ';' && cin_isinit())
2717 				break;
2718 
2719 			    // nothing useful found
2720 			    if (terminated == 0 || terminated == '{')
2721 				continue;
2722 			}
2723 
2724 			if (terminated != ';')
2725 			{
2726 			    // Skip parens and braces. Position the cursor
2727 			    // over the rightmost paren, so that matching it
2728 			    // will take us back to the start of the line.
2729 			    // XXX
2730 			    trypos = NULL;
2731 			    if (find_last_paren(l, '(', ')'))
2732 				trypos = find_match_paren(
2733 						      curbuf->b_ind_maxparen);
2734 
2735 			    if (trypos == NULL && find_last_paren(l, '{', '}'))
2736 				trypos = find_start_brace();
2737 
2738 			    if (trypos != NULL)
2739 			    {
2740 				curwin->w_cursor.lnum = trypos->lnum + 1;
2741 				curwin->w_cursor.col = 0;
2742 				continue;
2743 			    }
2744 			}
2745 
2746 			// it's a variable declaration, add indentation
2747 			// like in
2748 			// int a,
2749 			//    b;
2750 			if (cont_amount > 0)
2751 			    amount = cont_amount;
2752 			else
2753 			    amount += ind_continuation;
2754 		    }
2755 		    else if (lookfor == LOOKFOR_UNTERM)
2756 		    {
2757 			if (cont_amount > 0)
2758 			    amount = cont_amount;
2759 			else
2760 			    amount += ind_continuation;
2761 		    }
2762 		    else
2763 		    {
2764 			if (lookfor != LOOKFOR_TERM
2765 					&& lookfor != LOOKFOR_CPP_BASECLASS
2766 					&& lookfor != LOOKFOR_COMMA)
2767 			{
2768 			    amount = scope_amount;
2769 			    if (theline[0] == '{')
2770 			    {
2771 				amount += curbuf->b_ind_open_extra;
2772 				added_to_amount = curbuf->b_ind_open_extra;
2773 			    }
2774 			}
2775 
2776 			if (lookfor_cpp_namespace)
2777 			{
2778 			    // Looking for C++ namespace, need to look further
2779 			    // back.
2780 			    if (curwin->w_cursor.lnum == ourscope)
2781 				continue;
2782 
2783 			    if (curwin->w_cursor.lnum == 0
2784 				    || curwin->w_cursor.lnum
2785 					      < ourscope - FIND_NAMESPACE_LIM)
2786 				break;
2787 
2788 			    l = ml_get_curline();
2789 
2790 			    // If we're in a comment or raw string now, skip
2791 			    // to the start of it.
2792 			    trypos = ind_find_start_CORS(NULL);
2793 			    if (trypos != NULL)
2794 			    {
2795 				curwin->w_cursor.lnum = trypos->lnum + 1;
2796 				curwin->w_cursor.col = 0;
2797 				continue;
2798 			    }
2799 
2800 			    // Skip preprocessor directives and blank lines.
2801 			    if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum,
2802 								    &amount))
2803 				continue;
2804 
2805 			    // Finally the actual check for "namespace".
2806 			    if (cin_is_cpp_namespace(l))
2807 			    {
2808 				amount += curbuf->b_ind_cpp_namespace
2809 							    - added_to_amount;
2810 				break;
2811 			    }
2812 			    else if (cin_is_cpp_extern_c(l))
2813 			    {
2814 				amount += curbuf->b_ind_cpp_extern_c
2815 							    - added_to_amount;
2816 				break;
2817 			    }
2818 
2819 			    if (cin_nocode(l))
2820 				continue;
2821 			}
2822 		    }
2823 		    break;
2824 		}
2825 
2826 		// If we're in a comment or raw string now, skip to the start
2827 		// of it.  XXX
2828 		if ((trypos = ind_find_start_CORS(&raw_string_start)) != NULL)
2829 		{
2830 		    curwin->w_cursor.lnum = trypos->lnum + 1;
2831 		    curwin->w_cursor.col = 0;
2832 		    continue;
2833 		}
2834 
2835 		l = ml_get_curline();
2836 
2837 		// If this is a switch() label, may line up relative to that.
2838 		// If this is a C++ scope declaration, do the same.
2839 		iscase = cin_iscase(l, FALSE);
2840 		if (iscase || cin_isscopedecl(l))
2841 		{
2842 		    // we are only looking for cpp base class
2843 		    // declaration/initialization any longer
2844 		    if (lookfor == LOOKFOR_CPP_BASECLASS)
2845 			break;
2846 
2847 		    // When looking for a "do" we are not interested in
2848 		    // labels.
2849 		    if (whilelevel > 0)
2850 			continue;
2851 
2852 		    //	case xx:
2853 		    //	    c = 99 +	    <- this indent plus continuation
2854 		    //->	   here;
2855 		    if (lookfor == LOOKFOR_UNTERM
2856 					   || lookfor == LOOKFOR_ENUM_OR_INIT)
2857 		    {
2858 			if (cont_amount > 0)
2859 			    amount = cont_amount;
2860 			else
2861 			    amount += ind_continuation;
2862 			break;
2863 		    }
2864 
2865 		    //	case xx:	<- line up with this case
2866 		    //	    x = 333;
2867 		    //	case yy:
2868 		    if (       (iscase && lookfor == LOOKFOR_CASE)
2869 			    || (iscase && lookfor_break)
2870 			    || (!iscase && lookfor == LOOKFOR_SCOPEDECL))
2871 		    {
2872 			// Check that this case label is not for another
2873 			// switch()		    XXX
2874 			if ((trypos = find_start_brace()) == NULL
2875 						  || trypos->lnum == ourscope)
2876 			{
2877 			    amount = get_indent();	// XXX
2878 			    break;
2879 			}
2880 			continue;
2881 		    }
2882 
2883 		    n = get_indent_nolabel(curwin->w_cursor.lnum);  // XXX
2884 
2885 		    //	 case xx: if (cond)	    <- line up with this if
2886 		    //		      y = y + 1;
2887 		    // ->	  s = 99;
2888 		    //
2889 		    //	 case xx:
2890 		    //	     if (cond)		<- line up with this line
2891 		    //		 y = y + 1;
2892 		    // ->    s = 99;
2893 		    if (lookfor == LOOKFOR_TERM)
2894 		    {
2895 			if (n)
2896 			    amount = n;
2897 
2898 			if (!lookfor_break)
2899 			    break;
2900 		    }
2901 
2902 		    //	 case xx: x = x + 1;	    <- line up with this x
2903 		    // ->	  y = y + 1;
2904 		    //
2905 		    //	 case xx: if (cond)	    <- line up with this if
2906 		    // ->	       y = y + 1;
2907 		    if (n)
2908 		    {
2909 			amount = n;
2910 			l = after_label(ml_get_curline());
2911 			if (l != NULL && cin_is_cinword(l))
2912 			{
2913 			    if (theline[0] == '{')
2914 				amount += curbuf->b_ind_open_extra;
2915 			    else
2916 				amount += curbuf->b_ind_level
2917 						     + curbuf->b_ind_no_brace;
2918 			}
2919 			break;
2920 		    }
2921 
2922 		    // Try to get the indent of a statement before the switch
2923 		    // label.  If nothing is found, line up relative to the
2924 		    // switch label.
2925 		    //	    break;		<- may line up with this line
2926 		    //	 case xx:
2927 		    // ->   y = 1;
2928 		    scope_amount = get_indent() + (iscase    // XXX
2929 					? curbuf->b_ind_case_code
2930 					: curbuf->b_ind_scopedecl_code);
2931 		    lookfor = curbuf->b_ind_case_break
2932 					      ? LOOKFOR_NOBREAK : LOOKFOR_ANY;
2933 		    continue;
2934 		}
2935 
2936 		// Looking for a switch() label or C++ scope declaration,
2937 		// ignore other lines, skip {}-blocks.
2938 		if (lookfor == LOOKFOR_CASE || lookfor == LOOKFOR_SCOPEDECL)
2939 		{
2940 		    if (find_last_paren(l, '{', '}')
2941 				     && (trypos = find_start_brace()) != NULL)
2942 		    {
2943 			curwin->w_cursor.lnum = trypos->lnum + 1;
2944 			curwin->w_cursor.col = 0;
2945 		    }
2946 		    continue;
2947 		}
2948 
2949 		// Ignore jump labels with nothing after them.
2950 		if (!curbuf->b_ind_js && cin_islabel())
2951 		{
2952 		    l = after_label(ml_get_curline());
2953 		    if (l == NULL || cin_nocode(l))
2954 			continue;
2955 		}
2956 
2957 		// Ignore #defines, #if, etc.
2958 		// Ignore comment and empty lines.
2959 		// (need to get the line again, cin_islabel() may have
2960 		// unlocked it)
2961 		l = ml_get_curline();
2962 		if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum, &amount)
2963 							     || cin_nocode(l))
2964 		    continue;
2965 
2966 		// Are we at the start of a cpp base class declaration or
2967 		// constructor initialization?  XXX
2968 		n = FALSE;
2969 		if (lookfor != LOOKFOR_TERM && curbuf->b_ind_cpp_baseclass > 0)
2970 		{
2971 		    n = cin_is_cpp_baseclass(&cache_cpp_baseclass);
2972 		    l = ml_get_curline();
2973 		}
2974 		if (n)
2975 		{
2976 		    if (lookfor == LOOKFOR_UNTERM)
2977 		    {
2978 			if (cont_amount > 0)
2979 			    amount = cont_amount;
2980 			else
2981 			    amount += ind_continuation;
2982 		    }
2983 		    else if (theline[0] == '{')
2984 		    {
2985 			// Need to find start of the declaration.
2986 			lookfor = LOOKFOR_UNTERM;
2987 			ind_continuation = 0;
2988 			continue;
2989 		    }
2990 		    else
2991 			// XXX
2992 			amount = get_baseclass_amount(
2993 						cache_cpp_baseclass.lpos.col);
2994 		    break;
2995 		}
2996 		else if (lookfor == LOOKFOR_CPP_BASECLASS)
2997 		{
2998 		    // only look, whether there is a cpp base class
2999 		    // declaration or initialization before the opening brace.
3000 		    if (cin_isterminated(l, TRUE, FALSE))
3001 			break;
3002 		    else
3003 			continue;
3004 		}
3005 
3006 		// What happens next depends on the line being terminated.
3007 		// If terminated with a ',' only consider it terminating if
3008 		// there is another unterminated statement behind, eg:
3009 		//   123,
3010 		//   sizeof
3011 		//	  here
3012 		// Otherwise check whether it is a enumeration or structure
3013 		// initialisation (not indented) or a variable declaration
3014 		// (indented).
3015 		terminated = cin_isterminated(l, FALSE, TRUE);
3016 
3017 		if (js_cur_has_key)
3018 		{
3019 		    js_cur_has_key = 0; // only check the first line
3020 		    if (curbuf->b_ind_js && terminated == ',')
3021 		    {
3022 			// For Javascript we might be inside an object:
3023 			//   key: something,  <- align with this
3024 			//   key: something
3025 			// or:
3026 			//   key: something +  <- align with this
3027 			//       something,
3028 			//   key: something
3029 			lookfor = LOOKFOR_JS_KEY;
3030 		    }
3031 		}
3032 		if (lookfor == LOOKFOR_JS_KEY && cin_has_js_key(l))
3033 		{
3034 		    amount = get_indent();
3035 		    break;
3036 		}
3037 		if (lookfor == LOOKFOR_COMMA)
3038 		{
3039 		    if (tryposBrace != NULL && tryposBrace->lnum
3040 						    >= curwin->w_cursor.lnum)
3041 			break;
3042 		    if (terminated == ',')
3043 			// line below current line is the one that starts a
3044 			// (possibly broken) line ending in a comma.
3045 			break;
3046 		    else
3047 		    {
3048 			amount = get_indent();
3049 			if (curwin->w_cursor.lnum - 1 == ourscope)
3050 			    // line above is start of the scope, thus current
3051 			    // line is the one that stars a (possibly broken)
3052 			    // line ending in a comma.
3053 			    break;
3054 		    }
3055 		}
3056 
3057 		if (terminated == 0 || (lookfor != LOOKFOR_UNTERM
3058 							&& terminated == ','))
3059 		{
3060 		    if (lookfor != LOOKFOR_ENUM_OR_INIT &&
3061 			    (*skipwhite(l) == '[' || l[STRLEN(l) - 1] == '['))
3062 			amount += ind_continuation;
3063 		    // if we're in the middle of a paren thing,
3064 		    // go back to the line that starts it so
3065 		    // we can get the right prevailing indent
3066 		    //	   if ( foo &&
3067 		    //		    bar )
3068 
3069 		    // Position the cursor over the rightmost paren, so that
3070 		    // matching it will take us back to the start of the line.
3071 		    // Ignore a match before the start of the block.
3072 		    (void)find_last_paren(l, '(', ')');
3073 		    trypos = find_match_paren(corr_ind_maxparen(&cur_curpos));
3074 		    if (trypos != NULL && (trypos->lnum < tryposBrace->lnum
3075 				|| (trypos->lnum == tryposBrace->lnum
3076 				    && trypos->col < tryposBrace->col)))
3077 			trypos = NULL;
3078 
3079 		    // If we are looking for ',', we also look for matching
3080 		    // braces.
3081 		    if (trypos == NULL && terminated == ','
3082 					      && find_last_paren(l, '{', '}'))
3083 			trypos = find_start_brace();
3084 
3085 		    if (trypos != NULL)
3086 		    {
3087 			// Check if we are on a case label now.  This is
3088 			// handled above.
3089 			//     case xx:  if ( asdf &&
3090 			//			asdf)
3091 			curwin->w_cursor = *trypos;
3092 			l = ml_get_curline();
3093 			if (cin_iscase(l, FALSE) || cin_isscopedecl(l))
3094 			{
3095 			    ++curwin->w_cursor.lnum;
3096 			    curwin->w_cursor.col = 0;
3097 			    continue;
3098 			}
3099 		    }
3100 
3101 		    /*
3102 		     * Skip over continuation lines to find the one to get the
3103 		     * indent from
3104 		     * char *usethis = "bla\
3105 		     *		 bla",
3106 		     *      here;
3107 		     */
3108 		    if (terminated == ',')
3109 		    {
3110 			while (curwin->w_cursor.lnum > 1)
3111 			{
3112 			    l = ml_get(curwin->w_cursor.lnum - 1);
3113 			    if (*l == NUL || l[STRLEN(l) - 1] != '\\')
3114 				break;
3115 			    --curwin->w_cursor.lnum;
3116 			    curwin->w_cursor.col = 0;
3117 			}
3118 		    }
3119 
3120 		    // Get indent and pointer to text for current line,
3121 		    // ignoring any jump label.  XXX
3122 		    if (curbuf->b_ind_js)
3123 			cur_amount = get_indent();
3124 		    else
3125 			cur_amount = skip_label(curwin->w_cursor.lnum, &l);
3126 		    // If this is just above the line we are indenting, and it
3127 		    // starts with a '{', line it up with this line.
3128 		    //		while (not)
3129 		    // ->	{
3130 		    //		}
3131 		    if (terminated != ',' && lookfor != LOOKFOR_TERM
3132 							 && theline[0] == '{')
3133 		    {
3134 			amount = cur_amount;
3135 			// Only add b_ind_open_extra when the current line
3136 			// doesn't start with a '{', which must have a match
3137 			// in the same line (scope is the same).  Probably:
3138 			//	{ 1, 2 },
3139 			// ->	{ 3, 4 }
3140 			if (*skipwhite(l) != '{')
3141 			    amount += curbuf->b_ind_open_extra;
3142 
3143 			if (curbuf->b_ind_cpp_baseclass && !curbuf->b_ind_js)
3144 			{
3145 			    // have to look back, whether it is a cpp base
3146 			    // class declaration or initialization
3147 			    lookfor = LOOKFOR_CPP_BASECLASS;
3148 			    continue;
3149 			}
3150 			break;
3151 		    }
3152 
3153 		    // Check if we are after an "if", "while", etc.
3154 		    // Also allow "   } else".
3155 		    if (cin_is_cinword(l) || cin_iselse(skipwhite(l)))
3156 		    {
3157 			// Found an unterminated line after an if (), line up
3158 			// with the last one.
3159 			//   if (cond)
3160 			//	    100 +
3161 			// ->		here;
3162 			if (lookfor == LOOKFOR_UNTERM
3163 					   || lookfor == LOOKFOR_ENUM_OR_INIT)
3164 			{
3165 			    if (cont_amount > 0)
3166 				amount = cont_amount;
3167 			    else
3168 				amount += ind_continuation;
3169 			    break;
3170 			}
3171 
3172 			// If this is just above the line we are indenting, we
3173 			// are finished.
3174 			//	    while (not)
3175 			// ->		here;
3176 			// Otherwise this indent can be used when the line
3177 			// before this is terminated.
3178 			//	yyy;
3179 			//	if (stat)
3180 			//	    while (not)
3181 			//		xxx;
3182 			// ->	here;
3183 			amount = cur_amount;
3184 			if (theline[0] == '{')
3185 			    amount += curbuf->b_ind_open_extra;
3186 			if (lookfor != LOOKFOR_TERM)
3187 			{
3188 			    amount += curbuf->b_ind_level
3189 						     + curbuf->b_ind_no_brace;
3190 			    break;
3191 			}
3192 
3193 			// Special trick: when expecting the while () after a
3194 			// do, line up with the while()
3195 			//     do
3196 			//	    x = 1;
3197 			// ->  here
3198 			l = skipwhite(ml_get_curline());
3199 			if (cin_isdo(l))
3200 			{
3201 			    if (whilelevel == 0)
3202 				break;
3203 			    --whilelevel;
3204 			}
3205 
3206 			// When searching for a terminated line, don't use the
3207 			// one between the "if" and the matching "else".
3208 			// Need to use the scope of this "else".  XXX
3209 			// If whilelevel != 0 continue looking for a "do {".
3210 			if (cin_iselse(l) && whilelevel == 0)
3211 			{
3212 			    // If we're looking at "} else", let's make sure we
3213 			    // find the opening brace of the enclosing scope,
3214 			    // not the one from "if () {".
3215 			    if (*l == '}')
3216 				curwin->w_cursor.col =
3217 					  (colnr_T)(l - ml_get_curline()) + 1;
3218 
3219 			    if ((trypos = find_start_brace()) == NULL
3220 				       || find_match(LOOKFOR_IF, trypos->lnum)
3221 								      == FAIL)
3222 				break;
3223 			}
3224 		    }
3225 
3226 		    // If we're below an unterminated line that is not an
3227 		    // "if" or something, we may line up with this line or
3228 		    // add something for a continuation line, depending on
3229 		    // the line before this one.
3230 		    else
3231 		    {
3232 			// Found two unterminated lines on a row, line up with
3233 			// the last one.
3234 			//   c = 99 +
3235 			//	    100 +
3236 			// ->	    here;
3237 			if (lookfor == LOOKFOR_UNTERM)
3238 			{
3239 			    // When line ends in a comma add extra indent
3240 			    if (terminated == ',')
3241 				amount += ind_continuation;
3242 			    break;
3243 			}
3244 
3245 			if (lookfor == LOOKFOR_ENUM_OR_INIT)
3246 			{
3247 			    // Found two lines ending in ',', lineup with the
3248 			    // lowest one, but check for cpp base class
3249 			    // declaration/initialization, if it is an
3250 			    // opening brace or we are looking just for
3251 			    // enumerations/initializations.
3252 			    if (terminated == ',')
3253 			    {
3254 				if (curbuf->b_ind_cpp_baseclass == 0)
3255 				    break;
3256 
3257 				lookfor = LOOKFOR_CPP_BASECLASS;
3258 				continue;
3259 			    }
3260 
3261 			    // Ignore unterminated lines in between, but
3262 			    // reduce indent.
3263 			    if (amount > cur_amount)
3264 				amount = cur_amount;
3265 			}
3266 			else
3267 			{
3268 			    // Found first unterminated line on a row, may
3269 			    // line up with this line, remember its indent
3270 			    //	    100 +
3271 			    // ->	    here;
3272 			    l = ml_get_curline();
3273 			    amount = cur_amount;
3274 
3275 			    n = (int)STRLEN(l);
3276 			    if (terminated == ',' && (*skipwhite(l) == ']'
3277 					|| (n >=2 && l[n - 2] == ']')))
3278 				break;
3279 
3280 			    // If previous line ends in ',', check whether we
3281 			    // are in an initialization or enum
3282 			    // struct xxx =
3283 			    // {
3284 			    //      sizeof a,
3285 			    //      124 };
3286 			    // or a normal possible continuation line.
3287 			    // but only, of no other statement has been found
3288 			    // yet.
3289 			    if (lookfor == LOOKFOR_INITIAL && terminated == ',')
3290 			    {
3291 				if (curbuf->b_ind_js)
3292 				{
3293 				    // Search for a line ending in a comma
3294 				    // and line up with the line below it
3295 				    // (could be the current line).
3296 				    // some = [
3297 				    //     1,     <- line up here
3298 				    //     2,
3299 				    // some = [
3300 				    //     3 +    <- line up here
3301 				    //       4 *
3302 				    //        5,
3303 				    //     6,
3304 				    if (cin_iscomment(skipwhite(l)))
3305 					break;
3306 				    lookfor = LOOKFOR_COMMA;
3307 				    trypos = find_match_char('[',
3308 						      curbuf->b_ind_maxparen);
3309 				    if (trypos != NULL)
3310 				    {
3311 					if (trypos->lnum
3312 						 == curwin->w_cursor.lnum - 1)
3313 					{
3314 					    // Current line is first inside
3315 					    // [], line up with it.
3316 					    break;
3317 					}
3318 					ourscope = trypos->lnum;
3319 				    }
3320 				}
3321 				else
3322 				{
3323 				    lookfor = LOOKFOR_ENUM_OR_INIT;
3324 				    cont_amount = cin_first_id_amount();
3325 				}
3326 			    }
3327 			    else
3328 			    {
3329 				if (lookfor == LOOKFOR_INITIAL
3330 					&& *l != NUL
3331 					&& l[STRLEN(l) - 1] == '\\')
3332 								// XXX
3333 				    cont_amount = cin_get_equal_amount(
3334 						       curwin->w_cursor.lnum);
3335 				if (lookfor != LOOKFOR_TERM
3336 						&& lookfor != LOOKFOR_JS_KEY
3337 						&& lookfor != LOOKFOR_COMMA
3338 						&& raw_string_start != curwin->w_cursor.lnum)
3339 				    lookfor = LOOKFOR_UNTERM;
3340 			    }
3341 			}
3342 		    }
3343 		}
3344 
3345 		// Check if we are after a while (cond);
3346 		// If so: Ignore until the matching "do".
3347 		else if (cin_iswhileofdo_end(terminated)) // XXX
3348 		{
3349 		    // Found an unterminated line after a while ();, line up
3350 		    // with the last one.
3351 		    //	    while (cond);
3352 		    //	    100 +		<- line up with this one
3353 		    // ->	    here;
3354 		    if (lookfor == LOOKFOR_UNTERM
3355 					   || lookfor == LOOKFOR_ENUM_OR_INIT)
3356 		    {
3357 			if (cont_amount > 0)
3358 			    amount = cont_amount;
3359 			else
3360 			    amount += ind_continuation;
3361 			break;
3362 		    }
3363 
3364 		    if (whilelevel == 0)
3365 		    {
3366 			lookfor = LOOKFOR_TERM;
3367 			amount = get_indent();	    // XXX
3368 			if (theline[0] == '{')
3369 			    amount += curbuf->b_ind_open_extra;
3370 		    }
3371 		    ++whilelevel;
3372 		}
3373 
3374 		// We are after a "normal" statement.
3375 		// If we had another statement we can stop now and use the
3376 		// indent of that other statement.
3377 		// Otherwise the indent of the current statement may be used,
3378 		// search backwards for the next "normal" statement.
3379 		else
3380 		{
3381 		    // Skip single break line, if before a switch label. It
3382 		    // may be lined up with the case label.
3383 		    if (lookfor == LOOKFOR_NOBREAK
3384 				  && cin_isbreak(skipwhite(ml_get_curline())))
3385 		    {
3386 			lookfor = LOOKFOR_ANY;
3387 			continue;
3388 		    }
3389 
3390 		    // Handle "do {" line.
3391 		    if (whilelevel > 0)
3392 		    {
3393 			l = cin_skipcomment(ml_get_curline());
3394 			if (cin_isdo(l))
3395 			{
3396 			    amount = get_indent();	// XXX
3397 			    --whilelevel;
3398 			    continue;
3399 			}
3400 		    }
3401 
3402 		    // Found a terminated line above an unterminated line. Add
3403 		    // the amount for a continuation line.
3404 		    //	 x = 1;
3405 		    //	 y = foo +
3406 		    // ->	here;
3407 		    // or
3408 		    //	 int x = 1;
3409 		    //	 int foo,
3410 		    // ->	here;
3411 		    if (lookfor == LOOKFOR_UNTERM
3412 					   || lookfor == LOOKFOR_ENUM_OR_INIT)
3413 		    {
3414 			if (cont_amount > 0)
3415 			    amount = cont_amount;
3416 			else
3417 			    amount += ind_continuation;
3418 			break;
3419 		    }
3420 
3421 		    // Found a terminated line above a terminated line or "if"
3422 		    // etc. line. Use the amount of the line below us.
3423 		    //	 x = 1;				x = 1;
3424 		    //	 if (asdf)		    y = 2;
3425 		    //	     while (asdf)	  ->here;
3426 		    //		here;
3427 		    // ->foo;
3428 		    if (lookfor == LOOKFOR_TERM)
3429 		    {
3430 			if (!lookfor_break && whilelevel == 0)
3431 			    break;
3432 		    }
3433 
3434 		    // First line above the one we're indenting is terminated.
3435 		    // To know what needs to be done look further backward for
3436 		    // a terminated line.
3437 		    else
3438 		    {
3439 			// position the cursor over the rightmost paren, so
3440 			// that matching it will take us back to the start of
3441 			// the line.  Helps for:
3442 			//     func(asdr,
3443 			//	      asdfasdf);
3444 			//     here;
3445 term_again:
3446 			l = ml_get_curline();
3447 			if (find_last_paren(l, '(', ')')
3448 				&& (trypos = find_match_paren(
3449 					   curbuf->b_ind_maxparen)) != NULL)
3450 			{
3451 			    // Check if we are on a case label now.  This is
3452 			    // handled above.
3453 			    //	   case xx:  if ( asdf &&
3454 			    //			    asdf)
3455 			    curwin->w_cursor = *trypos;
3456 			    l = ml_get_curline();
3457 			    if (cin_iscase(l, FALSE) || cin_isscopedecl(l))
3458 			    {
3459 				++curwin->w_cursor.lnum;
3460 				curwin->w_cursor.col = 0;
3461 				continue;
3462 			    }
3463 			}
3464 
3465 			// When aligning with the case statement, don't align
3466 			// with a statement after it.
3467 			//  case 1: {   <-- don't use this { position
3468 			//	stat;
3469 			//  }
3470 			//  case 2:
3471 			//	stat;
3472 			// }
3473 			iscase = (curbuf->b_ind_keep_case_label
3474 						     && cin_iscase(l, FALSE));
3475 
3476 			// Get indent and pointer to text for current line,
3477 			// ignoring any jump label.
3478 			amount = skip_label(curwin->w_cursor.lnum, &l);
3479 
3480 			if (theline[0] == '{')
3481 			    amount += curbuf->b_ind_open_extra;
3482 			// See remark above: "Only add b_ind_open_extra.."
3483 			l = skipwhite(l);
3484 			if (*l == '{')
3485 			    amount -= curbuf->b_ind_open_extra;
3486 			lookfor = iscase ? LOOKFOR_ANY : LOOKFOR_TERM;
3487 
3488 			// When a terminated line starts with "else" skip to
3489 			// the matching "if":
3490 			//       else 3;
3491 			//	     indent this;
3492 			// Need to use the scope of this "else".  XXX
3493 			// If whilelevel != 0 continue looking for a "do {".
3494 			if (lookfor == LOOKFOR_TERM
3495 				&& *l != '}'
3496 				&& cin_iselse(l)
3497 				&& whilelevel == 0)
3498 			{
3499 			    if ((trypos = find_start_brace()) == NULL
3500 				       || find_match(LOOKFOR_IF, trypos->lnum)
3501 								      == FAIL)
3502 				break;
3503 			    continue;
3504 			}
3505 
3506 			// If we're at the end of a block, skip to the start of
3507 			// that block.
3508 			l = ml_get_curline();
3509 			if (find_last_paren(l, '{', '}') // XXX
3510 				     && (trypos = find_start_brace()) != NULL)
3511 			{
3512 			    curwin->w_cursor = *trypos;
3513 			    // if not "else {" check for terminated again
3514 			    // but skip block for "} else {"
3515 			    l = cin_skipcomment(ml_get_curline());
3516 			    if (*l == '}' || !cin_iselse(l))
3517 				goto term_again;
3518 			    ++curwin->w_cursor.lnum;
3519 			    curwin->w_cursor.col = 0;
3520 			}
3521 		    }
3522 		}
3523 	    }
3524 	}
3525       }
3526 
3527       // add extra indent for a comment
3528       if (cin_iscomment(theline))
3529 	  amount += curbuf->b_ind_comment;
3530 
3531       // subtract extra left-shift for jump labels
3532       if (curbuf->b_ind_jump_label > 0 && original_line_islabel)
3533 	  amount -= curbuf->b_ind_jump_label;
3534 
3535       goto theend;
3536     }
3537 
3538     // ok -- we're not inside any sort of structure at all!
3539     //
3540     // This means we're at the top level, and everything should
3541     // basically just match where the previous line is, except
3542     // for the lines immediately following a function declaration,
3543     // which are K&R-style parameters and need to be indented.
3544     //
3545     // if our line starts with an open brace, forget about any
3546     // prevailing indent and make sure it looks like the start
3547     // of a function
3548 
3549     if (theline[0] == '{')
3550     {
3551 	amount = curbuf->b_ind_first_open;
3552 	goto theend;
3553     }
3554 
3555     // If the NEXT line is a function declaration, the current
3556     // line needs to be indented as a function type spec.
3557     // Don't do this if the current line looks like a comment or if the
3558     // current line is terminated, ie. ends in ';', or if the current line
3559     // contains { or }: "void f() {\n if (1)"
3560     if (cur_curpos.lnum < curbuf->b_ml.ml_line_count
3561 	    && !cin_nocode(theline)
3562 	    && vim_strchr(theline, '{') == NULL
3563 	    && vim_strchr(theline, '}') == NULL
3564 	    && !cin_ends_in(theline, (char_u *)":", NULL)
3565 	    && !cin_ends_in(theline, (char_u *)",", NULL)
3566 	    && cin_isfuncdecl(NULL, cur_curpos.lnum + 1,
3567 			      cur_curpos.lnum + 1)
3568 	    && !cin_isterminated(theline, FALSE, TRUE))
3569     {
3570 	amount = curbuf->b_ind_func_type;
3571 	goto theend;
3572     }
3573 
3574     // search backwards until we find something we recognize
3575     amount = 0;
3576     curwin->w_cursor = cur_curpos;
3577     while (curwin->w_cursor.lnum > 1)
3578     {
3579 	curwin->w_cursor.lnum--;
3580 	curwin->w_cursor.col = 0;
3581 
3582 	l = ml_get_curline();
3583 
3584 	// If we're in a comment or raw string now, skip to the start
3585 	// of it.  XXX
3586 	if ((trypos = ind_find_start_CORS(NULL)) != NULL)
3587 	{
3588 	    curwin->w_cursor.lnum = trypos->lnum + 1;
3589 	    curwin->w_cursor.col = 0;
3590 	    continue;
3591 	}
3592 
3593 	// Are we at the start of a cpp base class declaration or
3594 	// constructor initialization?  XXX
3595 	n = FALSE;
3596 	if (curbuf->b_ind_cpp_baseclass != 0 && theline[0] != '{')
3597 	{
3598 	    n = cin_is_cpp_baseclass(&cache_cpp_baseclass);
3599 	    l = ml_get_curline();
3600 	}
3601 	if (n)
3602 	{
3603 							     // XXX
3604 	    amount = get_baseclass_amount(cache_cpp_baseclass.lpos.col);
3605 	    break;
3606 	}
3607 
3608 	// Skip preprocessor directives and blank lines.
3609 	if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum, &amount))
3610 	    continue;
3611 
3612 	if (cin_nocode(l))
3613 	    continue;
3614 
3615 	// If the previous line ends in ',', use one level of
3616 	// indentation:
3617 	// int foo,
3618 	//     bar;
3619 	// do this before checking for '}' in case of eg.
3620 	// enum foobar
3621 	// {
3622 	//   ...
3623 	// } foo,
3624 	//   bar;
3625 	n = 0;
3626 	if (cin_ends_in(l, (char_u *)",", NULL)
3627 		     || (*l != NUL && (n = l[STRLEN(l) - 1]) == '\\'))
3628 	{
3629 	    // take us back to opening paren
3630 	    if (find_last_paren(l, '(', ')')
3631 		    && (trypos = find_match_paren(
3632 				     curbuf->b_ind_maxparen)) != NULL)
3633 		curwin->w_cursor = *trypos;
3634 
3635 	    /*
3636 	     * For a line ending in ',' that is a continuation line go
3637 	     * back to the first line with a backslash:
3638 	     * char *foo = "bla\
3639 	     *		 bla",
3640 	     *      here;
3641 	     */
3642 	    while (n == 0 && curwin->w_cursor.lnum > 1)
3643 	    {
3644 		l = ml_get(curwin->w_cursor.lnum - 1);
3645 		if (*l == NUL || l[STRLEN(l) - 1] != '\\')
3646 		    break;
3647 		--curwin->w_cursor.lnum;
3648 		curwin->w_cursor.col = 0;
3649 	    }
3650 
3651 	    amount = get_indent();	    // XXX
3652 
3653 	    if (amount == 0)
3654 		amount = cin_first_id_amount();
3655 	    if (amount == 0)
3656 		amount = ind_continuation;
3657 	    break;
3658 	}
3659 
3660 	// If the line looks like a function declaration, and we're
3661 	// not in a comment, put it the left margin.
3662 	if (cin_isfuncdecl(NULL, cur_curpos.lnum, 0))  // XXX
3663 	    break;
3664 	l = ml_get_curline();
3665 
3666 	// Finding the closing '}' of a previous function.  Put
3667 	// current line at the left margin.  For when 'cino' has "fs".
3668 	if (*skipwhite(l) == '}')
3669 	    break;
3670 
3671 	//			    (matching {)
3672 	// If the previous line ends on '};' (maybe followed by
3673 	// comments) align at column 0.  For example:
3674 	// char *string_array[] = { "foo",
3675 	//     / * x * / "b};ar" }; / * foobar * /
3676 	if (cin_ends_in(l, (char_u *)"};", NULL))
3677 	    break;
3678 
3679 	// If the previous line ends on '[' we are probably in an
3680 	// array constant:
3681 	// something = [
3682 	//     234,  <- extra indent
3683 	if (cin_ends_in(l, (char_u *)"[", NULL))
3684 	{
3685 	    amount = get_indent() + ind_continuation;
3686 	    break;
3687 	}
3688 
3689 	// Find a line only has a semicolon that belongs to a previous
3690 	// line ending in '}', e.g. before an #endif.  Don't increase
3691 	// indent then.
3692 	if (*(look = skipwhite(l)) == ';' && cin_nocode(look + 1))
3693 	{
3694 	    pos_T curpos_save = curwin->w_cursor;
3695 
3696 	    while (curwin->w_cursor.lnum > 1)
3697 	    {
3698 		look = ml_get(--curwin->w_cursor.lnum);
3699 		if (!(cin_nocode(look) || cin_ispreproc_cont(
3700 				      &look, &curwin->w_cursor.lnum, &amount)))
3701 		    break;
3702 	    }
3703 	    if (curwin->w_cursor.lnum > 0
3704 			    && cin_ends_in(look, (char_u *)"}", NULL))
3705 		break;
3706 
3707 	    curwin->w_cursor = curpos_save;
3708 	}
3709 
3710 	// If the PREVIOUS line is a function declaration, the current
3711 	// line (and the ones that follow) needs to be indented as
3712 	// parameters.
3713 	if (cin_isfuncdecl(&l, curwin->w_cursor.lnum, 0))
3714 	{
3715 	    amount = curbuf->b_ind_param;
3716 	    break;
3717 	}
3718 
3719 	// If the previous line ends in ';' and the line before the
3720 	// previous line ends in ',' or '\', ident to column zero:
3721 	// int foo,
3722 	//     bar;
3723 	// indent_to_0 here;
3724 	if (cin_ends_in(l, (char_u *)";", NULL))
3725 	{
3726 	    l = ml_get(curwin->w_cursor.lnum - 1);
3727 	    if (cin_ends_in(l, (char_u *)",", NULL)
3728 		    || (*l != NUL && l[STRLEN(l) - 1] == '\\'))
3729 		break;
3730 	    l = ml_get_curline();
3731 	}
3732 
3733 	// Doesn't look like anything interesting -- so just
3734 	// use the indent of this line.
3735 	//
3736 	// Position the cursor over the rightmost paren, so that
3737 	// matching it will take us back to the start of the line.
3738 	find_last_paren(l, '(', ')');
3739 
3740 	if ((trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL)
3741 	    curwin->w_cursor = *trypos;
3742 	amount = get_indent();	    // XXX
3743 	break;
3744     }
3745 
3746     // add extra indent for a comment
3747     if (cin_iscomment(theline))
3748 	amount += curbuf->b_ind_comment;
3749 
3750     /*
3751      * add extra indent if the previous line ended in a backslash:
3752      *	      "asdfasdf\
3753      *		  here";
3754      *	    char *foo = "asdf\
3755      *			 here";
3756      */
3757     if (cur_curpos.lnum > 1)
3758     {
3759 	l = ml_get(cur_curpos.lnum - 1);
3760 	if (*l != NUL && l[STRLEN(l) - 1] == '\\')
3761 	{
3762 	    cur_amount = cin_get_equal_amount(cur_curpos.lnum - 1);
3763 	    if (cur_amount > 0)
3764 		amount = cur_amount;
3765 	    else if (cur_amount == 0)
3766 		amount += ind_continuation;
3767 	}
3768     }
3769 
3770 theend:
3771     if (amount < 0)
3772 	amount = 0;
3773 
3774 laterend:
3775     // put the cursor back where it belongs
3776     curwin->w_cursor = cur_curpos;
3777 
3778     vim_free(linecopy);
3779 
3780     return amount;
3781 }
3782 
3783     static int
3784 find_match(int lookfor, linenr_T ourscope)
3785 {
3786     char_u	*look;
3787     pos_T	*theirscope;
3788     char_u	*mightbeif;
3789     int		elselevel;
3790     int		whilelevel;
3791 
3792     if (lookfor == LOOKFOR_IF)
3793     {
3794 	elselevel = 1;
3795 	whilelevel = 0;
3796     }
3797     else
3798     {
3799 	elselevel = 0;
3800 	whilelevel = 1;
3801     }
3802 
3803     curwin->w_cursor.col = 0;
3804 
3805     while (curwin->w_cursor.lnum > ourscope + 1)
3806     {
3807 	curwin->w_cursor.lnum--;
3808 	curwin->w_cursor.col = 0;
3809 
3810 	look = cin_skipcomment(ml_get_curline());
3811 	if (cin_iselse(look)
3812 		|| cin_isif(look)
3813 		|| cin_isdo(look)			    // XXX
3814 		|| cin_iswhileofdo(look, curwin->w_cursor.lnum))
3815 	{
3816 	    // if we've gone outside the braces entirely,
3817 	    // we must be out of scope...
3818 	    theirscope = find_start_brace();  // XXX
3819 	    if (theirscope == NULL)
3820 		break;
3821 
3822 	    // and if the brace enclosing this is further
3823 	    // back than the one enclosing the else, we're
3824 	    // out of luck too.
3825 	    if (theirscope->lnum < ourscope)
3826 		break;
3827 
3828 	    // and if they're enclosed in a *deeper* brace,
3829 	    // then we can ignore it because it's in a
3830 	    // different scope...
3831 	    if (theirscope->lnum > ourscope)
3832 		continue;
3833 
3834 	    // if it was an "else" (that's not an "else if")
3835 	    // then we need to go back to another if, so
3836 	    // increment elselevel
3837 	    look = cin_skipcomment(ml_get_curline());
3838 	    if (cin_iselse(look))
3839 	    {
3840 		mightbeif = cin_skipcomment(look + 4);
3841 		if (!cin_isif(mightbeif))
3842 		    ++elselevel;
3843 		continue;
3844 	    }
3845 
3846 	    // if it was a "while" then we need to go back to
3847 	    // another "do", so increment whilelevel.  XXX
3848 	    if (cin_iswhileofdo(look, curwin->w_cursor.lnum))
3849 	    {
3850 		++whilelevel;
3851 		continue;
3852 	    }
3853 
3854 	    // If it's an "if" decrement elselevel
3855 	    look = cin_skipcomment(ml_get_curline());
3856 	    if (cin_isif(look))
3857 	    {
3858 		elselevel--;
3859 		// When looking for an "if" ignore "while"s that
3860 		// get in the way.
3861 		if (elselevel == 0 && lookfor == LOOKFOR_IF)
3862 		    whilelevel = 0;
3863 	    }
3864 
3865 	    // If it's a "do" decrement whilelevel
3866 	    if (cin_isdo(look))
3867 		whilelevel--;
3868 
3869 	    // if we've used up all the elses, then
3870 	    // this must be the if that we want!
3871 	    // match the indent level of that if.
3872 	    if (elselevel <= 0 && whilelevel <= 0)
3873 	    {
3874 		return OK;
3875 	    }
3876 	}
3877     }
3878     return FAIL;
3879 }
3880 
3881 # if defined(FEAT_EVAL) || defined(PROTO)
3882 /*
3883  * Get indent level from 'indentexpr'.
3884  */
3885     int
3886 get_expr_indent(void)
3887 {
3888     int		indent = -1;
3889     char_u	*inde_copy;
3890     pos_T	save_pos;
3891     colnr_T	save_curswant;
3892     int		save_set_curswant;
3893     int		save_State;
3894     int		use_sandbox = was_set_insecurely((char_u *)"indentexpr",
3895 								   OPT_LOCAL);
3896 
3897     // Save and restore cursor position and curswant, in case it was changed
3898     // via :normal commands
3899     save_pos = curwin->w_cursor;
3900     save_curswant = curwin->w_curswant;
3901     save_set_curswant = curwin->w_set_curswant;
3902     set_vim_var_nr(VV_LNUM, curwin->w_cursor.lnum);
3903     if (use_sandbox)
3904 	++sandbox;
3905     ++textlock;
3906 
3907     // Need to make a copy, the 'indentexpr' option could be changed while
3908     // evaluating it.
3909     inde_copy = vim_strsave(curbuf->b_p_inde);
3910     if (inde_copy != NULL)
3911     {
3912 	indent = (int)eval_to_number(inde_copy);
3913 	vim_free(inde_copy);
3914     }
3915 
3916     if (use_sandbox)
3917 	--sandbox;
3918     --textlock;
3919 
3920     // Restore the cursor position so that 'indentexpr' doesn't need to.
3921     // Pretend to be in Insert mode, allow cursor past end of line for "o"
3922     // command.
3923     save_State = State;
3924     State = INSERT;
3925     curwin->w_cursor = save_pos;
3926     curwin->w_curswant = save_curswant;
3927     curwin->w_set_curswant = save_set_curswant;
3928     check_cursor();
3929     State = save_State;
3930 
3931     // If there is an error, just keep the current indent.
3932     if (indent < 0)
3933 	indent = get_indent();
3934 
3935     return indent;
3936 }
3937 # endif
3938 
3939 /*
3940  * return TRUE if 'cinkeys' contains the key "keytyped",
3941  * when == '*':	    Only if key is preceded with '*'	(indent before insert)
3942  * when == '!':	    Only if key is preceded with '!'	(don't insert)
3943  * when == ' ':	    Only if key is not preceded with '*'(indent afterwards)
3944  *
3945  * "keytyped" can have a few special values:
3946  * KEY_OPEN_FORW
3947  * KEY_OPEN_BACK
3948  * KEY_COMPLETE	    just finished completion.
3949  *
3950  * If line_is_empty is TRUE accept keys with '0' before them.
3951  */
3952     int
3953 in_cinkeys(
3954     int		keytyped,
3955     int		when,
3956     int		line_is_empty)
3957 {
3958     char_u	*look;
3959     int		try_match;
3960     int		try_match_word;
3961     char_u	*p;
3962     char_u	*line;
3963     int		icase;
3964     int		i;
3965 
3966     if (keytyped == NUL)
3967 	// Can happen with CTRL-Y and CTRL-E on a short line.
3968 	return FALSE;
3969 
3970 #ifdef FEAT_EVAL
3971     if (*curbuf->b_p_inde != NUL)
3972 	look = curbuf->b_p_indk;	// 'indentexpr' set: use 'indentkeys'
3973     else
3974 #endif
3975 	look = curbuf->b_p_cink;	// 'indentexpr' empty: use 'cinkeys'
3976     while (*look)
3977     {
3978 	// Find out if we want to try a match with this key, depending on
3979 	// 'when' and a '*' or '!' before the key.
3980 	switch (when)
3981 	{
3982 	    case '*': try_match = (*look == '*'); break;
3983 	    case '!': try_match = (*look == '!'); break;
3984 	     default: try_match = (*look != '*'); break;
3985 	}
3986 	if (*look == '*' || *look == '!')
3987 	    ++look;
3988 
3989 	// If there is a '0', only accept a match if the line is empty.
3990 	// But may still match when typing last char of a word.
3991 	if (*look == '0')
3992 	{
3993 	    try_match_word = try_match;
3994 	    if (!line_is_empty)
3995 		try_match = FALSE;
3996 	    ++look;
3997 	}
3998 	else
3999 	    try_match_word = FALSE;
4000 
4001 	// does it look like a control character?
4002 	if (*look == '^'
4003 #ifdef EBCDIC
4004 		&& (Ctrl_chr(look[1]) != 0)
4005 #else
4006 		&& look[1] >= '?' && look[1] <= '_'
4007 #endif
4008 		)
4009 	{
4010 	    if (try_match && keytyped == Ctrl_chr(look[1]))
4011 		return TRUE;
4012 	    look += 2;
4013 	}
4014 	// 'o' means "o" command, open forward.
4015 	// 'O' means "O" command, open backward.
4016 	else if (*look == 'o')
4017 	{
4018 	    if (try_match && keytyped == KEY_OPEN_FORW)
4019 		return TRUE;
4020 	    ++look;
4021 	}
4022 	else if (*look == 'O')
4023 	{
4024 	    if (try_match && keytyped == KEY_OPEN_BACK)
4025 		return TRUE;
4026 	    ++look;
4027 	}
4028 
4029 	// 'e' means to check for "else" at start of line and just before the
4030 	// cursor.
4031 	else if (*look == 'e')
4032 	{
4033 	    if (try_match && keytyped == 'e' && curwin->w_cursor.col >= 4)
4034 	    {
4035 		p = ml_get_curline();
4036 		if (skipwhite(p) == p + curwin->w_cursor.col - 4 &&
4037 			STRNCMP(p + curwin->w_cursor.col - 4, "else", 4) == 0)
4038 		    return TRUE;
4039 	    }
4040 	    ++look;
4041 	}
4042 
4043 	// ':' only causes an indent if it is at the end of a label or case
4044 	// statement, or when it was before typing the ':' (to fix
4045 	// class::method for C++).
4046 	else if (*look == ':')
4047 	{
4048 	    if (try_match && keytyped == ':')
4049 	    {
4050 		p = ml_get_curline();
4051 		if (cin_iscase(p, FALSE) || cin_isscopedecl(p) || cin_islabel())
4052 		    return TRUE;
4053 		// Need to get the line again after cin_islabel().
4054 		p = ml_get_curline();
4055 		if (curwin->w_cursor.col > 2
4056 			&& p[curwin->w_cursor.col - 1] == ':'
4057 			&& p[curwin->w_cursor.col - 2] == ':')
4058 		{
4059 		    p[curwin->w_cursor.col - 1] = ' ';
4060 		    i = (cin_iscase(p, FALSE) || cin_isscopedecl(p)
4061 							    || cin_islabel());
4062 		    p = ml_get_curline();
4063 		    p[curwin->w_cursor.col - 1] = ':';
4064 		    if (i)
4065 			return TRUE;
4066 		}
4067 	    }
4068 	    ++look;
4069 	}
4070 
4071 
4072 	// Is it a key in <>, maybe?
4073 	else if (*look == '<')
4074 	{
4075 	    if (try_match)
4076 	    {
4077 		// make up some named keys <o>, <O>, <e>, <0>, <>>, <<>, <*>,
4078 		// <:> and <!> so that people can re-indent on o, O, e, 0, <,
4079 		// >, *, : and ! keys if they really really want to.
4080 		if (vim_strchr((char_u *)"<>!*oOe0:", look[1]) != NULL
4081 						       && keytyped == look[1])
4082 		    return TRUE;
4083 
4084 		if (keytyped == get_special_key_code(look + 1))
4085 		    return TRUE;
4086 	    }
4087 	    while (*look && *look != '>')
4088 		look++;
4089 	    while (*look == '>')
4090 		look++;
4091 	}
4092 
4093 	// Is it a word: "=word"?
4094 	else if (*look == '=' && look[1] != ',' && look[1] != NUL)
4095 	{
4096 	    ++look;
4097 	    if (*look == '~')
4098 	    {
4099 		icase = TRUE;
4100 		++look;
4101 	    }
4102 	    else
4103 		icase = FALSE;
4104 	    p = vim_strchr(look, ',');
4105 	    if (p == NULL)
4106 		p = look + STRLEN(look);
4107 	    if ((try_match || try_match_word)
4108 		    && curwin->w_cursor.col >= (colnr_T)(p - look))
4109 	    {
4110 		int		match = FALSE;
4111 
4112 #ifdef FEAT_INS_EXPAND
4113 		if (keytyped == KEY_COMPLETE)
4114 		{
4115 		    char_u	*s;
4116 
4117 		    // Just completed a word, check if it starts with "look".
4118 		    // search back for the start of a word.
4119 		    line = ml_get_curline();
4120 		    if (has_mbyte)
4121 		    {
4122 			char_u	*n;
4123 
4124 			for (s = line + curwin->w_cursor.col; s > line; s = n)
4125 			{
4126 			    n = mb_prevptr(line, s);
4127 			    if (!vim_iswordp(n))
4128 				break;
4129 			}
4130 		    }
4131 		    else
4132 			for (s = line + curwin->w_cursor.col; s > line; --s)
4133 			    if (!vim_iswordc(s[-1]))
4134 				break;
4135 		    if (s + (p - look) <= line + curwin->w_cursor.col
4136 			    && (icase
4137 				? MB_STRNICMP(s, look, p - look)
4138 				: STRNCMP(s, look, p - look)) == 0)
4139 			match = TRUE;
4140 		}
4141 		else
4142 #endif
4143 		    // TODO: multi-byte
4144 		    if (keytyped == (int)p[-1] || (icase && keytyped < 256
4145 			 && TOLOWER_LOC(keytyped) == TOLOWER_LOC((int)p[-1])))
4146 		{
4147 		    line = ml_get_cursor();
4148 		    if ((curwin->w_cursor.col == (colnr_T)(p - look)
4149 				|| !vim_iswordc(line[-(p - look) - 1]))
4150 			    && (icase
4151 				? MB_STRNICMP(line - (p - look), look, p - look)
4152 				: STRNCMP(line - (p - look), look, p - look))
4153 									 == 0)
4154 			match = TRUE;
4155 		}
4156 		if (match && try_match_word && !try_match)
4157 		{
4158 		    // "0=word": Check if there are only blanks before the
4159 		    // word.
4160 		    if (getwhitecols_curline() !=
4161 				     (int)(curwin->w_cursor.col - (p - look)))
4162 			match = FALSE;
4163 		}
4164 		if (match)
4165 		    return TRUE;
4166 	    }
4167 	    look = p;
4168 	}
4169 
4170 	// ok, it's a boring generic character.
4171 	else
4172 	{
4173 	    if (try_match && *look == keytyped)
4174 		return TRUE;
4175 	    if (*look != NUL)
4176 		++look;
4177 	}
4178 
4179 	// Skip over ", ".
4180 	look = skip_to_option_part(look);
4181     }
4182     return FALSE;
4183 }
4184 #endif // FEAT_CINDENT
4185 
4186 #if defined(FEAT_LISP) || defined(PROTO)
4187 
4188     static int
4189 lisp_match(char_u *p)
4190 {
4191     char_u	buf[LSIZE];
4192     int		len;
4193     char_u	*word = *curbuf->b_p_lw != NUL ? curbuf->b_p_lw : p_lispwords;
4194 
4195     while (*word != NUL)
4196     {
4197 	(void)copy_option_part(&word, buf, LSIZE, ",");
4198 	len = (int)STRLEN(buf);
4199 	if (STRNCMP(buf, p, len) == 0 && p[len] == ' ')
4200 	    return TRUE;
4201     }
4202     return FALSE;
4203 }
4204 
4205 /*
4206  * When 'p' is present in 'cpoptions, a Vi compatible method is used.
4207  * The incompatible newer method is quite a bit better at indenting
4208  * code in lisp-like languages than the traditional one; it's still
4209  * mostly heuristics however -- Dirk van Deun, [email protected]
4210  *
4211  * TODO:
4212  * Findmatch() should be adapted for lisp, also to make showmatch
4213  * work correctly: now (v5.3) it seems all C/C++ oriented:
4214  * - it does not recognize the #\( and #\) notations as character literals
4215  * - it doesn't know about comments starting with a semicolon
4216  * - it incorrectly interprets '(' as a character literal
4217  * All this messes up get_lisp_indent in some rare cases.
4218  * Update from Sergey Khorev:
4219  * I tried to fix the first two issues.
4220  */
4221     int
4222 get_lisp_indent(void)
4223 {
4224     pos_T	*pos, realpos, paren;
4225     int		amount;
4226     char_u	*that;
4227     colnr_T	col;
4228     colnr_T	firsttry;
4229     int		parencount, quotecount;
4230     int		vi_lisp;
4231 
4232     // Set vi_lisp to use the vi-compatible method
4233     vi_lisp = (vim_strchr(p_cpo, CPO_LISP) != NULL);
4234 
4235     realpos = curwin->w_cursor;
4236     curwin->w_cursor.col = 0;
4237 
4238     if ((pos = findmatch(NULL, '(')) == NULL)
4239 	pos = findmatch(NULL, '[');
4240     else
4241     {
4242 	paren = *pos;
4243 	pos = findmatch(NULL, '[');
4244 	if (pos == NULL || LT_POSP(pos, &paren))
4245 	    pos = &paren;
4246     }
4247     if (pos != NULL)
4248     {
4249 	// Extra trick: Take the indent of the first previous non-white
4250 	// line that is at the same () level.
4251 	amount = -1;
4252 	parencount = 0;
4253 
4254 	while (--curwin->w_cursor.lnum >= pos->lnum)
4255 	{
4256 	    if (linewhite(curwin->w_cursor.lnum))
4257 		continue;
4258 	    for (that = ml_get_curline(); *that != NUL; ++that)
4259 	    {
4260 		if (*that == ';')
4261 		{
4262 		    while (*(that + 1) != NUL)
4263 			++that;
4264 		    continue;
4265 		}
4266 		if (*that == '\\')
4267 		{
4268 		    if (*(that + 1) != NUL)
4269 			++that;
4270 		    continue;
4271 		}
4272 		if (*that == '"' && *(that + 1) != NUL)
4273 		{
4274 		    while (*++that && *that != '"')
4275 		    {
4276 			// skipping escaped characters in the string
4277 			if (*that == '\\')
4278 			{
4279 			    if (*++that == NUL)
4280 				break;
4281 			    if (that[1] == NUL)
4282 			    {
4283 				++that;
4284 				break;
4285 			    }
4286 			}
4287 		    }
4288 		}
4289 		if (*that == '(' || *that == '[')
4290 		    ++parencount;
4291 		else if (*that == ')' || *that == ']')
4292 		    --parencount;
4293 	    }
4294 	    if (parencount == 0)
4295 	    {
4296 		amount = get_indent();
4297 		break;
4298 	    }
4299 	}
4300 
4301 	if (amount == -1)
4302 	{
4303 	    curwin->w_cursor.lnum = pos->lnum;
4304 	    curwin->w_cursor.col = pos->col;
4305 	    col = pos->col;
4306 
4307 	    that = ml_get_curline();
4308 
4309 	    if (vi_lisp && get_indent() == 0)
4310 		amount = 2;
4311 	    else
4312 	    {
4313 		char_u *line = that;
4314 
4315 		amount = 0;
4316 		while (*that && col)
4317 		{
4318 		    amount += lbr_chartabsize_adv(line, &that, (colnr_T)amount);
4319 		    col--;
4320 		}
4321 
4322 		// Some keywords require "body" indenting rules (the
4323 		// non-standard-lisp ones are Scheme special forms):
4324 		//
4325 		// (let ((a 1))    instead    (let ((a 1))
4326 		//   (...))	      of	   (...))
4327 
4328 		if (!vi_lisp && (*that == '(' || *that == '[')
4329 						      && lisp_match(that + 1))
4330 		    amount += 2;
4331 		else
4332 		{
4333 		    that++;
4334 		    amount++;
4335 		    firsttry = amount;
4336 
4337 		    while (VIM_ISWHITE(*that))
4338 		    {
4339 			amount += lbr_chartabsize(line, that, (colnr_T)amount);
4340 			++that;
4341 		    }
4342 
4343 		    if (*that && *that != ';') // not a comment line
4344 		    {
4345 			// test *that != '(' to accommodate first let/do
4346 			// argument if it is more than one line
4347 			if (!vi_lisp && *that != '(' && *that != '[')
4348 			    firsttry++;
4349 
4350 			parencount = 0;
4351 			quotecount = 0;
4352 
4353 			if (vi_lisp
4354 				|| (*that != '"'
4355 				    && *that != '\''
4356 				    && *that != '#'
4357 				    && (*that < '0' || *that > '9')))
4358 			{
4359 			    while (*that
4360 				    && (!VIM_ISWHITE(*that)
4361 					|| quotecount
4362 					|| parencount)
4363 				    && (!((*that == '(' || *that == '[')
4364 					    && !quotecount
4365 					    && !parencount
4366 					    && vi_lisp)))
4367 			    {
4368 				if (*that == '"')
4369 				    quotecount = !quotecount;
4370 				if ((*that == '(' || *that == '[')
4371 							       && !quotecount)
4372 				    ++parencount;
4373 				if ((*that == ')' || *that == ']')
4374 							       && !quotecount)
4375 				    --parencount;
4376 				if (*that == '\\' && *(that+1) != NUL)
4377 				    amount += lbr_chartabsize_adv(
4378 						line, &that, (colnr_T)amount);
4379 				amount += lbr_chartabsize_adv(
4380 						line, &that, (colnr_T)amount);
4381 			    }
4382 			}
4383 			while (VIM_ISWHITE(*that))
4384 			{
4385 			    amount += lbr_chartabsize(
4386 						 line, that, (colnr_T)amount);
4387 			    that++;
4388 			}
4389 			if (!*that || *that == ';')
4390 			    amount = firsttry;
4391 		    }
4392 		}
4393 	    }
4394 	}
4395     }
4396     else
4397 	amount = 0;	// no matching '(' or '[' found, use zero indent
4398 
4399     curwin->w_cursor = realpos;
4400 
4401     return amount;
4402 }
4403 #endif // FEAT_LISP
4404 
4405 #if defined(FEAT_CINDENT) || defined(PROTO)
4406 /*
4407  * Do C or expression indenting on the current line.
4408  */
4409     void
4410 do_c_expr_indent(void)
4411 {
4412 # ifdef FEAT_EVAL
4413     if (*curbuf->b_p_inde != NUL)
4414 	fixthisline(get_expr_indent);
4415     else
4416 # endif
4417 	fixthisline(get_c_indent);
4418 }
4419 #endif
4420 
4421 #if defined(FEAT_LISP) || defined(FEAT_CINDENT) || defined(PROTO)
4422 /*
4423  * Re-indent the current line, based on the current contents of it and the
4424  * surrounding lines. Fixing the cursor position seems really easy -- I'm very
4425  * confused what all the part that handles Control-T is doing that I'm not.
4426  * "get_the_indent" should be get_c_indent, get_expr_indent or get_lisp_indent.
4427  */
4428 
4429     void
4430 fixthisline(int (*get_the_indent)(void))
4431 {
4432     int amount = get_the_indent();
4433 
4434     if (amount >= 0)
4435     {
4436 	change_indent(INDENT_SET, amount, FALSE, 0, TRUE);
4437 	if (linewhite(curwin->w_cursor.lnum))
4438 	    did_ai = TRUE;	// delete the indent if the line stays empty
4439     }
4440 }
4441 
4442     void
4443 fix_indent(void)
4444 {
4445     if (p_paste)
4446 	return;
4447 # ifdef FEAT_LISP
4448     if (curbuf->b_p_lisp && curbuf->b_p_ai)
4449 	fixthisline(get_lisp_indent);
4450 # endif
4451 # if defined(FEAT_LISP) && defined(FEAT_CINDENT)
4452     else
4453 # endif
4454 # ifdef FEAT_CINDENT
4455 	if (cindent_on())
4456 	    do_c_expr_indent();
4457 # endif
4458 }
4459 
4460 #endif
4461