/* -*- LPC -*- */
/*
* $Locker: $
* $Id: nroff.c,v 1.9 2003/01/29 17:23:50 wyvyrn Exp $
* $Log: nroff.c,v $
* Revision 1.9 2003/01/29 17:23:50 wyvyrn
* Fixed up justification on document title (.DT) for mud and web viewing
*
* Revision 1.7 2001/06/13 22:58:51 pinkfish
* Fix up the columns stuff for the nroffing of files
*
* Revision 1.6 2001/02/05 20:20:02 pinkfish
* Fix up columns.
*
* Revision 1.5 1999/10/28 02:22:21 ceres
* can't remember
*
* Revision 1.4 1998/03/26 10:23:32 pinkfish
* Make it handle html files neater.
*
* Revision 1.3 1998/03/26 10:11:54 pinkfish
* Change the nroff system to not break when there is no
* this_)player and doing a cat_file
*
* Revision 1.2 1998/03/06 10:22:50 pinkfish
* Make the header stuff look better in html files.
*
* Revision 1.1 1998/01/06 05:03:33 ceres
* Initial revision
*
*/
/**
* An nroff like object for formating text files.
*<p>
* This creates a saveable file format thingy.
*
* @author Pinkfish
*/
#include <nroff.h>
mixed *nroffed_file;
string nroffed_file_name;
int modified_time;
nosave int new_string;
nosave int force_string;
void create() {
nroffed_file = ({ });
seteuid("Root"); /* Security risk? nahhhhh */
} /* create() */
#define do_bounds(bing) (bing<0?bing+cols:bing)
/**
* Creates a string from a nroffed file.
* <p>
* If update is non zero it will look to see if the source file has been
* modified since the saved nroff file was created. If it has, this
* function returns 0 and the nroff file needs to be recreated.
*
* @param fname the file to process
* @param update force update if file is newer?
* @return the string representation of the nroff file
*/
string cat_file(string fname, int update) {
int i;
int k;
int cols;
string ret;
string pat;
mixed* tmp;
if (!master()->valid_read(fname, geteuid(previous_object()),
"restore_object")) {
return 0;
}
nroffed_file_name = 0;
modified_time = 0;
if (!restore_object(fname))
return 0;
if (!nroffed_file_name && update)
return 0;
if (update) {
mixed *something;
if (!master()->valid_read(nroffed_file_name,
geteuid(previous_object()),
"restore_object"))
return 0;
if (file_size(nroffed_file_name) <= 0)
return 0;
something = stat(nroffed_file_name);
if (something[1] > modified_time)
return 0;
}
ret = "";
if (this_player()) {
cols = (int)this_player()->query_cols();
} else {
cols = 79;
}
for (i=0;i<sizeof(nroffed_file);i++) {
if (stringp(nroffed_file[i])) {
ret += nroffed_file[i];
} else {
switch (nroffed_file[i]) {
case V_HEADER :
ret += sprintf("%%^BOLD%%^%s%%^RESET%%^\n", nroffed_file[i+1]);
i++;
break;
case V_CENTER :
ret += sprintf("%|=*s", cols, nroffed_file[i+1]);
i++;
break;
case V_ALL :
ret += "%^BOLD%^\n" + sprintf("%-s%*|s%*s\n",
nroffed_file[i+2],
cols - nroffed_file[i+1]*2,
nroffed_file[i+3],
nroffed_file[i+1],
nroffed_file[i+4]) + "%^RESET%^\n";
//if (this_player() == find_player("presto")) write("middle == :" + nroffed_file[i + 3] + ":\n" + nroffed_file[i + 1] + "\n");
//if (this_player() == find_player("wyvyrn")) write( "file: '" + nroffed_file[i+1] + "', left: '" + nroffed_file[i+2] + "', centre: '" + nroffed_file[i+3] + "', right: '" + nroffed_file[i+4] + "'\n");
i += 4;
break;
case V_INDENT :
ret += sprintf( "%*=s%-=*s", nroffed_file[ i + 1 ], "",
cols - nroffed_file[ i + 1 ], nroffed_file[ i + 2 ] );
i += 2;
break;
case V_PARA :
if (nroffed_file[i+1])
ret += sprintf("%*=s%-=*s%=*s\n", nroffed_file[i+1], "",
cols-nroffed_file[i+1]-
nroffed_file[i+2], nroffed_file[i+3],
nroffed_file[i+2], "");
else if (nroffed_file[i+2])
ret += sprintf("%-=*s%=*s\n", cols-nroffed_file[i+2],
nroffed_file[i+3],
nroffed_file[i+2], "");
else
ret += sprintf("%-=*s\n", cols, nroffed_file[i+3]);
i += 3;
break;
case V_LEFT :
ret += sprintf("%-=*s", cols, nroffed_file[i+1]);
i++;
break;
case V_TABLE :
ret += sprintf("%-#*s", cols, nroffed_file[i+1]);
i++;
break;
case V_COLUMN : {
int j;
switch (sizeof(nroffed_file[i+1])) {
case 2 :
for (j=0;j<sizeof(nroffed_file[i+2]);j++) {
ret += sprintf("%*-=s%*-=s\n", do_bounds(nroffed_file[i+1][0]),
nroffed_file[i+2][j],
do_bounds(nroffed_file[i+1][1]),
nroffed_file[i+3][j]);
}
i += 3;
break;
case 3 :
for (j=0;j<sizeof(nroffed_file[i+2]);j++) {
ret += sprintf("%*-=s%*-=s%*-=s\n",
do_bounds(nroffed_file[i+1][0]),
nroffed_file[i+2][j],
do_bounds(nroffed_file[i+1][1]),
nroffed_file[i+3][j],
do_bounds(nroffed_file[i+1][2]),
nroffed_file[i+4][j]);
}
i += 4;
break;
default :
pat = implode(allocate(sizeof(nroffed_file[i+1]), "%*-=s"), "");
for (j=0;j<sizeof(nroffed_file[i+2]);j++) {
tmp = ({ });
for (k = 0; k < sizeof(nroffed_file[i+1]); k++) {
tmp += ({ do_bounds(nroffed_file[i+1][k]),
nroffed_file[i+2+k][j] });
}
ret += sprintf(pat + "\n", tmp ... );
}
i += sizeof(nroffed_file[i+1]) + 1;
break;
}
break;
}
}
}
}
return " \n"+ret;
} /* cat_file() */
/**
* @ignore yes
*/
private string htmlify(string str) {
return replace(str, ({ "&", "&", "<", "<", ">", ">"}));
} /* htmlify() */
/**
* Turns the nroff file into a html output. This works on nroff files
* creating a html output from the mud source.
*
* @param file the name to process
* @param title the title to give the document
* @return the html file
*/
string html_file(string file, string title) {
int i, j, cols, in_bold, in_italic;
int k;
string ret, *bits;
if (!master()->valid_read(file, geteuid(previous_object()),
"restore_object"))
return 0;
nroffed_file_name = 0;
modified_time = 0;
if (!restore_object(file))
return 0;
ret = "";
cols = 78;
for (i=0;i<sizeof(nroffed_file);i++)
if (stringp(nroffed_file[i]))
nroffed_file[i] = htmlify(nroffed_file[i]);
else if(arrayp(nroffed_file[i])) {
for (j=0;j<sizeof(nroffed_file[i]);j++)
if(stringp(nroffed_file[i][j]))
nroffed_file[i][j] = htmlify(nroffed_file[i][j]);
}
for (i=0;i<sizeof(nroffed_file);i++) {
if (stringp(nroffed_file[i])) {
ret += "<h3>"+nroffed_file[i]+"</h3>";
#ifdef UNUSED
if(strsrch(nroffed_file[i], "See also") > -1) {
for(j=i+1; j < sizeof(nroffed_file); j++) {
if(stringp(nroffed_file[j])) {
nroffed_file[j] = make_links(nroffed_file[j]);
}
}
}
#endif
} else {
switch (nroffed_file[i]) {
case V_HEADER :
ret += "<h3>"+replace_string(nroffed_file[i+1], "\n", "<br>")+
"</h3>";
i++;
break;
case V_CENTER :
ret += "<center>"+replace(nroffed_file[i+1], "\n", "<br>")+
"</center>";
i++;
break;
case V_ALL :
ret += "\n<table width=100%><tr>\n" +
"<td nowrap width=* align=left><h2>" +
nroffed_file[i+2] + "</h2></td>\n" +
"<td nowrap align=center><h2>" +
nroffed_file[i+3] + "</h2></td>\n" +
"<td nowrap width=* align=right><h2>" +
nroffed_file[i+4] + "</h2></td>\n" +
"</tr></table>\n";
i += 4;
break;
case V_INDENT :
ret += replace(nroffed_file[i+2], ({"<", "<", ">",
">", "\n", "<br>"}));
i += 2;
break;
case V_PARA :
ret += replace(nroffed_file[i+3], "\n", "<p>");
i += 3;
break;
case V_LEFT :
ret += "<left>"+nroffed_file[i+1]+"</left>";
i++;
break;
case V_TABLE :
ret += "<ul><li>"+replace(nroffed_file[i+1], "\n", "<li>")+"</ul>";
i++;
break;
case V_COLUMN : {
ret += "<table cellpadding=10>";
switch (sizeof(nroffed_file[i+1])) {
case 2 :
for (j=0;j<sizeof(nroffed_file[i+2]);j++) {
ret += "<tr>\n";
ret += "<td nowrap>"+nroffed_file[i+2][j] + "</td>";
ret += "<td>"+nroffed_file[i+3][j] + "</td>";
ret += "</tr>";
}
i += 3;
break;
case 3 :
for (j=0;j<sizeof(nroffed_file[i+2]);j++) {
ret += "<tr>\n";
ret += "<td nowrap>"+nroffed_file[i+2][j] + "</td>";
ret += "<td nowrap>"+nroffed_file[i+3][j] + "</td>";
ret += "<td>"+nroffed_file[i+4][j] + "</td>";
ret += "</tr>";
}
i += 4;
break;
default :
for (j=0;j<sizeof(nroffed_file[i+2]);j++) {
ret += "<tr>\n";
for (k = 0; k < sizeof(nroffed_file[i+1]); k++) {
ret += "<td nowrap>" + nroffed_file[i+2+k][j] + "</td>\n";
}
ret += "</tr>\n";
}
i += sizeof(nroffed_file[i+1]) + 1;
break;
}
ret += "</table>";
break;
}
}
}
}
bits = explode(ret, "%^");
ret = "";
for (i=0;i<sizeof(bits);i+=2) {
ret += bits[i];
if (i+1 < sizeof(bits)) {
switch (bits[i+1]) {
case "BOLD" :
if (!in_bold)
ret += "<strong>";
else
ret += "</strong>";
in_bold = !in_bold;
break;
case "RESET" :
if (in_bold)
ret += "</strong>";
if (in_italic)
ret += "</i>";
in_bold = 0;
in_italic = 0;
break;
default :
if (!in_italic)
ret += "<i>";
else
ret += "</i>";
in_italic = !in_italic;
break;
}
}
}
return ret;
} /* html_file() */
private void add_array(mixed *i) {
if (!sizeof(nroffed_file)) {
nroffed_file += ({ i });
} else if (force_string) {
nroffed_file += ({ "", i });
} else {
nroffed_file += ({ i });
}
force_string = 0;
new_string = 0;
} /* add_array() */
private void add_int(int i) {
if (!sizeof(nroffed_file)) {
nroffed_file += ({ i });
} else if (force_string) {
nroffed_file += ({ "", i });
} else {
nroffed_file += ({ i });
}
force_string = 0;
new_string = 0;
} /* add_int() */
private void add_string(string s) {
if (!sizeof(nroffed_file) || new_string) {
nroffed_file += ({ s });
} else if (stringp(nroffed_file[<1])) {
nroffed_file[<1] += s;
} else {
nroffed_file += ({ s });
}
new_string = 0;
force_string = 0;
} /* add_string() */
/**
* Makes the nroff saveable file. Turns the input nroff file into a saved
* output format.
*
* @param in_file the file name been processed
* @param out_file the file to save it as
* @return 1 if the operation was successful
*/
int create_nroff(string in_file, string out_file) {
string text,
tmp,
*bits;
string *bing;
mixed *cols;
int strip_crs,
col_mode,
conv_tabs,
i, j, k, fluff,
num_cols;
if (!master()->valid_read(in_file, geteuid(previous_object()),
"read_file"))
return 0;
nroffed_file_name = in_file;
modified_time = time();
text = read_file(in_file);
if (!text) {
return 0;
}
bits = explode("#\n"+text, "\n.");
bits[0] = bits[0][1..];
nroffed_file = ({ 0 });
if (strlen(bits[0])) {
add_string(bits[0]);
}
for (i=1;i<sizeof(bits);i++) {
if (sscanf(bits[i], "%s\n%s", tmp, bits[i]) != 2) {
tmp = bits[i];
bits[i] = "";
fluff = 1;
} else {
fluff = 0;
}
switch (tmp[0..1]) {
case "SH" : /* Section header */
add_int(V_HEADER);
add_string(tmp[3..]);
new_string = 1;
break;
case "SI" : /* Start indent */
add_int(V_INDENT);
j = 0;
sscanf(tmp[2..], "%d%s", j, tmp);
add_int(j);
force_string = 1;
break;
case "EI" : /* End indent */
add_string("");
new_string = 1;
break;
case "SP" : /* Start paragraph */
add_int(V_PARA);
j = 0;
sscanf(tmp[2..], "%d%s", j, tmp);
add_int(j);
j = 0;
sscanf(tmp, " %d%s", j, tmp);
add_int(j);
force_string = 1;
strip_crs = 1;
break;
case "EP" : /* End paragraph */
add_string("");
new_string = 1;
strip_crs = 0;
break;
case "SC" : /* start centering */
add_int(V_CENTER);
force_string = 1;
break;
case "EC" : /* End centering */
new_string = 1;
break;
case "SL" : /* Start left justify */
add_int(V_LEFT);
force_string = 1;
break;
case "EL " : /* End left justify */
new_string = 1;
break;
case "ST" : /* Start table mode (Turn tabs into new lines) */
add_int(V_TABLE);
force_string = 1;
conv_tabs = 1;
break;
case "ET" : /* End table mode */
new_string = 1;
conv_tabs = 0;
break;
case "DT" : /* Do title. Take the next three lines... */
bing = explode(bits[i], "\n");
if (sizeof(bing) < 3) {
if (this_player()->query_creator()) {
tell_object(this_player(), "Text file "+in_file+
" did not have enough lines after the .DT directive.\n");
tell_object(this_player(), sprintf("%O\n", bing));
}
return 0; /* failed! */
}
add_int(V_ALL);
if (strlen(bing[0]) > strlen(bing[2]))
add_int(strlen(bing[0]));
else
add_int(strlen(bing[2]));
new_string = 1;
add_string(bing[0]);
new_string = 1;
add_string(bing[1]);
new_string = 1;
add_string(bing[2]);
new_string = 1;
bits[i] = implode(bing[3..], "\n");
break;
case "SO" : /* starts column mode. The numbers after it
* are column size */
num_cols = 0;
tmp = tmp[2..];
cols = ({ });
while (sscanf(tmp, "%d%s", j, tmp) == 2) {
cols += ({ j });
num_cols++;
while (strlen(tmp) && tmp[0] == ' ')
tmp = tmp[1..];
}
add_int(V_COLUMN);
if (sscanf(tmp, "%d", j) == 1) {
cols += ({ j });
num_cols++;
}
add_array(cols);
cols = allocate(num_cols);
for (j=0;j<num_cols;j++) {
cols[j] = ({ });
}
col_mode = 1;
break;
case "EO" : /* End column mode */
for (j=0;j<num_cols;j++) {
add_array(cols[j]);
}
col_mode = 0;
break;
case "NF" : /* New File. Take the next line and ignore everything
* else in the file */
bing = explode(bits[i], "\n");
if (sizeof(bing) < 1) {
if (this_player()->query_creator()) {
tell_object(this_player(), "Text file "+in_file+
" did not have enough lines after the .NF directive.\n");
tell_object(this_player(), sprintf("%O\n", bing));
}
return 0; /* failed! */
}
/* read the new file and start again, but keep the old name */
text = read_file(bing[ 0 ]);
if (!text) {
return 0;
}
bits = explode("#\n"+text, "\n.");
bits[0] = bits[0][1..];
nroffed_file = ({ 0 });
if (strlen(bits[0])) {
add_string(bits[0]);
}
strip_crs = col_mode = conv_tabs = fluff = num_cols = i = 0;
break;
}
if (fluff) {
continue;
}
if (conv_tabs) {
bits[i] = replace(bits[i], "\t", "\n");
}
if (col_mode) {
string *frog;
frog = explode(bits[i], "\n");
for (k = 0; k < sizeof(frog); k++) {
bing = explode("#"+frog[k], "\t");
bing[0] = bing[0][1..];
for (j = 0; j < num_cols && j < sizeof(bing); j++) {
cols[j] += ({ bing[j] });
}
for (j = sizeof(bing);j < num_cols; j++) {
cols[j] += ({ "\n" });
}
}
} else if (strip_crs) {
bits[i] = replace_string(bits[i], "\n\n", "$%^NeW_LiNe^%$");
bits[i] = replace_string(bits[i], ".\n", ". ");
bits[i] = replace_string(bits[i], "\n", " ");
bits[i] = replace_string(bits[i], "$%^NeW_LiNe^%$", "\n\n");
add_string(bits[i]+" ");
} else {
add_string(bits[i]+"\n");
}
}
new_string = 0;
force_string = 0;
unguarded((: save_object, out_file :));
return 1;
} /* create_nroff() */
/**
* Will attempt to find the name of the nroffed file. Will attempt to
* find the name of the source file associated with the save file.
*
* @param fname the name of the file to check
* @return the source file name or 0
*/
string query_file_name( string fname ) {
if (!master()->valid_read(fname, geteuid(previous_object()),
"restore_object")) {
return 0;
}
nroffed_file_name = 0;
modified_time = 0;
if (!restore_object(fname)) {
return 0;
}
return nroffed_file_name;
} /* query_file_name() */