/** * A simplified version of the standard unix command 'ls', built for * the NS mudlib but based off similar mud variants of the command. * @author Galileo, 10-26-98. * @changed Ported to DS from the Sorrows 1.8 Mudlib, Shaydz 14-7-2000. * @changed Rewrote partly to give more sensible fail messages and * made it a little faster, Sandoz 18-5-2002. */ #define DIR_COLOR "%^BOLD%^%^BLUE%^" #define C_COLOR "%^GREEN%^" #define H_COLOR "%^CYAN%^" #define LOADED_COLOR "%^MAGENTA%^" #define RESET "%^RESET%^" inherit COMMAND_BASE; string directory_listing( string, string *, mapping ); /** @ignore yes */ string query_usage() { return "ls -adfhloFS <directory>\n\n" " -a Don't hide . and .. files\n" " -d List directory entries instead of files\n" " -f List files instead of directory entries\n" " -h Display this help and exit\n" " -l Use a long listing format\n" " -o Colorize entries\n" " -F Prepend an '*' to indicatate loaded\n" " -Sn Sort entries:\n" " d - Date\n" " e - Extension\n" " n - Name\n" " s - Size\n"; } /* query_usage() */ /** @ignore yes */ int cmd( string arg ) { int i; mapping flags; string *files, *parts; string mask, dir, tmp; if( arg ) parts = explode( arg, " ") - ({ 0, "" }); flags = ([ ]); mask = ""; dir = "."; // Cycle through each part, if it starts with an '-' assume // it's a switch, if it doesn't start with a '-' set it as the // specified directory. If we try and set the directory twice, // error out we've got a syntax problem. if( sizeof(parts) ) { foreach( tmp in parts ) { for( i = 0; i < sizeof(tmp); i++ ) { if( tmp[0] == '-') { switch( tmp[++i] ) { case 'a': flags["a"] = 1; break; case 'd': flags["d"] = 1; break; case 'f': flags["f"] = 1; break; case 'h': flags["h"] = 1; break; case 'l': flags["l"] = 1; break; case 'o': flags["o"] = 1; break; case 'F': flags["F"] = 1; break; case 'S': // Check for specified sort order if( i++ < sizeof(tmp) ) { if( tmp[i] == 'd' || tmp[i] == 'e' || tmp[i] == 'n' || tmp[i] == 's' ) { flags["S"] = 1; flags["n"] = tmp[i]; } else return notify_fail("Invalid sort order.\n" "Type 'ls -h' for help.\n"); } else { return notify_fail("No sort order was passed.\n" "Type 'ls -h' for help.\n"); } break; } } else { if( dir == ".") { dir = tmp; break; } else { return notify_fail("Only one directory may be " "listed.\nType 'ls -h' for help.\n"); } } } } } // Check for flags we need to do immediately. if( flags["h"] ) return notify_fail(query_usage());; tmp = master()->make_path_absolute(dir); dir = tmp; mask = sizeof( explode( dir, "/") ) ? explode( dir, "/")[<1] : "*"; if( !dir_exists(dir) ) { dir = implode( explode( dir, "/")[0..<2], "/"); if( !dir_exists(dir) ) return notify_fail("Directory '"+tmp+"' does not exist.\n"); } else { mask = "*"; } if( sizeof(dir) ) if( dir[<1] != '/') dir += "/"; if( !master()->valid_read( dir, geteuid(TP), "get_dir") ) return notify_fail("$I$0=ls: "+dir+": Permission denied.\n"); if( !files = get_dir( dir + mask ) ) files = get_dir(dir); if( !sizeof(files) && !dir_exists(tmp) ) return notify_fail("Directory '"+tmp+"' does not exist.\n"); if( flags["a"] ) files = filter( files, (: $1 != "." :) ); else files = filter( files, (: $1[0] != '.' :) ); if( !sizeof(files) || ( sizeof(files) == 1 && files[0] == "..") ) return notify_fail("Directory is empty.\n"); TP->more_string( directory_listing( dir, files, flags ), "ls ("+dir+")"); return 1; } /* cmd() */ /** @ignore yes */ string colorize_dir( string dir ) { return DIR_COLOR + dir + RESET; } /** @ignore yes */ string colorize_file( string file ) { switch( file[<2..] ) { case ".c": return C_COLOR + file + RESET; case ".h": return H_COLOR + file + RESET; } return file; } /* colorize_file() */ /** @ignore yes */ int date_sort( mixed arg1, mixed arg2, string dir ) { int *stat1 = stat( dir + arg1 ); int *stat2 = stat( dir + arg2 ); if( stat1[1] > stat2[1] ) return -1; else if( stat1[1] < stat2[1] ) return 1; return 0; } /* date_sort() */ /** @ignore yes */ int extension_sort( mixed arg1, mixed arg2 ) { return strcmp( arg1[<2..], arg2[<2..] ); } /* extension_sort() */ /** @ignore yes */ int size_sort( mixed arg1, mixed arg2, string dir ) { int size1 = file_size( dir + arg1 ); int size2 = file_size( dir + arg2 ); if( size1 > size2 ) return -1; else if( size1 < size2 ) return 1; return 0; } /* size_sort() */ /** @ignore yes */ int name_sort( mixed arg1, mixed arg2 ) { return strcmp( arg1, arg2 ); } /** @ignore yes */ string short_print( string *info, int max ) { int cols, rows, entry, i, j, size; string ret; ret = ""; cols = TP->query_cols() / ( max + 5 ); rows = ( ( sizeof(info) % cols ) ? ( sizeof(info) / cols ) + 1 : sizeof(info) / cols ); for( i = 0; i < rows; i++ ) { entry = i; for( j = 0; j < cols; j++ ) { if( j >= ( size = sizeof(info) ) ) return ret+"\n"; if( entry < size ) { if( ( size % cols ) < ( j + 1 ) && ( i + 1 ) == rows && ( size % cols ) ) break; ret += info[entry] + sprintf("%:"+( max + 5 - sizeof( strip_colours( info[entry] ) ) )+"s", ""); } if( rows == 1 ) entry++; else if( size % cols ) entry += ( ( size % cols ) > j ? rows : rows - 1 ); else entry += rows; } ret += "\n"; } return ret; } /* short_print() */ /** @ignore yes */ string directory_listing( string dir, string *lfiles, mapping flags ) { string r1, r2, file; string *files, *dirs; int size, max_dir_length, max_file_length; files = ({ }); dirs = ({ }); foreach( file in lfiles ) { size = file_size( dir + file ); if( size == -2 ) { dirs += ({ file }); if( sizeof(file) > max_dir_length ) max_dir_length = sizeof(file); } else if( size != -1 ) { files += ({ file }); if( sizeof(file) > max_file_length ) max_file_length = sizeof(file); } } if( !sizeof(files) && flags["f"] ) return "No files in '"+dir+"'.\n"; if( !sizeof(dirs) && flags["d"] ) return "No directories in '"+dir+"'.\n"; if( flags["S"] ) { switch( flags["n"] ) { case 'd': files = sort_array( files, "date_sort", TO, dir ); break; case 'e': files = sort_array( files, "extension_sort", TO ); break; case 'n': dirs = sort_array( files, "name_sort", TO ); files = sort_array( dirs, "name_sort", TO ); break; case 's': files = sort_array( files, "size_sort", TO, dir ); break; } } if( flags["l"] ) { r1 = "\n"; foreach( file in dirs ) { r1 += sprintf("drwx------ %-3d %-10.10s %-10.10s %8d %12s %s\n", sizeof( get_dir( dir + file + "/") ), "user", "user", 1024, "", ( flags["o"] ? colorize_dir(file)+"/" : file+"/" ) ); } if( flags["d"] ) return dir+":\n"+r1; r2 = "\n"; foreach( file in files ) { r2 += sprintf("-rw-rw---- %-3d %-10.10s %-10.10s %8d %12s %s%s\n", ( size = file_size( dir + file ) ) / 1000 + 1, "user", "user", size, ctime( stat( dir + file )[1] )[4..15], ( flags["F"] ? ( find_object( dir + file ) ? ( flags["o"] ? LOADED_COLOR+"*"+RESET : "*") : "") : ""), ( flags["o"] ? colorize_file(file) : file ) ); } if( flags["f"] ) return dir+":\n"+r2; return dir+":\n"+( sizeof(dirs) ? r1 : "")+( sizeof(files) ? r2 : ""); } else { if( flags["o"] ) { dirs = map( dirs, (: sprintf("%3d %s/", sizeof( get_dir($2+$1+"/") ), colorize_dir($1)+RESET ) :), dir ); if( flags["d"] ) return dir+":\n"+short_print( dirs, max_dir_length ); if( flags["F"] ) files = map( files, (: sprintf("%3d %s%s", file_size($2+$1) / 1000 + 1, ( find_object($2+$1) ? LOADED_COLOR+"*"+RESET : ""), colorize_file($1) ) :), dir ); else files = map( files, (: sprintf("%3d %s", file_size($2+$1) / 1000 + 1, colorize_file($1) ) :), dir ); if( flags["f"] ) return dir+":\n"+short_print( files, max_file_length ); } else { dirs = map( dirs, (: sprintf("%3d %s/", sizeof( get_dir($2+$1+"/") ), $1 ) :), dir ); if( flags["d"] ) return dir+":\n"+short_print( dirs, max_dir_length ); if( flags["F"] ) files = map( files, (: sprintf("%3d %s%s", file_size($2+$1) / 1000 + 1, ( find_object($2+$1) ? "*" : ""), $1 ) :), dir ); else files = map( files, (: sprintf("%3d %s", file_size($2+$1) / 1000 + 1, $1 ) :), dir ); if( flags["f"] ) return dir+":\n"+short_print( files, max_file_length ); } return dir+":\n"+( sizeof(dirs) ? short_print( dirs,max_dir_length)+ ( sizeof(files) ? "\n" : "") : "")+( sizeof(files) ? short_print( files, max_file_length ) : ""); } return "Directory is empty.\n"; } /* directory_listing() */