// File : /cmds/file/_less.c /* Written sometime by someone - loved by Sulam :) Modified Oct27/91 by Jubal - added pager function to call more_file Modified Nov3/91 by Jubal - tidied up format and arg passing - adjusted so that file is not kept in memory (phew) Modified Nov4/91 by Jubal - added support for LINES environment variable Modified Dec5/91 by Jubal - added more_pipe() to allow paging of strings Modified Dec12/91 by Sulam - added code to display_page() to prevent 'over-shooting' things - integrated it into the /bin system (involved adding cmd_more()) Modified Jan27/92 by Oros - added search for regular expression Modified Jan28/92 by Brian - added help Modified Jan29/92 by Jubal - fixed the security _yet_ again */ #include <config.h> #include <mudlib.h> inherit DAEMON ; #define SEARCH_LINES 500 #define LESS_HELP "/doc/mudlib/less_help" private int lines, eof, temp_file; private int top_line, page_size; private string fname, swap_file; private string rem_expr; private mixed *mark; string help(); int more_file( string file ); void pager( string file ); private int get_oid() { string junk; int oid; sscanf( file_name( this_player() ), "%s#%d", junk, oid ); return oid; } private void swap_in() { swap_file = "/tmp/moreswap" + get_oid(); temp_file = 0; mark = 0; rem_expr = 0; eof = 0; if( ! restore_object( swap_file ) ) write( "** Swap file corrupted. **\n" ); seteuid( getuid( this_player(1) ) ); } private void swap_out() { save_object( swap_file ); temp_file = 0; seteuid( "root" ); } static void write_menu_bar() { int max; max = top_line + page_size - 1; if( max > lines ) max = lines; if( fname ) write( fname + " " ); write( top_line + "-" + max + " (" + lines + ") " + ( max * 100 / lines ) + "% (help ?) " ); } static void display_page() { int n, ps; ps = page_size; if( top_line + ps > lines ) ps = lines - top_line + 1; n = cat( fname, top_line, ps ); if( top_line + n > lines ) eof = 1; } static void cont_more() { write_menu_bar(); input_to( "get_more_com" ); swap_out(); } private int get_mark( string str ) { int n; if( ! sscanf( str, "%d", n ) ) { write( "Format should be \"m#\" where # is mark number.\n" ); n = 0; } else if( n > 5 || n < 1 ) { write( "Marks must be in range 1-5.\n" ); n = 0; } return n; } private int search_string( string str ) { int tmp_line; string tmp1; string tmp2; tmp_line = top_line + page_size / 2; tmp1 = read_file( fname, tmp_line, SEARCH_LINES ); while( tmp1 && sscanf( tmp1, "%s" + str, tmp2 ) != 1 ) { tmp_line += SEARCH_LINES; tmp1 = read_file( fname, tmp_line, SEARCH_LINES ); } if( tmp2 ) { while( sscanf( tmp2, "%s\n%s",tmp1, tmp2 ) ) tmp_line++; tmp_line -= 2; return tmp_line; } return top_line; } static void get_more_com( string str ) { int n, cmd; int rem_line; string path; swap_in(); if( ! str || str == "" ) str = " "; if( sscanf( str, "%d%s", n, str ) != 2 ) n = 1; if( ! str || str == "" ) str = "G"; cmd = str[0]; str = extract( str, 1 ); switch( cmd ) { case 'G': /* goto line */ top_line = n; break; case ' ': /* next page */ if( ! eof ) { top_line += n * page_size; break; } case 'q': /* quit */ if( temp_file && sscanf( fname, "/tmp/%s", path ) == 1 ) rm( fname ); rm( swap_file + __SAVE_EXTENSION__ ); temp_file = 0; seteuid( "root" ); return; case '?': /* help */ cat ( LESS_HELP ); return cont_more(); case 'b': /* previous page */ top_line -= n * page_size; break; case 'e': /* switch files */ if( temp_file ) { write( "Cannot switch out of a temporary file.\n" ); return cont_more(); } while( str[0] == ' ' ) str = extract( str, 1 ); path = (string) this_player() -> query("cwd"); str = resolv_path("cwd", str); if( ! more_file( str ) ) { write( "File not found.\n" ); return cont_more(); } return; case 'p': /* switch page length */ if( sscanf( str, "%d ", n ) ) page_size = n; if( page_size < 1 ) page_size = 1; if( page_size > 40 ) page_size = 40; write( "Page length is now " + page_size + ".\n" ); return cont_more(); case 'm': /* mark line */ if( ! fname ) { write( "Cannot place mark here.\n" ); return cont_more(); } n = get_mark( str ); if( n ) mark[n-1] = ({ fname, top_line, lines }); return cont_more(); case 'g': /* goto mark */ n = get_mark( str ); if( ! mark[n-1] ) { write( "Mark not set.\n" ); return cont_more(); } fname = mark[n-1][0]; top_line = mark[n-1][1]; lines = mark[n-1][2]; break; case 'n': /* Search for last r.e */ if( rem_expr ) str = rem_expr; else str = ""; case '/': /* Search for a regular expresssion */ if( ! str || str == "" ) { write( "\nNo previous regular expression.\n\n" ); return cont_more(); } rem_expr = str; rem_line = top_line; top_line = search_string( str ); if( top_line == rem_line ) { write( "\nNo match.\n\n" ); return cont_more(); } break; default: write( "Unknown command.\n" ); return cont_more(); } eof = 0; if( top_line < 1 ) top_line = 1; if( top_line > lines ) top_line = lines; display_page(); cont_more(); } int more_file( string str ) { mixed data; seteuid( getuid( this_player(1) ) ); data = read_file( str ); if( ! data ) return 0; swap_file = "/tmp/moreswap" + get_oid(); fname = str; top_line = 1; rem_expr = ""; lines = sizeof( explode( data, "\n" ) ); if( ! mark ) mark = allocate( 5 ); data = this_player() -> getenv( "LINES" ); if (data) { if (stringp(data)) sscanf(data, "%d", page_size); else page_size = data; if( page_size < 1 ) page_size = 1; if( page_size > 40 ) page_size = 40; } else page_size = 20; eof = 0; display_page(); cont_more(); return 1; } varargs void more_pipe( string str, string fstr ) { seteuid( getuid( this_player(1) ) ); fname = "/tmp/" + ( fstr ? fstr : (string) this_player() -> query("name") ) + "." + get_oid(); if( file_size( fname ) > 0 ) rm( fname ); write_file( fname, str ); temp_file = 1; more_file( fname ); } void pager( string str ) { more_file( str ); } int cmd_less( string arg ) { string more; object more_ob; seteuid( getuid( this_player(1) ) ); if( ! arg || arg == "" ) return write(help()), 1; more = (string) this_player() -> getenv("PAGER"); if( ! more ) more = "/cmds/file/_less"; more_ob = find_object( more ); arg = resolv_path( (string) this_player() -> query("cwd"), arg ); if( file_size( arg ) < 0 ) { notify_fail( arg + ": file not found.\n" ); return 0; } if( ! more_ob || more_ob == this_object() ) more_file( arg ); else more_ob -> pager( arg ); return 1; } string help() { return( "Command: more\nSyntax: more <filename>\n" + "This command lets you use more to read a file. This means\n" + "that the file will be displayed one screenful at a time. \n" + "You may call up the nest screenful by hitting <ENTER>. If\n" + "you want to goto a specific line then type that in and hit\n" + "<ENTER>. You can get further help from within more by using\n" + "the ? command.\n" ); } /* EOF */