/* Do not remove the headers from this file! see /USAGE for more info. */
/*
** more_ob.c
**
** Standard object for providing "more" type functionality.
**
** Originally written by Justice, I believe.
**
** Converted to the new modal input system by Deathblade on 8/16/94.
** Big rewrite and cleanup.
** Beek added ANSI support
** Rust made it check your shell's MORE variable
** Rust added more_lines(lines, chunksize) for intentionally small more's.
*/
#include <more.h>
#define NUM_LINES 999
inherit M_INPUT;
inherit M_ACCESS;
private string current_search;
private string last_search;
private int direction;
private string * file_list;
private int file_index;
private string * lines;
private int line_index;
private int chunk_size;
private function continue_func;
private int output_flags;
private nomask string query_prompt()
{
string prompt = "";
int last = line_index + chunk_size;
int percent;
if (last > sizeof(lines)) {
last = sizeof(lines);
percent = 100;
} else {
percent = last*100/sizeof(lines);
}
if (file_list && file_index < sizeof(file_list) && wizardp(this_user()))
prompt = "\"" + file_list[file_index] + "\" ";
prompt += sprintf("(%i-%i %i%%) [h]:", line_index + 1, last, percent);
return "%^MORE%^" + prompt + "%^RESET%^";
}
/* returns 1 if no more files are available */
private int next_file()
{
file_index += direction;
if ( file_index < 0 || file_index >= sizeof(file_list) )
return 1;
if (direction == -1)
printf("more: going back to file \"%s\"\n", file_list[file_index]);
else
printf("more: going on to file \"%s\"\n", file_list[file_index]);
lines = 0;
return 0;
}
private void print_help()
{
write(
"More Help:\n\n Commands are one letter anachronyms as listed below\n\n"+
" a : Print current page again.\n"+
" / : /<string> starts foward search for string.\n"+
" h,? : This help, OR ?<string> to start backward search for string.\n"+
" d : Toggle scanning direction.\n"+
" Changes which direction you page through the file(s).\n"+
" b : goto the beginning of the file.\n"+
" e : goto the end of the file.\n"+
" n : Next file in scan direction if any.\n"+
" q : quit\n"+
" s : Set or toggle off search string.\n"+
" s <string> where <string> is what you're looking for.\n"+
" Searches are done in the scan direction and page displayed\n"+
" is the one directly following any match made.\n"+
" Until you toggle s off, any scan will search for a match.\n"+
" s by itself turns off the search parameter\n\n"+
" enter or anything else scans the next page.\n");
}
private void finish()
{
modal_pop();
if ( continue_func )
evaluate(continue_func);
destruct(this_object());
}
private nomask void do_more(mixed arg) {
int x;
if (arg == -1) {
destruct(this_object());
return;
}
if (arg)
switch(arg[0]) {
case '?':
current_search = arg[1..];
if (current_search != "") {
direction = -1;
last_search = current_search;
break;
}
if (last_search) {
current_search = last_search;
direction = -1;
line_index += chunk_size * direction;
if (line_index < 0 || line_index >= sizeof(lines)) {
if ( next_file()) {
finish();
return;
}
}
break;
}
if(!current_search || current_search=="") {
print_help();
return;
}
write("more: illegal syntax, type \"h\" for help.\n");
return;
case 'h':
print_help();
return;
case 's': // Set search string
if (arg != "s") {
current_search = arg[1..];
write("more: search set to \"" + current_search + "\"\n");
} else {
current_search = 0;
write("more: search off\n");
}
return;
case '/':
current_search = arg[1..];
if (current_search != "") {
direction = 1;
last_search = current_search;
break;
}
if (last_search) {
current_search = last_search;
direction = 1;
line_index += chunk_size * direction;
if (line_index < 0 || line_index >= sizeof(lines)) {
if ( next_file() ) {
finish();
return;
}
}
break;
}
write("more: illegal syntax, type \"h\" for help.\n");
return;
case 'd': // Toggle Direction
direction = -direction;
write("more: now scanning " +
(direction == 1 ? "forward" : "backward") + "\n");
return;
case 'n': // Next file if any
if (sizeof(file_list) > 1)
file_index += direction;
if (!sizeof(file_list))
{
finish();
return;
}
if (file_index < 0 || file_index >= sizeof(file_list)) {
write("more: no more files " + (direction == 1 ? "after" : "preceding") +
"\"" + file_list[file_index - 1] + "\"\n");
file_index -= direction;
return;
}
else
lines = 0;
break;
case 'q':
finish();
return;
case 'b':
line_index = 0;
break;
case 'e':
line_index = (sizeof(lines) - chunk_size >= 0 ?
sizeof(lines) - chunk_size : 0);
break;
case 'a':
break;
default: // Next chunk
if (last_search)
current_search = 0;
line_index += chunk_size * direction;
if (line_index < 0 || line_index >= sizeof(lines)) {
if ( next_file() )
{
finish();
return;
}
}
break;
}
while(1) {
if (!lines) {
string contents;
if (!file_list || !sizeof(file_list))
break;
if(wizardp(this_user()))
write("filename: "+file_list[file_index]+"\n");
if (file_size(file_list[file_index]) == -1) {
write("more: no such file \"" + file_list[file_index] +
"\"\n");
if ( next_file() )
break;
continue;
}
contents = read_file(file_list[file_index], 0, NUM_LINES);
if ( !contents || !sizeof(lines = explode(contents, "\n")) )
{
write("more: file \"" + file_list[file_index] +
"\" contains nothing\n");
if ( next_file() )
break;
continue;
}
if (direction == -1)
line_index = (sizeof(lines) - chunk_size >= 0 ?
sizeof(lines) - chunk_size : 0);
else
line_index = 0;
}
if (current_search) {
for(;line_index < sizeof(lines) && line_index >= 0;
line_index += direction)
if (regexp(lines[line_index], current_search))
break;
if (line_index < 0 || line_index >= sizeof(lines)) {
write("more: \"" + current_search + "\" not found" + (file_list ? " in \"" + file_list[file_index] + "\"\n" : "\n"));
if ( next_file() )
{
/* oops. not found. back up and get some input. */
file_index -= direction;
return;
}
/* refill the list of lines */
continue;
}
}
for(x = line_index;x < sizeof(lines) && x < line_index + chunk_size; x++)
tell(this_user(), lines[x] + "\n", output_flags);
if (sizeof(lines) >= chunk_size || (file_list && sizeof(file_list) > 1))
{
/* return to prompt about more lines/next file */
return;
}
/* break: we're done, so finish up */
break;
}
finish();
return;
}
void create(int kind, mixed arg, int c, function continuation,
int of) {
set_privilege(1);
switch (kind) {
case 0: // blueprint
return;
case MORE_FILES:
file_list = arg;
file_index = 0;
break;
case MORE_LINES:
lines = arg;
break;
default:
error("Bad argument 2 to new(MORE_OB, ...)\n");
}
direction = 1;
chunk_size = c;
continue_func = continuation;
output_flags = of;
modal_push((: do_more :), (: query_prompt :));
if (catch(do_more(0))) modal_pop();
}