📄 cmd1.c
字号:
/* cmd1.c *//* Author: * Steve Kirkendall * 14407 SW Teal Blvd. #C * Beaverton, OR 97005 * kirkenda@cs.pdx.edu *//* This file contains some of the EX commands - mostly ones that deal with * files, options, etc. -- anything except text. */#include "config.h"#include "ctype.h"#include "vi.h"#include "regexp.h"#ifdef DEBUG/* print the selected lines with info on the blocks *//*ARGSUSED*/void cmd_debug(frommark, tomark, cmd, bang, extra) MARK frommark; MARK tomark; CMD cmd; int bang; char *extra;{ REG char *scan; REG long l; REG int i; int len; /* scan lnum[] to determine which block its in */ l = markline(frommark); for (i = 1; l > lnum[i]; i++) { } do { /* fetch text of the block containing that line */ scan = blkget(i)->c; /* calculate its length */ if (scan[BLKSIZE - 1]) { len = BLKSIZE; } else { len = strlen(scan); } /* print block stats */ msg("##### hdr[%d]=%d, lnum[%d-1]=%ld, lnum[%d]=%ld (%ld lines)", i, hdr.n[i], i, lnum[i-1], i, lnum[i], lnum[i] - lnum[i - 1]); msg("##### len=%d, buf=0x%lx, %sdirty", len, scan, ((int *)scan)[MAXBLKS + 1] ? "" : "not "); if (bang) { while (--len >= 0) { addch(*scan); scan++; } } exrefresh(); /* next block */ i++; } while (i < MAXBLKS && lnum[i] && lnum[i - 1] < markline(tomark));}/* This function checks a lot of conditions to make sure they aren't screwy *//*ARGSUSED*/void cmd_validate(frommark, tomark, cmd, bang, extra) MARK frommark; MARK tomark; CMD cmd; int bang; char *extra;{ char *scan; int i; int nlcnt; /* used to count newlines */ int len; /* counts non-NUL characters */ /* check lnum[0] */ if (lnum[0] != 0L) { msg("lnum[0] = %ld", lnum[0]); } /* check each block */ for (i = 1; lnum[i] <= nlines; i++) { scan = blkget(i)->c; if (scan[BLKSIZE - 1]) { msg("block %d has no NUL at the end", i); } else { for (nlcnt = len = 0; *scan; scan++, len++) { if (*scan == '\n') { nlcnt++; } } if (scan[-1] != '\n') { msg("block %d doesn't end with '\\n' (length %d)", i, len); } if (bang || nlcnt != lnum[i] - lnum[i - 1]) { msg("block %d (line %ld?) has %d lines, but should have %ld", i, lnum[i - 1] + 1L, nlcnt, lnum[i] - lnum[i - 1]); } } exrefresh(); } /* check lnum again */ if (lnum[i] != INFINITY) { msg("hdr.n[%d] = %d, but lnum[%d] = %ld", i, hdr.n[i], i, lnum[i]); } msg("# = \"%s\", %% = \"%s\"", prevorig, origname); msg("V_from=%ld.%d, cursor=%ld.%d", markline(V_from), markidx(V_from), markline(cursor), markidx(cursor));}#endif /* DEBUG *//*ARGSUSED*/void cmd_mark(frommark, tomark, cmd, bang, extra) MARK frommark; MARK tomark; CMD cmd; int bang; char *extra;{ /* validate the name of the mark */ if (*extra == '"') { extra++; } /* valid mark names are lowercase ascii characters */ if (!isascii(*extra) || !islower(*extra) || extra[1]) { msg("Invalid mark name"); return; } mark[*extra - 'a'] = tomark;}/*ARGSUSED*/void cmd_write(frommark, tomark, cmd, bang, extra) MARK frommark; MARK tomark; CMD cmd; int bang; char *extra;{ int fd; int append; /* boolean: write in "append" mode? */ REG long l; REG char *scan; REG int i; /* if writing to a filter, then let filter() handle it */ if (*extra == '!') { filter(frommark, tomark, extra + 1, FALSE); return; } /* if all lines are to be written, use tmpsave() */ if (frommark == MARK_FIRST && tomark == MARK_LAST && cmd == CMD_WRITE) { tmpsave(extra, bang); return; } /* see if we're going to do this in append mode or not */ append = FALSE; if (extra[0] == '>' && extra[1] == '>') { extra += 2; append = TRUE; } /* either the file must not exist, or we must have a ! or be appending */ if (access(extra, 0) == 0 && !bang && !append) { msg("File already exists - Use :w! to overwrite"); return; } /* else do it line-by-line, like cmd_print() */ if (append) {#ifdef O_APPEND fd = open(extra, O_WRONLY|O_APPEND);#else fd = open(extra, O_WRONLY); if (fd >= 0) { lseek(fd, 0L, 2); }#endif } else { fd = -1; /* so we know the file isn't open yet */ } if (fd < 0) { fd = creat(extra, FILEPERMS); if (fd < 0) { msg("Can't write to \"%s\"", extra); return; } } for (l = markline(frommark); l <= markline(tomark); l++) { /* get the next line */ scan = fetchline(l); i = strlen(scan); scan[i++] = '\n'; /* print the line */ if (twrite(fd, scan, i) < i) { msg("Write failed"); break; } } rptlines = markline(tomark) - markline(frommark) + 1; rptlabel = "written"; close(fd);} /*ARGSUSED*/void cmd_shell(frommark, tomark, cmd, bang, extra) MARK frommark, tomark; CMD cmd; int bang; char *extra;{ static char prevextra[80]; /* special case: ":sh" means ":!sh" */ if (cmd == CMD_SHELL) { extra = o_shell; frommark = tomark = 0L; } /* if extra is "!", substitute previous command */ if (*extra == '!') { if (!*prevextra) { msg("No previous shell command to substitute for '!'"); return; } extra = prevextra; } else if (cmd == CMD_BANG && strlen(extra) < sizeof(prevextra) - 1) { strcpy(prevextra, extra); } /* warn the user if the file hasn't been saved yet */ if (*o_warn && tstflag(file, MODIFIED)) { if (mode == MODE_VI) { mode = MODE_COLON; } msg("Warning: \"%s\" has been modified but not yet saved", origname); } /* if no lines were specified, just run the command */ suspend_curses(); if (frommark == 0L) { system(extra); } else /* pipe lines from the file through the command */ { filter(frommark, tomark, extra, TRUE); } /* resume curses quietly for MODE_EX, but noisily otherwise */ resume_curses(mode == MODE_EX);}/*ARGSUSED*/void cmd_global(frommark, tomark, cmd, bang, extra) MARK frommark, tomark; CMD cmd; int bang; char *extra; /* rest of the command line */{ char *cmdptr; /* the command from the command line */ char cmdln[100]; /* copy of the command from the command line */ char *line; /* a line from the file */ long l; /* used as a counter to move through lines */ long lqty; /* quantity of lines to be scanned */ long nchanged; /* number of lines changed */ regexp *re; /* the compiled search expression */ /* can't nest global commands */ if (doingglobal) { msg("Can't nest global commands."); rptlines = -1L; return; } /* ":g! ..." is the same as ":v ..." */ if (bang) { cmd = CMD_VGLOBAL; } /* make sure we got a search pattern */ if (*extra != '/' && *extra != '?') { msg("Usage: %c /regular expression/ command", cmd == CMD_GLOBAL ? 'g' : 'v'); return; } /* parse & compile the search pattern */ cmdptr = parseptrn(extra); if (!extra[1]) { msg("Can't use empty regular expression with '%c' command", cmd == CMD_GLOBAL ? 'g' : 'v'); return; } re = regcomp(extra + 1); if (!re) { /* regcomp found & described an error */ return; } /* for each line in the range */ doingglobal = TRUE; ChangeText { /* NOTE: we have to go through the lines in a forward order, * otherwise "g/re/p" would look funny. *BUT* for "g/re/d" * to work, simply adding 1 to the line# on each loop won't * work. The solution: count lines relative to the end of * the file. Think about it. */ for (l = nlines - markline(frommark), lqty = markline(tomark) - markline(frommark) + 1L, nchanged = 0L; lqty > 0 && nlines - l >= 0 && nchanged >= 0L; l--, lqty--) { /* fetch the line */ line = fetchline(nlines - l); /* if it contains the search pattern... */ if ((!regexec(re, line, 1)) == (cmd != CMD_GLOBAL)) { /* move the cursor to that line */ cursor = MARK_AT_LINE(nlines - l); /* do the ex command (without mucking up * the original copy of the command line) */ strcpy(cmdln, cmdptr); rptlines = 0L; doexcmd(cmdln); nchanged += rptlines; } } } doingglobal = FALSE; /* free the regexp */ free(re); /* Reporting...*/ rptlines = nchanged;}/*ARGSUSED*/void cmd_file(frommark, tomark, cmd, bang, extra) MARK frommark, tomark; CMD cmd; int bang; char *extra;{#ifndef CRUNCH /* if we're given a new filename, use it as this file's name */ if (extra && *extra) { strcpy(origname, extra); storename(origname); setflag(file, NOTEDITED); }#endif if (cmd == CMD_FILE) {#ifndef CRUNCH msg("\"%s\" %s%s%s %ld lines, line %ld [%ld%%]",#else msg("\"%s\" %s%s %ld lines, line %ld [%ld%%]",#endif *origname ? origname : "[NO FILE]", tstflag(file, MODIFIED) ? "[MODIFIED]" : "",#ifndef CRUNCH tstflag(file, NOTEDITED) ?"[NOT EDITED]":"",#endif tstflag(file, READONLY) ? "[READONLY]" : "", nlines, markline(frommark), markline(frommark) * 100 / nlines); }#ifndef CRUNCH else if (markline(frommark) != markline(tomark)) { msg("range \"%ld,%ld\" contains %ld lines", markline(frommark), markline(tomark), markline(tomark) - markline(frommark) + 1L); }#endif else { msg("%ld", markline(frommark)); }}/*ARGSUSED*/void cmd_edit(frommark, tomark, cmd, bang, extra) MARK frommark, tomark; CMD cmd; int bang; char *extra;{ long line = 1L; /* might be set to prevline */#ifndef CRUNCH char *init = (char *)0;#endif /* if ":vi", then switch to visual mode, and if no file is named * then don't switch files. */ if (cmd == CMD_VISUAL) { mode = MODE_VI; msg(""); if (!*extra) { return; } } /* Editing previous file? Then start at previous line */ if (!strcmp(extra, prevorig)) { line = prevline; }#ifndef CRUNCH /* if we were given an explicit starting line, then start there */ if (*extra == '+') { for (init = ++extra; !isspace(*extra); extra++) { } while (isspace(*extra)) { *extra++ = '\0'; } if (!*init) { init = "$"; } if (!extra) { extra = origname; } }#endif /* not CRUNCH */ /* switch files */ if (tmpabort(bang)) { tmpstart(extra); if (line <= nlines && line >= 1L) { cursor = MARK_AT_LINE(line); }#ifndef CRUNCH if (init) { doexcmd(init); }#endif } else { msg("Use edit! to abort changes, or w to save changes"); /* so we can say ":e!#" next time... */ strcpy(prevorig, extra); prevline = 1L; }}/* This code is also used for rewind -- GB *//*ARGSUSED*/void cmd_next(frommark, tomark, cmd, bang, extra) MARK frommark, tomark; CMD cmd; int bang; char *extra;{ int i, j; char *scan; /* if extra stuff given, use ":args" to define a new args list */ if (cmd == CMD_NEXT && extra && *extra) { cmd_args(frommark, tomark, cmd, bang, extra); } /* move to the next arg */ if (cmd == CMD_NEXT) { i = argno + 1; } else if (cmd == CMD_PREVIOUS) { i = argno - 1; } else /* cmd == CMD_REWIND */ { i = 0; } if (i < 0 || i >= nargs) { msg("No %sfiles to edit", cmd == CMD_REWIND ? "" : "more "); return; } /* find & isolate the name of the file to edit */ for (j = i, scan = args; j > 0; j--) { while(*scan++) { } } /* switch to the next file */ if (tmpabort(bang)) { tmpstart(scan); argno = i; } else { msg("Use :%s! to abort changes, or w to save changes", cmd == CMD_NEXT ? "next" : cmd == CMD_PREVIOUS ? "previous" : "rewind"); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -