diff options
| author | Eliseo Martínez <eliseomarmol@gmail.com> | 2014-05-12 02:25:17 +0200 |
|---|---|---|
| committer | Eliseo Martínez <eliseomarmol@gmail.com> | 2014-05-15 20:46:01 +0200 |
| commit | da51dc9cf202772f60bd2da975dbef257bd9237c (patch) | |
| tree | 5c16b93238a153f55634e9323077f30c8133970c /src/ex_cmds.c | |
| parent | ffe61e5ba1721340ca51d56bae3ddaca415fb5bc (diff) | |
| download | rneovim-da51dc9cf202772f60bd2da975dbef257bd9237c.tar.gz rneovim-da51dc9cf202772f60bd2da975dbef257bd9237c.tar.bz2 rneovim-da51dc9cf202772f60bd2da975dbef257bd9237c.zip | |
Introduce nvim namespace: Move files.
Move files from src/ to src/nvim/.
- src/nvim/ becomes the new root dir for nvim executable sources.
- src/libnvim/ is planned to become root dir of the neovim library.
Diffstat (limited to 'src/ex_cmds.c')
| -rw-r--r-- | src/ex_cmds.c | 6374 |
1 files changed, 0 insertions, 6374 deletions
diff --git a/src/ex_cmds.c b/src/ex_cmds.c deleted file mode 100644 index 3613a02cb3..0000000000 --- a/src/ex_cmds.c +++ /dev/null @@ -1,6374 +0,0 @@ -/* - * VIM - Vi IMproved by Bram Moolenaar - * - * Do ":help uganda" in Vim to read copying and usage conditions. - * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. - */ - -/* - * ex_cmds.c: some functions for command line commands - */ - -#include <string.h> -#include <stdlib.h> - -#include "vim.h" -#include "version_defs.h" -#include "ex_cmds.h" -#include "buffer.h" -#include "charset.h" -#include "diff.h" -#include "digraph.h" -#include "edit.h" -#include "eval.h" -#include "ex_cmds2.h" -#include "ex_docmd.h" -#include "ex_eval.h" -#include "ex_getln.h" -#include "farsi.h" -#include "fileio.h" -#include "fold.h" -#include "getchar.h" -#include "indent.h" -#include "main.h" -#include "mark.h" -#include "mbyte.h" -#include "memline.h" -#include "message.h" -#include "misc1.h" -#include "misc2.h" -#include "garray.h" -#include "memory.h" -#include "move.h" -#include "normal.h" -#include "ops.h" -#include "option.h" -#include "os_unix.h" -#include "path.h" -#include "quickfix.h" -#include "regexp.h" -#include "screen.h" -#include "search.h" -#include "spell.h" -#include "syntax.h" -#include "tag.h" -#include "term.h" -#include "ui.h" -#include "undo.h" -#include "window.h" -#include "os/os.h" -#include "os/shell.h" - -static int linelen(int *has_tab); -static void do_filter(linenr_T line1, linenr_T line2, exarg_T *eap, - char_u *cmd, int do_in, - int do_out); -static char_u *viminfo_filename(char_u *); -static void do_viminfo(FILE *fp_in, FILE *fp_out, int flags); -static int viminfo_encoding(vir_T *virp); -static int read_viminfo_up_to_marks(vir_T *virp, int forceit, - int writing); - -static int check_readonly(int *forceit, buf_T *buf); -static void delbuf_msg(char_u *name); -static int help_compare(const void *s1, const void *s2); - -/* - * ":ascii" and "ga". - */ -void do_ascii(exarg_T *eap) -{ - int c; - int cval; - char buf1[20]; - char buf2[20]; - char_u buf3[7]; - int cc[MAX_MCO]; - int ci = 0; - int len; - - if (enc_utf8) - c = utfc_ptr2char(ml_get_cursor(), cc); - else - c = gchar_cursor(); - if (c == NUL) { - MSG("NUL"); - return; - } - - IObuff[0] = NUL; - if (!has_mbyte || (enc_dbcs != 0 && c < 0x100) || c < 0x80) { - if (c == NL) /* NUL is stored as NL */ - c = NUL; - if (c == CAR && get_fileformat(curbuf) == EOL_MAC) - cval = NL; /* NL is stored as CR */ - else - cval = c; - if (vim_isprintc_strict(c) && (c < ' ' - || c > '~' - )) { - transchar_nonprint(buf3, c); - vim_snprintf(buf1, sizeof(buf1), " <%s>", (char *)buf3); - } else - buf1[0] = NUL; - if (c >= 0x80) - vim_snprintf(buf2, sizeof(buf2), " <M-%s>", - (char *)transchar(c & 0x7f)); - else - buf2[0] = NUL; - vim_snprintf((char *)IObuff, IOSIZE, - _("<%s>%s%s %d, Hex %02x, Octal %03o"), - transchar(c), buf1, buf2, cval, cval, cval); - if (enc_utf8) - c = cc[ci++]; - else - c = 0; - } - - /* Repeat for combining characters. */ - while (has_mbyte && (c >= 0x100 || (enc_utf8 && c >= 0x80))) { - len = (int)STRLEN(IObuff); - /* This assumes every multi-byte char is printable... */ - if (len > 0) - IObuff[len++] = ' '; - IObuff[len++] = '<'; - if (enc_utf8 && utf_iscomposing(c) -# ifdef USE_GUI - && !gui.in_use -# endif - ) - IObuff[len++] = ' '; /* draw composing char on top of a space */ - len += (*mb_char2bytes)(c, IObuff + len); - vim_snprintf((char *)IObuff + len, IOSIZE - len, - c < 0x10000 ? _("> %d, Hex %04x, Octal %o") - : _("> %d, Hex %08x, Octal %o"), c, c, c); - if (ci == MAX_MCO) - break; - if (enc_utf8) - c = cc[ci++]; - else - c = 0; - } - - msg(IObuff); -} - -/* - * ":left", ":center" and ":right": align text. - */ -void ex_align(exarg_T *eap) -{ - pos_T save_curpos; - int len; - int indent = 0; - int new_indent; - int has_tab; - int width; - - if (curwin->w_p_rl) { - /* switch left and right aligning */ - if (eap->cmdidx == CMD_right) - eap->cmdidx = CMD_left; - else if (eap->cmdidx == CMD_left) - eap->cmdidx = CMD_right; - } - - width = atoi((char *)eap->arg); - save_curpos = curwin->w_cursor; - if (eap->cmdidx == CMD_left) { /* width is used for new indent */ - if (width >= 0) - indent = width; - } else { - /* - * if 'textwidth' set, use it - * else if 'wrapmargin' set, use it - * if invalid value, use 80 - */ - if (width <= 0) - width = curbuf->b_p_tw; - if (width == 0 && curbuf->b_p_wm > 0) - width = W_WIDTH(curwin) - curbuf->b_p_wm; - if (width <= 0) - width = 80; - } - - if (u_save((linenr_T)(eap->line1 - 1), (linenr_T)(eap->line2 + 1)) == FAIL) - return; - - for (curwin->w_cursor.lnum = eap->line1; - curwin->w_cursor.lnum <= eap->line2; ++curwin->w_cursor.lnum) { - if (eap->cmdidx == CMD_left) /* left align */ - new_indent = indent; - else { - has_tab = FALSE; /* avoid uninit warnings */ - len = linelen(eap->cmdidx == CMD_right ? &has_tab - : NULL) - get_indent(); - - if (len <= 0) /* skip blank lines */ - continue; - - if (eap->cmdidx == CMD_center) - new_indent = (width - len) / 2; - else { - new_indent = width - len; /* right align */ - - /* - * Make sure that embedded TABs don't make the text go too far - * to the right. - */ - if (has_tab) - while (new_indent > 0) { - (void)set_indent(new_indent, 0); - if (linelen(NULL) <= width) { - /* - * Now try to move the line as much as possible to - * the right. Stop when it moves too far. - */ - do - (void)set_indent(++new_indent, 0); - while (linelen(NULL) <= width); - --new_indent; - break; - } - --new_indent; - } - } - } - if (new_indent < 0) - new_indent = 0; - (void)set_indent(new_indent, 0); /* set indent */ - } - changed_lines(eap->line1, 0, eap->line2 + 1, 0L); - curwin->w_cursor = save_curpos; - beginline(BL_WHITE | BL_FIX); -} - -/* - * Get the length of the current line, excluding trailing white space. - */ -static int linelen(int *has_tab) -{ - char_u *line; - char_u *first; - char_u *last; - int save; - int len; - - /* find the first non-blank character */ - line = ml_get_curline(); - first = skipwhite(line); - - /* find the character after the last non-blank character */ - for (last = first + STRLEN(first); - last > first && vim_iswhite(last[-1]); --last) - ; - save = *last; - *last = NUL; - len = linetabsize(line); /* get line length */ - if (has_tab != NULL) /* check for embedded TAB */ - *has_tab = (vim_strrchr(first, TAB) != NULL); - *last = save; - - return len; -} - -/* Buffer for two lines used during sorting. They are allocated to - * contain the longest line being sorted. */ -static char_u *sortbuf1; -static char_u *sortbuf2; - -static int sort_ic; /* ignore case */ -static int sort_nr; /* sort on number */ -static int sort_rx; /* sort on regex instead of skipping it */ - -static int sort_abort; /* flag to indicate if sorting has been interrupted */ - -/* Struct to store info to be sorted. */ -typedef struct { - linenr_T lnum; /* line number */ - long start_col_nr; /* starting column number or number */ - long end_col_nr; /* ending column number */ -} sorti_T; - -static int -sort_compare(const void *s1, const void *s2); - -static int sort_compare(const void *s1, const void *s2) -{ - sorti_T l1 = *(sorti_T *)s1; - sorti_T l2 = *(sorti_T *)s2; - int result = 0; - - /* If the user interrupts, there's no way to stop qsort() immediately, but - * if we return 0 every time, qsort will assume it's done sorting and - * exit. */ - if (sort_abort) - return 0; - fast_breakcheck(); - if (got_int) - sort_abort = TRUE; - - /* When sorting numbers "start_col_nr" is the number, not the column - * number. */ - if (sort_nr) - result = l1.start_col_nr == l2.start_col_nr ? 0 - : l1.start_col_nr > l2.start_col_nr ? 1 : -1; - else { - /* We need to copy one line into "sortbuf1", because there is no - * guarantee that the first pointer becomes invalid when obtaining the - * second one. */ - STRNCPY(sortbuf1, ml_get(l1.lnum) + l1.start_col_nr, - l1.end_col_nr - l1.start_col_nr + 1); - sortbuf1[l1.end_col_nr - l1.start_col_nr] = 0; - STRNCPY(sortbuf2, ml_get(l2.lnum) + l2.start_col_nr, - l2.end_col_nr - l2.start_col_nr + 1); - sortbuf2[l2.end_col_nr - l2.start_col_nr] = 0; - - result = sort_ic ? STRICMP(sortbuf1, sortbuf2) - : STRCMP(sortbuf1, sortbuf2); - } - - /* If two lines have the same value, preserve the original line order. */ - if (result == 0) - return (int)(l1.lnum - l2.lnum); - return result; -} - -/* - * ":sort". - */ -void ex_sort(exarg_T *eap) -{ - regmatch_T regmatch; - int len; - linenr_T lnum; - long maxlen = 0; - size_t count = (size_t)(eap->line2 - eap->line1 + 1); - size_t i; - char_u *p; - char_u *s; - char_u *s2; - char_u c; /* temporary character storage */ - int unique = FALSE; - long deleted; - colnr_T start_col; - colnr_T end_col; - int sort_oct; /* sort on octal number */ - int sort_hex; /* sort on hex number */ - - /* Sorting one line is really quick! */ - if (count <= 1) - return; - - if (u_save((linenr_T)(eap->line1 - 1), (linenr_T)(eap->line2 + 1)) == FAIL) - return; - sortbuf1 = NULL; - sortbuf2 = NULL; - regmatch.regprog = NULL; - sorti_T *nrs = xmalloc(count * sizeof(sorti_T)); - - sort_abort = sort_ic = sort_rx = sort_nr = sort_oct = sort_hex = 0; - - for (p = eap->arg; *p != NUL; ++p) { - if (vim_iswhite(*p)) - ; - else if (*p == 'i') - sort_ic = TRUE; - else if (*p == 'r') - sort_rx = TRUE; - else if (*p == 'n') - sort_nr = 2; - else if (*p == 'o') - sort_oct = 2; - else if (*p == 'x') - sort_hex = 2; - else if (*p == 'u') - unique = TRUE; - else if (*p == '"') /* comment start */ - break; - else if (check_nextcmd(p) != NULL) { - eap->nextcmd = check_nextcmd(p); - break; - } else if (!ASCII_ISALPHA(*p) && regmatch.regprog == NULL) { - s = skip_regexp(p + 1, *p, TRUE, NULL); - if (*s != *p) { - EMSG(_(e_invalpat)); - goto sortend; - } - *s = NUL; - /* Use last search pattern if sort pattern is empty. */ - if (s == p + 1) { - if (last_search_pat() == NULL) { - EMSG(_(e_noprevre)); - goto sortend; - } - regmatch.regprog = vim_regcomp(last_search_pat(), RE_MAGIC); - } else - regmatch.regprog = vim_regcomp(p + 1, RE_MAGIC); - if (regmatch.regprog == NULL) - goto sortend; - p = s; /* continue after the regexp */ - regmatch.rm_ic = p_ic; - } else { - EMSG2(_(e_invarg2), p); - goto sortend; - } - } - - /* Can only have one of 'n', 'o' and 'x'. */ - if (sort_nr + sort_oct + sort_hex > 2) { - EMSG(_(e_invarg)); - goto sortend; - } - - /* From here on "sort_nr" is used as a flag for any number sorting. */ - sort_nr += sort_oct + sort_hex; - - /* - * Make an array with all line numbers. This avoids having to copy all - * the lines into allocated memory. - * When sorting on strings "start_col_nr" is the offset in the line, for - * numbers sorting it's the number to sort on. This means the pattern - * matching and number conversion only has to be done once per line. - * Also get the longest line length for allocating "sortbuf". - */ - for (lnum = eap->line1; lnum <= eap->line2; ++lnum) { - s = ml_get(lnum); - len = (int)STRLEN(s); - if (maxlen < len) - maxlen = len; - - start_col = 0; - end_col = len; - if (regmatch.regprog != NULL && vim_regexec(®match, s, 0)) { - if (sort_rx) { - start_col = (colnr_T)(regmatch.startp[0] - s); - end_col = (colnr_T)(regmatch.endp[0] - s); - } else - start_col = (colnr_T)(regmatch.endp[0] - s); - } else if (regmatch.regprog != NULL) - end_col = 0; - - if (sort_nr) { - /* Make sure vim_str2nr doesn't read any digits past the end - * of the match, by temporarily terminating the string there */ - s2 = s + end_col; - c = *s2; - *s2 = NUL; - /* Sorting on number: Store the number itself. */ - p = s + start_col; - if (sort_hex) - s = skiptohex(p); - else - s = skiptodigit(p); - if (s > p && s[-1] == '-') - --s; /* include preceding negative sign */ - if (*s == NUL) - /* empty line should sort before any number */ - nrs[lnum - eap->line1].start_col_nr = -MAXLNUM; - else - vim_str2nr(s, NULL, NULL, sort_oct, sort_hex, - &nrs[lnum - eap->line1].start_col_nr, NULL); - *s2 = c; - } else { - /* Store the column to sort at. */ - nrs[lnum - eap->line1].start_col_nr = start_col; - nrs[lnum - eap->line1].end_col_nr = end_col; - } - - nrs[lnum - eap->line1].lnum = lnum; - - if (regmatch.regprog != NULL) - fast_breakcheck(); - if (got_int) - goto sortend; - } - - /* Allocate a buffer that can hold the longest line. */ - sortbuf1 = xmalloc(maxlen + 1); - sortbuf2 = xmalloc(maxlen + 1); - - /* Sort the array of line numbers. Note: can't be interrupted! */ - qsort((void *)nrs, count, sizeof(sorti_T), sort_compare); - - if (sort_abort) - goto sortend; - - /* Insert the lines in the sorted order below the last one. */ - lnum = eap->line2; - for (i = 0; i < count; ++i) { - s = ml_get(nrs[eap->forceit ? count - i - 1 : i].lnum); - if (!unique || i == 0 - || (sort_ic ? STRICMP(s, sortbuf1) : STRCMP(s, sortbuf1)) != 0) { - if (ml_append(lnum++, s, (colnr_T)0, FALSE) == FAIL) - break; - if (unique) - STRCPY(sortbuf1, s); - } - fast_breakcheck(); - if (got_int) - goto sortend; - } - - /* delete the original lines if appending worked */ - if (i == count) - for (i = 0; i < count; ++i) - ml_delete(eap->line1, FALSE); - else - count = 0; - - /* Adjust marks for deleted (or added) lines and prepare for displaying. */ - deleted = (long)(count - (lnum - eap->line2)); - if (deleted > 0) - mark_adjust(eap->line2 - deleted, eap->line2, (long)MAXLNUM, -deleted); - else if (deleted < 0) - mark_adjust(eap->line2, MAXLNUM, -deleted, 0L); - changed_lines(eap->line1, 0, eap->line2 + 1, -deleted); - - curwin->w_cursor.lnum = eap->line1; - beginline(BL_WHITE | BL_FIX); - -sortend: - free(nrs); - free(sortbuf1); - free(sortbuf2); - vim_regfree(regmatch.regprog); - if (got_int) - EMSG(_(e_interr)); -} - -/* - * ":retab". - */ -void ex_retab(exarg_T *eap) -{ - linenr_T lnum; - int got_tab = FALSE; - long num_spaces = 0; - long num_tabs; - long len; - long col; - long vcol; - long start_col = 0; /* For start of white-space string */ - long start_vcol = 0; /* For start of white-space string */ - int temp; - long old_len; - char_u *ptr; - char_u *new_line = (char_u *)1; /* init to non-NULL */ - int did_undo; /* called u_save for current line */ - int new_ts; - int save_list; - linenr_T first_line = 0; /* first changed line */ - linenr_T last_line = 0; /* last changed line */ - - save_list = curwin->w_p_list; - curwin->w_p_list = 0; /* don't want list mode here */ - - new_ts = getdigits(&(eap->arg)); - if (new_ts < 0) { - EMSG(_(e_positive)); - return; - } - if (new_ts == 0) - new_ts = curbuf->b_p_ts; - for (lnum = eap->line1; !got_int && lnum <= eap->line2; ++lnum) { - ptr = ml_get(lnum); - col = 0; - vcol = 0; - did_undo = FALSE; - for (;; ) { - if (vim_iswhite(ptr[col])) { - if (!got_tab && num_spaces == 0) { - /* First consecutive white-space */ - start_vcol = vcol; - start_col = col; - } - if (ptr[col] == ' ') - num_spaces++; - else - got_tab = TRUE; - } else { - if (got_tab || (eap->forceit && num_spaces > 1)) { - /* Retabulate this string of white-space */ - - /* len is virtual length of white string */ - len = num_spaces = vcol - start_vcol; - num_tabs = 0; - if (!curbuf->b_p_et) { - temp = new_ts - (start_vcol % new_ts); - if (num_spaces >= temp) { - num_spaces -= temp; - num_tabs++; - } - num_tabs += num_spaces / new_ts; - num_spaces -= (num_spaces / new_ts) * new_ts; - } - if (curbuf->b_p_et || got_tab || - (num_spaces + num_tabs < len)) { - if (did_undo == FALSE) { - did_undo = TRUE; - if (u_save((linenr_T)(lnum - 1), - (linenr_T)(lnum + 1)) == FAIL) { - new_line = NULL; /* flag out-of-memory */ - break; - } - } - - /* len is actual number of white characters used */ - len = num_spaces + num_tabs; - old_len = (long)STRLEN(ptr); - new_line = xmalloc(old_len - col + start_col + len + 1); - - if (start_col > 0) - memmove(new_line, ptr, (size_t)start_col); - memmove(new_line + start_col + len, - ptr + col, (size_t)(old_len - col + 1)); - ptr = new_line + start_col; - for (col = 0; col < len; col++) - ptr[col] = (col < num_tabs) ? '\t' : ' '; - ml_replace(lnum, new_line, FALSE); - if (first_line == 0) - first_line = lnum; - last_line = lnum; - ptr = new_line; - col = start_col + len; - } - } - got_tab = FALSE; - num_spaces = 0; - } - if (ptr[col] == NUL) - break; - vcol += chartabsize(ptr + col, (colnr_T)vcol); - if (has_mbyte) - col += (*mb_ptr2len)(ptr + col); - else - ++col; - } - if (new_line == NULL) /* out of memory */ - break; - line_breakcheck(); - } - if (got_int) - EMSG(_(e_interr)); - - if (curbuf->b_p_ts != new_ts) - redraw_curbuf_later(NOT_VALID); - if (first_line != 0) - changed_lines(first_line, 0, last_line + 1, 0L); - - curwin->w_p_list = save_list; /* restore 'list' */ - - curbuf->b_p_ts = new_ts; - coladvance(curwin->w_curswant); - - u_clearline(); -} - -/* - * :move command - move lines line1-line2 to line dest - * - * return FAIL for failure, OK otherwise - */ -int do_move(linenr_T line1, linenr_T line2, linenr_T dest) -{ - char_u *str; - linenr_T l; - linenr_T extra; /* Num lines added before line1 */ - linenr_T num_lines; /* Num lines moved */ - linenr_T last_line; /* Last line in file after adding new text */ - - if (dest >= line1 && dest < line2) { - EMSG(_("E134: Move lines into themselves")); - return FAIL; - } - - num_lines = line2 - line1 + 1; - - /* - * First we copy the old text to its new location -- webb - * Also copy the flag that ":global" command uses. - */ - if (u_save(dest, dest + 1) == FAIL) - return FAIL; - for (extra = 0, l = line1; l <= line2; l++) { - str = vim_strsave(ml_get(l + extra)); - if (str != NULL) { - ml_append(dest + l - line1, str, (colnr_T)0, FALSE); - free(str); - if (dest < line1) - extra++; - } - } - - /* - * Now we must be careful adjusting our marks so that we don't overlap our - * mark_adjust() calls. - * - * We adjust the marks within the old text so that they refer to the - * last lines of the file (temporarily), because we know no other marks - * will be set there since these line numbers did not exist until we added - * our new lines. - * - * Then we adjust the marks on lines between the old and new text positions - * (either forwards or backwards). - * - * And Finally we adjust the marks we put at the end of the file back to - * their final destination at the new text position -- webb - */ - last_line = curbuf->b_ml.ml_line_count; - mark_adjust(line1, line2, last_line - line2, 0L); - changed_lines(last_line - num_lines + 1, 0, last_line + 1, num_lines); - if (dest >= line2) { - mark_adjust(line2 + 1, dest, -num_lines, 0L); - curbuf->b_op_start.lnum = dest - num_lines + 1; - curbuf->b_op_end.lnum = dest; - } else { - mark_adjust(dest + 1, line1 - 1, num_lines, 0L); - curbuf->b_op_start.lnum = dest + 1; - curbuf->b_op_end.lnum = dest + num_lines; - } - curbuf->b_op_start.col = curbuf->b_op_end.col = 0; - mark_adjust(last_line - num_lines + 1, last_line, - -(last_line - dest - extra), 0L); - changed_lines(last_line - num_lines + 1, 0, last_line + 1, -extra); - - /* - * Now we delete the original text -- webb - */ - if (u_save(line1 + extra - 1, line2 + extra + 1) == FAIL) - return FAIL; - - for (l = line1; l <= line2; l++) - ml_delete(line1 + extra, TRUE); - - if (!global_busy && num_lines > p_report) { - if (num_lines == 1) - MSG(_("1 line moved")); - else - smsg((char_u *)_("%" PRId64 " lines moved"), (int64_t)num_lines); - } - - /* - * Leave the cursor on the last of the moved lines. - */ - if (dest >= line1) - curwin->w_cursor.lnum = dest; - else - curwin->w_cursor.lnum = dest + (line2 - line1) + 1; - - if (line1 < dest) { - dest += num_lines + 1; - last_line = curbuf->b_ml.ml_line_count; - if (dest > last_line + 1) - dest = last_line + 1; - changed_lines(line1, 0, dest, 0L); - } else - changed_lines(dest + 1, 0, line1 + num_lines, 0L); - - return OK; -} - -/* - * ":copy" - */ -void ex_copy(linenr_T line1, linenr_T line2, linenr_T n) -{ - linenr_T count; - char_u *p; - - count = line2 - line1 + 1; - curbuf->b_op_start.lnum = n + 1; - curbuf->b_op_end.lnum = n + count; - curbuf->b_op_start.col = curbuf->b_op_end.col = 0; - - /* - * there are three situations: - * 1. destination is above line1 - * 2. destination is between line1 and line2 - * 3. destination is below line2 - * - * n = destination (when starting) - * curwin->w_cursor.lnum = destination (while copying) - * line1 = start of source (while copying) - * line2 = end of source (while copying) - */ - if (u_save(n, n + 1) == FAIL) - return; - - curwin->w_cursor.lnum = n; - while (line1 <= line2) { - /* need to use vim_strsave() because the line will be unlocked within - * ml_append() */ - p = vim_strsave(ml_get(line1)); - if (p != NULL) { - ml_append(curwin->w_cursor.lnum, p, (colnr_T)0, FALSE); - free(p); - } - /* situation 2: skip already copied lines */ - if (line1 == n) - line1 = curwin->w_cursor.lnum; - ++line1; - if (curwin->w_cursor.lnum < line1) - ++line1; - if (curwin->w_cursor.lnum < line2) - ++line2; - ++curwin->w_cursor.lnum; - } - - appended_lines_mark(n, count); - - msgmore((long)count); -} - -static char_u *prevcmd = NULL; /* the previous command */ - -#if defined(EXITFREE) || defined(PROTO) -void free_prev_shellcmd(void) -{ - free(prevcmd); -} - -#endif - -/* - * Handle the ":!cmd" command. Also for ":r !cmd" and ":w !cmd" - * Bangs in the argument are replaced with the previously entered command. - * Remember the argument. - */ -void do_bang(int addr_count, exarg_T *eap, int forceit, int do_in, int do_out) -{ - char_u *arg = eap->arg; /* command */ - linenr_T line1 = eap->line1; /* start of range */ - linenr_T line2 = eap->line2; /* end of range */ - char_u *newcmd = NULL; /* the new command */ - int free_newcmd = FALSE; /* need to free() newcmd */ - int ins_prevcmd; - char_u *t; - char_u *p; - char_u *trailarg; - int len; - int scroll_save = msg_scroll; - - /* - * Disallow shell commands for "rvim". - * Disallow shell commands from .exrc and .vimrc in current directory for - * security reasons. - */ - if (check_restricted() || check_secure()) - return; - - if (addr_count == 0) { /* :! */ - msg_scroll = FALSE; /* don't scroll here */ - autowrite_all(); - msg_scroll = scroll_save; - } - - /* - * Try to find an embedded bang, like in :!<cmd> ! [args] - * (:!! is indicated by the 'forceit' variable) - */ - ins_prevcmd = forceit; - trailarg = arg; - do { - len = (int)STRLEN(trailarg) + 1; - if (newcmd != NULL) - len += (int)STRLEN(newcmd); - if (ins_prevcmd) { - if (prevcmd == NULL) { - EMSG(_(e_noprev)); - free(newcmd); - return; - } - len += (int)STRLEN(prevcmd); - } - t = xmalloc(len); - *t = NUL; - if (newcmd != NULL) - STRCAT(t, newcmd); - if (ins_prevcmd) - STRCAT(t, prevcmd); - p = t + STRLEN(t); - STRCAT(t, trailarg); - free(newcmd); - newcmd = t; - - /* - * Scan the rest of the argument for '!', which is replaced by the - * previous command. "\!" is replaced by "!" (this is vi compatible). - */ - trailarg = NULL; - while (*p) { - if (*p == '!') { - if (p > newcmd && p[-1] == '\\') - STRMOVE(p - 1, p); - else { - trailarg = p; - *trailarg++ = NUL; - ins_prevcmd = TRUE; - break; - } - } - ++p; - } - } while (trailarg != NULL); - - free(prevcmd); - prevcmd = newcmd; - - if (bangredo) { /* put cmd in redo buffer for ! command */ - /* If % or # appears in the command, it must have been escaped. - * Reescape them, so that redoing them does not substitute them by the - * buffername. */ - char_u *cmd = vim_strsave_escaped(prevcmd, (char_u *)"%#"); - - AppendToRedobuffLit(cmd, -1); - free(cmd); - AppendToRedobuff((char_u *)"\n"); - bangredo = FALSE; - } - /* - * Add quotes around the command, for shells that need them. - */ - if (*p_shq != NUL) { - newcmd = xmalloc(STRLEN(prevcmd) + 2 * STRLEN(p_shq) + 1); - STRCPY(newcmd, p_shq); - STRCAT(newcmd, prevcmd); - STRCAT(newcmd, p_shq); - free_newcmd = TRUE; - } - if (addr_count == 0) { /* :! */ - /* echo the command */ - msg_start(); - msg_putchar(':'); - msg_putchar('!'); - msg_outtrans(newcmd); - msg_clr_eos(); - windgoto(msg_row, msg_col); - - do_shell(newcmd, 0); - } else { /* :range! */ - /* Careful: This may recursively call do_bang() again! (because of - * autocommands) */ - do_filter(line1, line2, eap, newcmd, do_in, do_out); - apply_autocmds(EVENT_SHELLFILTERPOST, NULL, NULL, FALSE, curbuf); - } - if (free_newcmd) - free(newcmd); -} - -/* - * do_filter: filter lines through a command given by the user - * - * We mostly use temp files and the call_shell() routine here. This would - * normally be done using pipes on a UNIX machine, but this is more portable - * to non-unix machines. The call_shell() routine needs to be able - * to deal with redirection somehow, and should handle things like looking - * at the PATH env. variable, and adding reasonable extensions to the - * command name given by the user. All reasonable versions of call_shell() - * do this. - * Alternatively, if on Unix and redirecting input or output, but not both, - * and the 'shelltemp' option isn't set, use pipes. - * We use input redirection if do_in is TRUE. - * We use output redirection if do_out is TRUE. - */ -static void -do_filter ( - linenr_T line1, - linenr_T line2, - exarg_T *eap, /* for forced 'ff' and 'fenc' */ - char_u *cmd, - int do_in, - int do_out -) -{ - char_u *itmp = NULL; - char_u *otmp = NULL; - linenr_T linecount; - linenr_T read_linecount; - pos_T cursor_save; - char_u *cmd_buf; - buf_T *old_curbuf = curbuf; - int shell_flags = 0; - - if (*cmd == NUL) /* no filter command */ - return; - - - cursor_save = curwin->w_cursor; - linecount = line2 - line1 + 1; - curwin->w_cursor.lnum = line1; - curwin->w_cursor.col = 0; - changed_line_abv_curs(); - invalidate_botline(); - - /* - * When using temp files: - * 1. * Form temp file names - * 2. * Write the lines to a temp file - * 3. Run the filter command on the temp file - * 4. * Read the output of the command into the buffer - * 5. * Delete the original lines to be filtered - * 6. * Remove the temp files - * - * When writing the input with a pipe or when catching the output with a - * pipe only need to do 3. - */ - - if (do_out) - shell_flags |= kShellOptDoOut; - - if (!do_in && do_out && !p_stmp) { - // Use a pipe to fetch stdout of the command, do not use a temp file. - shell_flags |= kShellOptRead; - curwin->w_cursor.lnum = line2; - } else if (do_in && !do_out && !p_stmp) { - // Use a pipe to write stdin of the command, do not use a temp file. - shell_flags |= kShellOptWrite; - curbuf->b_op_start.lnum = line1; - curbuf->b_op_end.lnum = line2; - } else if (do_in && do_out && !p_stmp) { - // Use a pipe to write stdin and fetch stdout of the command, do not - // use a temp file. - shell_flags |= kShellOptRead | kShellOptWrite; - curbuf->b_op_start.lnum = line1; - curbuf->b_op_end.lnum = line2; - curwin->w_cursor.lnum = line2; - } else if ((do_in && (itmp = vim_tempname('i')) == NULL) - || (do_out && (otmp = vim_tempname('o')) == NULL)) { - EMSG(_(e_notmp)); - goto filterend; - } - - /* - * The writing and reading of temp files will not be shown. - * Vi also doesn't do this and the messages are not very informative. - */ - ++no_wait_return; /* don't call wait_return() while busy */ - if (itmp != NULL && buf_write(curbuf, itmp, NULL, line1, line2, eap, - FALSE, FALSE, FALSE, TRUE) == FAIL) { - msg_putchar('\n'); /* keep message from buf_write() */ - --no_wait_return; - if (!aborting()) - (void)EMSG2(_(e_notcreate), itmp); /* will call wait_return */ - goto filterend; - } - if (curbuf != old_curbuf) - goto filterend; - - if (!do_out) - msg_putchar('\n'); - - /* Create the shell command in allocated memory. */ - cmd_buf = make_filter_cmd(cmd, itmp, otmp); - - windgoto((int)Rows - 1, 0); - cursor_on(); - - /* - * When not redirecting the output the command can write anything to the - * screen. If 'shellredir' is equal to ">", screen may be messed up by - * stderr output of external command. Clear the screen later. - * If do_in is FALSE, this could be something like ":r !cat", which may - * also mess up the screen, clear it later. - */ - if (!do_out || STRCMP(p_srr, ">") == 0 || !do_in) - redraw_later_clear(); - - if (do_out) { - if (u_save((linenr_T)(line2), (linenr_T)(line2 + 1)) == FAIL) { - free(cmd_buf); - goto error; - } - redraw_curbuf_later(VALID); - } - read_linecount = curbuf->b_ml.ml_line_count; - - /* - * When call_shell() fails wait_return() is called to give the user a - * chance to read the error messages. Otherwise errors are ignored, so you - * can see the error messages from the command that appear on stdout; use - * 'u' to fix the text - * Switch to cooked mode when not redirecting stdin, avoids that something - * like ":r !cat" hangs. - * Pass on the kShellDoOut flag when the output is being redirected. - */ - if (call_shell( |