// File : /cmds/xtra/_grep.c
// Creator : Watcher@TMI-2 (04/26/93)
//
// This is a new and improved grep command that will even
// accept directories, piping, and argument flags.
#include <mudlib.h>
inherit DAEMON;
static int grep_file(string pattern, string file, int count, int lnnum,
int nomat, int exact);
#define SYNTAX "Syntax: grep [-cnvx] [pattern] [file | directory]\n" + \
" grep [-cnvx] [pattern] [file | directory] > [file]\n"
static mixed *hold;
static int matches, busy;
int cmd_grep(string str) {
string *files, pattern, pipe, where, flag, tmp1, tmp2;
int count, lnnum, nomat, exact, loop;
notify_fail( SYNTAX );
if(!str || str == "") return 0;
// Check for piping to a file.
if(sscanf(str, "%s > %s", str, pipe) == 2)
pipe = resolv_path("cwd", pipe);
// Check for argument flags (c,n,v,x)
if(sscanf(str, "-%s %s", flag, str) == 2) {
if(sscanf(" " + flag + " ", "%sc%s", tmp1, tmp2) == 2) count = 1;
if(sscanf(" " + flag + " ", "%sn%s", tmp1, tmp2) == 2) lnnum = 1;
if(sscanf(" " + flag + " ", "%sv%s", tmp1, tmp2) == 2) nomat = 1;
if(sscanf(" " + flag + " ", "%sx%s", tmp1, tmp2) == 2) exact = 1;
}
// Added support for bracing with "arg" - Brainstorm
if(sscanf(str, "\"%s\" %s", pattern, where) != 2 )
if(sscanf(str, "%s %s", pattern, where) != 2) return 0;
if(busy) {
write("The grep command is presently busy. Please try again shortly.\n");
return 1; }
if(nomat && exact) {
write("Grep: Cannot specify both the v and x options.\n");
return 1; }
seteuid(getuid(this_player()));
// Reset grep status variables.
hold = ({ }); matches = 0;
// Complete the path of the location request.
// where = resolv_path("cwd", where);
// Get array of all possible location matches.
files = (string *)this_player()->wild_card(where);
if(!files || !sizeof(files)) {
notify_fail("Grep: No such file pattern found.\n");
return 0; }
// Check to see if the request is a directory.
if(sizeof(files) == 1 && directory_exists(files[0])) {
files = (string *)this_player()->wild_card(files[0] + "/*");
if(!files || !sizeof(files)) {
notify_fail("Grep: Directory is empty.\n");
return 0; }
}
// Activate busy flag to prevent data overwriting.
busy = 1;
// Loop through and grep each selected file.
for(loop=0; loop<sizeof(files); loop++)
if(catch(grep_file(pattern, files[loop], count, lnnum, nomat, exact)))
write("Grep: An evaluation error has occurred. Grep is incomplete.\n");
// Give the resulting output ...
if(!hold || !sizeof(hold) || hold == ({}))
write("Grep: No pattern matches found.\n");
else if(count)
write("Grep: " + matches + " line" + (matches == 1 ? " has " : "s have ") +
"pattern matches.\n");
else if(pipe) {
if(!master()->valid_write(pipe, geteuid(this_player()), "grep"))
write("Grep: Access denied in " + pipe + ".\n");
else {
if(!write_file(pipe, implode(hold, "\n")))
write("Grep: Failed to pipe pattern matches to " + pipe + ".\n");
else write("Grep: Pattern matches piped to " + pipe + ".\n");
}
}
else this_player()->more( hold );
// All done with the grep ... remove busy flag.
busy = 0;
return 1; }
static int grep_file(string pattern, string file, int count, int lnnum,
int nomat, int exact) {
string *lines, *tmp, *diff, dump;
int loop;
dump = read_file( file );
if(!dump) {
notify_fail("Grep: " + file + " not found.\n");
return 0; }
lines = explode(dump, "\n");
for(loop=0; loop<sizeof(lines); loop++) {
if(exact) {
if(lines[loop] == pattern) {
if(!tmp) tmp = ({ "[" + file + "]" });
tmp += ({ (lnnum ? (loop+1) + ":" : "") + lines[loop] });
matches++; }
continue; }
if(sizeof(regexp( ({ lines[loop] }), pattern))) {
if(nomat) continue;
if(!tmp) tmp = ({ "[" + file + "]" });
tmp += ({ (lnnum ? (loop+1) + ":" : "") + lines[loop] });
matches++; }
else if(nomat) {
if(!tmp) tmp = ({ "[" + file + "]" });
tmp += ({ (lnnum ? (loop+1) + ":" : "") + lines[loop] });
matches++; }
}
if(tmp) hold += tmp + ({ "" });
return 1; }
string help() {
return( SYNTAX + "\n" +
"The grep command allows you to produce a list of all lines within a\n" +
"named file or directory of files that matches the given pattern. It\n" +
"supports the regular expression patterns used by the regexp() efun, and\n"+
"allows the use of the unix c, n, v, and x flags. If the c flag is used\n"+
"only a count of matching lines found will be displayed. The n flag\n" +
"causes all matching lines to be prepened with that line's corresponding\n"+
"line number. The v flag results in an output of all those lines that\n" +
"do not match the requested pattern, and the x flag results in an output\n"+
"of only those lines that exactly match the requested pattern. You may\n"+
"also pipe the output into a file with the \" > [file]\" ending.\n");
}