// The new, more efficient, improved ls command. // Thanks to Huthar and Wayfarer for this one. // Italian added the -la options (18-11-92) // Mobydick added the help 11-13-92, using the ls.command doc file. // Hacked by Zeus to work a bit faster...by putting the output into // an array of string, and displaying it at the end using more. 29/01/92 // Modified by Zeus to use get_dir(path, -1) thus increasing the overall // speed by twofolds. // Watcher rerouted the output through the mudlib's PAGER system (4/10/93). // Fixed by Blue to be a bit faster and to work properly with wildcards // (previously something like ls /adm/daemons/*.t would give everything // in /adm/daemons). (11/5/93) (that's 11th of May for US ppl :) Also // the pager now works properly for stuff like 'ls /adm/*' #include <mudlib.h> #define spaces " " inherit DAEMON ; string *text; int show_dots, show_long, line; string *long_ls(mixed *files, string path); int is_file(mixed *file); int remove_dots(string file); void do_more(string *str); string *do_ls(mixed *files, string path) { int index,x,y,rows,cols,l,length,num,size,i; string *output; if(!files) files = ({}); if(!show_dots) files = filter_array(files, "remove_dots", this_object()); num = sizeof(files); if(!num) { return ({ "Directory is empty.\n" }); } if(show_long) return long_ls(files, path); for (index = 0; index < num; index++) { i = strlen(files[index][0]); if (i > length) length = i; } length ++; if (length > 75) length = 75; cols = 80 / (length + 5); if (!cols) cols = 1; /* filenames can be huge in un*x */ rows = num / cols; if (rows * cols < num) rows++; output = allocate(rows); for (y = 0; y < rows; y++) { output[y] = ""; for (x = 0; x < cols; x++) { index = x * rows + y; if (index > num - 1) break; size = files[index][1]; l = strlen(files[index][0]); switch(size) { case -2: output[y] += " 1 " + files[index][0] + "/"; l++; break; case -1: output[y] += " - " + files[index][0]; break; default: size /= 1024; if (size == 0) size = 1; if (size < 10) output[y] += " "; if (size < 100) output[y] += " "; output[y] += " " + size + " " + files[index][0]; break; } if (length - l > 0) output[y] += (spaces[1 .. (length - l)]); } } return output; } string *long_ls(mixed *files, string path) { int i, j; mixed *stats; string *output; int num; string tmp; num = sizeof(files); output = allocate(num+2); output[0]=" Last change Loaded Size Name"; output[1]="-------------------- -------------------- ------ -----------"; for(i=0; i<num; i++) { tmp = path + "/" + files[i][0]; j = strlen(tmp); if (file_size(tmp) == -2 || (j > 2 && tmp[j-3 .. j-1] == "/..")) output[i+2] = sprintf(spaces[0..46]+"<DIR> "+files[i][0]); else if (file_size(tmp) == -1) output[i+2] = sprintf(spaces[0..39]+"<UNREADABLE> "+files[i][0]); // The above line added 22/9/93 by Blue, to fix /adm/link problem. else { stats = stat(tmp); stats[0]=spaces[0..(8-strlen(stats[0]+" "))]+stats[0]; stats[1]=ctime(stats[1]); if(stats[2]) stats[2]=ctime(stats[2]); else stats[2]=" < not loaded > "; output[i+2] = sprintf("%s %s %s %s", stats[1][4..strlen(stats[1])], stats[2][4..strlen(stats[2])], stats[0], files[i][0]); } } return output; } void do_more(string *str) { this_player()->more( str, 1, 1 ); } int cmd_ts(string path) { mixed *Files,*Dirs; string *output; int i, num; string *wcfiles; string str1, str2, full_path; show_dots = 0; show_long = 0; seteuid(getuid(this_player())); if(path && sscanf(path,"-%s %s",str1,str2) == 2) { path = str2; switch(str1) { case "a" : show_dots = 1; break; case "l" : show_long = 1; break; case "al" : case "la" : show_long = 1; show_dots = 1; break; default : show_long = 0; show_dots = 0; } } else if(path && sscanf(path,"-%s",str1) == 1) { path = 0; switch(str1) { case "a" : show_dots = 1; break; case "l" : show_long = 1; break; case "al" : case "la" : show_long = 1; show_dots = 1; break; default : show_long = 0; show_dots = 0; } } output = ({ }); full_path = extract(resolv_path(this_player()->query("cwd"), path),1); if (file_size(full_path)==-2) { output = do_ls(get_dir(full_path+"/*", -1), full_path); do_more(output); return 1; } wcfiles = get_dir(full_path, -1); if (!wcfiles || !sizeof(wcfiles)) { write("No such file or directory.\n"); return 1; } full_path = extract(path_file(full_path)[0], 1); Files = filter_array(wcfiles, "is_file", this_object()); Dirs = wcfiles - Files; if(pointerp(Files) && sizeof(Files) > 0) { output += do_ls(wcfiles, full_path); } if(pointerp(Dirs) && sizeof(Dirs) > 0) { for(i = 0; i < sizeof(Dirs); i++) { string *ffiles; if (Dirs[i][0]=="." || Dirs[i][0]=="..") continue; output += ({ "\n"+Dirs[i][0]+":" }); ffiles = get_dir(full_path+"/"+Dirs[i][0]+"/*", -1); if (sizeof(ffiles)) output += do_ls(ffiles, full_path+"/"+Dirs[i][0]); } } do_more(output); return 1; } int is_file(mixed *file) { return(file[1] != -2); // isn't file size in field 2 from get_dir()? // and isn't it undefined for dirs? // bleah...who's to argue...this seems to work } int remove_dots(mixed *file) { if(file[0][0] == '.') return 0; return 1; } string help() { return ( "Give a list of all files in 'path'. If no argument is given, list the\n"+ "files in the current directory.\n"+ "'ls /' will give a list of all files in the root directory.\n") ; }