/*
* file.c
*
* File thingy-bobedidabobobudidis
*
* (C) Frank Schmidt, Jesus@NorseMUD
*
*/
/* check master for read/write permission */
#ifdef MUDOS_USER_ID
# define MASTER_READ(file) \
call_other(master(), __VALID_READ_FUNC, file, geteuid(), previous_function() )
# define MASTER_WRITE(file) \
call_other(master(), __VALID_WRITE_FUNC, file, geteuid(), previous_function() )
#else
# define MASTER_READ(file) \
call_other(master(), __VALID_READ_FUNC, file, this_object(), previous_function() )
# define MASTER_WRITE(file) \
call_other(master(), __VALID_WRITE_FUNC, file, this_object(), previous_function() )
#endif
/* get the size of a file */
static int file_size(string file) {
int *sizes;
if (!MASTER_READ(file)) return -1;
sizes = ::get_dir(file)[GDIR_SIZES];
if (::sizeof(sizes) != 1) return -1;
return sizes[0];
}
/* return filenames found by <path> (with wildcards etc) */
static string *get_files(string path) {
if (!MASTER_READ(path)) return ({ });
return ::get_dir(path)[GDIR_NAMES];
}
#ifdef MUDOS_GET_DIR_BEHAVIOUR
/* get directory info (not very good simulated) */
static varargs mixed *get_dir(string file, int flag) {
int len;
if (!MASTER_READ(file)) return ({ });
len = ::strlen(file);
if (file == "" || file[len - 1] == '/')
file += "*";
else if (len > 1 && file[len - 2 ..] == "/.")
file[len - 1] = '*';
if (flag != -1)
return ::get_dir(file)[GDIR_NAMES];
else
return ::get_dir(file);
}
#else
/* get directory info */
static mixed *get_dir(string file) {
if (!MASTER_READ(file)) return ({ ({}), ({}), ({}) });
return ::get_dir(file);
}
#endif
/* make a directory */
static int make_dir(string file) {
if (!MASTER_WRITE(file)) return -1;
return ::make_dir(file);
}
/* read bytes from a file */
static varargs string read_bytes(string file, int start, int size) {
if (!MASTER_READ(file)) return 0;
return ::read_file(file, start, size);
}
/* return a line range of a file */
private static string *read_lines(string file, int first, int num) {
int i, offset, size;
string buf, res, *result;
/* bad numbers? */
if (first < 0 || num <= 0) return 0;
/* scan to beginning */
size = file_size(file);
while (first > 0 && size > 0) {
int bytes;
buf = ::read_file(file, offset, bytes=min(size, FILE_CHUNK));
size -= bytes;
offset += bytes;
/* loop through carriage returns */
while ((i=strsrch(buf, "\n")) != -1) {
buf = buf[i+1..];
if (--first <= 0)
/* found beginning */
break;
}
}
/* read lines till end */
result = ({ });
res = "";
while (num > 0 && size > 0) {
int bytes;
if (!buf) {
buf = ::read_file(file, offset, bytes=min(size, FILE_CHUNK));
size -= bytes;
offset += bytes;
}
/* loop through carriage returns */
while ((i=strsrch(buf, "\n")) != -1) {
res += buf[..i-1];
result += ({ res });
res = "";
buf = buf[i+1..];
if (--num <= 0)
/* found end */
return result;
}
res += buf;
/* read new chunk from file */
buf = 0;
}
#if 0
/* reached EOF */
if (num > 1)
/* still got some lines left */
return 0;
#endif
/* got correct result */
return result + ({ res });
}
/* read a file */
static varargs string read_file(string file, int first, int num) {
string *lines;
if (!MASTER_READ(file)) return 0;
if (!first && !num)
return ::read_file(file);
if (!(lines = read_lines(file, first, num)))
return 0;
return implode(lines, "\n");
}
/* remove a file */
static int remove_file(string file) {
if (!MASTER_WRITE(file)) return 0;
return ::remove_file(file);
}
/* remove a directory */
static int remove_dir(string file) {
if (!MASTER_WRITE(file)) return 0;
return ::remove_dir(file);
}
/* rename a file */
static int rename_file(string from, string to) {
if (!MASTER_WRITE(from)) return 0;
if (!MASTER_WRITE(to)) return 0;
::remove_file(to); /* overwrite old file */
return ::rename_file(from, to);
}
/* copy a file of any size */
static int copy_file(string from, string to) {
int size, offset;
mixed *sizes;
string buf;
if (!MASTER_READ(from)) return 0;
if (!MASTER_WRITE(to)) return 0;
/* get from filesize */
sizes = ::get_dir(from)[GDIR_SIZES];
if (::sizeof(sizes) != 1) return 0;
if ((size=sizes[0]) < 0) return 0;
::remove_file(to); /* overwrite old file */
if (size == 0) return ::write_file(to, "");
for (; offset < size; offset+=COPY_FILE_CHUNK) {
if ((buf=::read_file(from, offset, COPY_FILE_CHUNK))) {
if (!::write_file(to, buf))
return 0;
}
else
return 0;
}
return 1;
}
/* restore an object */
#ifdef MUDOS_RESTORE_OBJECT_FLAG
static varargs int restore_object(string file, int dummy) {
#else
static int restore_object(string file) {
#endif
if (!MASTER_READ(file)) return 0;
#ifdef DEFAULT_OBJ_EXTENSION
{
string s1, s2;
if (sscanf(file, "%s.%s",s1,s2) != 2)
/* add default extension */
file += DEFAULT_OBJ_EXTENSION;
}
#endif
return ::restore_object(file);
}
/* save an object */
#ifdef MUDOS_SAVE_OBJECT_FLAG
static varargs int save_object(string file, int dummy) {
#else
static int save_object(string file) {
#endif
if (!MASTER_WRITE(file)) return 0;
#ifdef DEFAULT_OBJ_EXTENSION
{
string s1, s2;
if (sscanf(file, "%s.%s",s1,s2) != 2)
/* add default extension */
file += DEFAULT_OBJ_EXTENSION;
}
#endif
::save_object(file);
return 1;
}
/* write bytes to file */
#ifdef MUDOS_WRITE_BYTES_ARGS
static int write_bytes(string file, int start, string str) {
#else
static int write_bytes(string file, string str, int start) {
#endif
int *sizes;
if (!MASTER_WRITE(file)) return 0;
if (start == 0)
/* write from start in DGD */
start = -file_size(file);
return ::write_file(file, str, start);
}
/* write string to file */
static int write_file(string file, string str) {
if (!MASTER_WRITE(file)) return 0;
return ::write_file(file, str);
}
#ifdef MUDOS_EXTRA_FILEFUNCS
/* get file info (not very good simulated) */
static varargs mixed *stat(string file, int flag) {
if (flag == -1) return get_dir(file);
if (!MASTER_READ(file)) return ({ ({}), ({}), ({}) });
return ::get_dir(file);
}
/* show a file to this_player() */
static varargs int cat(string file, int first, int num) {
string *lines;
if (num == 0)
num = CAT_LINES;
if (!(lines=read_lines(file, first, num)))
return 0;
if (::sizeof(lines) <= CAT_LINES)
write(implode(lines, "\n"));
else
write(implode(lines[0 .. CAT_LINES - 1], "\n") +
"\n***TRUNCATED***\n");
return 1;
}
/* show the tail of a file to this_player() */
static int tail(string file) {
int size, *sizes;
string str, *lines;
if (!MASTER_READ(file)) return 0;
sizes = ::get_dir(file)[GDIR_SIZES];
if (::sizeof(sizes) == 1) {
size = TAIL_CHUNK;
while (1) {
size = min(size, sizes[0]);
str = ::read_file(file, -size, size);
if (str == 0 || ::strlen(str) != size)
return 0;
lines = explode("\n" + str + "\n", "\n");
if (::sizeof(lines) >= TAIL_LINES + 1 || size == sizes[0]) {
if ((size=::sizeof(lines)) > TAIL_LINES + 1)
str = implode(lines[size - TAIL_LINES - 1 ..], "\n");
else if (size == 1)
str = lines[0];
write(str);
return 1;
}
size += TAIL_CHUNK;
}
}
return 0;
}
#endif /* MUDOS_EXTRA_FILEFUNCS */