Blame signal.c

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
  }