tmi2_fluffos_v2/
tmi2_fluffos_v2/bin/
tmi2_fluffos_v2/etc/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/ChangeLog.old/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/Win32/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/compat/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/compat/simuls/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/include/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/clone/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/command/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/data/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/etc/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/include/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/inherit/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/inherit/master/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/log/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/single/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/single/tests/compiler/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/single/tests/efuns/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/single/tests/operators/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/u/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/tmp/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/windows/
tmi2_fluffos_v2/lib/
tmi2_fluffos_v2/lib/adm/
tmi2_fluffos_v2/lib/adm/daemons/languages/
tmi2_fluffos_v2/lib/adm/daemons/network/I3/
tmi2_fluffos_v2/lib/adm/daemons/virtual/
tmi2_fluffos_v2/lib/adm/daemons/virtual/template/
tmi2_fluffos_v2/lib/adm/news/
tmi2_fluffos_v2/lib/adm/obj/
tmi2_fluffos_v2/lib/adm/obj/master/
tmi2_fluffos_v2/lib/adm/priv/
tmi2_fluffos_v2/lib/adm/shell/
tmi2_fluffos_v2/lib/adm/tmp/
tmi2_fluffos_v2/lib/cmds/
tmi2_fluffos_v2/lib/d/
tmi2_fluffos_v2/lib/d/Conf/
tmi2_fluffos_v2/lib/d/Conf/adm/
tmi2_fluffos_v2/lib/d/Conf/boards/
tmi2_fluffos_v2/lib/d/Conf/cmds/
tmi2_fluffos_v2/lib/d/Conf/data/
tmi2_fluffos_v2/lib/d/Conf/logs/
tmi2_fluffos_v2/lib/d/Conf/obj/
tmi2_fluffos_v2/lib/d/Conf/text/help/
tmi2_fluffos_v2/lib/d/Fooland/adm/
tmi2_fluffos_v2/lib/d/Fooland/data/
tmi2_fluffos_v2/lib/d/Fooland/data/attic/
tmi2_fluffos_v2/lib/d/Fooland/items/
tmi2_fluffos_v2/lib/d/TMI/
tmi2_fluffos_v2/lib/d/TMI/adm/
tmi2_fluffos_v2/lib/d/TMI/boards/
tmi2_fluffos_v2/lib/d/TMI/data/
tmi2_fluffos_v2/lib/d/TMI/rooms/
tmi2_fluffos_v2/lib/d/grid/
tmi2_fluffos_v2/lib/d/grid/adm/
tmi2_fluffos_v2/lib/d/grid/data/
tmi2_fluffos_v2/lib/d/std/
tmi2_fluffos_v2/lib/d/std/adm/
tmi2_fluffos_v2/lib/data/adm/
tmi2_fluffos_v2/lib/data/adm/daemons/
tmi2_fluffos_v2/lib/data/adm/daemons/doc_d/
tmi2_fluffos_v2/lib/data/adm/daemons/emoted/
tmi2_fluffos_v2/lib/data/adm/daemons/network/http/
tmi2_fluffos_v2/lib/data/adm/daemons/network/services/mail_q/
tmi2_fluffos_v2/lib/data/adm/daemons/network/smtp/
tmi2_fluffos_v2/lib/data/adm/daemons/news/archives/
tmi2_fluffos_v2/lib/data/attic/connection/
tmi2_fluffos_v2/lib/data/attic/user/
tmi2_fluffos_v2/lib/data/std/connection/b/
tmi2_fluffos_v2/lib/data/std/connection/l/
tmi2_fluffos_v2/lib/data/std/user/a/
tmi2_fluffos_v2/lib/data/std/user/b/
tmi2_fluffos_v2/lib/data/std/user/d/
tmi2_fluffos_v2/lib/data/std/user/f/
tmi2_fluffos_v2/lib/data/std/user/l/
tmi2_fluffos_v2/lib/data/std/user/x/
tmi2_fluffos_v2/lib/data/u/d/dm/working/doc_d/
tmi2_fluffos_v2/lib/data/u/l/leto/doc_d/
tmi2_fluffos_v2/lib/data/u/l/leto/smtp/
tmi2_fluffos_v2/lib/doc/
tmi2_fluffos_v2/lib/doc/driverdoc/applies/
tmi2_fluffos_v2/lib/doc/driverdoc/applies/interactive/
tmi2_fluffos_v2/lib/doc/driverdoc/concepts/
tmi2_fluffos_v2/lib/doc/driverdoc/driver/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/arrays/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/buffers/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/compile/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/ed/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/filesystem/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/floats/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/functions/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/general/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/mappings/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/numbers/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/parsing/
tmi2_fluffos_v2/lib/doc/driverdoc/lpc/constructs/
tmi2_fluffos_v2/lib/doc/driverdoc/lpc/preprocessor/
tmi2_fluffos_v2/lib/doc/driverdoc/lpc/types/
tmi2_fluffos_v2/lib/doc/driverdoc/platforms/
tmi2_fluffos_v2/lib/doc/mudlib/
tmi2_fluffos_v2/lib/ftp/
tmi2_fluffos_v2/lib/include/driver/
tmi2_fluffos_v2/lib/log/
tmi2_fluffos_v2/lib/log/driver/
tmi2_fluffos_v2/lib/obj/net/
tmi2_fluffos_v2/lib/obj/shells/
tmi2_fluffos_v2/lib/obj/tools/
tmi2_fluffos_v2/lib/std/adt/
tmi2_fluffos_v2/lib/std/board/
tmi2_fluffos_v2/lib/std/body/
tmi2_fluffos_v2/lib/std/fun/
tmi2_fluffos_v2/lib/std/living/
tmi2_fluffos_v2/lib/std/object/
tmi2_fluffos_v2/lib/std/shop/
tmi2_fluffos_v2/lib/std/socket/
tmi2_fluffos_v2/lib/std/user/
tmi2_fluffos_v2/lib/std/virtual/
tmi2_fluffos_v2/lib/student/
tmi2_fluffos_v2/lib/student/kalypso/
tmi2_fluffos_v2/lib/student/kalypso/armor/
tmi2_fluffos_v2/lib/student/kalypso/rooms/
tmi2_fluffos_v2/lib/student/kalypso/weapons/
tmi2_fluffos_v2/lib/u/l/leto/
tmi2_fluffos_v2/lib/u/l/leto/cmds/
tmi2_fluffos_v2/lib/www/errors/
tmi2_fluffos_v2/lib/www/gateways/
tmi2_fluffos_v2/lib/www/images/
tmi2_fluffos_v2/old/
tmi2_fluffos_v2/win32/
int atoi(string a) { return to_int(a); }
/*
 * Unix-style find
 *
 * Author:	Zak (Luke Mewburn - zak@rmit.edu.au)
 * Date:	930205 00:43
 *
 *  This file is Copyright (C) 1992, 1993, Luke Mewburn. You are free
 * to distribute this file as long as it is not sold for profit,
 * and this header is not removed.
 *
 */

#define VERSION "1.0 930307"

/*
 * Notes:
 *
 * Requires:
 *  - MudOS 0.9.14 or greater.
 *  - get_dir(path, -1) (res of format: file, mtime, size)
 *  - printf() efun.
 *  - match_string (interface to match_string() in file.c)
 *     (if unavailable, uncomment code around `case "-name":' in find_the_way())
 *	(Note: now have simul_efun() for match_string() if necessary)
 *
 * Todo:
 *  - add -mmin, expr grouping.
 *  - fix -ok (currently it doesn't get confirmation)
 *
 */
 
#include <config.h>
#include <mudlib.h>
inherit DAEMON;

#define DIR_NAM	0	// offset in get_dir result for name
#define DIR_SIZ	1	// offset in get_dir result for size
#define DIR_MOD	2	// offset in get_dir result for last modification

#define STAT_SIZ 0	// offset in stat result for size
#define STAT_MOD 1	// offset in stat result for last modification

    // guess who wants enums... :)
#define EXPR_EXPR	1
#define EXPR_NOT	2
#define EXPR_GRTR	4
#define EXPR_LESS	8
#define EXPR_EQUAL	16

#define FLAG_CONFIRM	1
#define FLAG_DEBUG	2


#define EOL_CHAR "\\;"

#define error_rep(err)	printf( "%s: %s\n", query_verb(), err );

static mixed *	commands;
static object	act_ob;
static int	flags;

//
// Format of commands array:
//
//  ({
//     ({ path }) [ ({ expr, pred, args }) .. ] 
//        . . . 
//  })
//  

void parse_opts( string path, string str )
{
    mixed	*stbuf;
    string	cur, arg, *list, tstr;
    int		x, max, expr, cpos, today, t, no_print;

    list = explode( str, " " );
    max = sizeof( list );
    commands = ({ ({ path }) });
    cpos = 0;
    expr = 0;
    no_print = 0;
    today = time();

    for ( x = 0; x < max; x++ )
    {
	if ( !list[x] )
	    continue;
	cur = list[x];
	if (x < max -1 )
	    arg = list[x + 1];
	else
	    arg = 0;
	if ( cur == "!" )
	{
	    if ( !arg )
	    {
		error_rep("Invalid expression after !.");
		return 0;
	    }
	    expr |= EXPR_EXPR;
	    expr ^= EXPR_NOT;
	    continue;
	}
	switch( cur )
	{
            case "-debug":
                if ( expr & EXPR_NOT )
                    flags &= ~FLAG_DEBUG;
                else
                    flags |= FLAG_DEBUG;
                arg = 0;
                break;
	    case "-print":
	    case "-ls":
		no_print++;
	    case "-prune":
		arg = 0;
		break;
	    case "-type":
		if ( arg != "d" && arg != "f")
		{
		    error_rep("Argument to -type must be d or f.");
		    return 0;
		}
		break;
            case "-path":
		if ( !arg )
		{
		    error_rep("Expect argument after -path");
		    return 0;
		}
		arg = resolv_path( (string) act_ob->query("cwd"), arg ) + "/";
		break;
	    case "-newer":
		if ( !arg )
		{
		    error_rep("Expect argument after -newer");
		    return 0;
		}
		tstr = resolv_path( (string) act_ob->query("cwd"), arg );
		stbuf = stat( tstr );
		if ( ( sizeof( stbuf ) != 3 ) || ( stbuf[ STAT_MOD ] < 0 ) )
		{
		    error_rep("Argument to -newer must be a file");
		    return 0;
		}
		expr |= EXPR_GRTR;
		arg = "" + stbuf[ STAT_MOD ];
		break;
	    case "-size":
		if ( !arg
		    || arg[0] != '+' && arg[0] != '-' 
			&& ! (arg[0] >= '0' && arg[0] <= '9' )
		    || sscanf( arg + " ", "%d%s", t, tstr ) != 2
		    || tstr != " " && tstr != "c " && tstr != "k "
		    )
		{
		    error_rep("Invalid argument to -size");
		    return 0;
		}
		if ( arg[0] == '+' )
		    expr |= EXPR_GRTR;
		else
		    if ( arg[0] == '-' )
			expr |= EXPR_LESS;
		    else
			expr |= EXPR_EQUAL;
		if ( t < 0 )
		    t = -t;		// ensure value is +ve
		if ( tstr == " " )
		    tstr = "b ";	// b == block
		arg = tstr[0..0] + t;
		break;
	    case "-mtime":
		if ( !arg
		    || arg[0] != '+' && arg[0] != '-' 
			&& ! (arg[0] >= '0' && arg[0] <= '9' )
		    || sscanf( arg + " ", "%d%s", t, tstr ) != 2
		    || tstr != " "
		    )
		{
		    error_rep("Invalid argument to -mtime");
		    return 0;
		}
		if ( arg[0] == '+' )
		    expr |= EXPR_LESS;
		else
		    if ( arg[0] == '-' )
			expr |= EXPR_GRTR;
		    else
			expr |= EXPR_EQUAL;
		if ( t < 0 )
		    t = -t;		// ensure value is +ve
		t = today - t * 60 * 60 * 24;
		arg = "" + t;
		break;
	    case "-exec":
	    case "-ok":
		no_print++;
		for (t = x + 1 ; t < max ; t++ )
		    if ( list[t] == EOL_CHAR )
			break;
		if ( t >= max )
		{
		    error_rep("Expect " + EOL_CHAR + " after expression to " + cur);
		    return 0;
		}
		arg = implode( list[x + 1 .. t - 1], " " );
		x = t;
		break;
	    case "-name":
	    case "-author":
	    case "-user":
	    case "-domain":
	    case "-group":
	    case "-uid":
		if ( !arg )
		{
		    error_rep("Expect argument after " + cur);
		    return 0;
		}
		break;
	    default:
		if ( cur[0] == '-' )
		{
		    error_rep("Invalid predicate `" + cur + "'");
		    return 0;
		}
		if ( expr & EXPR_EXPR )
		{
		    error_rep("Paths must precede expression.");
		    return 0;
		}
		if ( ! no_print )	// default -print.
		    commands[ cpos ] += ({ 0, "-print", 0 });
		no_print = 0;
		expr = 0;
		commands += ({ ({ cur }) });
		cpos++;
		continue;
	} // switch
	commands[cpos] += ({ expr, cur, arg });
	expr = 0;
	if (arg)
	    x++;
    } // for
    if ( ! no_print )	// default -print.
	commands[ cpos ] += ({ 0, "-print", 0 });
} // parse_opts


void debug_command( int pos )
{
    int x;
    if ( sizeof( commands[ pos ] ) <= 1 )
    {
	write("No commands.\n");
	return;
    }
    printf( "Path is: %s\n", commands[pos][ 0 ] );
    for ( x = 1; x < sizeof( commands[pos] ); x+= 3 )
    {
	printf( "%d: %s %s", x, commands[pos][x + 1], commands[pos][x + 2] );
	if ( commands[pos][x] & EXPR_NOT )
	    write( "  [NOT]");
	if ( commands[pos][x] & EXPR_GRTR )
	    write( "  >n");
	if ( commands[pos][x] & EXPR_LESS )
	    write( "  <n");
	write("\n");
    }
} // debug_command


void conf_cmd_res( string res )
{
    if ( !res )
	return;
    if ( lower_case( res[ 0..0 ] ) == "y" )
	flags |= FLAG_CONFIRM;
} // conf_cmd_res

void confirm_cmd( string cmd, string path, string file)
{
    flags ^= FLAG_CONFIRM;
    printf( "< %s ... %s%s >?", cmd, path, file );
    input_to( "conf_cmd_res", 0 );
} // confirm_cmd


void find_the_way( int pos, string cwd, string path )
{
    mixed *dir;
    string curpath, tstr;
    int sx, x, sy, y;
    int res, dif, prune, sixmonths;

    curpath = path;
    if ( curpath != "/" )
	curpath += "/";
    path = resolv_path( cwd, path );
    if ( path != "/" )
	path += "/.";
    dir = get_dir( path, -1 );
    sx = sizeof( dir );
    sy = sizeof( commands[ pos ] );
    prune = 0;
    sixmonths = time() - 60*60*24*30*6;
    for ( x = 0; x < sx; x++ )
    {
	for ( y = 1; y < sy; y+= 3 )
	{
	    res = 0;
	    switch ( commands[ pos ][ y + 1 ] )
	    {
		case "-print":
		    printf( "%s%s\n", curpath, dir[ x ][ DIR_NAM ] );
                    	// fall thru.
                case "-debug":
		    res = ( ! ( commands[ pos ][ y ] & EXPR_NOT ) );
			    // force TRUE
		    break;
		case "-ls":
		    tstr = ctime( (int) dir[ x ][ DIR_MOD ] );
	    // if file older than 6 months, use year instead of hh:mm
		    if ( dir[ x ][ DIR_MOD ] < sixmonths )
			tstr = tstr[ 4..9 ] + tstr[ 19..23 ];
		    else
			tstr = tstr[ 4..15 ];
		    printf("% 7d  %s  %s%s\n", dir[ x ][DIR_SIZ], tstr, curpath, dir[ x ][DIR_NAM]);
		    res = ( ! ( commands[ pos ][ y ] & EXPR_NOT ) );
			    // force TRUE
		    break;
		case "-type":
		    if ( ( commands[ pos ][ y + 2 ] == "f" && dir[ x ][ DIR_SIZ ] >= 0 )
		      || ( commands[ pos ][ y + 2 ] == "d" && dir[ x ][ DIR_SIZ ] < 0 ) )
			res = 1;
		    break;
		case "-newer":
		case "-mtime":
		case "-size":
		    if ( commands[ pos ][ y + 1 ] == "-size" )
		    {
			dif = dir[ x ][ DIR_SIZ ];
			if ( commands[ pos ][ y + 2 ][ 0 ] == 'b' ) 
			{
			    dif = ( dif + 511 ) >> 9;
				// round up to nearest block
			}
			else
			    if ( commands[ pos ][ y + 2 ][ 0 ] == 'k' ) 
			    {
				dif = ( dif + 1023 ) >> 10;
				    // round to nearest K
			    }
			dif -= atoi( extract( commands[ pos ][ y + 2 ], 1 ) );
		    }
		    else
			dif = dir[ x ][ DIR_MOD ] - atoi( commands[ pos ][ y + 2 ] );
		    if ( ( dif < 0 ) && ( commands[ pos ][ y ] & EXPR_LESS )
		      || ( dif > 0 ) && ( commands[ pos ][ y ] & EXPR_GRTR )
		      || ( dif == 0 ) && ( commands[ pos ][ y ] & EXPR_EQUAL ) )
			res = 1;
		    break;
		case "-ok":
// ignore confirmation for now.
//		    confirm_cmd( commands[ pos ][ y + 1 ], curpath, commands[ pos ][ y + 2] );
//		    if ( ! ( flags & FLAG_CONFIRM ) )
//			break;
		    // fall thru
		case "-exec":
		    tstr = replace_string( commands[ pos ][ y + 2 ],
				"{}", curpath + dir[ x ][ DIR_NAM ] );
		    res = act_ob->force_me( tstr );
		    break;
		case "-name":
		    res = match_string( commands[ pos ][ y + 2 ], dir[ x ][ DIR_NAM ] );
// uncomment below if no match_string() available
//		    res = ( commands[ pos ][ y + 2 ]== dir[ x ][ DIR_NAM ] );
		    break;
		case "-path":
		    tstr = ( path == "/" ?  path :
					    path[ 0..strlen( path ) - 2 ] );
		    res = match_string( commands[ pos ][ y + 2 ], tstr );
// uncomment below if no match_string() available
//		    res = ( tstr == commands[ pos ][ y + 2 ] );
		    break;
		case "-prune":
		    res = ( ! ( commands[ pos ][ y ] & EXPR_NOT ) );
			// force TRUE
		    prune = 1;
		    break;
		case "-author":
		case "-user":
		    tstr = MASTER_OB->author_file( curpath + dir[ x ][ DIR_NAM ] );
		    res = ( commands[ pos ][ y + 2 ] == tstr );
		    break;
		case "-domain":
		case "-group":
		    tstr = MASTER_OB->domain_file( curpath + dir[ x ][ DIR_NAM ] );
		    res = ( commands[ pos ][ y + 2 ] == tstr );
		    break;
		case "-uid":
		    tstr = MASTER_OB->creator_file( curpath + dir[ x ][ DIR_NAM ] );
		    res = ( commands[ pos ][ y + 2 ] == tstr );
		    break;
		default:
			// for predicates we forgot to code for.
		    printf( "%s: %s%s\n", commands[ pos ][ y + 1 ], curpath, dir[ x ][ DIR_NAM ] );
		    break;
	    } // switch
	    if ( commands[ pos ][ y ] & EXPR_NOT )
		res = !res;
	    if ( !res )
		break;
	} // for commands
	if ( ( dir[ x ][ DIR_SIZ ] == -2 ) && ( !prune ) )	// recurse dirs
	{
	    find_the_way( pos, cwd, curpath + dir[ x ][ DIR_NAM ] );
	    continue;
	}
    } // for x .. dir
} // find_the_way


int cmd_find( string str )
{
    string path, pred, cwd;
    int    x;

    act_ob = this_player();
    if ( !adminp(geteuid(this_player(1))) )
    {
        write("Sorry, due to the fact that this command eats lots of CPU, only admins\nan use it.\n");
        return 1;
    }
    seteuid( getuid( act_ob ) );

    if ( !str || str == "" )
    {
	notify_fail( "Usage: find path [ predicates ] ...\n" );
	return 0;
    }
    if ( sscanf( str, "%s %s", path, pred ) != 2 )
    {
	path = str;
	pred = "";
    }
    parse_opts( path, pred );
    if ( ! commands )
	return 1;			// it failed
    cwd = (string) previous_object()->query( "cwd" );
    for ( x = 0; x < sizeof( commands ); x++ )
    {
	if ( flags & FLAG_DEBUG )
	    debug_command( x );
	find_the_way( x, cwd, commands[ x ][ 0 ] );
    }
    return 1;
} // find


string help( string str )
{
    return "\
Usage: find path predicates\n\
\n\
path       - directory to begin the search from.\n\
predicates - list of commands which determine all must be true if further\n\
	     actions are to be performed upon the current file.\n\
\n\
Predicates supported include:\n\
!		inverts the result of the following expression.\n\
-name expr      true if current file matches expr\n\
-path dir	true if dir matches preceeding path of current file\n\
-print          print current match (is always true)\n\
-ls             print current match as long listing (is always true)\n\
-prune		don't descend into subtree (always true)\n\
-type (d|f)     true if file is of correct type (d == dir, f == file)\n\
-newer cmpfil	true if file is newer than cmpfil\n\
-mtime n	true if file modified n days ago\n\
-size n[ck]	true if file of size n 512byte blocks [c=byte, k=Kbyte]\n\
-author wiz	true if file is owned by wiz\n\
-user wiz	as -author\n\
-domain dom	true if file is in domain dom\n\
-group dom	as -domain\n\
-uid id		true if file has uid id (only at load time)\n\
-exec cmd " + EOL_CHAR + "    executes command cmd. True if commands returns non-zero\n\
		result. Occurances of {} in cmd will be replaced by the\n\
		current filename.\n\
-ok cmd " + EOL_CHAR + "      as -exec, but displays the command which will be executed\n\
		and prompts with for a confirmation of each action.\n\
\n\
'n' as an argument is 'n' for exactly n, '-n' for < n, and '+n' for > n.\n\
\n\
This command was written by Zak, version " +VERSION+ ". Send all comments to:\n\
zak@rmit.edu.au\n\
\n\
Warning!:  -ok  doesn't actually ask for confirmation in this\n\
version, it just acts as -exec.\n\
";
} // help