home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
rtsi.com
/
2014.01.www.rtsi.com.tar
/
www.rtsi.com
/
OS9
/
OSK
/
CMDS
/
pvic_10a.lzh
/
SRCE
/
cmdline.c
< prev
next >
Wrap
Text File
|
1998-06-09
|
13KB
|
686 lines
/*
*
* Routines to parse and execute "command line" commands, such as searches
* or colon commands.
*/
#include <stdio.h>
#include "pvic.h"
#include "locdefs.h"
static char *altfile = NULL; /* alternate file */
static int altline; /* line # in alternate file */
static char *nowrtmsg = "No write since last change (use '!' to override)";
static char *nooutfile = "No output file";
static char *morefiles = "More files to edit";
extern char **files; /* used for "n" and "rew" */
extern int number_of_files, current_file;
#define CMDSZ 100 /* size of the command buffer */
static void get_range();
static LPTR *get_line();
void do_exit();
/*
* getcmdln() - read a command line from the terminal
*
* Reads a command line started by typing '/', '?', '!', or ':'. Returns a
* pointer to the string that was read. For searches, an optional trailing
* '/' or '?' is removed.
*/
char *getcmdln(firstc)
char firstc;
{
static char buff[CMDSZ];
register char *p = buff;
register int c;
register char *q;
update_screen(1);
goto_command((1), firstc);
/* collect the command string, handling '\b' and @ */
do {
switch (c = get_char_from_input_buffer()) {
default: /* a normal character */
putc(c,stdout);
*p++ = c;
break;
case CTRL_H:
if (p > buff) {
/*
* this is gross, but it relies
* only on 'goto_command'
*/
p--;
goto_command((1), firstc);
for (q = buff; q < p ;q++)
putc(*q,stdout);
} else {
msg("");
return NULL; /* back to cmd mode */
}
break;
case '@': /* line kill */
p = buff;
goto_command((1), firstc);
break;
case ESC: /* abandon command */
msg("");
return NULL;
case CTRL_J: /* done reading the line */
case CTRL_M:
break;
}
} while (c != CTRL_J && c != CTRL_M);
*p = '\0';
if (firstc == '/' || firstc == '?') { /* did we do a search? */
/*
* Look for a terminating '/' or '?'. This will be the first
* one that isn't quoted. Truncate the search string there.
*/
for (p = buff; *p ;) {
if (*p == firstc) { /* we're done */
*p = '\0';
break;
} else if (*p == '\\') /* next char quoted */
p += 2;
else
p++; /* normal char */
}
}
return buff;
}
/*
* do_command_line() - handle a colon command
*
* Handles a colon command received interactively by getcmdln() or from
* the environment variable "EXINIT" (or eventually .virc).
*/
void do_command_line(cmdline)
char *cmdline;
{
char buff[CMDSZ];
char cmdbuf[CMDSZ];
char argbuf[CMDSZ];
char *cmd, *arg;
register char *p;
/*
* The next two variables contain the bounds of any range given in a
* command. If no range was given, both contain null line pointers.
* If only a single line was given, u_pos will contain a null line
* pointer.
*/
LPTR l_pos, u_pos;
/*
* Clear the range variables.
*/
l_pos.linep = (struct line *) NULL;
u_pos.linep = (struct line *) NULL;
if (cmdline == NULL)
return;
if (strlen(cmdline) > CMDSZ-2) {
msg("Command line too long");
return;
}
strcpy(buff, cmdline);
/* skip any initial white space */
for (cmd = buff; *cmd != '\0' && is_space(*cmd) ;cmd++)
;
if (*cmd == '%') { /* change '%' to "1,$" */
strcpy(cmdbuf, "1,$"); /* kind of gross... */
strcat(cmdbuf, cmd+1);
strcpy(cmd, cmdbuf);
}
while ((p=get_pointer_to_chr_in_string(cmd, '%')) != NULL
&& *(p-1) != '\\')
{
/*
change '%' to file_name
*/
if (file_name == NULL) {
error_message("No filename");
return;
}
*p= '\0';
strcpy (cmdbuf, cmd);
strcat (cmdbuf, file_name);
strcat (cmdbuf, p+1);
strcpy(cmd, cmdbuf);
msg(cmd); /*repeat */
}
while ((p=get_pointer_to_chr_in_string(cmd, '#')) != NULL
&& *(p-1) != '\\')
{
/*
change '#' to Altname
*/
if (altfile == NULL) {
error_message("No alternate file");
return;
}
*p= '\0';
strcpy (cmdbuf, cmd);
strcat (cmdbuf, altfile);
strcat (cmdbuf, p+1);
strcpy(cmd, cmdbuf);
msg(cmd); /*repeat */
}
/*
* Parse a range, if present (and update the cmd pointer).
*/
get_range(&cmd, &l_pos, &u_pos);
if (l_pos.linep != NULL)
{
if (LINEOF(&l_pos) > LINEOF(&u_pos))
{
error_message("Invalid range");
return;
}
}
strcpy(cmdbuf, cmd); /* save the unmodified command */
/*
isolate the command and find any argument
*/
for ( p=cmd; *p != '\0' && ! is_space(*p); p++ )
;
if ( *p == '\0' )
arg = NULL;
else
{
*p = '\0';
for (p++; *p != '\0' && is_space(*p) ;p++)
;
if (*p == '\0')
arg = NULL;
else
{
strcpy(argbuf, p);
arg = argbuf;
}
}
if (strcmp(cmd,"q!") == 0)
get_out();
if (strcmp(cmd,"q") == 0)
{
if (changed)
error_message(nowrtmsg);
else
{
if ((current_file + 1) < number_of_files)
error_message(morefiles);
else
get_out();
}
return;
}
if (strcmp(cmd,"w") == 0)
{
if (arg == NULL)
{
if (file_name != NULL)
{
write_it(file_name, &l_pos, &u_pos);
}
else
error_message(nooutfile);
}
else
write_it(arg, &l_pos, &u_pos);
return;
}
if (strcmp(cmd,"wq") == 0)
{
if (file_name != NULL)
{
if (write_it(file_name, (LPTR *)NULL, (LPTR *)NULL))
get_out();
}
else
error_message(nooutfile);
return;
}
if (strcmp(cmd, "x") == 0) {
do_exit();
return;
}
if (strcmp(cmd,"f") == 0 && arg == NULL) {
file_info();
return;
}
if (*cmd == 'n') {
if ((current_file + 1) < number_of_files) {
/*
* stuff ":e[!] FILE\n"
*/
put_string_into_input_buffer(":e");
if (cmd[1] == '!')
put_string_into_input_buffer("!");
put_string_into_input_buffer(" ");
put_string_into_input_buffer(files[++current_file]);
put_string_into_input_buffer("\n");
} else
error_message("No more files");
return;
}
if (*cmd == 'N') {
if (current_file > 0) {
/*
* stuff ":e[!] FILE\n"
*/
put_string_into_input_buffer(":e");
if (cmd[1] == '!')
put_string_into_input_buffer("!");
put_string_into_input_buffer(" ");
put_string_into_input_buffer(files[--current_file]);
put_string_into_input_buffer("\n");
} else
error_message("No more files");
return;
}
if (strncmp(cmd, "rew", 3) == 0) {
if (number_of_files <= 1) /* nothing to rewind */
return;
current_file = 0;
/*
* stuff ":e[!] FILE\n"
*/
put_string_into_input_buffer(":e");
if (cmd[3] == '!')
put_string_into_input_buffer("!");
put_string_into_input_buffer(" ");
put_string_into_input_buffer(files[0]);
put_string_into_input_buffer("\n");
return;
}
if (strcmp(cmd,"e") == 0 || strcmp(cmd,"e!") == 0) {
(void) do_e_command(arg, cmd[1] == '!');
return;
}
/*
* The command ":e#" gets expanded to something like ":efile", so
* detect that case here.
*/
if (*cmd == 'e' && arg == NULL) {
if (cmd[1] == '!')
(void) do_e_command(&cmd[2], (1));
else
(void) do_e_command(&cmd[1], (0));
return;
}
if (strcmp(cmd,"f") == 0) {
eval_environment (arg, CMDSZ); /* expand environment vars */
file_name = strsave(arg);
file_message("");
return;
}
if (strcmp(cmd,"r") == 0) {
if (arg == NULL) {
bad_command();
return;
}
if (read_file(arg, cursor_char, 1)) {
error_message("Can't open file");
return;
}
update_screen(1);
CHANGED;
return;
}
if (strcmp(cmd,"=") == 0) {
show_message("%d", cntllines(file_memory, &l_pos));
return;
}
if (strncmp(cmd,"set", 2) == 0) {
do_set(arg);
return;
}
if (strcmp(cmd,"help") == 0) {
if(help()==0)
{
clear_screen();
update_screen(0);
}
else error_message("No help available");
return;
}
if (strncmp(cmd, "ve", 2) == 0) {
msg(VERSION_STRING);
return;
}
if (strcmp(cmd, "sh") == 0) {
do_shell(NULL);
return;
}
if (*cmd == '!') {
do_shell(cmdbuf+1);
return;
}
if (strncmp(cmd, "s/", 2) == 0) {
do_sub(&l_pos, &u_pos, cmdbuf+1);
return;
}
if (strncmp(cmd, "g/", 2) == 0) {
do_glob(&l_pos, &u_pos, cmdbuf+1);
return;
}
if (strcmp(cmd, "j") == 0) {
do_join(1);
update_screen(0);
return;
}
/*
* If we got a line, but no command, then go to the line.
*/
if (*cmd == '\0' && l_pos.linep != NULL) {
*cursor_char = l_pos;
return;
}
bad_command();
}
void do_exit() /* v1.1 */
{
if (changed) {
if (file_name != NULL) {
if (!write_it(file_name, (LPTR *)NULL, (LPTR *)NULL))
return;
} else {
error_message(nooutfile);
return;
}
}
if ((current_file + 1) < number_of_files)
error_message(morefiles);
else
get_out();
}
/*
* get_range - parse a range specifier
*
* Ranges are of the form:
*
* addr[,addr]
*
* where 'addr' is:
*
* $ [+- NUM]
* 'x [+- NUM] (where x denotes a currently defined mark)
* . [+- NUM]
* [+- NUM] (short cut on .+- NUM implemented by real vi)
* NUM
*
* The pointer *cp is updated to point to the first character following
* the range spec. If an initial address is found, but no second, the
* upper bound is equal to the lower.
*/
static void get_range(cp, lower, upper)
register char **cp;
LPTR *lower, *upper;
{
register LPTR *l;
register char *p;
if ((l = get_line(cp)) == NULL)
return;
*lower = *l;
for (p = *cp; *p != '\0' && is_space(*p) ;p++)
;
*cp = p;
if (*p != ',') { /* is there another line spec ? */
*upper = *lower;
return;
}
*cp = ++p;
if ((l = get_line(cp)) == NULL) {
*upper = *lower;
return;
}
*upper = *l;
}
static LPTR *get_line(cp)
char **cp;
{
static LPTR pos;
LPTR *lp;
register char *p, c;
register int lnum;
int neg;
pos.index = 0; /* shouldn't matter... check back later */
p = *cp;
/*
* Determine the basic form, if present.
*/
switch (c = *p++) {
case '$':
pos.linep = end_of_file->linep->prev;
break;
case '.':
pos.linep = cursor_char->linep;
break;
case '-':
case '+':
pos.linep = cursor_char->linep;
neg = (c == '-');
for (lnum = 0; is_digit(*p) ;p++)
lnum = (lnum * 10) + (*p - '0');
if (neg)
lnum = -lnum;
pos = *goto_line( cntllines(file_memory, &pos) + lnum );
break;
case '\'':
if ((lp = get_mark(*p++)) == NULL) {
error_message("Unknown mark");
return (LPTR *) NULL;
}
pos = *lp;
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
for (lnum = c - '0'; is_digit(*p) ;p++)
lnum = (lnum * 10) + (*p - '0');
pos = *goto_line(lnum);
break;
default:
return (LPTR *) NULL;
}
while (*p != '\0' && is_space(*p))
p++;
if (*p == '-' || *p == '+')
{
neg = (*p++ == '-');
for (lnum = 0; is_digit(*p) ;p++)
lnum = (lnum * 10) + (*p - '0');
if (neg)
lnum = -lnum;
pos = *goto_line( cntllines(file_memory, &pos) + lnum );
}
*cp = p;
return &pos;
}
void bad_command()
{
error_message("Unrecognized command");
}
int do_e_command(arg, force)
char *arg;
int force;
{
int line = 1; /* line # to go to in new file */
if (!force && changed) {
error_message(nowrtmsg);
if (altfile)
free(altfile);
altfile = strsave(arg);
return (0);
}
if (arg != NULL) {
/*
* First detect a ":e" on the current file. This is mainly
* for ":ta" commands where the destination is within the
* current file.
*/
if (file_name != NULL && strcmp(arg, file_name) == 0) {
if (!changed || (changed && !force))
return (1);
}
if (altfile) {
if (strcmp (arg, altfile) == 0)
line = altline;
free(altfile);
}
altfile = file_name;
altline = cntllines(file_memory, cursor_char);
file_name = strsave(arg);
}
if (file_name == NULL) {
error_message("No filename");
return (0);
}
/* clear mem and read file */
freeall();
file_alloc();
UNCHANGED;
if (read_file(file_name, file_memory, 0))
file_message("[New File]");
*top_char = *cursor_char;
if (line != 1) {
put_int_into_input_buffer(line);
put_string_into_input_buffer("G");
}
set_pc_mark();
update_screen(0);
return (1);
}
void goto_command(clr, firstc)
int clr;
char firstc;
{
goto_screen_pos(current_lines-1,0);
if (clr)termcap_out(termcap_clr_eol); /* clear the bottom line */
if (firstc)
putc(firstc,stdout);
}
/*
* msg(s) - displays the string 's' on the status line
*/
void msg(s)
char *s;
{
goto_command((1), 0);
fprintf(stdout,"%s",s);
fflush(stdout);
}
/*VARARGS1*/
void show_message(s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16)
char *s;
int a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16;
{
char sbuf[80];
sprintf(sbuf, s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16);
msg(sbuf);
}
/*
* error_message() - display an error message
*
* Rings the bell, if appropriate, and calls message() to do the real work
*/
void error_message(s)
char *s;
{
if (PARAMETER_VALUE(PARAMETER_ERRORBELLS))
beep();
msg(s);
}
void wait_return()
{
register char c;
if(local_control_c_pressed())fprintf(stdout,"%s","Interrupt ");
fprintf(stdout,"Press RETURN to continue");
do
{
c = get_char_from_input_buffer();
}
while (c != CTRL_J && c != CTRL_M && c != ' ' && c != ':');
if (c == ':')
{
putc('\n',stdout);
do_command_line(getcmdln(c));
}
else clear_screen();
update_screen(0);
}