Blame signal.c

Packit Bot a3ac83
/* signal.c: signal and miscellaneous routines for the ed line editor. */
Packit Bot a3ac83
/*  GNU ed - The GNU line editor.
Packit Bot a3ac83
    Copyright (C) 1993, 1994 Andrew Moore, Talke Studio
Packit Bot a3ac83
    Copyright (C) 2006-2017 Antonio Diaz Diaz.
Packit Bot a3ac83
Packit Bot a3ac83
    This program is free software: you can redistribute it and/or modify
Packit Bot a3ac83
    it under the terms of the GNU General Public License as published by
Packit Bot a3ac83
    the Free Software Foundation, either version 2 of the License, or
Packit Bot a3ac83
    (at your option) any later version.
Packit Bot a3ac83
Packit Bot a3ac83
    This program is distributed in the hope that it will be useful,
Packit Bot a3ac83
    but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Bot a3ac83
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Bot a3ac83
    GNU General Public License for more details.
Packit Bot a3ac83
Packit Bot a3ac83
    You should have received a copy of the GNU General Public License
Packit Bot a3ac83
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit Bot a3ac83
*/
Packit Bot a3ac83
Packit Bot a3ac83
#include <ctype.h>
Packit Bot a3ac83
#include <errno.h>
Packit Bot a3ac83
#include <limits.h>
Packit Bot a3ac83
#include <setjmp.h>
Packit Bot a3ac83
#include <signal.h>
Packit Bot a3ac83
#include <stdlib.h>
Packit Bot a3ac83
#include <string.h>
Packit Bot a3ac83
#include <termios.h>
Packit Bot a3ac83
#include <unistd.h>
Packit Bot a3ac83
#include <sys/ioctl.h>
Packit Bot a3ac83
Packit Bot a3ac83
#include "ed.h"
Packit Bot a3ac83
Packit Bot a3ac83
Packit Bot a3ac83
jmp_buf jmp_state;
Packit Bot a3ac83
static int mutex = 0;			/* If > 0, signals stay pending */
Packit Bot a3ac83
static int window_lines_ = 22;		/* scroll lines set by sigwinch_handler */
Packit Bot a3ac83
static int window_columns_ = 72;
Packit Bot a3ac83
static bool sighup_pending = false;
Packit Bot a3ac83
static bool sigint_pending = false;
Packit Bot a3ac83
Packit Bot a3ac83
Packit Bot a3ac83
static void sighup_handler( int signum )
Packit Bot a3ac83
  {
Packit Bot a3ac83
  if( signum ) {}			/* keep compiler happy */
Packit Bot a3ac83
  if( mutex ) sighup_pending = true;
Packit Bot a3ac83
  else
Packit Bot a3ac83
    {
Packit Bot a3ac83
    const char hb[] = "ed.hup";
Packit Bot a3ac83
    sighup_pending = false;
Packit Bot a3ac83
    if( last_addr() && modified() &&
Packit Bot a3ac83
        write_file( hb, "w", 1, last_addr() ) < 0 )
Packit Bot a3ac83
      {
Packit Bot a3ac83
      char * const s = getenv( "HOME" );
Packit Bot a3ac83
      const int len = ( s ? strlen( s ) : 0 );
Packit Bot a3ac83
      const int need_slash = ( ( !len || s[len-1] != '/' ) ? 1 : 0 );
Packit Bot a3ac83
      char * const hup = ( ( len + need_slash + (int)sizeof hb < path_max( 0 ) ) ?
Packit Bot a3ac83
                    (char *) malloc( len + need_slash + sizeof hb ) : 0 );
Packit Bot a3ac83
      if( len && hup )			/* hup filename */
Packit Bot a3ac83
        {
Packit Bot a3ac83
        memcpy( hup, s, len );
Packit Bot a3ac83
        if( need_slash ) hup[len] = '/';
Packit Bot a3ac83
        memcpy( hup + len + need_slash, hb, sizeof hb );
Packit Bot a3ac83
        if( write_file( hup, "w", 1, last_addr() ) >= 0 ) exit( 0 );
Packit Bot a3ac83
        }
Packit Bot a3ac83
      exit( 1 );			/* hup file write failed */
Packit Bot a3ac83
      }
Packit Bot a3ac83
    exit( 0 );
Packit Bot a3ac83
    }
Packit Bot a3ac83
  }
Packit Bot a3ac83
Packit Bot a3ac83
Packit Bot a3ac83
static void sigint_handler( int signum )
Packit Bot a3ac83
  {
Packit Bot a3ac83
  if( mutex ) sigint_pending = true;
Packit Bot a3ac83
  else
Packit Bot a3ac83
    {
Packit Bot a3ac83
    sigset_t set;
Packit Bot a3ac83
    sigint_pending = false;
Packit Bot a3ac83
    sigemptyset( &set );
Packit Bot a3ac83
    sigaddset( &set, signum );
Packit Bot a3ac83
    sigprocmask( SIG_UNBLOCK, &set, 0 );
Packit Bot a3ac83
    longjmp( jmp_state, -1 );
Packit Bot a3ac83
    }
Packit Bot a3ac83
  }
Packit Bot a3ac83
Packit Bot a3ac83
Packit Bot a3ac83
static void sigwinch_handler( int signum )
Packit Bot a3ac83
  {
Packit Bot a3ac83
#ifdef TIOCGWINSZ
Packit Bot a3ac83
  struct winsize ws;			/* window size structure */
Packit Bot a3ac83
Packit Bot a3ac83
  if( ioctl( 0, TIOCGWINSZ, (char *) &ws ) >= 0 )
Packit Bot a3ac83
    {
Packit Bot a3ac83
    /* Sanity check values of environment vars */
Packit Bot a3ac83
    if( ws.ws_row > 2 && ws.ws_row < 600 ) window_lines_ = ws.ws_row - 2;
Packit Bot a3ac83
    if( ws.ws_col > 8 && ws.ws_col < 1800 ) window_columns_ = ws.ws_col - 8;
Packit Bot a3ac83
    }
Packit Bot a3ac83
#endif
Packit Bot a3ac83
  if( signum ) {}			/* keep compiler happy */
Packit Bot a3ac83
  }
Packit Bot a3ac83
Packit Bot a3ac83
Packit Bot a3ac83
static int set_signal( const int signum, void (*handler)( int ) )
Packit Bot a3ac83
  {
Packit Bot a3ac83
  struct sigaction new_action;
Packit Bot a3ac83
Packit Bot a3ac83
  new_action.sa_handler = handler;
Packit Bot a3ac83
  sigemptyset( &new_action.sa_mask );
Packit Bot a3ac83
#ifdef SA_RESTART
Packit Bot a3ac83
  new_action.sa_flags = SA_RESTART;
Packit Bot a3ac83
#else
Packit Bot a3ac83
  new_action.sa_flags = 0;
Packit Bot a3ac83
#endif
Packit Bot a3ac83
  return sigaction( signum, &new_action, 0 );
Packit Bot a3ac83
  }
Packit Bot a3ac83
Packit Bot a3ac83
Packit Bot a3ac83
void enable_interrupts( void )
Packit Bot a3ac83
  {
Packit Bot a3ac83
  if( --mutex <= 0 )
Packit Bot a3ac83
    {
Packit Bot a3ac83
    mutex = 0;
Packit Bot a3ac83
    if( sighup_pending ) sighup_handler( SIGHUP );
Packit Bot a3ac83
    if( sigint_pending ) sigint_handler( SIGINT );
Packit Bot a3ac83
    }
Packit Bot a3ac83
  }
Packit Bot a3ac83
Packit Bot a3ac83
Packit Bot a3ac83
void disable_interrupts( void ) { ++mutex; }
Packit Bot a3ac83
Packit Bot a3ac83
Packit Bot a3ac83
void set_signals( void )
Packit Bot a3ac83
  {
Packit Bot a3ac83
#ifdef SIGWINCH
Packit Bot a3ac83
  sigwinch_handler( SIGWINCH );
Packit Bot a3ac83
  if( isatty( 0 ) ) set_signal( SIGWINCH, sigwinch_handler );
Packit Bot a3ac83
#endif
Packit Bot a3ac83
  set_signal( SIGHUP, sighup_handler );
Packit Bot a3ac83
  set_signal( SIGQUIT, SIG_IGN );
Packit Bot a3ac83
  set_signal( SIGINT, sigint_handler );
Packit Bot a3ac83
  }
Packit Bot a3ac83
Packit Bot a3ac83
Packit Bot a3ac83
void set_window_lines( const int lines ) { window_lines_ = lines; }
Packit Bot a3ac83
int window_columns( void ) { return window_columns_; }
Packit Bot a3ac83
int window_lines( void ) { return window_lines_; }
Packit Bot a3ac83
Packit Bot a3ac83
Packit Bot a3ac83
/* convert a string to int with out_of_range detection */
Packit Bot a3ac83
bool parse_int( int * const i, const char * const str, const char ** const tail )
Packit Bot a3ac83
  {
Packit Bot a3ac83
  char * tmp;
Packit Bot a3ac83
  long li;
Packit Bot a3ac83
Packit Bot a3ac83
  errno = 0;
Packit Bot a3ac83
  *i = li = strtol( str, &tmp, 10 );
Packit Bot a3ac83
  if( tail ) *tail = tmp;
Packit Bot a3ac83
  if( tmp == str )
Packit Bot a3ac83
    {
Packit Bot a3ac83
    set_error_msg( "Bad numerical result" );
Packit Bot a3ac83
    *i = 0;
Packit Bot a3ac83
    return false;
Packit Bot a3ac83
    }
Packit Bot a3ac83
  if( errno == ERANGE || li > INT_MAX || li < -INT_MAX )
Packit Bot a3ac83
    {
Packit Bot a3ac83
    set_error_msg( "Numerical result out of range" );
Packit Bot a3ac83
    *i = 0;
Packit Bot a3ac83
    return false;
Packit Bot a3ac83
    }
Packit Bot a3ac83
  return true;
Packit Bot a3ac83
  }
Packit Bot a3ac83
Packit Bot a3ac83
Packit Bot a3ac83
/* assure at least a minimum size for buffer 'buf' */
Packit Bot a3ac83
bool resize_buffer( char ** const buf, int * const size, const int min_size )
Packit Bot a3ac83
  {
Packit Bot a3ac83
  if( *size < min_size )
Packit Bot a3ac83
    {
Packit Bot a3ac83
    const int new_size = ( min_size < 512 ? 512 : ( min_size / 512 ) * 1024 );
Packit Bot a3ac83
    void * new_buf = 0;
Packit Bot a3ac83
    disable_interrupts();
Packit Bot a3ac83
    if( *buf ) new_buf = realloc( *buf, new_size );
Packit Bot a3ac83
    else new_buf = malloc( new_size );
Packit Bot a3ac83
    if( !new_buf )
Packit Bot a3ac83
      {
Packit Bot a3ac83
      show_strerror( 0, errno );
Packit Bot a3ac83
      set_error_msg( "Memory exhausted" );
Packit Bot a3ac83
      enable_interrupts();
Packit Bot a3ac83
      return false;
Packit Bot a3ac83
      }
Packit Bot a3ac83
    *size = new_size;
Packit Bot a3ac83
    *buf = (char *)new_buf;
Packit Bot a3ac83
    enable_interrupts();
Packit Bot a3ac83
    }
Packit Bot a3ac83
  return true;
Packit Bot a3ac83
  }
Packit Bot a3ac83
Packit Bot a3ac83
Packit Bot a3ac83
/* assure at least a minimum size for buffer 'buf' */
Packit Bot a3ac83
bool resize_line_buffer( const line_t *** const buf, int * const size,
Packit Bot a3ac83
                         const int min_size )
Packit Bot a3ac83
  {
Packit Bot a3ac83
  if( *size < min_size )
Packit Bot a3ac83
    {
Packit Bot a3ac83
    const int new_size = ( min_size < 512 ? 512 : ( min_size / 512 ) * 1024 );
Packit Bot a3ac83
    void * new_buf = 0;
Packit Bot a3ac83
    disable_interrupts();
Packit Bot a3ac83
    if( *buf ) new_buf = realloc( *buf, new_size );
Packit Bot a3ac83
    else new_buf = malloc( new_size );
Packit Bot a3ac83
    if( !new_buf )
Packit Bot a3ac83
      {
Packit Bot a3ac83
      show_strerror( 0, errno );
Packit Bot a3ac83
      set_error_msg( "Memory exhausted" );
Packit Bot a3ac83
      enable_interrupts();
Packit Bot a3ac83
      return false;
Packit Bot a3ac83
      }
Packit Bot a3ac83
    *size = new_size;
Packit Bot a3ac83
    *buf = (const line_t **)new_buf;
Packit Bot a3ac83
    enable_interrupts();
Packit Bot a3ac83
    }
Packit Bot a3ac83
  return true;
Packit Bot a3ac83
  }
Packit Bot a3ac83
Packit Bot a3ac83
Packit Bot a3ac83
/* assure at least a minimum size for buffer 'buf' */
Packit Bot a3ac83
bool resize_undo_buffer( undo_t ** const buf, int * const size,
Packit Bot a3ac83
                         const int min_size )
Packit Bot a3ac83
  {
Packit Bot a3ac83
  if( *size < min_size )
Packit Bot a3ac83
    {
Packit Bot a3ac83
    const int new_size = ( min_size < 512 ? 512 : ( min_size / 512 ) * 1024 );
Packit Bot a3ac83
    void * new_buf = 0;
Packit Bot a3ac83
    disable_interrupts();
Packit Bot a3ac83
    if( *buf ) new_buf = realloc( *buf, new_size );
Packit Bot a3ac83
    else new_buf = malloc( new_size );
Packit Bot a3ac83
    if( !new_buf )
Packit Bot a3ac83
      {
Packit Bot a3ac83
      show_strerror( 0, errno );
Packit Bot a3ac83
      set_error_msg( "Memory exhausted" );
Packit Bot a3ac83
      enable_interrupts();
Packit Bot a3ac83
      return false;
Packit Bot a3ac83
      }
Packit Bot a3ac83
    *size = new_size;
Packit Bot a3ac83
    *buf = (undo_t *)new_buf;
Packit Bot a3ac83
    enable_interrupts();
Packit Bot a3ac83
    }
Packit Bot a3ac83
  return true;
Packit Bot a3ac83
  }
Packit Bot a3ac83
Packit Bot a3ac83
Packit Bot a3ac83
/* return unescaped copy of escaped string */
Packit Bot a3ac83
const char * strip_escapes( const char * p )
Packit Bot a3ac83
  {
Packit Bot a3ac83
  static char * buf = 0;
Packit Bot a3ac83
  static int bufsz = 0;
Packit Bot a3ac83
  const int len = strlen( p );
Packit Bot a3ac83
  int i = 0;
Packit Bot a3ac83
Packit Bot a3ac83
  if( !resize_buffer( &buf, &bufsz, len + 1 ) ) return 0;
Packit Bot a3ac83
  /* assert: no trailing escape */
Packit Bot a3ac83
  while( ( buf[i++] = ( (*p == '\\' ) ? *++p : *p ) ) )
Packit Bot a3ac83
    ++p;
Packit Bot a3ac83
  return buf;
Packit Bot a3ac83
  }