Annotation of src/usr.bin/vim/cmdline.c, Revision 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: * cmdline.c: functions for reading in the command line and executing it
! 12: */
! 13:
! 14: #include "vim.h"
! 15: #include "globals.h"
! 16: #include "proto.h"
! 17: #include "option.h"
! 18: #include "cmdtab.h"
! 19: #include "ops.h" /* included because we call functions in ops.c */
! 20: #ifdef HAVE_FCNTL_H
! 21: # include <fcntl.h> /* for chdir() */
! 22: #endif
! 23:
! 24: /*
! 25: * variables shared between getcmdline() and redrawcmdline()
! 26: */
! 27: static char_u *cmdbuff; /* pointer to command line buffer */
! 28: static int cmdbufflen; /* length of cmdbuff */
! 29: static int cmdlen; /* number of chars on command line */
! 30: static int cmdpos; /* current cursor position */
! 31: static int cmdspos; /* cursor column on screen */
! 32: static int cmdfirstc; /* ':', '/' or '?' */
! 33:
! 34: /*
! 35: * Typing mode on the command line. Shared by getcmdline() and
! 36: * put_on_cmdline().
! 37: */
! 38: static int overstrike = FALSE; /* typing mode */
! 39:
! 40: /*
! 41: * The next two variables contain the bounds of any range given in a command.
! 42: * They are set by do_cmdline().
! 43: */
! 44: static linenr_t line1, line2;
! 45:
! 46: static int forceit;
! 47: static int regname;
! 48: static int quitmore = 0;
! 49: static int cmd_numfiles = -1; /* number of files found by
! 50: filename completion */
! 51: /*
! 52: * There are two history tables:
! 53: * 0: colon commands
! 54: * 1: search commands
! 55: */
! 56: static char_u **(history[2]) = {NULL, NULL}; /* history tables */
! 57: static int hisidx[2] = {-1, -1}; /* last entered entry */
! 58: static int hislen = 0; /* actual lengt of history tables */
! 59:
! 60: #ifdef RIGHTLEFT
! 61: static int cmd_hkmap = 0; /* Hebrew mapping during command line */
! 62: #endif
! 63:
! 64: static void init_history __ARGS((void));
! 65:
! 66: static int is_in_history __ARGS((int, char_u *, int));
! 67: static void putcmdline __ARGS((int));
! 68: static void redrawcmd __ARGS((void));
! 69: static void cursorcmd __ARGS((void));
! 70: static int ccheck_abbr __ARGS((int));
! 71: static char_u *do_one_cmd __ARGS((char_u **, int *, int));
! 72: static int buf_write_all __ARGS((BUF *));
! 73: static int do_write __ARGS((char_u *, int));
! 74: static char_u *getargcmd __ARGS((char_u **));
! 75: static void backslash_halve __ARGS((char_u *p, int expand_wildcards));
! 76: static void do_make __ARGS((char_u *));
! 77: static int do_arglist __ARGS((char_u *));
! 78: static int is_backslash __ARGS((char_u *str));
! 79: static int check_readonly __ARGS((void));
! 80: static int check_changed __ARGS((BUF *, int, int));
! 81: static int check_changed_any __ARGS((void));
! 82: static int check_more __ARGS((int));
! 83: static void vim_strncpy __ARGS((char_u *, char_u *, int));
! 84: static int nextwild __ARGS((int));
! 85: static int showmatches __ARGS((char_u *));
! 86: static linenr_t get_address __ARGS((char_u **));
! 87: static void set_expand_context __ARGS((int, char_u *));
! 88: static char_u *set_one_cmd_context __ARGS((int, char_u *));
! 89: static int ExpandFromContext __ARGS((char_u *, int *, char_u ***, int, int));
! 90: static int ExpandCommands __ARGS((regexp *, int *, char_u ***));
! 91:
! 92: /*
! 93: * init_history() - initialize the command line history
! 94: */
! 95: static void
! 96: init_history()
! 97: {
! 98: int newlen; /* new length of history table */
! 99: char_u **temp;
! 100: register int i;
! 101: int j;
! 102: int type;
! 103:
! 104: /*
! 105: * If size of history table changed, reallocate it
! 106: */
! 107: newlen = (int)p_hi;
! 108: if (newlen != hislen) /* history length changed */
! 109: {
! 110: for (type = 0; type <= 1; ++type) /* adjust both history tables */
! 111: {
! 112: if (newlen)
! 113: temp = (char_u **)lalloc((long_u)(newlen * sizeof(char_u *)),
! 114: TRUE);
! 115: else
! 116: temp = NULL;
! 117: if (newlen == 0 || temp != NULL)
! 118: {
! 119: if (hisidx[type] < 0) /* there are no entries yet */
! 120: {
! 121: for (i = 0; i < newlen; ++i)
! 122: temp[i] = NULL;
! 123: }
! 124: else if (newlen > hislen) /* array becomes bigger */
! 125: {
! 126: for (i = 0; i <= hisidx[type]; ++i)
! 127: temp[i] = history[type][i];
! 128: j = i;
! 129: for ( ; i <= newlen - (hislen - hisidx[type]); ++i)
! 130: temp[i] = NULL;
! 131: for ( ; j < hislen; ++i, ++j)
! 132: temp[i] = history[type][j];
! 133: }
! 134: else /* array becomes smaller or 0 */
! 135: {
! 136: j = hisidx[type];
! 137: for (i = newlen - 1; ; --i)
! 138: {
! 139: if (i >= 0) /* copy newest entries */
! 140: temp[i] = history[type][j];
! 141: else /* remove older entries */
! 142: vim_free(history[type][j]);
! 143: if (--j < 0)
! 144: j = hislen - 1;
! 145: if (j == hisidx[type])
! 146: break;
! 147: }
! 148: hisidx[type] = newlen - 1;
! 149: }
! 150: vim_free(history[type]);
! 151: history[type] = temp;
! 152: }
! 153: }
! 154: hislen = newlen;
! 155: }
! 156: }
! 157:
! 158: /*
! 159: * check if command line 'str' is already in history
! 160: * 'type' is 0 for ':' commands, '1' for search commands
! 161: * if 'move_to_front' is TRUE, matching entry is moved to end of history
! 162: */
! 163: static int
! 164: is_in_history(type, str, move_to_front)
! 165: int type;
! 166: char_u *str;
! 167: int move_to_front; /* Move the entry to the front if it exists */
! 168: {
! 169: int i;
! 170: int last_i = -1;
! 171:
! 172: if (hisidx[type] < 0)
! 173: return FALSE;
! 174: i = hisidx[type];
! 175: do
! 176: {
! 177: if (history[type][i] == NULL)
! 178: return FALSE;
! 179: if (STRCMP(str, history[type][i]) == 0)
! 180: {
! 181: if (!move_to_front)
! 182: return TRUE;
! 183: last_i = i;
! 184: break;
! 185: }
! 186: if (--i < 0)
! 187: i = hislen - 1;
! 188: } while (i != hisidx[type]);
! 189:
! 190: if (last_i >= 0)
! 191: {
! 192: str = history[type][i];
! 193: while (i != hisidx[type])
! 194: {
! 195: if (++i >= hislen)
! 196: i = 0;
! 197: history[type][last_i] = history[type][i];
! 198: last_i = i;
! 199: }
! 200: history[type][i] = str;
! 201: return TRUE;
! 202: }
! 203: return FALSE;
! 204: }
! 205:
! 206: /*
! 207: * Add the given string to the given history. If the string is already in the
! 208: * history then it is moved to the front. histype may be 0 for the ':'
! 209: * history, or 1 for the '/' history.
! 210: */
! 211: void
! 212: add_to_history(histype, new_entry)
! 213: int histype;
! 214: char_u *new_entry;
! 215: {
! 216: if (hislen != 0 && !is_in_history(histype, new_entry, TRUE))
! 217: {
! 218: if (++hisidx[histype] == hislen)
! 219: hisidx[histype] = 0;
! 220: vim_free(history[histype][hisidx[histype]]);
! 221: history[histype][hisidx[histype]] = strsave(new_entry);
! 222: }
! 223: }
! 224:
! 225:
! 226: /*
! 227: * getcmdline() - accept a command line starting with ':', '/', or '?'
! 228: *
! 229: * The line is collected in cmdbuff, which is reallocated to fit the command
! 230: * line.
! 231: *
! 232: * Return pointer to allocated string if there is a commandline, NULL
! 233: * otherwise.
! 234: */
! 235:
! 236: char_u *
! 237: getcmdline(firstc, count)
! 238: int firstc; /* either ':', '/', or '?' */
! 239: long count; /* only used for incremental search */
! 240: {
! 241: register int c;
! 242: #ifdef DIGRAPHS
! 243: int cc;
! 244: #endif
! 245: register int i;
! 246: int j;
! 247: char_u *p;
! 248: int hiscnt; /* current history line in use */
! 249: char_u *lookfor = NULL; /* string to match */
! 250: int gotesc = FALSE; /* TRUE when <ESC> just typed */
! 251: int do_abbr; /* when TRUE check for abbr. */
! 252: int histype; /* history type to be used */
! 253: FPOS old_cursor;
! 254: colnr_t old_curswant;
! 255: int did_incsearch = FALSE;
! 256: int incsearch_postponed = FALSE;
! 257: int save_msg_scroll = msg_scroll;
! 258: int some_key_typed = FALSE; /* one of the keys was typed */
! 259: #ifdef USE_MOUSE
! 260: /* mouse drag and release events are ignored, unless they are
! 261: * preceded with a mouse down event */
! 262: int ignore_drag_release = TRUE;
! 263: #endif
! 264:
! 265: overstrike = FALSE; /* always start in insert mode */
! 266: old_cursor = curwin->w_cursor; /* needs to be restored later */
! 267: old_curswant = curwin->w_curswant;
! 268: /*
! 269: * set some variables for redrawcmd()
! 270: */
! 271: cmdfirstc = firstc;
! 272: alloc_cmdbuff(0); /* allocate initial cmdbuff */
! 273: if (cmdbuff == NULL)
! 274: return NULL; /* out of memory */
! 275: cmdlen = cmdpos = 0;
! 276: cmdspos = 1;
! 277: State = CMDLINE;
! 278: #ifdef USE_MOUSE
! 279: setmouse();
! 280: #endif
! 281: gotocmdline(TRUE);
! 282: msg_outchar(firstc);
! 283: /*
! 284: * Avoid scrolling when called by a recursive do_cmdline(), e.g. when doing
! 285: * ":@0" when register 0 doesn't contain a CR.
! 286: */
! 287: msg_scroll = FALSE;
! 288:
! 289: init_history();
! 290: hiscnt = hislen; /* set hiscnt to impossible history value */
! 291: histype = (firstc == ':' ? 0 : 1);
! 292:
! 293: #ifdef DIGRAPHS
! 294: do_digraph(-1); /* init digraph typahead */
! 295: #endif
! 296:
! 297: /* collect the command string, handling editing keys */
! 298: for (;;)
! 299: {
! 300: cursorcmd(); /* set the cursor on the right spot */
! 301: c = vgetc();
! 302: if (KeyTyped)
! 303: {
! 304: some_key_typed = TRUE;
! 305: #ifdef RIGHTLEFT
! 306: if (cmd_hkmap)
! 307: c = hkmap(c);
! 308: #endif
! 309: }
! 310: if (c == Ctrl('C'))
! 311: got_int = FALSE; /* ignore got_int when CTRL-C was typed here */
! 312:
! 313: /* free old command line when finished moving around in the
! 314: * history list */
! 315: if (lookfor && c != K_S_DOWN && c != K_S_UP &&
! 316: c != K_DOWN && c != K_UP &&
! 317: c != K_PAGEDOWN && c != K_PAGEUP &&
! 318: (cmd_numfiles > 0 || (c != Ctrl('P') && c != Ctrl('N'))))
! 319: {
! 320: vim_free(lookfor);
! 321: lookfor = NULL;
! 322: }
! 323:
! 324: /*
! 325: * <S-Tab> works like CTRL-P (unless 'wc' is <S-Tab>).
! 326: */
! 327: if (c != p_wc && c == K_S_TAB)
! 328: c = Ctrl('P');
! 329:
! 330: /* free expanded names when finished walking through matches */
! 331: if (cmd_numfiles != -1 && !(c == p_wc && KeyTyped) && c != Ctrl('N') &&
! 332: c != Ctrl('P') && c != Ctrl('A') && c != Ctrl('L'))
! 333: (void)ExpandOne(NULL, NULL, 0, WILD_FREE);
! 334:
! 335: #ifdef DIGRAPHS
! 336: c = do_digraph(c);
! 337: #endif
! 338:
! 339: if (c == '\n' || c == '\r' || (c == ESC && (!KeyTyped ||
! 340: vim_strchr(p_cpo, CPO_ESC) != NULL)))
! 341: {
! 342: if (ccheck_abbr(c + ABBR_OFF))
! 343: goto cmdline_changed;
! 344: outchar('\r'); /* show that we got the return */
! 345: screen_cur_col = 0;
! 346: flushbuf();
! 347: break;
! 348: }
! 349:
! 350: /* hitting <ESC> twice means: abandon command line */
! 351: /* wildcard expansion is only done when the key is really typed,
! 352: * not when it comes from a macro */
! 353: if (c == p_wc && !gotesc && KeyTyped)
! 354: {
! 355: if (cmd_numfiles > 0) /* typed p_wc twice */
! 356: i = nextwild(WILD_NEXT);
! 357: else /* typed p_wc first time */
! 358: i = nextwild(WILD_EXPAND_KEEP);
! 359: if (c == ESC)
! 360: gotesc = TRUE;
! 361: if (i)
! 362: goto cmdline_changed;
! 363: }
! 364: gotesc = FALSE;
! 365:
! 366: if (c == NUL || c == K_ZERO) /* NUL is stored as NL */
! 367: c = NL;
! 368:
! 369: do_abbr = TRUE; /* default: check for abbreviation */
! 370: switch (c)
! 371: {
! 372: case K_BS:
! 373: case Ctrl('H'):
! 374: case K_DEL:
! 375: case Ctrl('W'):
! 376: /*
! 377: * delete current character is the same as backspace on next
! 378: * character, except at end of line
! 379: */
! 380: if (c == K_DEL && cmdpos != cmdlen)
! 381: ++cmdpos;
! 382: if (cmdpos > 0)
! 383: {
! 384: j = cmdpos;
! 385: if (c == Ctrl('W'))
! 386: {
! 387: while (cmdpos && vim_isspace(cmdbuff[cmdpos - 1]))
! 388: --cmdpos;
! 389: i = iswordchar(cmdbuff[cmdpos - 1]);
! 390: while (cmdpos && !vim_isspace(cmdbuff[cmdpos - 1]) &&
! 391: iswordchar(cmdbuff[cmdpos - 1]) == i)
! 392: --cmdpos;
! 393: }
! 394: else
! 395: --cmdpos;
! 396: cmdlen -= j - cmdpos;
! 397: i = cmdpos;
! 398: while (i < cmdlen)
! 399: cmdbuff[i++] = cmdbuff[j++];
! 400: redrawcmd();
! 401: }
! 402: else if (cmdlen == 0 && c != Ctrl('W'))
! 403: {
! 404: vim_free(cmdbuff); /* no commandline to return */
! 405: cmdbuff = NULL;
! 406: msg_pos(-1, 0);
! 407: msg_outchar(' '); /* delete ':' */
! 408: redraw_cmdline = TRUE;
! 409: goto returncmd; /* back to cmd mode */
! 410: }
! 411: goto cmdline_changed;
! 412:
! 413: case K_INS:
! 414: overstrike = !overstrike;
! 415: /* should change shape of cursor */
! 416: goto cmdline_not_changed;
! 417:
! 418: /* case '@': only in very old vi */
! 419: case Ctrl('U'):
! 420: cmdpos = 0;
! 421: cmdlen = 0;
! 422: cmdspos = 1;
! 423: redrawcmd();
! 424: goto cmdline_changed;
! 425:
! 426: case ESC: /* get here if p_wc != ESC or when ESC typed twice */
! 427: case Ctrl('C'):
! 428: gotesc = TRUE; /* will free cmdbuff after putting it in
! 429: history */
! 430: goto returncmd; /* back to cmd mode */
! 431:
! 432: case Ctrl('R'): /* insert register */
! 433: putcmdline('"');
! 434: ++no_mapping;
! 435: c = vgetc();
! 436: --no_mapping;
! 437: if (c != ESC) /* use ESC to cancel inserting register */
! 438: cmdline_paste(c);
! 439: redrawcmd();
! 440: goto cmdline_changed;
! 441:
! 442: case Ctrl('D'):
! 443: {
! 444: if (showmatches(cmdbuff) == FAIL)
! 445: break; /* Use ^D as normal char instead */
! 446:
! 447: redrawcmd();
! 448: continue; /* don't do incremental search now */
! 449: }
! 450:
! 451: case K_RIGHT:
! 452: case K_S_RIGHT:
! 453: do
! 454: {
! 455: if (cmdpos >= cmdlen)
! 456: break;
! 457: cmdspos += charsize(cmdbuff[cmdpos]);
! 458: ++cmdpos;
! 459: }
! 460: while (c == K_S_RIGHT && cmdbuff[cmdpos] != ' ');
! 461: goto cmdline_not_changed;
! 462:
! 463: case K_LEFT:
! 464: case K_S_LEFT:
! 465: do
! 466: {
! 467: if (cmdpos <= 0)
! 468: break;
! 469: --cmdpos;
! 470: cmdspos -= charsize(cmdbuff[cmdpos]);
! 471: }
! 472: while (c == K_S_LEFT && cmdbuff[cmdpos - 1] != ' ');
! 473: goto cmdline_not_changed;
! 474:
! 475: #ifdef USE_MOUSE
! 476: case K_MIDDLEDRAG:
! 477: case K_MIDDLERELEASE:
! 478: case K_IGNORE:
! 479: goto cmdline_not_changed; /* Ignore mouse */
! 480:
! 481: case K_MIDDLEMOUSE:
! 482: # ifdef USE_GUI
! 483: /* When GUI is active, also paste when 'mouse' is empty */
! 484: if (!gui.in_use)
! 485: # endif
! 486: if (!mouse_has(MOUSE_COMMAND))
! 487: goto cmdline_not_changed; /* Ignore mouse */
! 488: # ifdef USE_GUI
! 489: if (gui.in_use && yankbuffer == 0)
! 490: cmdline_paste('*');
! 491: else
! 492: # endif
! 493: cmdline_paste(yankbuffer);
! 494: redrawcmd();
! 495: goto cmdline_changed;
! 496:
! 497: case K_LEFTDRAG:
! 498: case K_LEFTRELEASE:
! 499: case K_RIGHTDRAG:
! 500: case K_RIGHTRELEASE:
! 501: if (ignore_drag_release)
! 502: goto cmdline_not_changed;
! 503: /* FALLTHROUGH */
! 504: case K_LEFTMOUSE:
! 505: case K_RIGHTMOUSE:
! 506: if (c == K_LEFTRELEASE || c == K_RIGHTRELEASE)
! 507: ignore_drag_release = TRUE;
! 508: else
! 509: ignore_drag_release = FALSE;
! 510: # ifdef USE_GUI
! 511: /* When GUI is active, also move when 'mouse' is empty */
! 512: if (!gui.in_use)
! 513: # endif
! 514: if (!mouse_has(MOUSE_COMMAND))
! 515: goto cmdline_not_changed; /* Ignore mouse */
! 516: cmdspos = 1;
! 517: for (cmdpos = 0; cmdpos < cmdlen; ++cmdpos)
! 518: {
! 519: i = charsize(cmdbuff[cmdpos]);
! 520: if (mouse_row <= cmdline_row + cmdspos / Columns &&
! 521: mouse_col < cmdspos % Columns + i)
! 522: break;
! 523: cmdspos += i;
! 524: }
! 525: goto cmdline_not_changed;
! 526: #endif /* USE_MOUSE */
! 527:
! 528: #ifdef USE_GUI
! 529: case K_SCROLLBAR:
! 530: if (!msg_scrolled)
! 531: {
! 532: gui_do_scroll();
! 533: redrawcmd();
! 534: }
! 535: goto cmdline_not_changed;
! 536:
! 537: case K_HORIZ_SCROLLBAR:
! 538: if (!msg_scrolled)
! 539: {
! 540: gui_do_horiz_scroll();
! 541: redrawcmd();
! 542: }
! 543: goto cmdline_not_changed;
! 544: #endif
! 545:
! 546: case Ctrl('B'): /* begin of command line */
! 547: case K_HOME:
! 548: cmdpos = 0;
! 549: cmdspos = 1;
! 550: goto cmdline_not_changed;
! 551:
! 552: case Ctrl('E'): /* end of command line */
! 553: case K_END:
! 554: cmdpos = cmdlen;
! 555: cmdbuff[cmdlen] = NUL;
! 556: cmdspos = strsize(cmdbuff) + 1;
! 557: goto cmdline_not_changed;
! 558:
! 559: case Ctrl('A'): /* all matches */
! 560: if (!nextwild(WILD_ALL))
! 561: break;
! 562: goto cmdline_changed;
! 563:
! 564: case Ctrl('L'): /* longest common part */
! 565: if (!nextwild(WILD_LONGEST))
! 566: break;
! 567: goto cmdline_changed;
! 568:
! 569: case Ctrl('N'): /* next match */
! 570: case Ctrl('P'): /* previous match */
! 571: if (cmd_numfiles > 0)
! 572: {
! 573: if (!nextwild((c == Ctrl('P')) ? WILD_PREV : WILD_NEXT))
! 574: break;
! 575: goto cmdline_changed;
! 576: }
! 577:
! 578: case K_UP:
! 579: case K_DOWN:
! 580: case K_S_UP:
! 581: case K_S_DOWN:
! 582: case K_PAGEUP:
! 583: case K_PAGEDOWN:
! 584: if (hislen == 0) /* no history */
! 585: goto cmdline_not_changed;
! 586:
! 587: i = hiscnt;
! 588:
! 589: /* save current command string so it can be restored later */
! 590: cmdbuff[cmdpos] = NUL;
! 591: if (lookfor == NULL && (lookfor = strsave(cmdbuff)) == NULL)
! 592: goto cmdline_not_changed;
! 593:
! 594: j = STRLEN(lookfor);
! 595: for (;;)
! 596: {
! 597: /* one step backwards */
! 598: if (c == K_UP || c == K_S_UP || c == Ctrl('P') ||
! 599: c == K_PAGEUP)
! 600: {
! 601: if (hiscnt == hislen) /* first time */
! 602: hiscnt = hisidx[histype];
! 603: else if (hiscnt == 0 && hisidx[histype] != hislen - 1)
! 604: hiscnt = hislen - 1;
! 605: else if (hiscnt != hisidx[histype] + 1)
! 606: --hiscnt;
! 607: else /* at top of list */
! 608: {
! 609: hiscnt = i;
! 610: break;
! 611: }
! 612: }
! 613: else /* one step forwards */
! 614: {
! 615: /* on last entry, clear the line */
! 616: if (hiscnt == hisidx[histype])
! 617: {
! 618: hiscnt = hislen;
! 619: break;
! 620: }
! 621: /* not on a history line, nothing to do */
! 622: if (hiscnt == hislen)
! 623: break;
! 624: if (hiscnt == hislen - 1) /* wrap around */
! 625: hiscnt = 0;
! 626: else
! 627: ++hiscnt;
! 628: }
! 629: if (hiscnt < 0 || history[histype][hiscnt] == NULL)
! 630: {
! 631: hiscnt = i;
! 632: break;
! 633: }
! 634: if ((c != K_UP && c != K_DOWN) || hiscnt == i ||
! 635: STRNCMP(history[histype][hiscnt],
! 636: lookfor, (size_t)j) == 0)
! 637: break;
! 638: }
! 639:
! 640: if (hiscnt != i) /* jumped to other entry */
! 641: {
! 642: vim_free(cmdbuff);
! 643: if (hiscnt == hislen)
! 644: p = lookfor; /* back to the old one */
! 645: else
! 646: p = history[histype][hiscnt];
! 647:
! 648: alloc_cmdbuff((int)STRLEN(p));
! 649: if (cmdbuff == NULL)
! 650: goto returncmd;
! 651: STRCPY(cmdbuff, p);
! 652:
! 653: cmdpos = cmdlen = STRLEN(cmdbuff);
! 654: redrawcmd();
! 655: goto cmdline_changed;
! 656: }
! 657: beep_flush();
! 658: goto cmdline_not_changed;
! 659:
! 660: case Ctrl('V'):
! 661: case Ctrl('Q'):
! 662: #ifdef USE_MOUSE
! 663: ignore_drag_release = TRUE;
! 664: #endif
! 665: putcmdline('^');
! 666: c = get_literal(); /* get next (two) character(s) */
! 667: do_abbr = FALSE; /* don't do abbreviation now */
! 668: break;
! 669:
! 670: #ifdef DIGRAPHS
! 671: case Ctrl('K'):
! 672: #ifdef USE_MOUSE
! 673: ignore_drag_release = TRUE;
! 674: #endif
! 675: putcmdline('?');
! 676: ++no_mapping;
! 677: ++allow_keys;
! 678: c = vgetc();
! 679: --no_mapping;
! 680: --allow_keys;
! 681: if (c != ESC) /* ESC cancels CTRL-K */
! 682: {
! 683: if (IS_SPECIAL(c)) /* insert special key code */
! 684: break;
! 685: if (charsize(c) == 1)
! 686: putcmdline(c);
! 687: ++no_mapping;
! 688: ++allow_keys;
! 689: cc = vgetc();
! 690: --no_mapping;
! 691: --allow_keys;
! 692: if (cc != ESC) /* ESC cancels CTRL-K */
! 693: {
! 694: c = getdigraph(c, cc, TRUE);
! 695: break;
! 696: }
! 697: }
! 698: redrawcmd();
! 699: goto cmdline_not_changed;
! 700: #endif /* DIGRAPHS */
! 701:
! 702: #ifdef RIGHTLEFT
! 703: case Ctrl('_'): /* CTRL-_: switch language mode */
! 704: cmd_hkmap = !cmd_hkmap;
! 705: goto cmdline_not_changed;
! 706: #endif
! 707:
! 708: default:
! 709: /*
! 710: * Normal character with no special meaning. Just set mod_mask
! 711: * to 0x0 so that typing Shift-Space in the GUI doesn't enter
! 712: * the string <S-Space>. This should only happen after ^V.
! 713: */
! 714: if (!IS_SPECIAL(c))
! 715: mod_mask = 0x0;
! 716: break;
! 717: }
! 718:
! 719: /* we come here if we have a normal character */
! 720:
! 721: if (do_abbr && (IS_SPECIAL(c) || !iswordchar(c)) && ccheck_abbr(c))
! 722: goto cmdline_changed;
! 723:
! 724: /*
! 725: * put the character in the command line
! 726: */
! 727: if (IS_SPECIAL(c) || mod_mask != 0x0)
! 728: put_on_cmdline(get_special_key_name(c, mod_mask), -1, TRUE);
! 729: else
! 730: {
! 731: IObuff[0] = c;
! 732: put_on_cmdline(IObuff, 1, TRUE);
! 733: }
! 734: goto cmdline_changed;
! 735:
! 736: /*
! 737: * This part implements incremental searches for "/" and "?"
! 738: * Jump to cmdline_not_changed when a character has been read but the command
! 739: * line did not change. Then we only search and redraw if something changed in
! 740: * the past.
! 741: * Jump to cmdline_changed when the command line did change.
! 742: * (Sorry for the goto's, I know it is ugly).
! 743: */
! 744: cmdline_not_changed:
! 745: if (!incsearch_postponed)
! 746: continue;
! 747:
! 748: cmdline_changed:
! 749: if (p_is && (firstc == '/' || firstc == '?'))
! 750: {
! 751: /* if there is a character waiting, search and redraw later */
! 752: if (char_avail())
! 753: {
! 754: incsearch_postponed = TRUE;
! 755: continue;
! 756: }
! 757: incsearch_postponed = FALSE;
! 758: curwin->w_cursor = old_cursor; /* start at old position */
! 759:
! 760: /* If there is no command line, don't do anything */
! 761: if (cmdlen == 0)
! 762: i = 0;
! 763: else
! 764: {
! 765: cmdbuff[cmdlen] = NUL;
! 766: emsg_off = TRUE; /* So it doesn't beep if bad expr */
! 767: i = do_search(firstc, cmdbuff, count,
! 768: SEARCH_KEEP + SEARCH_OPT + SEARCH_NOOF);
! 769: emsg_off = FALSE;
! 770: }
! 771: if (i)
! 772: {
! 773: highlight_match = TRUE; /* highlight position */
! 774: cursupdate();
! 775: }
! 776: else
! 777: {
! 778: highlight_match = FALSE; /* don't highlight */
! 779: /* vim_beep(); */ /* even beeps when invalid expr, e.g. "[" */
! 780: }
! 781: updateScreen(NOT_VALID);
! 782: redrawcmdline();
! 783: did_incsearch = TRUE;
! 784: }
! 785: }
! 786:
! 787: returncmd:
! 788: if (did_incsearch)
! 789: {
! 790: curwin->w_cursor = old_cursor;
! 791: curwin->w_curswant = old_curswant;
! 792: highlight_match = FALSE;
! 793: redraw_later(NOT_VALID);
! 794: }
! 795: if (cmdbuff != NULL)
! 796: {
! 797: /*
! 798: * Put line in history buffer (":" only when it was typed).
! 799: */
! 800: cmdbuff[cmdlen] = NUL;
! 801: if (cmdlen != 0 && (some_key_typed || firstc != ':'))
! 802: {
! 803: add_to_history(histype, cmdbuff);
! 804: if (firstc == ':')
! 805: {
! 806: vim_free(new_last_cmdline);
! 807: new_last_cmdline = strsave(cmdbuff);
! 808: }
! 809: }
! 810:
! 811: if (gotesc) /* abandon command line */
! 812: {
! 813: vim_free(cmdbuff);
! 814: cmdbuff = NULL;
! 815: MSG("");
! 816: redraw_cmdline = TRUE;
! 817: }
! 818: }
! 819:
! 820: /*
! 821: * If the screen was shifted up, redraw the whole screen (later).
! 822: * If the line is too long, clear it, so ruler and shown command do
! 823: * not get printed in the middle of it.
! 824: */
! 825: msg_check();
! 826: msg_scroll = save_msg_scroll;
! 827: State = NORMAL;
! 828: #ifdef USE_MOUSE
! 829: setmouse();
! 830: #endif
! 831: return cmdbuff;
! 832: }
! 833:
! 834: /*
! 835: * Put the given string, of the given length, onto the command line.
! 836: * If len is -1, then STRLEN() is used to calculate the length.
! 837: * If 'redraw' is TRUE then the new part of the command line, and the remaining
! 838: * part will be redrawn, otherwise it will not. If this function is called
! 839: * twice in a row, then 'redraw' should be FALSE and redrawcmd() should be
! 840: * called afterwards.
! 841: */
! 842: int
! 843: put_on_cmdline(str, len, redraw)
! 844: char_u *str;
! 845: int len;
! 846: int redraw;
! 847: {
! 848: int i;
! 849:
! 850: if (len < 0)
! 851: len = STRLEN(str);
! 852:
! 853: /* Check if cmdbuff needs to be longer */
! 854: if (cmdlen + len + 1 >= cmdbufflen)
! 855: i = realloc_cmdbuff(cmdlen + len);
! 856: else
! 857: i = OK;
! 858: if (i == OK)
! 859: {
! 860: if (!overstrike)
! 861: {
! 862: vim_memmove(cmdbuff + cmdpos + len, cmdbuff + cmdpos,
! 863: (size_t)(cmdlen - cmdpos));
! 864: cmdlen += len;
! 865: }
! 866: else if (cmdpos + len > cmdlen)
! 867: cmdlen = cmdpos + len;
! 868: vim_memmove(cmdbuff + cmdpos, str, (size_t)len);
! 869: if (redraw)
! 870: msg_outtrans_len(cmdbuff + cmdpos, cmdlen - cmdpos);
! 871: cmdpos += len;
! 872: while (len--)
! 873: cmdspos += charsize(str[len]);
! 874: }
! 875: if (redraw)
! 876: msg_check();
! 877: return i;
! 878: }
! 879:
! 880: void
! 881: alloc_cmdbuff(len)
! 882: int len;
! 883: {
! 884: /*
! 885: * give some extra space to avoid having to allocate all the time
! 886: */
! 887: if (len < 80)
! 888: len = 100;
! 889: else
! 890: len += 20;
! 891:
! 892: cmdbuff = alloc(len); /* caller should check for out of memory */
! 893: cmdbufflen = len;
! 894: }
! 895:
! 896: /*
! 897: * Re-allocate the command line to length len + something extra.
! 898: * return FAIL for failure, OK otherwise
! 899: */
! 900: int
! 901: realloc_cmdbuff(len)
! 902: int len;
! 903: {
! 904: char_u *p;
! 905:
! 906: p = cmdbuff;
! 907: alloc_cmdbuff(len); /* will get some more */
! 908: if (cmdbuff == NULL) /* out of memory */
! 909: {
! 910: cmdbuff = p; /* keep the old one */
! 911: return FAIL;
! 912: }
! 913: vim_memmove(cmdbuff, p, (size_t)cmdlen);
! 914: vim_free(p);
! 915: return OK;
! 916: }
! 917:
! 918: /*
! 919: * put a character on the command line.
! 920: * Used for CTRL-V and CTRL-K
! 921: */
! 922: static void
! 923: putcmdline(c)
! 924: int c;
! 925: {
! 926: char_u buf[1];
! 927:
! 928: buf[0] = c;
! 929: msg_outtrans_len(buf, 1);
! 930: msg_outtrans_len(cmdbuff + cmdpos, cmdlen - cmdpos);
! 931: cursorcmd();
! 932: }
! 933:
! 934: /*
! 935: * this fuction is called when the screen size changes and with incremental
! 936: * search
! 937: */
! 938: void
! 939: redrawcmdline()
! 940: {
! 941: msg_scrolled = 0;
! 942: need_wait_return = FALSE;
! 943: compute_cmdrow();
! 944: redrawcmd();
! 945: cursorcmd();
! 946: }
! 947:
! 948: void
! 949: compute_cmdrow()
! 950: {
! 951: cmdline_row = lastwin->w_winpos + lastwin->w_height +
! 952: lastwin->w_status_height;
! 953: }
! 954:
! 955: /*
! 956: * Redraw what is currently on the command line.
! 957: */
! 958: static void
! 959: redrawcmd()
! 960: {
! 961: register int i;
! 962:
! 963: msg_start();
! 964: msg_outchar(cmdfirstc);
! 965: msg_outtrans_len(cmdbuff, cmdlen);
! 966: msg_clr_eos();
! 967:
! 968: cmdspos = 1;
! 969: for (i = 0; i < cmdlen && i < cmdpos; ++i)
! 970: cmdspos += charsize(cmdbuff[i]);
! 971: /*
! 972: * An emsg() before may have set msg_scroll and need_sleep. These are used
! 973: * in normal mode, in cmdline mode we can reset them now.
! 974: */
! 975: msg_scroll = FALSE; /* next message overwrites cmdline */
! 976: #ifdef SLEEP_IN_EMSG
! 977: need_sleep = FALSE; /* don't sleep */
! 978: #endif
! 979: }
! 980:
! 981: static void
! 982: cursorcmd()
! 983: {
! 984: msg_pos(cmdline_row + (cmdspos / (int)Columns), cmdspos % (int)Columns);
! 985: windgoto(msg_row, msg_col);
! 986: }
! 987:
! 988: /*
! 989: * Check the word in front of the cursor for an abbreviation.
! 990: * Called when the non-id character "c" has been entered.
! 991: * When an abbreviation is recognized it is removed from the text with
! 992: * backspaces and the replacement string is inserted, followed by "c".
! 993: */
! 994: static int
! 995: ccheck_abbr(c)
! 996: int c;
! 997: {
! 998: if (p_paste || no_abbr) /* no abbreviations or in paste mode */
! 999: return FALSE;
! 1000:
! 1001: return check_abbr(c, cmdbuff, cmdpos, 0);
! 1002: }
! 1003:
! 1004: /*
! 1005: * do_cmdline(): execute an Ex command line
! 1006: *
! 1007: * 1. If no line given, get one.
! 1008: * 2. Split up in parts separated with '|'.
! 1009: *
! 1010: * This function may be called recursively!
! 1011: *
! 1012: * If 'sourcing' is TRUE, the command will be included in the error message.
! 1013: * If 'repeating' is TRUE, there is no wait_return() and friends.
! 1014: *
! 1015: * return FAIL if commandline could not be executed, OK otherwise
! 1016: */
! 1017: int
! 1018: do_cmdline(cmdline, sourcing, repeating)
! 1019: char_u *cmdline;
! 1020: int sourcing;
! 1021: int repeating;
! 1022: {
! 1023: int cmdlinelen;
! 1024: char_u *nextcomm;
! 1025: static int recursive = 0; /* recursive depth */
! 1026: int got_cmdline = FALSE; /* TRUE when cmdline was typed */
! 1027: int msg_didout_before_start;
! 1028:
! 1029: /*
! 1030: * 1. If no line given: Get a line in cmdbuff.
! 1031: * If a line is given: Copy it into cmdbuff.
! 1032: * After this we don't use cmdbuff but cmdline, because of recursiveness
! 1033: */
! 1034: if (cmdline == NULL)
! 1035: {
! 1036: if ((cmdline = getcmdline(':', 1L)) == NULL)
! 1037: {
! 1038: /* don't call wait_return for aborted command line */
! 1039: need_wait_return = FALSE;
! 1040: return FAIL;
! 1041: }
! 1042: got_cmdline = TRUE;
! 1043: }
! 1044: else
! 1045: {
! 1046: /* Make a copy of the command so we can mess with it. */
! 1047: alloc_cmdbuff((int)STRLEN(cmdline));
! 1048: if (cmdbuff == NULL)
! 1049: return FAIL;
! 1050: STRCPY(cmdbuff, cmdline);
! 1051: cmdline = cmdbuff;
! 1052: }
! 1053: cmdlinelen = cmdbufflen; /* we need to copy it for recursiveness */
! 1054:
! 1055: /*
! 1056: * All output from the commands is put below each other, without waiting for a
! 1057: * return. Don't do this when executing commands from a script or when being
! 1058: * called recursive (e.g. for ":e +command file").
! 1059: */
! 1060: msg_didout_before_start = msg_didout;
! 1061: if (!repeating && !recursive)
! 1062: {
! 1063: msg_didany = FALSE; /* no output yet */
! 1064: msg_start();
! 1065: msg_scroll = TRUE; /* put messages below each other */
! 1066: #ifdef SLEEP_IN_EMSG
! 1067: ++dont_sleep; /* don't sleep in emsg() */
! 1068: #endif
! 1069: ++no_wait_return; /* dont wait for return until finished */
! 1070: ++RedrawingDisabled;
! 1071: }
! 1072:
! 1073: /*
! 1074: * 2. Loop for each '|' separated command.
! 1075: * do_one_cmd will set nextcomm to NULL if there is no trailing '|'.
! 1076: * cmdline and cmdlinelen may change, e.g. for '%' and '#' expansion.
! 1077: */
! 1078: ++recursive;
! 1079: for (;;)
! 1080: {
! 1081: nextcomm = do_one_cmd(&cmdline, &cmdlinelen, sourcing);
! 1082: if (nextcomm == NULL)
! 1083: break;
! 1084: STRCPY(cmdline, nextcomm);
! 1085: }
! 1086: --recursive;
! 1087: vim_free(cmdline);
! 1088:
! 1089: /*
! 1090: * If there was too much output to fit on the command line, ask the user to
! 1091: * hit return before redrawing the screen. With the ":global" command we do
! 1092: * this only once after the command is finished.
! 1093: */
! 1094: if (!repeating && !recursive)
! 1095: {
! 1096: --RedrawingDisabled;
! 1097: #ifdef SLEEP_IN_EMSG
! 1098: --dont_sleep;
! 1099: #endif
! 1100: --no_wait_return;
! 1101: msg_scroll = FALSE;
! 1102: if (need_wait_return || (msg_check() && !dont_wait_return))
! 1103: {
! 1104: /*
! 1105: * The msg_start() above clears msg_didout. The wait_return we do
! 1106: * here should not overwrite the command that may be shown before
! 1107: * doing that.
! 1108: */
! 1109: msg_didout = msg_didout_before_start;
! 1110: wait_return(FALSE);
! 1111: }
! 1112: }
! 1113:
! 1114: /*
! 1115: * If the command was typed, remember it for register :
! 1116: * Do this AFTER executing the command to make :@: work.
! 1117: */
! 1118: if (got_cmdline && new_last_cmdline != NULL)
! 1119: {
! 1120: vim_free(last_cmdline);
! 1121: last_cmdline = new_last_cmdline;
! 1122: new_last_cmdline = NULL;
! 1123: }
! 1124: return OK;
! 1125: }
! 1126:
! 1127: static char *(make_cmd_chars[6]) =
! 1128: { " \164\145a",
! 1129: "\207\171\204\170\060\175\171\174\173\117\032",
! 1130: " c\157\146\146e\145",
! 1131: "\200\174\165\161\203\165\060\171\176\203\165\202\204\060\163\177\171\176\060\204\177\060\202\205\176\060\175\161\173\165\032",
! 1132: " \164o\141\163t",
! 1133: "\136\137\122\137\124\151\060\165\210\200\165\163\204\203\060\204\170\165\060\143\200\161\176\171\203\170\060\171\176\201\205\171\203\171\204\171\177\176\061\032"
! 1134: };
! 1135:
! 1136: /*
! 1137: * Execute one Ex command.
! 1138: *
! 1139: * If 'sourcing' is TRUE, the command will be included in the error message.
! 1140: *
! 1141: * 2. skip comment lines and leading space
! 1142: * 3. parse range
! 1143: * 4. parse command
! 1144: * 5. parse arguments
! 1145: * 6. switch on command name
! 1146: *
! 1147: * This function may be called recursively!
! 1148: */
! 1149: static char_u *
! 1150: do_one_cmd(cmdlinep, cmdlinelenp, sourcing)
! 1151: char_u **cmdlinep;
! 1152: int *cmdlinelenp;
! 1153: int sourcing;
! 1154: {
! 1155: char_u *p;
! 1156: char_u *q;
! 1157: char_u *s;
! 1158: char_u *cmd, *arg;
! 1159: char_u *do_ecmd_cmd = NULL; /* +command for do_ecmd() */
! 1160: linenr_t do_ecmd_lnum = 0; /* lnum file for do_ecmd() */
! 1161: int i = 0; /* init to shut up gcc */
! 1162: int len;
! 1163: int cmdidx;
! 1164: long argt;
! 1165: register linenr_t lnum;
! 1166: long n = 0; /* init to shut up gcc */
! 1167: int addr_count; /* number of address specs */
! 1168: FPOS pos;
! 1169: int append = FALSE; /* write with append */
! 1170: int usefilter = FALSE; /* no read/write but filter */
! 1171: char_u *nextcomm = NULL; /* no next command yet */
! 1172: int amount = 0; /* for ":>"; init for gcc */
! 1173: char_u *errormsg = NULL; /* error message */
! 1174: WIN *old_curwin = NULL; /* init for GCC */
! 1175:
! 1176: /* when not editing the last file :q has to be typed twice */
! 1177: if (quitmore)
! 1178: --quitmore;
! 1179: did_emsg = FALSE; /* will be set to TRUE when emsg() used, in which
! 1180: * case we set nextcomm to NULL to cancel the
! 1181: * whole command line */
! 1182: /*
! 1183: * 2. skip comment lines and leading space and colons
! 1184: */
! 1185: for (cmd = *cmdlinep; vim_strchr((char_u *)" \t:", *cmd) != NULL; cmd++)
! 1186: ;
! 1187:
! 1188: if (*cmd == '"' || *cmd == NUL) /* ignore comment and empty lines */
! 1189: goto doend;
! 1190:
! 1191: /*
! 1192: * 3. parse a range specifier of the form: addr [,addr] [;addr] ..
! 1193: *
! 1194: * where 'addr' is:
! 1195: *
! 1196: * % (entire file)
! 1197: * $ [+-NUM]
! 1198: * 'x [+-NUM] (where x denotes a currently defined mark)
! 1199: * . [+-NUM]
! 1200: * [+-NUM]..
! 1201: * NUM
! 1202: *
! 1203: * The cmd pointer is updated to point to the first character following the
! 1204: * range spec. If an initial address is found, but no second, the upper bound
! 1205: * is equal to the lower.
! 1206: */
! 1207:
! 1208: addr_count = 0;
! 1209: --cmd;
! 1210: do
! 1211: {
! 1212: line1 = line2;
! 1213: line2 = curwin->w_cursor.lnum; /* default is current line number */
! 1214: cmd = skipwhite(cmd + 1); /* skip ',' or ';' and following ' ' */
! 1215: lnum = get_address(&cmd);
! 1216: if (cmd == NULL) /* error detected */
! 1217: goto doend;
! 1218: if (lnum == MAXLNUM)
! 1219: {
! 1220: if (*cmd == '%') /* '%' - all lines */
! 1221: {
! 1222: ++cmd;
! 1223: line1 = 1;
! 1224: line2 = curbuf->b_ml.ml_line_count;
! 1225: ++addr_count;
! 1226: }
! 1227: else if (*cmd == '*') /* '*' - visual area */
! 1228: {
! 1229: FPOS *fp;
! 1230:
! 1231: ++cmd;
! 1232: fp = getmark('<', FALSE);
! 1233: if (check_mark(fp) == FAIL)
! 1234: goto doend;
! 1235: line1 = fp->lnum;
! 1236: fp = getmark('>', FALSE);
! 1237: if (check_mark(fp) == FAIL)
! 1238: goto doend;
! 1239: line2 = fp->lnum;
! 1240: ++addr_count;
! 1241: }
! 1242: }
! 1243: else
! 1244: line2 = lnum;
! 1245: addr_count++;
! 1246:
! 1247: if (*cmd == ';')
! 1248: {
! 1249: if (line2 == 0)
! 1250: curwin->w_cursor.lnum = 1;
! 1251: else
! 1252: curwin->w_cursor.lnum = line2;
! 1253: }
! 1254: } while (*cmd == ',' || *cmd == ';');
! 1255:
! 1256: /* One address given: set start and end lines */
! 1257: if (addr_count == 1)
! 1258: {
! 1259: line1 = line2;
! 1260: /* ... but only implicit: really no address given */
! 1261: if (lnum == MAXLNUM)
! 1262: addr_count = 0;
! 1263: }
! 1264:
! 1265: /*
! 1266: * 4. parse command
! 1267: */
! 1268:
! 1269: /*
! 1270: * Skip ':' and any white space
! 1271: */
! 1272: cmd = skipwhite(cmd);
! 1273: if (*cmd == ':')
! 1274: cmd = skipwhite(cmd + 1);
! 1275:
! 1276: /*
! 1277: * If we got a line, but no command, then go to the line.
! 1278: * If we find a '|' or '\n' we set nextcomm.
! 1279: */
! 1280: if (*cmd == NUL || *cmd == '"' ||
! 1281: ((*cmd == '|' || *cmd == '\n') &&
! 1282: (nextcomm = cmd + 1) != NULL)) /* just an assignment */
! 1283: {
! 1284: /*
! 1285: * strange vi behaviour:
! 1286: * ":3" jumps to line 3
! 1287: * ":3|..." prints line 3
! 1288: * ":|" prints current line
! 1289: */
! 1290: if (*cmd == '|')
! 1291: {
! 1292: cmdidx = CMD_print;
! 1293: goto cmdswitch; /* UGLY goto */
! 1294: }
! 1295: if (addr_count != 0)
! 1296: {
! 1297: if (line2 == 0)
! 1298: curwin->w_cursor.lnum = 1;
! 1299: else if (line2 > curbuf->b_ml.ml_line_count)
! 1300: curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
! 1301: else
! 1302: curwin->w_cursor.lnum = line2;
! 1303: beginline(MAYBE);
! 1304: /* This causes problems for ":234", since displaying is disabled
! 1305: * here */
! 1306: /* cursupdate(); */
! 1307: }
! 1308: goto doend;
! 1309: }
! 1310:
! 1311: /*
! 1312: * Isolate the command and search for it in the command table.
! 1313: * Exeptions:
! 1314: * - the 'k' command can directly be followed by any character.
! 1315: * - the 's' command can be followed directly by 'c', 'g' or 'r'
! 1316: * but :sre[wind] is another command.
! 1317: */
! 1318: if (*cmd == 'k')
! 1319: {
! 1320: cmdidx = CMD_k;
! 1321: p = cmd + 1;
! 1322: }
! 1323: else if (*cmd == 's' && vim_strchr((char_u *)"cgr", cmd[1]) != NULL &&
! 1324: STRNCMP("sre", cmd, (size_t)3) != 0)
! 1325: {
! 1326: cmdidx = CMD_substitute;
! 1327: p = cmd + 1;
! 1328: }
! 1329: else
! 1330: {
! 1331: p = cmd;
! 1332: while (isalpha(*p))
! 1333: ++p;
! 1334: /* check for non-alpha command */
! 1335: if (p == cmd && vim_strchr((char_u *)"@!=><&~#", *p) != NULL)
! 1336: ++p;
! 1337: i = (int)(p - cmd);
! 1338:
! 1339: for (cmdidx = 0; cmdidx < CMD_SIZE; ++cmdidx)
! 1340: if (STRNCMP(cmdnames[cmdidx].cmd_name, (char *)cmd, (size_t)i) == 0)
! 1341: break;
! 1342: if (i == 0 || cmdidx == CMD_SIZE)
! 1343: {
! 1344: STRCPY(IObuff, "Not an editor command");
! 1345: if (!sourcing)
! 1346: {
! 1347: STRCAT(IObuff, ": ");
! 1348: STRNCAT(IObuff, *cmdlinep, 40);
! 1349: }
! 1350: errormsg = IObuff;
! 1351: goto doend;
! 1352: }
! 1353: }
! 1354:
! 1355: if (*p == '!') /* forced commands */
! 1356: {
! 1357: ++p;
! 1358: forceit = TRUE;
! 1359: }
! 1360: else
! 1361: forceit = FALSE;
! 1362:
! 1363: /*
! 1364: * 5. parse arguments
! 1365: */
! 1366: argt = cmdnames[cmdidx].cmd_argt;
! 1367:
! 1368: if (!(argt & RANGE) && addr_count) /* no range allowed */
! 1369: {
! 1370: errormsg = e_norange;
! 1371: goto doend;
! 1372: }
! 1373:
! 1374: if (!(argt & BANG) && forceit) /* no <!> allowed */
! 1375: {
! 1376: errormsg = e_nobang;
! 1377: goto doend;
! 1378: }
! 1379:
! 1380: /*
! 1381: * If the range is backwards, ask for confirmation and, if given, swap
! 1382: * line1 & line2 so it's forwards again.
! 1383: * When global command is busy, don't ask, will fail below.
! 1384: */
! 1385: if (!global_busy && line1 > line2)
! 1386: {
! 1387: if (sourcing)
! 1388: {
! 1389: errormsg = (char_u *)"Backwards range given";
! 1390: goto doend;
! 1391: }
! 1392: else if (ask_yesno((char_u *)"Backwards range given, OK to swap", FALSE) != 'y')
! 1393: goto doend;
! 1394: lnum = line1;
! 1395: line1 = line2;
! 1396: line2 = lnum;
! 1397: }
! 1398: /*
! 1399: * don't complain about the range if it is not used
! 1400: * (could happen if line_count is accidently set to 0)
! 1401: */
! 1402: if (line1 < 0 || line2 < 0 || line1 > line2 || ((argt & RANGE) &&
! 1403: !(argt & NOTADR) && line2 > curbuf->b_ml.ml_line_count))
! 1404: {
! 1405: errormsg = e_invrange;
! 1406: goto doend;
! 1407: }
! 1408:
! 1409: if ((argt & NOTADR) && addr_count == 0) /* default is 1, not cursor */
! 1410: line2 = 1;
! 1411:
! 1412: if (!(argt & ZEROR)) /* zero in range not allowed */
! 1413: {
! 1414: if (line1 == 0)
! 1415: line1 = 1;
! 1416: if (line2 == 0)
! 1417: line2 = 1;
! 1418: }
! 1419:
! 1420: /*
! 1421: * for the :make command we insert the 'makeprg' option here,
! 1422: * so things like % get expanded
! 1423: */
! 1424: if (cmdidx == CMD_make)
! 1425: {
! 1426: alloc_cmdbuff((int)(STRLEN(p_mp) + STRLEN(p) + 2));
! 1427: if (cmdbuff == NULL) /* out of memory */
! 1428: goto doend;
! 1429: /*
! 1430: * Check for special command characters and echo them.
! 1431: */
! 1432: for (i = 0; i < 6; i += 2)
! 1433: if (!STRCMP(make_cmd_chars[i], p))
! 1434: for (s = (char_u *)(make_cmd_chars[i + 1]); *s; ++s)
! 1435: msg_outchar(*s - 16);
! 1436: STRCPY(cmdbuff, p_mp);
! 1437: STRCAT(cmdbuff, " ");
! 1438: STRCAT(cmdbuff, p);
! 1439: /* 'cmd' is not set here, because it is not used at CMD_make */
! 1440: vim_free(*cmdlinep);
! 1441: *cmdlinep = cmdbuff;
! 1442: *cmdlinelenp = cmdbufflen;
! 1443: p = cmdbuff;
! 1444: }
! 1445:
! 1446: /*
! 1447: * Skip to start of argument.
! 1448: * Don't do this for the ":!" command, because ":!! -l" needs the space.
! 1449: */
! 1450: if (cmdidx == CMD_bang)
! 1451: arg = p;
! 1452: else
! 1453: arg = skipwhite(p);
! 1454:
! 1455: if (cmdidx == CMD_write)
! 1456: {
! 1457: if (*arg == '>') /* append */
! 1458: {
! 1459: if (*++arg != '>') /* typed wrong */
! 1460: {
! 1461: errormsg = (char_u *)"Use w or w>>";
! 1462: goto doend;
! 1463: }
! 1464: arg = skipwhite(arg + 1);
! 1465: append = TRUE;
! 1466: }
! 1467: else if (*arg == '!') /* :w !filter */
! 1468: {
! 1469: ++arg;
! 1470: usefilter = TRUE;
! 1471: }
! 1472: }
! 1473:
! 1474: if (cmdidx == CMD_read)
! 1475: {
! 1476: if (forceit)
! 1477: {
! 1478: usefilter = TRUE; /* :r! filter if forceit */
! 1479: forceit = FALSE;
! 1480: }
! 1481: else if (*arg == '!') /* :r !filter */
! 1482: {
! 1483: ++arg;
! 1484: usefilter = TRUE;
! 1485: }
! 1486: }
! 1487:
! 1488: if (cmdidx == CMD_lshift || cmdidx == CMD_rshift)
! 1489: {
! 1490: amount = 1;
! 1491: while (*arg == *cmd) /* count number of '>' or '<' */
! 1492: {
! 1493: ++arg;
! 1494: ++amount;
! 1495: }
! 1496: arg = skipwhite(arg);
! 1497: }
! 1498:
! 1499: /*
! 1500: * Check for "+command" argument, before checking for next command.
! 1501: * Don't do this for ":read !cmd" and ":write !cmd".
! 1502: */
! 1503: if ((argt & EDITCMD) && !usefilter)
! 1504: do_ecmd_cmd = getargcmd(&arg);
! 1505:
! 1506: /*
! 1507: * Check for '|' to separate commands and '"' to start comments.
! 1508: * Don't do this for ":read !cmd" and ":write !cmd".
! 1509: */
! 1510: if ((argt & TRLBAR) && !usefilter)
! 1511: {
! 1512: for (p = arg; *p; ++p)
! 1513: {
! 1514: if (*p == Ctrl('V'))
! 1515: {
! 1516: if (argt & (USECTRLV | XFILE))
! 1517: ++p; /* skip CTRL-V and next char */
! 1518: else
! 1519: STRCPY(p, p + 1); /* remove CTRL-V and skip next char */
! 1520: if (*p == NUL) /* stop at NUL after CTRL-V */
! 1521: break;
! 1522: }
! 1523: else if ((*p == '"' && !(argt & NOTRLCOM)) ||
! 1524: *p == '|' || *p == '\n')
! 1525: {
! 1526: /*
! 1527: * We remove the '\' before the '|', unless USECTRLV is used
! 1528: * AND 'b' is present in 'cpoptions'.
! 1529: */
! 1530: if ((vim_strchr(p_cpo, CPO_BAR) == NULL ||
! 1531: !(argt & USECTRLV)) && *(p - 1) == '\\')
! 1532: {
! 1533: STRCPY(p - 1, p); /* remove the backslash */
! 1534: --p;
! 1535: }
! 1536: else
! 1537: {
! 1538: if (*p == '|' || *p == '\n')
! 1539: nextcomm = p + 1;
! 1540: *p = NUL;
! 1541: break;
! 1542: }
! 1543: }
! 1544: }
! 1545: if (!(argt & NOTRLCOM)) /* remove trailing spaces */
! 1546: del_trailing_spaces(arg);
! 1547: }
! 1548:
! 1549: /*
! 1550: * Check for <newline> to end a shell command.
! 1551: * Also do this for ":read !cmd" and ":write !cmd".
! 1552: */
! 1553: else if (cmdidx == CMD_bang || usefilter)
! 1554: {
! 1555: for (p = arg; *p; ++p)
! 1556: {
! 1557: if (*p == '\\' && p[1])
! 1558: ++p;
! 1559: else if (*p == '\n')
! 1560: {
! 1561: nextcomm = p + 1;
! 1562: *p = NUL;
! 1563: break;
! 1564: }
! 1565: }
! 1566: }
! 1567:
! 1568: if ((argt & DFLALL) && addr_count == 0)
! 1569: {
! 1570: line1 = 1;
! 1571: line2 = curbuf->b_ml.ml_line_count;
! 1572: }
! 1573:
! 1574: regname = 0;
! 1575: /* accept numbered register only when no count allowed (:put) */
! 1576: if ((argt & REGSTR) && *arg != NUL && is_yank_buffer(*arg, FALSE) &&
! 1577: !((argt & COUNT) && isdigit(*arg)))
! 1578: {
! 1579: regname = *arg;
! 1580: arg = skipwhite(arg + 1);
! 1581: }
! 1582:
! 1583: if ((argt & COUNT) && isdigit(*arg))
! 1584: {
! 1585: n = getdigits(&arg);
! 1586: arg = skipwhite(arg);
! 1587: if (n <= 0)
! 1588: {
! 1589: errormsg = e_zerocount;
! 1590: goto doend;
! 1591: }
! 1592: if (argt & NOTADR) /* e.g. :buffer 2, :sleep 3 */
! 1593: {
! 1594: line2 = n;
! 1595: if (addr_count == 0)
! 1596: addr_count = 1;
! 1597: }
! 1598: else
! 1599: {
! 1600: line1 = line2;
! 1601: line2 += n - 1;
! 1602: ++addr_count;
! 1603: /*
! 1604: * Be vi compatible: no error message for out of range.
! 1605: */
! 1606: if (line2 > curbuf->b_ml.ml_line_count)
! 1607: line2 = curbuf->b_ml.ml_line_count;
! 1608: }
! 1609: }
! 1610: /* no arguments allowed */
! 1611: if (!(argt & EXTRA) && *arg != NUL &&
! 1612: vim_strchr((char_u *)"|\"", *arg) == NULL)
! 1613: {
! 1614: errormsg = e_trailing;
! 1615: goto doend;
! 1616: }
! 1617:
! 1618: if ((argt & NEEDARG) && *arg == NUL)
! 1619: {
! 1620: errormsg = e_argreq;
! 1621: goto doend;
! 1622: }
! 1623:
! 1624: /*
! 1625: * change '%' to curbuf->b_filename
! 1626: * '#' to curwin->w_altfile
! 1627: * '<cword>' to word under the cursor
! 1628: * '<cWORD>' to WORD under the cursor
! 1629: * '<cfile>' to path name under the cursor
! 1630: * '<afile>' to file name for autocommand
! 1631: */
! 1632: if (argt & XFILE)
! 1633: {
! 1634: char_u *buf = NULL;
! 1635: int expand_wildcards; /* need to expand wildcards */
! 1636: int spec_idx;
! 1637: static char *(spec_str[]) =
! 1638: {
! 1639: "%",
! 1640: #define SPEC_PERC 0
! 1641: "#",
! 1642: #define SPEC_HASH 1
! 1643: "<cword>", /* cursor word */
! 1644: #define SPEC_CWORD 2
! 1645: "<cWORD>", /* cursor WORD */
! 1646: #define SPEC_CCWORD 3
! 1647: "<cfile>", /* cursor path name */
! 1648: #define SPEC_CFILE 4
! 1649: "<afile>" /* autocommand file name */
! 1650: #define SPEC_AFILE 5
! 1651: };
! 1652: #define SPEC_COUNT 6
! 1653:
! 1654: /*
! 1655: * Decide to expand wildcards *before* replacing '%', '#', etc. If
! 1656: * the file name contains a wildcard it should not cause expanding.
! 1657: * (it will be expanded anyway if there is a wildcard before replacing).
! 1658: */
! 1659: expand_wildcards = mch_has_wildcard(arg);
! 1660: for (p = arg; *p; ++p)
! 1661: {
! 1662: /*
! 1663: * Check if there is something to do.
! 1664: */
! 1665: for (spec_idx = 0; spec_idx < SPEC_COUNT; ++spec_idx)
! 1666: {
! 1667: n = strlen(spec_str[spec_idx]);
! 1668: if (STRNCMP(p, spec_str[spec_idx], n) == 0)
! 1669: break;
! 1670: }
! 1671: if (spec_idx == SPEC_COUNT) /* no match */
! 1672: continue;
! 1673:
! 1674: /*
! 1675: * Skip when preceded with a backslash "\%" and "\#".
! 1676: * Note: In "\\%" the % is also not recognized!
! 1677: */
! 1678: if (*(p - 1) == '\\')
! 1679: {
! 1680: --p;
! 1681: STRCPY(p, p + 1); /* remove escaped char */
! 1682: continue;
! 1683: }
! 1684:
! 1685: /*
! 1686: * word or WORD under cursor
! 1687: */
! 1688: if (spec_idx == SPEC_CWORD || spec_idx == SPEC_CCWORD)
! 1689: {
! 1690: len = find_ident_under_cursor(&q, spec_idx == SPEC_CWORD ?
! 1691: (FIND_IDENT|FIND_STRING) : FIND_STRING);
! 1692: if (len == 0)
! 1693: goto doend;
! 1694: }
! 1695:
! 1696: /*
! 1697: * '#': Alternate file name
! 1698: * '%': Current file name
! 1699: * File name under the cursor
! 1700: * File name for autocommand
! 1701: * and following modifiers
! 1702: */
! 1703: else
! 1704: {
! 1705: switch (spec_idx)
! 1706: {
! 1707: case SPEC_PERC: /* '%': current file */
! 1708: if (curbuf->b_filename == NULL)
! 1709: {
! 1710: errormsg = (char_u *)"No file name to substitute for '%'";
! 1711: goto doend;
! 1712: }
! 1713: q = curbuf->b_xfilename;
! 1714: break;
! 1715:
! 1716: case SPEC_HASH: /* '#' or "#99": alternate file */
! 1717: q = p + 1;
! 1718: i = (int)getdigits(&q);
! 1719: n = q - p; /* length of what we expand */
! 1720:
! 1721: if (buflist_name_nr(i, &q, &do_ecmd_lnum) ==
! 1722: FAIL)
! 1723: {
! 1724: errormsg = (char_u *)"no alternate filename to substitute for '#'";
! 1725: goto doend;
! 1726: }
! 1727: break;
! 1728:
! 1729: case SPEC_CFILE: /* file name under cursor */
! 1730: q = file_name_at_cursor(FNAME_MESS|FNAME_HYP);
! 1731: if (q == NULL)
! 1732: goto doend;
! 1733: buf = q;
! 1734: break;
! 1735:
! 1736: case SPEC_AFILE: /* file name for autocommand */
! 1737: q = autocmd_fname;
! 1738: if (q == NULL)
! 1739: {
! 1740: errormsg = (char_u *)"no autocommand filename to substitute for \"<afile>\"";
! 1741: goto doend;
! 1742: }
! 1743: break;
! 1744: }
! 1745:
! 1746: len = STRLEN(q); /* length of new string */
! 1747: if (p[n] == '<') /* remove the file name extension */
! 1748: {
! 1749: ++n;
! 1750: if ((s = vim_strrchr(q, '.')) != NULL && s >= gettail(q))
! 1751: len = s - q;
! 1752: }
! 1753: else
! 1754: {
! 1755: char_u *tail;
! 1756:
! 1757: /* ":p" - full path/filename */
! 1758: if (p[n] == ':' && p[n + 1] == 'p')
! 1759: {
! 1760: n += 2;
! 1761: s = FullName_save(q);
! 1762: vim_free(buf); /* free any allocated file name */
! 1763: if (s == NULL)
! 1764: goto doend;
! 1765: q = s;
! 1766: len = STRLEN(q);
! 1767: buf = q;
! 1768: }
! 1769:
! 1770: tail = gettail(q);
! 1771:
! 1772: /* ":h" - head, remove "/filename" */
! 1773: /* ":h" can be repeated */
! 1774: while (p[n] == ':' && p[n + 1] == 'h')
! 1775: {
! 1776: n += 2;
! 1777: while (tail > q && ispathsep(tail[-1]))
! 1778: --tail;
! 1779: len = tail - q;
! 1780: while (tail > q && !ispathsep(tail[-1]))
! 1781: --tail;
! 1782: }
! 1783:
! 1784: /* ":t" - tail, just the basename */
! 1785: if (p[n] == ':' && p[n + 1] == 't')
! 1786: {
! 1787: n += 2;
! 1788: len -= tail - q;
! 1789: q = tail;
! 1790: }
! 1791:
! 1792: /* ":e" - extension */
! 1793: /* ":e" can be repeated */
! 1794: /* ":r" - root, without extension */
! 1795: /* ":r" can be repeated */
! 1796: while (p[n] == ':' &&
! 1797: (p[n + 1] == 'e' || p[n + 1] == 'r'))
! 1798: {
! 1799: /* find a '.' in the tail:
! 1800: * - for second :e: before the current fname
! 1801: * - otherwise: The last '.'
! 1802: */
! 1803: if (p[n + 1] == 'e' && q > tail)
! 1804: s = q - 2;
! 1805: else
! 1806: s = q + len - 1;
! 1807: for ( ; s > tail; --s)
! 1808: if (s[0] == '.')
! 1809: break;
! 1810: if (p[n + 1] == 'e') /* :e */
! 1811: {
! 1812: if (s > tail)
! 1813: {
! 1814: len += q - (s + 1);
! 1815: q = s + 1;
! 1816: }
! 1817: else if (q <= tail)
! 1818: len = 0;
! 1819: }
! 1820: else /* :r */
! 1821: {
! 1822: if (s > tail) /* remove one extension */
! 1823: len = s - q;
! 1824: }
! 1825: n += 2;
! 1826: }
! 1827: }
! 1828:
! 1829: /* TODO - ":s/pat/foo/" - substitute */
! 1830: /* if (p[n] == ':' && p[n + 1] == 's') */
! 1831: }
! 1832:
! 1833: /*
! 1834: * The new command line is build in cmdbuff[].
! 1835: * First allocate it.
! 1836: */
! 1837: i = STRLEN(*cmdlinep) + len + 3;
! 1838: if (nextcomm)
! 1839: i += STRLEN(nextcomm); /* add space for next command */
! 1840: alloc_cmdbuff(i);
! 1841: if (cmdbuff == NULL) /* out of memory! */
! 1842: goto doend;
! 1843:
! 1844: i = p - *cmdlinep; /* length of part before c */
! 1845: vim_memmove(cmdbuff, *cmdlinep, (size_t)i);
! 1846: vim_memmove(cmdbuff + i, q, (size_t)len); /* append the string */
! 1847: i += len; /* remember the end of the string */
! 1848: STRCPY(cmdbuff + i, p + n); /* append what is after '#' or '%' */
! 1849: p = cmdbuff + i - 1; /* remember where to continue */
! 1850: vim_free(buf); /* free any allocated string */
! 1851:
! 1852: if (nextcomm) /* append next command */
! 1853: {
! 1854: i = STRLEN(cmdbuff) + 1;
! 1855: STRCPY(cmdbuff + i, nextcomm);
! 1856: nextcomm = cmdbuff + i;
! 1857: }
! 1858: cmd = cmdbuff + (cmd - *cmdlinep);
! 1859: arg = cmdbuff + (arg - *cmdlinep);
! 1860: vim_free(*cmdlinep);
! 1861: *cmdlinep = cmdbuff;
! 1862: *cmdlinelenp = cmdbufflen;
! 1863: }
! 1864:
! 1865: /*
! 1866: * One file argument: expand wildcards.
! 1867: * Don't do this with ":r !command" or ":w !command".
! 1868: */
! 1869: if ((argt & NOSPC) && !usefilter)
! 1870: {
! 1871: #if defined(UNIX)
! 1872: /*
! 1873: * Only for Unix we check for more than one file name.
! 1874: * For other systems spaces are considered to be part
! 1875: * of the file name.
! 1876: * Only check here if there is no wildcard, otherwise ExpandOne
! 1877: * will check for errors. This allows ":e `ls ve*.c`" on Unix.
! 1878: */
! 1879: if (!expand_wildcards)
! 1880: for (p = arg; *p; ++p)
! 1881: {
! 1882: /* skip escaped characters */
! 1883: if (p[1] && (*p == '\\' || *p == Ctrl('V')))
! 1884: ++p;
! 1885: else if (vim_iswhite(*p))
! 1886: {
! 1887: errormsg = (char_u *)"Only one file name allowed";
! 1888: goto doend;
! 1889: }
! 1890: }
! 1891: #endif
! 1892: /*
! 1893: * halve the number of backslashes (this is vi compatible)
! 1894: */
! 1895: backslash_halve(arg, expand_wildcards);
! 1896:
! 1897: if (expand_wildcards)
! 1898: {
! 1899: if ((p = ExpandOne(arg, NULL, WILD_LIST_NOTFOUND,
! 1900: WILD_EXPAND_FREE)) == NULL)
! 1901: goto doend;
! 1902: n = arg - *cmdlinep;
! 1903: i = STRLEN(p) + n;
! 1904: if (nextcomm)
! 1905: i += STRLEN(nextcomm);
! 1906: alloc_cmdbuff(i);
! 1907: if (cmdbuff != NULL)
! 1908: {
! 1909: STRNCPY(cmdbuff, *cmdlinep, n);
! 1910: STRCPY(cmdbuff + n, p);
! 1911: if (nextcomm) /* append next command */
! 1912: {
! 1913: i = STRLEN(cmdbuff) + 1;
! 1914: STRCPY(cmdbuff + i, nextcomm);
! 1915: nextcomm = cmdbuff + i;
! 1916: }
! 1917: cmd = cmdbuff + (cmd - *cmdlinep);
! 1918: arg = cmdbuff + n;
! 1919: vim_free(*cmdlinep);
! 1920: *cmdlinep = cmdbuff;
! 1921: *cmdlinelenp = cmdbufflen;
! 1922: }
! 1923: vim_free(p);
! 1924: }
! 1925: }
! 1926: }
! 1927:
! 1928: /*
! 1929: * Accept buffer name. Cannot be used at the same time with a buffer
! 1930: * number.
! 1931: */
! 1932: if ((argt & BUFNAME) && *arg && addr_count == 0)
! 1933: {
! 1934: /*
! 1935: * :bdelete and :bunload take several arguments, separated by spaces:
! 1936: * find next space (skipping over escaped characters).
! 1937: * The others take one argument: ignore trailing spaces.
! 1938: */
! 1939: if (cmdidx == CMD_bdelete || cmdidx == CMD_bunload)
! 1940: p = skiptowhite_esc(arg);
! 1941: else
! 1942: {
! 1943: p = arg + STRLEN(arg);
! 1944: while (p > arg && vim_iswhite(p[-1]))
! 1945: --p;
! 1946: }
! 1947: line2 = buflist_findpat(arg, p);
! 1948: if (line2 < 0) /* failed */
! 1949: goto doend;
! 1950: addr_count = 1;
! 1951: arg = skipwhite(p);
! 1952: }
! 1953:
! 1954: /*
! 1955: * 6. switch on command name
! 1956: * arg points to the argument of the command
! 1957: * nextcomm points to the next command (if any)
! 1958: * cmd points to the name of the command (except for :make)
! 1959: * cmdidx is the index for the command
! 1960: * forceit is TRUE if ! present
! 1961: * addr_count is the number of addresses given
! 1962: * line1 is the first line number
! 1963: * line2 is the second line number or count
! 1964: * do_ecmd_cmd is +command argument to be used in edited file
! 1965: * do_ecmd_lnum is the line number in edited file
! 1966: * append is TRUE with ":w >>file" command
! 1967: * usefilter is TRUE with ":w !command" and ":r!command"
! 1968: * amount is number of '>' or '<' for shift command
! 1969: */
! 1970: cmdswitch:
! 1971: switch (cmdidx)
! 1972: {
! 1973: /*
! 1974: * quit current window, quit Vim if closed the last window
! 1975: */
! 1976: case CMD_quit:
! 1977: /* if more files or windows we won't exit */
! 1978: if (check_more(FALSE) == OK && only_one_window())
! 1979: exiting = TRUE;
! 1980: if (check_changed(curbuf, FALSE, FALSE) ||
! 1981: check_more(TRUE) == FAIL ||
! 1982: (only_one_window() && check_changed_any()))
! 1983: {
! 1984: exiting = FALSE;
! 1985: settmode(1);
! 1986: break;
! 1987: }
! 1988: if (only_one_window()) /* quit last window */
! 1989: getout(0);
! 1990: close_window(curwin, TRUE); /* may free buffer */
! 1991: break;
! 1992:
! 1993: /*
! 1994: * try to quit all windows
! 1995: */
! 1996: case CMD_qall:
! 1997: exiting = TRUE;
! 1998: if (!check_changed_any())
! 1999: getout(0);
! 2000: exiting = FALSE;
! 2001: settmode(1);
! 2002: break;
! 2003:
! 2004: /*
! 2005: * close current window, unless it is the last one
! 2006: */
! 2007: case CMD_close:
! 2008: close_window(curwin, FALSE); /* don't free buffer */
! 2009: break;
! 2010:
! 2011: /*
! 2012: * close all but current window, unless it is the last one
! 2013: */
! 2014: case CMD_only:
! 2015: close_others(TRUE);
! 2016: break;
! 2017:
! 2018: case CMD_stop:
! 2019: case CMD_suspend:
! 2020: #ifdef WIN32
! 2021: /*
! 2022: * Check if external commands are allowed now.
! 2023: */
! 2024: if (can_end_termcap_mode(TRUE) == FALSE)
! 2025: break;
! 2026: #endif
! 2027: if (!forceit)
! 2028: autowrite_all();
! 2029: windgoto((int)Rows - 1, 0);
! 2030: outchar('\n');
! 2031: flushbuf();
! 2032: stoptermcap();
! 2033: mch_restore_title(3); /* restore window titles */
! 2034: mch_suspend(); /* call machine specific function */
! 2035: maketitle();
! 2036: starttermcap();
! 2037: scroll_start(); /* scroll screen before redrawing */
! 2038: must_redraw = CLEAR;
! 2039: set_winsize(0, 0, FALSE); /* May have resized window -- webb */
! 2040: break;
! 2041:
! 2042: case CMD_exit:
! 2043: case CMD_xit:
! 2044: case CMD_wq:
! 2045: /* if more files or windows we won't exit */
! 2046: if (check_more(FALSE) == OK && only_one_window())
! 2047: exiting = TRUE;
! 2048: if (((cmdidx == CMD_wq || curbuf->b_changed) &&
! 2049: do_write(arg, FALSE) == FAIL) ||
! 2050: check_more(TRUE) == FAIL ||
! 2051: (only_one_window() && check_changed_any()))
! 2052: {
! 2053: exiting = FALSE;
! 2054: settmode(1);
! 2055: break;
! 2056: }
! 2057: if (only_one_window()) /* quit last window, exit Vim */
! 2058: getout(0);
! 2059: close_window(curwin, TRUE); /* quit current window, may free buffer */
! 2060: break;
! 2061:
! 2062: case CMD_xall: /* write all changed files and exit */
! 2063: case CMD_wqall: /* write all changed files and quit */
! 2064: exiting = TRUE;
! 2065: /* FALLTHROUGH */
! 2066:
! 2067: case CMD_wall: /* write all changed files */
! 2068: {
! 2069: BUF *buf;
! 2070: int error = 0;
! 2071:
! 2072: for (buf = firstbuf; buf != NULL; buf = buf->b_next)
! 2073: {
! 2074: if (buf->b_changed)
! 2075: {
! 2076: if (buf->b_filename == NULL)
! 2077: {
! 2078: emsg(e_noname);
! 2079: ++error;
! 2080: }
! 2081: else if (!forceit && buf->b_p_ro)
! 2082: {
! 2083: EMSG2("\"%s\" is readonly, use ! to write anyway", buf->b_xfilename);
! 2084: ++error;
! 2085: }
! 2086: else if (buf_write_all(buf) == FAIL)
! 2087: ++error;
! 2088: }
! 2089: }
! 2090: if (exiting)
! 2091: {
! 2092: if (!error)
! 2093: getout(0); /* exit Vim */
! 2094: exiting = FALSE;
! 2095: settmode(1);
! 2096: }
! 2097: }
! 2098: break;
! 2099:
! 2100: case CMD_preserve: /* put everything in .swp file */
! 2101: ml_preserve(curbuf, TRUE);
! 2102: break;
! 2103:
! 2104: case CMD_recover: /* recover file */
! 2105: recoverymode = TRUE;
! 2106: if (!check_changed(curbuf, FALSE, TRUE) &&
! 2107: (*arg == NUL || setfname(arg, NULL, TRUE) == OK))
! 2108: ml_recover();
! 2109: recoverymode = FALSE;
! 2110: break;
! 2111:
! 2112: case CMD_args:
! 2113: /*
! 2114: * ":args file": handle like :next
! 2115: */
! 2116: if (*arg != NUL && *arg != '|' && *arg != '\n')
! 2117: goto do_next;
! 2118:
! 2119: if (arg_count == 0) /* no file name list */
! 2120: {
! 2121: if (check_fname() == OK) /* check for no file name */
! 2122: smsg((char_u *)"[%s]", curbuf->b_filename);
! 2123: break;
! 2124: }
! 2125: /*
! 2126: * Overwrite the command, in most cases there is no scrolling
! 2127: * required and no wait_return().
! 2128: */
! 2129: gotocmdline(TRUE);
! 2130: for (i = 0; i < arg_count; ++i)
! 2131: {
! 2132: if (i == curwin->w_arg_idx)
! 2133: msg_outchar('[');
! 2134: msg_outtrans(arg_files[i]);
! 2135: if (i == curwin->w_arg_idx)
! 2136: msg_outchar(']');
! 2137: msg_outchar(' ');
! 2138: }
! 2139: break;
! 2140:
! 2141: case CMD_wnext:
! 2142: case CMD_wNext:
! 2143: case CMD_wprevious:
! 2144: if (cmd[1] == 'n')
! 2145: i = curwin->w_arg_idx + (int)line2;
! 2146: else
! 2147: i = curwin->w_arg_idx - (int)line2;
! 2148: line1 = 1;
! 2149: line2 = curbuf->b_ml.ml_line_count;
! 2150: if (do_write(arg, FALSE) == FAIL)
! 2151: break;
! 2152: goto donextfile;
! 2153:
! 2154: case CMD_next:
! 2155: case CMD_snext:
! 2156: do_next:
! 2157: /*
! 2158: * check for changed buffer now, if this fails the
! 2159: * argument list is not redefined.
! 2160: */
! 2161: if (!(p_hid || cmdidx == CMD_snext) &&
! 2162: check_changed(curbuf, TRUE, FALSE))
! 2163: break;
! 2164:
! 2165: if (*arg != NUL) /* redefine file list */
! 2166: {
! 2167: if (do_arglist(arg) == FAIL)
! 2168: break;
! 2169: i = 0;
! 2170: }
! 2171: else
! 2172: i = curwin->w_arg_idx + (int)line2;
! 2173:
! 2174: donextfile: if (i < 0 || i >= arg_count)
! 2175: {
! 2176: if (arg_count <= 1)
! 2177: EMSG("There is only one file to edit");
! 2178: else if (i < 0)
! 2179: EMSG("Cannot go before first file");
! 2180: else
! 2181: EMSG("Cannot go beyond last file");
! 2182: break;
! 2183: }
! 2184: setpcmark();
! 2185: if (*cmd == 's') /* split window first */
! 2186: {
! 2187: if (win_split(0, FALSE) == FAIL)
! 2188: break;
! 2189: }
! 2190: else
! 2191: {
! 2192: register int other;
! 2193:
! 2194: /*
! 2195: * if 'hidden' set, only check for changed file when
! 2196: * re-editing the same buffer
! 2197: */
! 2198: other = TRUE;
! 2199: if (p_hid)
! 2200: other = otherfile(fix_fname(arg_files[i]));
! 2201: if ((!p_hid || !other) &&
! 2202: check_changed(curbuf, TRUE, !other))
! 2203: break;
! 2204: }
! 2205: curwin->w_arg_idx = i;
! 2206: if (i == arg_count - 1)
! 2207: arg_had_last = TRUE;
! 2208: (void)do_ecmd(0, arg_files[curwin->w_arg_idx],
! 2209: NULL, do_ecmd_cmd, p_hid, do_ecmd_lnum, FALSE);
! 2210: break;
! 2211:
! 2212: case CMD_previous:
! 2213: case CMD_sprevious:
! 2214: case CMD_Next:
! 2215: case CMD_sNext:
! 2216: i = curwin->w_arg_idx - (int)line2;
! 2217: goto donextfile;
! 2218:
! 2219: case CMD_rewind:
! 2220: case CMD_srewind:
! 2221: i = 0;
! 2222: goto donextfile;
! 2223:
! 2224: case CMD_last:
! 2225: case CMD_slast:
! 2226: i = arg_count - 1;
! 2227: goto donextfile;
! 2228:
! 2229: case CMD_argument:
! 2230: case CMD_sargument:
! 2231: if (addr_count)
! 2232: i = line2 - 1;
! 2233: else
! 2234: i = curwin->w_arg_idx;
! 2235: goto donextfile;
! 2236:
! 2237: case CMD_all:
! 2238: case CMD_sall:
! 2239: if (addr_count == 0)
! 2240: line2 = 9999;
! 2241: do_arg_all((int)line2); /* open a window for each argument */
! 2242: break;
! 2243:
! 2244: case CMD_buffer: /* :[N]buffer [N] to buffer N */
! 2245: case CMD_sbuffer: /* :[N]sbuffer [N] to buffer N */
! 2246: if (*arg)
! 2247: {
! 2248: errormsg = e_trailing;
! 2249: break;
! 2250: }
! 2251: if (addr_count == 0) /* default is current buffer */
! 2252: (void)do_buffer(*cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO,
! 2253: DOBUF_CURRENT, FORWARD, 0, 0);
! 2254: else
! 2255: (void)do_buffer(*cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO,
! 2256: DOBUF_FIRST, FORWARD, (int)line2, 0);
! 2257: break;
! 2258:
! 2259: case CMD_bmodified: /* :[N]bmod [N] to next modified buffer */
! 2260: case CMD_sbmodified: /* :[N]sbmod [N] to next modified buffer */
! 2261: (void)do_buffer(*cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO,
! 2262: DOBUF_MOD, FORWARD, (int)line2, 0);
! 2263: break;
! 2264:
! 2265: case CMD_bnext: /* :[N]bnext [N] to next buffer */
! 2266: case CMD_sbnext: /* :[N]sbnext [N] to next buffer */
! 2267: (void)do_buffer(*cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO,
! 2268: DOBUF_CURRENT, FORWARD, (int)line2, 0);
! 2269: break;
! 2270:
! 2271: case CMD_bNext: /* :[N]bNext [N] to previous buffer */
! 2272: case CMD_bprevious: /* :[N]bprevious [N] to previous buffer */
! 2273: case CMD_sbNext: /* :[N]sbNext [N] to previous buffer */
! 2274: case CMD_sbprevious: /* :[N]sbprevious [N] to previous buffer */
! 2275: (void)do_buffer(*cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO,
! 2276: DOBUF_CURRENT, BACKWARD, (int)line2, 0);
! 2277: break;
! 2278:
! 2279: case CMD_brewind: /* :brewind to first buffer */
! 2280: case CMD_sbrewind: /* :sbrewind to first buffer */
! 2281: (void)do_buffer(*cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO,
! 2282: DOBUF_FIRST, FORWARD, 0, 0);
! 2283: break;
! 2284:
! 2285: case CMD_blast: /* :blast to last buffer */
! 2286: case CMD_sblast: /* :sblast to last buffer */
! 2287: (void)do_buffer(*cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO,
! 2288: DOBUF_LAST, FORWARD, 0, 0);
! 2289: break;
! 2290:
! 2291: case CMD_bunload: /* :[N]bunload[!] [N] [bufname] unload buffer */
! 2292: case CMD_bdelete: /* :[N]bdelete[!] [N] [bufname] delete buffer */
! 2293: errormsg = do_bufdel(
! 2294: cmdidx == CMD_bdelete ? DOBUF_DEL : DOBUF_UNLOAD,
! 2295: arg, addr_count, (int)line1, (int)line2, forceit);
! 2296: break;
! 2297:
! 2298: case CMD_unhide:
! 2299: case CMD_sunhide: /* open a window for loaded buffers */
! 2300: if (addr_count == 0)
! 2301: line2 = 9999;
! 2302: (void)do_buffer_all((int)line2, FALSE);
! 2303: break;
! 2304:
! 2305: case CMD_ball:
! 2306: case CMD_sball: /* open a window for every buffer */
! 2307: if (addr_count == 0)
! 2308: line2 = 9999;
! 2309: (void)do_buffer_all((int)line2, TRUE);
! 2310: break;
! 2311:
! 2312: case CMD_buffers:
! 2313: case CMD_files:
! 2314: case CMD_ls:
! 2315: buflist_list();
! 2316: break;
! 2317:
! 2318: case CMD_write:
! 2319: if (usefilter) /* input lines to shell command */
! 2320: do_bang(1, line1, line2, FALSE, arg, TRUE, FALSE);
! 2321: else
! 2322: (void)do_write(arg, append);
! 2323: break;
! 2324:
! 2325: /*
! 2326: * set screen mode
! 2327: * if no argument given, just get the screen size and redraw
! 2328: */
! 2329: case CMD_mode:
! 2330: if (*arg == NUL || mch_screenmode(arg) != FAIL)
! 2331: set_winsize(0, 0, FALSE);
! 2332: break;
! 2333:
! 2334: /*
! 2335: * set, increment or decrement current window height
! 2336: */
! 2337: case CMD_resize:
! 2338: n = atol((char *)arg);
! 2339: if (*arg == '-' || *arg == '+')
! 2340: win_setheight(curwin->w_height + (int)n);
! 2341: else
! 2342: {
! 2343: if (n == 0) /* default is very high */
! 2344: n = 9999;
! 2345: win_setheight((int)n);
! 2346: }
! 2347: break;
! 2348:
! 2349: /*
! 2350: * :sview [+command] file split window with new file, ro
! 2351: * :split [[+command] file] split window with current or new file
! 2352: * :new [[+command] file] split window with no or new file
! 2353: */
! 2354: case CMD_sview:
! 2355: case CMD_split:
! 2356: case CMD_new:
! 2357: old_curwin = curwin;
! 2358: if (win_split(addr_count ? (int)line2 : 0, FALSE) == FAIL)
! 2359: break;
! 2360: /*FALLTHROUGH*/
! 2361:
! 2362: case CMD_edit:
! 2363: case CMD_ex:
! 2364: case CMD_visual:
! 2365: case CMD_view:
! 2366: if ((cmdidx == CMD_new) && *arg == NUL)
! 2367: {
! 2368: setpcmark();
! 2369: (void)do_ecmd(0, NULL, NULL, do_ecmd_cmd, TRUE,
! 2370: (linenr_t)1, FALSE);
! 2371: }
! 2372: else if (cmdidx != CMD_split || *arg != NUL)
! 2373: {
! 2374: n = readonlymode;
! 2375: if (cmdidx == CMD_view || cmdidx == CMD_sview)
! 2376: readonlymode = TRUE;
! 2377: setpcmark();
! 2378: (void)do_ecmd(0, arg, NULL, do_ecmd_cmd, p_hid,
! 2379: do_ecmd_lnum, FALSE);
! 2380: readonlymode = n;
! 2381: }
! 2382: else
! 2383: updateScreen(NOT_VALID);
! 2384: /* if ":split file" worked, set alternate filename in
! 2385: * old window to new file */
! 2386: if ((cmdidx == CMD_new || cmdidx == CMD_split) &&
! 2387: *arg != NUL && curwin != old_curwin &&
! 2388: old_curwin->w_buffer != curbuf)
! 2389: old_curwin->w_alt_fnum = curbuf->b_fnum;
! 2390: break;
! 2391:
! 2392: #ifdef USE_GUI
! 2393: /*
! 2394: * Change from the terminal version to the GUI version. File names may
! 2395: * be given to redefine the args list -- webb
! 2396: */
! 2397: case CMD_gvim:
! 2398: case CMD_gui:
! 2399: if (arg[0] == '-' && arg[1] == 'f' &&
! 2400: (arg[2] == NUL || vim_iswhite(arg[2])))
! 2401: {
! 2402: gui.dofork = FALSE;
! 2403: arg = skipwhite(arg + 2);
! 2404: }
! 2405: else
! 2406: gui.dofork = TRUE;
! 2407: if (!gui.in_use)
! 2408: gui_start();
! 2409: if (*arg != NUL && *arg != '|' && *arg != '\n')
! 2410: goto do_next;
! 2411: break;
! 2412: #endif
! 2413:
! 2414: case CMD_file:
! 2415: do_file(arg, forceit);
! 2416: break;
! 2417:
! 2418: case CMD_swapname:
! 2419: if (curbuf->b_ml.ml_mfp == NULL ||
! 2420: (p = curbuf->b_ml.ml_mfp->mf_fname) == NULL)
! 2421: MSG("No swap file");
! 2422: else
! 2423: msg(p);
! 2424: break;
! 2425:
! 2426: case CMD_mfstat: /* print memfile statistics, for debugging */
! 2427: mf_statistics();
! 2428: break;
! 2429:
! 2430: case CMD_read:
! 2431: if (usefilter) /* :r!cmd */
! 2432: {
! 2433: do_bang(1, line1, line2, FALSE, arg, FALSE, TRUE);
! 2434: break;
! 2435: }
! 2436: if (u_save(line2, (linenr_t)(line2 + 1)) == FAIL)
! 2437: break;
! 2438: if (*arg == NUL)
! 2439: {
! 2440: if (check_fname() == FAIL) /* check for no file name */
! 2441: break;
! 2442: i = readfile(curbuf->b_filename, curbuf->b_sfilename,
! 2443: line2, FALSE, (linenr_t)0, MAXLNUM, FALSE);
! 2444: }
! 2445: else
! 2446: {
! 2447: i = readfile(arg, NULL,
! 2448: line2, FALSE, (linenr_t)0, MAXLNUM, FALSE);
! 2449: }
! 2450: if (i == FAIL)
! 2451: {
! 2452: emsg2(e_notopen, arg);
! 2453: break;
! 2454: }
! 2455:
! 2456: updateScreen(NOT_VALID);
! 2457: break;
! 2458:
! 2459: case CMD_cd:
! 2460: case CMD_chdir:
! 2461: #ifdef UNIX
! 2462: /*
! 2463: * for UNIX ":cd" means: go to home directory
! 2464: */
! 2465: if (*arg == NUL) /* use NameBuff for home directory name */
! 2466: {
! 2467: expand_env((char_u *)"$HOME", NameBuff, MAXPATHL);
! 2468: arg = NameBuff;
! 2469: }
! 2470: #endif
! 2471: if (*arg != NUL)
! 2472: {
! 2473: if (!did_cd)
! 2474: {
! 2475: BUF *buf;
! 2476:
! 2477: /* use full path from now on for names of files
! 2478: * being edited and swap files */
! 2479: for (buf = firstbuf; buf != NULL; buf = buf->b_next)
! 2480: {
! 2481: buf->b_xfilename = buf->b_filename;
! 2482: mf_fullname(buf->b_ml.ml_mfp);
! 2483: }
! 2484: status_redraw_all();
! 2485: }
! 2486: did_cd = TRUE;
! 2487: if (vim_chdir((char *)arg))
! 2488: emsg(e_failed);
! 2489: break;
! 2490: }
! 2491: /*FALLTHROUGH*/
! 2492:
! 2493: case CMD_pwd:
! 2494: if (mch_dirname(NameBuff, MAXPATHL) == OK)
! 2495: msg(NameBuff);
! 2496: else
! 2497: emsg(e_unknown);
! 2498: break;
! 2499:
! 2500: case CMD_equal:
! 2501: smsg((char_u *)"line %ld", (long)line2);
! 2502: break;
! 2503:
! 2504: case CMD_list:
! 2505: i = curwin->w_p_list;
! 2506: curwin->w_p_list = 1;
! 2507: case CMD_number: /* :nu */
! 2508: case CMD_pound: /* :# */
! 2509: case CMD_print: /* :p */
! 2510: for ( ;!got_int; mch_breakcheck())
! 2511: {
! 2512: print_line(line1,
! 2513: (cmdidx == CMD_number || cmdidx == CMD_pound));
! 2514: if (++line1 > line2)
! 2515: break;
! 2516: flushbuf(); /* show one line at a time */
! 2517: }
! 2518: setpcmark();
! 2519: curwin->w_cursor.lnum = line2; /* put cursor at last line */
! 2520:
! 2521: if (cmdidx == CMD_list)
! 2522: curwin->w_p_list = i;
! 2523:
! 2524: break;
! 2525:
! 2526: case CMD_shell:
! 2527: do_shell(NULL);
! 2528: break;
! 2529:
! 2530: case CMD_sleep:
! 2531: n = curwin->w_winpos + curwin->w_row - msg_scrolled;
! 2532: if (n >= 0)
! 2533: {
! 2534: windgoto((int)n, curwin->w_col);
! 2535: flushbuf();
! 2536: }
! 2537: mch_delay(line2 * 1000L, TRUE);
! 2538: break;
! 2539:
! 2540: case CMD_stag:
! 2541: postponed_split = TRUE;
! 2542: /*FALLTHROUGH*/
! 2543: case CMD_tag:
! 2544: do_tag(arg, 0, addr_count ? (int)line2 : 1);
! 2545: break;
! 2546:
! 2547: case CMD_pop:
! 2548: do_tag((char_u *)"", 1, addr_count ? (int)line2 : 1);
! 2549: break;
! 2550:
! 2551: case CMD_tags:
! 2552: do_tags();
! 2553: break;
! 2554:
! 2555: case CMD_marks:
! 2556: do_marks(arg);
! 2557: break;
! 2558:
! 2559: case CMD_jumps:
! 2560: do_jumps();
! 2561: break;
! 2562:
! 2563: case CMD_ascii:
! 2564: do_ascii();
! 2565: break;
! 2566:
! 2567: case CMD_checkpath:
! 2568: find_pattern_in_path(NULL, 0, FALSE, FALSE, CHECK_PATH, 1L,
! 2569: forceit ? ACTION_SHOW_ALL : ACTION_SHOW,
! 2570: (linenr_t)1, (linenr_t)MAXLNUM);
! 2571: break;
! 2572:
! 2573: case CMD_digraphs:
! 2574: #ifdef DIGRAPHS
! 2575: if (*arg)
! 2576: putdigraph(arg);
! 2577: else
! 2578: listdigraphs();
! 2579: #else
! 2580: EMSG("No digraphs in this version");
! 2581: #endif /* DIGRAPHS */
! 2582: break;
! 2583:
! 2584: case CMD_set:
! 2585: (void)do_set(arg);
! 2586: break;
! 2587:
! 2588: case CMD_fixdel:
! 2589: do_fixdel();
! 2590: break;
! 2591:
! 2592: #ifdef AUTOCMD
! 2593: case CMD_autocmd:
! 2594: /*
! 2595: * Disallow auto commands from .exrc and .vimrc in current
! 2596: * directory for security reasons.
! 2597: */
! 2598: if (secure)
! 2599: {
! 2600: secure = 2;
! 2601: errormsg = e_curdir;
! 2602: }
! 2603: else
! 2604: do_autocmd(arg, forceit); /* handle the auto commands */
! 2605: break;
! 2606:
! 2607: case CMD_doautocmd:
! 2608: do_doautocmd(arg); /* apply the automatic commands */
! 2609: do_modelines();
! 2610: break;
! 2611: #endif
! 2612:
! 2613: case CMD_abbreviate:
! 2614: case CMD_cabbrev:
! 2615: case CMD_iabbrev:
! 2616: case CMD_cnoreabbrev:
! 2617: case CMD_inoreabbrev:
! 2618: case CMD_noreabbrev:
! 2619: case CMD_unabbreviate:
! 2620: case CMD_cunabbrev:
! 2621: case CMD_iunabbrev:
! 2622: i = ABBREV;
! 2623: goto doabbr; /* almost the same as mapping */
! 2624:
! 2625: case CMD_nmap:
! 2626: case CMD_vmap:
! 2627: case CMD_cmap:
! 2628: case CMD_imap:
! 2629: case CMD_map:
! 2630: case CMD_nnoremap:
! 2631: case CMD_vnoremap:
! 2632: case CMD_cnoremap:
! 2633: case CMD_inoremap:
! 2634: case CMD_noremap:
! 2635: /*
! 2636: * If we are sourcing .exrc or .vimrc in current directory we
! 2637: * print the mappings for security reasons.
! 2638: */
! 2639: if (secure)
! 2640: {
! 2641: secure = 2;
! 2642: msg_outtrans(cmd);
! 2643: msg_outchar('\n');
! 2644: }
! 2645: case CMD_nunmap:
! 2646: case CMD_vunmap:
! 2647: case CMD_cunmap:
! 2648: case CMD_iunmap:
! 2649: case CMD_unmap:
! 2650: i = 0;
! 2651: doabbr:
! 2652: if (*cmd == 'c') /* cmap, cunmap, cnoremap, etc. */
! 2653: {
! 2654: i += CMDLINE;
! 2655: ++cmd;
! 2656: }
! 2657: else if (*cmd == 'i') /* imap, iunmap, inoremap, etc. */
! 2658: {
! 2659: i += INSERT;
! 2660: ++cmd;
! 2661: }
! 2662: /* nmap, nunmap, nnoremap */
! 2663: else if (*cmd == 'n' && *(cmd + 1) != 'o')
! 2664: {
! 2665: i += NORMAL;
! 2666: ++cmd;
! 2667: }
! 2668: else if (*cmd == 'v') /* vmap, vunmap, vnoremap */
! 2669: {
! 2670: i += VISUAL;
! 2671: ++cmd;
! 2672: }
! 2673: else if (forceit || i) /* map!, unmap!, noremap!, abbrev */
! 2674: i += INSERT + CMDLINE;
! 2675: else /* map, unmap, noremap */
! 2676: i += NORMAL + VISUAL;
! 2677: switch (do_map((*cmd == 'n') ? 2 : (*cmd == 'u'), arg, i))
! 2678: {
! 2679: case 1: emsg(e_invarg);
! 2680: break;
! 2681: case 2: emsg(e_nomap);
! 2682: break;
! 2683: case 3: emsg(e_ambmap);
! 2684: break;
! 2685: }
! 2686: break;
! 2687:
! 2688: case CMD_mapclear:
! 2689: case CMD_imapclear:
! 2690: case CMD_nmapclear:
! 2691: case CMD_vmapclear:
! 2692: case CMD_cmapclear:
! 2693: map_clear(*cmd, forceit, FALSE);
! 2694: break;
! 2695:
! 2696: case CMD_abclear:
! 2697: case CMD_iabclear:
! 2698: case CMD_cabclear:
! 2699: map_clear(*cmd, FALSE, TRUE);
! 2700: break;
! 2701:
! 2702: #ifdef USE_GUI
! 2703: case CMD_menu: case CMD_noremenu: case CMD_unmenu:
! 2704: case CMD_nmenu: case CMD_nnoremenu: case CMD_nunmenu:
! 2705: case CMD_vmenu: case CMD_vnoremenu: case CMD_vunmenu:
! 2706: case CMD_imenu: case CMD_inoremenu: case CMD_iunmenu:
! 2707: case CMD_cmenu: case CMD_cnoremenu: case CMD_cunmenu:
! 2708: gui_do_menu(cmd, arg, forceit);
! 2709: break;
! 2710: #endif /* USE_GUI */
! 2711:
! 2712: case CMD_display:
! 2713: case CMD_registers:
! 2714: do_dis(arg); /* display buffer contents */
! 2715: break;
! 2716:
! 2717: case CMD_help:
! 2718: do_help(arg);
! 2719: break;
! 2720:
! 2721: case CMD_version:
! 2722: do_version(arg);
! 2723: break;
! 2724:
! 2725: case CMD_winsize: /* obsolete command */
! 2726: line1 = getdigits(&arg);
! 2727: arg = skipwhite(arg);
! 2728: line2 = getdigits(&arg);
! 2729: set_winsize((int)line1, (int)line2, TRUE);
! 2730: break;
! 2731:
! 2732: case CMD_delete:
! 2733: case CMD_yank:
! 2734: case CMD_rshift:
! 2735: case CMD_lshift:
! 2736: yankbuffer = regname;
! 2737: curbuf->b_op_start.lnum = line1;
! 2738: curbuf->b_op_end.lnum = line2;
! 2739: op_line_count = line2 - line1 + 1;
! 2740: op_motion_type = MLINE;
! 2741: if (cmdidx != CMD_yank) /* set cursor position for undo */
! 2742: {
! 2743: setpcmark();
! 2744: curwin->w_cursor.lnum = line1;
! 2745: beginline(MAYBE);
! 2746: }
! 2747: switch (cmdidx)
! 2748: {
! 2749: case CMD_delete:
! 2750: do_delete();
! 2751: break;
! 2752: case CMD_yank:
! 2753: (void)do_yank(FALSE, TRUE);
! 2754: break;
! 2755: #ifdef RIGHTLEFT
! 2756: case CMD_rshift:
! 2757: do_shift(curwin->w_p_rl ? LSHIFT : RSHIFT, FALSE, amount);
! 2758: break;
! 2759: case CMD_lshift:
! 2760: do_shift(curwin->w_p_rl ? RSHIFT : LSHIFT, FALSE, amount);
! 2761: break;
! 2762: #else
! 2763: case CMD_rshift:
! 2764: do_shift(RSHIFT, FALSE, amount);
! 2765: break;
! 2766: case CMD_lshift:
! 2767: do_shift(LSHIFT, FALSE, amount);
! 2768: break;
! 2769: #endif
! 2770: }
! 2771: break;
! 2772:
! 2773: case CMD_put:
! 2774: yankbuffer = regname;
! 2775: curwin->w_cursor.lnum = line2;
! 2776: do_put(forceit ? BACKWARD : FORWARD, -1L, FALSE);
! 2777: break;
! 2778:
! 2779: case CMD_t:
! 2780: case CMD_copy:
! 2781: case CMD_move:
! 2782: n = get_address(&arg);
! 2783: if (arg == NULL) /* error detected */
! 2784: {
! 2785: nextcomm = NULL;
! 2786: break;
! 2787: }
! 2788: /*
! 2789: * move or copy lines from 'line1'-'line2' to below line 'n'
! 2790: */
! 2791: if (n == MAXLNUM || n < 0 || n > curbuf->b_ml.ml_line_count)
! 2792: {
! 2793: emsg(e_invaddr);
! 2794: break;
! 2795: }
! 2796:
! 2797: if (cmdidx == CMD_move)
! 2798: {
! 2799: if (do_move(line1, line2, n) == FAIL)
! 2800: break;
! 2801: }
! 2802: else
! 2803: do_copy(line1, line2, n);
! 2804: u_clearline();
! 2805: beginline(MAYBE);
! 2806: updateScreen(NOT_VALID);
! 2807: break;
! 2808:
! 2809: case CMD_and: /* :& */
! 2810: case CMD_tilde: /* :~ */
! 2811: case CMD_substitute: /* :s */
! 2812: do_sub(line1, line2, arg, &nextcomm,
! 2813: cmdidx == CMD_substitute ? 0 :
! 2814: cmdidx == CMD_and ? 1 : 2);
! 2815: break;
! 2816:
! 2817: case CMD_join:
! 2818: curwin->w_cursor.lnum = line1;
! 2819: if (line1 == line2)
! 2820: {
! 2821: if (addr_count >= 2) /* :2,2join does nothing */
! 2822: break;
! 2823: if (line2 == curbuf->b_ml.ml_line_count)
! 2824: {
! 2825: beep_flush();
! 2826: break;
! 2827: }
! 2828: ++line2;
! 2829: }
! 2830: do_do_join(line2 - line1 + 1, !forceit, FALSE);
! 2831: beginline(TRUE);
! 2832: break;
! 2833:
! 2834: case CMD_global:
! 2835: if (forceit)
! 2836: *cmd = 'v';
! 2837: case CMD_vglobal:
! 2838: do_glob(*cmd, line1, line2, arg);
! 2839: break;
! 2840:
! 2841: case CMD_at: /* :[addr]@r */
! 2842: curwin->w_cursor.lnum = line2;
! 2843: /* put the register in mapbuf */
! 2844: if (do_execbuf(*arg, TRUE,
! 2845: vim_strchr(p_cpo, CPO_EXECBUF) != NULL) == FAIL)
! 2846: beep_flush();
! 2847: else
! 2848: /* execute from the mapbuf */
! 2849: while (vpeekc() == ':')
! 2850: {
! 2851: (void)vgetc();
! 2852: (void)do_cmdline((char_u *)NULL, TRUE, TRUE);
! 2853: }
! 2854: break;
! 2855:
! 2856: case CMD_bang:
! 2857: do_bang(addr_count, line1, line2, forceit, arg, TRUE, TRUE);
! 2858: break;
! 2859:
! 2860: case CMD_undo:
! 2861: u_undo(1);
! 2862: break;
! 2863:
! 2864: case CMD_redo:
! 2865: u_redo(1);
! 2866: break;
! 2867:
! 2868: case CMD_source:
! 2869: if (forceit) /* :so! read vi commands */
! 2870: (void)openscript(arg);
! 2871: /* :so read ex commands */
! 2872: else if (do_source(arg, FALSE) == FAIL)
! 2873: emsg2(e_notopen, arg);
! 2874: break;
! 2875:
! 2876: #ifdef VIMINFO
! 2877: case CMD_rviminfo:
! 2878: p = p_viminfo;
! 2879: if (*p_viminfo == NUL)
! 2880: p_viminfo = (char_u *)"'100";
! 2881: if (read_viminfo(arg, TRUE, TRUE, forceit) == FAIL)
! 2882: EMSG("Cannot open viminfo file for reading");
! 2883: p_viminfo = p;
! 2884: break;
! 2885:
! 2886: case CMD_wviminfo:
! 2887: p = p_viminfo;
! 2888: if (*p_viminfo == NUL)
! 2889: p_viminfo = (char_u *)"'100";
! 2890: write_viminfo(arg, forceit);
! 2891: p_viminfo = p;
! 2892: break;
! 2893: #endif /* VIMINFO */
! 2894:
! 2895: case CMD_mkvimrc:
! 2896: if (*arg == NUL)
! 2897: arg = (char_u *)VIMRC_FILE;
! 2898: /*FALLTHROUGH*/
! 2899:
! 2900: case CMD_mkexrc:
! 2901: {
! 2902: FILE *fd;
! 2903:
! 2904: if (*arg == NUL)
! 2905: arg = (char_u *)EXRC_FILE;
! 2906: #ifdef UNIX
! 2907: /* with Unix it is possible to open a directory */
! 2908: if (mch_isdir(arg))
! 2909: {
! 2910: EMSG2("\"%s\" is a directory", arg);
! 2911: break;
! 2912: }
! 2913: #endif
! 2914: if (!forceit && vim_fexists(arg))
! 2915: {
! 2916: EMSG2("\"%s\" exists (use ! to override)", arg);
! 2917: break;
! 2918: }
! 2919:
! 2920: if ((fd = fopen((char *)arg, WRITEBIN)) == NULL)
! 2921: {
! 2922: EMSG2("Cannot open \"%s\" for writing", arg);
! 2923: break;
! 2924: }
! 2925:
! 2926: /* Write the version command for :mkvimrc */
! 2927: if (cmdidx == CMD_mkvimrc)
! 2928: {
! 2929: #ifdef USE_CRNL
! 2930: fprintf(fd, "version 4.0\r\n");
! 2931: #else
! 2932: fprintf(fd, "version 4.0\n");
! 2933: #endif
! 2934: }
! 2935:
! 2936: if (makemap(fd) == FAIL || makeset(fd) == FAIL ||
! 2937: fclose(fd))
! 2938: emsg(e_write);
! 2939: break;
! 2940: }
! 2941:
! 2942: case CMD_cc:
! 2943: qf_jump(0, addr_count ? (int)line2 : 0);
! 2944: break;
! 2945:
! 2946: case CMD_cfile:
! 2947: if (*arg != NUL)
! 2948: {
! 2949: /*
! 2950: * Great trick: Insert 'ef=' before arg.
! 2951: * Always ok, because "cf " must be there.
! 2952: */
! 2953: arg -= 3;
! 2954: arg[0] = 'e';
! 2955: arg[1] = 'f';
! 2956: arg[2] = '=';
! 2957: (void)do_set(arg);
! 2958: }
! 2959: if (qf_init() == OK)
! 2960: qf_jump(0, 0); /* display first error */
! 2961: break;
! 2962:
! 2963: case CMD_clist:
! 2964: qf_list(forceit);
! 2965: break;
! 2966:
! 2967: case CMD_cnext:
! 2968: qf_jump(FORWARD, addr_count ? (int)line2 : 1);
! 2969: break;
! 2970:
! 2971: case CMD_cNext:
! 2972: case CMD_cprevious:
! 2973: qf_jump(BACKWARD, addr_count ? (int)line2 : 1);
! 2974: break;
! 2975:
! 2976: case CMD_cquit:
! 2977: getout(1); /* this does not always work. why? */
! 2978:
! 2979: case CMD_mark:
! 2980: case CMD_k:
! 2981: pos = curwin->w_cursor; /* save curwin->w_cursor */
! 2982: curwin->w_cursor.lnum = line2;
! 2983: beginline(MAYBE);
! 2984: (void)setmark(*arg); /* set mark */
! 2985: curwin->w_cursor = pos; /* restore curwin->w_cursor */
! 2986: break;
! 2987:
! 2988: case CMD_center:
! 2989: case CMD_right:
! 2990: case CMD_left:
! 2991: do_align(line1, line2, atoi((char *)arg),
! 2992: cmdidx == CMD_center ? 0 : cmdidx == CMD_right ? 1 : -1);
! 2993: break;
! 2994:
! 2995: case CMD_retab:
! 2996: n = getdigits(&arg);
! 2997: do_retab(line1, line2, (int)n, forceit);
! 2998: u_clearline();
! 2999: updateScreen(NOT_VALID);
! 3000: break;
! 3001:
! 3002: case CMD_make:
! 3003: do_make(arg);
! 3004: break;
! 3005:
! 3006: /*
! 3007: * :normal[!] {commands} - execute normal mode commands
! 3008: * Mostly used for ":autocmd".
! 3009: */
! 3010: case CMD_normal:
! 3011: /*
! 3012: * Stuff the argument into the typeahead buffer.
! 3013: * Execute normal() until there is no more typeahead than
! 3014: * there was before this command.
! 3015: */
! 3016: len = typelen;
! 3017: ins_typebuf(arg, forceit ? -1 : 0, 0, TRUE);
! 3018: while ((!stuff_empty() ||
! 3019: (!typebuf_typed() && typelen > len)) && !got_int)
! 3020: {
! 3021: adjust_cursor(); /* put cursor on an existing line */
! 3022: cursupdate(); /* update cursor position */
! 3023: normal(); /* get and execute a normal mode command */
! 3024: }
! 3025: break;
! 3026:
! 3027: case CMD_isearch:
! 3028: case CMD_dsearch:
! 3029: i = ACTION_SHOW;
! 3030: goto find_pat;
! 3031:
! 3032: case CMD_ilist:
! 3033: case CMD_dlist:
! 3034: i = ACTION_SHOW_ALL;
! 3035: goto find_pat;
! 3036:
! 3037: case CMD_ijump:
! 3038: case CMD_djump:
! 3039: i = ACTION_GOTO;
! 3040: goto find_pat;
! 3041:
! 3042: case CMD_isplit:
! 3043: case CMD_dsplit:
! 3044: i = ACTION_SPLIT;
! 3045: find_pat:
! 3046: {
! 3047: int whole = TRUE;
! 3048:
! 3049: n = 1;
! 3050: if (isdigit(*arg)) /* get count */
! 3051: {
! 3052: n = getdigits(&arg);
! 3053: arg = skipwhite(arg);
! 3054: }
! 3055: if (*arg == '/') /* Match regexp, not just whole words */
! 3056: {
! 3057: whole = FALSE;
! 3058: ++arg;
! 3059: for (p = arg; *p && *p != '/'; p++)
! 3060: if (*p == '\\' && p[1] != NUL)
! 3061: p++;
! 3062: if (*p)
! 3063: {
! 3064: *p++ = NUL;
! 3065: p = skipwhite(p);
! 3066:
! 3067: /* Check for trailing illegal characters */
! 3068: if (*p && vim_strchr((char_u *)"|\"\n", *p) == NULL)
! 3069: errormsg = e_trailing;
! 3070: else
! 3071: nextcomm = p;
! 3072: }
! 3073: }
! 3074: find_pattern_in_path(arg, (int)STRLEN(arg), whole, !forceit,
! 3075: *cmd == 'd' ? FIND_DEFINE : FIND_ANY,
! 3076: n, i, line1, line2);
! 3077: }
! 3078: break;
! 3079:
! 3080: default:
! 3081: /* Normal illegal commands have already been handled */
! 3082: errormsg = (char_u *)"Sorry, this command is not implemented";
! 3083: }
! 3084:
! 3085:
! 3086: doend:
! 3087: if (errormsg != NULL)
! 3088: {
! 3089: emsg(errormsg);
! 3090: if (sourcing)
! 3091: {
! 3092: MSG_OUTSTR(": ");
! 3093: msg_outtrans(*cmdlinep);
! 3094: }
! 3095: }
! 3096: if (did_emsg)
! 3097: nextcomm = NULL; /* cancel nextcomm at an error */
! 3098: forceit = FALSE; /* reset now so it can be used in getfile() */
! 3099: if (nextcomm && *nextcomm == NUL) /* not really a next command */
! 3100: nextcomm = NULL;
! 3101: return nextcomm;
! 3102: }
! 3103:
! 3104: /*
! 3105: * If 'autowrite' option set, try to write the file.
! 3106: *
! 3107: * return FAIL for failure, OK otherwise
! 3108: */
! 3109: int
! 3110: autowrite(buf)
! 3111: BUF *buf;
! 3112: {
! 3113: if (!p_aw || (!forceit && buf->b_p_ro) || buf->b_filename == NULL)
! 3114: return FAIL;
! 3115: return buf_write_all(buf);
! 3116: }
! 3117:
! 3118: /*
! 3119: * flush all buffers, except the ones that are readonly
! 3120: */
! 3121: void
! 3122: autowrite_all()
! 3123: {
! 3124: BUF *buf;
! 3125:
! 3126: if (!p_aw)
! 3127: return;
! 3128: for (buf = firstbuf; buf; buf = buf->b_next)
! 3129: if (buf->b_changed && !buf->b_p_ro)
! 3130: (void)buf_write_all(buf);
! 3131: }
! 3132:
! 3133: /*
! 3134: * flush the contents of a buffer, unless it has no file name
! 3135: *
! 3136: * return FAIL for failure, OK otherwise
! 3137: */
! 3138: static int
! 3139: buf_write_all(buf)
! 3140: BUF *buf;
! 3141: {
! 3142: return (buf_write(buf, buf->b_filename, buf->b_sfilename,
! 3143: (linenr_t)1, buf->b_ml.ml_line_count, 0, 0, TRUE, FALSE));
! 3144: }
! 3145:
! 3146: /*
! 3147: * write current buffer to file 'fname'
! 3148: * if 'append' is TRUE, append to the file
! 3149: *
! 3150: * if *fname == NUL write to current file
! 3151: * if b_notedited is TRUE, check for overwriting current file
! 3152: *
! 3153: * return FAIL for failure, OK otherwise
! 3154: */
! 3155: static int
! 3156: do_write(fname, append)
! 3157: char_u *fname;
! 3158: int append;
! 3159: {
! 3160: int other;
! 3161: char_u *sfname = NULL; /* init to shut up gcc */
! 3162:
! 3163: if (*fname == NUL)
! 3164: other = FALSE;
! 3165: else
! 3166: {
! 3167: sfname = fname;
! 3168: fname = fix_fname(fname);
! 3169: other = otherfile(fname);
! 3170: }
! 3171:
! 3172: /*
! 3173: * if we have a new file name put it in the list of alternate file names
! 3174: */
! 3175: if (other)
! 3176: setaltfname(fname, sfname, (linenr_t)1);
! 3177:
! 3178: /*
! 3179: * writing to the current file is not allowed in readonly mode
! 3180: * and need a file name
! 3181: */
! 3182: if (!other && (check_readonly() || check_fname() == FAIL))
! 3183: return FAIL;
! 3184:
! 3185: if (!other)
! 3186: {
! 3187: fname = curbuf->b_filename;
! 3188: sfname = curbuf->b_sfilename;
! 3189: /*
! 3190: * Not writing the whole file is only allowed with '!'.
! 3191: */
! 3192: if ((line1 != 1 || line2 != curbuf->b_ml.ml_line_count) &&
! 3193: !forceit && !append && !p_wa)
! 3194: {
! 3195: EMSG("Use ! to write partial buffer");
! 3196: return FAIL;
! 3197: }
! 3198: }
! 3199:
! 3200: /*
! 3201: * write to other file or b_notedited set or not writing the whole file:
! 3202: * overwriting only allowed with '!'
! 3203: */
! 3204: if ((other || curbuf->b_notedited) && !forceit &&
! 3205: !append && !p_wa && vim_fexists(fname))
! 3206: { /* don't overwrite existing file */
! 3207: #ifdef UNIX
! 3208: /* with UNIX it is possible to open a directory */
! 3209: if (mch_isdir(fname))
! 3210: EMSG2("\"%s\" is a directory", fname);
! 3211: else
! 3212: #endif
! 3213: emsg(e_exists);
! 3214: return FAIL;
! 3215: }
! 3216: return (buf_write(curbuf, fname, sfname, line1, line2,
! 3217: append, forceit, TRUE, FALSE));
! 3218: }
! 3219:
! 3220: /*
! 3221: * start editing a new file
! 3222: *
! 3223: * fnum: file number; if zero use fname/sfname
! 3224: * fname: the file name
! 3225: * - full path if sfname used,
! 3226: * - any file name if sfname is NULL
! 3227: * - empty string to re-edit with the same file name (but may be
! 3228: * in a different directory)
! 3229: * - NULL to start an empty buffer
! 3230: * sfname: the short file name (or NULL)
! 3231: * command: the command to be executed after loading the file
! 3232: * hide: if TRUE don't free the current buffer
! 3233: * newlnum: put cursor on this line number (if possible)
! 3234: * set_help: set b_help flag of (new) buffer before opening file
! 3235: *
! 3236: * return FAIL for failure, OK otherwise
! 3237: */
! 3238: int
! 3239: do_ecmd(fnum, fname, sfname, command, hide, newlnum, set_help)
! 3240: int fnum;
! 3241: char_u *fname;
! 3242: char_u *sfname;
! 3243: char_u *command;
! 3244: int hide;
! 3245: linenr_t newlnum;
! 3246: int set_help;
! 3247: {
! 3248: int other_file; /* TRUE if editing another file */
! 3249: int oldbuf = FALSE; /* TRUE if using existing buffer */
! 3250: BUF *buf;
! 3251:
! 3252: if (fnum != 0)
! 3253: {
! 3254: if (fnum == curbuf->b_fnum) /* file is already being edited */
! 3255: return OK; /* nothing to do */
! 3256: other_file = TRUE;
! 3257: }
! 3258: else
! 3259: {
! 3260: /* if no short name given, use fname for short name */
! 3261: if (sfname == NULL)
! 3262: sfname = fname;
! 3263: #ifdef USE_FNAME_CASE
! 3264: # ifdef USE_LONG_FNAME
! 3265: if (USE_LONG_FNAME)
! 3266: # endif
! 3267: fname_case(sfname); /* set correct case for short filename */
! 3268: #endif
! 3269:
! 3270: if (fname == NULL)
! 3271: other_file = TRUE;
! 3272: /* there is no file name */
! 3273: else if (*fname == NUL && curbuf->b_filename == NULL)
! 3274: other_file = FALSE;
! 3275: else
! 3276: {
! 3277: if (*fname == NUL) /* re-edit with same file name */
! 3278: {
! 3279: fname = curbuf->b_filename;
! 3280: sfname = curbuf->b_sfilename;
! 3281: }
! 3282: fname = fix_fname(fname); /* may expand to full path name */
! 3283: other_file = otherfile(fname);
! 3284: }
! 3285: }
! 3286: /*
! 3287: * if the file was changed we may not be allowed to abandon it
! 3288: * - if we are going to re-edit the same file
! 3289: * - or if we are the only window on this file and if hide is FALSE
! 3290: */
! 3291: if ((!other_file || (curbuf->b_nwindows == 1 && !hide)) &&
! 3292: check_changed(curbuf, FALSE, !other_file))
! 3293: {
! 3294: if (fnum == 0 && other_file && fname != NULL)
! 3295: setaltfname(fname, sfname, (linenr_t)1);
! 3296: return FAIL;
! 3297: }
! 3298:
! 3299: /*
! 3300: * End Visual mode before switching to another buffer, so the text can be
! 3301: * copied into the GUI selection buffer.
! 3302: */
! 3303: if (VIsual_active)
! 3304: end_visual_mode();
! 3305:
! 3306: /*
! 3307: * If we are starting to edit another file, open a (new) buffer.
! 3308: * Otherwise we re-use the current buffer.
! 3309: */
! 3310: if (other_file)
! 3311: {
! 3312: curwin->w_alt_fnum = curbuf->b_fnum;
! 3313: buflist_altlnum();
! 3314:
! 3315: if (fnum)
! 3316: buf = buflist_findnr(fnum);
! 3317: else
! 3318: buf = buflist_new(fname, sfname, 1L, TRUE);
! 3319: if (buf == NULL)
! 3320: return FAIL;
! 3321: if (buf->b_ml.ml_mfp == NULL) /* no memfile yet */
! 3322: {
! 3323: oldbuf = FALSE;
! 3324: buf->b_nwindows = 1;
! 3325: }
! 3326: else /* existing memfile */
! 3327: {
! 3328: oldbuf = TRUE;
! 3329: ++buf->b_nwindows;
! 3330: buf_check_timestamp(buf);
! 3331: }
! 3332:
! 3333: /*
! 3334: * make the (new) buffer the one used by the current window
! 3335: * if the old buffer becomes unused, free it if hide is FALSE
! 3336: * If the current buffer was empty and has no file name, curbuf
! 3337: * is returned by buflist_new().
! 3338: */
! 3339: if (buf != curbuf)
! 3340: {
! 3341: #ifdef AUTOCMD
! 3342: apply_autocmds(EVENT_BUFLEAVE, NULL, NULL);
! 3343: #endif
! 3344: #ifdef VIMINFO
! 3345: curbuf->b_last_cursor = curwin->w_cursor;
! 3346: #endif
! 3347: buf_copy_options(curbuf, buf, TRUE);
! 3348: close_buffer(curwin, curbuf, !hide, FALSE);
! 3349: curwin->w_buffer = buf;
! 3350: curbuf = buf;
! 3351: }
! 3352:
! 3353: curwin->w_pcmark.lnum = 1;
! 3354: curwin->w_pcmark.col = 0;
! 3355: }
! 3356: else if (check_fname() == FAIL)
! 3357: return FAIL;
! 3358:
! 3359: /*
! 3360: * If we get here we are sure to start editing
! 3361: */
! 3362: /* don't redraw until the cursor is in the right line */
! 3363: ++RedrawingDisabled;
! 3364: if (set_help)
! 3365: curbuf->b_help = TRUE;
! 3366:
! 3367: /*
! 3368: * other_file oldbuf
! 3369: * FALSE FALSE re-edit same file, buffer is re-used
! 3370: * FALSE TRUE not posible
! 3371: * TRUE FALSE start editing new file, new buffer
! 3372: * TRUE TRUE start editing in existing buffer (nothing to do)
! 3373: */
! 3374: if (!other_file) /* re-use the buffer */
! 3375: {
! 3376: if (newlnum == 0)
! 3377: newlnum = curwin->w_cursor.lnum;
! 3378: buf_freeall(curbuf); /* free all things for buffer */
! 3379: buf_clear(curbuf);
! 3380: curbuf->b_op_start.lnum = 0; /* clear '[ and '] marks */
! 3381: curbuf->b_op_end.lnum = 0;
! 3382: }
! 3383:
! 3384: /*
! 3385: * Check if we are editing the w_arg_idx file in the argument list.
! 3386: */
! 3387: check_arg_idx();
! 3388:
! 3389: if (!oldbuf) /* need to read the file */
! 3390: (void)open_buffer();
! 3391: #ifdef AUTOCMD
! 3392: else
! 3393: apply_autocmds(EVENT_BUFENTER, NULL, NULL);
! 3394: #endif
! 3395: win_init(curwin);
! 3396: maketitle();
! 3397:
! 3398: if (command == NULL)
! 3399: {
! 3400: if (newlnum)
! 3401: {
! 3402: curwin->w_cursor.lnum = newlnum;
! 3403: check_cursor();
! 3404: beginline(MAYBE);
! 3405: }
! 3406: else
! 3407: beginline(TRUE);
! 3408: }
! 3409:
! 3410: /*
! 3411: * Did not read the file, need to show some info about the file.
! 3412: * Do this after setting the cursor.
! 3413: */
! 3414: if (oldbuf)
! 3415: fileinfo(did_cd, TRUE, FALSE);
! 3416:
! 3417: if (command != NULL)
! 3418: do_cmdline(command, TRUE, FALSE);
! 3419: --RedrawingDisabled;
! 3420: if (!skip_redraw)
! 3421: updateScreen(CURSUPD); /* redraw now */
! 3422:
! 3423: if (p_im)
! 3424: need_start_insertmode = TRUE;
! 3425: return OK;
! 3426: }
! 3427:
! 3428: /*
! 3429: * get + command from ex argument
! 3430: */
! 3431: static char_u *
! 3432: getargcmd(argp)
! 3433: char_u **argp;
! 3434: {
! 3435: char_u *arg = *argp;
! 3436: char_u *command = NULL;
! 3437:
! 3438: if (*arg == '+') /* +[command] */
! 3439: {
! 3440: ++arg;
! 3441: if (vim_isspace(*arg))
! 3442: command = (char_u *)"$";
! 3443: else
! 3444: {
! 3445: /*
! 3446: * should check for "\ " (but vi has a bug that prevents it to work)
! 3447: */
! 3448: command = arg;
! 3449: arg = skiptowhite(command);
! 3450: if (*arg)
! 3451: *arg++ = NUL; /* terminate command with NUL */
! 3452: }
! 3453:
! 3454: arg = skipwhite(arg); /* skip over spaces */
! 3455: *argp = arg;
! 3456: }
! 3457: return command;
! 3458: }
! 3459:
! 3460: /*
! 3461: * Halve the number of backslashes in a file name argument.
! 3462: * For MS-DOS we only do this if the character after the backslash
! 3463: * is not a normal file character.
! 3464: * For Unix, when wildcards are going to be expanded, don't remove
! 3465: * backslashes before special characters.
! 3466: */
! 3467: static void
! 3468: backslash_halve(p, expand_wildcards)
! 3469: char_u *p;
! 3470: int expand_wildcards; /* going to expand wildcards later */
! 3471: {
! 3472: for ( ; *p; ++p)
! 3473: if (is_backslash(p)
! 3474: #if defined(MSDOS) || defined(WIN32)
! 3475: && p[1] != '*' && p[1] != '?'
! 3476: #endif
! 3477: #if defined(UNIX) || defined(OS2)
! 3478: && !(expand_wildcards &&
! 3479: vim_strchr((char_u *)" *?[{`$\\", p[1]))
! 3480: #endif
! 3481: )
! 3482: STRCPY(p, p + 1);
! 3483: }
! 3484:
! 3485: static void
! 3486: do_make(arg)
! 3487: char_u *arg;
! 3488: {
! 3489: if (*p_ef == NUL)
! 3490: {
! 3491: EMSG("errorfile option not set");
! 3492: return;
! 3493: }
! 3494:
! 3495: autowrite_all();
! 3496: vim_remove(p_ef);
! 3497:
! 3498: sprintf((char *)IObuff, "%s %s %s", arg, p_sp, p_ef);
! 3499: MSG_OUTSTR(":!");
! 3500: msg_outtrans(IObuff); /* show what we are doing */
! 3501: do_shell(IObuff);
! 3502:
! 3503: #ifdef AMIGA
! 3504: flushbuf();
! 3505: /* read window status report and redraw before message */
! 3506: (void)char_avail();
! 3507: #endif
! 3508:
! 3509: if (qf_init() == OK)
! 3510: qf_jump(0, 0); /* display first error */
! 3511:
! 3512: vim_remove(p_ef);
! 3513: }
! 3514:
! 3515: /*
! 3516: * Redefine the argument list to 'str'.
! 3517: *
! 3518: * Return FAIL for failure, OK otherwise.
! 3519: */
! 3520: static int
! 3521: do_arglist(str)
! 3522: char_u *str;
! 3523: {
! 3524: int new_count = 0;
! 3525: char_u **new_files = NULL;
! 3526: int exp_count;
! 3527: char_u **exp_files;
! 3528: char_u **t;
! 3529: char_u *p;
! 3530: int inquote;
! 3531: int i;
! 3532:
! 3533: while (*str)
! 3534: {
! 3535: /*
! 3536: * create a new entry in new_files[]
! 3537: */
! 3538: t = (char_u **)lalloc((long_u)(sizeof(char_u *) * (new_count + 1)), TRUE);
! 3539: if (t != NULL)
! 3540: for (i = new_count; --i >= 0; )
! 3541: t[i] = new_files[i];
! 3542: vim_free(new_files);
! 3543: if (t == NULL)
! 3544: return FAIL;
! 3545: new_files = t;
! 3546: new_files[new_count++] = str;
! 3547:
! 3548: /*
! 3549: * isolate one argument, taking quotes
! 3550: */
! 3551: inquote = FALSE;
! 3552: for (p = str; *str; ++str)
! 3553: {
! 3554: /*
! 3555: * for MSDOS et.al. a backslash is part of a file name.
! 3556: * Only skip ", space and tab.
! 3557: */
! 3558: if (is_backslash(str))
! 3559: *p++ = *++str;
! 3560: else
! 3561: {
! 3562: if (!inquote && vim_isspace(*str))
! 3563: break;
! 3564: if (*str == '"')
! 3565: inquote ^= TRUE;
! 3566: else
! 3567: *p++ = *str;
! 3568: }
! 3569: }
! 3570: str = skipwhite(str);
! 3571: *p = NUL;
! 3572: }
! 3573:
! 3574: i = ExpandWildCards(new_count, new_files, &exp_count,
! 3575: &exp_files, FALSE, TRUE);
! 3576: vim_free(new_files);
! 3577: if (i == FAIL)
! 3578: return FAIL;
! 3579: if (exp_count == 0)
! 3580: {
! 3581: emsg(e_nomatch);
! 3582: return FAIL;
! 3583: }
! 3584: if (arg_exp) /* arg_files[] has been allocated, free it */
! 3585: FreeWild(arg_count, arg_files);
! 3586: else
! 3587: arg_exp = TRUE;
! 3588: arg_files = exp_files;
! 3589: arg_count = exp_count;
! 3590: arg_had_last = FALSE;
! 3591:
! 3592: /*
! 3593: * put all file names in the buffer list
! 3594: */
! 3595: for (i = 0; i < arg_count; ++i)
! 3596: (void)buflist_add(arg_files[i]);
! 3597:
! 3598: return OK;
! 3599: }
! 3600:
! 3601: /*
! 3602: * Return TRUE if "str" starts with a backslash that should be removed.
! 3603: * For MS-DOS, WIN32 and OS/2 this is only done when the character after the
! 3604: * backslash is not a normal file name character.
! 3605: */
! 3606: static int
! 3607: is_backslash(str)
! 3608: char_u *str;
! 3609: {
! 3610: #ifdef BACKSLASH_IN_FILENAME
! 3611: return (str[0] == '\\' && str[1] != NUL &&
! 3612: !(isfilechar(str[1]) && str[1] != '\\'));
! 3613: #else
! 3614: return (str[0] == '\\' && str[1] != NUL);
! 3615: #endif
! 3616: }
! 3617:
! 3618: /*
! 3619: * Check if we are editing the w_arg_idx file in the argument list.
! 3620: */
! 3621: void
! 3622: check_arg_idx()
! 3623: {
! 3624: int t;
! 3625:
! 3626: if (arg_count > 1 && (curbuf->b_filename == NULL ||
! 3627: curwin->w_arg_idx >= arg_count ||
! 3628: (t = fullpathcmp(arg_files[curwin->w_arg_idx],
! 3629: curbuf->b_filename)) == FPC_DIFF || t == FPC_DIFFX))
! 3630: curwin->w_arg_idx_invalid = TRUE;
! 3631: else
! 3632: curwin->w_arg_idx_invalid = FALSE;
! 3633: }
! 3634:
! 3635: void
! 3636: gotocmdline(clr)
! 3637: int clr;
! 3638: {
! 3639: msg_start();
! 3640: if (clr) /* clear the bottom line(s) */
! 3641: msg_clr_eos(); /* will reset clear_cmdline */
! 3642: windgoto(cmdline_row, 0);
! 3643: }
! 3644:
! 3645: static int
! 3646: check_readonly()
! 3647: {
! 3648: if (!forceit && curbuf->b_p_ro)
! 3649: {
! 3650: emsg(e_readonly);
! 3651: return TRUE;
! 3652: }
! 3653: return FALSE;
! 3654: }
! 3655:
! 3656: /*
! 3657: * return TRUE if buffer was changed and cannot be abandoned.
! 3658: */
! 3659: static int
! 3660: check_changed(buf, checkaw, mult_win)
! 3661: BUF *buf;
! 3662: int checkaw; /* do autowrite if buffer was changed */
! 3663: int mult_win; /* check also when several windows for the buffer */
! 3664: {
! 3665: if ( !forceit &&
! 3666: buf->b_changed && (mult_win || buf->b_nwindows <= 1) &&
! 3667: (!checkaw || autowrite(buf) == FAIL))
! 3668: {
! 3669: emsg(e_nowrtmsg);
! 3670: return TRUE;
! 3671: }
! 3672: return FALSE;
! 3673: }
! 3674:
! 3675: /*
! 3676: * return TRUE if any buffer was changed and cannot be abandoned.
! 3677: * That changed buffer becomes the current buffer.
! 3678: */
! 3679: static int
! 3680: check_changed_any()
! 3681: {
! 3682: BUF *buf;
! 3683: int save;
! 3684:
! 3685: if (!forceit)
! 3686: {
! 3687: for (buf = firstbuf; buf != NULL; buf = buf->b_next)
! 3688: {
! 3689: if (buf->b_changed)
! 3690: {
! 3691: /* There must be a wait_return for this message, do_buffer
! 3692: * will cause a redraw */
! 3693: exiting = FALSE;
! 3694: if (EMSG2("No write since last change for buffer \"%s\"",
! 3695: buf->b_xfilename == NULL ? (char_u *)"No File" :
! 3696: buf->b_xfilename))
! 3697: {
! 3698: save = no_wait_return;
! 3699: no_wait_return = FALSE;
! 3700: wait_return(FALSE);
! 3701: no_wait_return = save;
! 3702: }
! 3703: (void)do_buffer(DOBUF_GOTO, DOBUF_FIRST, FORWARD,
! 3704: buf->b_fnum, 0);
! 3705: return TRUE;
! 3706: }
! 3707: }
! 3708: }
! 3709: return FALSE;
! 3710: }
! 3711:
! 3712: /*
! 3713: * return FAIL if there is no filename, OK if there is one
! 3714: * give error message for FAIL
! 3715: */
! 3716: int
! 3717: check_fname()
! 3718: {
! 3719: if (curbuf->b_filename == NULL)
! 3720: {
! 3721: emsg(e_noname);
! 3722: return FAIL;
! 3723: }
! 3724: return OK;
! 3725: }
! 3726:
! 3727: /*
! 3728: * - if there are more files to edit
! 3729: * - and this is the last window
! 3730: * - and forceit not used
! 3731: * - and not repeated twice on a row
! 3732: * return FAIL and give error message if 'message' TRUE
! 3733: * return OK otherwise
! 3734: */
! 3735: static int
! 3736: check_more(message)
! 3737: int message; /* when FALSE check only, no messages */
! 3738: {
! 3739: if (!forceit && only_one_window() && arg_count > 1 && !arg_had_last &&
! 3740: quitmore == 0)
! 3741: {
! 3742: if (message)
! 3743: {
! 3744: EMSGN("%ld more files to edit", arg_count - curwin->w_arg_idx - 1);
! 3745: quitmore = 2; /* next try to quit is allowed */
! 3746: }
! 3747: return FAIL;
! 3748: }
! 3749: return OK;
! 3750: }
! 3751:
! 3752: /*
! 3753: * try to abandon current file and edit a new or existing file
! 3754: * 'fnum' is the number of the file, if zero use fname/sfname
! 3755: *
! 3756: * return 1 for "normal" error, 2 for "not written" error, 0 for success
! 3757: * -1 for succesfully opening another file
! 3758: * 'lnum' is the line number for the cursor in the new file (if non-zero).
! 3759: */
! 3760: int
! 3761: getfile(fnum, fname, sfname, setpm, lnum)
! 3762: int fnum;
! 3763: char_u *fname;
! 3764: char_u *sfname;
! 3765: int setpm;
! 3766: linenr_t lnum;
! 3767: {
! 3768: int other;
! 3769:
! 3770: if (fnum == 0)
! 3771: {
! 3772: fname_expand(&fname, &sfname); /* make fname full path, set sfname */
! 3773: other = otherfile(fname);
! 3774: }
! 3775: else
! 3776: other = (fnum != curbuf->b_fnum);
! 3777:
! 3778: if (other)
! 3779: ++no_wait_return; /* don't wait for autowrite message */
! 3780: if (other && !forceit && curbuf->b_nwindows == 1 &&
! 3781: !p_hid && curbuf->b_changed && autowrite(curbuf) == FAIL)
! 3782: {
! 3783: if (other)
! 3784: --no_wait_return;
! 3785: emsg(e_nowrtmsg);
! 3786: return 2; /* file has been changed */
! 3787: }
! 3788: if (other)
! 3789: --no_wait_return;
! 3790: if (setpm)
! 3791: setpcmark();
! 3792: if (!other)
! 3793: {
! 3794: if (lnum != 0)
! 3795: curwin->w_cursor.lnum = lnum;
! 3796: check_cursor();
! 3797: beginline(MAYBE);
! 3798:
! 3799: return 0; /* it's in the same file */
! 3800: }
! 3801: if (do_ecmd(fnum, fname, sfname, NULL, p_hid, lnum, FALSE) == OK)
! 3802: return -1; /* opened another file */
! 3803: return 1; /* error encountered */
! 3804: }
! 3805:
! 3806: /*
! 3807: * vim_strncpy()
! 3808: *
! 3809: * This is here because strncpy() does not guarantee successful results when
! 3810: * the to and from strings overlap. It is only currently called from nextwild()
! 3811: * which copies part of the command line to another part of the command line.
! 3812: * This produced garbage when expanding files etc in the middle of the command
! 3813: * line (on my terminal, anyway) -- webb.
! 3814: */
! 3815: static void
! 3816: vim_strncpy(to, from, len)
! 3817: char_u *to;
! 3818: char_u *from;
! 3819: int len;
! 3820: {
! 3821: int i;
! 3822:
! 3823: if (to <= from)
! 3824: {
! 3825: while (len-- && *from)
! 3826: *to++ = *from++;
! 3827: if (len >= 0)
! 3828: *to = *from; /* Copy NUL */
! 3829: }
! 3830: else
! 3831: {
! 3832: for (i = 0; i < len; i++)
! 3833: {
! 3834: to++;
! 3835: if (*from++ == NUL)
! 3836: {
! 3837: i++;
! 3838: break;
! 3839: }
! 3840: }
! 3841: for (; i > 0; i--)
! 3842: *--to = *--from;
! 3843: }
! 3844: }
! 3845:
! 3846: /*
! 3847: * Return FALSE if this is not an appropriate context in which to do
! 3848: * completion of anything, & TRUE if it is (even if there are no matches).
! 3849: * For the caller, this means that the character is just passed through like a
! 3850: * normal character (instead of being expanded). This allows :s/^I^D etc.
! 3851: */
! 3852: static int
! 3853: nextwild(type)
! 3854: int type;
! 3855: {
! 3856: int i;
! 3857: char_u *p1;
! 3858: char_u *p2;
! 3859: int oldlen;
! 3860: int difflen;
! 3861: int v;
! 3862:
! 3863: if (cmd_numfiles == -1)
! 3864: set_expand_context(cmdfirstc, cmdbuff);
! 3865: if (expand_context == EXPAND_UNSUCCESSFUL)
! 3866: {
! 3867: beep_flush();
! 3868: return OK; /* Something illegal on command line */
! 3869: }
! 3870: if (expand_context == EXPAND_NOTHING)
! 3871: {
! 3872: /* Caller can use the character as a normal char instead */
! 3873: return FAIL;
! 3874: }
! 3875: expand_interactively = TRUE;
! 3876:
! 3877: MSG_OUTSTR("..."); /* show that we are busy */
! 3878: flushbuf();
! 3879:
! 3880: i = expand_pattern - cmdbuff;
! 3881: oldlen = cmdpos - i;
! 3882:
! 3883: if (type == WILD_NEXT || type == WILD_PREV)
! 3884: {
! 3885: /*
! 3886: * Get next/previous match for a previous expanded pattern.
! 3887: */
! 3888: p2 = ExpandOne(NULL, NULL, 0, type);
! 3889: }
! 3890: else
! 3891: {
! 3892: /*
! 3893: * Translate string into pattern and expand it.
! 3894: */
! 3895: if ((p1 = addstar(&cmdbuff[i], oldlen)) == NULL)
! 3896: p2 = NULL;
! 3897: else
! 3898: {
! 3899: p2 = ExpandOne(p1, strnsave(&cmdbuff[i], oldlen),
! 3900: WILD_HOME_REPLACE, type);
! 3901: vim_free(p1);
! 3902: }
! 3903: }
! 3904:
! 3905: if (p2 != NULL)
! 3906: {
! 3907: if (cmdlen + (difflen = STRLEN(p2) - oldlen) > cmdbufflen - 4)
! 3908: v = realloc_cmdbuff(cmdlen + difflen);
! 3909: else
! 3910: v = OK;
! 3911: if (v == OK)
! 3912: {
! 3913: vim_strncpy(&cmdbuff[cmdpos + difflen], &cmdbuff[cmdpos],
! 3914: cmdlen - cmdpos);
! 3915: STRNCPY(&cmdbuff[i], p2, STRLEN(p2));
! 3916: cmdlen += difflen;
! 3917: cmdpos += difflen;
! 3918: }
! 3919: vim_free(p2);
! 3920: }
! 3921:
! 3922: redrawcmd();
! 3923: if (cmd_numfiles <= 0 && p2 == NULL)
! 3924: beep_flush();
! 3925: else if (cmd_numfiles == 1)
! 3926: (void)ExpandOne(NULL, NULL, 0, WILD_FREE); /* free expanded pattern */
! 3927:
! 3928: expand_interactively = FALSE; /* reset for next call */
! 3929: return OK;
! 3930: }
! 3931:
! 3932: #define MAXSUFLEN 30 /* maximum length of a file suffix */
! 3933:
! 3934: /*
! 3935: * Do wildcard expansion on the string 'str'.
! 3936: * Return a pointer to alloced memory containing the new string.
! 3937: * Return NULL for failure.
! 3938: *
! 3939: * mode = WILD_FREE: just free previously expanded matches
! 3940: * mode = WILD_EXPAND_FREE: normal expansion, do not keep matches
! 3941: * mode = WILD_EXPAND_KEEP: normal expansion, keep matches
! 3942: * mode = WILD_NEXT: use next match in multiple match, wrap to first
! 3943: * mode = WILD_PREV: use previous match in multiple match, wrap to first
! 3944: * mode = WILD_ALL: return all matches concatenated
! 3945: * mode = WILD_LONGEST: return longest matched part
! 3946: *
! 3947: * options = WILD_LIST_NOTFOUND: list entries without a match
! 3948: * options = WILD_HOME_REPLACE: do home_replace() for buffer names
! 3949: */
! 3950: char_u *
! 3951: ExpandOne(str, orig, options, mode)
! 3952: char_u *str;
! 3953: char_u *orig; /* original string which is expanded */
! 3954: int options;
! 3955: int mode;
! 3956: {
! 3957: char_u *ss = NULL;
! 3958: static char_u **cmd_files = NULL; /* list of input files */
! 3959: static int findex;
! 3960: static char_u *orig_save = NULL; /* kept value of orig */
! 3961: int i, found = 0;
! 3962: int multmatch = FALSE;
! 3963: long_u len;
! 3964: char_u *setsuf;
! 3965: int fnamelen, setsuflen;
! 3966: char_u suf_buf[MAXSUFLEN];
! 3967: char_u *p;
! 3968:
! 3969: /*
! 3970: * first handle the case of using an old match
! 3971: */
! 3972: if (mode == WILD_NEXT || mode == WILD_PREV)
! 3973: {
! 3974: if (cmd_numfiles > 0)
! 3975: {
! 3976: if (mode == WILD_PREV)
! 3977: {
! 3978: if (findex == -1)
! 3979: findex = cmd_numfiles;
! 3980: --findex;
! 3981: }
! 3982: else /* mode == WILD_NEXT */
! 3983: ++findex;
! 3984:
! 3985: /*
! 3986: * When wrapping around, return the original string, set findex to
! 3987: * -1.
! 3988: */
! 3989: if (findex < 0)
! 3990: {
! 3991: if (orig_save == NULL)
! 3992: findex = cmd_numfiles - 1;
! 3993: else
! 3994: findex = -1;
! 3995: }
! 3996: if (findex >= cmd_numfiles)
! 3997: {
! 3998: if (orig_save == NULL)
! 3999: findex = 0;
! 4000: else
! 4001: findex = -1;
! 4002: }
! 4003: if (findex == -1)
! 4004: return strsave(orig_save);
! 4005: return strsave(cmd_files[findex]);
! 4006: }
! 4007: else
! 4008: return NULL;
! 4009: }
! 4010:
! 4011: /* free old names */
! 4012: if (cmd_numfiles != -1 && mode != WILD_ALL && mode != WILD_LONGEST)
! 4013: {
! 4014: FreeWild(cmd_numfiles, cmd_files);
! 4015: cmd_numfiles = -1;
! 4016: vim_free(orig_save);
! 4017: orig_save = NULL;
! 4018: }
! 4019: findex = 0;
! 4020:
! 4021: if (mode == WILD_FREE) /* only release file name */
! 4022: return NULL;
! 4023:
! 4024: if (cmd_numfiles == -1)
! 4025: {
! 4026: vim_free(orig_save);
! 4027: orig_save = orig;
! 4028: if (ExpandFromContext(str, &cmd_numfiles, &cmd_files, FALSE,
! 4029: options) == FAIL)
! 4030: /* error: do nothing */;
! 4031: else if (cmd_numfiles == 0)
! 4032: {
! 4033: if (!expand_interactively)
! 4034: emsg(e_nomatch);
! 4035: }
! 4036: else
! 4037: {
! 4038: /*
! 4039: * If the pattern starts with a '~', replace the home diretory
! 4040: * with '~' again.
! 4041: */
! 4042: if (*str == '~' && (options & WILD_HOME_REPLACE))
! 4043: {
! 4044: for (i = 0; i < cmd_numfiles; ++i)
! 4045: {
! 4046: p = home_replace_save(NULL, cmd_files[i]);
! 4047: if (p != NULL)
! 4048: {
! 4049: vim_free(cmd_files[i]);
! 4050: cmd_files[i] = p;
! 4051: }
! 4052: }
! 4053: }
! 4054:
! 4055: /*
! 4056: * Insert backslashes into a file name before a space, \, %, # and
! 4057: * wildmatch characters, except '~'.
! 4058: */
! 4059: if (expand_interactively &&
! 4060: (expand_context == EXPAND_FILES ||
! 4061: expand_context == EXPAND_BUFFERS ||
! 4062: expand_context == EXPAND_DIRECTORIES))
! 4063: {
! 4064: for (i = 0; i < cmd_numfiles; ++i)
! 4065: {
! 4066: p = strsave_escaped(cmd_files[i],
! 4067: #ifdef BACKSLASH_IN_FILENAME
! 4068: (char_u *)" *?[{`$%#");
! 4069: #else
! 4070: (char_u *)" *?[{`$\\%#");
! 4071: #endif
! 4072: if (p != NULL)
! 4073: {
! 4074: vim_free(cmd_files[i]);
! 4075: cmd_files[i] = p;
! 4076: }
! 4077: }
! 4078: }
! 4079:
! 4080: if (mode != WILD_ALL && mode != WILD_LONGEST)
! 4081: {
! 4082: if (cmd_numfiles > 1) /* more than one match; check suffix */
! 4083: {
! 4084: found = -2;
! 4085: for (i = 0; i < cmd_numfiles; ++i)
! 4086: {
! 4087: fnamelen = STRLEN(cmd_files[i]);
! 4088: setsuflen = 0;
! 4089: for (setsuf = p_su; *setsuf; )
! 4090: {
! 4091: setsuflen = copy_option_part(&setsuf, suf_buf,
! 4092: MAXSUFLEN, ".,");
! 4093: if (fnamelen >= setsuflen && STRNCMP(suf_buf,
! 4094: cmd_files[i] + fnamelen - setsuflen,
! 4095: (size_t)setsuflen) == 0)
! 4096: break;
! 4097: setsuflen = 0;
! 4098: }
! 4099: if (setsuflen) /* suffix matched: ignore file */
! 4100: continue;
! 4101: if (found >= 0)
! 4102: {
! 4103: multmatch = TRUE;
! 4104: break;
! 4105: }
! 4106: found = i;
! 4107: }
! 4108: }
! 4109: if (multmatch || found < 0)
! 4110: {
! 4111: /* Can we ever get here unless it's while expanding
! 4112: * interactively? If not, we can get rid of this all
! 4113: * together. Don't really want to wait for this message
! 4114: * (and possibly have to hit return to continue!).
! 4115: */
! 4116: if (!expand_interactively)
! 4117: emsg(e_toomany);
! 4118: else
! 4119: beep_flush();
! 4120: found = 0; /* return first one */
! 4121: multmatch = TRUE; /* for found < 0 */
! 4122: }
! 4123: if (found >= 0 && !(multmatch && mode == WILD_EXPAND_FREE))
! 4124: ss = strsave(cmd_files[found]);
! 4125: }
! 4126: }
! 4127: }
! 4128:
! 4129: /* Find longest common part */
! 4130: if (mode == WILD_LONGEST && cmd_numfiles > 0)
! 4131: {
! 4132: for (len = 0; cmd_files[0][len]; ++len)
! 4133: {
! 4134: for (i = 0; i < cmd_numfiles; ++i)
! 4135: {
! 4136: #ifdef CASE_INSENSITIVE_FILENAME
! 4137: if ((expand_context == EXPAND_DIRECTORIES ||
! 4138: expand_context == EXPAND_FILES ||
! 4139: expand_context == EXPAND_BUFFERS) &&
! 4140: toupper(cmd_files[i][len]) != toupper(cmd_files[0][len]))
! 4141: break;
! 4142: else
! 4143: #endif
! 4144: if (cmd_files[i][len] != cmd_files[0][len])
! 4145: break;
! 4146: }
! 4147: if (i < cmd_numfiles)
! 4148: {
! 4149: vim_beep();
! 4150: break;
! 4151: }
! 4152: }
! 4153: ss = alloc((unsigned)len + 1);
! 4154: if (ss)
! 4155: {
! 4156: STRNCPY(ss, cmd_files[0], len);
! 4157: ss[len] = NUL;
! 4158: }
! 4159: findex = -1; /* next p_wc gets first one */
! 4160: }
! 4161:
! 4162: /* Concatenate all matching names */
! 4163: if (mode == WILD_ALL && cmd_numfiles > 0)
! 4164: {
! 4165: len = 0;
! 4166: for (i = 0; i < cmd_numfiles; ++i)
! 4167: len += STRLEN(cmd_files[i]) + 1;
! 4168: ss = lalloc(len, TRUE);
! 4169: if (ss)
! 4170: {
! 4171: *ss = NUL;
! 4172: for (i = 0; i < cmd_numfiles; ++i)
! 4173: {
! 4174: STRCAT(ss, cmd_files[i]);
! 4175: if (i != cmd_numfiles - 1)
! 4176: STRCAT(ss, " ");
! 4177: }
! 4178: }
! 4179: }
! 4180:
! 4181: if (mode == WILD_EXPAND_FREE || mode == WILD_ALL)
! 4182: {
! 4183: FreeWild(cmd_numfiles, cmd_files);
! 4184: cmd_numfiles = -1;
! 4185: }
! 4186: return ss;
! 4187: }
! 4188:
! 4189: /*
! 4190: * show all matches for completion on the command line
! 4191: */
! 4192: static int
! 4193: showmatches(buff)
! 4194: char_u *buff;
! 4195: {
! 4196: char_u *file_str;
! 4197: int num_files;
! 4198: char_u **files_found;
! 4199: int i, j, k;
! 4200: int maxlen;
! 4201: int lines;
! 4202: int columns;
! 4203: char_u *p;
! 4204: int lastlen;
! 4205:
! 4206: set_expand_context(cmdfirstc, cmdbuff);
! 4207: if (expand_context == EXPAND_UNSUCCESSFUL)
! 4208: {
! 4209: beep_flush();
! 4210: return OK; /* Something illegal on command line */
! 4211: }
! 4212: if (expand_context == EXPAND_NOTHING)
! 4213: {
! 4214: /* Caller can use the character as a normal char instead */
! 4215: return FAIL;
! 4216: }
! 4217: expand_interactively = TRUE;
! 4218:
! 4219: /* add star to file name, or convert to regexp if not expanding files! */
! 4220: file_str = addstar(expand_pattern, (int)(buff + cmdpos - expand_pattern));
! 4221: if (file_str == NULL)
! 4222: {
! 4223: expand_interactively = FALSE;
! 4224: return OK;
! 4225: }
! 4226:
! 4227: msg_didany = FALSE; /* lines_left will be set */
! 4228: msg_start(); /* prepare for paging */
! 4229: msg_outchar('\n');
! 4230: flushbuf();
! 4231: cmdline_row = msg_row;
! 4232: msg_didany = FALSE; /* lines_left will be set again */
! 4233: msg_start(); /* prepare for paging */
! 4234:
! 4235: /* find all files that match the description */
! 4236: if (ExpandFromContext(file_str, &num_files, &files_found, FALSE, 0) == FAIL)
! 4237: {
! 4238: num_files = 0;
! 4239: files_found = (char_u **)"";
! 4240: }
! 4241:
! 4242: /* find the length of the longest file name */
! 4243: maxlen = 0;
! 4244: for (i = 0; i < num_files; ++i)
! 4245: {
! 4246: if (expand_context == EXPAND_FILES || expand_context == EXPAND_BUFFERS)
! 4247: {
! 4248: home_replace(NULL, files_found[i], NameBuff, MAXPATHL);
! 4249: j = strsize(NameBuff);
! 4250: }
! 4251: else
! 4252: j = strsize(files_found[i]);
! 4253: if (j > maxlen)
! 4254: maxlen = j;
! 4255: }
! 4256:
! 4257: /* compute the number of columns and lines for the listing */
! 4258: maxlen += 2; /* two spaces between file names */
! 4259: columns = ((int)Columns + 2) / maxlen;
! 4260: if (columns < 1)
! 4261: columns = 1;
! 4262: lines = (num_files + columns - 1) / columns;
! 4263:
! 4264: (void)set_highlight('d'); /* find out highlight mode for directories */
! 4265:
! 4266: /* list the files line by line */
! 4267: for (i = 0; i < lines; ++i)
! 4268: {
! 4269: lastlen = 999;
! 4270: for (k = i; k < num_files; k += lines)
! 4271: {
! 4272: for (j = maxlen - lastlen; --j >= 0; )
! 4273: msg_outchar(' ');
! 4274: if (expand_context == EXPAND_FILES ||
! 4275: expand_context == EXPAND_BUFFERS)
! 4276: {
! 4277: /* highlight directories */
! 4278: j = (mch_isdir(files_found[k]));
! 4279: home_replace(NULL, files_found[k], NameBuff, MAXPATHL);
! 4280: p = NameBuff;
! 4281: }
! 4282: else
! 4283: {
! 4284: j = FALSE;
! 4285: p = files_found[k];
! 4286: }
! 4287: if (j)
! 4288: start_highlight();
! 4289: lastlen = msg_outtrans(p);
! 4290: if (j)
! 4291: stop_highlight();
! 4292: }
! 4293: msg_outchar('\n');
! 4294: flushbuf(); /* show one line at a time */
! 4295: if (got_int)
! 4296: {
! 4297: got_int = FALSE;
! 4298: break;
! 4299: }
! 4300: }
! 4301: vim_free(file_str);
! 4302: FreeWild(num_files, files_found);
! 4303:
! 4304: /*
! 4305: * we redraw the command below the lines that we have just listed
! 4306: * This is a bit tricky, but it saves a lot of screen updating.
! 4307: */
! 4308: cmdline_row = msg_row; /* will put it back later */
! 4309:
! 4310: expand_interactively = FALSE;
! 4311: return OK;
! 4312: }
! 4313:
! 4314: /*
! 4315: * Prepare a string for expansion.
! 4316: * When expanding file names: The string will be used with ExpandWildCards().
! 4317: * Copy the file name into allocated memory and add a '*' at the end.
! 4318: * When expanding other names: The string will be used with regcomp(). Copy
! 4319: * the name into allocated memory and add ".*" at the end.
! 4320: */
! 4321: char_u *
! 4322: addstar(fname, len)
! 4323: char_u *fname;
! 4324: int len;
! 4325: {
! 4326: char_u *retval;
! 4327: int i, j;
! 4328: int new_len;
! 4329: char_u *tail;
! 4330:
! 4331: if (expand_interactively && expand_context != EXPAND_FILES &&
! 4332: expand_context != EXPAND_DIRECTORIES)
! 4333: {
! 4334: /*
! 4335: * Matching will be done internally (on something other than files).
! 4336: * So we convert the file-matching-type wildcards into our kind for
! 4337: * use with vim_regcomp(). First work out how long it will be:
! 4338: */
! 4339:
! 4340: /* for help tags the translation is done in find_help_tags() */
! 4341: if (expand_context == EXPAND_HELP)
! 4342: retval = strnsave(fname, len);
! 4343: else
! 4344: {
! 4345: new_len = len + 2; /* +2 for '^' at start, NUL at end */
! 4346: for (i = 0; i < len; i++)
! 4347: {
! 4348: if (fname[i] == '*' || fname[i] == '~')
! 4349: new_len++; /* '*' needs to be replaced by ".*"
! 4350: '~' needs to be replaced by "\~" */
! 4351:
! 4352: /* Buffer names are like file names. "." should be literal */
! 4353: if (expand_context == EXPAND_BUFFERS && fname[i] == '.')
! 4354: new_len++; /* "." becomes "\." */
! 4355: }
! 4356: retval = alloc(new_len);
! 4357: if (retval != NULL)
! 4358: {
! 4359: retval[0] = '^';
! 4360: j = 1;
! 4361: for (i = 0; i < len; i++, j++)
! 4362: {
! 4363: if (fname[i] == '\\' && ++i == len) /* skip backslash */
! 4364: break;
! 4365:
! 4366: switch (fname[i])
! 4367: {
! 4368: case '*': retval[j++] = '.';
! 4369: break;
! 4370: case '~': retval[j++] = '\\';
! 4371: break;
! 4372: case '?': retval[j] = '.';
! 4373: continue;
! 4374: case '.': if (expand_context == EXPAND_BUFFERS)
! 4375: retval[j++] = '\\';
! 4376: break;
! 4377: }
! 4378: retval[j] = fname[i];
! 4379: }
! 4380: retval[j] = NUL;
! 4381: }
! 4382: }
! 4383: }
! 4384: else
! 4385: {
! 4386: retval = alloc(len + 4);
! 4387: if (retval != NULL)
! 4388: {
! 4389: STRNCPY(retval, fname, len);
! 4390: retval[len] = NUL;
! 4391: backslash_halve(retval, TRUE); /* remove some backslashes */
! 4392: len = STRLEN(retval);
! 4393:
! 4394: /*
! 4395: * Don't add a star to ~, ~user, $var or `cmd`.
! 4396: * ~ would be at the start of the tail.
! 4397: * $ could be anywhere in the tail.
! 4398: * ` could be anywhere in the file name.
! 4399: */
! 4400: tail = gettail(retval);
! 4401: if (*tail != '~' && vim_strchr(tail, '$') == NULL
! 4402: && vim_strchr(retval, '`') == NULL)
! 4403: {
! 4404: #ifdef MSDOS
! 4405: /*
! 4406: * if there is no dot in the file name, add "*.*" instead of
! 4407: * "*".
! 4408: */
! 4409: for (i = len - 1; i >= 0; --i)
! 4410: if (vim_strchr((char_u *)".\\/:", retval[i]) != NULL)
! 4411: break;
! 4412: if (i < 0 || retval[i] != '.')
! 4413: {
! 4414: retval[len++] = '*';
! 4415: retval[len++] = '.';
! 4416: }
! 4417: #endif
! 4418: retval[len++] = '*';
! 4419: }
! 4420: retval[len] = NUL;
! 4421: }
! 4422: }
! 4423: return retval;
! 4424: }
! 4425:
! 4426: /*
! 4427: * do_source: read the file "fname" and execute its lines as EX commands
! 4428: *
! 4429: * This function may be called recursively!
! 4430: *
! 4431: * return FAIL if file could not be opened, OK otherwise
! 4432: */
! 4433: int
! 4434: do_source(fname, check_other)
! 4435: register char_u *fname;
! 4436: int check_other; /* check for .vimrc and _vimrc */
! 4437: {
! 4438: register FILE *fp;
! 4439: register int len;
! 4440: #ifdef USE_CRNL
! 4441: int has_cr;
! 4442: int textmode = -1; /* -1 = unknown, 0 = NL, 1 = CR-NL */
! 4443: int error = FALSE;
! 4444: #endif
! 4445: /* use NameBuff for expanded name */
! 4446: expand_env(fname, NameBuff, MAXPATHL);
! 4447: fp = fopen((char *)NameBuff, READBIN);
! 4448: if (fp == NULL && check_other)
! 4449: {
! 4450: /*
! 4451: * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa
! 4452: * (if applicable)
! 4453: */
! 4454: len = STRLEN(NameBuff);
! 4455: if (((len > 6 && ispathsep(NameBuff[len - 7])) || len == 6) &&
! 4456: (NameBuff[len - 6] == '.' || NameBuff[len - 6] == '_') &&
! 4457: (STRCMP(&NameBuff[len - 5], "vimrc") == 0))
! 4458: {
! 4459: if (NameBuff[len - 6] == '_')
! 4460: NameBuff[len - 6] = '.';
! 4461: else
! 4462: NameBuff[len - 6] = '_';
! 4463: fp = fopen((char *)NameBuff, READBIN);
! 4464: }
! 4465: }
! 4466:
! 4467: if (fp == NULL)
! 4468: return FAIL;
! 4469:
! 4470: #ifdef USE_CRNL
! 4471: /* no automatic textmode: Set default to CR-NL */
! 4472: if (!p_ta)
! 4473: textmode = 1;
! 4474: #endif
! 4475: sourcing_name = fname;
! 4476: sourcing_lnum = 1;
! 4477: #ifdef SLEEP_IN_EMSG
! 4478: ++dont_sleep; /* don't call sleep() in emsg() */
! 4479: #endif
! 4480: len = 0;
! 4481: while (fgets((char *)IObuff + len, IOSIZE - len, fp) != NULL && !got_int)
! 4482: {
! 4483: len = STRLEN(IObuff) - 1;
! 4484: if (len >= 0 && IObuff[len] == '\n') /* remove trailing newline */
! 4485: {
! 4486: #ifdef USE_CRNL
! 4487: has_cr = (len > 0 && IObuff[len - 1] == '\r');
! 4488: if (textmode == -1)
! 4489: {
! 4490: if (has_cr)
! 4491: textmode = 1;
! 4492: else
! 4493: textmode = 0;
! 4494: }
! 4495:
! 4496: if (textmode)
! 4497: {
! 4498: if (has_cr) /* remove trailing CR-LF */
! 4499: --len;
! 4500: else /* lines like ":map xx yy^M" will have failed */
! 4501: {
! 4502: if (!error)
! 4503: EMSG("Warning: Wrong line separator, ^M may be missing");
! 4504: error = TRUE;
! 4505: textmode = 0;
! 4506: }
! 4507: }
! 4508: #endif
! 4509: /* escaped newline, read more */
! 4510: if (len > 0 && len < IOSIZE && IObuff[len - 1] == Ctrl('V'))
! 4511: {
! 4512: IObuff[len - 1] = '\n'; /* remove CTRL-V */
! 4513: ++sourcing_lnum;
! 4514: continue;
! 4515: }
! 4516: IObuff[len] = NUL;
! 4517: }
! 4518: /* check for ^C here, so recursive :so will be broken */
! 4519: mch_breakcheck();
! 4520: do_cmdline(IObuff, TRUE, TRUE);
! 4521: len = 0;
! 4522: ++sourcing_lnum;
! 4523: }
! 4524: fclose(fp);
! 4525: if (got_int)
! 4526: emsg(e_interr);
! 4527: #ifdef SLEEP_IN_EMSG
! 4528: --dont_sleep;
! 4529: #endif
! 4530: sourcing_name = NULL;
! 4531: sourcing_lnum = 0;
! 4532: return OK;
! 4533: }
! 4534:
! 4535: /*
! 4536: * get a single EX address
! 4537: *
! 4538: * Set ptr to the next character after the part that was interpreted.
! 4539: * Set ptr to NULL when an error is encountered.
! 4540: */
! 4541: static linenr_t
! 4542: get_address(ptr)
! 4543: char_u **ptr;
! 4544: {
! 4545: linenr_t cursor_lnum = curwin->w_cursor.lnum;
! 4546: int c;
! 4547: int i;
! 4548: long n;
! 4549: char_u *cmd;
! 4550: FPOS pos;
! 4551: FPOS *fp;
! 4552: linenr_t lnum;
! 4553:
! 4554: cmd = skipwhite(*ptr);
! 4555: lnum = MAXLNUM;
! 4556: do
! 4557: {
! 4558: switch (*cmd)
! 4559: {
! 4560: case '.': /* '.' - Cursor position */
! 4561: ++cmd;
! 4562: lnum = cursor_lnum;
! 4563: break;
! 4564:
! 4565: case '$': /* '$' - last line */
! 4566: ++cmd;
! 4567: lnum = curbuf->b_ml.ml_line_count;
! 4568: break;
! 4569:
! 4570: case '\'': /* ''' - mark */
! 4571: if (*++cmd == NUL || (check_mark(
! 4572: fp = getmark(*cmd++, FALSE)) == FAIL))
! 4573: goto error;
! 4574: lnum = fp->lnum;
! 4575: break;
! 4576:
! 4577: case '/':
! 4578: case '?': /* '/' or '?' - search */
! 4579: c = *cmd++;
! 4580: pos = curwin->w_cursor; /* save curwin->w_cursor */
! 4581: if (c == '/') /* forward search, start on next line */
! 4582: {
! 4583: ++curwin->w_cursor.lnum;
! 4584: curwin->w_cursor.col = 0;
! 4585: }
! 4586: else /* backward search, start on prev line */
! 4587: {
! 4588: --curwin->w_cursor.lnum;
! 4589: curwin->w_cursor.col = MAXCOL;
! 4590: }
! 4591: searchcmdlen = 0;
! 4592: if (!do_search(c, cmd, 1L,
! 4593: SEARCH_HIS + SEARCH_MSG + SEARCH_START))
! 4594: {
! 4595: cmd = NULL;
! 4596: curwin->w_cursor = pos;
! 4597: goto error;
! 4598: }
! 4599: lnum = curwin->w_cursor.lnum;
! 4600: curwin->w_cursor = pos;
! 4601: /* adjust command string pointer */
! 4602: cmd += searchcmdlen;
! 4603: break;
! 4604:
! 4605: case '\\': /* "\?", "\/" or "\&", repeat search */
! 4606: ++cmd;
! 4607: if (*cmd == '&')
! 4608: i = RE_SUBST;
! 4609: else if (*cmd == '?' || *cmd == '/')
! 4610: i = RE_SEARCH;
! 4611: else
! 4612: {
! 4613: emsg(e_backslash);
! 4614: cmd = NULL;
! 4615: goto error;
! 4616: }
! 4617:
! 4618: /* forward search, start on next line */
! 4619: if (*cmd != '?')
! 4620: {
! 4621: pos.lnum = curwin->w_cursor.lnum + 1;
! 4622: pos.col = 0;
! 4623: }
! 4624: /* backward search, start on prev line */
! 4625: else
! 4626: {
! 4627: pos.lnum = curwin->w_cursor.lnum - 1;
! 4628: pos.col = MAXCOL;
! 4629: }
! 4630: if (searchit(&pos, *cmd == '?' ? BACKWARD : FORWARD,
! 4631: (char_u *)"", 1L,
! 4632: SEARCH_MSG + SEARCH_START, i) == OK)
! 4633: lnum = pos.lnum;
! 4634: else
! 4635: {
! 4636: cmd = NULL;
! 4637: goto error;
! 4638: }
! 4639: ++cmd;
! 4640: break;
! 4641:
! 4642: default:
! 4643: if (isdigit(*cmd)) /* absolute line number */
! 4644: lnum = getdigits(&cmd);
! 4645: }
! 4646:
! 4647: for (;;)
! 4648: {
! 4649: cmd = skipwhite(cmd);
! 4650: if (*cmd != '-' && *cmd != '+' && !isdigit(*cmd))
! 4651: break;
! 4652:
! 4653: if (lnum == MAXLNUM)
! 4654: lnum = cursor_lnum; /* "+1" is same as ".+1" */
! 4655: if (isdigit(*cmd))
! 4656: i = '+'; /* "number" is same as "+number" */
! 4657: else
! 4658: i = *cmd++;
! 4659: if (!isdigit(*cmd)) /* '+' is '+1', but '+0' is not '+1' */
! 4660: n = 1;
! 4661: else
! 4662: n = getdigits(&cmd);
! 4663: if (i == '-')
! 4664: lnum -= n;
! 4665: else
! 4666: lnum += n;
! 4667: }
! 4668: cursor_lnum = lnum;
! 4669: } while (*cmd == '/' || *cmd == '?');
! 4670:
! 4671: error:
! 4672: *ptr = cmd;
! 4673: return lnum;
! 4674: }
! 4675:
! 4676:
! 4677: /*
! 4678: * Must parse the command line so far to work out what context we are in.
! 4679: * Completion can then be done based on that context.
! 4680: * This routine sets two global variables:
! 4681: * char_u *expand_pattern The start of the pattern to be expanded within
! 4682: * the command line (ends at the cursor).
! 4683: * int expand_context The type of thing to expand. Will be one of:
! 4684: *
! 4685: * EXPAND_UNSUCCESSFUL Used sometimes when there is something illegal on
! 4686: * the command line, like an unknown command. Caller
! 4687: * should beep.
! 4688: * EXPAND_NOTHING Unrecognised context for completion, use char like
! 4689: * a normal char, rather than for completion. eg
! 4690: * :s/^I/
! 4691: * EXPAND_COMMANDS Cursor is still touching the command, so complete
! 4692: * it.
! 4693: * EXPAND_BUFFERS Complete file names for :buf and :sbuf commands.
! 4694: * EXPAND_FILES After command with XFILE set, or after setting
! 4695: * with P_EXPAND set. eg :e ^I, :w>>^I
! 4696: * EXPAND_DIRECTORIES In some cases this is used instead of the latter
! 4697: * when we know only directories are of interest. eg
! 4698: * :set dir=^I
! 4699: * EXPAND_SETTINGS Complete variable names. eg :set d^I
! 4700: * EXPAND_BOOL_SETTINGS Complete boolean variables only, eg :set no^I
! 4701: * EXPAND_TAGS Complete tags from the files in p_tags. eg :ta a^I
! 4702: * EXPAND_HELP Complete tags from the file 'helpfile'/vim_tags
! 4703: * EXPAND_EVENTS Complete event names
! 4704: *
! 4705: * -- webb.
! 4706: */
! 4707: static void
! 4708: set_expand_context(firstc, buff)
! 4709: int firstc; /* either ':', '/', or '?' */
! 4710: char_u *buff; /* buffer for command string */
! 4711: {
! 4712: char_u *nextcomm;
! 4713: char_u old_char;
! 4714:
! 4715: old_char = cmdbuff[cmdpos];
! 4716: cmdbuff[cmdpos] = NUL;
! 4717: nextcomm = buff;
! 4718: while (nextcomm != NULL)
! 4719: nextcomm = set_one_cmd_context(firstc, nextcomm);
! 4720: cmdbuff[cmdpos] = old_char;
! 4721: }
! 4722:
! 4723: /*
! 4724: * This is all pretty much copied from do_one_cmd(), with all the extra stuff
! 4725: * we don't need/want deleted. Maybe this could be done better if we didn't
! 4726: * repeat all this stuff. The only problem is that they may not stay perfectly
! 4727: * compatible with each other, but then the command line syntax probably won't
! 4728: * change that much -- webb.
! 4729: */
! 4730: static char_u *
! 4731: set_one_cmd_context(firstc, buff)
! 4732: int firstc; /* either ':', '/', or '?' */
! 4733: char_u *buff; /* buffer for command string */
! 4734: {
! 4735: char_u *p;
! 4736: char_u *cmd, *arg;
! 4737: int i;
! 4738: int cmdidx;
! 4739: long argt;
! 4740: char_u delim;
! 4741: int forced = FALSE;
! 4742: int usefilter = FALSE; /* filter instead of file name */
! 4743:
! 4744: expand_pattern = buff;
! 4745: if (firstc != ':')
! 4746: {
! 4747: expand_context = EXPAND_NOTHING;
! 4748: return NULL;
! 4749: }
! 4750: expand_context = EXPAND_COMMANDS; /* Default until we get past command */
! 4751:
! 4752: /*
! 4753: * 2. skip comment lines and leading space, colons or bars
! 4754: */
! 4755: for (cmd = buff; vim_strchr((char_u *)" \t:|", *cmd) != NULL; cmd++)
! 4756: ;
! 4757: expand_pattern = cmd;
! 4758:
! 4759: if (*cmd == NUL)
! 4760: return NULL;
! 4761: if (*cmd == '"') /* ignore comment lines */
! 4762: {
! 4763: expand_context = EXPAND_NOTHING;
! 4764: return NULL;
! 4765: }
! 4766:
! 4767: /*
! 4768: * 3. parse a range specifier of the form: addr [,addr] [;addr] ..
! 4769: */
! 4770: /*
! 4771: * Backslashed delimiters after / or ? will be skipped, and commands will
! 4772: * not be expanded between /'s and ?'s or after "'". -- webb
! 4773: */
! 4774: while (*cmd != NUL && (vim_isspace(*cmd) || isdigit(*cmd) ||
! 4775: vim_strchr((char_u *)".$%'/?-+,;", *cmd) != NULL))
! 4776: {
! 4777: if (*cmd == '\'')
! 4778: {
! 4779: if (*++cmd == NUL)
! 4780: expand_context = EXPAND_NOTHING;
! 4781: }
! 4782: else if (*cmd == '/' || *cmd == '?')
! 4783: {
! 4784: delim = *cmd++;
! 4785: while (*cmd != NUL && *cmd != delim)
! 4786: if (*cmd++ == '\\' && *cmd != NUL)
! 4787: ++cmd;
! 4788: if (*cmd == NUL)
! 4789: expand_context = EXPAND_NOTHING;
! 4790: }
! 4791: if (*cmd != NUL)
! 4792: ++cmd;
! 4793: }
! 4794:
! 4795: /*
! 4796: * 4. parse command
! 4797: */
! 4798:
! 4799: cmd = skipwhite(cmd);
! 4800: expand_pattern = cmd;
! 4801: if (*cmd == NUL)
! 4802: return NULL;
! 4803: if (*cmd == '"')
! 4804: {
! 4805: expand_context = EXPAND_NOTHING;
! 4806: return NULL;
! 4807: }
! 4808:
! 4809: if (*cmd == '|' || *cmd == '\n')
! 4810: return cmd + 1; /* There's another command */
! 4811:
! 4812: /*
! 4813: * Isolate the command and search for it in the command table.
! 4814: * Exeptions:
! 4815: * - the 'k' command can directly be followed by any character.
! 4816: * - the 's' command can be followed directly by 'c', 'g' or 'r'
! 4817: */
! 4818: if (*cmd == 'k')
! 4819: {
! 4820: cmdidx = CMD_k;
! 4821: p = cmd + 1;
! 4822: }
! 4823: else
! 4824: {
! 4825: p = cmd;
! 4826: while (isalpha(*p) || *p == '*') /* Allow * wild card */
! 4827: ++p;
! 4828: /* check for non-alpha command */
! 4829: if (p == cmd && vim_strchr((char_u *)"@!=><&~#", *p) != NULL)
! 4830: ++p;
! 4831: i = (int)(p - cmd);
! 4832:
! 4833: if (i == 0)
! 4834: {
! 4835: expand_context = EXPAND_UNSUCCESSFUL;
! 4836: return NULL;
! 4837: }
! 4838: for (cmdidx = 0; cmdidx < CMD_SIZE; ++cmdidx)
! 4839: if (STRNCMP(cmdnames[cmdidx].cmd_name, cmd, (size_t)i) == 0)
! 4840: break;
! 4841: }
! 4842:
! 4843: /*
! 4844: * If the cursor is touching the command, and it ends in an alphabetic
! 4845: * character, complete the command name.
! 4846: */
! 4847: if (p == cmdbuff + cmdpos && isalpha(p[-1]))
! 4848: return NULL;
! 4849:
! 4850: if (cmdidx == CMD_SIZE)
! 4851: {
! 4852: if (*cmd == 's' && vim_strchr((char_u *)"cgr", cmd[1]) != NULL)
! 4853: {
! 4854: cmdidx = CMD_substitute;
! 4855: p = cmd + 1;
! 4856: }
! 4857: else
! 4858: {
! 4859: /* Not still touching the command and it was an illegal command */
! 4860: expand_context = EXPAND_UNSUCCESSFUL;
! 4861: return NULL;
! 4862: }
! 4863: }
! 4864:
! 4865: expand_context = EXPAND_NOTHING; /* Default now that we're past command */
! 4866:
! 4867: if (*p == '!') /* forced commands */
! 4868: {
! 4869: forced = TRUE;
! 4870: ++p;
! 4871: }
! 4872:
! 4873: /*
! 4874: * 5. parse arguments
! 4875: */
! 4876: argt = cmdnames[cmdidx].cmd_argt;
! 4877:
! 4878: arg = skipwhite(p);
! 4879:
! 4880: if (cmdidx == CMD_write)
! 4881: {
! 4882: if (*arg == '>') /* append */
! 4883: {
! 4884: if (*++arg == '>') /* It should be */
! 4885: ++arg;
! 4886: arg = skipwhite(arg);
! 4887: }
! 4888: else if (*arg == '!') /* :w !filter */
! 4889: {
! 4890: ++arg;
! 4891: usefilter = TRUE;
! 4892: }
! 4893: }
! 4894:
! 4895: if (cmdidx == CMD_read)
! 4896: {
! 4897: usefilter = forced; /* :r! filter if forced */
! 4898: if (*arg == '!') /* :r !filter */
! 4899: {
! 4900: ++arg;
! 4901: usefilter = TRUE;
! 4902: }
! 4903: }
! 4904:
! 4905: if (cmdidx == CMD_lshift || cmdidx == CMD_rshift)
! 4906: {
! 4907: while (*arg == *cmd) /* allow any number of '>' or '<' */
! 4908: ++arg;
! 4909: arg = skipwhite(arg);
! 4910: }
! 4911:
! 4912: /* Does command allow "+command"? */
! 4913: if ((argt & EDITCMD) && !usefilter && *arg == '+')
! 4914: {
! 4915: /* Check if we're in the +command */
! 4916: p = arg + 1;
! 4917: arg = skiptowhite(arg);
! 4918:
! 4919: /* Still touching the command after '+'? */
! 4920: if (arg >= cmdbuff + cmdpos)
! 4921: return p;
! 4922:
! 4923: /* Skip space after +command to get to the real argument */
! 4924: arg = skipwhite(arg);
! 4925: }
! 4926:
! 4927: /*
! 4928: * Check for '|' to separate commands and '"' to start comments.
! 4929: * Don't do this for ":read !cmd" and ":write !cmd".
! 4930: */
! 4931: if ((argt & TRLBAR) && !usefilter)
! 4932: {
! 4933: p = arg;
! 4934: while (*p)
! 4935: {
! 4936: if (*p == Ctrl('V'))
! 4937: {
! 4938: if (p[1] != NUL)
! 4939: ++p;
! 4940: }
! 4941: else if ((*p == '"' && !(argt & NOTRLCOM)) || *p == '|' || *p == '\n')
! 4942: {
! 4943: if (*(p - 1) != '\\')
! 4944: {
! 4945: if (*p == '|' || *p == '\n')
! 4946: return p + 1;
! 4947: return NULL; /* It's a comment */
! 4948: }
! 4949: }
! 4950: ++p;
! 4951: }
! 4952: }
! 4953:
! 4954: /* no arguments allowed */
! 4955: if (!(argt & EXTRA) && *arg != NUL &&
! 4956: vim_strchr((char_u *)"|\"", *arg) == NULL)
! 4957: return NULL;
! 4958:
! 4959: /* Find start of last argument (argument just before cursor): */
! 4960: p = cmdbuff + cmdpos;
! 4961: while (p != arg && *p != ' ' && *p != TAB)
! 4962: p--;
! 4963: if (*p == ' ' || *p == TAB)
! 4964: p++;
! 4965: expand_pattern = p;
! 4966:
! 4967: if (argt & XFILE)
! 4968: {
! 4969: int in_quote = FALSE;
! 4970: char_u *bow = NULL; /* Beginning of word */
! 4971:
! 4972: /*
! 4973: * Allow spaces within back-quotes to count as part of the argument
! 4974: * being expanded.
! 4975: */
! 4976: expand_pattern = skipwhite(arg);
! 4977: for (p = expand_pattern; *p; ++p)
! 4978: {
! 4979: if (*p == '\\' && p[1])
! 4980: ++p;
! 4981: #ifdef SPACE_IN_FILENAME
! 4982: else if (vim_iswhite(*p) && (!(argt & NOSPC) || usefilter))
! 4983: #else
! 4984: else if (vim_iswhite(*p))
! 4985: #endif
! 4986: {
! 4987: p = skipwhite(p);
! 4988: if (in_quote)
! 4989: bow = p;
! 4990: else
! 4991: expand_pattern = p;
! 4992: --p;
! 4993: }
! 4994: else if (*p == '`')
! 4995: {
! 4996: if (!in_quote)
! 4997: {
! 4998: expand_pattern = p;
! 4999: bow = p + 1;
! 5000: }
! 5001: in_quote = !in_quote;
! 5002: }
! 5003: }
! 5004:
! 5005: /*
! 5006: * If we are still inside the quotes, and we passed a space, just
! 5007: * expand from there.
! 5008: */
! 5009: if (bow != NULL && in_quote)
! 5010: expand_pattern = bow;
! 5011: expand_context = EXPAND_FILES;
! 5012: }
! 5013:
! 5014: /*
! 5015: * 6. switch on command name
! 5016: */
! 5017: switch (cmdidx)
! 5018: {
! 5019: case CMD_cd:
! 5020: case CMD_chdir:
! 5021: expand_context = EXPAND_DIRECTORIES;
! 5022: break;
! 5023: case CMD_global:
! 5024: case CMD_vglobal:
! 5025: delim = *arg; /* get the delimiter */
! 5026: if (delim)
! 5027: ++arg; /* skip delimiter if there is one */
! 5028:
! 5029: while (arg[0] != NUL && arg[0] != delim)
! 5030: {
! 5031: if (arg[0] == '\\' && arg[1] != NUL)
! 5032: ++arg;
! 5033: ++arg;
! 5034: }
! 5035: if (arg[0] != NUL)
! 5036: return arg + 1;
! 5037: break;
! 5038: case CMD_and:
! 5039: case CMD_substitute:
! 5040: delim = *arg;
! 5041: if (delim)
! 5042: ++arg;
! 5043: for (i = 0; i < 2; i++)
! 5044: {
! 5045: while (arg[0] != NUL && arg[0] != delim)
! 5046: {
! 5047: if (arg[0] == '\\' && arg[1] != NUL)
! 5048: ++arg;
! 5049: ++arg;
! 5050: }
! 5051: if (arg[0] != NUL) /* skip delimiter */
! 5052: ++arg;
! 5053: }
! 5054: while (arg[0] && vim_strchr((char_u *)"|\"#", arg[0]) == NULL)
! 5055: ++arg;
! 5056: if (arg[0] != NUL)
! 5057: return arg;
! 5058: break;
! 5059: case CMD_isearch:
! 5060: case CMD_dsearch:
! 5061: case CMD_ilist:
! 5062: case CMD_dlist:
! 5063: case CMD_ijump:
! 5064: case CMD_djump:
! 5065: case CMD_isplit:
! 5066: case CMD_dsplit:
! 5067: arg = skipwhite(skipdigits(arg)); /* skip count */
! 5068: if (*arg == '/') /* Match regexp, not just whole words */
! 5069: {
! 5070: for (++arg; *arg && *arg != '/'; arg++)
! 5071: if (*arg == '\\' && arg[1] != NUL)
! 5072: arg++;
! 5073: if (*arg)
! 5074: {
! 5075: arg = skipwhite(arg + 1);
! 5076:
! 5077: /* Check for trailing illegal characters */
! 5078: if (*arg && vim_strchr((char_u *)"|\"\n", *arg) == NULL)
! 5079: expand_context = EXPAND_NOTHING;
! 5080: else
! 5081: return arg;
! 5082: }
! 5083: }
! 5084: break;
! 5085: #ifdef AUTOCMD
! 5086: case CMD_autocmd:
! 5087: return set_context_in_autocmd(arg, FALSE);
! 5088:
! 5089: case CMD_doautocmd:
! 5090: return set_context_in_autocmd(arg, TRUE);
! 5091: #endif
! 5092: case CMD_set:
! 5093: set_context_in_set_cmd(arg);
! 5094: break;
! 5095: case CMD_stag:
! 5096: case CMD_tag:
! 5097: expand_context = EXPAND_TAGS;
! 5098: expand_pattern = arg;
! 5099: break;
! 5100: case CMD_help:
! 5101: expand_context = EXPAND_HELP;
! 5102: expand_pattern = arg;
! 5103: break;
! 5104: case CMD_bdelete:
! 5105: case CMD_bunload:
! 5106: while ((expand_pattern = vim_strchr(arg, ' ')) != NULL)
! 5107: arg = expand_pattern + 1;
! 5108: case CMD_buffer:
! 5109: case CMD_sbuffer:
! 5110: expand_context = EXPAND_BUFFERS;
! 5111: expand_pattern = arg;
! 5112: break;
! 5113: #ifdef USE_GUI
! 5114: case CMD_menu: case CMD_noremenu: case CMD_unmenu:
! 5115: case CMD_nmenu: case CMD_nnoremenu: case CMD_nunmenu:
! 5116: case CMD_vmenu: case CMD_vnoremenu: case CMD_vunmenu:
! 5117: case CMD_imenu: case CMD_inoremenu: case CMD_iunmenu:
! 5118: case CMD_cmenu: case CMD_cnoremenu: case CMD_cunmenu:
! 5119: return gui_set_context_in_menu_cmd(cmd, arg, forced);
! 5120: break;
! 5121: #endif
! 5122: default:
! 5123: break;
! 5124: }
! 5125: return NULL;
! 5126: }
! 5127:
! 5128: /*
! 5129: * Do the expansion based on the global variables expand_context and
! 5130: * expand_pattern -- webb.
! 5131: */
! 5132: static int
! 5133: ExpandFromContext(pat, num_file, file, files_only, options)
! 5134: char_u *pat;
! 5135: int *num_file;
! 5136: char_u ***file;
! 5137: int files_only;
! 5138: int options;
! 5139: {
! 5140: regexp *prog;
! 5141: int ret;
! 5142: int i;
! 5143: int count;
! 5144:
! 5145: if (!expand_interactively || expand_context == EXPAND_FILES)
! 5146: return ExpandWildCards(1, &pat, num_file, file, files_only,
! 5147: (options & WILD_LIST_NOTFOUND));
! 5148: else if (expand_context == EXPAND_DIRECTORIES)
! 5149: {
! 5150: if (ExpandWildCards(1, &pat, num_file, file, files_only,
! 5151: (options & WILD_LIST_NOTFOUND)) == FAIL)
! 5152: return FAIL;
! 5153: count = 0;
! 5154: for (i = 0; i < *num_file; i++)
! 5155: if (mch_isdir((*file)[i]))
! 5156: (*file)[count++] = (*file)[i];
! 5157: else
! 5158: vim_free((*file)[i]);
! 5159: if (count == 0)
! 5160: {
! 5161: vim_free(*file);
! 5162: *file = (char_u **)"";
! 5163: *num_file = -1;
! 5164: return FAIL;
! 5165: }
! 5166: *num_file = count;
! 5167: return OK;
! 5168: }
! 5169: *file = (char_u **)"";
! 5170: *num_file = 0;
! 5171: if (expand_context == EXPAND_OLD_SETTING)
! 5172: return ExpandOldSetting(num_file, file);
! 5173:
! 5174: if (expand_context == EXPAND_HELP)
! 5175: return find_help_tags(pat, num_file, file);
! 5176:
! 5177: set_reg_ic(pat); /* set reg_ic according to p_ic, p_scs and pat */
! 5178: #ifdef AUTOCMD
! 5179: if (expand_context == EXPAND_EVENTS)
! 5180: reg_ic = TRUE; /* always ignore case for events */
! 5181: #endif
! 5182: reg_magic = p_magic;
! 5183:
! 5184: if (expand_context == EXPAND_BUFFERS)
! 5185: return ExpandBufnames(pat, num_file, file, options);
! 5186:
! 5187: prog = vim_regcomp(pat);
! 5188: if (prog == NULL)
! 5189: return FAIL;
! 5190:
! 5191: if (expand_context == EXPAND_COMMANDS)
! 5192: ret = ExpandCommands(prog, num_file, file);
! 5193: else if (expand_context == EXPAND_SETTINGS ||
! 5194: expand_context == EXPAND_BOOL_SETTINGS)
! 5195: ret = ExpandSettings(prog, num_file, file);
! 5196: else if (expand_context == EXPAND_TAGS)
! 5197: ret = find_tags(NULL, prog, num_file, file, FALSE);
! 5198: #ifdef AUTOCMD
! 5199: else if (expand_context == EXPAND_EVENTS)
! 5200: ret = ExpandEvents(prog, num_file, file);
! 5201: #endif
! 5202: #ifdef USE_GUI
! 5203: else if (expand_context == EXPAND_MENUS)
! 5204: ret = gui_ExpandMenuNames(prog, num_file, file);
! 5205: #endif
! 5206: else
! 5207: ret = FAIL;
! 5208:
! 5209: vim_free(prog);
! 5210: return ret;
! 5211: }
! 5212:
! 5213: static int
! 5214: ExpandCommands(prog, num_file, file)
! 5215: regexp *prog;
! 5216: int *num_file;
! 5217: char_u ***file;
! 5218: {
! 5219: int cmdidx;
! 5220: int count;
! 5221: int round;
! 5222:
! 5223: /*
! 5224: * round == 1: Count the matches.
! 5225: * round == 2: Save the matches into the array.
! 5226: */
! 5227: for (round = 1; round <= 2; ++round)
! 5228: {
! 5229: count = 0;
! 5230: for (cmdidx = 0; cmdidx < CMD_SIZE; cmdidx++)
! 5231: if (vim_regexec(prog, cmdnames[cmdidx].cmd_name, TRUE))
! 5232: {
! 5233: if (round == 1)
! 5234: count++;
! 5235: else
! 5236: (*file)[count++] = strsave(cmdnames[cmdidx].cmd_name);
! 5237: }
! 5238: if (round == 1)
! 5239: {
! 5240: *num_file = count;
! 5241: if (count == 0 || (*file = (char_u **)
! 5242: alloc((unsigned)(count * sizeof(char_u *)))) == NULL)
! 5243: return FAIL;
! 5244: }
! 5245: }
! 5246: return OK;
! 5247: }
! 5248:
! 5249: #ifdef VIMINFO
! 5250: static char_u **viminfo_history[2] = {NULL, NULL};
! 5251: static int viminfo_hisidx[2] = {0, 0};
! 5252: static int viminfo_hislen = 0;
! 5253: static int viminfo_add_at_front = FALSE;
! 5254:
! 5255: void
! 5256: prepare_viminfo_history(len)
! 5257: int len;
! 5258: {
! 5259: int i;
! 5260: int num;
! 5261: int type;
! 5262:
! 5263: init_history();
! 5264: viminfo_add_at_front = (len != 0);
! 5265: if (len > hislen)
! 5266: len = hislen;
! 5267:
! 5268: for (type = 0; type <= 1; ++type)
! 5269: {
! 5270: /* If there are more spaces available than we request, then fill them
! 5271: * up */
! 5272: for (i = 0, num = 0; i < hislen; i++)
! 5273: if (history[type][i] == NULL)
! 5274: num++;
! 5275: if (num > len)
! 5276: len = num;
! 5277: viminfo_hisidx[type] = 0;
! 5278: if (len <= 0)
! 5279: viminfo_history[type] = NULL;
! 5280: else
! 5281: viminfo_history[type] = (char_u **)lalloc(len * sizeof(char_u *),
! 5282: FALSE);
! 5283: }
! 5284: viminfo_hislen = len;
! 5285: if (viminfo_history[0] == NULL || viminfo_history[1] == NULL)
! 5286: viminfo_hislen = 0;
! 5287: }
! 5288:
! 5289: int
! 5290: read_viminfo_history(line, fp)
! 5291: char_u *line;
! 5292: FILE *fp;
! 5293: {
! 5294: int type;
! 5295:
! 5296: type = (line[0] == ':' ? 0 : 1);
! 5297: if (viminfo_hisidx[type] != viminfo_hislen)
! 5298: {
! 5299: viminfo_readstring(line);
! 5300: if (!is_in_history(type, line + 1, viminfo_add_at_front))
! 5301: viminfo_history[type][viminfo_hisidx[type]++] = strsave(line + 1);
! 5302: }
! 5303: return vim_fgets(line, LSIZE, fp);
! 5304: }
! 5305:
! 5306: void
! 5307: finish_viminfo_history()
! 5308: {
! 5309: int idx;
! 5310: int i;
! 5311: int type;
! 5312:
! 5313: for (type = 0; type <= 1; ++type)
! 5314: {
! 5315: if (history[type] == NULL)
! 5316: return;
! 5317: idx = hisidx[type] + viminfo_hisidx[type];
! 5318: if (idx >= hislen)
! 5319: idx -= hislen;
! 5320: if (viminfo_add_at_front)
! 5321: hisidx[type] = idx;
! 5322: else
! 5323: {
! 5324: if (hisidx[type] == -1)
! 5325: hisidx[type] = hislen - 1;
! 5326: do
! 5327: {
! 5328: if (history[type][idx] != NULL)
! 5329: break;
! 5330: if (++idx == hislen)
! 5331: idx = 0;
! 5332: } while (idx != hisidx[type]);
! 5333: if (idx != hisidx[type] && --idx < 0)
! 5334: idx = hislen - 1;
! 5335: }
! 5336: for (i = 0; i < viminfo_hisidx[type]; i++)
! 5337: {
! 5338: history[type][idx] = viminfo_history[type][i];
! 5339: if (--idx < 0)
! 5340: idx = hislen - 1;
! 5341: }
! 5342: vim_free(viminfo_history[type]);
! 5343: viminfo_history[type] = NULL;
! 5344: }
! 5345: }
! 5346:
! 5347: void
! 5348: write_viminfo_history(fp)
! 5349: FILE *fp;
! 5350: {
! 5351: int i;
! 5352: int type;
! 5353: int num_saved;
! 5354:
! 5355: init_history();
! 5356: if (hislen == 0)
! 5357: return;
! 5358: for (type = 0; type <= 1; ++type)
! 5359: {
! 5360: num_saved = get_viminfo_parameter(type == 0 ? ':' : '/');
! 5361: if (num_saved == 0)
! 5362: continue;
! 5363: if (num_saved < 0) /* Use default */
! 5364: num_saved = hislen;
! 5365: fprintf(fp, "\n# %s History (newest to oldest):\n",
! 5366: type == 0 ? "Command Line" : "Search String");
! 5367: if (num_saved > hislen)
! 5368: num_saved = hislen;
! 5369: i = hisidx[type];
! 5370: if (i >= 0)
! 5371: while (num_saved--)
! 5372: {
! 5373: if (history[type][i] != NULL)
! 5374: {
! 5375: putc(type == 0 ? ':' : '?', fp);
! 5376: viminfo_writestring(fp, history[type][i]);
! 5377: }
! 5378: if (--i < 0)
! 5379: i = hislen - 1;
! 5380: }
! 5381: }
! 5382: }
! 5383: #endif /* VIMINFO */