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