|
Packit |
4e1bf9 |
/* GNU ed - The GNU line editor.
|
|
Packit |
4e1bf9 |
Copyright (C) 1993, 1994 Andrew Moore, Talke Studio
|
|
Packit |
4e1bf9 |
Copyright (C) 2006-2017 Antonio Diaz Diaz.
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
This program is free software: you can redistribute it and/or modify
|
|
Packit |
4e1bf9 |
it under the terms of the GNU General Public License as published by
|
|
Packit |
4e1bf9 |
the Free Software Foundation, either version 2 of the License, or
|
|
Packit |
4e1bf9 |
(at your option) any later version.
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
This program is distributed in the hope that it will be useful,
|
|
Packit |
4e1bf9 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
4e1bf9 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
4e1bf9 |
GNU General Public License for more details.
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
You should have received a copy of the GNU General Public License
|
|
Packit |
4e1bf9 |
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
4e1bf9 |
*/
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
#include <ctype.h>
|
|
Packit |
4e1bf9 |
#include <setjmp.h>
|
|
Packit |
4e1bf9 |
#include <stdio.h>
|
|
Packit |
4e1bf9 |
#include <stdlib.h>
|
|
Packit |
4e1bf9 |
#include <string.h>
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
#include "ed.h"
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
enum Status { QUIT = -1, ERR = -2, EMOD = -3, FATAL = -4 };
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
static char def_filename[1024] = ""; /* default filename */
|
|
Packit |
4e1bf9 |
static char errmsg[80] = ""; /* error message buffer */
|
|
Packit |
4e1bf9 |
static char prompt_str[80] = "*"; /* command prompt */
|
|
Packit |
4e1bf9 |
static int first_addr = 0, second_addr = 0;
|
|
Packit |
4e1bf9 |
static bool prompt_on = false; /* if set, show command prompt */
|
|
Packit |
4e1bf9 |
static bool verbose = false; /* if set, print all error messages */
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
void set_def_filename( const char * const s )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
strncpy( def_filename, s, sizeof def_filename );
|
|
Packit |
4e1bf9 |
def_filename[sizeof(def_filename)-1] = 0;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
void set_error_msg( const char * msg )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
if( !msg ) msg = "";
|
|
Packit |
4e1bf9 |
strncpy( errmsg, msg, sizeof errmsg );
|
|
Packit |
4e1bf9 |
errmsg[sizeof(errmsg)-1] = 0;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
void set_prompt( const char * const s )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
prompt_on = true;
|
|
Packit |
4e1bf9 |
strncpy( prompt_str, s, sizeof prompt_str );
|
|
Packit |
4e1bf9 |
prompt_str[sizeof(prompt_str)-1] = 0;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
void set_verbose( void ) { verbose = true; }
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
static const line_t * mark[26]; /* line markers */
|
|
Packit |
4e1bf9 |
static int markno; /* line marker count */
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
static bool mark_line_node( const line_t * const lp, int c )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
c -= 'a';
|
|
Packit |
4e1bf9 |
if( c < 0 || c >= 26 )
|
|
Packit |
4e1bf9 |
{ set_error_msg( "Invalid mark character" ); return false; }
|
|
Packit |
4e1bf9 |
if( !mark[c] ) ++markno;
|
|
Packit |
4e1bf9 |
mark[c] = lp;
|
|
Packit |
4e1bf9 |
return true;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
void unmark_line_node( const line_t * const lp )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
int i;
|
|
Packit |
4e1bf9 |
for( i = 0; markno && i < 26; ++i )
|
|
Packit |
4e1bf9 |
if( mark[i] == lp )
|
|
Packit |
4e1bf9 |
{ mark[i] = 0; --markno; }
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
/* return address of a marked line */
|
|
Packit |
4e1bf9 |
static int get_marked_node_addr( int c )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
c -= 'a';
|
|
Packit |
4e1bf9 |
if( c < 0 || c >= 26 )
|
|
Packit |
4e1bf9 |
{ set_error_msg( "Invalid mark character" ); return -1; }
|
|
Packit |
4e1bf9 |
return get_line_node_addr( mark[c] );
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
/* Returns pointer to copy of shell command in the command buffer */
|
|
Packit |
4e1bf9 |
static const char * get_shell_command( const char ** const ibufpp )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
static char * buf = 0; /* temporary buffer */
|
|
Packit |
4e1bf9 |
static int bufsz = 0;
|
|
Packit |
4e1bf9 |
static char * shcmd = 0; /* shell command buffer */
|
|
Packit |
4e1bf9 |
static int shcmdsz = 0; /* shell command buffer size */
|
|
Packit |
4e1bf9 |
static int shcmdlen = 0; /* shell command length */
|
|
Packit |
4e1bf9 |
int i = 0, len = 0;
|
|
Packit |
4e1bf9 |
bool replacement = false;
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
if( restricted() ) { set_error_msg( "Shell access restricted" ); return 0; }
|
|
Packit |
4e1bf9 |
if( !get_extended_line( ibufpp, &len, true ) ) return 0;
|
|
Packit |
4e1bf9 |
if( !resize_buffer( &buf, &bufsz, len + 1 ) ) return 0;
|
|
Packit |
4e1bf9 |
if( **ibufpp != '!' ) buf[i++] = '!'; /* prefix command w/ bang */
|
|
Packit |
4e1bf9 |
else
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
if( shcmdlen <= 0 || ( traditional() && !shcmd[1] ) )
|
|
Packit |
4e1bf9 |
{ set_error_msg( "No previous command" ); return 0; }
|
|
Packit |
4e1bf9 |
memcpy( buf, shcmd, shcmdlen ); /* bufsz >= shcmdlen */
|
|
Packit |
4e1bf9 |
i += shcmdlen; ++*ibufpp; replacement = true;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
while( **ibufpp != '\n' )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
if( **ibufpp == '%' )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
const char * p;
|
|
Packit |
4e1bf9 |
if( !def_filename[0] )
|
|
Packit |
4e1bf9 |
{ set_error_msg( "No current filename" ); return 0; }
|
|
Packit |
4e1bf9 |
p = strip_escapes( def_filename );
|
|
Packit |
4e1bf9 |
len = strlen( p );
|
|
Packit |
4e1bf9 |
if( !resize_buffer( &buf, &bufsz, i + len ) ) return 0;
|
|
Packit |
4e1bf9 |
memcpy( buf + i, p, len );
|
|
Packit |
4e1bf9 |
i += len; ++*ibufpp; replacement = true;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
else
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
if( !resize_buffer( &buf, &bufsz, i + 2 ) ) return 0;
|
|
Packit |
4e1bf9 |
if( ( buf[i++] = *(*ibufpp)++ ) == '\\' ) buf[i++] = *(*ibufpp)++;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
while( **ibufpp == '\n' ) ++*ibufpp; /* skip newline */
|
|
Packit |
4e1bf9 |
if( !resize_buffer( &shcmd, &shcmdsz, i + 1 ) ) return 0;
|
|
Packit |
4e1bf9 |
memcpy( shcmd, buf, i );
|
|
Packit |
4e1bf9 |
shcmd[i] = 0; shcmdlen = i;
|
|
Packit |
4e1bf9 |
if( replacement ) printf( "%s\n", shcmd + 1 );
|
|
Packit |
4e1bf9 |
return shcmd;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
static const char * skip_blanks( const char * p )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
while( isspace( (unsigned char)*p ) && *p != '\n' ) ++p;
|
|
Packit |
4e1bf9 |
return p;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
/* Returns pointer to copy of filename in the command buffer */
|
|
Packit |
4e1bf9 |
static const char * get_filename( const char ** const ibufpp,
|
|
Packit |
4e1bf9 |
const bool traditional_f_command )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
static char * buf = 0;
|
|
Packit |
4e1bf9 |
static int bufsz = 0;
|
|
Packit |
4e1bf9 |
const int pmax = path_max( 0 );
|
|
Packit |
4e1bf9 |
int n;
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
*ibufpp = skip_blanks( *ibufpp );
|
|
Packit |
4e1bf9 |
if( **ibufpp != '\n' )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
int size = 0;
|
|
Packit |
4e1bf9 |
if( !get_extended_line( ibufpp, &size, true ) ) return 0;
|
|
Packit |
4e1bf9 |
if( **ibufpp == '!' )
|
|
Packit |
4e1bf9 |
{ ++*ibufpp; return get_shell_command( ibufpp ); }
|
|
Packit |
4e1bf9 |
else if( size > pmax )
|
|
Packit |
4e1bf9 |
{ set_error_msg( "Filename too long" ); return 0; }
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
else if( !traditional_f_command && !def_filename[0] )
|
|
Packit |
4e1bf9 |
{ set_error_msg( "No current filename" ); return 0; }
|
|
Packit |
4e1bf9 |
if( !resize_buffer( &buf, &bufsz, pmax + 1 ) ) return 0;
|
|
Packit |
4e1bf9 |
for( n = 0; **ibufpp != '\n'; ++n, ++*ibufpp ) buf[n] = **ibufpp;
|
|
Packit |
4e1bf9 |
buf[n] = 0;
|
|
Packit |
4e1bf9 |
while( **ibufpp == '\n' ) ++*ibufpp; /* skip newline */
|
|
Packit |
4e1bf9 |
return ( may_access_filename( buf ) ? buf : 0 );
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
static void invalid_address( void ) { set_error_msg( "Invalid address" ); }
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
/* Get line addresses from the command buffer until an invalid address
|
|
Packit |
4e1bf9 |
is seen. Returns the number of addresses read, or -1 if error.
|
|
Packit |
4e1bf9 |
If no addresses are found, both addresses are set to the current address.
|
|
Packit |
4e1bf9 |
If one address is found, both addresses are set to that address. */
|
|
Packit |
4e1bf9 |
static int extract_addresses( const char ** const ibufpp )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
bool first = true; /* true == addr, false == offset */
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
first_addr = second_addr = -1; /* set to undefined */
|
|
Packit |
4e1bf9 |
*ibufpp = skip_blanks( *ibufpp );
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
while( true )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
int n;
|
|
Packit |
4e1bf9 |
const unsigned char ch = **ibufpp;
|
|
Packit |
4e1bf9 |
if( isdigit( ch ) )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
if( !parse_int( &n, *ibufpp, ibufpp ) ) return -1;
|
|
Packit |
4e1bf9 |
if( first ) { first = false; second_addr = n; } else second_addr += n;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
else switch( ch )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
case '\t':
|
|
Packit |
4e1bf9 |
case ' ': *ibufpp = skip_blanks( ++*ibufpp ); break;
|
|
Packit |
4e1bf9 |
case '+':
|
|
Packit |
4e1bf9 |
case '-': if( first ) { first = false; second_addr = current_addr(); }
|
|
Packit |
4e1bf9 |
if( isdigit( (unsigned char)(*ibufpp)[1] ) )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
if( !parse_int( &n, *ibufpp, ibufpp ) ) return -1;
|
|
Packit |
4e1bf9 |
second_addr += n;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
else { ++*ibufpp;
|
|
Packit |
4e1bf9 |
if( ch == '+' ) ++second_addr; else --second_addr; }
|
|
Packit |
4e1bf9 |
break;
|
|
Packit |
4e1bf9 |
case '.':
|
|
Packit |
4e1bf9 |
case '$': if( !first ) { invalid_address(); return -1; };
|
|
Packit |
4e1bf9 |
first = false; ++*ibufpp;
|
|
Packit |
4e1bf9 |
second_addr = ( ( ch == '.' ) ? current_addr() : last_addr() );
|
|
Packit |
4e1bf9 |
break;
|
|
Packit |
4e1bf9 |
case '/':
|
|
Packit |
4e1bf9 |
case '?': if( !first ) { invalid_address(); return -1; };
|
|
Packit |
4e1bf9 |
second_addr = next_matching_node_addr( ibufpp, ch == '/' );
|
|
Packit |
4e1bf9 |
if( second_addr < 0 ) return -1;
|
|
Packit |
4e1bf9 |
if( ch == **ibufpp ) ++*ibufpp; /* remove delimiter */
|
|
Packit |
4e1bf9 |
first = false; break;
|
|
Packit |
4e1bf9 |
case '\'':if( !first ) { invalid_address(); return -1; };
|
|
Packit |
4e1bf9 |
first = false; ++*ibufpp;
|
|
Packit |
4e1bf9 |
second_addr = get_marked_node_addr( *(*ibufpp)++ );
|
|
Packit |
4e1bf9 |
if( second_addr < 0 ) return -1;
|
|
Packit |
4e1bf9 |
break;
|
|
Packit |
4e1bf9 |
case '%':
|
|
Packit |
4e1bf9 |
case ',':
|
|
Packit |
4e1bf9 |
case ';': if( first )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
if( first_addr < 0 )
|
|
Packit |
4e1bf9 |
{ first_addr = ( ( ch == ';' ) ? current_addr() : 1 );
|
|
Packit |
4e1bf9 |
second_addr = last_addr(); }
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
else
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
if( second_addr < 0 || second_addr > last_addr() )
|
|
Packit |
4e1bf9 |
{ invalid_address(); return -1; }
|
|
Packit |
4e1bf9 |
if( ch == ';' ) set_current_addr( second_addr );
|
|
Packit |
4e1bf9 |
first_addr = second_addr; first = true;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
++*ibufpp;
|
|
Packit |
4e1bf9 |
break;
|
|
Packit |
4e1bf9 |
default :
|
|
Packit |
4e1bf9 |
if( !first && ( second_addr < 0 || second_addr > last_addr() ) )
|
|
Packit |
4e1bf9 |
{ invalid_address(); return -1; }
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
int addr_cnt = 0; /* limited to 2 */
|
|
Packit |
4e1bf9 |
if( second_addr >= 0 ) addr_cnt = ( first_addr >= 0 ) ? 2 : 1;
|
|
Packit |
4e1bf9 |
if( addr_cnt <= 0 ) second_addr = current_addr();
|
|
Packit |
4e1bf9 |
if( addr_cnt <= 1 ) first_addr = second_addr;
|
|
Packit |
4e1bf9 |
return addr_cnt;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
/* get a valid address from the command buffer */
|
|
Packit |
4e1bf9 |
static bool get_third_addr( const char ** const ibufpp, int * const addr )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
const int old1 = first_addr;
|
|
Packit |
4e1bf9 |
const int old2 = second_addr;
|
|
Packit |
4e1bf9 |
int addr_cnt = extract_addresses( ibufpp );
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
if( addr_cnt < 0 ) return false;
|
|
Packit |
4e1bf9 |
if( traditional() && addr_cnt == 0 )
|
|
Packit |
4e1bf9 |
{ set_error_msg( "Destination expected" ); return false; }
|
|
Packit |
4e1bf9 |
if( second_addr < 0 || second_addr > last_addr() )
|
|
Packit |
4e1bf9 |
{ invalid_address(); return false; }
|
|
Packit |
4e1bf9 |
*addr = second_addr;
|
|
Packit |
4e1bf9 |
first_addr = old1; second_addr = old2;
|
|
Packit |
4e1bf9 |
return true;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
/* set default range and return true if address range is valid */
|
|
Packit |
4e1bf9 |
static bool check_addr_range( const int n, const int m, const int addr_cnt )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
if( addr_cnt == 0 ) { first_addr = n; second_addr = m; }
|
|
Packit |
4e1bf9 |
if( first_addr < 1 || first_addr > second_addr || second_addr > last_addr() )
|
|
Packit |
4e1bf9 |
{ invalid_address(); return false; }
|
|
Packit |
4e1bf9 |
return true;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
/* set defaults to current_addr and return true if address range is valid */
|
|
Packit |
4e1bf9 |
static bool check_addr_range2( const int addr_cnt )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
return check_addr_range( current_addr(), current_addr(), addr_cnt );
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
/* set default second_addr and return true if second_addr is valid */
|
|
Packit |
4e1bf9 |
static bool check_second_addr( const int addr, const int addr_cnt )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
if( addr_cnt == 0 ) second_addr = addr;
|
|
Packit |
4e1bf9 |
if( second_addr < 1 || second_addr > last_addr() )
|
|
Packit |
4e1bf9 |
{ invalid_address(); return false; }
|
|
Packit |
4e1bf9 |
return true;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
/* verify the command suffixes in the command buffer */
|
|
Packit |
4e1bf9 |
static bool get_command_suffix( const char ** const ibufpp,
|
|
Packit |
4e1bf9 |
int * const pflagsp, int * const snump )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
bool nos_or_rep = !snump; /* not s command or repeated g/count */
|
|
Packit |
4e1bf9 |
bool error = false;
|
|
Packit |
4e1bf9 |
while( true )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
const unsigned char ch = **ibufpp;
|
|
Packit |
4e1bf9 |
if( ch >= '1' && ch <= '9' )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
int n = 0;
|
|
Packit |
4e1bf9 |
if( nos_or_rep || !parse_int( &n, *ibufpp, ibufpp ) || n <= 0 )
|
|
Packit |
4e1bf9 |
{ error = true; break; }
|
|
Packit |
4e1bf9 |
nos_or_rep = true; *snump = n; continue;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
else if( ch == 'g' )
|
|
Packit |
4e1bf9 |
{ if( nos_or_rep ) break; else { nos_or_rep = true; *snump = 0; } }
|
|
Packit |
4e1bf9 |
else if( ch == 'l' ) { if( *pflagsp & GLS ) break; else *pflagsp |= GLS; }
|
|
Packit |
4e1bf9 |
else if( ch == 'n' ) { if( *pflagsp & GNP ) break; else *pflagsp |= GNP; }
|
|
Packit |
4e1bf9 |
else if( ch == 'p' ) { if( *pflagsp & GPR ) break; else *pflagsp |= GPR; }
|
|
Packit |
4e1bf9 |
else break;
|
|
Packit |
4e1bf9 |
++*ibufpp;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
if( error || *(*ibufpp)++ != '\n' )
|
|
Packit |
4e1bf9 |
{ set_error_msg( "Invalid command suffix" ); return false; }
|
|
Packit |
4e1bf9 |
return true;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
static bool unexpected_address( const int addr_cnt )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
if( addr_cnt > 0 ) { set_error_msg( "Unexpected address" ); return true; }
|
|
Packit |
4e1bf9 |
return false;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
static bool unexpected_command_suffix( const unsigned char ch )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
if( !isspace( ch ) )
|
|
Packit |
4e1bf9 |
{ set_error_msg( "Unexpected command suffix" ); return true; }
|
|
Packit |
4e1bf9 |
return false;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
static bool command_s( const char ** const ibufpp, int * const pflagsp,
|
|
Packit |
4e1bf9 |
const int addr_cnt, const bool isglobal )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
static int pflags = 0; /* print suffixes */
|
|
Packit |
4e1bf9 |
static int gmask = GPR; /* the print suffixes to be toggled */
|
|
Packit |
4e1bf9 |
static int snum = 1; /* > 0 count, <= 0 global substitute */
|
|
Packit |
4e1bf9 |
enum Sflags {
|
|
Packit |
4e1bf9 |
SGG = 0x01, /* complement previous global substitute suffix */
|
|
Packit |
4e1bf9 |
SGP = 0x02, /* complement previous print suffix */
|
|
Packit |
4e1bf9 |
SGR = 0x04, /* use regex of last search (if newer) */
|
|
Packit |
4e1bf9 |
SGF = 0x08
|
|
Packit |
4e1bf9 |
} sflags = 0; /* if sflags != 0, repeat last substitution */
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
if( !check_addr_range2( addr_cnt ) ) return false;
|
|
Packit |
4e1bf9 |
do {
|
|
Packit |
4e1bf9 |
bool error = false;
|
|
Packit |
4e1bf9 |
if( **ibufpp >= '1' && **ibufpp <= '9' )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
int n = 0;
|
|
Packit |
4e1bf9 |
if( ( sflags & SGG ) || !parse_int( &n, *ibufpp, ibufpp ) || n <= 0 )
|
|
Packit |
4e1bf9 |
error = true;
|
|
Packit |
4e1bf9 |
else
|
|
Packit |
4e1bf9 |
{ sflags |= SGG; snum = n; }
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
else switch( **ibufpp )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
case '\n':sflags |= SGF; break;
|
|
Packit |
4e1bf9 |
case 'g': if( sflags & SGG ) error = true;
|
|
Packit |
4e1bf9 |
else { sflags |= SGG; snum = !snum; ++*ibufpp; }
|
|
Packit |
4e1bf9 |
break;
|
|
Packit |
4e1bf9 |
case 'p': if( sflags & SGP ) error = true;
|
|
Packit |
4e1bf9 |
else { sflags |= SGP; ++*ibufpp; } break;
|
|
Packit |
4e1bf9 |
case 'r': if( sflags & SGR ) error = true;
|
|
Packit |
4e1bf9 |
else { sflags |= SGR; ++*ibufpp; } break;
|
|
Packit |
4e1bf9 |
default : if( sflags ) error = true;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
if( error ) { set_error_msg( "Invalid command suffix" ); return false; }
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
while( sflags && **ibufpp != '\n' );
|
|
Packit |
4e1bf9 |
if( sflags && !subst_regex() )
|
|
Packit |
4e1bf9 |
{ set_error_msg( "No previous substitution" ); return false; }
|
|
Packit |
4e1bf9 |
if( ( !sflags || ( sflags & SGR ) ) && !set_subst_regex( ibufpp ) )
|
|
Packit |
4e1bf9 |
return false;
|
|
Packit |
4e1bf9 |
if( !sflags )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
const char delimiter = **ibufpp;
|
|
Packit |
4e1bf9 |
pflags = 0; snum = 1;
|
|
Packit |
4e1bf9 |
if( !extract_replacement( ibufpp, isglobal ) ) return false;
|
|
Packit |
4e1bf9 |
if( **ibufpp == '\n' ) pflags = GPR; /* omitted last delimiter */
|
|
Packit |
4e1bf9 |
else if( **ibufpp == delimiter ) ++*ibufpp; /* skip delimiter */
|
|
Packit |
4e1bf9 |
if( !get_command_suffix( ibufpp, &pflags, &snum ) ) return false;
|
|
Packit |
4e1bf9 |
gmask = pflags & ( GPR | GLS | GNP ); if( gmask == 0 ) gmask = GPR;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
else if( sflags & SGP ) pflags ^= gmask;
|
|
Packit |
4e1bf9 |
*pflagsp = pflags;
|
|
Packit |
4e1bf9 |
if( !isglobal ) clear_undo_stack();
|
|
Packit |
4e1bf9 |
if( !search_and_replace( first_addr, second_addr, snum, isglobal ) )
|
|
Packit |
4e1bf9 |
return false;
|
|
Packit |
4e1bf9 |
return true;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
static bool exec_global( const char ** const ibufpp, const int pflags,
|
|
Packit |
4e1bf9 |
const bool interactive );
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
/* execute the next command in command buffer; return error status */
|
|
Packit |
4e1bf9 |
static int exec_command( const char ** const ibufpp, const int prev_status,
|
|
Packit |
4e1bf9 |
const bool isglobal )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
const char * fnp; /* filename */
|
|
Packit |
4e1bf9 |
int pflags = 0; /* print suffixes */
|
|
Packit |
4e1bf9 |
int addr, c, n;
|
|
Packit |
4e1bf9 |
const int addr_cnt = extract_addresses( ibufpp );
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
if( addr_cnt < 0 ) return ERR;
|
|
Packit |
4e1bf9 |
*ibufpp = skip_blanks( *ibufpp );
|
|
Packit |
4e1bf9 |
c = *(*ibufpp)++;
|
|
Packit |
4e1bf9 |
switch( c )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
case 'a': if( !get_command_suffix( ibufpp, &pflags, 0 ) ) return ERR;
|
|
Packit |
4e1bf9 |
if( !isglobal ) clear_undo_stack();
|
|
Packit |
4e1bf9 |
if( !append_lines( ibufpp, second_addr, false, isglobal ) )
|
|
Packit |
4e1bf9 |
return ERR;
|
|
Packit |
4e1bf9 |
break;
|
|
Packit |
4e1bf9 |
case 'c': if( first_addr == 0 ) first_addr = 1;
|
|
Packit |
4e1bf9 |
if( second_addr == 0 ) second_addr = 1;
|
|
Packit |
4e1bf9 |
if( !check_addr_range2( addr_cnt ) ||
|
|
Packit |
4e1bf9 |
!get_command_suffix( ibufpp, &pflags, 0 ) ) return ERR;
|
|
Packit |
4e1bf9 |
if( !isglobal ) clear_undo_stack();
|
|
Packit |
4e1bf9 |
if( !delete_lines( first_addr, second_addr, isglobal ) ||
|
|
Packit |
4e1bf9 |
!append_lines( ibufpp, current_addr(),
|
|
Packit |
4e1bf9 |
current_addr() >= first_addr, isglobal ) )
|
|
Packit |
4e1bf9 |
return ERR;
|
|
Packit |
4e1bf9 |
break;
|
|
Packit |
4e1bf9 |
case 'd': if( !check_addr_range2( addr_cnt ) ||
|
|
Packit |
4e1bf9 |
!get_command_suffix( ibufpp, &pflags, 0 ) ) return ERR;
|
|
Packit |
4e1bf9 |
if( !isglobal ) clear_undo_stack();
|
|
Packit |
4e1bf9 |
if( !delete_lines( first_addr, second_addr, isglobal ) ) return ERR;
|
|
Packit |
4e1bf9 |
break;
|
|
Packit |
4e1bf9 |
case 'e': if( modified() && prev_status != EMOD ) return EMOD;
|
|
Packit |
4e1bf9 |
/* fall through */
|
|
Packit |
4e1bf9 |
case 'E': if( unexpected_address( addr_cnt ) ||
|
|
Packit |
4e1bf9 |
unexpected_command_suffix( **ibufpp ) ) return ERR;
|
|
Packit |
4e1bf9 |
fnp = get_filename( ibufpp, false );
|
|
Packit |
4e1bf9 |
if( !fnp || !delete_lines( 1, last_addr(), isglobal ) ||
|
|
Packit |
4e1bf9 |
!close_sbuf() ) return ERR;
|
|
Packit |
4e1bf9 |
if( !open_sbuf() ) return FATAL;
|
|
Packit |
4e1bf9 |
if( fnp[0] && fnp[0] != '!' ) set_def_filename( fnp );
|
|
Packit |
4e1bf9 |
if( read_file( fnp[0] ? fnp : def_filename, 0 ) < 0 )
|
|
Packit |
4e1bf9 |
return ERR;
|
|
Packit |
4e1bf9 |
reset_undo_state(); set_modified( false );
|
|
Packit |
4e1bf9 |
break;
|
|
Packit |
4e1bf9 |
case 'f': if( unexpected_address( addr_cnt ) ||
|
|
Packit |
4e1bf9 |
unexpected_command_suffix( **ibufpp ) ) return ERR;
|
|
Packit |
4e1bf9 |
fnp = get_filename( ibufpp, traditional() );
|
|
Packit |
4e1bf9 |
if( !fnp ) return ERR;
|
|
Packit |
4e1bf9 |
if( fnp[0] == '!' )
|
|
Packit |
4e1bf9 |
{ set_error_msg( "Invalid redirection" ); return ERR; }
|
|
Packit |
4e1bf9 |
if( fnp[0] ) set_def_filename( fnp );
|
|
Packit |
4e1bf9 |
printf( "%s\n", strip_escapes( def_filename ) );
|
|
Packit |
4e1bf9 |
break;
|
|
Packit |
4e1bf9 |
case 'g':
|
|
Packit |
4e1bf9 |
case 'v':
|
|
Packit |
4e1bf9 |
case 'G':
|
|
Packit |
4e1bf9 |
case 'V': if( isglobal )
|
|
Packit |
4e1bf9 |
{ set_error_msg( "Cannot nest global commands" ); return ERR; }
|
|
Packit |
4e1bf9 |
n = ( c == 'g' || c == 'G' ); /* mark matching lines */
|
|
Packit |
4e1bf9 |
if( !check_addr_range( 1, last_addr(), addr_cnt ) ||
|
|
Packit |
4e1bf9 |
!build_active_list( ibufpp, first_addr, second_addr, n ) )
|
|
Packit |
4e1bf9 |
return ERR;
|
|
Packit |
4e1bf9 |
n = ( c == 'G' || c == 'V' ); /* interactive */
|
|
Packit |
4e1bf9 |
if( ( n && !get_command_suffix( ibufpp, &pflags, 0 ) ) ||
|
|
Packit |
4e1bf9 |
!exec_global( ibufpp, pflags, n ) )
|
|
Packit |
4e1bf9 |
return ERR;
|
|
Packit |
4e1bf9 |
break;
|
|
Packit |
4e1bf9 |
case 'h':
|
|
Packit |
4e1bf9 |
case 'H': if( unexpected_address( addr_cnt ) ||
|
|
Packit |
4e1bf9 |
!get_command_suffix( ibufpp, &pflags, 0 ) ) return ERR;
|
|
Packit |
4e1bf9 |
if( c == 'H' ) verbose = !verbose;
|
|
Packit |
4e1bf9 |
if( ( c == 'h' || verbose ) && errmsg[0] )
|
|
Packit |
4e1bf9 |
printf( "%s\n", errmsg );
|
|
Packit |
4e1bf9 |
break;
|
|
Packit |
4e1bf9 |
case 'i': if( !get_command_suffix( ibufpp, &pflags, 0 ) ) return ERR;
|
|
Packit |
4e1bf9 |
if( !isglobal ) clear_undo_stack();
|
|
Packit |
4e1bf9 |
if( !append_lines( ibufpp, second_addr, true, isglobal ) )
|
|
Packit |
4e1bf9 |
return ERR;
|
|
Packit |
4e1bf9 |
break;
|
|
Packit |
4e1bf9 |
case 'j': if( !check_addr_range( current_addr(), current_addr() + 1, addr_cnt ) ||
|
|
Packit |
4e1bf9 |
!get_command_suffix( ibufpp, &pflags, 0 ) ) return ERR;
|
|
Packit |
4e1bf9 |
if( !isglobal ) clear_undo_stack();
|
|
Packit |
4e1bf9 |
if( first_addr < second_addr &&
|
|
Packit |
4e1bf9 |
!join_lines( first_addr, second_addr, isglobal ) ) return ERR;
|
|
Packit |
4e1bf9 |
break;
|
|
Packit |
4e1bf9 |
case 'k': n = *(*ibufpp)++;
|
|
Packit |
4e1bf9 |
if( second_addr == 0 ) { invalid_address(); return ERR; }
|
|
Packit |
4e1bf9 |
if( !get_command_suffix( ibufpp, &pflags, 0 ) ||
|
|
Packit |
4e1bf9 |
!mark_line_node( search_line_node( second_addr ), n ) )
|
|
Packit |
4e1bf9 |
return ERR;
|
|
Packit |
4e1bf9 |
break;
|
|
Packit |
4e1bf9 |
case 'l':
|
|
Packit |
4e1bf9 |
case 'n':
|
|
Packit |
4e1bf9 |
case 'p': if( c == 'l' ) n = GLS; else if( c == 'n' ) n = GNP; else n = GPR;
|
|
Packit |
4e1bf9 |
if( !check_addr_range2( addr_cnt ) ||
|
|
Packit |
4e1bf9 |
!get_command_suffix( ibufpp, &pflags, 0 ) ||
|
|
Packit |
4e1bf9 |
!print_lines( first_addr, second_addr, pflags | n ) )
|
|
Packit |
4e1bf9 |
return ERR;
|
|
Packit |
4e1bf9 |
pflags = 0;
|
|
Packit |
4e1bf9 |
break;
|
|
Packit |
4e1bf9 |
case 'm': if( !check_addr_range2( addr_cnt ) ||
|
|
Packit |
4e1bf9 |
!get_third_addr( ibufpp, &addr ) ) return ERR;
|
|
Packit |
4e1bf9 |
if( addr >= first_addr && addr < second_addr )
|
|
Packit |
4e1bf9 |
{ set_error_msg( "Invalid destination" ); return ERR; }
|
|
Packit |
4e1bf9 |
if( !get_command_suffix( ibufpp, &pflags, 0 ) ) return ERR;
|
|
Packit |
4e1bf9 |
if( !isglobal ) clear_undo_stack();
|
|
Packit |
4e1bf9 |
if( !move_lines( first_addr, second_addr, addr, isglobal ) )
|
|
Packit |
4e1bf9 |
return ERR;
|
|
Packit |
4e1bf9 |
break;
|
|
Packit |
4e1bf9 |
case 'P':
|
|
Packit |
4e1bf9 |
case 'q':
|
|
Packit |
4e1bf9 |
case 'Q': if( unexpected_address( addr_cnt ) ||
|
|
Packit |
4e1bf9 |
!get_command_suffix( ibufpp, &pflags, 0 ) ) return ERR;
|
|
Packit |
4e1bf9 |
if( c == 'P' ) prompt_on = !prompt_on;
|
|
Packit |
4e1bf9 |
else if( c == 'q' && modified() && prev_status != EMOD )
|
|
Packit |
4e1bf9 |
return EMOD;
|
|
Packit |
4e1bf9 |
else return QUIT;
|
|
Packit |
4e1bf9 |
break;
|
|
Packit |
4e1bf9 |
case 'r': if( unexpected_command_suffix( **ibufpp ) ) return ERR;
|
|
Packit |
4e1bf9 |
if( addr_cnt == 0 ) second_addr = last_addr();
|
|
Packit |
4e1bf9 |
fnp = get_filename( ibufpp, false );
|
|
Packit |
4e1bf9 |
if( !fnp ) return ERR;
|
|
Packit |
4e1bf9 |
if( !def_filename[0] && fnp[0] != '!' ) set_def_filename( fnp );
|
|
Packit |
4e1bf9 |
if( !isglobal ) clear_undo_stack();
|
|
Packit |
4e1bf9 |
addr = read_file( fnp[0] ? fnp : def_filename, second_addr );
|
|
Packit |
4e1bf9 |
if( addr < 0 ) return ERR;
|
|
Packit |
4e1bf9 |
if( addr ) set_modified( true );
|
|
Packit |
4e1bf9 |
break;
|
|
Packit |
4e1bf9 |
case 's': if( !command_s( ibufpp, &pflags, addr_cnt, isglobal ) )
|
|
Packit |
4e1bf9 |
return ERR;
|
|
Packit |
4e1bf9 |
break;
|
|
Packit |
4e1bf9 |
case 't': if( !check_addr_range2( addr_cnt ) ||
|
|
Packit |
4e1bf9 |
!get_third_addr( ibufpp, &addr ) ||
|
|
Packit |
4e1bf9 |
!get_command_suffix( ibufpp, &pflags, 0 ) ) return ERR;
|
|
Packit |
4e1bf9 |
if( !isglobal ) clear_undo_stack();
|
|
Packit |
4e1bf9 |
if( !copy_lines( first_addr, second_addr, addr ) ) return ERR;
|
|
Packit |
4e1bf9 |
break;
|
|
Packit |
4e1bf9 |
case 'u': if( unexpected_address( addr_cnt ) ||
|
|
Packit |
4e1bf9 |
!get_command_suffix( ibufpp, &pflags, 0 ) ||
|
|
Packit |
4e1bf9 |
!undo( isglobal ) ) return ERR;
|
|
Packit |
4e1bf9 |
break;
|
|
Packit |
4e1bf9 |
case 'w':
|
|
Packit |
4e1bf9 |
case 'W': n = **ibufpp;
|
|
Packit |
4e1bf9 |
if( n == 'q' || n == 'Q' ) ++*ibufpp;
|
|
Packit |
4e1bf9 |
if( unexpected_command_suffix( **ibufpp ) ) return ERR;
|
|
Packit |
4e1bf9 |
fnp = get_filename( ibufpp, false );
|
|
Packit |
4e1bf9 |
if( !fnp ) return ERR;
|
|
Packit |
4e1bf9 |
if( addr_cnt == 0 && last_addr() == 0 )
|
|
Packit |
4e1bf9 |
first_addr = second_addr = 0;
|
|
Packit |
4e1bf9 |
else if( !check_addr_range( 1, last_addr(), addr_cnt ) )
|
|
Packit |
4e1bf9 |
return ERR;
|
|
Packit |
4e1bf9 |
if( !def_filename[0] && fnp[0] != '!' ) set_def_filename( fnp );
|
|
Packit |
4e1bf9 |
addr = write_file( fnp[0] ? fnp : def_filename,
|
|
Packit |
4e1bf9 |
( c == 'W' ) ? "a" : "w", first_addr, second_addr );
|
|
Packit |
4e1bf9 |
if( addr < 0 ) return ERR;
|
|
Packit |
4e1bf9 |
if( addr == last_addr() && fnp[0] != '!' ) set_modified( false );
|
|
Packit |
4e1bf9 |
else if( n == 'q' && modified() && prev_status != EMOD )
|
|
Packit |
4e1bf9 |
return EMOD;
|
|
Packit |
4e1bf9 |
if( n == 'q' || n == 'Q' ) return QUIT;
|
|
Packit |
4e1bf9 |
break;
|
|
Packit |
4e1bf9 |
case 'x': if( second_addr < 0 || second_addr > last_addr() )
|
|
Packit |
4e1bf9 |
{ invalid_address(); return ERR; }
|
|
Packit |
4e1bf9 |
if( !get_command_suffix( ibufpp, &pflags, 0 ) ) return ERR;
|
|
Packit |
4e1bf9 |
if( !isglobal ) clear_undo_stack();
|
|
Packit |
4e1bf9 |
if( !put_lines( second_addr ) ) return ERR;
|
|
Packit |
4e1bf9 |
break;
|
|
Packit |
4e1bf9 |
case 'y': if( !check_addr_range2( addr_cnt ) ||
|
|
Packit |
4e1bf9 |
!get_command_suffix( ibufpp, &pflags, 0 ) ||
|
|
Packit |
4e1bf9 |
!yank_lines( first_addr, second_addr ) ) return ERR;
|
|
Packit |
4e1bf9 |
break;
|
|
Packit |
4e1bf9 |
case 'z': if( !check_second_addr( current_addr() + !isglobal, addr_cnt ) )
|
|
Packit |
4e1bf9 |
return ERR;
|
|
Packit |
4e1bf9 |
if( **ibufpp > '0' && **ibufpp <= '9' )
|
|
Packit |
4e1bf9 |
{ if( parse_int( &n, *ibufpp, ibufpp ) ) set_window_lines( n );
|
|
Packit |
4e1bf9 |
else return ERR; }
|
|
Packit |
4e1bf9 |
if( !get_command_suffix( ibufpp, &pflags, 0 ) ||
|
|
Packit |
4e1bf9 |
!print_lines( second_addr,
|
|
Packit |
4e1bf9 |
min( last_addr(), second_addr + window_lines() - 1 ),
|
|
Packit |
4e1bf9 |
pflags ) )
|
|
Packit |
4e1bf9 |
return ERR;
|
|
Packit |
4e1bf9 |
pflags = 0;
|
|
Packit |
4e1bf9 |
break;
|
|
Packit |
4e1bf9 |
case '=': if( !get_command_suffix( ibufpp, &pflags, 0 ) ) return ERR;
|
|
Packit |
4e1bf9 |
printf( "%d\n", addr_cnt ? second_addr : last_addr() );
|
|
Packit |
4e1bf9 |
break;
|
|
Packit |
4e1bf9 |
case '!': if( unexpected_address( addr_cnt ) ) return ERR;
|
|
Packit |
4e1bf9 |
fnp = get_shell_command( ibufpp );
|
|
Packit |
4e1bf9 |
if( !fnp ) return ERR;
|
|
Packit |
4e1bf9 |
if( system( fnp + 1 ) < 0 )
|
|
Packit |
4e1bf9 |
{ set_error_msg( "Can't create shell process" ); return ERR; }
|
|
Packit |
4e1bf9 |
if( !scripted() ) fputs( "!\n", stdout );
|
|
Packit |
4e1bf9 |
break;
|
|
Packit |
4e1bf9 |
case '\n': if( !check_second_addr( current_addr() +
|
|
Packit |
4e1bf9 |
( traditional() || !isglobal ), addr_cnt ) ||
|
|
Packit |
4e1bf9 |
!print_lines( second_addr, second_addr, 0 ) )
|
|
Packit |
4e1bf9 |
return ERR;
|
|
Packit |
4e1bf9 |
break;
|
|
Packit |
4e1bf9 |
case '#': while( *(*ibufpp)++ != '\n' ) ;
|
|
Packit |
4e1bf9 |
break;
|
|
Packit |
4e1bf9 |
default : set_error_msg( "Unknown command" ); return ERR;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
if( pflags && !print_lines( current_addr(), current_addr(), pflags ) )
|
|
Packit |
4e1bf9 |
return ERR;
|
|
Packit |
4e1bf9 |
return 0;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
/* apply command list in the command buffer to the active lines in a
|
|
Packit |
4e1bf9 |
range; return false if error */
|
|
Packit |
4e1bf9 |
static bool exec_global( const char ** const ibufpp, const int pflags,
|
|
Packit |
4e1bf9 |
const bool interactive )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
static char * buf = 0;
|
|
Packit |
4e1bf9 |
static int bufsz = 0;
|
|
Packit |
4e1bf9 |
const char * cmd = 0;
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
if( !interactive )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
if( traditional() && strcmp( *ibufpp, "\n" ) == 0 )
|
|
Packit |
4e1bf9 |
cmd = "p\n"; /* null cmd_list == 'p' */
|
|
Packit |
4e1bf9 |
else
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
if( !get_extended_line( ibufpp, 0, false ) ) return false;
|
|
Packit |
4e1bf9 |
cmd = *ibufpp;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
clear_undo_stack();
|
|
Packit |
4e1bf9 |
while( true )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
const line_t * const lp = next_active_node();
|
|
Packit |
4e1bf9 |
if( !lp ) break;
|
|
Packit |
4e1bf9 |
set_current_addr( get_line_node_addr( lp ) );
|
|
Packit |
4e1bf9 |
if( current_addr() < 0 ) return false;
|
|
Packit |
4e1bf9 |
if( interactive )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
/* print current_addr; get a command in global syntax */
|
|
Packit |
4e1bf9 |
int len = 0;
|
|
Packit |
4e1bf9 |
if( !print_lines( current_addr(), current_addr(), pflags ) )
|
|
Packit |
4e1bf9 |
return false;
|
|
Packit |
4e1bf9 |
*ibufpp = get_stdin_line( &len );
|
|
Packit |
4e1bf9 |
if( !*ibufpp ) return false; /* error */
|
|
Packit |
4e1bf9 |
if( len <= 0 ) return false; /* EOF */
|
|
Packit |
4e1bf9 |
if( len == 1 && strcmp( *ibufpp, "\n" ) == 0 ) continue;
|
|
Packit |
4e1bf9 |
if( len == 2 && strcmp( *ibufpp, "&\n" ) == 0 )
|
|
Packit |
4e1bf9 |
{ if( !cmd ) { set_error_msg( "No previous command" ); return false; } }
|
|
Packit |
4e1bf9 |
else
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
if( !get_extended_line( ibufpp, &len, false ) ||
|
|
Packit |
4e1bf9 |
!resize_buffer( &buf, &bufsz, len + 1 ) ) return false;
|
|
Packit |
4e1bf9 |
memcpy( buf, *ibufpp, len + 1 );
|
|
Packit |
4e1bf9 |
cmd = buf;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
*ibufpp = cmd;
|
|
Packit |
4e1bf9 |
while( **ibufpp ) if( exec_command( ibufpp, 0, true ) < 0 ) return false;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
return true;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
static void script_error( void )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
if( verbose ) fprintf( stderr, "script, line %d: %s\n", linenum(), errmsg );
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
int main_loop( const bool loose )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
extern jmp_buf jmp_state;
|
|
Packit |
4e1bf9 |
const char * ibufp; /* pointer to command buffer */
|
|
Packit |
4e1bf9 |
volatile int err_status = 0; /* program exit status */
|
|
Packit |
4e1bf9 |
int len = 0, status;
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
disable_interrupts();
|
|
Packit |
4e1bf9 |
set_signals();
|
|
Packit |
4e1bf9 |
status = setjmp( jmp_state );
|
|
Packit |
4e1bf9 |
if( !status ) enable_interrupts();
|
|
Packit |
4e1bf9 |
else { status = -1; fputs( "\n?\n", stdout ); set_error_msg( "Interrupt" ); }
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
while( true )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
fflush( stdout ); fflush( stderr );
|
|
Packit |
4e1bf9 |
if( status < 0 && verbose ) { printf( "%s\n", errmsg ); fflush( stdout ); }
|
|
Packit |
4e1bf9 |
if( prompt_on ) { fputs( prompt_str, stdout ); fflush( stdout ); }
|
|
Packit |
4e1bf9 |
ibufp = get_stdin_line( &len );
|
|
Packit |
4e1bf9 |
if( !ibufp ) return 2; /* an error happened */
|
|
Packit |
4e1bf9 |
if( len <= 0 ) /* EOF on stdin ('q') */
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
if( !modified() || status == EMOD ) status = QUIT;
|
|
Packit |
4e1bf9 |
else { status = EMOD; if( !loose ) err_status = 2; }
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
else status = exec_command( &ibufp, status, false );
|
|
Packit |
4e1bf9 |
if( status == 0 ) continue;
|
|
Packit |
4e1bf9 |
if( status == QUIT ) return err_status;
|
|
Packit |
4e1bf9 |
fputs( "?\n", stdout ); /* give warning */
|
|
Packit |
4e1bf9 |
if( !loose && err_status == 0 ) err_status = 1;
|
|
Packit |
4e1bf9 |
if( status == EMOD ) set_error_msg( "Warning: buffer modified" );
|
|
Packit |
4e1bf9 |
if( is_regular_file( 0 ) )
|
|
Packit |
4e1bf9 |
{ script_error(); return ( ( status == FATAL ) ? 1 : err_status ); }
|
|
Packit |
4e1bf9 |
if( status == FATAL )
|
|
Packit |
4e1bf9 |
{ if( verbose ) { printf( "%s\n", errmsg ); } return 1; }
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
}
|