#define write(x) message( "more", x, this_object() );
/*
* more.c
* description: the more command for the player object
* author: wayfarer
*
* Modified by Watcher@TMI (3/27/93) to add done_more() passing and
* elimination of 100% more prompts.
*
* Inspiral (4/94) made the input_to()'s not be silent any longer.
*/
#include <ansi.h>
varargs string *wild_card (string arg, int keepdots);
static void search_forward (string arg);
static void search_reverse (string arg);
static void even_more(string str);
void do_more_file(string file);
#define CHUNK 24
static private object previous;
static private mixed *files;
static private string more_file, *lines, last_regexp, chunkstr;
static private int more_line, from_file, num_lines, direction, chunk;
void
write_more_line()
{
write (inverse("--More--("+((more_line*100)/num_lines)+"%)"));
}
int more_line_pos() { return (more_line*100/num_lines); }
varargs int
more (mixed str, int flag, int mask)
{
int i;
string tmp, hold, hold2;
if (!str)
{
notify_fail("Usage: more <filename>\n");
return 0;
}
previous = previous_object();
direction = 1;
last_regexp = "";
more_line = 0;
chunk = (int)this_object()->getenv("LINES") ;
if (stringp(chunk)) chunk = to_int(chunk);
/*
if (!chunkstr || !sscanf(chunkstr, "%d", chunk))
*/
if (!chunk || !intp(chunk))
chunk = CHUNK;
chunk--; // Make room for the more prompt.
if (stringp(str))
{
from_file = 1;
if (!flag)
{
files = wild_card(str,1);
if (!(i = sizeof(files)))
{
notify_fail("No such file or directory.\n");
return 0;
}
else if (i == 1 && file_size(files[0]) == -2) {
files = wild_card(str + "/*");
if (!sizeof(files)) {
notify_fail("Directory is empty.\n");
return 0;
}
}
while (1)
{
if(file_size(files[0]) <= 0)
{
files = files[1..(sizeof(files) - 1)];
notify_fail("All zero length files.\n");
if(!sizeof(files) || files == ({})) {
files = 0; return 0; }
continue;
}
if(!files || !sizeof(files)) return 0;
if(!mask)
hold = "::::::::::::::\n"+files[0]+"\n::::::::::::::\n\n";
tmp = files[0];
if (sizeof(files) == 1)
files = ({});
else
files = files[1..(sizeof(files) - 1)];
if(!hold) more(tmp, 1);
else {
if (hold2 = read_file(tmp)) {
more(explode(hold, "\n") + explode(hold2, "\n"));
} else {
notify_fail ("*Wrong permissions for opening file " +
tmp + " for read.\n");
return 0;
}
}
return 1;
}
return 1;
}
do_more_file(str);
previous->done_more();
return 1;
}
else if (pointerp(str))
lines = str;
else
{
notify_fail ("Bad argument to more.\n");
return 0;
}
num_lines = sizeof(lines);
if(!num_lines) return 1;
even_more(" ");
return 1;
}
void
do_more_file(string file)
{
string tmp;
more_file = file;
more_line = 0;
tmp = read_file (more_file);
if(!stringp(tmp) || tmp == "") return; /* Thanks to Zeus */
lines = explode(tmp,"\n");
more (lines);
}
varargs void
next_more_file(string arg)
{
string tmp;
if (!files || sizeof(files) == 0) {
if(previous) previous->done_more();
return;
}
if (!arg)
{
write("next file:\n"+
":::::::::::::::::::::::\n"+files[0]+"\n::::::::::::::::::::::\n"+
"");
input_to("next_more_file",1);
return;
}
tmp = files[0];
if (sizeof(files) == 1)
files = ({});
else
files = files[1..(sizeof(files) - 1)];
do_more_file(tmp);
}
static void
even_more(string str)
{
int i;
if (!str) str = " ";
str = str[0..0];
switch (str)
{
case " ":
break;
case "":
#if 0
// if get_char() ever gets fixed we can enable this part and use it
if (!this_player()->getenv("getchar")) break;
write(erase_line());
if (more_line >= sizeof(lines))
return;
write (lines[more_line]+"\n");
more_line ++;
write_more_line();
input_to ("even_more",0);
return;
#endif
break;
case "b":
case "B":
more_line -= chunk * 2;
if (more_line < 0)
{
more_line = chunk - 1;
input_to ("even_more",0);
return;
}
break;
case "<":
more_line = 0;
break;
case ">":
more_line = sizeof(lines) - chunk;
break;
case "!":
write(erase_line() + "!");
input_to("exec_cmd");
return;
break;
case "/":
input_to ("search_forward");
write(erase_line());
write ("/");
direction = 1;
return;
break;
case "\\":
input_to ("search_reverse");
write(erase_line());
write ("\\");
direction = 0;
return;
break;
case "n":
if (!last_regexp || last_regexp == "")
{
input_to("even_more",0);
return;
}
write(erase_line());
if (direction == 1)
search_forward (last_regexp);
else
search_reverse (last_regexp);
return;
break;
case "=":
write(erase_line());
write ("" + more_line + " ");
input_to ("even_more",0);
return;
break;
case "v":
write(erase_line());
write ("more for tmi v1.0, written by wayfarer@portals ");
input_to ("even_more",0);
return;
break;
case "h":
case "?":
write(erase_line() + clear_screen());
write ("------------------------------------------------------------------------------\n" +
" [more - help page]\n"+
"------------------------------------------------------------------------------\n" +
"<space>\t\t\tDisplay next page of text.\n"+
"B,b\t\t\tDisplay previous page of text.\n"+
"<return>\t\tDisplay next page of text.\n"+
"<\t\t\tGo to the beginning of the document.\n"+
">\t\t\tGo to the end of the document.\n"+
"=\t\t\tDisplay the current line number.\n"+
"/\t\t\tRegexp search forward.\n"+
"\\\t\t\tRegexp search backward.\n"+
"n\t\t\tContinue last regexp search. (maintain direction)\n"+
"^L\t\t\tRedraw screen.\n"+
"!\t\t\tExecute a command in the mud.\n"+
"v\t\t\tPrint the version number.\n" +
"h,?\t\t\tPrint this help screen.\n"+
"Q,q\t\t\tQuit.\n"+
"");
write_more_line();
input_to ("even_more",1);
return;
break;
case "":
write (clear_screen());
write ( ESC + "[1;1f");
more_line -= chunk;
break;
case "q":
case "Q":
write(erase_line());
write ("\n");
if (previous) previous->done_more(); // Leto
files = ({ });
return;
break;
default:
write(erase_line());
write("Unrecognized command ");
input_to("even_more",0);
return;
break;
}
if(more_line) write(erase_line());
for (i = 0; i < chunk; i++)
{
if (more_line >= sizeof(lines))
{
next_more_file();
return;
}
write (lines[more_line] + "\n");
more_line++;
if(more_line_pos() >= 100) { next_more_file(); return; }
}
input_to ("even_more",0);
write_more_line();
chunk = (int)this_object()->getenv("LINES") ;
if (stringp(chunk)) chunk = to_int(chunk);
if (!chunk || !intp(chunk))
chunk = CHUNK;
chunk -= 1;
return;
}
static void
search_forward (string arg)
{
string *matches;
int i;
matches = regexp (lines[more_line .. (sizeof(lines) - 1)],arg);
if (!matches || (sizeof(matches) == 0))
{
write(up_line()+erase_line()+"\n");
write(inverse("Pattern not found"));
input_to ("even_more",0);
return;
}
for (i = more_line; i < sizeof(lines); i++)
{
if (matches[0] == lines[i])
{
more_line = i;
write ("...skipping\n");
chunk -= 2;
even_more(" ");
last_regexp = arg;
return;
}
}
return;
}
static void
search_reverse (string arg)
{
string *matches;
int i;
matches = regexp (lines[0 .. (more_line - chunk - 1)],arg);
if (!matches || (sizeof(matches) == 0))
{
write(up_line()+erase_line()+"\n");
write(inverse("Pattern not found"));
input_to ("even_more",0);
return;
}
for (i = more_line - chunk - 1; i >= 0; i--)
{
if (matches[sizeof(matches) - 1] == lines[i])
{
more_line = i;
even_more(" ");
last_regexp = arg;
return;
}
}
return;
}
static
void
exec_cmd (string arg)
{
this_player()->force_me(arg);
write(erase_line()+"\n");
write_more_line();
input_to("even_more",0);
}