/* GNU ed - The GNU line editor.
Copyright (C) 2006, 2007, 2008, 2009 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
/*
Return values: 0 for a normal exit, 1 for environmental problems
(file not found, invalid flags, I/O errors, etc), 2 to indicate a
corrupt or invalid input file, 3 for an internal consistency error
(eg, bug) which caused ed to panic.
*/
/*
* CREDITS
*
* This program is based on the editor algorithm described in
* Brian W. Kernighan and P. J. Plauger's book "Software Tools
* in Pascal," Addison-Wesley, 1981.
*
* The buffering algorithm is attributed to Rodney Ruddock of
* the University of Guelph, Guelph, Ontario.
*
*/
#include
#include
#include
#include
#include
#include "carg_parser.h"
#include "ed.h"
static const char * invocation_name = 0;
static const char * const Program_name = "GNU Ed";
static const char * const program_name = "ed";
static const char * const program_year = "2009";
static char restricted_ = 0; /* invoked as "red" */
static char scripted_ = 0; /* if set, suppress diagnostics */
static char traditional_ = 0; /* if set, be backwards compatible */
char restricted( void ) { return restricted_; }
char scripted( void ) { return scripted_; }
char traditional( void ) { return traditional_; }
static void show_help( void )
{
printf( "%s - The GNU line editor.\n", Program_name );
printf( "\nUsage: %s [options] [file]\n", invocation_name );
printf( "\nOptions:\n" );
printf( " -h, --help display this help and exit\n" );
printf( " -V, --version output version information and exit\n" );
printf( " -G, --traditional run in compatibility mode\n" );
printf( " -l, --loose-exit-status exit with 0 status even if a command fails\n" );
printf( " -p, --prompt=STRING use STRING as an interactive prompt\n" );
printf( " -s, --quiet, --silent suppress diagnostics\n" );
printf( " -v, --verbose be verbose\n" );
printf( "Start edit by reading in `file' if given. Read output of shell command\n" );
printf( "if `file' begins with a `!'.\n" );
printf( "\nReport bugs to .\n" );
printf( "Ed home page: http://www.gnu.org/software/ed/ed.html\n" );
printf( "General help using GNU software: http://www.gnu.org/gethelp\n" );
}
static void show_version( void )
{
printf( "%s %s\n", Program_name, PROGVERSION );
printf( "Copyright (C) 1994 Andrew L. Moore, %s Antonio Diaz Diaz.\n", program_year );
printf( "License GPLv3+: GNU GPL version 3 or later \n" );
printf( "This is free software: you are free to change and redistribute it.\n" );
printf( "There is NO WARRANTY, to the extent permitted by law.\n" );
}
void show_strerror( const char *filename, int errcode )
{
if( !scripted_ )
{
if( filename && filename[0] != 0 )
fprintf( stderr, "%s: ", filename );
fprintf( stderr, "%s\n", strerror( errcode ) );
}
}
static void show_error( const char * msg, const int errcode, const char help )
{
if( msg && msg[0] != 0 )
{
fprintf( stderr, "%s: %s", program_name, msg );
if( errcode > 0 ) fprintf( stderr, ": %s", strerror( errcode ) );
fprintf( stderr, "\n" );
}
if( help && invocation_name && invocation_name[0] != 0 )
fprintf( stderr, "Try `%s --help' for more information.\n", invocation_name );
}
/* return true if file descriptor is a regular file */
char is_regular_file( int fd )
{
struct stat sb;
return ( fstat( fd, &sb ) < 0 || S_ISREG( sb.st_mode ) );
}
char may_access_filename( const char *name )
{
if( restricted_ && ( *name == '!' || !strcmp( name, ".." ) || strchr( name, '/' ) ) )
{
set_error_msg( "Shell access restricted" );
return 0;
}
return 1;
}
int main( const int argc, const char *argv[] )
{
int n = strlen( argv[0] );
char loose = 0;
const ap_Option options[] =
{
{ 'G', "traditional", ap_no },
{ 'h', "help", ap_no },
{ 'l', "loose-exit-status", ap_no },
{ 'p', "prompt", ap_yes },
{ 's', "quiet", ap_no },
{ 's', "silent", ap_no },
{ 'v', "verbose", ap_no },
{ 'V', "version", ap_no },
{ 0, 0, ap_no } };
Arg_parser parser;
int argind;
if( !ap_init( &parser, argc, argv, options, 0 ) )
{ show_error( "Memory exhausted", 0, 0 ); return 1; }
if( ap_error( &parser ) ) /* bad option */
{ show_error( ap_error( &parser ), 0, 1 ); return 1; }
invocation_name = argv[0];
restricted_ = ( n > 2 && argv[0][n-3] == 'r' );
for( argind = 0; argind < ap_arguments( &parser ); ++argind )
{
const int code = ap_code( &parser, argind );
const char * arg = ap_argument( &parser, argind );
if( !code ) break; /* no more options */
switch( code )
{
case 'G': traditional_ = 1; break; /* backward compatibility */
case 'h': show_help(); return 0;
case 'l': loose = 1; break;
case 'p': set_prompt( arg ); break;
case 's': scripted_ = 1; break;
case 'v': set_verbose(); break;
case 'V': show_version(); return 0;
default: show_error( "internal_error: uncaught option", 0, 0 ); return 3;
}
}
setlocale( LC_ALL, "" );
if( !init_buffers() ) return 1;
while( argind < ap_arguments( &parser ) )
{
const char * arg = ap_argument( &parser, argind );
if( !strcmp( arg, "-" ) ) { scripted_ = 1; ++argind; continue; }
if( may_access_filename( arg ) )
{
if( read_file( arg, 0 ) < 0 && is_regular_file( 0 ) )
return 2;
else if( arg[0] != '!' ) set_def_filename( arg );
}
else
{
fputs( "?\n", stderr );
if( arg[0] ) set_error_msg( "Invalid filename" );
if( is_regular_file( 0 ) ) return 2;
}
break;
}
ap_free( &parser );
return main_loop( loose );
}