/* 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
 * 2001-10-10 V 1.3.1  
 * 2003-07-04 V 1.3.2
 * 2005-08-17 V 1.3.3
 * 2010-06-02 V 1.3.4
 * 2014-01-28 V 1.4.0
 *
 * NOTE: Edit this file with tabstop=4 !
 *
 * Copyright 1996-2014 by Gerhard Buergmann
 * gerhard@puon.at
 *
 * 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

#if defined(__MSDOS__) && !defined(DJGPP)
#   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, ret;
	int		force = 0;
	int		saveflag;

	if (*cmdline == '\0') 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 %lld", (long long)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();
		ret = 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) {
				save_chk(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;
}


/*********** Save file if not read only ********************/
int
save_chk(fname, start, end, flags)
   char    *fname;
   char    *start;
   char    *end;
   int     flags;
{
   if (P(P_RO)) {
       sprintf(string, "\"%s\" File is read only", name);
       emsg(string);
       return FALSE;
   }
   return save(fname, start, end, flags);
}

void
do_exit()
{
	if (edits) {
		if (!save_chk(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;
	int stchar;

	if (P(P_EB)) beep();
	if (P(P_MO)) {
		stchar = statsize;
	} else {
		stchar = 0;
	}

	clearstr();
	attrset(A_REVERSE);
	cnt = outmsg(s);
	attrset(A_NORMAL);
	if (cnt >= (maxx - stchar)) {
		addch('\n');
		wait_return(TRUE); }
}


/*** System error message *****/
void
sysemsg(s)
	char	*s;
{
	char	string[256];

#ifdef HAVE_STRERROR
	sprintf(string, "%s: %s", s, strerror(errno));
#else
	sprintf(string, "%s: %s", s, sys_errlist[errno]);
#endif

	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;
{
	int stchar;

	if (P(P_MO)) {
		stchar = statsize;
	} else {
		stchar = 0;
	}
	clearstr();
	if (outmsg(s) >= (maxx - stchar)) {
		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;
}
