This is cmdcmds.c in view mode; [Download] [Up]
/* vi:ts=4:sw=4 * * VIM - Vi IMproved by Bram Moolenaar * * Read the file "credits.txt" for a list of people who contributed. * Read the file "uganda.txt" for copying and usage conditions. */ /* * cmdcmds.c: functions for command line commands */ #include "vim.h" #include "globals.h" #include "proto.h" #include "param.h" #if defined(LATTICE) || defined(NT) # define mktemp(a) tmpnam(a) #endif extern char *mktemp __ARGS((char *)); /* * align text: * type = -1 left aligned * type = 0 centered * type = 1 right aligned */ void do_align(start, end, width, type) linenr_t start; linenr_t end; int width; int type; { FPOS pos; int len; int indent = 0; pos = curwin->w_cursor; if (type == -1) /* left align: 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 = Columns - curbuf->b_p_wm; if (width <= 0) width = 80; } if (!u_save((linenr_t)(start - 1), (linenr_t)(end + 1))) return; for (curwin->w_cursor.lnum = start; curwin->w_cursor.lnum <= end; ++curwin->w_cursor.lnum) { set_indent(indent, TRUE); /* remove existing indent */ if (type == -1) /* left align */ continue; len = strsize(ml_get(curwin->w_cursor.lnum)); /* get line lenght */ if (len < width) switch (type) { case 0: set_indent((width - len) / 2, FALSE); /* center */ break; case 1: set_indent(width - len, FALSE); /* right */ break; } } curwin->w_cursor = pos; beginline(TRUE); updateScreen(NOT_VALID); } /* * :move command - move lines line1-line2 to line n * * return FAIL for failure, OK otherwise */ int do_move(line1, line2, n) linenr_t line1; linenr_t line2; linenr_t n; { char_u *q; int has_mark; if (n >= line1 && n < line2 && line2 > line1) { EMSG("Move lines into themselves"); return FAIL; } /* * adjust line marks (global marks done below) * if the lines are moved down, the marks in the moved lines * move down and the marks in the lines between the old and * new position move up. * If the lines are moved up it is just the other way round */ if (n >= line2) /* move down */ { mark_adjust(line1, line2, n - line2); mark_adjust(line2 + 1, n, -(line2 - line1 + 1)); } else /* move up */ { mark_adjust(line1, line2, -(line1 - n - 1)); mark_adjust(n + 1, line1 - 1, line2 - line1 + 1); } if (n >= line1) { --n; curwin->w_cursor.lnum = n - (line2 - line1) + 1; } else curwin->w_cursor.lnum = n + 1; while (line1 <= line2) { /* this undo is not efficient, but it works */ u_save(line1 - 1, line1 + 1); q = strsave(ml_get(line1)); if (q != NULL) { /* * marks from global command go with the line */ has_mark = ml_has_mark(line1); ml_delete(line1); u_save(n, n + 1); ml_append(n, q, (colnr_t)0, FALSE); free(q); if (has_mark) ml_setmarked(n + 1); } if (n < line1) { ++n; ++line1; } else --line2; } CHANGED; return OK; } /* * :copy command - copy lines line1-line2 to line n */ void do_copy(line1, line2, n) linenr_t line1; linenr_t line2; linenr_t n; { linenr_t lnum; char_u *p; mark_adjust(n + 1, MAXLNUM, line2 - line1 + 1); /* * 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) */ u_save(n, n + 1); curwin->w_cursor.lnum = n; lnum = line2 - line1 + 1; while (line1 <= line2) { /* need to use strsave() because the line will be unlocked within ml_append */ p = 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; } CHANGED; msgmore((long)lnum); } /* * handle the :! command. * We replace the extra bangs by the previously entered command and remember * the command. */ void dobang(addr_count, line1, line2, forceit, arg) int addr_count; linenr_t line1, line2; int forceit; char_u *arg; { static char_u *prevcmd = NULL; /* the previous command */ char_u *t; char_u *trailarg; int len; /* * Disallow shell commands from .exrc and .vimrc in current directory for * security reasons. */ if (secure) { secure = 2; emsg(e_curdir); return; } len = STRLEN(arg) + 1; autowrite_all(); /* * try to find an embedded bang, like in :!<cmd> ! [args] * (:!! is indicated by the 'forceit' variable) */ trailarg = arg; skiptospace(&trailarg); skipspace(&trailarg); if (*trailarg == '!') *trailarg++ = NUL; else trailarg = NULL; if (forceit || trailarg != NULL) /* use the previous command */ { if (prevcmd == NULL) { emsg(e_noprev); return; } len += STRLEN(prevcmd) * (trailarg != NULL && forceit ? 2 : 1); } if (len > CMDBUFFSIZE) { emsg(e_toolong); return; } if ((t = alloc(len)) == NULL) return; *t = NUL; if (forceit) STRCPY(t, prevcmd); STRCAT(t, arg); if (trailarg != NULL) { STRCAT(t, prevcmd); STRCAT(t, trailarg); } free(prevcmd); prevcmd = t; if (bangredo) /* put cmd in redo buffer for ! command */ { AppendToRedobuff(prevcmd); AppendToRedobuff((char_u *)"\n"); bangredo = FALSE; } /* echo the command */ msg_start(); msg_outchar(':'); if (addr_count) /* :range! */ { msg_outnum((long)line1); msg_outchar(','); msg_outnum((long)line2); } msg_outchar('!'); msg_outtrans(prevcmd, -1); msg_ceol(); if (addr_count == 0) /* :! */ doshell(prevcmd); else /* :range! */ dofilter(line1, line2, prevcmd, TRUE, TRUE); } /* * call a shell to execute a command */ void doshell(cmd) char_u *cmd; { BUF *buf; /* * Disallow shell commands from .exrc and .vimrc in current directory for * security reasons. */ if (secure) { secure = 2; emsg(e_curdir); msg_end(); return; } stoptermcap(); msg_outchar('\n'); /* may shift screen one line up */ /* warning message before calling the shell */ if (p_warn) for (buf = firstbuf; buf; buf = buf->b_next) if (buf->b_changed) { msg_outstr((char_u *)"[No write since last change]\n"); break; } windgoto((int)Rows - 1, 0); cursor_on(); (void)call_shell(cmd, 0, TRUE); #ifdef AMIGA wait_return(term_console ? -1 : TRUE); /* see below */ #else wait_return(TRUE); /* includes starttermcap() */ #endif /* * In an Amiga window redrawing is caused by asking the window size. * If we got an interrupt this will not work. The chance that the window * size is wrong is very small, but we need to redraw the screen. * Don't do this if ':' hit in wait_return(). * THIS IS UGLY but it save an extra redraw. */ #ifdef AMIGA if (skip_redraw) /* ':' hit in wait_return() */ must_redraw = CLEAR; else if (term_console) { OUTSTR("\033[0 q"); /* get window size */ if (got_int) must_redraw = CLEAR; /* if got_int is TRUE we have to redraw */ else must_redraw = 0; /* no extra redraw needed */ } #endif /* AMIGA */ } /* * dofilter: filter lines through a command given by the user * * We 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 * the machines we usually run on. 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. * We use input redirection if do_in is TRUE. * We use output redirection if do_out is TRUE. */ void dofilter(line1, line2, buff, do_in, do_out) linenr_t line1, line2; char_u *buff; int do_in, do_out; { #ifdef LATTICE char_u itmp[L_tmpnam]; /* use tmpnam() */ char_u otmp[L_tmpnam]; #else char_u itmp[TMPNAMELEN]; char_u otmp[TMPNAMELEN]; #endif linenr_t linecount; /* * Disallow shell commands from .exrc and .vimrc in current directory for * security reasons. */ if (secure) { secure = 2; emsg(e_curdir); return; } if (*buff == NUL) /* no filter command */ return; linecount = line2 - line1 + 1; curwin->w_cursor.lnum = line1; curwin->w_cursor.col = 0; /* cursupdate(); */ /* * 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 */ #ifndef LATTICE /* for lattice we use tmpnam(), which will make its own name */ STRCPY(itmp, TMPNAME1); STRCPY(otmp, TMPNAME2); #endif if ((do_in && *mktemp((char *)itmp) == NUL) || (do_out && *mktemp((char *)otmp) == NUL)) { emsg(e_notmp); return; } /* * ! command will be overwritten by next mesages * This is a trade off between showing the command and not scrolling the * text one line up (problem on slow terminals). */ must_redraw = CLEAR; /* screen has been shifted up one line */ ++no_wait_return; /* don't call wait_return() while busy */ if (do_in && buf_write(curbuf, itmp, NULL, line1, line2, FALSE, 0, FALSE) == FAIL) { msg_outchar('\n'); /* keep message from writeit() */ --no_wait_return; (void)emsg2(e_notcreate, itmp); /* will call wait_return */ return; } if (!do_out) outchar('\n'); #if defined(UNIX) && !defined(ARCHIE) /* * put braces around the command (for concatenated commands) */ sprintf((char *)IObuff, "(%s)", (char *)buff); if (do_in) { STRCAT(IObuff, " < "); STRCAT(IObuff, itmp); } if (do_out) { STRCAT(IObuff, " > "); STRCAT(IObuff, otmp); } #else /* * for shells that don't understand braces around commands, at least allow * the use of commands in a pipe. */ STRCPY(IObuff, buff); if (do_in) { char_u *p; /* * If there is a pipe, we have to put the '<' in front of it */ p = STRCHR(IObuff, '|'); if (p) *p = NUL; STRCAT(IObuff, " < "); STRCAT(IObuff, itmp); p = STRCHR(buff, '|'); if (p) STRCAT(IObuff, p); } if (do_out) { STRCAT(IObuff, " > "); STRCAT(IObuff, otmp); } #endif windgoto((int)Rows - 1, 0); cursor_on(); /* errors are ignored, so you can see the error messages from the command; use 'u' to fix the text */ (void)call_shell(IObuff, 1, FALSE); if (do_out) { if (!u_save((linenr_t)(line2), (linenr_t)(line2 + 1))) { linecount = 0; goto error; } if (readfile(otmp, NULL, line2, FALSE, (linenr_t)0, MAXLNUM) == FAIL) { outchar('\n'); emsg2(e_notread, otmp); linecount = 0; goto error; } if (do_in) { curwin->w_cursor.lnum = line1; dellines(linecount, TRUE, TRUE); } --no_wait_return; } else { error: --no_wait_return; wait_return(FALSE); } updateScreen(CLEAR); /* do this before messages below */ if (linecount > p_report) { if (!do_in && do_out) msgmore(linecount); else smsg((char_u *)"%ld lines filtered", (long)linecount); } remove((char *)itmp); remove((char *)otmp); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.