|
Packit |
4e1bf9 |
/* signal.c: signal and miscellaneous routines for the ed line editor. */
|
|
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 <errno.h>
|
|
Packit |
4e1bf9 |
#include <limits.h>
|
|
Packit |
4e1bf9 |
#include <setjmp.h>
|
|
Packit |
4e1bf9 |
#include <signal.h>
|
|
Packit |
4e1bf9 |
#include <stdlib.h>
|
|
Packit |
4e1bf9 |
#include <string.h>
|
|
Packit |
4e1bf9 |
#include <termios.h>
|
|
Packit |
4e1bf9 |
#include <unistd.h>
|
|
Packit |
4e1bf9 |
#include <sys/ioctl.h>
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
#include "ed.h"
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
jmp_buf jmp_state;
|
|
Packit |
4e1bf9 |
static int mutex = 0; /* If > 0, signals stay pending */
|
|
Packit |
4e1bf9 |
static int window_lines_ = 22; /* scroll lines set by sigwinch_handler */
|
|
Packit |
4e1bf9 |
static int window_columns_ = 72;
|
|
Packit |
4e1bf9 |
static bool sighup_pending = false;
|
|
Packit |
4e1bf9 |
static bool sigint_pending = false;
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
static void sighup_handler( int signum )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
if( signum ) {} /* keep compiler happy */
|
|
Packit |
4e1bf9 |
if( mutex ) sighup_pending = true;
|
|
Packit |
4e1bf9 |
else
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
const char hb[] = "ed.hup";
|
|
Packit |
4e1bf9 |
sighup_pending = false;
|
|
Packit |
4e1bf9 |
if( last_addr() && modified() &&
|
|
Packit |
4e1bf9 |
write_file( hb, "w", 1, last_addr() ) < 0 )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
char * const s = getenv( "HOME" );
|
|
Packit |
4e1bf9 |
const int len = ( s ? strlen( s ) : 0 );
|
|
Packit |
4e1bf9 |
const int need_slash = ( ( !len || s[len-1] != '/' ) ? 1 : 0 );
|
|
Packit |
4e1bf9 |
char * const hup = ( ( len + need_slash + (int)sizeof hb < path_max( 0 ) ) ?
|
|
Packit |
4e1bf9 |
(char *) malloc( len + need_slash + sizeof hb ) : 0 );
|
|
Packit |
4e1bf9 |
if( len && hup ) /* hup filename */
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
memcpy( hup, s, len );
|
|
Packit |
4e1bf9 |
if( need_slash ) hup[len] = '/';
|
|
Packit |
4e1bf9 |
memcpy( hup + len + need_slash, hb, sizeof hb );
|
|
Packit |
4e1bf9 |
if( write_file( hup, "w", 1, last_addr() ) >= 0 ) exit( 0 );
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
exit( 1 ); /* hup file write failed */
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
exit( 0 );
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
static void sigint_handler( int signum )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
if( mutex ) sigint_pending = true;
|
|
Packit |
4e1bf9 |
else
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
sigset_t set;
|
|
Packit |
4e1bf9 |
sigint_pending = false;
|
|
Packit |
4e1bf9 |
sigemptyset( &set );
|
|
Packit |
4e1bf9 |
sigaddset( &set, signum );
|
|
Packit |
4e1bf9 |
sigprocmask( SIG_UNBLOCK, &set, 0 );
|
|
Packit |
4e1bf9 |
longjmp( jmp_state, -1 );
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
static void sigwinch_handler( int signum )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
#ifdef TIOCGWINSZ
|
|
Packit |
4e1bf9 |
struct winsize ws; /* window size structure */
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
if( ioctl( 0, TIOCGWINSZ, (char *) &ws ) >= 0 )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
/* Sanity check values of environment vars */
|
|
Packit |
4e1bf9 |
if( ws.ws_row > 2 && ws.ws_row < 600 ) window_lines_ = ws.ws_row - 2;
|
|
Packit |
4e1bf9 |
if( ws.ws_col > 8 && ws.ws_col < 1800 ) window_columns_ = ws.ws_col - 8;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
#endif
|
|
Packit |
4e1bf9 |
if( signum ) {} /* keep compiler happy */
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
static int set_signal( const int signum, void (*handler)( int ) )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
struct sigaction new_action;
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
new_action.sa_handler = handler;
|
|
Packit |
4e1bf9 |
sigemptyset( &new_action.sa_mask );
|
|
Packit |
4e1bf9 |
#ifdef SA_RESTART
|
|
Packit |
4e1bf9 |
new_action.sa_flags = SA_RESTART;
|
|
Packit |
4e1bf9 |
#else
|
|
Packit |
4e1bf9 |
new_action.sa_flags = 0;
|
|
Packit |
4e1bf9 |
#endif
|
|
Packit |
4e1bf9 |
return sigaction( signum, &new_action, 0 );
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
void enable_interrupts( void )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
if( --mutex <= 0 )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
mutex = 0;
|
|
Packit |
4e1bf9 |
if( sighup_pending ) sighup_handler( SIGHUP );
|
|
Packit |
4e1bf9 |
if( sigint_pending ) sigint_handler( SIGINT );
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
void disable_interrupts( void ) { ++mutex; }
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
void set_signals( void )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
#ifdef SIGWINCH
|
|
Packit |
4e1bf9 |
sigwinch_handler( SIGWINCH );
|
|
Packit |
4e1bf9 |
if( isatty( 0 ) ) set_signal( SIGWINCH, sigwinch_handler );
|
|
Packit |
4e1bf9 |
#endif
|
|
Packit |
4e1bf9 |
set_signal( SIGHUP, sighup_handler );
|
|
Packit |
4e1bf9 |
set_signal( SIGQUIT, SIG_IGN );
|
|
Packit |
4e1bf9 |
set_signal( SIGINT, sigint_handler );
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
void set_window_lines( const int lines ) { window_lines_ = lines; }
|
|
Packit |
4e1bf9 |
int window_columns( void ) { return window_columns_; }
|
|
Packit |
4e1bf9 |
int window_lines( void ) { return window_lines_; }
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
/* convert a string to int with out_of_range detection */
|
|
Packit |
4e1bf9 |
bool parse_int( int * const i, const char * const str, const char ** const tail )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
char * tmp;
|
|
Packit |
4e1bf9 |
long li;
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
errno = 0;
|
|
Packit |
4e1bf9 |
*i = li = strtol( str, &tmp, 10 );
|
|
Packit |
4e1bf9 |
if( tail ) *tail = tmp;
|
|
Packit |
4e1bf9 |
if( tmp == str )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
set_error_msg( "Bad numerical result" );
|
|
Packit |
4e1bf9 |
*i = 0;
|
|
Packit |
4e1bf9 |
return false;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
if( errno == ERANGE || li > INT_MAX || li < -INT_MAX )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
set_error_msg( "Numerical result out of range" );
|
|
Packit |
4e1bf9 |
*i = 0;
|
|
Packit |
4e1bf9 |
return false;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
return true;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
/* assure at least a minimum size for buffer 'buf' */
|
|
Packit |
4e1bf9 |
bool resize_buffer( char ** const buf, int * const size, const int min_size )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
if( *size < min_size )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
const int new_size = ( min_size < 512 ? 512 : ( min_size / 512 ) * 1024 );
|
|
Packit |
4e1bf9 |
void * new_buf = 0;
|
|
Packit |
4e1bf9 |
disable_interrupts();
|
|
Packit |
4e1bf9 |
if( *buf ) new_buf = realloc( *buf, new_size );
|
|
Packit |
4e1bf9 |
else new_buf = malloc( new_size );
|
|
Packit |
4e1bf9 |
if( !new_buf )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
show_strerror( 0, errno );
|
|
Packit |
4e1bf9 |
set_error_msg( "Memory exhausted" );
|
|
Packit |
4e1bf9 |
enable_interrupts();
|
|
Packit |
4e1bf9 |
return false;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
*size = new_size;
|
|
Packit |
4e1bf9 |
*buf = (char *)new_buf;
|
|
Packit |
4e1bf9 |
enable_interrupts();
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
return true;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
/* assure at least a minimum size for buffer 'buf' */
|
|
Packit |
4e1bf9 |
bool resize_line_buffer( const line_t *** const buf, int * const size,
|
|
Packit |
4e1bf9 |
const int min_size )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
if( *size < min_size )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
const int new_size = ( min_size < 512 ? 512 : ( min_size / 512 ) * 1024 );
|
|
Packit |
4e1bf9 |
void * new_buf = 0;
|
|
Packit |
4e1bf9 |
disable_interrupts();
|
|
Packit |
4e1bf9 |
if( *buf ) new_buf = realloc( *buf, new_size );
|
|
Packit |
4e1bf9 |
else new_buf = malloc( new_size );
|
|
Packit |
4e1bf9 |
if( !new_buf )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
show_strerror( 0, errno );
|
|
Packit |
4e1bf9 |
set_error_msg( "Memory exhausted" );
|
|
Packit |
4e1bf9 |
enable_interrupts();
|
|
Packit |
4e1bf9 |
return false;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
*size = new_size;
|
|
Packit |
4e1bf9 |
*buf = (const line_t **)new_buf;
|
|
Packit |
4e1bf9 |
enable_interrupts();
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
return true;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
/* assure at least a minimum size for buffer 'buf' */
|
|
Packit |
4e1bf9 |
bool resize_undo_buffer( undo_t ** const buf, int * const size,
|
|
Packit |
4e1bf9 |
const int min_size )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
if( *size < min_size )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
const int new_size = ( min_size < 512 ? 512 : ( min_size / 512 ) * 1024 );
|
|
Packit |
4e1bf9 |
void * new_buf = 0;
|
|
Packit |
4e1bf9 |
disable_interrupts();
|
|
Packit |
4e1bf9 |
if( *buf ) new_buf = realloc( *buf, new_size );
|
|
Packit |
4e1bf9 |
else new_buf = malloc( new_size );
|
|
Packit |
4e1bf9 |
if( !new_buf )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
show_strerror( 0, errno );
|
|
Packit |
4e1bf9 |
set_error_msg( "Memory exhausted" );
|
|
Packit |
4e1bf9 |
enable_interrupts();
|
|
Packit |
4e1bf9 |
return false;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
*size = new_size;
|
|
Packit |
4e1bf9 |
*buf = (undo_t *)new_buf;
|
|
Packit |
4e1bf9 |
enable_interrupts();
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
return true;
|
|
Packit |
4e1bf9 |
}
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
/* return unescaped copy of escaped string */
|
|
Packit |
4e1bf9 |
const char * strip_escapes( const char * p )
|
|
Packit |
4e1bf9 |
{
|
|
Packit |
4e1bf9 |
static char * buf = 0;
|
|
Packit |
4e1bf9 |
static int bufsz = 0;
|
|
Packit |
4e1bf9 |
const int len = strlen( p );
|
|
Packit |
4e1bf9 |
int i = 0;
|
|
Packit |
4e1bf9 |
|
|
Packit |
4e1bf9 |
if( !resize_buffer( &buf, &bufsz, len + 1 ) ) return 0;
|
|
Packit |
4e1bf9 |
/* assert: no trailing escape */
|
|
Packit |
4e1bf9 |
while( ( buf[i++] = ( (*p == '\\' ) ? *++p : *p ) ) )
|
|
Packit |
4e1bf9 |
++p;
|
|
Packit |
4e1bf9 |
return buf;
|
|
Packit |
4e1bf9 |
}
|