/* -*- LPC -*- */
/*
* $Locker: $
* $Id: more_file.c,v 1.9 2002/02/26 02:41:22 presto Exp $
* $Log: more_file.c,v $
* Revision 1.9 2002/02/26 02:41:22 presto
* Fixed bug with trying to more a file for which you didn't have read perms.
* Slight changes for efficiency.
*
* Revision 1.8 2001/06/03 20:23:09 pinkfish
* Change a variable name.
*
* Revision 1.7 2001/06/01 21:05:29 ceres
* Can't remember
*
* Revision 1.6 2000/10/20 18:03:57 pinkfish
* Add in some code to deal with tab stops.
*
* Revision 1.5 2000/10/20 17:54:46 ceres
* Forcibly unlocked by pinkfish
*
* Revision 1.4 2000/04/26 04:53:18 ceres
* Fixed runtime
*
* Revision 1.3 1999/07/24 13:52:30 presto
* Fix for my fix. Gerbil was getting sarcastic. :)
*
* Revision 1.2 1999/07/24 01:24:54 presto
* Fixed problem with more-ing files containing blank lines.
*
* Revision 1.1 1998/01/06 04:54:05 ceres
* Initial revision
*
*/
/*
* Original by Ember.
* Improved version by Pinkfish.
* Debugged by Deutha.
*/
#include <nroff.h>
#include <cmds/options.h>
#define ROWS (this_player()->query_rows() - 1)
#define COLS this_player()->query_cols()
private nosave int fsize, topl, botl, charl, real_rows, search_flag;
private nosave mixed mark_data;
private nosave string _more_file_fname,
*mark_name,
*filenames,
finish_func,
stat_line,
last_search;
private int display_file() {
int i;
int ncols;
int nrows;
string file;
string *bits;
string *lines;
string tstop;
int tab;
ncols = COLS;
nrows = ROWS;
file = read_file(_more_file_fname, topl, nrows);
if (file == 0)
return 0;
// Work out the tabstops.
tab = this_player()->query_property(TABSTOP_PROP);
if (tab)
tstop = sprintf("%" + tab + "' 's", "");
else
tstop = "<TAB>";
file = replace(file, ({ "\t", tstop,
"\r", "^M",
sprintf("%c", 13), "^M" }));
/* We add the extra character and then remove it from the resulting
* array because this won't work on totally blank lines. :( */
bits = explode("x\n" + file, "\n")[1 .. ];
if (charl)
bits[0] = bits[0][charl .. ];
real_rows = 0;
lines = ({ });
for (i = 0; i < sizeof(bits); i++) {
if (strlen(bits[i]) > ncols) {
lines = ({ lines..., bits[i][0 .. ncols - 1] });
bits[i] = bits[i][ncols .. ];
charl += ncols;
--i;
} else {
lines = ({ lines..., bits[i] });
charl = 0;
++real_rows;
}
if (sizeof(lines) == nrows)
break;
}
printf("%s\n", implode(lines, "\n"));
botl = topl + real_rows - 1;
if (botl > fsize)
botl = fsize;
return 1;
} /* display_file() */
private int get_next_filename() {
string str;
_more_file_fname = filenames[0];
filenames = filenames[1 .. ];
fsize = file_length(_more_file_fname);
if (fsize == 0) {
printf("Empty file.\n");
if (sizeof(filenames) > 1)
return get_next_filename();
else
return 0;
}
if (fsize == -1) {
printf("File does not exist.\n");
if (sizeof(filenames) > 1)
return get_next_filename();
else
return 0;
}
if (fsize == -2) {
printf("You cannot more a directory.\n");
if (sizeof(filenames) > 1)
return get_next_filename();
else
return 0;
}
topl = 1;
charl = 0;
printf( "\n" );
str = read_file(_more_file_fname, 1, 1);
if (str == 0)
return 0;
if (str[0] == '.') {
string s2;
/*
* Nroff file... do horrible things! Turn into a mushroom! Blow up
* all the hairy crater eating womble doovalacies...
* In the case of a nroff file we push the file through nroff then shove
* it through more_string...
*/
str = "/tmp/nroffed_file";
if (NROFF_HAND->create_nroff(_more_file_fname, "/tmp/nroffed_file")) {
s2 = NROFF_HAND->cat_file("/tmp/nroffed_file");
rm("/tmp/nroffed_file.o");
if (s2 != 0) {
this_player()->more_string(s2, _more_file_fname);
fsize = ROWS - 3;
return 1;
}
}
}
return display_file();
} /* get_next_file_name() */
private string *expand_path(string s) {
string *s1;
s1 = this_player()->get_files(s);
if (s1 == 0)
return ({ s });
return s1;
} /* expand_path() */
int set_mark(string s) {
int i;
if (!mark_name) {
mark_name = ({ });
mark_data = ({ });
}
if ((i = member_array(s, mark_name)) != -1)
mark_data[i] = ({ _more_file_fname, topl });
else {
mark_name += ({ s });
mark_data += ({ ({ _more_file_fname, topl }) });
}
return 1;
} /* set_mark() */
private void status_line() {
string *frog;
string s;
int i, percentage;
if (!stat_line)
stat_line = "$N From $T to $B of $S ($%%) - h for help. ";
s = "";
frog = explode(stat_line, "$");
for (i = 0; i < sizeof(frog); i++) {
if (frog[i] == "") {
s += "$";
++i;
}
else switch (frog[i][0]) {
case 'N':
s += _more_file_fname + frog[i][1 .. ];
break;
case 'T':
s += topl + frog[i][1 .. ];
break;
case 'B':
if (botl > fsize)
s += fsize + frog[i][1 .. ];
else
s += botl + frog[i][1 .. ];
break;
case '%':
percentage = (botl * 100) / fsize;
if (percentage > 100) percentage = 100;
s += percentage + frog[i][1 .. ];
break;
case 'S':
s += fsize + frog[i][1 .. ];
break;
default:
printf("Bad tag (%s) found in format string.\n", frog[i]);
break;
}
}
printf("%s", s);
return;
} /* status_line() */
void next_page(string str) {
int num, noargs, i, j, k, redraw;
string s1, *s3;
if (str == 0)
str = "";
if (sscanf(str, "%d%s", num, str) != 2)
noargs = 1;
s1 = extract(str, 1);
/* case statements WEEEEEE */
switch (str[0 .. 0]) {
case "":
case " ":
topl += real_rows;
redraw = 1;
break;
case "f":
/* go on a number of pages... */
if (noargs)
num = 1;
topl += ROWS * num;
redraw = 1;
break;
case "q" :
printf("OK.\n");
return;
case "/":
/* sigh */
search_flag = 0;
j = topl + 4;
if (s1[0] == '!') {
search_flag = 1;
s1 = extract(s1, 1);
}
set_mark("'");
if (s1=="" || !s1)
s1 = last_search;
if (s1 == "") {
printf("No previous search string.\n");
break;
}
do {
i = j;
j = i + 900;
if (j > fsize)
j = fsize;
s3 = explode(read_file(_more_file_fname, i, j), "\n");
for (k = 0; k < sizeof(s3); k++)
if (!search_flag) {
if (sscanf(s3[k], "%*s" + s1 + "%*s") == 2)
if (num-- <= 0)
break;
} else
if (sscanf(s3[k], "%*s" + s1 + "%*s") != 2)
if (num-- <= 0)
break;
} while (j < fsize && k == sizeof(s3));
if (k == sizeof(s3))
printf("Sorry " + s1 + " not found.\n");
else {
topl = i + k - 3;
redraw = 1;
}
last_search = s1;
break;
case "?":
i = topl;
if (s1[0] == '!') {
s1 = extract(s1, 1);
search_flag = 3;
} else
search_flag = 2;
set_mark("'");
if (s1=="" || !s1)
s1 = last_search;
if (s1 == "") {
printf("No previous search string.\n");
break;
}
do {
j = i - 900;
if (j < 0)
j = 0;
s3 = explode(read_file(_more_file_fname, j, i), "\n");
for (k = 0; k < sizeof(s3); k++)
if (search_flag == 2) {
if (sscanf(s3[k], "%*s" + s1 + "%*s") == 2)
if (num-- <= 0)
break;
} else
if (sscanf(s3[k], "%*s" + s1 + "%*s") != 2)
if (num-- <= 0)
break;
i = j;
} while (j > 0 && k == sizeof(s3));
if (k == sizeof(s3))
printf("Sorry "+ s1 +" not found.\n");
else {
topl = k + i - 2;
redraw = 1;
}
last_search = s1;
break;
case "n":
switch (search_flag) {
case 0:
next_page(num + "/");
break;
case 1:
next_page(num + "/!");
break;
case 2:
next_page(num + "?");
break;
case 3:
next_page(num + "?!");
break;
}
return;
case "b":
if (noargs)
num = 1;
if (topl > 0) {
topl -= ROWS * num;
redraw = 1;
if (topl < 0)
topl = 0;
}
break;
case "G":
if (noargs)
num = fsize - ROWS + 1;
case "g":
set_mark("'");
topl = num;
if (topl >= fsize)
topl = fsize - 2;
redraw = 1;
break;
case "P":
if (noargs)
num = 100;
case "p":
case "%":
redraw = 1;
set_mark("'");
topl = (num * fsize) / 100;
if (topl + ROWS - 1 > fsize)
topl -= ROWS - 1;
break;
case "d":
if (noargs)
num = ROWS / 2;
topl += num;
redraw = 1;
break;
case "u":
if (noargs)
num = ROWS / 2;
topl -= num;
redraw = 1;
break;
case "r":
redraw = 1;
break;
case "m":
if (s1 == "") {
printf("Sorry, you must specify a name.\n");
break;
}
set_mark(s1);
printf("OK, mark " + s1 + " set.\n");
break;
case "'":
if (!mark_name) {
printf("Sorry, must go to a mark.\n");
break;
}
if ((i = member_array(s1, mark_name)) != -1) {
if (_more_file_fname != mark_data[i][0]) {
_more_file_fname = mark_data[i][0];
redraw = 1;
}
if (topl != mark_data[i][1]) {
topl = mark_data[i][1];
redraw = 1;
}
} else
printf("Mark " + s1 + " not set.\n");
break;
case "F":
filenames = expand_path(str);
if (sizeof(filenames) == 0) {
printf("No matching files.\n");
break;
}
last_search = "";
redraw = get_next_filename();
break;
case "h":
cat("/doc/helpdir/more");
break;
}
if (redraw)
display_file();
if (botl < fsize || charl) {
status_line();
input_to("next_page");
} else
if (sizeof(filenames) > 0) {
if (get_next_filename())
input_to("next_page");
else if (finish_func)
call_other(this_player(), finish_func);
} else {
if (finish_func)
call_other(this_player(), finish_func);
}
} /* next_page() */
int more_file(string str) {
filenames = expand_path(str);
if (!sizeof(filenames)) {
notify_fail("No matching files.\n");
return 0;
}
last_search = "";
if (!get_next_filename()) {
notify_fail("Could not read " + _more_file_fname + ".\n");
return 0;
}
if (botl < fsize || charl) {
status_line();
input_to("next_page");
} else
if (finish_func)
call_other(this_player(), finish_func);
return 1;
} /* more_file() */