mirror of
https://github.com/vbatts/bvi.git
synced 2024-11-26 02:25:39 +00:00
829 lines
19 KiB
C
829 lines
19 KiB
C
|
/* COMM.C - Routines to parse and execute "command line" commands, such as
|
||
|
* search or colon commands.
|
||
|
*
|
||
|
* 1996-01-16 created;
|
||
|
* 1998-03-14 V 1.0.1
|
||
|
* 1999-02-03 V 1.1.0
|
||
|
* 1999-06-22 V 1.2.0 beta
|
||
|
* 1999-09-10 V 1.2.0 final
|
||
|
* 2000-03-03 V 1.3.0 beta
|
||
|
* 2000-07-15 V 1.3.0 final
|
||
|
*
|
||
|
* NOTE: Edit this file with tabstop=4 !
|
||
|
*
|
||
|
* Copyright 1996-2000 by Gerhard Buergmann
|
||
|
* Gerhard.Buergmann@altavista.net
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify it
|
||
|
* under the terms of the GNU General Public License as published by the
|
||
|
* Free Software Foundation; either version 2, or (at your option) any
|
||
|
* later version.
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful, but
|
||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
* General Public License for more details.
|
||
|
*
|
||
|
* See file COPYING for information on distribution conditions.
|
||
|
*/
|
||
|
|
||
|
#include "bvi.h"
|
||
|
#include "set.h"
|
||
|
|
||
|
#ifdef HAVE_UNISTD_H
|
||
|
# include <unistd.h>
|
||
|
#endif
|
||
|
|
||
|
#ifdef HAVE_FCNTL_H
|
||
|
# include <fcntl.h>
|
||
|
#endif
|
||
|
|
||
|
#ifdef __MSDOS__
|
||
|
# include <io.h>
|
||
|
# include <dir.h>
|
||
|
# define WRITE (O_WRONLY|O_CREAT|O_TRUNC|O_BINARY)
|
||
|
# define APPEND (O_WRONLY|O_APPEND|O_BINARY)
|
||
|
#else
|
||
|
# define WRITE (O_WRONLY|O_CREAT|O_TRUNC)
|
||
|
# define APPEND (O_WRONLY|O_APPEND)
|
||
|
#endif
|
||
|
|
||
|
#define CMDSZ 256 /* size of the command buffer */
|
||
|
#define MAXNAME 10 /* size of a : command name */
|
||
|
|
||
|
#define NO_ADDR 1
|
||
|
#define NO_ARG 8
|
||
|
#define ONE_ARG 16
|
||
|
#define MAX_ONE_ARG 32
|
||
|
#define ONE_FILE 64
|
||
|
#define MAX_ONE_FILE 128
|
||
|
|
||
|
static char *altfile = NULL; /* alternate file */
|
||
|
static struct stat buf;
|
||
|
static int c_argc = 0;
|
||
|
static char *c_argv[9];
|
||
|
|
||
|
char *nowrtmsg = "No write@since last change (:%s! overrides)";
|
||
|
char *morefiles = "more files@to edit";
|
||
|
char *ambigous = "Ambigous|Too many file names";
|
||
|
char *ambvalue = "Ambigous|Too many values";
|
||
|
char *extra = "Extra chars|Extra characters at end of command";
|
||
|
char *noaddr = "No address allowed@on this command";
|
||
|
char *noval = "No value@for binary operation";
|
||
|
int repl_count = -1;
|
||
|
int addr_flag;
|
||
|
|
||
|
PTR start_addr;
|
||
|
PTR end_addr;
|
||
|
|
||
|
extern char *name; /* actual filename */
|
||
|
extern char **files; /* used for "next" and "rewind" */
|
||
|
extern int numfiles, curfile;
|
||
|
extern int errno;
|
||
|
|
||
|
static char oldbuf[CMDSZ]; /** for :!! command **/
|
||
|
|
||
|
|
||
|
/*
|
||
|
* docmdline() - handle a colon command
|
||
|
*
|
||
|
* Handles a colon command received interactively by getcmdln() or from
|
||
|
* the environment variable "BVIINIT" (or eventually .bvirc).
|
||
|
*/
|
||
|
void
|
||
|
docmdline(cmdline)
|
||
|
char *cmdline;
|
||
|
{
|
||
|
char buff[CMDSZ];
|
||
|
char cmdbuf[CMDSZ];
|
||
|
char cmdname[MAXNAME];
|
||
|
char *cmd;
|
||
|
char *p;
|
||
|
size_t len;
|
||
|
int n, ok;
|
||
|
int force = 0;
|
||
|
int saveflag;
|
||
|
|
||
|
if (cmdline == NULL) return;
|
||
|
if (*cmdline == '"') return; /** comment **/
|
||
|
if (strlen(cmdline) > CMDSZ - 2) {
|
||
|
emsg("Command too long");
|
||
|
return;
|
||
|
}
|
||
|
strcpy(buff, cmdline);
|
||
|
cmd = buff;
|
||
|
|
||
|
/* With no address given, we start at the beginning of the file and
|
||
|
* go to the end of the file (not line like in vi).
|
||
|
*/
|
||
|
addr_flag = 0;
|
||
|
start_addr = mem;
|
||
|
end_addr = maxpos - 1;
|
||
|
SKIP_WHITE
|
||
|
if (*cmd == '%') {
|
||
|
cmd++;
|
||
|
addr_flag = 2;
|
||
|
} else {
|
||
|
if ((start_addr = calc_addr(&cmd, mem)) == NULL) {
|
||
|
return;
|
||
|
}
|
||
|
if (*cmd == ',') {
|
||
|
cmd++;
|
||
|
addr_flag = 1;
|
||
|
SKIP_WHITE
|
||
|
if ((end_addr = calc_addr(&cmd, maxpos - 1)) == NULL) {
|
||
|
return;
|
||
|
}
|
||
|
} else {
|
||
|
if (addr_flag) {
|
||
|
/* if we have only one address */
|
||
|
end_addr = start_addr;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
SKIP_WHITE
|
||
|
|
||
|
if (start_addr > (end_addr + 1)) {
|
||
|
emsg("Addr1 > addr2|First address exceeds second");
|
||
|
return;
|
||
|
}
|
||
|
if ((end_addr + 1) > maxpos) {
|
||
|
emsg("Not that many bytes@in buffer");
|
||
|
return;
|
||
|
}
|
||
|
if (start_addr < mem) {
|
||
|
sprintf(string, "Negative address@- first byte is %ld", P(P_OF));
|
||
|
emsg(string);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
SKIP_WHITE
|
||
|
|
||
|
/**** End of address range calculation ****/
|
||
|
|
||
|
if (*cmd == '\0') {
|
||
|
setpage(end_addr);
|
||
|
return;
|
||
|
}
|
||
|
strcpy(cmdbuf, cmd); /* save the unmodified command */
|
||
|
|
||
|
if (*cmd == '!') {
|
||
|
if (*(cmdbuf + 1) == '\0') {
|
||
|
emsg("Incomplete shell escape command@- use 'shell' to get a shell");
|
||
|
return;
|
||
|
}
|
||
|
if (*(cmdbuf + 1) == '!') {
|
||
|
if (oldbuf[0] != '\0') {
|
||
|
strcpy(cmdbuf + 1, oldbuf);
|
||
|
msg(oldbuf);
|
||
|
} else {
|
||
|
emsg("No previous command@to substitute for !");
|
||
|
return;
|
||
|
}
|
||
|
} else sprintf(oldbuf, "\n%s\n", cmdbuf + 1);
|
||
|
|
||
|
if (P(P_AW)) {
|
||
|
save(name, mem, maxpos, WRITE);
|
||
|
edits = 0;
|
||
|
}
|
||
|
if (edits) msg("[No write]|[No write since last change]");
|
||
|
savetty();
|
||
|
endwin();
|
||
|
system(cmdbuf + 1);
|
||
|
fprintf(stderr, "[Hit return to continue]");
|
||
|
getchar();
|
||
|
doupdate();
|
||
|
repaint();
|
||
|
clearstr();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
n = 0;
|
||
|
while (*cmd >= 'a' && *cmd <= 'z') {
|
||
|
cmdname[n++] = *cmd++;
|
||
|
if (n == MAXNAME) {
|
||
|
sprintf(string, "What?|%s: Not an editor command", cmdbuf);
|
||
|
emsg(string);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
cmdname[n] = '\0';
|
||
|
if (*cmd == '!') {
|
||
|
force = 1;
|
||
|
cmd++;
|
||
|
}
|
||
|
len = strlen(cmdname);
|
||
|
SKIP_WHITE
|
||
|
|
||
|
if (!strncmp("substitute", cmdname, len) && CMDLNG(10,1)) {
|
||
|
repl_count = do_substitution(*cmd, cmd + 1, start_addr, end_addr);
|
||
|
if (repl_count == -1) {
|
||
|
emsg("No previous substitute re|No previous substitute regular expression");
|
||
|
return; /* No prev subst */
|
||
|
}
|
||
|
repaint();
|
||
|
if (!repl_count) {
|
||
|
emsg("Fail|Substitute pattern matching failed");
|
||
|
} else if (repl_count > 1) {
|
||
|
sprintf(string, "%d subs|%d substitutions", repl_count, repl_count);
|
||
|
msg(string);
|
||
|
}
|
||
|
return;
|
||
|
} else if (!strncmp("global", cmdname, len) && CMDLNG(6,1)) {
|
||
|
current = start_addr - 1;
|
||
|
repl_count = 0;
|
||
|
addch('\n');
|
||
|
while ((current = searching(*cmd, cmd + 1, current,
|
||
|
end_addr, FALSE|S_GLOBAL)) != 0L) {
|
||
|
addch('\n');
|
||
|
printline(current, maxy - 1);
|
||
|
repl_count++;
|
||
|
if (repl_count == LINES - 2) {
|
||
|
if (wait_return(FALSE)) return;
|
||
|
repl_count = 0;
|
||
|
}
|
||
|
}
|
||
|
if (repl_count) {
|
||
|
wait_return(TRUE);
|
||
|
} else {
|
||
|
repaint();
|
||
|
emsg(notfound);
|
||
|
}
|
||
|
return;
|
||
|
} else if (cmdname[0] == 't') {
|
||
|
if (!addr_flag) start_addr = current;
|
||
|
cmd = cmdname + 1L;
|
||
|
SKIP_WHITE
|
||
|
do_mark(*cmd, start_addr);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ((!strncmp("write", cmdname, len) && CMDLNG(5,1)) || !strcmp("wq", cmdname)) {
|
||
|
if (*cmd == '>') {
|
||
|
if (*(++cmd) == '>') {
|
||
|
cmd++;
|
||
|
saveflag = APPEND;
|
||
|
} else {
|
||
|
emsg("Write forms are 'w' and 'w>>'");
|
||
|
return;
|
||
|
}
|
||
|
} else if (*cmd == '!') {
|
||
|
emsg("Not yet implemented");
|
||
|
return;
|
||
|
} else {
|
||
|
saveflag = WRITE;
|
||
|
}
|
||
|
SKIP_WHITE
|
||
|
|
||
|
c_argc = 0;
|
||
|
if ((c_argv[c_argc] = strtok(cmd, " \t")) != NULL) c_argc++;
|
||
|
while ((c_argv[c_argc] = strtok(NULL, " \t")) != NULL) c_argc++;
|
||
|
|
||
|
if (c_argc > 1) {
|
||
|
emsg(ambigous);
|
||
|
return; }
|
||
|
if (c_argc == 1) {
|
||
|
/* change '%' to Filename */
|
||
|
while ((p = strchr(c_argv[0], '%')) != NULL && *(p-1) != '\\') {
|
||
|
if (name == NULL) {
|
||
|
emsg("No filename@to substitute for %");
|
||
|
return;
|
||
|
}
|
||
|
*p = '\0';
|
||
|
strcpy (oldbuf, c_argv[0]);
|
||
|
strcat (oldbuf, name);
|
||
|
strcat (oldbuf, p + 1);
|
||
|
c_argv[0] = oldbuf;
|
||
|
}
|
||
|
}
|
||
|
if (name == NULL && c_argc != 0) name = strdup(c_argv[0]);
|
||
|
if (force) {
|
||
|
if (c_argc == 0) ok = save(name, start_addr, end_addr, saveflag);
|
||
|
else ok = save(c_argv[0], start_addr, end_addr, saveflag);
|
||
|
} else {
|
||
|
if (c_argc == 0) {
|
||
|
if (P(P_RO)) {
|
||
|
sprintf(string, "\"%s\" File is read only", name);
|
||
|
emsg(string);
|
||
|
return;
|
||
|
} else ok = save(name, start_addr, end_addr, saveflag);
|
||
|
} else {
|
||
|
if (!stat(c_argv[0], &buf)) {
|
||
|
if (saveflag == WRITE) {
|
||
|
sprintf(string, "File exists@- use \"%s! %s\" to overwrite", cmdname, c_argv[0]);
|
||
|
emsg(string);
|
||
|
return;
|
||
|
} else { /* APPEND */
|
||
|
/* We can only append to a regular file! */
|
||
|
if (S_ISREG(buf.st_mode)) {
|
||
|
if (filemode == PARTIAL) filemode = REGULAR;
|
||
|
} else if (S_ISBLK(buf.st_mode)) {
|
||
|
emsg("Cannot append to a block special file");
|
||
|
return;
|
||
|
}
|
||
|
ok = save(c_argv[0], start_addr, end_addr, saveflag);
|
||
|
}
|
||
|
} else {
|
||
|
if (saveflag == APPEND) {
|
||
|
emsg("No such file");
|
||
|
return;
|
||
|
} else { /* WRITE */
|
||
|
/* If we write the block of a partial file to a new file, it will
|
||
|
* become a regular file!
|
||
|
*/
|
||
|
if (filemode == PARTIAL) filemode = REGULAR;
|
||
|
ok = save(c_argv[0], start_addr, end_addr, saveflag);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (!strcmp("wq", cmdname)) {
|
||
|
if (ok) quit();
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
c_argc = 0;
|
||
|
cmd = strtok(cmdbuf, " \t");
|
||
|
while ((c_argv[c_argc] = strtok(NULL, " \t")) != NULL) c_argc++;
|
||
|
|
||
|
if (!strncmp("set", cmdname, len) && CMDLNG(3, 2)) {
|
||
|
if (chk_comm(NO_ADDR)) return;
|
||
|
if (c_argc == 0) {
|
||
|
doset(NULL);
|
||
|
} else {
|
||
|
for (n = 0; n < c_argc; n++) {
|
||
|
if (doset(c_argv[n])) return;
|
||
|
}
|
||
|
}
|
||
|
} else if (!strncmp("args", cmdname, len) && CMDLNG(4, 2)) {
|
||
|
if (chk_comm(NO_ADDR|NO_ARG)) return;
|
||
|
string[0] = '\0';
|
||
|
for (n = 0; n < numfiles; n++) {
|
||
|
if (n == curfile) strcat(string, "[");
|
||
|
strcat(string, files[n]);
|
||
|
if (n == curfile) strcat(string, "]");
|
||
|
strcat(string, " ");
|
||
|
}
|
||
|
msg(string);
|
||
|
} else if (!strncmp("source", cmdname, len) && CMDLNG(6, 2)) {
|
||
|
if (chk_comm(NO_ADDR|ONE_FILE)) return;
|
||
|
if (read_rc(c_argv[0])) sysemsg(c_argv[0]);
|
||
|
refresh();
|
||
|
} else if (!strncmp("cd", cmdname, len) && CMDLNG(2, 2)) {
|
||
|
if (chk_comm(NO_ADDR|ONE_FILE)) return;
|
||
|
if (!force) {
|
||
|
if (edits) {
|
||
|
if (P(P_AW)) {
|
||
|
save(name, mem, maxpos, WRITE);
|
||
|
edits = 0;
|
||
|
} else {
|
||
|
sprintf(string, nowrtmsg, "cd");
|
||
|
emsg(string);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (c_argc == 0) {
|
||
|
sprintf(string, "%c", DELIM);
|
||
|
c_argv[0] = string;
|
||
|
}
|
||
|
if (chdir(c_argv[0])) sysemsg(c_argv[0]);
|
||
|
} else if (!strncmp("edit", cmdname, len) && CMDLNG(4, 1)) {
|
||
|
/*
|
||
|
* The command ":e#" gets expanded to something like ":efile", so
|
||
|
* detect that case here.
|
||
|
*/
|
||
|
if (*cmd == 'e' && c_argc == 0) {
|
||
|
if (cmd[1] == '!')
|
||
|
(void) doecmd(&cmd[2], TRUE);
|
||
|
else
|
||
|
(void) doecmd(&cmd[1], FALSE);
|
||
|
return;
|
||
|
}
|
||
|
if (chk_comm(NO_ADDR|MAX_ONE_FILE)) return;
|
||
|
doecmd(c_argv[0], force);
|
||
|
} else if (!strncmp("file", cmdname, len) && CMDLNG(4, 1)) {
|
||
|
if (chk_comm(NO_ADDR|MAX_ONE_FILE)) return;
|
||
|
if (c_argc != 0) name = strdup(c_argv[0]);
|
||
|
fileinfo(name);
|
||
|
} else if (!strncmp("read", cmdname, len) && CMDLNG(4, 1)) {
|
||
|
if (chk_comm(NO_ADDR|MAX_ONE_FILE)) return;
|
||
|
/* read reads a file at EOF */
|
||
|
if (c_argc == 0) c_argv[0] = name;
|
||
|
if (!addfile(c_argv[0])) {
|
||
|
edits = U_TRUNC;
|
||
|
undosize = filesize;
|
||
|
repaint();
|
||
|
}
|
||
|
} else if (!strncmp("xit", cmdname, len) && CMDLNG(3, 1)) {
|
||
|
if (chk_comm(NO_ADDR|NO_ARG)) return;
|
||
|
do_exit();
|
||
|
} else if (!strncmp("next", cmdname, len) && CMDLNG(4, 1)) {
|
||
|
if (chk_comm(NO_ADDR|NO_ARG)) return;
|
||
|
if (!force) {
|
||
|
if (edits) {
|
||
|
if (P(P_AW)) {
|
||
|
save(name, mem, maxpos, WRITE);
|
||
|
edits = 0;
|
||
|
} else {
|
||
|
sprintf(string, nowrtmsg, "next");
|
||
|
emsg(string);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if ((curfile + 1) < numfiles) {
|
||
|
if (force) stuffin(":e! ");
|
||
|
else stuffin(":e ");
|
||
|
stuffin(files[++curfile]);
|
||
|
stuffin("\n");
|
||
|
} else
|
||
|
emsg("No more files@to edit!");
|
||
|
} else if (!strncmp("rewind", cmdname, len) && CMDLNG(6, 3)) {
|
||
|
if (chk_comm(NO_ADDR|NO_ARG)) return;
|
||
|
if (numfiles <= 1) /* nothing to rewind */
|
||
|
return;
|
||
|
if (!force) {
|
||
|
if (edits) {
|
||
|
if (P(P_AW)) {
|
||
|
save(name, mem, maxpos, WRITE);
|
||
|
edits = 0;
|
||
|
} else {
|
||
|
sprintf(string, nowrtmsg, "rewind");
|
||
|
emsg(string);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
curfile = 0;
|
||
|
if (force) stuffin(":e! ");
|
||
|
else stuffin(":e ");
|
||
|
stuffin(files[0]);
|
||
|
stuffin("\n");
|
||
|
} else if (!strncmp("append", cmdname, len) && CMDLNG(6, 1)) {
|
||
|
if (chk_comm(NO_ADDR|MAX_ONE_ARG)) return;
|
||
|
do_ins_chg(start_addr, c_argc == 1 ? c_argv[0] : "a", U_APPEND);
|
||
|
} else if (!strncmp("change", cmdname, len) && CMDLNG(6, 1)) {
|
||
|
if (chk_comm(MAX_ONE_ARG)) return;
|
||
|
if (!addr_flag) start_addr = current;
|
||
|
do_ins_chg(start_addr, c_argc == 1 ? c_argv[0] : "a", U_EDIT);
|
||
|
} else if (!strncmp("mark", cmdname, len) && CMDLNG(4, 2)) {
|
||
|
if (c_argc == 0) { emsg("Mark what?"); return; }
|
||
|
if (c_argc > 1 || (strlen(c_argv[0]) > 1)) { emsg(extra); return; }
|
||
|
if (!addr_flag) start_addr = current;
|
||
|
do_mark(c_argv[0][0], start_addr);
|
||
|
} else if (!strncmp("yank", cmdname, len) && CMDLNG(4, 1)) {
|
||
|
if ((yanked = yd_addr()) == 0L) return;
|
||
|
if ((yanked = alloc_buf(yanked, &yank_buf)) == 0L) return;
|
||
|
memcpy(yank_buf, start_addr, yanked);
|
||
|
sprintf(string, "%lu bytes", (long)yanked);
|
||
|
msg(string);
|
||
|
} else if (!strncmp("overwrite", cmdname, len) && CMDLNG(9, 1)) {
|
||
|
if (chk_comm(NO_ARG)) return;
|
||
|
if (!addr_flag) start_addr = current;
|
||
|
do_over(start_addr, yanked, yank_buf);
|
||
|
} else if (!strncmp("undo", cmdname, len) && CMDLNG(4, 1)) {
|
||
|
if (chk_comm(NO_ADDR|NO_ARG)) return;
|
||
|
do_undo();
|
||
|
} else if (!strncmp("version", cmdname, len) && CMDLNG(7, 2)) {
|
||
|
if (chk_comm(NO_ADDR|NO_ARG)) return;
|
||
|
sprintf(string, "bvi version %s %s", VERSION, copyright);
|
||
|
msg(string);
|
||
|
} else if (!strncmp("shell", cmdname, len) && CMDLNG(5, 2)) {
|
||
|
if (chk_comm(NO_ADDR|NO_ARG)) return;
|
||
|
do_shell();
|
||
|
clear();
|
||
|
repaint();
|
||
|
clearstr();
|
||
|
} else if (!strncmp("quit", cmdname, len) && CMDLNG(4, 1)) {
|
||
|
if (chk_comm(NO_ADDR|NO_ARG)) return;
|
||
|
if (!force) {
|
||
|
if (edits) {
|
||
|
sprintf(string, nowrtmsg, "quit");
|
||
|
emsg(string);
|
||
|
} else {
|
||
|
if ((curfile + 1) < numfiles) {
|
||
|
sprintf(string, "%d %s", numfiles - curfile - 1, morefiles);
|
||
|
emsg(string);
|
||
|
} else
|
||
|
quit();
|
||
|
}
|
||
|
} else quit();
|
||
|
} else if (!strncmp("sleft", cmdname, len) && CMDLNG(5, 2)) {
|
||
|
if (c_argc == 1) {
|
||
|
do_logic(LSHIFT, c_argv[0]);
|
||
|
} else if (c_argc == 0) {
|
||
|
do_logic(LSHIFT, "1");
|
||
|
} else { emsg(ambvalue); return; }
|
||
|
} else if (!strncmp("sright", cmdname, len) && CMDLNG(6, 2)) {
|
||
|
if (c_argc == 1) {
|
||
|
do_logic(RSHIFT, c_argv[0]);
|
||
|
} else if (c_argc == 0) {
|
||
|
do_logic(RSHIFT, "1");
|
||
|
} else { emsg(ambvalue); return; }
|
||
|
} else if (!strncmp("rleft", cmdname, len) && CMDLNG(5, 2)) {
|
||
|
if (c_argc == 1) {
|
||
|
do_logic(LROTATE, c_argv[0]);
|
||
|
} else if (c_argc == 0) {
|
||
|
do_logic(LROTATE, "1");
|
||
|
} else { emsg(ambvalue); return; }
|
||
|
} else if (!strncmp("rright", cmdname, len) && CMDLNG(6, 2)) {
|
||
|
if (c_argc == 1) {
|
||
|
do_logic(RROTATE, c_argv[0]);
|
||
|
} else if (c_argc == 0) {
|
||
|
do_logic(RROTATE, "1");
|
||
|
} else { emsg(ambvalue); return; }
|
||
|
} else if (!strcmp("and", cmdname)) {
|
||
|
if (c_argc == 1) {
|
||
|
do_logic(AND, c_argv[0]);
|
||
|
} else if (c_argc == 0) {
|
||
|
emsg(noval); return;
|
||
|
} else { emsg(ambvalue); return; }
|
||
|
} else if (!strcmp("or", cmdname)) {
|
||
|
if (c_argc == 1) {
|
||
|
do_logic(OR, c_argv[0]);
|
||
|
} else if (c_argc == 0) {
|
||
|
emsg(noval); return;
|
||
|
} else { emsg(ambvalue); return; }
|
||
|
} else if (!strcmp("xor", cmdname)) {
|
||
|
if (c_argc == 1) {
|
||
|
do_logic(XOR, c_argv[0]);
|
||
|
} else if (c_argc == 0) {
|
||
|
emsg(noval); return;
|
||
|
} else { emsg(ambvalue); return; }
|
||
|
} else if (!strcmp("neg", cmdname)) {
|
||
|
if (c_argc != 0) { emsg(extra); return; }
|
||
|
do_logic(NEG, "255");
|
||
|
} else if (!strcmp("not", cmdname)) {
|
||
|
if (c_argc != 0) { emsg(extra); return; }
|
||
|
do_logic(NOT, "255");
|
||
|
} else {
|
||
|
sprintf(string, "What?|%s: Not an editor command", cmd);
|
||
|
if P(P_MM) {
|
||
|
if (!strncmp("delete", cmdname, len) && CMDLNG(6, 1)) {
|
||
|
if ((undo_count = yd_addr()) == 0L) return;
|
||
|
do_delete(undo_count, start_addr);
|
||
|
sprintf(string, "%lu bytes", (long)undo_count);
|
||
|
msg(string);
|
||
|
} else if (!strncmp("insert", cmdname, len) && CMDLNG(6, 1)) {
|
||
|
if (chk_comm(MAX_ONE_ARG)) return;
|
||
|
if (!addr_flag) start_addr = current;
|
||
|
do_ins_chg(start_addr - 1, c_argc == 1 ? c_argv[0] : "a", U_INSERT);
|
||
|
} else if (!strncmp("put", cmdname, len) && CMDLNG(3, 2)) {
|
||
|
if (chk_comm(NO_ARG)) return;
|
||
|
if (!addr_flag) start_addr = current;
|
||
|
do_put(start_addr, yanked, yank_buf);
|
||
|
} else {
|
||
|
emsg(string);
|
||
|
}
|
||
|
} else {
|
||
|
if (!strncmp("delete", cmdname, len) && CMDLNG(6, 1)) {
|
||
|
movebyte();
|
||
|
} else if (!strncmp("insert", cmdname, len) && CMDLNG(6, 1)) {
|
||
|
movebyte();
|
||
|
} else if (!strncmp("put", cmdname, len) && CMDLNG(3, 2)) {
|
||
|
movebyte();
|
||
|
} else {
|
||
|
emsg(string);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* calculate address range for :yank and :delete command */
|
||
|
off_t
|
||
|
yd_addr()
|
||
|
{
|
||
|
off_t count = 0;
|
||
|
|
||
|
if (c_argc == 0) {
|
||
|
switch (addr_flag) {
|
||
|
case 0: start_addr = current;
|
||
|
case 1: count = 1;
|
||
|
break;
|
||
|
case 2: count = end_addr - start_addr + 1;
|
||
|
break;
|
||
|
}
|
||
|
} else if (c_argc == 1) {
|
||
|
count = atoi(c_argv[0]);
|
||
|
switch (addr_flag) {
|
||
|
case 0: start_addr = current;
|
||
|
case 1: end_addr = start_addr + count - 1;
|
||
|
break;
|
||
|
case 2: start_addr = end_addr;
|
||
|
end_addr = start_addr + count - 1;
|
||
|
break;
|
||
|
}
|
||
|
} else {
|
||
|
emsg(ambvalue);
|
||
|
return 0;
|
||
|
}
|
||
|
return count;
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
do_exit()
|
||
|
{
|
||
|
if (edits) {
|
||
|
if (!save(name, mem, maxpos - 1L, WRITE)) return;
|
||
|
}
|
||
|
if ((curfile + 1) < numfiles) {
|
||
|
sprintf(string, "%d %s", numfiles - curfile - 1, morefiles);
|
||
|
emsg(string);
|
||
|
} else quit();
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
doecmd(arg, force)
|
||
|
char *arg;
|
||
|
int force;
|
||
|
{
|
||
|
char *tmp;
|
||
|
|
||
|
if (*arg == '\0') arg = NULL;
|
||
|
if (!force && edits) {
|
||
|
sprintf(string, nowrtmsg, "edit");
|
||
|
emsg(string);
|
||
|
/*
|
||
|
if (altfile)
|
||
|
free(altfile);
|
||
|
altfile = strdup(arg);
|
||
|
*/
|
||
|
return FALSE;
|
||
|
}
|
||
|
if (arg != NULL) {
|
||
|
if (name != NULL && !strcmp(arg, name)) {
|
||
|
if (!edits || (edits && !force))
|
||
|
return TRUE;
|
||
|
}
|
||
|
if (name != NULL && !strcmp(arg, "#")) {
|
||
|
if (altfile == NULL) {
|
||
|
emsg("No alternate filename@to substitute for #");
|
||
|
return FALSE;
|
||
|
}
|
||
|
tmp = name;
|
||
|
name = altfile;
|
||
|
altfile = tmp;
|
||
|
} else {
|
||
|
if (altfile) {
|
||
|
free(altfile);
|
||
|
}
|
||
|
altfile = name;
|
||
|
name = strdup(arg);
|
||
|
}
|
||
|
}
|
||
|
if (name == NULL) {
|
||
|
emsg("No file|No current filename");
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
edits = 0;
|
||
|
filesize = load(name);
|
||
|
if (arg == NULL) {
|
||
|
setpage(current < maxpos ? current : maxpos - 1L);
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
clearstr()
|
||
|
{
|
||
|
int n;
|
||
|
|
||
|
move(maxy, 0);
|
||
|
for (n = 0; n < maxx; n++) addch(' ');
|
||
|
move(maxy, 0);
|
||
|
}
|
||
|
|
||
|
|
||
|
/**** displays an error message *****/
|
||
|
void
|
||
|
emsg(s)
|
||
|
char *s;
|
||
|
{
|
||
|
int cnt;
|
||
|
|
||
|
if (P(P_EB)) beep();
|
||
|
clearstr();
|
||
|
attrset(A_REVERSE);
|
||
|
cnt = outmsg(s);
|
||
|
attrset(A_NORMAL);
|
||
|
if (cnt >= (maxx - 25)) { /* 25 = status */
|
||
|
addch('\n');
|
||
|
wait_return(TRUE); }
|
||
|
}
|
||
|
|
||
|
|
||
|
/*** System error message *****/
|
||
|
void
|
||
|
sysemsg(s)
|
||
|
char *s;
|
||
|
{
|
||
|
char string[256];
|
||
|
|
||
|
sprintf(string, "%s: %s", s, sys_errlist[errno]);
|
||
|
emsg(string);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*** displays mode if showmode set *****/
|
||
|
void
|
||
|
smsg(s)
|
||
|
char *s;
|
||
|
{
|
||
|
if (P(P_MO)) {
|
||
|
msg(s);
|
||
|
setcur();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/************* displays s on status line *****************/
|
||
|
void
|
||
|
msg(s)
|
||
|
char *s;
|
||
|
{
|
||
|
clearstr();
|
||
|
if (outmsg(s) >= (maxx - 25)) { /* 25 = status */
|
||
|
addch('\n');
|
||
|
wait_return(TRUE); }
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
outmsg(s)
|
||
|
char *s;
|
||
|
{
|
||
|
char *poi;
|
||
|
int cnt = 0;
|
||
|
|
||
|
move(maxy, 0);
|
||
|
poi = strchr(s, '|');
|
||
|
|
||
|
if (P(P_TE)) {
|
||
|
poi = s;
|
||
|
while (*poi != '\0' && *poi != '@' && *poi != '|') {
|
||
|
addch(*poi++);
|
||
|
cnt++; }
|
||
|
} else {
|
||
|
if (poi) poi++;
|
||
|
else poi = s;
|
||
|
while (*poi) {
|
||
|
if (*poi == '@') addch(' ');
|
||
|
else addch(*poi);
|
||
|
poi++;
|
||
|
cnt++;
|
||
|
}
|
||
|
}
|
||
|
return cnt;
|
||
|
}
|
||
|
|
||
|
/* If flag == TRUE we do a repaint
|
||
|
*
|
||
|
*/
|
||
|
int
|
||
|
wait_return(flag)
|
||
|
int flag;
|
||
|
{
|
||
|
int c;
|
||
|
|
||
|
signal(SIGINT, jmpproc);
|
||
|
clearstr();
|
||
|
attrset(A_REVERSE);
|
||
|
mvaddstr(maxy, 0, "[Hit return to continue]");
|
||
|
attrset(A_NORMAL);
|
||
|
refresh();
|
||
|
c = getch();
|
||
|
if (flag) {
|
||
|
clear();
|
||
|
repaint();
|
||
|
}
|
||
|
clearstr();
|
||
|
signal(SIGINT, SIG_IGN);
|
||
|
if (c != CR && c != NL && c != ' ' && c != ':' && c != KEY_ENTER) return 1;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
chk_comm(flag)
|
||
|
int flag;
|
||
|
{
|
||
|
if ((flag & NO_ADDR) && (addr_flag > 0)) {
|
||
|
emsg(noaddr); return 1; }
|
||
|
if ((flag & NO_ARG) && (c_argc > 0)) {
|
||
|
emsg(extra); return 1; }
|
||
|
if ((flag & MAX_ONE_ARG) && (c_argc > 1)) {
|
||
|
emsg(ambvalue); return 1; }
|
||
|
if ((flag & ONE_FILE) && (c_argc == 0)) {
|
||
|
emsg("Missing filename"); return 1; }
|
||
|
if ((flag & MAX_ONE_FILE) && (c_argc > 1)) {
|
||
|
emsg(ambigous); return 1; }
|
||
|
return 0;
|
||
|
}
|