[BACK]Return to misccmds.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / vim

Annotation of src/usr.bin/vim/misccmds.c, Revision 1.1.1.1

1.1       downsj      1: /* $OpenBSD$   */
                      2: /* vi:set ts=4 sw=4:
                      3:  *
                      4:  * VIM - Vi IMproved       by Bram Moolenaar
                      5:  *
                      6:  * Do ":help uganda"  in Vim to read copying and usage conditions.
                      7:  * Do ":help credits" in Vim to see a list of people who contributed.
                      8:  */
                      9:
                     10: /*
                     11:  * misccmds.c: functions that didn't seem to fit elsewhere
                     12:  */
                     13:
                     14: #include "vim.h"
                     15: #include "globals.h"
                     16: #include "proto.h"
                     17: #include "option.h"
                     18: #ifdef HAVE_FCNTL_H
                     19: # include <fcntl.h>            /* for chdir() */
                     20: #endif
                     21:
                     22: static int get_indent_str __ARGS((char_u *ptr));
                     23: static void check_status __ARGS((BUF *));
                     24:
                     25: /*
                     26:  * count the size of the indent in the current line
                     27:  */
                     28:    int
                     29: get_indent()
                     30: {
                     31:    return get_indent_str(ml_get_curline());
                     32: }
                     33:
                     34: /*
                     35:  * count the size of the indent in line "lnum"
                     36:  */
                     37:    int
                     38: get_indent_lnum(lnum)
                     39:    linenr_t    lnum;
                     40: {
                     41:    return get_indent_str(ml_get(lnum));
                     42: }
                     43:
                     44: /*
                     45:  * count the size of the indent in line "ptr"
                     46:  */
                     47:    static int
                     48: get_indent_str(ptr)
                     49:    register char_u *ptr;
                     50: {
                     51:    register int count = 0;
                     52:
                     53:    for ( ; *ptr; ++ptr)
                     54:    {
                     55:        if (*ptr == TAB)    /* count a tab for what it is worth */
                     56:            count += (int)curbuf->b_p_ts - (count % (int)curbuf->b_p_ts);
                     57:        else if (*ptr == ' ')
                     58:            ++count;            /* count a space for one */
                     59:        else
                     60:            break;
                     61:    }
                     62:    return (count);
                     63: }
                     64:
                     65: /*
                     66:  * set the indent of the current line
                     67:  * leaves the cursor on the first non-blank in the line
                     68:  */
                     69:    void
                     70: set_indent(size, del_first)
                     71:    register int    size;
                     72:    int             del_first;
                     73: {
                     74:    int             oldstate = State;
                     75:    register int    c;
                     76:
                     77:    State = INSERT;                 /* don't want REPLACE for State */
                     78:    curwin->w_cursor.col = 0;
                     79:    if (del_first)                  /* delete old indent */
                     80:    {
                     81:                                    /* vim_iswhite() is a define! */
                     82:        while ((c = gchar_cursor()), vim_iswhite(c))
                     83:            (void)delchar(FALSE);
                     84:    }
                     85:    if (!curbuf->b_p_et)            /* if 'expandtab' is set, don't use TABs */
                     86:        while (size >= (int)curbuf->b_p_ts)
                     87:        {
                     88:            ins_char(TAB);
                     89:            size -= (int)curbuf->b_p_ts;
                     90:        }
                     91:    while (size)
                     92:    {
                     93:        ins_char(' ');
                     94:        --size;
                     95:    }
                     96:    State = oldstate;
                     97: }
                     98:
                     99: #if defined(CINDENT) || defined(SMARTINDENT)
                    100:
                    101: static int is_cinword __ARGS((char_u *line));
                    102:
                    103: /*
                    104:  * Return TRUE if the string "line" starts with a word from 'cinwords'.
                    105:  */
                    106:    static int
                    107: is_cinword(line)
                    108:    char_u      *line;
                    109: {
                    110:    char_u  *cinw;
                    111:    char_u  *cinw_buf;
                    112:    int     cinw_len;
                    113:    int     retval = FALSE;
                    114:    int     len;
                    115:
                    116:    cinw_len = STRLEN(curbuf->b_p_cinw) + 1;
                    117:    cinw_buf = alloc((unsigned)cinw_len);
                    118:    if (cinw_buf != NULL)
                    119:    {
                    120:        line = skipwhite(line);
                    121:        for (cinw = curbuf->b_p_cinw; *cinw; )
                    122:        {
                    123:            len = copy_option_part(&cinw, cinw_buf, cinw_len, ",");
                    124:            if (STRNCMP(line, cinw_buf, len) == 0 &&
                    125:                       (!iswordchar(line[len]) || !iswordchar(line[len - 1])))
                    126:            {
                    127:                retval = TRUE;
                    128:                break;
                    129:            }
                    130:        }
                    131:        vim_free(cinw_buf);
                    132:    }
                    133:    return retval;
                    134: }
                    135: #endif
                    136:
                    137: /*
                    138:  * Opencmd
                    139:  *
                    140:  * Add a new line below or above the current line.
                    141:  * Caller must take care of undo.
                    142:  *
                    143:  * Return TRUE for success, FALSE for failure
                    144:  */
                    145:
                    146:    int
                    147: Opencmd(dir, redraw, del_spaces)
                    148:    int         dir;            /* FORWARD or BACKWARD */
                    149:    int         redraw;         /* redraw afterwards */
                    150:    int         del_spaces;     /* delete spaces after cursor */
                    151: {
                    152:    char_u  *saved_line;        /* copy of the original line */
                    153:    char_u  *p_extra = NULL;    /* what goes to next line */
                    154:    int     extra_len = 0;      /* length of p_extra string */
                    155:    FPOS    old_cursor;         /* old cursor position */
                    156:    int     newcol = 0;         /* new cursor column */
                    157:    int     newindent = 0;      /* auto-indent of the new line */
                    158:    int     n;
                    159:    int     trunc_line = FALSE; /* truncate current line afterwards */
                    160:    int     retval = FALSE;     /* return value, default is FAIL */
                    161:    int     lead_len;           /* length of comment leader */
                    162:    char_u  *lead_flags;        /* position in 'comments' for comment leader */
                    163:    char_u  *leader = NULL;     /* copy of comment leader */
                    164:    char_u  *allocated = NULL;  /* allocated memory */
                    165:    char_u  *p;
                    166:    int     saved_char = NUL;   /* init for GCC */
                    167:    FPOS    *pos;
                    168:    int     old_plines = 0;     /* init for GCC */
                    169:    int     new_plines = 0;     /* init for GCC */
                    170: #ifdef SMARTINDENT
                    171:    int     no_si = FALSE;      /* reset did_si afterwards */
                    172:    int     first_char = NUL;   /* init for GCC */
                    173: #endif
                    174:
                    175:    /*
                    176:     * make a copy of the current line so we can mess with it
                    177:     */
                    178:    saved_line = strsave(ml_get_curline());
                    179:    if (saved_line == NULL)         /* out of memory! */
                    180:        return FALSE;
                    181:
                    182:    if (State == INSERT || State == REPLACE)
                    183:    {
                    184:        p_extra = saved_line + curwin->w_cursor.col;
                    185: #ifdef SMARTINDENT
                    186:        if (curbuf->b_p_si)         /* need first char after new line break */
                    187:        {
                    188:            p = skipwhite(p_extra);
                    189:            first_char = *p;
                    190:        }
                    191: #endif
                    192:        extra_len = STRLEN(p_extra);
                    193:        saved_char = *p_extra;
                    194:        *p_extra = NUL;
                    195:    }
                    196:
                    197:    u_clearline();              /* cannot do "U" command when adding lines */
                    198: #ifdef SMARTINDENT
                    199:    did_si = FALSE;
                    200: #endif
                    201:
                    202:    /*
                    203:     * If 'autoindent' and/or 'smartindent' is set, try to figure out what
                    204:     * indent to use for the new line.
                    205:     */
                    206:    if (curbuf->b_p_ai
                    207: #ifdef SMARTINDENT
                    208:                        || curbuf->b_p_si
                    209: #endif
                    210:                                            )
                    211:    {
                    212:        /*
                    213:         * count white space on current line
                    214:         */
                    215:        newindent = get_indent();
                    216:        if (newindent == 0)
                    217:            newindent = old_indent;     /* for ^^D command in insert mode */
                    218:        old_indent = 0;
                    219:
                    220:        /*
                    221:         * If we just did an auto-indent, then we didn't type anything on
                    222:         * the prior line, and it should be truncated.
                    223:         */
                    224:        if (dir == FORWARD && did_ai)
                    225:            trunc_line = TRUE;
                    226:
                    227: #ifdef SMARTINDENT
                    228:        /*
                    229:         * Do smart indenting.
                    230:         * In insert/replace mode (only when dir == FORWARD)
                    231:         * we may move some text to the next line. If it starts with '{'
                    232:         * don't add an indent. Fixes inserting a NL before '{' in line
                    233:         *      "if (condition) {"
                    234:         */
                    235:        else if (curbuf->b_p_si && *saved_line != NUL &&
                    236:                                       (p_extra == NULL || first_char != '{'))
                    237:        {
                    238:            char_u  *ptr;
                    239:            char_u  last_char;
                    240:
                    241:            old_cursor = curwin->w_cursor;
                    242:            ptr = saved_line;
                    243:            lead_len = get_leader_len(ptr, NULL);
                    244:            if (dir == FORWARD)
                    245:            {
                    246:                /*
                    247:                 * Skip preprocessor directives, unless they are
                    248:                 * recognised as comments.
                    249:                 */
                    250:                if (lead_len == 0 && ptr[0] == '#')
                    251:                {
                    252:                    while (ptr[0] == '#' && curwin->w_cursor.lnum > 1)
                    253:                        ptr = ml_get(--curwin->w_cursor.lnum);
                    254:                    newindent = get_indent();
                    255:                }
                    256:                lead_len = get_leader_len(ptr, NULL);
                    257:                if (lead_len > 0)
                    258:                {
                    259:                    /*
                    260:                     * This case gets the following right:
                    261:                     *      \*
                    262:                     *       * A comment (read "\" as "/").
                    263:                     *       *\
                    264:                     * #define IN_THE_WAY
                    265:                     *      This should line up here;
                    266:                     */
                    267:                    p = skipwhite(ptr);
                    268:                    if (p[0] == '/' && p[1] == '*')
                    269:                        p++;
                    270:                    if (p[0] == '*')
                    271:                    {
                    272:                        for (p++; *p; p++)
                    273:                        {
                    274:                            if (p[0] == '/' && p[-1] == '*')
                    275:                            {
                    276:                                /*
                    277:                                 * End of C comment, indent should line up
                    278:                                 * with the line containing the start of
                    279:                                 * the comment
                    280:                                 */
                    281:                                curwin->w_cursor.col = p - ptr;
                    282:                                if ((pos = findmatch(NUL)) != NULL)
                    283:                                {
                    284:                                    curwin->w_cursor.lnum = pos->lnum;
                    285:                                    newindent = get_indent();
                    286:                                }
                    287:                            }
                    288:                        }
                    289:                    }
                    290:                }
                    291:                else    /* Not a comment line */
                    292:                {
                    293:                    /* Find last non-blank in line */
                    294:                    p = ptr + STRLEN(ptr) - 1;
                    295:                    while (p > ptr && vim_iswhite(*p))
                    296:                        --p;
                    297:                    last_char = *p;
                    298:
                    299:                    /*
                    300:                     * find the character just before the '{' or ';'
                    301:                     */
                    302:                    if (last_char == '{' || last_char == ';')
                    303:                    {
                    304:                        if (p > ptr)
                    305:                            --p;
                    306:                        while (p > ptr && vim_iswhite(*p))
                    307:                            --p;
                    308:                    }
                    309:                    /*
                    310:                     * Try to catch lines that are split over multiple
                    311:                     * lines.  eg:
                    312:                     *      if (condition &&
                    313:                     *                  condition) {
                    314:                     *          Should line up here!
                    315:                     *      }
                    316:                     */
                    317:                    if (*p == ')')
                    318:                    {
                    319:                        curwin->w_cursor.col = p - ptr;
                    320:                        if ((pos = findmatch('(')) != NULL)
                    321:                        {
                    322:                            curwin->w_cursor.lnum = pos->lnum;
                    323:                            newindent = get_indent();
                    324:                            ptr = ml_get_curline();
                    325:                        }
                    326:                    }
                    327:                    /*
                    328:                     * If last character is '{' do indent, without
                    329:                     * checking for "if" and the like.
                    330:                     */
                    331:                    if (last_char == '{')
                    332:                    {
                    333:                        did_si = TRUE;  /* do indent */
                    334:                        no_si = TRUE;   /* don't delete it when '{' typed */
                    335:                    }
                    336:                    /*
                    337:                     * Look for "if" and the like, use 'cinwords'.
                    338:                     * Don't do this if the previous line ended in ';' or
                    339:                     * '}'.
                    340:                     */
                    341:                    else if (last_char != ';' && last_char != '}' &&
                    342:                                                            is_cinword(ptr))
                    343:                        did_si = TRUE;
                    344:                }
                    345:            }
                    346:            else /* dir == BACKWARD */
                    347:            {
                    348:                /*
                    349:                 * Skip preprocessor directives, unless they are
                    350:                 * recognised as comments.
                    351:                 */
                    352:                if (lead_len == 0 && ptr[0] == '#')
                    353:                {
                    354:                    int was_backslashed = FALSE;
                    355:
                    356:                    while ((ptr[0] == '#' || was_backslashed) &&
                    357:                         curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
                    358:                    {
                    359:                        if (*ptr && ptr[STRLEN(ptr) - 1] == '\\')
                    360:                            was_backslashed = TRUE;
                    361:                        else
                    362:                            was_backslashed = FALSE;
                    363:                        ptr = ml_get(++curwin->w_cursor.lnum);
                    364:                    }
                    365:                    if (was_backslashed)
                    366:                        newindent = 0;      /* Got to end of file */
                    367:                    else
                    368:                        newindent = get_indent();
                    369:                }
                    370:                p = skipwhite(ptr);
                    371:                if (*p == '}')      /* if line starts with '}': do indent */
                    372:                    did_si = TRUE;
                    373:                else                /* can delete indent when '{' typed */
                    374:                    can_si_back = TRUE;
                    375:            }
                    376:            curwin->w_cursor = old_cursor;
                    377:        }
                    378:        if (curbuf->b_p_si)
                    379:            can_si = TRUE;
                    380: #endif /* SMARTINDENT */
                    381:
                    382:        did_ai = TRUE;
                    383:    }
                    384:
                    385:    /*
                    386:     * Find out if the current line starts with a comment leader.
                    387:     * This may then be inserted in front of the new line.
                    388:     */
                    389:    lead_len = get_leader_len(saved_line, &lead_flags);
                    390:    if (lead_len > 0)
                    391:    {
                    392:        char_u  *lead_repl = NULL;          /* replaces comment leader */
                    393:        int     lead_repl_len = 0;          /* length of *lead_repl */
                    394:        char_u  lead_middle[COM_MAX_LEN];   /* middle-comment string */
                    395:        char_u  lead_end[COM_MAX_LEN];      /* end-comment string */
                    396:        char_u  *comment_end = NULL;        /* where lead_end has been found */
                    397:        int     extra_space = FALSE;        /* append extra space */
                    398:        int     current_flag;
                    399:
                    400:        /*
                    401:         * If the comment leader has the start, middle or end flag, it may not
                    402:         * be used or may be replaced with the middle leader.
                    403:         */
                    404:        for (p = lead_flags; *p && *p != ':'; ++p)
                    405:        {
                    406:            if (*p == COM_START || *p == COM_MIDDLE)
                    407:            {
                    408:                current_flag = *p;
                    409:                if (*p == COM_START)
                    410:                {
                    411:                    /*
                    412:                     * Doing "O" on a start of comment does not insert leader.
                    413:                     */
                    414:                    if (dir == BACKWARD)
                    415:                    {
                    416:                        lead_len = 0;
                    417:                        break;
                    418:                    }
                    419:
                    420:                   /* find start of middle part */
                    421:                    (void)copy_option_part(&p, lead_middle, COM_MAX_LEN, ",");
                    422:                }
                    423:
                    424:                /*
                    425:                 * Isolate the strings of the middle and end leader.
                    426:                 */
                    427:                while (*p && p[-1] != ':')      /* find end of middle flags */
                    428:                    ++p;
                    429:                (void)copy_option_part(&p, lead_middle, COM_MAX_LEN, ",");
                    430:                while (*p && p[-1] != ':')      /* find end of end flags */
                    431:                    ++p;
                    432:                (void)copy_option_part(&p, lead_end, COM_MAX_LEN, ",");
                    433:
                    434:                /*
                    435:                 * If the end of the comment is in the same line, don't use
                    436:                 * the comment leader.
                    437:                 */
                    438:                if (dir == FORWARD)
                    439:                {
                    440:                    n = STRLEN(lead_end);
                    441:                    for (p = saved_line + lead_len; *p; ++p)
                    442:                        if (STRNCMP(p, lead_end, n) == 0)
                    443:                        {
                    444:                            comment_end = p;
                    445:                            lead_len = 0;
                    446:                            break;
                    447:                        }
                    448:                }
                    449:
                    450:                /*
                    451:                 * Doing "o" on a start of comment inserts the middle leader.
                    452:                 */
                    453:                if (lead_len)
                    454:                {
                    455:                    if (current_flag == COM_START)
                    456:                    {
                    457:                        lead_repl = lead_middle;
                    458:                        lead_repl_len = STRLEN(lead_middle);
                    459:                    }
                    460:
                    461:                    /*
                    462:                     * If we have hit RETURN immediately after the start
                    463:                     * comment leader, then put a space after the middle
                    464:                     * comment leader on the next line.
                    465:                     */
                    466:                    if (!vim_iswhite(saved_line[lead_len - 1]) &&
                    467:                            ((p_extra != NULL &&
                    468:                                     (int)curwin->w_cursor.col == lead_len) ||
                    469:                             (p_extra == NULL && saved_line[lead_len] == NUL)))
                    470:                        extra_space = TRUE;
                    471:                }
                    472:                break;
                    473:            }
                    474:            if (*p == COM_END)
                    475:            {
                    476:                /*
                    477:                 * Doing "o" on the end of a comment does not insert leader.
                    478:                 * Remember where the end is, might want to use it to find the
                    479:                 * start (for C-comments).
                    480:                 */
                    481:                if (dir == FORWARD)
                    482:                {
                    483:                    comment_end = skipwhite(saved_line);
                    484:                    lead_len = 0;
                    485:                    break;
                    486:                }
                    487:
                    488:                /*
                    489:                 * Doing "O" on the end of a comment inserts the middle leader.
                    490:                 * Find the string for the middle leader, searching backwards.
                    491:                 */
                    492:                while (p > curbuf->b_p_com && *p != ',')
                    493:                    --p;
                    494:                for (lead_repl = p; lead_repl > curbuf->b_p_com &&
                    495:                                            lead_repl[-1] != ':'; --lead_repl)
                    496:                    ;
                    497:                lead_repl_len = p - lead_repl;
                    498:                break;
                    499:            }
                    500:            if (*p == COM_FIRST)
                    501:            {
                    502:                /*
                    503:                 * Comment leader for first line only:  Don't repeat leader
                    504:                 * when using "O", blank out leader when using "o".
                    505:                 */
                    506:                if (dir == BACKWARD)
                    507:                    lead_len = 0;
                    508:                else
                    509:                {
                    510:                    lead_repl = (char_u *)"";
                    511:                    lead_repl_len = 0;
                    512:                }
                    513:                break;
                    514:            }
                    515:        }
                    516:        if (lead_len)
                    517:        {
                    518:            /* allocate buffer (may concatenate p_exta later) */
                    519:            leader = alloc(lead_len + lead_repl_len + extra_space +
                    520:                                                              extra_len + 1);
                    521:            allocated = leader;             /* remember to free it later */
                    522:
                    523:            if (leader == NULL)
                    524:                lead_len = 0;
                    525:            else
                    526:            {
                    527:                STRNCPY(leader, saved_line, lead_len);
                    528:                leader[lead_len] = NUL;
                    529:
                    530:                /*
                    531:                 * Replace leader with lead_repl, right or left adjusted
                    532:                 */
                    533:                if (lead_repl != NULL)
                    534:                {
                    535:                    for (p = lead_flags; *p && *p != ':'; ++p)
                    536:                        if (*p == COM_RIGHT || *p == COM_LEFT)
                    537:                            break;
                    538:                    if (*p == COM_RIGHT)    /* right adjusted leader */
                    539:                    {
                    540:                        /* find last non-white in the leader to line up with */
                    541:                        for (p = leader + lead_len - 1; p > leader &&
                    542:                                                         vim_iswhite(*p); --p)
                    543:                            ;
                    544:
                    545:                        ++p;
                    546:                        if (p < leader + lead_repl_len)
                    547:                            p = leader;
                    548:                        else
                    549:                            p -= lead_repl_len;
                    550:                        vim_memmove(p, lead_repl, (size_t)lead_repl_len);
                    551:                        if (p + lead_repl_len > leader + lead_len)
                    552:                            p[lead_repl_len] = NUL;
                    553:
                    554:                        /* blank-out any other chars from the old leader. */
                    555:                        while (--p >= leader)
                    556:                            if (!vim_iswhite(*p))
                    557:                                *p = ' ';
                    558:                    }
                    559:                    else                    /* left adjusted leader */
                    560:                    {
                    561:                        p = skipwhite(leader);
                    562:                        vim_memmove(p, lead_repl, (size_t)lead_repl_len);
                    563:
                    564:                        /* blank-out any other chars from the old leader. */
                    565:                        for (p += lead_repl_len; p < leader + lead_len; ++p)
                    566:                            if (!vim_iswhite(*p))
                    567:                                *p = ' ';
                    568:                        *p = NUL;
                    569:                    }
                    570:
                    571:                    /* Recompute the indent, it may have changed. */
                    572:                    if (curbuf->b_p_ai
                    573: #ifdef SMARTINDENT
                    574:                                        || curbuf->b_p_si
                    575: #endif
                    576:                                                           )
                    577:                        newindent = get_indent_str(leader);
                    578:                }
                    579:
                    580:                lead_len = STRLEN(leader);
                    581:                if (extra_space)
                    582:                {
                    583:                    leader[lead_len++] = ' ';
                    584:                    leader[lead_len] = NUL;
                    585:                }
                    586:
                    587:                newcol = lead_len;
                    588:
                    589:                /*
                    590:                 * if a new indent will be set below, remove the indent that
                    591:                 * is in the comment leader
                    592:                 */
                    593:                if (newindent
                    594: #ifdef SMARTINDENT
                    595:                                || did_si
                    596: #endif
                    597:                                           )
                    598:                {
                    599:                    while (lead_len && vim_iswhite(*leader))
                    600:                    {
                    601:                        --lead_len;
                    602:                        --newcol;
                    603:                        ++leader;
                    604:                    }
                    605:                }
                    606:
                    607:            }
                    608: #ifdef SMARTINDENT
                    609:            did_si = can_si = FALSE;
                    610: #endif
                    611:        }
                    612:        else if (comment_end != NULL)
                    613:        {
                    614:            /*
                    615:             * We have finished a comment, so we don't use the leader.
                    616:             * If this was a C-comment and 'ai' or 'si' is set do a normal
                    617:             * indent to align with the line containing the start of the
                    618:             * comment.
                    619:             */
                    620:            if (comment_end[0] == '*' && comment_end[1] == '/' &&
                    621:                        (curbuf->b_p_ai
                    622: #ifdef SMARTINDENT
                    623:                                        || curbuf->b_p_si
                    624: #endif
                    625:                                                           ))
                    626:            {
                    627:                old_cursor = curwin->w_cursor;
                    628:                curwin->w_cursor.col = comment_end - saved_line;
                    629:                if ((pos = findmatch(NUL)) != NULL)
                    630:                {
                    631:                    curwin->w_cursor.lnum = pos->lnum;
                    632:                    newindent = get_indent();
                    633:                }
                    634:                curwin->w_cursor = old_cursor;
                    635:            }
                    636:        }
                    637:    }
                    638:
                    639:    /* (State == INSERT || State == REPLACE), only when dir == FORWARD */
                    640:    if (p_extra != NULL)
                    641:    {
                    642:        *p_extra = saved_char;          /* restore char that NUL replaced */
                    643:
                    644:        /*
                    645:         * When 'ai' set or "del_spaces" TRUE, skip to the first non-blank.
                    646:         *
                    647:         * When in REPLACE mode, put the deleted blanks on the replace
                    648:         * stack, followed by a NUL, so they can be put back when
                    649:         * a BS is entered.
                    650:         */
                    651:        if (State == REPLACE)
                    652:            replace_push(NUL);      /* end of extra blanks */
                    653:        if (curbuf->b_p_ai || del_spaces)
                    654:        {
                    655:            while (*p_extra == ' ' || *p_extra == '\t')
                    656:            {
                    657:                if (State == REPLACE)
                    658:                    replace_push(*p_extra);
                    659:                ++p_extra;
                    660:            }
                    661:        }
                    662:        if (*p_extra != NUL)
                    663:            did_ai = FALSE;         /* append some text, don't trucate now */
                    664:    }
                    665:
                    666:    if (p_extra == NULL)
                    667:        p_extra = (char_u *)"";             /* append empty line */
                    668:
                    669:    /* concatenate leader and p_extra, if there is a leader */
                    670:    if (lead_len)
                    671:    {
                    672:        STRCAT(leader, p_extra);
                    673:        p_extra = leader;
                    674:    }
                    675:
                    676:    old_cursor = curwin->w_cursor;
                    677:    if (dir == BACKWARD)
                    678:        --curwin->w_cursor.lnum;
                    679:    if (ml_append(curwin->w_cursor.lnum, p_extra, (colnr_t)0, FALSE) == FAIL)
                    680:        goto theend;
                    681:    mark_adjust(curwin->w_cursor.lnum + 1, MAXLNUM, 1L, 0L);
                    682:    if (newindent
                    683: #ifdef SMARTINDENT
                    684:                    || did_si
                    685: #endif
                    686:                                )
                    687:    {
                    688:        ++curwin->w_cursor.lnum;
                    689: #ifdef SMARTINDENT
                    690:        if (did_si)
                    691:        {
                    692:            if (p_sr)
                    693:                newindent -= newindent % (int)curbuf->b_p_sw;
                    694:            newindent += (int)curbuf->b_p_sw;
                    695:        }
                    696: #endif
                    697:        set_indent(newindent, FALSE);
                    698:        /*
                    699:         * In REPLACE mode the new indent must be put on
                    700:         * the replace stack for when it is deleted with BS
                    701:         */
                    702:        if (State == REPLACE)
                    703:            for (n = 0; n < (int)curwin->w_cursor.col; ++n)
                    704:                replace_push(NUL);
                    705:        newcol += curwin->w_cursor.col;
                    706: #ifdef SMARTINDENT
                    707:        if (no_si)
                    708:            did_si = FALSE;
                    709: #endif
                    710:    }
                    711:    /*
                    712:     * In REPLACE mode the extra leader must be put on the replace stack for
                    713:     * when it is deleted with BS.
                    714:     */
                    715:    if (State == REPLACE)
                    716:        while (lead_len-- > 0)
                    717:            replace_push(NUL);
                    718:
                    719:    curwin->w_cursor = old_cursor;
                    720:
                    721:    if (dir == FORWARD)
                    722:    {
                    723:        if (redraw)     /* want to know the old number of screen lines */
                    724:        {
                    725:            old_plines = plines(curwin->w_cursor.lnum);
                    726:            new_plines = old_plines;
                    727:        }
                    728:        if (trunc_line || State == INSERT || State == REPLACE)
                    729:        {
                    730:            if (trunc_line)
                    731:            {
                    732:                    /* find start of trailing white space */
                    733:                for (n = STRLEN(saved_line); n > 0 &&
                    734:                                          vim_iswhite(saved_line[n - 1]); --n)
                    735:                    ;
                    736:                saved_line[n] = NUL;
                    737:            }
                    738:            else                    /* truncate current line at cursor */
                    739:                *(saved_line + curwin->w_cursor.col) = NUL;
                    740:            ml_replace(curwin->w_cursor.lnum, saved_line, FALSE);
                    741:            saved_line = NULL;
                    742:            new_plines = plines(curwin->w_cursor.lnum);
                    743:        }
                    744:
                    745:        /*
                    746:         * Get the cursor to the start of the line, so that 'curwin->w_row'
                    747:         * gets set to the right physical line number for the stuff that
                    748:         * follows...
                    749:         */
                    750:        curwin->w_cursor.col = 0;
                    751:
                    752:        if (redraw)
                    753:        {
                    754:            /*
                    755:             * Call cursupdate() to compute w_row.
                    756:             * But we don't want it to update the srceen.
                    757:             */
                    758:            ++RedrawingDisabled;
                    759:            cursupdate();
                    760:            --RedrawingDisabled;
                    761:
                    762:            /*
                    763:             * If we're doing an open on the last logical line, then go ahead
                    764:             * and scroll the screen up. Otherwise, just insert a blank line
                    765:             * at the right place if the number of screen lines changed.
                    766:             * We use calls to plines() in case the cursor is resting on a
                    767:             * long line, we want to know the row below the line.
                    768:             */
                    769:            n = curwin->w_row + new_plines;
                    770:            if (n == curwin->w_winpos + curwin->w_height)
                    771:                scrollup(1L);
                    772:            else
                    773:                win_ins_lines(curwin, n,
                    774:                  plines(curwin->w_cursor.lnum + 1) + new_plines - old_plines,
                    775:                                                                  TRUE, TRUE);
                    776:        }
                    777:
                    778:        /*
                    779:         * Put the cursor on the new line.  Careful: the cursupdate() and
                    780:         * scrollup() above may have moved w_cursor, we must use old_cursor.
                    781:         */
                    782:        curwin->w_cursor.lnum = old_cursor.lnum + 1;
                    783:    }
                    784:    else if (redraw)            /* insert physical line above current line */
                    785:        win_ins_lines(curwin, curwin->w_row, 1, TRUE, TRUE);
                    786:
                    787:    curwin->w_cursor.col = newcol;
                    788:
                    789: #ifdef LISPINDENT
                    790:    /*
                    791:     * May do lisp indenting.
                    792:     */
                    793:    if (leader == NULL && curbuf->b_p_lisp && curbuf->b_p_ai)
                    794:        fixthisline(get_lisp_indent);
                    795: #endif
                    796: #ifdef CINDENT
                    797:    /*
                    798:     * May do indenting after opening a new line.
                    799:     */
                    800:    if (leader == NULL && curbuf->b_p_cin &&
                    801:            in_cinkeys(dir == FORWARD ? KEY_OPEN_FORW :
                    802:                        KEY_OPEN_BACK, ' ', linewhite(curwin->w_cursor.lnum)))
                    803:        fixthisline(get_c_indent);
                    804: #endif
                    805:
                    806:    if (redraw)
                    807:    {
                    808:        updateScreen(VALID_TO_CURSCHAR);
                    809:        cursupdate();           /* update curwin->w_row */
                    810:    }
                    811:    CHANGED;
                    812:
                    813:    retval = TRUE;              /* success! */
                    814: theend:
                    815:    vim_free(saved_line);
                    816:    vim_free(allocated);
                    817:    return retval;
                    818: }
                    819:
                    820: /*
                    821:  * get_leader_len() returns the length of the prefix of the given string
                    822:  * which introduces a comment.  If this string is not a comment then 0 is
                    823:  * returned.
                    824:  * When "flags" is non-zero, it is set to point to the flags of the recognized
                    825:  * comment leader.
                    826:  */
                    827:    int
                    828: get_leader_len(line, flags)
                    829:    char_u  *line;
                    830:    char_u  **flags;
                    831: {
                    832:    int     i, j;
                    833:    int     got_com = FALSE;
                    834:    int     found_one;
                    835:    char_u  part_buf[COM_MAX_LEN];  /* buffer for one option part */
                    836:    char_u  *string;                /* pointer to comment string */
                    837:    char_u  *list;
                    838:
                    839:    if (!fo_do_comments)            /* don't format comments at all */
                    840:        return 0;
                    841:
                    842:    i = 0;
                    843:    while (vim_iswhite(line[i]))    /* leading white space is ignored */
                    844:        ++i;
                    845:
                    846:    /*
                    847:     * Repeat to match several nested comment strings.
                    848:     */
                    849:    while (line[i])
                    850:    {
                    851:        /*
                    852:         * scan through the 'comments' option for a match
                    853:         */
                    854:        found_one = FALSE;
                    855:        for (list = curbuf->b_p_com; *list; )
                    856:        {
                    857:            /*
                    858:             * Get one option part into part_buf[].  Advance list to next one.
                    859:             * put string at start of string.
                    860:             */
                    861:            if (!got_com && flags != NULL)  /* remember where flags started */
                    862:                *flags = list;
                    863:            (void)copy_option_part(&list, part_buf, COM_MAX_LEN, ",");
                    864:            string = vim_strchr(part_buf, ':');
                    865:            if (string == NULL)     /* missing ':', ignore this part */
                    866:                continue;
                    867:            *string++ = NUL;        /* isolate flags from string */
                    868:
                    869:            /*
                    870:             * When already found a nested comment, only accept further
                    871:             * nested comments.
                    872:             */
                    873:            if (got_com && vim_strchr(part_buf, COM_NEST) == NULL)
                    874:                continue;
                    875:
                    876:            /*
                    877:             * Line contents and string must match.
                    878:             */
                    879:            for (j = 0; string[j] != NUL && string[j] == line[i + j]; ++j)
                    880:                ;
                    881:            if (string[j] != NUL)
                    882:                continue;
                    883:
                    884:            /*
                    885:             * When 'b' flag used, there must be white space or an
                    886:             * end-of-line after the string in the line.
                    887:             */
                    888:            if (vim_strchr(part_buf, COM_BLANK) != NULL &&
                    889:                              !vim_iswhite(line[i + j]) && line[i + j] != NUL)
                    890:                continue;
                    891:
                    892:            /*
                    893:             * We have found a match, stop searching.
                    894:             */
                    895:            i += j;
                    896:            got_com = TRUE;
                    897:            found_one = TRUE;
                    898:            break;
                    899:        }
                    900:
                    901:        /*
                    902:         * No match found, stop scanning.
                    903:         */
                    904:        if (!found_one)
                    905:            break;
                    906:
                    907:        /*
                    908:         * Include any trailing white space.
                    909:         */
                    910:        while (vim_iswhite(line[i]))
                    911:            ++i;
                    912:
                    913:        /*
                    914:         * If this comment doesn't nest, stop here.
                    915:         */
                    916:        if (vim_strchr(part_buf, COM_NEST) == NULL)
                    917:            break;
                    918:    }
                    919:    return (got_com ? i : 0);
                    920: }
                    921:
                    922: /*
                    923:  * plines(p) - return the number of physical screen lines taken by line 'p'
                    924:  */
                    925:    int
                    926: plines(p)
                    927:    linenr_t    p;
                    928: {
                    929:    return plines_win(curwin, p);
                    930: }
                    931:
                    932:    int
                    933: plines_win(wp, p)
                    934:    WIN         *wp;
                    935:    linenr_t    p;
                    936: {
                    937:    register long       col;
                    938:    register char_u     *s;
                    939:    register int        lines;
                    940:
                    941:    if (!wp->w_p_wrap)
                    942:        return 1;
                    943:
                    944:    s = ml_get_buf(wp->w_buffer, p, FALSE);
                    945:    if (*s == NUL)              /* empty line */
                    946:        return 1;
                    947:
                    948:    col = linetabsize(s);
                    949:
                    950:    /*
                    951:     * If list mode is on, then the '$' at the end of the line takes up one
                    952:     * extra column.
                    953:     */
                    954:    if (wp->w_p_list)
                    955:        col += 1;
                    956:
                    957:    /*
                    958:     * If 'number' mode is on, add another 8.
                    959:     */
                    960:    if (wp->w_p_nu)
                    961:        col += 8;
                    962:
                    963:    lines = (col + (Columns - 1)) / Columns;
                    964:    if (lines <= wp->w_height)
                    965:        return lines;
                    966:    return (int)(wp->w_height);     /* maximum length */
                    967: }
                    968:
                    969: /*
                    970:  * Count the physical lines (rows) for the lines "first" to "last" inclusive.
                    971:  */
                    972:    int
                    973: plines_m(first, last)
                    974:    linenr_t        first, last;
                    975: {
                    976:    return plines_m_win(curwin, first, last);
                    977: }
                    978:
                    979:    int
                    980: plines_m_win(wp, first, last)
                    981:    WIN             *wp;
                    982:    linenr_t        first, last;
                    983: {
                    984:    int count = 0;
                    985:
                    986:    while (first <= last)
                    987:        count += plines_win(wp, first++);
                    988:    return (count);
                    989: }
                    990:
                    991: /*
                    992:  * Insert or replace a single character at the cursor position.
                    993:  * When in REPLACE mode, replace any existing character.
                    994:  */
                    995:    void
                    996: ins_char(c)
                    997:    int         c;
                    998: {
                    999:    register char_u  *p;
                   1000:    char_u          *newp;
                   1001:    char_u          *oldp;
                   1002:    int             oldlen;
                   1003:    int             extra;
                   1004:    colnr_t         col = curwin->w_cursor.col;
                   1005:    linenr_t        lnum = curwin->w_cursor.lnum;
                   1006:
                   1007:    oldp = ml_get(lnum);
                   1008:    oldlen = STRLEN(oldp) + 1;
                   1009:
                   1010:    if (State != REPLACE || *(oldp + col) == NUL)
                   1011:        extra = 1;
                   1012:    else
                   1013:        extra = 0;
                   1014:
                   1015:    /*
                   1016:     * a character has to be put on the replace stack if there is a
                   1017:     * character that is replaced, so it can be put back when BS is used.
                   1018:     * Otherwise a 0 is put on the stack, indicating that a new character
                   1019:     * was inserted, which can be deleted when BS is used.
                   1020:     */
                   1021:    if (State == REPLACE)
                   1022:        replace_push(!extra ? *(oldp + col) : 0);
                   1023:    newp = alloc_check((unsigned)(oldlen + extra));
                   1024:    if (newp == NULL)
                   1025:        return;
                   1026:    vim_memmove(newp, oldp, (size_t)col);
                   1027:    p = newp + col;
                   1028:    vim_memmove(p + extra, oldp + col, (size_t)(oldlen - col));
                   1029:    *p = c;
                   1030:    ml_replace(lnum, newp, FALSE);
                   1031:
                   1032:    /*
                   1033:     * If we're in insert or replace mode and 'showmatch' is set, then check for
                   1034:     * right parens and braces. If there isn't a match, then beep. If there
                   1035:     * is a match AND it's on the screen, then flash to it briefly. If it
                   1036:     * isn't on the screen, don't do anything.
                   1037:     */
                   1038: #ifdef RIGHTLEFT
                   1039:    if (p_sm && (State & INSERT) &&
                   1040:            ((!curwin->w_p_rl && (c == ')' || c == '}' || c == ']')) ||
                   1041:             (curwin->w_p_rl && (c == '(' || c == '{' || c == '['))))
                   1042: #else
                   1043:    if (p_sm && (State & INSERT) && (c == ')' || c == '}' || c == ']'))
                   1044: #endif
                   1045:        showmatch();
                   1046:
                   1047: #ifdef RIGHTLEFT
                   1048:    if (!p_ri || State == REPLACE)      /* normal insert: cursor right */
                   1049: #endif
                   1050:        ++curwin->w_cursor.col;
                   1051:    CHANGED;
                   1052: }
                   1053:
                   1054: /*
                   1055:  * Insert a string at the cursor position.
                   1056:  * Note: Nothing special for replace mode.
                   1057:  */
                   1058:    void
                   1059: ins_str(s)
                   1060:    char_u  *s;
                   1061: {
                   1062:    register char_u     *oldp, *newp;
                   1063:    register int        newlen = STRLEN(s);
                   1064:    int                 oldlen;
                   1065:    colnr_t             col = curwin->w_cursor.col;
                   1066:    linenr_t            lnum = curwin->w_cursor.lnum;
                   1067:
                   1068:    oldp = ml_get(lnum);
                   1069:    oldlen = STRLEN(oldp);
                   1070:
                   1071:    newp = alloc_check((unsigned)(oldlen + newlen + 1));
                   1072:    if (newp == NULL)
                   1073:        return;
                   1074:    vim_memmove(newp, oldp, (size_t)col);
                   1075:    vim_memmove(newp + col, s, (size_t)newlen);
                   1076:    vim_memmove(newp + col + newlen, oldp + col, (size_t)(oldlen - col + 1));
                   1077:    ml_replace(lnum, newp, FALSE);
                   1078:    curwin->w_cursor.col += newlen;
                   1079:    CHANGED;
                   1080: }
                   1081:
                   1082: /*
                   1083:  * delete one character under the cursor
                   1084:  *
                   1085:  * return FAIL for failure, OK otherwise
                   1086:  */
                   1087:    int
                   1088: delchar(fixpos)
                   1089:    int         fixpos;     /* if TRUE fix the cursor position when done */
                   1090: {
                   1091:    char_u      *oldp, *newp;
                   1092:    colnr_t     oldlen;
                   1093:    linenr_t    lnum = curwin->w_cursor.lnum;
                   1094:    colnr_t     col = curwin->w_cursor.col;
                   1095:    int         was_alloced;
                   1096:
                   1097:    oldp = ml_get(lnum);
                   1098:    oldlen = STRLEN(oldp);
                   1099:
                   1100:    if (col >= oldlen)  /* can't do anything (happens with replace mode) */
                   1101:        return FAIL;
                   1102:
                   1103: /*
                   1104:  * If the old line has been allocated the deletion can be done in the
                   1105:  * existing line. Otherwise a new line has to be allocated
                   1106:  */
                   1107:    was_alloced = ml_line_alloced();        /* check if oldp was allocated */
                   1108:    if (was_alloced)
                   1109:        newp = oldp;                            /* use same allocated memory */
                   1110:    else
                   1111:    {
                   1112:        newp = alloc((unsigned)oldlen);     /* need to allocated a new line */
                   1113:        if (newp == NULL)
                   1114:            return FAIL;
                   1115:        vim_memmove(newp, oldp, (size_t)col);
                   1116:    }
                   1117:    vim_memmove(newp + col, oldp + col + 1, (size_t)(oldlen - col));
                   1118:    if (!was_alloced)
                   1119:        ml_replace(lnum, newp, FALSE);
                   1120:
                   1121:    /*
                   1122:     * If we just took off the last character of a non-blank line, we don't
                   1123:     * want to end up positioned at the NUL.
                   1124:     */
                   1125:    if (fixpos && curwin->w_cursor.col > 0 && col == oldlen - 1)
                   1126:        --curwin->w_cursor.col;
                   1127:
                   1128:    CHANGED;
                   1129:    return OK;
                   1130: }
                   1131:
                   1132: /*
                   1133:  * Delete from cursor to end of line.
                   1134:  *
                   1135:  * return FAIL for failure, OK otherwise
                   1136:  */
                   1137:    int
                   1138: truncate_line(fixpos)
                   1139:    int         fixpos;     /* if TRUE fix the cursor position when done */
                   1140: {
                   1141:    char_u      *newp;
                   1142:    linenr_t    lnum = curwin->w_cursor.lnum;
                   1143:    colnr_t     col = curwin->w_cursor.col;
                   1144:
                   1145:    if (col == 0)
                   1146:        newp = strsave((char_u *)"");
                   1147:    else
                   1148:        newp = strnsave(ml_get(lnum), col);
                   1149:
                   1150:    if (newp == NULL)
                   1151:        return FAIL;
                   1152:
                   1153:    ml_replace(lnum, newp, FALSE);
                   1154:
                   1155:    /*
                   1156:     * If "fixpos" is TRUE we don't want to end up positioned at the NUL.
                   1157:     */
                   1158:    if (fixpos && curwin->w_cursor.col > 0)
                   1159:        --curwin->w_cursor.col;
                   1160:
                   1161:    CHANGED;
                   1162:    return OK;
                   1163: }
                   1164:
                   1165:    void
                   1166: dellines(nlines, dowindow, undo)
                   1167:    long            nlines;         /* number of lines to delete */
                   1168:    int             dowindow;       /* if true, update the window */
                   1169:    int             undo;           /* if true, prepare for undo */
                   1170: {
                   1171:    int             num_plines = 0;
                   1172:
                   1173:    if (nlines <= 0)
                   1174:        return;
                   1175:    /*
                   1176:     * There's no point in keeping the window updated if redrawing is disabled
                   1177:     * or we're deleting more than a window's worth of lines.
                   1178:     */
                   1179:    if (RedrawingDisabled)
                   1180:        dowindow = FALSE;
                   1181:    else if (nlines > (curwin->w_height - curwin->w_row) && dowindow)
                   1182:    {
                   1183:        dowindow = FALSE;
                   1184:        /* flaky way to clear rest of window */
                   1185:        win_del_lines(curwin, curwin->w_row, curwin->w_height, TRUE, TRUE);
                   1186:    }
                   1187:    /* save the deleted lines for undo */
                   1188:    if (undo && u_savedel(curwin->w_cursor.lnum, nlines) == FAIL)
                   1189:        return;
                   1190:
                   1191:    /* adjust marks for deleted lines and lines that follow */
                   1192:    mark_adjust(curwin->w_cursor.lnum, curwin->w_cursor.lnum + nlines - 1,
                   1193:                                                            MAXLNUM, -nlines);
                   1194:
                   1195:    while (nlines-- > 0)
                   1196:    {
                   1197:        if (curbuf->b_ml.ml_flags & ML_EMPTY)       /* nothing to delete */
                   1198:            break;
                   1199:
                   1200:        /*
                   1201:         * Set up to delete the correct number of physical lines on the
                   1202:         * window
                   1203:         */
                   1204:        if (dowindow)
                   1205:            num_plines += plines(curwin->w_cursor.lnum);
                   1206:
                   1207:        ml_delete(curwin->w_cursor.lnum, TRUE);
                   1208:
                   1209:        CHANGED;
                   1210:
                   1211:        /* If we delete the last line in the file, stop */
                   1212:        if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
                   1213:        {
                   1214:            curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
                   1215:            break;
                   1216:        }
                   1217:    }
                   1218:    curwin->w_cursor.col = 0;
                   1219:    /*
                   1220:     * Delete the correct number of physical lines on the window
                   1221:     */
                   1222:    if (dowindow && num_plines > 0)
                   1223:        win_del_lines(curwin, curwin->w_row, num_plines, TRUE, TRUE);
                   1224: }
                   1225:
                   1226:    int
                   1227: gchar(pos)
                   1228:    FPOS *pos;
                   1229: {
                   1230:    return (int)(*(ml_get_pos(pos)));
                   1231: }
                   1232:
                   1233:    int
                   1234: gchar_cursor()
                   1235: {
                   1236:    return (int)(*(ml_get_cursor()));
                   1237: }
                   1238:
                   1239: /*
                   1240:  * Write a character at the current cursor position.
                   1241:  * It is directly written into the block.
                   1242:  */
                   1243:    void
                   1244: pchar_cursor(c)
                   1245:    int c;
                   1246: {
                   1247:    *(ml_get_buf(curbuf, curwin->w_cursor.lnum, TRUE) +
                   1248:                                                    curwin->w_cursor.col) = c;
                   1249: }
                   1250:
                   1251: /*
                   1252:  * Put *pos at end of current buffer
                   1253:  */
                   1254:    void
                   1255: goto_endofbuf(pos)
                   1256:    FPOS    *pos;
                   1257: {
                   1258:    char_u  *p;
                   1259:
                   1260:    pos->lnum = curbuf->b_ml.ml_line_count;
                   1261:    pos->col = 0;
                   1262:    p = ml_get(pos->lnum);
                   1263:    while (*p++)
                   1264:        ++pos->col;
                   1265: }
                   1266:
                   1267: /*
                   1268:  * When extra == 0: Return TRUE if the cursor is before or on the first
                   1269:  *                 non-blank in the line.
                   1270:  * When extra == 1: Return TRUE if the cursor is before the first non-blank in
                   1271:  *                 the line.
                   1272:  */
                   1273:    int
                   1274: inindent(extra)
                   1275:    int     extra;
                   1276: {
                   1277:    register char_u *ptr;
                   1278:    register colnr_t col;
                   1279:
                   1280:    for (col = 0, ptr = ml_get_curline(); vim_iswhite(*ptr); ++col)
                   1281:        ++ptr;
                   1282:    if (col >= curwin->w_cursor.col + extra)
                   1283:        return TRUE;
                   1284:    else
                   1285:        return FALSE;
                   1286: }
                   1287:
                   1288: /*
                   1289:  * skipwhite: skip over ' ' and '\t'.
                   1290:  */
                   1291:    char_u *
                   1292: skipwhite(p)
                   1293:    register char_u *p;
                   1294: {
                   1295:     while (vim_iswhite(*p))    /* skip to next non-white */
                   1296:        ++p;
                   1297:    return p;
                   1298: }
                   1299:
                   1300: /*
                   1301:  * skipdigits: skip over digits;
                   1302:  */
                   1303:    char_u *
                   1304: skipdigits(p)
                   1305:    register char_u *p;
                   1306: {
                   1307:     while (isdigit(*p))    /* skip to next non-digit */
                   1308:        ++p;
                   1309:    return p;
                   1310: }
                   1311:
                   1312: /*
                   1313:  * skiptowhite: skip over text until ' ' or '\t' or NUL.
                   1314:  */
                   1315:    char_u *
                   1316: skiptowhite(p)
                   1317:    register char_u *p;
                   1318: {
                   1319:    while (*p != ' ' && *p != '\t' && *p != NUL)
                   1320:        ++p;
                   1321:    return p;
                   1322: }
                   1323:
                   1324: /*
                   1325:  * skiptowhite_esc: Like skiptowhite(), but also skip escaped chars
                   1326:  */
                   1327:    char_u *
                   1328: skiptowhite_esc(p)
                   1329:    register char_u *p;
                   1330: {
                   1331:    while (*p != ' ' && *p != '\t' && *p != NUL)
                   1332:    {
                   1333:        if ((*p == '\\' || *p == Ctrl('V')) && *(p + 1) != NUL)
                   1334:            ++p;
                   1335:        ++p;
                   1336:    }
                   1337:    return p;
                   1338: }
                   1339:
                   1340: /*
                   1341:  * getdigits: get a number from a string and skip over it
                   1342:  *
                   1343:  * note: you must give a pointer to a char_u pointer!
                   1344:  */
                   1345:
                   1346:    long
                   1347: getdigits(pp)
                   1348:    char_u **pp;
                   1349: {
                   1350:     register char_u *p;
                   1351:    long retval;
                   1352:
                   1353:    p = *pp;
                   1354:    retval = atol((char *)p);
                   1355:    p = skipdigits(p);      /* skip to next non-digit */
                   1356:     *pp = p;
                   1357:    return retval;
                   1358: }
                   1359:
                   1360: /*
                   1361:  * Skip to next part of an option argument: Skip space and comma.
                   1362:  */
                   1363:    char_u *
                   1364: skip_to_option_part(p)
                   1365:    char_u  *p;
                   1366: {
                   1367:    if (*p == ',')
                   1368:        ++p;
                   1369:    while (*p == ' ')
                   1370:        ++p;
                   1371:    return p;
                   1372: }
                   1373:
                   1374:    char *
                   1375: plural(n)
                   1376:    long n;
                   1377: {
                   1378:    static char buf[2] = "s";
                   1379:
                   1380:    if (n == 1)
                   1381:        return &(buf[1]);
                   1382:    return &(buf[0]);
                   1383: }
                   1384:
                   1385: /*
                   1386:  * set_Changed is called when something in the current buffer is changed
                   1387:  */
                   1388:    void
                   1389: set_Changed()
                   1390: {
                   1391:    if (!curbuf->b_changed)
                   1392:    {
                   1393:        change_warning();
                   1394:        curbuf->b_changed = TRUE;
                   1395:        check_status(curbuf);
                   1396:    }
                   1397:    modified = TRUE;                /* used for redrawing */
                   1398: }
                   1399:
                   1400: /*
                   1401:  * unset_Changed is called when the changed flag must be reset for buffer 'buf'
                   1402:  */
                   1403:    void
                   1404: unset_Changed(buf)
                   1405:    BUF     *buf;
                   1406: {
                   1407:    if (buf->b_changed)
                   1408:    {
                   1409:        buf->b_changed = 0;
                   1410:        check_status(buf);
                   1411:    }
                   1412: }
                   1413:
                   1414: /*
                   1415:  * check_status: called when the status bars for the buffer 'buf'
                   1416:  *              need to be updated
                   1417:  */
                   1418:    static void
                   1419: check_status(buf)
                   1420:    BUF     *buf;
                   1421: {
                   1422:    WIN     *wp;
                   1423:    int     i;
                   1424:
                   1425:    i = 0;
                   1426:    for (wp = firstwin; wp != NULL; wp = wp->w_next)
                   1427:        if (wp->w_buffer == buf && wp->w_status_height)
                   1428:        {
                   1429:            wp->w_redr_status = TRUE;
                   1430:            ++i;
                   1431:        }
                   1432:    if (i)
                   1433:        redraw_later(NOT_VALID);
                   1434: }
                   1435:
                   1436: /*
                   1437:  * If the file is readonly, give a warning message with the first change.
                   1438:  * Don't do this for autocommands.
                   1439:  * Don't use emsg(), because it flushes the macro buffer.
                   1440:  * If we have undone all changes b_changed will be FALSE, but b_did_warn
                   1441:  * will be TRUE.
                   1442:  */
                   1443:    void
                   1444: change_warning()
                   1445: {
                   1446:    if (curbuf->b_did_warn == FALSE && curbuf->b_changed == 0 &&
                   1447: #ifdef AUTOCMD
                   1448:                                              !autocmd_busy &&
                   1449: #endif
                   1450:                                              curbuf->b_p_ro)
                   1451:    {
                   1452:        curbuf->b_did_warn = TRUE;
                   1453:        MSG("Warning: Changing a readonly file");
                   1454:        mch_delay(1000L, TRUE); /* give him some time to think about it */
                   1455:    }
                   1456: }
                   1457:
                   1458: /*
                   1459:  * Ask for a reply from the user, a 'y' or a 'n'.
                   1460:  * No other characters are accepted, the message is repeated until a valid
                   1461:  * reply is entered or CTRL-C is hit.
                   1462:  * If direct is TRUE, don't use vgetc but mch_inchar, don't get characters from
                   1463:  * any buffers but directly from the user.
                   1464:  *
                   1465:  * return the 'y' or 'n'
                   1466:  */
                   1467:    int
                   1468: ask_yesno(str, direct)
                   1469:    char_u  *str;
                   1470:    int     direct;
                   1471: {
                   1472:    int     r = ' ';
                   1473:    char_u  buf[20];
                   1474:    int     len = 0;
                   1475:    int     idx = 0;
                   1476:
                   1477:    if (exiting)                /* put terminal in raw mode for this question */
                   1478:        settmode(1);
                   1479:    while (r != 'y' && r != 'n')
                   1480:    {
                   1481:        (void)set_highlight('r');   /* same highlighting as for wait_return */
                   1482:        msg_highlight = TRUE;
                   1483:        smsg((char_u *)"%s (y/n)?", str);
                   1484:        if (direct)
                   1485:        {
                   1486:            flushbuf();
                   1487:            if (idx >= len)
                   1488:            {
                   1489:                len = mch_inchar(buf, 20, -1L);
                   1490:                idx = 0;
                   1491:            }
                   1492:            r = buf[idx++];
                   1493:        }
                   1494:        else
                   1495:            r = vgetc();
                   1496:        if (r == Ctrl('C') || r == ESC)
                   1497:            r = 'n';
                   1498:        msg_outchar(r);     /* show what you typed */
                   1499:        flushbuf();
                   1500:    }
                   1501:    return r;
                   1502: }
                   1503:
                   1504: /*
                   1505:  * get a number from the user
                   1506:  */
                   1507:    int
                   1508: get_number()
                   1509: {
                   1510:    int     n = 0;
                   1511:    int     c;
                   1512:
                   1513:    for (;;)
                   1514:    {
                   1515:        windgoto(msg_row, msg_col);
                   1516:        c = vgetc();
                   1517:        if (isdigit(c))
                   1518:        {
                   1519:            n = n * 10 + c - '0';
                   1520:            msg_outchar(c);
                   1521:        }
                   1522:        else if (c == K_DEL || c == K_BS || c == Ctrl('H'))
                   1523:        {
                   1524:            n /= 10;
                   1525:            MSG_OUTSTR("\b \b");
                   1526:        }
                   1527:        else if (c == CR || c == NL || c == Ctrl('C'))
                   1528:            break;
                   1529:    }
                   1530:    return n;
                   1531: }
                   1532:
                   1533:    void
                   1534: msgmore(n)
                   1535:    long n;
                   1536: {
                   1537:    long pn;
                   1538:
                   1539:    if (global_busy ||      /* no messages now, wait until global is finished */
                   1540:            keep_msg)       /* there is a message already, skip this one */
                   1541:        return;
                   1542:
                   1543:    if (n > 0)
                   1544:        pn = n;
                   1545:    else
                   1546:        pn = -n;
                   1547:
                   1548:    if (pn > p_report)
                   1549:    {
                   1550:        sprintf((char *)msg_buf, "%ld %s line%s %s",
                   1551:                pn, n > 0 ? "more" : "fewer", plural(pn),
                   1552:                got_int ? "(Interrupted)" : "");
                   1553:        if (msg(msg_buf))
                   1554:            keep_msg = msg_buf;
                   1555:    }
                   1556: }
                   1557:
                   1558: /*
                   1559:  * flush map and typeahead buffers and give a warning for an error
                   1560:  */
                   1561:    void
                   1562: beep_flush()
                   1563: {
                   1564:    flush_buffers(FALSE);
                   1565:    vim_beep();
                   1566: }
                   1567:
                   1568: /*
                   1569:  * give a warning for an error
                   1570:  */
                   1571:    void
                   1572: vim_beep()
                   1573: {
                   1574:    if (p_vb)
                   1575:    {
                   1576: #ifdef DJGPP
                   1577:        ScreenVisualBell();
                   1578: #else
                   1579:        outstr(T_VB);
                   1580: #endif
                   1581:    }
                   1582:    else
                   1583:    {
                   1584: #if defined MSDOS  ||  defined WIN32 /* ? gvr */
                   1585:        /*
                   1586:         * The number of beeps outputted is reduced to avoid having to wait
                   1587:         * for all the beeps to finish. This is only a problem on systems
                   1588:         * where the beeps don't overlap.
                   1589:         */
                   1590:        if (beep_count == 0 || beep_count == 10)
                   1591:        {
                   1592:            outchar('\007');
                   1593:            beep_count = 1;
                   1594:        }
                   1595:        else
                   1596:            ++beep_count;
                   1597: #else
                   1598:        outchar('\007');
                   1599: #endif
                   1600:    }
                   1601: }
                   1602:
                   1603: /*
                   1604:  * To get the "real" home directory:
                   1605:  * - get value of $HOME
                   1606:  * For Unix:
                   1607:  * - go to that directory
                   1608:  * - do mch_dirname() to get the real name of that directory.
                   1609:  * This also works with mounts and links.
                   1610:  * Don't do this for MS-DOS, it will change the "current dir" for a drive.
                   1611:  */
                   1612: static char_u  *homedir = NULL;
                   1613:
                   1614:    void
                   1615: init_homedir()
                   1616: {
                   1617:    char_u  *var;
                   1618:
                   1619:    var = vim_getenv((char_u *)"HOME");
                   1620: #if defined(OS2) || defined(MSDOS) || defined(WIN32)
                   1621:    /*
                   1622:     * Default home dir is C:/
                   1623:     * Best assumption we can make in such a situation.
                   1624:     */
                   1625:    if (var == NULL)
                   1626:        var = "C:/";
                   1627: #endif
                   1628:    if (var != NULL)
                   1629:    {
                   1630: #ifdef UNIX
                   1631:        if (mch_dirname(NameBuff, MAXPATHL) == OK)
                   1632:        {
                   1633:            if (!vim_chdir((char *)var) && mch_dirname(IObuff, IOSIZE) == OK)
                   1634:                var = IObuff;
                   1635:            vim_chdir((char *)NameBuff);
                   1636:        }
                   1637: #endif
                   1638:        homedir = strsave(var);
                   1639:    }
                   1640: }
                   1641:
                   1642: /*
                   1643:  * Expand environment variable with path name.
                   1644:  * For Unix and OS/2 "~/" is also expanded, like $HOME.
                   1645:  * If anything fails no expansion is done and dst equals src.
                   1646:  * Note that IObuff must NOT be used as either src or dst!  This is because
                   1647:  * vim_getenv() may use IObuff to do its expansion.
                   1648:  */
                   1649:    void
                   1650: expand_env(src, dst, dstlen)
                   1651:    char_u  *src;           /* input string e.g. "$HOME/vim.hlp" */
                   1652:    char_u  *dst;           /* where to put the result */
                   1653:    int     dstlen;         /* maximum length of the result */
                   1654: {
                   1655:    char_u  *tail;
                   1656:    int     c;
                   1657:    char_u  *var;
                   1658:    int     copy_char;
                   1659: #if defined(UNIX) || defined(OS2)
                   1660:    int     mustfree;
                   1661:    int     at_start = TRUE;
                   1662: #endif
                   1663:
                   1664:    src = skipwhite(src);
                   1665:    --dstlen;               /* leave one char space for "\," */
                   1666:    while (*src && dstlen > 0)
                   1667:    {
                   1668:        copy_char = TRUE;
                   1669:        if (*src == '$'
                   1670: #if defined(UNIX) || defined(OS2)
                   1671:                        || (*src == '~' && at_start)
                   1672: #endif
                   1673:                                                    )
                   1674:        {
                   1675: #if defined(UNIX) || defined(OS2)
                   1676:            mustfree = FALSE;
                   1677:
                   1678:            /*
                   1679:             * The variable name is copied into dst temporarily, because it may
                   1680:             * be a string in read-only memory and a NUL needs to be inserted.
                   1681:             */
                   1682:            if (*src == '$')                            /* environment var */
                   1683:            {
                   1684: #endif
                   1685:                tail = src + 1;
                   1686:                var = dst;
                   1687:                c = dstlen - 1;
                   1688:                while (c-- > 0 && *tail && isidchar(*tail))
                   1689: #ifdef OS2
                   1690:                {   /* env vars only in uppercase */
                   1691:                    *var++ = toupper(*tail);    /* toupper() may be a macro! */
                   1692:                    tail++;
                   1693:                }
                   1694: #else
                   1695:                    *var++ = *tail++;
                   1696: #endif
                   1697:                *var = NUL;
                   1698: #if defined(OS2) || defined(MSDOS) || defined(WIN32)
                   1699:                /* use "C:/" when $HOME is not set */
                   1700:                if (STRCMP(dst, "HOME") == 0)
                   1701:                    var = homedir;
                   1702:                else
                   1703: #endif
                   1704:                    var = vim_getenv(dst);
                   1705: #if defined(UNIX) || defined(OS2)
                   1706:            }
                   1707:                                                        /* home directory */
                   1708:            else if (src[1] == NUL ||
                   1709:                              vim_strchr((char_u *)"/ ,\t\n", src[1]) != NULL)
                   1710:            {
                   1711:                var = homedir;
                   1712:                tail = src + 1;
                   1713:            }
                   1714:            else                                        /* user directory */
                   1715: # ifdef OS2
                   1716:            {
                   1717:                /* cannot expand user's home directory, so don't try */
                   1718:                var = NULL;
                   1719:                tail = "";  /* shut gcc up about "may be used uninitialized" */
                   1720:            }
                   1721: # else
                   1722:            {
                   1723:                /*
                   1724:                 * Copy ~user to dst[], so we can put a NUL after it.
                   1725:                 */
                   1726:                tail = src;
                   1727:                var = dst;
                   1728:                c = dstlen - 1;
                   1729:                while (c-- > 0 && *tail &&
                   1730:                                       isfilechar(*tail) && !ispathsep(*tail))
                   1731:                    *var++ = *tail++;
                   1732:                *var = NUL;
                   1733:
                   1734:                /*
                   1735:                 * If the system supports getpwnam(), use it.
                   1736:                 * Otherwise, or if getpwnam() fails, the shell is used to
                   1737:                 * expand ~user.  This is slower and may fail if the shell
                   1738:                 * does not support ~user (old versions of /bin/sh).
                   1739:                 */
                   1740: #  if defined(HAVE_GETPWNAM) && defined(HAVE_PWD_H)
                   1741:                {
                   1742:                    struct passwd *pw;
                   1743:
                   1744:                    pw = getpwnam((char *)dst + 1);
                   1745:                    if (pw != NULL)
                   1746:                        var = (char_u *)pw->pw_dir;
                   1747:                    else
                   1748:                        var = NULL;
                   1749:                }
                   1750:                if (var == NULL)
                   1751: #  endif
                   1752:                {
                   1753:                    var = ExpandOne(dst, NULL, 0, WILD_EXPAND_FREE);
                   1754:                    mustfree = TRUE;
                   1755:                }
                   1756:            }
                   1757: # endif /* OS2 */
                   1758: #endif /* UNIX || OS2 */
                   1759:            if (var != NULL && *var != NUL &&
                   1760:                          (STRLEN(var) + STRLEN(tail) + 1 < (unsigned)dstlen))
                   1761:            {
                   1762:                STRCPY(dst, var);
                   1763:                dstlen -= STRLEN(var);
                   1764:                dst += STRLEN(var);
                   1765:                    /* if var[] ends in a path separator and tail[] starts
                   1766:                     * with it, skip a character */
                   1767:                if (*var && ispathsep(*(dst-1)) && ispathsep(*tail))
                   1768:                    ++tail;
                   1769:                src = tail;
                   1770:                copy_char = FALSE;
                   1771:            }
                   1772: #if defined(UNIX) || defined(OS2)
                   1773:            if (mustfree)
                   1774:                vim_free(var);
                   1775: #endif
                   1776:        }
                   1777:
                   1778:        if (copy_char)      /* copy at least one char */
                   1779:        {
                   1780: #if defined(UNIX) || defined(OS2)
                   1781:            /*
                   1782:             * Recogize the start of a new name, for '~'.
                   1783:             */
                   1784:            at_start = FALSE;
                   1785: #endif
                   1786:            if (src[0] == '\\')
                   1787:            {
                   1788:                *dst++ = *src++;
                   1789:                --dstlen;
                   1790:            }
                   1791: #if defined(UNIX) || defined(OS2)
                   1792:            else if (src[0] == ' ' || src[0] == ',')
                   1793:                at_start = TRUE;
                   1794: #endif
                   1795:            *dst++ = *src++;
                   1796:            --dstlen;
                   1797:        }
                   1798:    }
                   1799:    *dst = NUL;
                   1800: }
                   1801:
                   1802: /*
                   1803:  * Replace home directory by "~/" in each space or comma separated filename in
                   1804:  * 'src'. If anything fails (except when out of space) dst equals src.
                   1805:  */
                   1806:    void
                   1807: home_replace(buf, src, dst, dstlen)
                   1808:    BUF     *buf;           /* when not NULL, check for help files */
                   1809:    char_u  *src;           /* input file name */
                   1810:    char_u  *dst;           /* where to put the result */
                   1811:    int     dstlen;         /* maximum length of the result */
                   1812: {
                   1813:    size_t  dirlen = 0, envlen = 0;
                   1814:    size_t  len;
                   1815:    char_u  *homedir_env;
                   1816:    char_u  *p;
                   1817:
                   1818:    if (src == NULL)
                   1819:    {
                   1820:        *dst = NUL;
                   1821:        return;
                   1822:    }
                   1823:
                   1824:    /*
                   1825:     * If the file is a help file, remove the path completely.
                   1826:     */
                   1827:    if (buf != NULL && buf->b_help)
                   1828:    {
                   1829:        STRCPY(dst, gettail(src));
                   1830:        return;
                   1831:    }
                   1832:
                   1833:    /*
                   1834:     * We check both the value of the $HOME environment variable and the
                   1835:     * "real" home directory.
                   1836:     */
                   1837:    if (homedir != NULL)
                   1838:        dirlen = STRLEN(homedir);
                   1839:    homedir_env = vim_getenv((char_u *)"HOME");
                   1840:    if (homedir_env != NULL)
                   1841:        envlen = STRLEN(homedir_env);
                   1842:
                   1843:    src = skipwhite(src);
                   1844:    while (*src && dstlen > 0)
                   1845:    {
                   1846:        /*
                   1847:         * Here we are at the beginning of a filename.
                   1848:         * First, check to see if the beginning of the filename matches
                   1849:         * $HOME or the "real" home directory. Check that there is a '/'
                   1850:         * after the match (so that if e.g. the file is "/home/pieter/bla",
                   1851:         * and the home directory is "/home/piet", the file does not end up
                   1852:         * as "~er/bla" (which would seem to indicate the file "bla" in user
                   1853:         * er's home directory)).
                   1854:         */
                   1855:        p = homedir;
                   1856:        len = dirlen;
                   1857:        for (;;)
                   1858:        {
                   1859:            if (len && fnamencmp(src, p, len) == 0 && (ispathsep(src[len]) ||
                   1860:                       src[len] == ',' || src[len] == ' ' || src[len] == NUL))
                   1861:            {
                   1862:                src += len;
                   1863:                if (--dstlen > 0)
                   1864:                    *dst++ = '~';
                   1865:                /*
                   1866:                 * If it's just the home directory, make it "~/".
                   1867:                 */
                   1868:                if (!ispathsep(src[0]) && --dstlen > 0)
                   1869:                    *dst++ = '/';
                   1870:            }
                   1871:            if (p == homedir_env)
                   1872:                break;
                   1873:            p = homedir_env;
                   1874:            len = envlen;
                   1875:        }
                   1876:
                   1877:        /* skip to separator: space or comma */
                   1878:        while (*src && *src != ',' && *src != ' ' && --dstlen > 0)
                   1879:            *dst++ = *src++;
                   1880:        /* skip separator */
                   1881:        while ((*src == ' ' || *src == ',') && --dstlen > 0)
                   1882:            *dst++ = *src++;
                   1883:    }
                   1884:    /* if (dstlen == 0) out of space, what to do??? */
                   1885:
                   1886:    *dst = NUL;
                   1887: }
                   1888:
                   1889: /*
                   1890:  * Like home_replace, store the replaced string in allocated memory.
                   1891:  * When something fails, NULL is returned.
                   1892:  */
                   1893:    char_u  *
                   1894: home_replace_save(buf, src)
                   1895:    BUF     *buf;           /* when not NULL, check for help files */
                   1896:    char_u  *src;           /* input file name */
                   1897: {
                   1898:    char_u      *dst;
                   1899:    unsigned    len;
                   1900:
                   1901:    if (src == NULL)        /* just in case */
                   1902:        len = 3;
                   1903:    else
                   1904:        len = STRLEN(src) + 3;      /* extra space for "~/" and trailing NUL */
                   1905:    dst = alloc(len);
                   1906:    if (dst != NULL)
                   1907:        home_replace(buf, src, dst, len);
                   1908:    return dst;
                   1909: }
                   1910:
                   1911: /*
                   1912:  * Compare two file names and return:
                   1913:  * FPC_SAME   if they both exist and are the same file.
                   1914:  * FPC_DIFF   if they both exist and are different files.
                   1915:  * FPC_NOTX   if they both don't exist.
                   1916:  * FPC_DIFFX  if one of them doesn't exist.
                   1917:  * For the first name environment variables are expanded
                   1918:  */
                   1919:    int
                   1920: fullpathcmp(s1, s2)
                   1921:    char_u *s1, *s2;
                   1922: {
                   1923: #ifdef UNIX
                   1924:    char_u          buf1[MAXPATHL];
                   1925:    struct stat     st1, st2;
                   1926:    int             r1, r2;
                   1927:
                   1928:    expand_env(s1, buf1, MAXPATHL);
                   1929:    r1 = stat((char *)buf1, &st1);
                   1930:    r2 = stat((char *)s2, &st2);
                   1931:    if (r1 != 0 && r2 != 0)
                   1932:        return FPC_NOTX;
                   1933:    if (r1 != 0 || r2 != 0)
                   1934:        return FPC_DIFFX;
                   1935:    if (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino)
                   1936:        return FPC_SAME;
                   1937:    return FPC_DIFF;
                   1938: #else
                   1939:    char_u  *buf1 = NULL;
                   1940:    char_u  *buf2 = NULL;
                   1941:    int     retval = FPC_DIFF;
                   1942:    int     r1, r2;
                   1943:
                   1944:    if ((buf1 = alloc(MAXPATHL)) != NULL && (buf2 = alloc(MAXPATHL)) != NULL)
                   1945:    {
                   1946:        expand_env(s1, buf2, MAXPATHL);
                   1947:        /*
                   1948:         * If FullName() failed, the file probably doesn't exist.
                   1949:         */
                   1950:        r1 = FullName(buf2, buf1, MAXPATHL, FALSE);
                   1951:        r2 = FullName(s2, buf2, MAXPATHL, FALSE);
                   1952:        if (r1 != OK && r2 != OK)
                   1953:            retval = FPC_NOTX;
                   1954:        else if (r1 != OK || r2 != OK)
                   1955:            retval = FPC_DIFFX;
                   1956:        else if (fnamecmp(buf1, buf2))
                   1957:            retval = FPC_DIFF;
                   1958:        else
                   1959:            retval = FPC_SAME;
                   1960:    }
                   1961:    vim_free(buf1);
                   1962:    vim_free(buf2);
                   1963:    return retval;
                   1964: #endif
                   1965: }
                   1966:
                   1967: /*
                   1968:  * get the tail of a path: the file name.
                   1969:  */
                   1970:    char_u *
                   1971: gettail(fname)
                   1972:    char_u *fname;
                   1973: {
                   1974:    register char_u *p1, *p2;
                   1975:
                   1976:    if (fname == NULL)
                   1977:        return (char_u *)"";
                   1978:    for (p1 = p2 = fname; *p2; ++p2)    /* find last part of path */
                   1979:    {
                   1980:        if (ispathsep(*p2))
                   1981:            p1 = p2 + 1;
                   1982:    }
                   1983:    return p1;
                   1984: }
                   1985:
                   1986: /*
                   1987:  * return TRUE if 'c' is a path separator.
                   1988:  */
                   1989:    int
                   1990: ispathsep(c)
                   1991:    int c;
                   1992: {
                   1993: #ifdef UNIX
                   1994:    return (c == PATHSEP);      /* UNIX has ':' inside file names */
                   1995: #else
                   1996: # ifdef BACKSLASH_IN_FILENAME
                   1997:    return (c == ':' || c == PATHSEP || c == '\\');
                   1998: # else
                   1999:    return (c == ':' || c == PATHSEP);
                   2000: # endif
                   2001: #endif
                   2002: }
                   2003:
                   2004: /*
                   2005:  * Concatenate filenames fname1 and fname2 into allocated memory.
                   2006:  * Only add a '/' when 'sep' is TRUE and it is neccesary.
                   2007:  */
                   2008:    char_u  *
                   2009: concat_fnames(fname1, fname2, sep)
                   2010:    char_u  *fname1;
                   2011:    char_u  *fname2;
                   2012:    int     sep;
                   2013: {
                   2014:    char_u  *dest;
                   2015:
                   2016:    dest = alloc((unsigned)(STRLEN(fname1) + STRLEN(fname2) + 2));
                   2017:    if (dest != NULL)
                   2018:    {
                   2019:        STRCPY(dest, fname1);
                   2020:        if (sep && *dest && !ispathsep(*(dest + STRLEN(dest) - 1)))
                   2021:            STRCAT(dest, PATHSEPSTR);
                   2022:        STRCAT(dest, fname2);
                   2023:    }
                   2024:    return dest;
                   2025: }
                   2026:
                   2027: /*
                   2028:  * FullName_save - Make an allocated copy of a full file name.
                   2029:  * Returns NULL when failed.
                   2030:  */
                   2031:    char_u  *
                   2032: FullName_save(fname)
                   2033:    char_u      *fname;
                   2034: {
                   2035:    char_u      *buf;
                   2036:    char_u      *new_fname = NULL;
                   2037:
                   2038:    buf = alloc((unsigned)MAXPATHL);
                   2039:    if (buf != NULL)
                   2040:    {
                   2041:        if (FullName(fname, buf, MAXPATHL, FALSE) != FAIL)
                   2042:            new_fname = strsave(buf);
                   2043:        vim_free(buf);
                   2044:    }
                   2045:    return new_fname;
                   2046: }
                   2047:
                   2048: #ifdef CINDENT
                   2049:
                   2050: /*
                   2051:  * Functions for C-indenting.
                   2052:  * Most of this originally comes from Eric Fischer.
                   2053:  */
                   2054: /*
                   2055:  * Below "XXX" means that this function may unlock the current line.
                   2056:  */
                   2057:
                   2058: static int     isdefault __ARGS((char_u *));
                   2059: static char_u  *after_label __ARGS((char_u *l));
                   2060: static int     get_indent_nolabel __ARGS((linenr_t lnum));
                   2061: static int     skip_label __ARGS((linenr_t, char_u **pp, int ind_maxcomment));
                   2062: static int     ispreproc __ARGS((char_u *));
                   2063: static int     iscomment __ARGS((char_u *));
                   2064: static int     commentorempty __ARGS((char_u *));
                   2065: static int     isterminated __ARGS((char_u *));
                   2066: static int     isfuncdecl __ARGS((char_u *));
                   2067: static char_u  *skip_string __ARGS((char_u *p));
                   2068: static int     isif __ARGS((char_u *));
                   2069: static int     iselse __ARGS((char_u *));
                   2070: static int     isdo __ARGS((char_u *));
                   2071: static int     iswhileofdo __ARGS((char_u *, linenr_t, int));
                   2072: static FPOS        *find_start_comment __ARGS((int ind_maxcomment));
                   2073: static FPOS        *find_start_brace __ARGS((int));
                   2074: static FPOS        *find_match_paren __ARGS((int, int));
                   2075: static int     find_last_paren __ARGS((char_u *l));
                   2076: static int     find_match __ARGS((int lookfor, linenr_t ourscope,
                   2077:                        int ind_maxparen, int ind_maxcomment));
                   2078:
                   2079: /*
                   2080:  * Recognize a label: "label:".
                   2081:  * Note: curwin->w_cursor must be where we are looking for the label.
                   2082:  */
                   2083:    int
                   2084: islabel(ind_maxcomment)            /* XXX */
                   2085:    int         ind_maxcomment;
                   2086: {
                   2087:    char_u      *s;
                   2088:
                   2089:    s = skipwhite(ml_get_curline());
                   2090:
                   2091:    /*
                   2092:     * Exclude "default" from labels, since it should be indented
                   2093:     * like a switch label.
                   2094:     */
                   2095:
                   2096:    if (isdefault(s))
                   2097:        return FALSE;
                   2098:
                   2099:    if (!isidchar(*s))      /* need at least one ID character */
                   2100:        return FALSE;
                   2101:
                   2102:    while (isidchar(*s))
                   2103:        s++;
                   2104:
                   2105:    s = skipwhite(s);
                   2106:
                   2107:    /* "::" is not a label, it's C++ */
                   2108:    if (*s == ':' && s[1] != ':')
                   2109:    {
                   2110:        /*
                   2111:         * Only accept a label if the previous line is terminated or is a case
                   2112:         * label.
                   2113:         */
                   2114:        FPOS    cursor_save;
                   2115:        FPOS    *trypos;
                   2116:        char_u  *line;
                   2117:
                   2118:        cursor_save = curwin->w_cursor;
                   2119:        while (curwin->w_cursor.lnum > 1)
                   2120:        {
                   2121:            --curwin->w_cursor.lnum;
                   2122:
                   2123:            /*
                   2124:             * If we're in a comment now, skip to the start of the comment.
                   2125:             */
                   2126:            curwin->w_cursor.col = 0;
                   2127:            if ((trypos = find_start_comment(ind_maxcomment)) != NULL) /* XXX */
                   2128:                curwin->w_cursor = *trypos;
                   2129:
                   2130:            line = ml_get_curline();
                   2131:            if (ispreproc(line))        /* ignore #defines, #if, etc. */
                   2132:                continue;
                   2133:            if (commentorempty(line))
                   2134:                continue;
                   2135:
                   2136:            curwin->w_cursor = cursor_save;
                   2137:            if (isterminated(line) || iscase(line))
                   2138:                return TRUE;
                   2139:            return FALSE;
                   2140:        }
                   2141:        curwin->w_cursor = cursor_save;
                   2142:        return TRUE;            /* label at start of file??? */
                   2143:    }
                   2144:    return FALSE;
                   2145: }
                   2146:
                   2147: /*
                   2148:  * Recognize a switch label: "case .*:" or "default:".
                   2149:  */
                   2150:     int
                   2151: iscase(s)
                   2152:    char_u *s;
                   2153: {
                   2154:    s = skipwhite(s);
                   2155:    if (STRNCMP(s, "case", 4) == 0 && !isidchar(s[4]))
                   2156:    {
                   2157:        for (s += 4; *s; ++s)
                   2158:            if (*s == ':')
                   2159:            {
                   2160:                if (s[1] == ':')        /* skip over "::" for C++ */
                   2161:                    ++s;
                   2162:                else
                   2163:                    return TRUE;
                   2164:            }
                   2165:        return FALSE;
                   2166:    }
                   2167:
                   2168:    if (isdefault(s))
                   2169:        return TRUE;
                   2170:    return FALSE;
                   2171: }
                   2172:
                   2173: /*
                   2174:  * Recognize a "default" switch label.
                   2175:  */
                   2176:    static int
                   2177: isdefault(s)
                   2178:    char_u  *s;
                   2179: {
                   2180:    return (STRNCMP(s, "default", 7) == 0 &&
                   2181:            *(s = skipwhite(s + 7)) == ':' &&
                   2182:            s[1] != ':');
                   2183: }
                   2184:
                   2185: /*
                   2186:  * Return a pointer to the first non-empty non-comment character after a ':'.
                   2187:  * Return NULL if not found.
                   2188:  *        case 234:    a = b;
                   2189:  *                     ^
                   2190:  */
                   2191:    static char_u *
                   2192: after_label(l)
                   2193:    char_u  *l;
                   2194: {
                   2195:    for ( ; *l; ++l)
                   2196:        if (*l == ':')
                   2197:        {
                   2198:            if (l[1] == ':')        /* skip over "::" for C++ */
                   2199:                ++l;
                   2200:            else
                   2201:                break;
                   2202:        }
                   2203:    if (*l == NUL)
                   2204:        return NULL;
                   2205:    l = skipwhite(l + 1);
                   2206:    if (commentorempty(l))
                   2207:        return NULL;
                   2208:    return l;
                   2209: }
                   2210:
                   2211: /*
                   2212:  * Get indent of line "lnum", skipping a label.
                   2213:  * Return 0 if there is nothing after the label.
                   2214:  */
                   2215:    static int
                   2216: get_indent_nolabel(lnum)               /* XXX */
                   2217:    linenr_t    lnum;
                   2218: {
                   2219:    char_u      *l;
                   2220:    FPOS        fp;
                   2221:    colnr_t     col;
                   2222:    char_u      *p;
                   2223:
                   2224:    l = ml_get(lnum);
                   2225:    p = after_label(l);
                   2226:    if (p == NULL)
                   2227:        return 0;
                   2228:
                   2229:    fp.col = p - l;
                   2230:    fp.lnum = lnum;
                   2231:    getvcol(curwin, &fp, &col, NULL, NULL);
                   2232:    return (int)col;
                   2233: }
                   2234:
                   2235: /*
                   2236:  * Find indent for line "lnum", ignoring any case or jump label.
                   2237:  * Also return a pointer to the text (after the label).
                   2238:  *   label:        if (asdf && asdfasdf)
                   2239:  *              ^
                   2240:  */
                   2241:    static int
                   2242: skip_label(lnum, pp, ind_maxcomment)
                   2243:    linenr_t    lnum;
                   2244:    char_u      **pp;
                   2245:    int         ind_maxcomment;
                   2246: {
                   2247:    char_u      *l;
                   2248:    int         amount;
                   2249:    FPOS        cursor_save;
                   2250:
                   2251:    cursor_save = curwin->w_cursor;
                   2252:    curwin->w_cursor.lnum = lnum;
                   2253:    l = ml_get_curline();
                   2254:    if (iscase(l) || islabel(ind_maxcomment)) /* XXX */
                   2255:    {
                   2256:        amount = get_indent_nolabel(lnum);
                   2257:        l = after_label(ml_get_curline());
                   2258:        if (l == NULL)          /* just in case */
                   2259:            l = ml_get_curline();
                   2260:    }
                   2261:    else
                   2262:    {
                   2263:        amount = get_indent();
                   2264:        l = ml_get_curline();
                   2265:    }
                   2266:    *pp = l;
                   2267:
                   2268:    curwin->w_cursor = cursor_save;
                   2269:    return amount;
                   2270: }
                   2271:
                   2272: /*
                   2273:  * Recognize a preprocessor statement: Any line that starts with '#'.
                   2274:  */
                   2275:    static int
                   2276: ispreproc(s)
                   2277:    char_u *s;
                   2278: {
                   2279:    s = skipwhite(s);
                   2280:    if (*s == '#')
                   2281:        return TRUE;
                   2282:    return 0;
                   2283: }
                   2284:
                   2285: /*
                   2286:  * Recognize the start of a C or C++ comment.
                   2287:  */
                   2288:    static int
                   2289: iscomment(p)
                   2290:    char_u  *p;
                   2291: {
                   2292:    return (p[0] == '/' && (p[1] == '*' || p[1] == '/'));
                   2293: }
                   2294:
                   2295: /*
                   2296:  * Recognize an empty or comment line.
                   2297:  */
                   2298:    static int
                   2299: commentorempty(s)
                   2300:    char_u *s;
                   2301: {
                   2302:    s = skipwhite(s);
                   2303:    if (*s == NUL || iscomment(s))
                   2304:        return TRUE;
                   2305:    return FALSE;
                   2306: }
                   2307:
                   2308: /*
                   2309:  * Recognize a line that starts with '{' or '}', or ends with ';' or '}'.
                   2310:  * Also consider a line terminated if it ends in ','.  This is not 100%
                   2311:  * correct, but this mostly means we are in initializations and then it's OK.
                   2312:  */
                   2313:    static int
                   2314: isterminated(s)
                   2315:    char_u *s;
                   2316: {
                   2317:    s = skipwhite(s);
                   2318:
                   2319:    if (*s == '{' || *s == '}')
                   2320:        return TRUE;
                   2321:
                   2322:    while (*s)
                   2323:    {
                   2324:        if (iscomment(s))       /* at start of comment ignore rest of line */
                   2325:            return FALSE;
                   2326:        s = skip_string(s);
                   2327:        if ((*s == ';' || *s == '{' || *s == ',') && commentorempty(s + 1))
                   2328:            return TRUE;
                   2329:        s++;
                   2330:    }
                   2331:    return FALSE;
                   2332: }
                   2333:
                   2334: /*
                   2335:  * Recognize the basic picture of a function declaration -- it needs to
                   2336:  * have an open paren somewhere and a close paren at the end of the line and
                   2337:  * no semicolons anywhere.
                   2338:  */
                   2339:    static int
                   2340: isfuncdecl(s)
                   2341:    char_u *s;
                   2342: {
                   2343:    while (*s && *s != '(' && *s != ';')
                   2344:        if (iscomment(s++))
                   2345:            return FALSE;           /* comment before () ??? */
                   2346:    if (*s != '(')
                   2347:        return FALSE;               /* ';' before any () or no '(' */
                   2348:
                   2349:    while (*s && *s != ';')
                   2350:    {
                   2351:        if (*s == ')' && commentorempty(s + 1))
                   2352:            return TRUE;
                   2353:        if (iscomment(s++))
                   2354:            return FALSE;           /* comment between ( and ) ??? */
                   2355:    }
                   2356:    return FALSE;
                   2357: }
                   2358:
                   2359: /*
                   2360:  * Skip over a "string" and a 'c' character.
                   2361:  */
                   2362:    static char_u *
                   2363: skip_string(p)
                   2364:    char_u  *p;
                   2365: {
                   2366:    int     i;
                   2367:
                   2368:    /*
                   2369:     * We loop, because strings may be concatenated: "date""time".
                   2370:     */
                   2371:    for ( ; ; ++p)
                   2372:    {
                   2373:        if (p[0] == '\'')                   /* 'c' or '\n' or '\000' */
                   2374:        {
                   2375:            if (!p[1])                      /* ' at end of line */
                   2376:                break;
                   2377:            i = 2;
                   2378:            if (p[1] == '\\')               /* '\n' or '\000' */
                   2379:            {
                   2380:                ++i;
                   2381:                while (isdigit(p[i - 1]))   /* '\000' */
                   2382:                    ++i;
                   2383:            }
                   2384:            if (p[i] == '\'')               /* check for trailing ' */
                   2385:            {
                   2386:                p += i;
                   2387:                continue;
                   2388:            }
                   2389:        }
                   2390:        else if (p[0] == '"')               /* start of string */
                   2391:        {
                   2392:            for (++p; p[0]; ++p)
                   2393:            {
                   2394:                if (p[0] == '\\' && p[1])
                   2395:                    ++p;
                   2396:                else if (p[0] == '"')       /* end of string */
                   2397:                    break;
                   2398:            }
                   2399:            continue;
                   2400:        }
                   2401:        break;                              /* no string found */
                   2402:    }
                   2403:    if (!*p)
                   2404:        --p;                                /* backup from NUL */
                   2405:    return p;
                   2406: }
                   2407:
                   2408:    static int
                   2409: isif(p)
                   2410:    char_u  *p;
                   2411: {
                   2412:    return (STRNCMP(p, "if", 2) == 0 && !isidchar(p[2]));
                   2413: }
                   2414:
                   2415:    static int
                   2416: iselse(p)
                   2417:    char_u  *p;
                   2418: {
                   2419:    return (STRNCMP(p, "else", 4) == 0 && !isidchar(p[4]));
                   2420: }
                   2421:
                   2422:    static int
                   2423: isdo(p)
                   2424:    char_u  *p;
                   2425: {
                   2426:    return (STRNCMP(p, "do", 2) == 0 && !isidchar(p[2]));
                   2427: }
                   2428:
                   2429: /*
                   2430:  * Check if this is a "while" that should have a matching "do".
                   2431:  * We only accept a "while (condition) ;", with only white space between the
                   2432:  * ')' and ';'. The condition may be spread over several lines.
                   2433:  */
                   2434:    static int
                   2435: iswhileofdo(p, lnum, ind_maxparen)         /* XXX */
                   2436:    char_u      *p;
                   2437:    linenr_t    lnum;
                   2438:    int         ind_maxparen;
                   2439: {
                   2440:    FPOS        cursor_save;
                   2441:    FPOS        *trypos;
                   2442:    int         retval = FALSE;
                   2443:
                   2444:    p = skipwhite(p);
                   2445:    if (STRNCMP(p, "while", 5) == 0 && !isidchar(p[5]))
                   2446:    {
                   2447:        cursor_save = curwin->w_cursor;
                   2448:        curwin->w_cursor.lnum = lnum;
                   2449:        curwin->w_cursor.col = 0;
                   2450:        if ((trypos = findmatchlimit(0, 0, ind_maxparen)) != NULL)
                   2451:        {
                   2452:            p = ml_get_pos(trypos) + 1;
                   2453:            p = skipwhite(p);
                   2454:            if (*p == ';')
                   2455:                retval = TRUE;
                   2456:        }
                   2457:        curwin->w_cursor = cursor_save;
                   2458:    }
                   2459:    return retval;
                   2460: }
                   2461:
                   2462: /*
                   2463:  * Find the start of a comment, not knowing if we are in a comment right now.
                   2464:  * Search starts at w_cursor.lnum and goes backwards.
                   2465:  */
                   2466:    static FPOS *
                   2467: find_start_comment(ind_maxcomment)         /* XXX */
                   2468:    int         ind_maxcomment;
                   2469: {
                   2470:    FPOS        *pos;
                   2471:    char_u      *line;
                   2472:    char_u      *p;
                   2473:
                   2474:    if ((pos = findmatchlimit('*', FM_BACKWARD, ind_maxcomment)) == NULL)
                   2475:        return NULL;
                   2476:
                   2477:    /*
                   2478:     * Check if the comment start we found is inside a string.
                   2479:     */
                   2480:    line = ml_get(pos->lnum);
                   2481:    for (p = line; *p && (unsigned)(p - line) < pos->col; ++p)
                   2482:        p = skip_string(p);
                   2483:    if ((unsigned)(p - line) > pos->col)
                   2484:        return NULL;
                   2485:    return pos;
                   2486: }
                   2487:
                   2488: /*
                   2489:  * Find the '{' at the start of the block we are in.
                   2490:  * Return NULL of no match found.
                   2491:  * Ignore a '{' that is in a comment, makes indenting the next three lines
                   2492:  * work. */
                   2493: /* foo()   */
                   2494: /* {       */
                   2495: /* }       */
                   2496:
                   2497:    static FPOS *
                   2498: find_start_brace(ind_maxcomment)           /* XXX */
                   2499:    int         ind_maxcomment;
                   2500: {
                   2501:    FPOS        cursor_save;
                   2502:    FPOS        *trypos;
                   2503:    FPOS        *pos;
                   2504:    static FPOS pos_copy;
                   2505:
                   2506:    cursor_save = curwin->w_cursor;
                   2507:    while ((trypos = findmatchlimit('{', FM_BLOCKSTOP, 0)) != NULL)
                   2508:    {
                   2509:        pos_copy = *trypos;     /* copy FPOS, next findmatch will change it */
                   2510:        trypos = &pos_copy;
                   2511:        curwin->w_cursor = *trypos;
                   2512:        pos = NULL;
                   2513:        if (!iscomment(skipwhite(ml_get(trypos->lnum))) &&
                   2514:                 (pos = find_start_comment(ind_maxcomment)) == NULL) /* XXX */
                   2515:            break;
                   2516:        if (pos != NULL)
                   2517:            curwin->w_cursor.lnum = pos->lnum;
                   2518:    }
                   2519:    curwin->w_cursor = cursor_save;
                   2520:    return trypos;
                   2521: }
                   2522:
                   2523: /*
                   2524:  * Find the matching '(', failing if it is in a comment.
                   2525:  * Return NULL of no match found.
                   2526:  */
                   2527:    static FPOS *
                   2528: find_match_paren(ind_maxparen, ind_maxcomment)     /* XXX */
                   2529:    int         ind_maxparen;
                   2530:    int         ind_maxcomment;
                   2531: {
                   2532:    FPOS        cursor_save;
                   2533:    FPOS        *trypos;
                   2534:    static FPOS pos_copy;
                   2535:
                   2536:    cursor_save = curwin->w_cursor;
                   2537:    if ((trypos = findmatchlimit('(', 0, ind_maxparen)) != NULL)
                   2538:    {
                   2539:        if (iscomment(skipwhite(ml_get(trypos->lnum))))
                   2540:            trypos = NULL;
                   2541:        else
                   2542:        {
                   2543:            pos_copy = *trypos;     /* copy trypos, findmatch will change it */
                   2544:            trypos = &pos_copy;
                   2545:            curwin->w_cursor = *trypos;
                   2546:            if (find_start_comment(ind_maxcomment) != NULL) /* XXX */
                   2547:                trypos = NULL;
                   2548:        }
                   2549:    }
                   2550:    curwin->w_cursor = cursor_save;
                   2551:    return trypos;
                   2552: }
                   2553:
                   2554: /*
                   2555:  * Set w_cursor.col to the column number of the last ')' in line "l".
                   2556:  */
                   2557:    static int
                   2558: find_last_paren(l)
                   2559:    char_u *l;
                   2560: {
                   2561:    int     i;
                   2562:    int     retval = FALSE;
                   2563:
                   2564:    curwin->w_cursor.col = 0;               /* default is start of line */
                   2565:
                   2566:    for (i = 0; l[i]; i++)
                   2567:    {
                   2568:        i = skip_string(l + i) - l;         /* ignore parens in quotes */
                   2569:        if (l[i] == ')')
                   2570:        {
                   2571:            curwin->w_cursor.col = i;
                   2572:            retval = TRUE;
                   2573:        }
                   2574:    }
                   2575:    return retval;
                   2576: }
                   2577:
                   2578:    int
                   2579: get_c_indent()
                   2580: {
                   2581:    /*
                   2582:     * spaces from a block's opening brace the prevailing indent for that
                   2583:     * block should be
                   2584:     */
                   2585:    int ind_level = curbuf->b_p_sw;
                   2586:
                   2587:    /*
                   2588:     * spaces from the edge of the line an open brace that's at the end of a
                   2589:     * line is imagined to be.
                   2590:     */
                   2591:    int ind_open_imag = 0;
                   2592:
                   2593:    /*
                   2594:     * spaces from the prevailing indent for a line that is not precededof by
                   2595:     * an opening brace.
                   2596:     */
                   2597:    int ind_no_brace = 0;
                   2598:
                   2599:    /*
                   2600:     * column where the first { of a function should be located
                   2601:     */
                   2602:    int ind_first_open = 0;
                   2603:
                   2604:    /*
                   2605:     * spaces from the prevailing indent a leftmost open brace should be
                   2606:     * located
                   2607:     */
                   2608:    int ind_open_extra = 0;
                   2609:
                   2610:    /*
                   2611:     * spaces from the matching open brace (real location for one at the left
                   2612:     * edge; imaginary location from one that ends a line) the matching close
                   2613:     * brace should be located
                   2614:     */
                   2615:    int ind_close_extra = 0;
                   2616:
                   2617:    /*
                   2618:     * spaces from the edge of the line an open brace sitting in the leftmost
                   2619:     * column is imagined to be
                   2620:     */
                   2621:    int ind_open_left_imag = 0;
                   2622:
                   2623:    /*
                   2624:     * spaces from the switch() indent a "case xx" label should be located
                   2625:     */
                   2626:    int ind_case = curbuf->b_p_sw;
                   2627:
                   2628:    /*
                   2629:     * spaces from the "case xx:" code after a switch() should be located
                   2630:     */
                   2631:    int ind_case_code = curbuf->b_p_sw;
                   2632:
                   2633:    /*
                   2634:     * amount K&R-style parameters should be indented
                   2635:     */
                   2636:    int ind_param = curbuf->b_p_sw;
                   2637:
                   2638:    /*
                   2639:     * amount a function type spec should be indented
                   2640:     */
                   2641:    int ind_func_type = curbuf->b_p_sw;
                   2642:
                   2643:    /*
                   2644:     * additional spaces beyond the prevailing indent a continuation line
                   2645:     * should be located
                   2646:     */
                   2647:    int ind_continuation = curbuf->b_p_sw;
                   2648:
                   2649:    /*
                   2650:     * spaces from the indent of the line with an unclosed parentheses
                   2651:     */
                   2652:    int ind_unclosed = curbuf->b_p_sw * 2;
                   2653:
                   2654:    /*
                   2655:     * spaces from the comment opener when there is nothing after it.
                   2656:     */
                   2657:    int ind_in_comment = 3;
                   2658:
                   2659:    /*
                   2660:     * max lines to search for an open paren
                   2661:     */
                   2662:    int ind_maxparen = 20;
                   2663:
                   2664:    /*
                   2665:     * max lines to search for an open comment
                   2666:     */
                   2667:    int ind_maxcomment = 30;
                   2668:
                   2669:    FPOS        cur_curpos;
                   2670:    int         amount;
                   2671:    int         scope_amount;
                   2672:    int         cur_amount;
                   2673:    colnr_t     col;
                   2674:    char_u      *theline;
                   2675:    char_u      *linecopy;
                   2676:    FPOS        *trypos;
                   2677:    FPOS        our_paren_pos;
                   2678:    char_u      *start;
                   2679:    int         start_brace;
                   2680: #define BRACE_IN_COL0  1           /* '{' is in comumn 0 */
                   2681: #define BRACE_AT_START 2           /* '{' is at start of line */
                   2682: #define BRACE_AT_END   3           /* '{' is at end of line */
                   2683:    linenr_t    ourscope;
                   2684:    char_u      *l;
                   2685:    char_u      *look;
                   2686:    int         lookfor;
                   2687: #define LOOKFOR_IF     1
                   2688: #define LOOKFOR_DO     2
                   2689: #define LOOKFOR_CASE   3
                   2690: #define LOOKFOR_ANY        4
                   2691: #define LOOKFOR_TERM   5
                   2692: #define LOOKFOR_UNTERM 6
                   2693:    int         whilelevel;
                   2694:    linenr_t    lnum;
                   2695:    char_u      *options;
                   2696:    int         fraction = 0;       /* init for GCC */
                   2697:    int         divider;
                   2698:    int         n;
                   2699:
                   2700:    for (options = curbuf->b_p_cino; *options; )
                   2701:    {
                   2702:        l = options++;
                   2703:        if (*options == '-')
                   2704:            ++options;
                   2705:        n = getdigits(&options);
                   2706:        divider = 0;
                   2707:        if (*options == '.')        /* ".5s" means a fraction */
                   2708:        {
                   2709:            fraction = atol((char *)++options);
                   2710:            while (isdigit(*options))
                   2711:            {
                   2712:                ++options;
                   2713:                if (divider)
                   2714:                    divider *= 10;
                   2715:                else
                   2716:                    divider = 10;
                   2717:            }
                   2718:        }
                   2719:        if (*options == 's')        /* "2s" means two times 'shiftwidth' */
                   2720:        {
                   2721:            if (n == 0 && fraction == 0)
                   2722:                n = curbuf->b_p_sw;     /* just "s" is one 'shiftwidth' */
                   2723:            else
                   2724:            {
                   2725:                n *= curbuf->b_p_sw;
                   2726:                if (divider)
                   2727:                    n += (curbuf->b_p_sw * fraction + divider / 2) / divider;
                   2728:            }
                   2729:            ++options;
                   2730:        }
                   2731:        if (l[1] == '-')
                   2732:            n = -n;
                   2733:        switch (*l)
                   2734:        {
                   2735:            case '>': ind_level = n; break;
                   2736:            case 'e': ind_open_imag = n; break;
                   2737:            case 'n': ind_no_brace = n; break;
                   2738:            case 'f': ind_first_open = n; break;
                   2739:            case '{': ind_open_extra = n; break;
                   2740:            case '}': ind_close_extra = n; break;
                   2741:            case '^': ind_open_left_imag = n; break;
                   2742:            case ':': ind_case = n; break;
                   2743:            case '=': ind_case_code = n; break;
                   2744:            case 'p': ind_param = n; break;
                   2745:            case 't': ind_func_type = n; break;
                   2746:            case 'c': ind_in_comment = n; break;
                   2747:            case '+': ind_continuation = n; break;
                   2748:            case '(': ind_unclosed = n; break;
                   2749:            case ')': ind_maxparen = n; break;
                   2750:            case '*': ind_maxcomment = n; break;
                   2751:        }
                   2752:    }
                   2753:
                   2754:    /* remember where the cursor was when we started */
                   2755:
                   2756:    cur_curpos = curwin->w_cursor;
                   2757:
                   2758:    /* get the current contents of the line.
                   2759:     * This is required, because onle the most recent line obtained with
                   2760:     * ml_get is valid! */
                   2761:
                   2762:    linecopy = strsave(ml_get(cur_curpos.lnum));
                   2763:    if (linecopy == NULL)
                   2764:        return 0;
                   2765:
                   2766:    /*
                   2767:     * In insert mode and the cursor is on a ')' trunctate the line at the
                   2768:     * cursor position.  We don't want to line up with the matching '(' when
                   2769:     * inserting new stuff.
                   2770:     */
                   2771:    if ((State & INSERT) && linecopy[curwin->w_cursor.col] == ')')
                   2772:        linecopy[curwin->w_cursor.col] = NUL;
                   2773:
                   2774:    theline = skipwhite(linecopy);
                   2775:
                   2776:    /* move the cursor to the start of the line */
                   2777:
                   2778:    curwin->w_cursor.col = 0;
                   2779:
                   2780:    /*
                   2781:     * #defines and so on always go at the left when included in 'cinkeys'.
                   2782:     */
                   2783:    if (*theline == '#' && (*linecopy == '#' || in_cinkeys('#', ' ', TRUE)))
                   2784:    {
                   2785:        amount = 0;
                   2786:    }
                   2787:
                   2788:    /*
                   2789:     * Is it a non-case label?  Then that goes at the left margin too.
                   2790:     */
                   2791:    else if (islabel(ind_maxcomment))       /* XXX */
                   2792:    {
                   2793:        amount = 0;
                   2794:    }
                   2795:
                   2796:    /*
                   2797:     * If we're inside a comment and not looking at the start of the
                   2798:     * comment...
                   2799:     */
                   2800:    else if (!iscomment(theline) &&
                   2801:              (trypos = find_start_comment(ind_maxcomment)) != NULL) /* XXX */
                   2802:    {
                   2803:
                   2804:        /* find how indented the line beginning the comment is */
                   2805:        getvcol(curwin, trypos, &col, NULL, NULL);
                   2806:        amount = col;
                   2807:
                   2808:        /* if our line starts with an asterisk, line up with the
                   2809:         * asterisk in the comment opener; otherwise, line up
                   2810:         * with the first character of the comment text.
                   2811:         */
                   2812:        if (theline[0] == '*')
                   2813:        {
                   2814:            amount += 1;
                   2815:        }
                   2816:        else
                   2817:        {
                   2818:            /*
                   2819:             * If we are more than one line away from the comment opener, take
                   2820:             * the indent of the previous non-empty line.
                   2821:             * If we are just below the comment opener and there are any
                   2822:             * white characters after it line up with the text after it.
                   2823:             * up with them; otherwise, just use a single space.
                   2824:             */
                   2825:            amount = -1;
                   2826:            for (lnum = cur_curpos.lnum - 1; lnum > trypos->lnum; --lnum)
                   2827:            {
                   2828:                if (linewhite(lnum))                /* skip blank lines */
                   2829:                    continue;
                   2830:                amount = get_indent_lnum(lnum);     /* XXX */
                   2831:                break;
                   2832:            }
                   2833:            if (amount == -1)                       /* use the comment opener */
                   2834:            {
                   2835:                start = ml_get(trypos->lnum);
                   2836:                look = start + trypos->col + 2;     /* skip / and * */
                   2837:                if (*look)                          /* if something after it */
                   2838:                    trypos->col = skipwhite(look) - start;
                   2839:                getvcol(curwin, trypos, &col, NULL, NULL);
                   2840:                amount = col;
                   2841:                if (!*look)
                   2842:                    amount += ind_in_comment;
                   2843:            }
                   2844:        }
                   2845:    }
                   2846:
                   2847:    /*
                   2848:     * Are we inside parentheses?
                   2849:     */                                             /* XXX */
                   2850:    else if ((trypos = find_match_paren(ind_maxparen, ind_maxcomment)) != NULL)
                   2851:    {
                   2852:        /*
                   2853:         * If the matching paren is more than one line away, use the indent of
                   2854:         * a previous non-empty line that matches the same paren.
                   2855:         */
                   2856:        amount = -1;
                   2857:        our_paren_pos = *trypos;
                   2858:        if (theline[0] != ')')
                   2859:        {
                   2860:            for (lnum = cur_curpos.lnum - 1; lnum > our_paren_pos.lnum; --lnum)
                   2861:            {
                   2862:                l = skipwhite(ml_get(lnum));
                   2863:                if (commentorempty(l))      /* skip comment lines */
                   2864:                    continue;
                   2865:                if (ispreproc(l))           /* ignore #defines, #if, etc. */
                   2866:                    continue;
                   2867:                curwin->w_cursor.lnum = lnum;
                   2868:                /* XXX */
                   2869:                if ((trypos = find_match_paren(ind_maxparen,
                   2870:                                                   ind_maxcomment)) != NULL &&
                   2871:                                         trypos->lnum == our_paren_pos.lnum &&
                   2872:                                             trypos->col == our_paren_pos.col)
                   2873:                {
                   2874:                    amount = get_indent_lnum(lnum);     /* XXX */
                   2875:                    break;
                   2876:                }
                   2877:            }
                   2878:        }
                   2879:
                   2880:        /*
                   2881:         * Line up with line where the matching paren is.
                   2882:         * If the line starts with a '(' or the indent for unclosed
                   2883:         * parentheses is zero, line up with the unclosed parentheses.
                   2884:         */
                   2885:        if (amount == -1)
                   2886:        {
                   2887:            amount = skip_label(our_paren_pos.lnum, &look, ind_maxcomment);
                   2888:            if (theline[0] == ')' || ind_unclosed == 0 ||
                   2889:                                                      *skipwhite(look) == '(')
                   2890:            {
                   2891:
                   2892:                /*
                   2893:                 * If we're looking at a close paren, line up right there;
                   2894:                 * otherwise, line up with the next non-white character.
                   2895:                 */
                   2896:                if (theline[0] != ')')
                   2897:                {
                   2898:                    col = our_paren_pos.col + 1;
                   2899:                    look = ml_get(our_paren_pos.lnum);
                   2900:                    while (vim_iswhite(look[col]))
                   2901:                        col++;
                   2902:                    if (look[col] != NUL)       /* In case of trailing space */
                   2903:                        our_paren_pos.col = col;
                   2904:                    else
                   2905:                        our_paren_pos.col++;
                   2906:                }
                   2907:
                   2908:                /*
                   2909:                 * Find how indented the paren is, or the character after it if
                   2910:                 * we did the above "if".
                   2911:                 */
                   2912:                getvcol(curwin, &our_paren_pos, &col, NULL, NULL);
                   2913:                amount = col;
                   2914:            }
                   2915:            else
                   2916:                amount += ind_unclosed;
                   2917:        }
                   2918:    }
                   2919:
                   2920:    /*
                   2921:     * Are we at least inside braces, then?
                   2922:     */
                   2923:    else if ((trypos = find_start_brace(ind_maxcomment)) != NULL) /* XXX */
                   2924:    {
                   2925:        ourscope = trypos->lnum;
                   2926:        start = ml_get(ourscope);
                   2927:
                   2928:        /*
                   2929:         * Now figure out how indented the line is in general.
                   2930:         * If the brace was at the start of the line, we use that;
                   2931:         * otherwise, check out the indentation of the line as
                   2932:         * a whole and then add the "imaginary indent" to that.
                   2933:         */
                   2934:        look = skipwhite(start);
                   2935:        if (*look == '{')
                   2936:        {
                   2937:            getvcol(curwin, trypos, &col, NULL, NULL);
                   2938:            amount = col;
                   2939:            if (*start == '{')
                   2940:                start_brace = BRACE_IN_COL0;
                   2941:            else
                   2942:                start_brace = BRACE_AT_START;
                   2943:        }
                   2944:        else
                   2945:        {
                   2946:            /*
                   2947:             * that opening brace might have been on a continuation
                   2948:             * line.  if so, find the start of the line.
                   2949:             */
                   2950:            curwin->w_cursor.lnum = ourscope;
                   2951:
                   2952:            /*
                   2953:             * position the cursor over the rightmost paren, so that
                   2954:             * matching it will take us back to the start of the line.
                   2955:             */
                   2956:            lnum = ourscope;
                   2957:            if (find_last_paren(start) &&
                   2958:                    (trypos = find_match_paren(ind_maxparen,
                   2959:                                                     ind_maxcomment)) != NULL)
                   2960:                lnum = trypos->lnum;
                   2961:
                   2962:            /*
                   2963:             * It could have been something like
                   2964:             *     case 1: if (asdf &&
                   2965:             *                  ldfd) {
                   2966:             *              }
                   2967:             */
                   2968:            amount = skip_label(lnum, &l, ind_maxcomment);
                   2969:
                   2970:            start_brace = BRACE_AT_END;
                   2971:        }
                   2972:
                   2973:        /*
                   2974:         * if we're looking at a closing brace, that's where
                   2975:         * we want to be.  otherwise, add the amount of room
                   2976:         * that an indent is supposed to be.
                   2977:         */
                   2978:        if (theline[0] == '}')
                   2979:        {
                   2980:            /*
                   2981:             * they may want closing braces to line up with something
                   2982:             * other than the open brace.  indulge them, if so.
                   2983:             */
                   2984:            amount += ind_close_extra;
                   2985:        }
                   2986:        else
                   2987:        {
                   2988:            /*
                   2989:             * If we're looking at an "else", try to find an "if"
                   2990:             * to match it with.
                   2991:             * If we're looking at a "while", try to find a "do"
                   2992:             * to match it with.
                   2993:             */
                   2994:            lookfor = 0;
                   2995:            if (iselse(theline))
                   2996:                lookfor = LOOKFOR_IF;
                   2997:            else if (iswhileofdo(theline, cur_curpos.lnum, ind_maxparen))
                   2998:                                                                    /* XXX */
                   2999:                lookfor = LOOKFOR_DO;
                   3000:            if (lookfor)
                   3001:            {
                   3002:                curwin->w_cursor.lnum = cur_curpos.lnum;
                   3003:                if (find_match(lookfor, ourscope, ind_maxparen,
                   3004:                                                        ind_maxcomment) == OK)
                   3005:                {
                   3006:                    amount = get_indent();      /* XXX */
                   3007:                    goto theend;
                   3008:                }
                   3009:            }
                   3010:
                   3011:            /*
                   3012:             * We get here if we are not on an "while-of-do" or "else" (or
                   3013:             * failed to find a matching "if").
                   3014:             * Search backwards for something to line up with.
                   3015:             * First set amount for when we don't find anything.
                   3016:             */
                   3017:
                   3018:            /*
                   3019:             * if the '{' is  _really_ at the left margin, use the imaginary
                   3020:             * location of a left-margin brace.  Otherwise, correct the
                   3021:             * location for ind_open_extra.
                   3022:             */
                   3023:
                   3024:            if (start_brace == BRACE_IN_COL0)       /* '{' is in column 0 */
                   3025:            {
                   3026:                amount = ind_open_left_imag;
                   3027:            }
                   3028:            else
                   3029:            {
                   3030:                if (start_brace == BRACE_AT_END)    /* '{' is at end of line */
                   3031:                    amount += ind_open_imag;
                   3032:                else
                   3033:                {
                   3034:                    amount -= ind_open_extra;
                   3035:                    if (amount < 0)
                   3036:                        amount = 0;
                   3037:                }
                   3038:            }
                   3039:
                   3040:            if (iscase(theline))        /* it's a switch() label */
                   3041:            {
                   3042:                lookfor = LOOKFOR_CASE; /* find a previous switch() label */
                   3043:                amount += ind_case;
                   3044:            }
                   3045:            else
                   3046:            {
                   3047:                lookfor = LOOKFOR_ANY;
                   3048:                amount += ind_level;    /* ind_level from start of block */
                   3049:            }
                   3050:            scope_amount = amount;
                   3051:            whilelevel = 0;
                   3052:
                   3053:            /*
                   3054:             * Search backwards.  If we find something we recognize, line up
                   3055:             * with that.
                   3056:             *
                   3057:             * if we're looking at an open brace, indent
                   3058:             * the usual amount relative to the conditional
                   3059:             * that opens the block.
                   3060:             */
                   3061:            curwin->w_cursor = cur_curpos;
                   3062:            for (;;)
                   3063:            {
                   3064:                curwin->w_cursor.lnum--;
                   3065:                curwin->w_cursor.col = 0;
                   3066:
                   3067:                /*
                   3068:                 * If we went all the way back to the start of our scope, line
                   3069:                 * up with it.
                   3070:                 */
                   3071:                if (curwin->w_cursor.lnum <= ourscope)
                   3072:                {
                   3073:                    if (lookfor == LOOKFOR_UNTERM)
                   3074:                        amount += ind_continuation;
                   3075:                    else if (lookfor != LOOKFOR_TERM)
                   3076:                        amount = scope_amount;
                   3077:                    break;
                   3078:                }
                   3079:
                   3080:                /*
                   3081:                 * If we're in a comment now, skip to the start of the comment.
                   3082:                 */                                         /* XXX */
                   3083:                if ((trypos = find_start_comment(ind_maxcomment)) != NULL)
                   3084:                {
                   3085:                    curwin->w_cursor.lnum = trypos->lnum + 1;
                   3086:                    continue;
                   3087:                }
                   3088:
                   3089:                l = ml_get_curline();
                   3090:
                   3091:                /*
                   3092:                 * If this is a switch() label, may line up relative to that.
                   3093:                 */
                   3094:                if (iscase(l))
                   3095:                {
                   3096:                    /*
                   3097:                     *  case xx:
                   3098:                     *      c = 99 +        <- this indent plus continuation
                   3099:                     *->           here;
                   3100:                     */
                   3101:                    if (lookfor == LOOKFOR_UNTERM)
                   3102:                    {
                   3103:                        amount += ind_continuation;
                   3104:                        break;
                   3105:                    }
                   3106:
                   3107:                    /*
                   3108:                     *  case xx:        <- line up with this case
                   3109:                     *      x = 333;
                   3110:                     *  case yy:
                   3111:                     */
                   3112:                    if (lookfor == LOOKFOR_CASE)
                   3113:                    {
                   3114:                        /*
                   3115:                         * Check that this case label is not for another
                   3116:                         * switch()
                   3117:                         */                                 /* XXX */
                   3118:                        if ((trypos = find_start_brace(ind_maxcomment)) ==
                   3119:                                             NULL || trypos->lnum == ourscope)
                   3120:                        {
                   3121:                            amount = get_indent();      /* XXX */
                   3122:                            break;
                   3123:                        }
                   3124:                        continue;
                   3125:                    }
                   3126:
                   3127:                    n = get_indent_nolabel(curwin->w_cursor.lnum);  /* XXX */
                   3128:
                   3129:                    /*
                   3130:                     *   case xx: if (cond)         <- line up with this if
                   3131:                     *                y = y + 1;
                   3132:                     * ->         s = 99;
                   3133:                     *
                   3134:                     *   case xx:
                   3135:                     *       if (cond)          <- line up with this line
                   3136:                     *           y = y + 1;
                   3137:                     * ->    s = 99;
                   3138:                     */
                   3139:                    if (lookfor == LOOKFOR_TERM)
                   3140:                    {
                   3141:                        if (n)
                   3142:                            amount = n;
                   3143:                        break;
                   3144:                    }
                   3145:
                   3146:                    /*
                   3147:                     *   case xx: x = x + 1;        <- line up with this x
                   3148:                     * ->         y = y + 1;
                   3149:                     *
                   3150:                     *   case xx: if (cond)         <- line up with this if
                   3151:                     * ->              y = y + 1;
                   3152:                     */
                   3153:                    if (n)
                   3154:                    {
                   3155:                        amount = n;
                   3156:                        l = after_label(ml_get_curline());
                   3157:                        if (l != NULL && is_cinword(l))
                   3158:                            amount += ind_level + ind_no_brace;
                   3159:                        break;
                   3160:                    }
                   3161:
                   3162:                    /*
                   3163:                     *   Try to get the indent of a statement before the
                   3164:                     *   switch label.  If nothing is found, line up relative
                   3165:                     *   to the switch label.
                   3166:                     *      break;              <- may line up with this line
                   3167:                     *   case xx:
                   3168:                     * ->   y = 1;
                   3169:                     */
                   3170:                    scope_amount = get_indent() + ind_case_code;    /* XXX */
                   3171:                    lookfor = LOOKFOR_ANY;
                   3172:                    continue;
                   3173:                }
                   3174:
                   3175:                /*
                   3176:                 * Looking for a switch() label, ignore other lines.
                   3177:                 */
                   3178:                if (lookfor == LOOKFOR_CASE)
                   3179:                    continue;
                   3180:
                   3181:                /*
                   3182:                 * Ignore jump labels with nothing after them.
                   3183:                 */
                   3184:                if (islabel(ind_maxcomment))
                   3185:                {
                   3186:                    l = after_label(ml_get_curline());
                   3187:                    if (l == NULL || commentorempty(l))
                   3188:                        continue;
                   3189:                }
                   3190:
                   3191:                /*
                   3192:                 * Ignore #defines, #if, etc.
                   3193:                 * Ignore comment and empty lines.
                   3194:                 * (need to get the line again, islabel() may have unlocked it)
                   3195:                 */
                   3196:                l = ml_get_curline();
                   3197:                if (ispreproc(l) || commentorempty(l))
                   3198:                    continue;
                   3199:
                   3200:                /*
                   3201:                 * What happens next depends on the line being terminated.
                   3202:                 */
                   3203:                if (!isterminated(l))
                   3204:                {
                   3205:                    /*
                   3206:                     * if we're in the middle of a paren thing,
                   3207:                     * go back to the line that starts it so
                   3208:                     * we can get the right prevailing indent
                   3209:                     *     if ( foo &&
                   3210:                     *              bar )
                   3211:                     */
                   3212:                    /*
                   3213:                     * position the cursor over the rightmost paren, so that
                   3214:                     * matching it will take us back to the start of the line.
                   3215:                     */
                   3216:                    (void)find_last_paren(l);
                   3217:                    if ((trypos = find_match_paren(ind_maxparen,
                   3218:                                                     ind_maxcomment)) != NULL)
                   3219:                    {
                   3220:                        /*
                   3221:                         * Check if we are on a case label now.  This is
                   3222:                         * handled above.
                   3223:                         *     case xx:  if ( asdf &&
                   3224:                         *                      asdf)
                   3225:                         */
                   3226:                        curwin->w_cursor.lnum = trypos->lnum;
                   3227:                        l = ml_get_curline();
                   3228:                        if (iscase(l))
                   3229:                        {
                   3230:                            ++curwin->w_cursor.lnum;
                   3231:                            continue;
                   3232:                        }
                   3233:                    }
                   3234:
                   3235:                    /*
                   3236:                     * Get indent and pointer to text for current line,
                   3237:                     * ignoring any jump label.     XXX
                   3238:                     */
                   3239:                    cur_amount = skip_label(curwin->w_cursor.lnum,
                   3240:                                                          &l, ind_maxcomment);
                   3241:
                   3242:                    /*
                   3243:                     * If this is just above the line we are indenting, and it
                   3244:                     * starts with a '{', line it up with this line.
                   3245:                     *          while (not)
                   3246:                     * ->       {
                   3247:                     *          }
                   3248:                     */
                   3249:                    if (lookfor != LOOKFOR_TERM && theline[0] == '{')
                   3250:                    {
                   3251:                        amount = cur_amount + ind_open_extra;
                   3252:                        break;
                   3253:                    }
                   3254:
                   3255:                    /*
                   3256:                     * Check if we are after an "if", "while", etc.
                   3257:                     */
                   3258:                    if (is_cinword(l))
                   3259:                    {
                   3260:                        /*
                   3261:                         * Found an unterminated line after an if (), line up
                   3262:                         * with the last one.
                   3263:                         *   if (cond)
                   3264:                         *          100 +
                   3265:                         * ->           here;
                   3266:                         */
                   3267:                        if (lookfor == LOOKFOR_UNTERM)
                   3268:                        {
                   3269:                            amount += ind_continuation;
                   3270:                            break;
                   3271:                        }
                   3272:
                   3273:                        /*
                   3274:                         * If this is just above the line we are indenting, we
                   3275:                         * are finished.
                   3276:                         *          while (not)
                   3277:                         * ->           here;
                   3278:                         * Otherwise this indent can be used when the line
                   3279:                         * before this is terminated.
                   3280:                         *      yyy;
                   3281:                         *      if (stat)
                   3282:                         *          while (not)
                   3283:                         *              xxx;
                   3284:                         * ->   here;
                   3285:                         */
                   3286:                        amount = cur_amount;
                   3287:                        if (lookfor != LOOKFOR_TERM)
                   3288:                        {
                   3289:                            amount += ind_level + ind_no_brace;
                   3290:                            break;
                   3291:                        }
                   3292:
                   3293:                        /*
                   3294:                         * Special trick: when expecting the while () after a
                   3295:                         * do, line up with the while()
                   3296:                         *     do
                   3297:                         *          x = 1;
                   3298:                         * ->  here
                   3299:                         */
                   3300:                        l = skipwhite(ml_get_curline());
                   3301:                        if (isdo(l))
                   3302:                        {
                   3303:                            if (whilelevel == 0)
                   3304:                                break;
                   3305:                            --whilelevel;
                   3306:                        }
                   3307:
                   3308:                        /*
                   3309:                         * When searching for a terminated line, don't use the
                   3310:                         * one between the "if" and the "else".
                   3311:                         */
                   3312:                        if (iselse(l))
                   3313:                        {
                   3314:                            if (find_match(LOOKFOR_IF, ourscope,
                   3315:                                        ind_maxparen, ind_maxcomment) == FAIL)
                   3316:                                break;
                   3317:                        }
                   3318:                    }
                   3319:
                   3320:                    /*
                   3321:                     * If we're below an unterminated line that is not an
                   3322:                     * "if" or something, we may line up with this line or
                   3323:                     * add someting for a continuation line, depending on
                   3324:                     * the line before this one.
                   3325:                     */
                   3326:                    else
                   3327:                    {
                   3328:                        /*
                   3329:                         * Found two unterminated lines on a row, line up with
                   3330:                         * the last one.
                   3331:                         *   c = 99 +
                   3332:                         *          100 +
                   3333:                         * ->       here;
                   3334:                         */
                   3335:                        if (lookfor == LOOKFOR_UNTERM)
                   3336:                            break;
                   3337:
                   3338:                        /*
                   3339:                         * Found first unterminated line on a row, may line up
                   3340:                         * with this line, remember its indent
                   3341:                         *          100 +
                   3342:                         * ->       here;
                   3343:                         */
                   3344:                        amount = cur_amount;
                   3345:                        if (lookfor != LOOKFOR_TERM)
                   3346:                            lookfor = LOOKFOR_UNTERM;
                   3347:                    }
                   3348:                }
                   3349:
                   3350:                /*
                   3351:                 * Check if we are after a while (cond);
                   3352:                 * If so: Ignore the matching "do".
                   3353:                 */
                   3354:                                                        /* XXX */
                   3355:                else if (iswhileofdo(l, curwin->w_cursor.lnum, ind_maxparen))
                   3356:                {
                   3357:                    /*
                   3358:                     * Found an unterminated line after a while ();, line up
                   3359:                     * with the last one.
                   3360:                     *      while (cond);
                   3361:                     *      100 +               <- line up with this one
                   3362:                     * ->           here;
                   3363:                     */
                   3364:                    if (lookfor == LOOKFOR_UNTERM)
                   3365:                    {
                   3366:                        amount += ind_continuation;
                   3367:                        break;
                   3368:                    }
                   3369:
                   3370:                    if (whilelevel == 0)
                   3371:                    {
                   3372:                        lookfor = LOOKFOR_TERM;
                   3373:                        amount = get_indent();      /* XXX */
                   3374:                        if (theline[0] == '{')
                   3375:                            amount += ind_open_extra;
                   3376:                    }
                   3377:                    ++whilelevel;
                   3378:                }
                   3379:
                   3380:                /*
                   3381:                 * We are after a "normal" statement.
                   3382:                 * If we had another statement we can stop now and use the
                   3383:                 * indent of that other statement.
                   3384:                 * Otherwise the indent of the current statement may be used,
                   3385:                 * search backwards for the next "normal" statement.
                   3386:                 */
                   3387:                else
                   3388:                {
                   3389:                    /*
                   3390:                     * Found a terminated line above an unterminated line. Add
                   3391:                     * the amount for a continuation line.
                   3392:                     *   x = 1;
                   3393:                     *   y = foo +
                   3394:                     * ->       here;
                   3395:                     */
                   3396:                    if (lookfor == LOOKFOR_UNTERM)
                   3397:                    {
                   3398:                        amount += ind_continuation;
                   3399:                        break;
                   3400:                    }
                   3401:
                   3402:                    /*
                   3403:                     * Found a terminated line above a terminated line or "if"
                   3404:                     * etc. line. Use the amount of the line below us.
                   3405:                     *   x = 1;                         x = 1;
                   3406:                     *   if (asdf)                  y = 2;
                   3407:                     *       while (asdf)         ->here;
                   3408:                     *          here;
                   3409:                     * ->foo;
                   3410:                     */
                   3411:                    if (lookfor == LOOKFOR_TERM)
                   3412:                    {
                   3413:                        if (whilelevel == 0)
                   3414:                            break;
                   3415:                    }
                   3416:
                   3417:                    /*
                   3418:                     * First line above the one we're indenting is terminated.
                   3419:                     * To know what needs to be done look further backward for
                   3420:                     * a terminated line.
                   3421:                     */
                   3422:                    else
                   3423:                    {
                   3424:                        /*
                   3425:                         * position the cursor over the rightmost paren, so
                   3426:                         * that matching it will take us back to the start of
                   3427:                         * the line.  Helps for:
                   3428:                         *     func(asdr,
                   3429:                         *            asdfasdf);
                   3430:                         *     here;
                   3431:                         */
                   3432:                        l = ml_get_curline();
                   3433:                        if (find_last_paren(l) &&
                   3434:                                (trypos = find_match_paren(ind_maxparen,
                   3435:                                                     ind_maxcomment)) != NULL)
                   3436:                        {
                   3437:                            /*
                   3438:                             * Check if we are on a case label now.  This is
                   3439:                             * handled above.
                   3440:                             *     case xx:  if ( asdf &&
                   3441:                             *                      asdf)
                   3442:                             */
                   3443:                            curwin->w_cursor.lnum = trypos->lnum;
                   3444:                            l = ml_get_curline();
                   3445:                            if (iscase(l))
                   3446:                            {
                   3447:                                ++curwin->w_cursor.lnum;
                   3448:                                continue;
                   3449:                            }
                   3450:                        }
                   3451:
                   3452:                        /*
                   3453:                         * Get indent and pointer to text for current line,
                   3454:                         * ignoring any jump label.
                   3455:                         */
                   3456:                        amount = skip_label(curwin->w_cursor.lnum,
                   3457:                                                          &l, ind_maxcomment);
                   3458:
                   3459:                        if (theline[0] == '{')
                   3460:                            amount += ind_open_extra;
                   3461:                        lookfor = LOOKFOR_TERM;
                   3462:
                   3463:                        /*
                   3464:                         * If we're at the end of a block, skip to the start of
                   3465:                         * that block.
                   3466:                         */
                   3467:                        if (*skipwhite(l) == '}' &&
                   3468:                                   (trypos = find_start_brace(ind_maxcomment))
                   3469:                                                            != NULL) /* XXX */
                   3470:                            curwin->w_cursor.lnum = trypos->lnum;
                   3471:                    }
                   3472:                }
                   3473:            }
                   3474:        }
                   3475:    }
                   3476:
                   3477:    /*
                   3478:     * ok -- we're not inside any sort of structure at all!
                   3479:     *
                   3480:     * this means we're at the top level, and everything should
                   3481:     * basically just match where the previous line is, except
                   3482:     * for the lines immediately following a function declaration,
                   3483:     * which are K&R-style parameters and need to be indented.
                   3484:     */
                   3485:    else
                   3486:    {
                   3487:        /*
                   3488:         * if our line starts with an open brace, forget about any
                   3489:         * prevailing indent and make sure it looks like the start
                   3490:         * of a function
                   3491:         */
                   3492:
                   3493:        if (theline[0] == '{')
                   3494:        {
                   3495:            amount = ind_first_open;
                   3496:        }
                   3497:
                   3498:        /*
                   3499:         * If the NEXT line is a function declaration, the current
                   3500:         * line needs to be indented as a function type spec.
                   3501:         * Don't do this if the current line looks like a comment.
                   3502:         */
                   3503:        else if (cur_curpos.lnum < curbuf->b_ml.ml_line_count &&
                   3504:                                                   !commentorempty(theline) &&
                   3505:                                      isfuncdecl(ml_get(cur_curpos.lnum + 1)))
                   3506:        {
                   3507:            amount = ind_func_type;
                   3508:        }
                   3509:        else
                   3510:        {
                   3511:            amount = 0;
                   3512:            curwin->w_cursor = cur_curpos;
                   3513:
                   3514:            /* search backwards until we find something we recognize */
                   3515:
                   3516:            while (curwin->w_cursor.lnum > 1)
                   3517:            {
                   3518:                curwin->w_cursor.lnum--;
                   3519:                curwin->w_cursor.col = 0;
                   3520:
                   3521:                l = ml_get_curline();
                   3522:
                   3523:                /*
                   3524:                 * If we're in a comment now, skip to the start of the comment.
                   3525:                 */                                             /* XXX */
                   3526:                if ((trypos = find_start_comment(ind_maxcomment)) != NULL)
                   3527:                {
                   3528:                    curwin->w_cursor.lnum = trypos->lnum + 1;
                   3529:                    continue;
                   3530:                }
                   3531:
                   3532:                /*
                   3533:                 * If the line looks like a function declaration, and we're
                   3534:                 * not in a comment, put it the left margin.
                   3535:                 */
                   3536:                if (isfuncdecl(theline))
                   3537:                    break;
                   3538:
                   3539:                /*
                   3540:                 * Skip preprocessor directives and blank lines.
                   3541:                 */
                   3542:                if (ispreproc(l))
                   3543:                    continue;
                   3544:
                   3545:                if (commentorempty(l))
                   3546:                    continue;
                   3547:
                   3548:                /*
                   3549:                 * If the PREVIOUS line is a function declaration, the current
                   3550:                 * line (and the ones that follow) needs to be indented as
                   3551:                 * parameters.
                   3552:                 */
                   3553:                if (isfuncdecl(l))
                   3554:                {
                   3555:                    amount = ind_param;
                   3556:                    break;
                   3557:                }
                   3558:
                   3559:                /*
                   3560:                 * Doesn't look like anything interesting -- so just
                   3561:                 * use the indent of this line.
                   3562:                 *
                   3563:                 * Position the cursor over the rightmost paren, so that
                   3564:                 * matching it will take us back to the start of the line.
                   3565:                 */
                   3566:                find_last_paren(l);
                   3567:
                   3568:                if ((trypos = find_match_paren(ind_maxparen,
                   3569:                                                     ind_maxcomment)) != NULL)
                   3570:                    curwin->w_cursor.lnum = trypos->lnum;
                   3571:                amount = get_indent();      /* XXX */
                   3572:                break;
                   3573:            }
                   3574:        }
                   3575:    }
                   3576:
                   3577: theend:
                   3578:    /* put the cursor back where it belongs */
                   3579:    curwin->w_cursor = cur_curpos;
                   3580:
                   3581:    vim_free(linecopy);
                   3582:
                   3583:    if (amount < 0)
                   3584:        return 0;
                   3585:    return amount;
                   3586: }
                   3587:
                   3588:    static int
                   3589: find_match(lookfor, ourscope, ind_maxparen, ind_maxcomment)
                   3590:    int         lookfor;
                   3591:    linenr_t    ourscope;
                   3592:    int         ind_maxparen;
                   3593:    int         ind_maxcomment;
                   3594: {
                   3595:    char_u      *look;
                   3596:    FPOS        *theirscope;
                   3597:    char_u      *mightbeif;
                   3598:    int         elselevel;
                   3599:    int         whilelevel;
                   3600:
                   3601:    if (lookfor == LOOKFOR_IF)
                   3602:    {
                   3603:        elselevel = 1;
                   3604:        whilelevel = 0;
                   3605:    }
                   3606:    else
                   3607:    {
                   3608:        elselevel = 0;
                   3609:        whilelevel = 1;
                   3610:    }
                   3611:
                   3612:    curwin->w_cursor.col = 0;
                   3613:
                   3614:    while (curwin->w_cursor.lnum > ourscope + 1)
                   3615:    {
                   3616:        curwin->w_cursor.lnum--;
                   3617:        curwin->w_cursor.col = 0;
                   3618:
                   3619:        look = skipwhite(ml_get_curline());
                   3620:        if (iselse(look) || isif(look) || isdo(look) ||
                   3621:             iswhileofdo(look, curwin->w_cursor.lnum, ind_maxparen))  /* XXX */
                   3622:        {
                   3623:            /*
                   3624:             * if we've gone outside the braces entirely,
                   3625:             * we must be out of scope...
                   3626:             */
                   3627:            theirscope = find_start_brace(ind_maxcomment);  /* XXX */
                   3628:            if (theirscope == NULL)
                   3629:                break;
                   3630:
                   3631:            /*
                   3632:             * and if the brace enclosing this is further
                   3633:             * back than the one enclosing the else, we're
                   3634:             * out of luck too.
                   3635:             */
                   3636:            if (theirscope->lnum < ourscope)
                   3637:                break;
                   3638:
                   3639:            /*
                   3640:             * and if they're enclosed in a *deeper* brace,
                   3641:             * then we can ignore it because it's in a
                   3642:             * different scope...
                   3643:             */
                   3644:            if (theirscope->lnum > ourscope)
                   3645:                continue;
                   3646:
                   3647:            /*
                   3648:             * if it was an "else" (that's not an "else if")
                   3649:             * then we need to go back to another if, so
                   3650:             * increment elselevel
                   3651:             */
                   3652:            look = skipwhite(ml_get_curline());
                   3653:            if (iselse(look))
                   3654:            {
                   3655:                mightbeif = skipwhite(look + 4);
                   3656:                if (!isif(mightbeif))
                   3657:                    ++elselevel;
                   3658:                continue;
                   3659:            }
                   3660:
                   3661:            /*
                   3662:             * if it was a "while" then we need to go back to
                   3663:             * another "do", so increment whilelevel.
                   3664:             */
                   3665:            if (iswhileofdo(look, curwin->w_cursor.lnum, ind_maxparen))/* XXX */
                   3666:            {
                   3667:                ++whilelevel;
                   3668:                continue;
                   3669:            }
                   3670:
                   3671:            /* If it's an "if" decrement elselevel */
                   3672:            look = skipwhite(ml_get_curline());
                   3673:            if (isif(look))
                   3674:            {
                   3675:                elselevel--;
                   3676:                /*
                   3677:                 * When looking for an "if" ignore "while"s that
                   3678:                 * get in the way.
                   3679:                 */
                   3680:                if (elselevel == 0 && lookfor == LOOKFOR_IF)
                   3681:                    whilelevel = 0;
                   3682:            }
                   3683:
                   3684:            /* If it's a "do" decrement whilelevel */
                   3685:            if (isdo(look))
                   3686:                whilelevel--;
                   3687:
                   3688:            /*
                   3689:             * if we've used up all the elses, then
                   3690:             * this must be the if that we want!
                   3691:             * match the indent level of that if.
                   3692:             */
                   3693:            if (elselevel <= 0 && whilelevel <= 0)
                   3694:            {
                   3695:                return OK;
                   3696:            }
                   3697:        }
                   3698:    }
                   3699:    return FAIL;
                   3700: }
                   3701:
                   3702: #endif /* CINDENT */
                   3703:
                   3704: #ifdef LISPINDENT
                   3705:    int
                   3706: get_lisp_indent()
                   3707: {
                   3708:    FPOS        *pos, realpos;
                   3709:    long        amount = 0;
                   3710:    char_u      *that;
                   3711:    colnr_t     col;
                   3712:    colnr_t     maybe;
                   3713:    colnr_t     firsttry;
                   3714:
                   3715:
                   3716:    realpos = curwin->w_cursor;
                   3717:    curwin->w_cursor.col = 0;
                   3718:
                   3719:    if ((pos = findmatch('(')) != NULL)
                   3720:    {
                   3721:        curwin->w_cursor.lnum = pos->lnum;
                   3722:        curwin->w_cursor.col = pos->col;
                   3723:        col = pos->col;
                   3724:
                   3725:        that = ml_get_curline();
                   3726:        maybe = get_indent();       /* XXX */
                   3727:
                   3728:        if (maybe == 0)
                   3729:            amount = 2;
                   3730:        else
                   3731:        {
                   3732:            while (*that && col)
                   3733:            {
                   3734:                amount += lbr_chartabsize(that, (colnr_t)amount);
                   3735:                col--;
                   3736:                that++;
                   3737:            }
                   3738:
                   3739:            that++;
                   3740:            amount++;
                   3741:            firsttry = amount;
                   3742:
                   3743:            /*
                   3744:             * Go to the start of the second word.
                   3745:             * If there is no second word, go back to firsttry.
                   3746:             * Also stop at a '('.
                   3747:             */
                   3748:
                   3749:            while (vim_iswhite(*that))
                   3750:            {
                   3751:                amount += lbr_chartabsize(that, (colnr_t)amount);
                   3752:                that++;
                   3753:            }
                   3754:            while (*that && !vim_iswhite(*that) && *that != '(')
                   3755:            {
                   3756:                amount += lbr_chartabsize(that, (colnr_t)amount);
                   3757:                that++;
                   3758:            }
                   3759:            while (vim_iswhite(*that))
                   3760:            {
                   3761:                amount += lbr_chartabsize(that, (colnr_t)amount);
                   3762:                that++;
                   3763:            }
                   3764:            if (! *that)
                   3765:                amount = firsttry;
                   3766:        }
                   3767:    }
                   3768:    else    /* no matching '(' found, use indent of previous non-empty line */
                   3769:    {
                   3770:        while (curwin->w_cursor.lnum > 1)
                   3771:        {
                   3772:            --curwin->w_cursor.lnum;
                   3773:            if (!linewhite(curwin->w_cursor.lnum))
                   3774:                break;
                   3775:        }
                   3776:        amount = get_indent();      /* XXX */
                   3777:    }
                   3778:
                   3779:    curwin->w_cursor = realpos;
                   3780:
                   3781:    if (amount < 0)
                   3782:        amount = 0;
                   3783:    return (int)amount;
                   3784: }
                   3785: #endif /* LISPINDENT */
                   3786:
                   3787: #if defined(UNIX) || defined(WIN32) || defined(__EMX__)
                   3788: /*
                   3789:  * Preserve files and exit.
                   3790:  * When called IObuff must contain a message.
                   3791:  */
                   3792:    void
                   3793: preserve_exit()
                   3794: {
                   3795:    BUF     *buf;
                   3796:
                   3797: #ifdef USE_GUI
                   3798:    if (gui.in_use)
                   3799:    {
                   3800:        gui.dying = TRUE;
                   3801:        trash_output_buf();     /* trash any pending output */
                   3802:    }
                   3803:    else
                   3804: #endif
                   3805:    {
                   3806:        windgoto((int)Rows - 1, 0);
                   3807:
                   3808:        /*
                   3809:         * Switch terminal mode back now, so these messages end up on the
                   3810:         * "normal" screen (if there are two screens).
                   3811:         */
                   3812:        settmode(0);
                   3813: #ifdef WIN32
                   3814:        if (can_end_termcap_mode(FALSE) == TRUE)
                   3815: #endif
                   3816:            stoptermcap();
                   3817:        flushbuf();
                   3818:    }
                   3819:
                   3820:    outstr(IObuff);
                   3821:    screen_start();                 /* don't know where cursor is now */
                   3822:    flushbuf();
                   3823:
                   3824:    ml_close_notmod();              /* close all not-modified buffers */
                   3825:
                   3826:    for (buf = firstbuf; buf != NULL; buf = buf->b_next)
                   3827:    {
                   3828:        if (buf->b_ml.ml_mfp != NULL && buf->b_ml.ml_mfp->mf_fname != NULL)
                   3829:        {
                   3830:            OUTSTR("Vim: preserving files...\n");
                   3831:            screen_start();         /* don't know where cursor is now */
                   3832:            flushbuf();
                   3833:            ml_sync_all(FALSE, FALSE);  /* preserve all swap files */
                   3834:            break;
                   3835:        }
                   3836:    }
                   3837:
                   3838:    ml_close_all(FALSE);            /* close all memfiles, without deleting */
                   3839:
                   3840:    OUTSTR("Vim: Finished.\n");
                   3841:
                   3842:    getout(1);
                   3843: }
                   3844: #endif /* defined(UNIX) || defined(WIN32) || defined(__EMX__) */
                   3845:
                   3846: /*
                   3847:  * return TRUE if "fname" exists.
                   3848:  */
                   3849:    int
                   3850: vim_fexists(fname)
                   3851:    char_u  *fname;
                   3852: {
                   3853:    struct stat st;
                   3854:
                   3855:    if (stat((char *)fname, &st))
                   3856:        return FALSE;
                   3857:    return TRUE;
                   3858: }
                   3859:
                   3860: /*
                   3861:  * Check for CTRL-C pressed, but only once in a while.
                   3862:  * Should be used instead of mch_breakcheck() for functions that check for
                   3863:  * each line in the file.  Calling mch_breakcheck() each time takes too much
                   3864:  * time, because it can be a system call.
                   3865:  */
                   3866:
                   3867: #ifndef BREAKCHECK_SKIP
                   3868: # define BREAKCHECK_SKIP 32
                   3869: #endif
                   3870:
                   3871:    void
                   3872: line_breakcheck()
                   3873: {
                   3874:    static int  count = 0;
                   3875:
                   3876:    if (++count == BREAKCHECK_SKIP)
                   3877:    {
                   3878:        count = 0;
                   3879:        mch_breakcheck();
                   3880:    }
                   3881: }
                   3882:
                   3883: /*
                   3884:  * Free the list of files returned by ExpandWildCards() or other expansion
                   3885:  * functions.
                   3886:  */
                   3887:    void
                   3888: FreeWild(num, file)
                   3889:    int     num;
                   3890:    char_u  **file;
                   3891: {
                   3892:    if (file == NULL || num == 0)
                   3893:        return;
                   3894: #if defined(__EMX__) && defined(__ALWAYS_HAS_TRAILING_NULL_POINTER) /* XXX */
                   3895:    /*
                   3896:     * Is this still OK for when other functions thatn ExpandWildCards() have
                   3897:     * been used???
                   3898:     */
                   3899:    _fnexplodefree((char **)file);
                   3900: #else
                   3901:    while (num--)
                   3902:        vim_free(file[num]);
                   3903:    vim_free(file);
                   3904: #endif
                   3905: }
                   3906: