2005-10-17 23:24:12 +10:00
/** \file output.c
Generic output functions
*/
2005-09-20 23:26:39 +10:00
# include "config.h"
# include <stdlib.h>
# include <stdio.h>
# include <string.h>
# include <errno.h>
# include <termios.h>
# include <sys/types.h>
# include <sys/stat.h>
2006-08-10 08:53:38 +10:00
# ifdef HAVE_SYS_TERMIOS_H
# include <sys/termios.h>
# endif
# ifdef HAVE_SYS_IOCTL_H
2005-09-20 23:26:39 +10:00
# include <sys/ioctl.h>
2006-08-10 08:53:38 +10:00
# endif
2005-09-20 23:26:39 +10:00
# include <sys/time.h>
# include <unistd.h>
# include <wctype.h>
# if HAVE_NCURSES_H
# include <ncurses.h>
# else
# include <curses.h>
# endif
# if HAVE_TERMIO_H
# include <termio.h>
# endif
2006-01-19 22:22:07 +10:00
# if HAVE_TERM_H
2005-09-20 23:26:39 +10:00
# include <term.h>
2006-01-19 22:22:07 +10:00
# elif HAVE_NCURSES_TERM_H
# include <ncurses/term.h>
# endif
2005-09-20 23:26:39 +10:00
# include <signal.h>
# include <fcntl.h>
# include <dirent.h>
# include <time.h>
# include <wchar.h>
2006-02-28 23:17:16 +10:00
# include "fallback.h"
2005-09-20 23:26:39 +10:00
# include "util.h"
2006-02-28 23:17:16 +10:00
2005-09-20 23:26:39 +10:00
# include "wutil.h"
# include "expand.h"
# include "common.h"
# include "output.h"
2006-02-10 01:50:20 +10:00
# include "halloc_util.h"
2005-09-20 23:26:39 +10:00
# include "highlight.h"
/**
Number of color names in the col array
*/
# define COLORS (sizeof(col) / sizeof(wchar_t *))
2006-02-17 00:21:00 +10:00
static int writeb_internal ( char c ) ;
2005-09-20 23:26:39 +10:00
/**
Names of different colors .
*/
static wchar_t * col [ ] =
{
L " black " ,
L " red " ,
L " green " ,
L " brown " ,
L " yellow " ,
L " blue " ,
L " magenta " ,
L " purple " ,
L " cyan " ,
L " white "
L " normal "
}
;
/**
Mapping from color name ( the ' col ' array ) to color index as used in
ANSI color terminals , and also the fish_color_ * constants defined
in highlight . h . Non - ANSI terminals will display the wrong colors ,
since they use a different mapping .
*/
static int col_idx [ ] =
{
0 ,
1 ,
2 ,
3 ,
3 ,
4 ,
5 ,
5 ,
6 ,
7 ,
FISH_COLOR_NORMAL ,
}
;
2005-10-17 23:24:12 +10:00
/**
Size of writestr_buff
*/
2005-10-14 00:08:33 +10:00
static size_t writestr_buff_sz = 0 ;
2005-10-17 23:24:12 +10:00
/**
Temp buffer used for converting from wide to narrow strings
*/
2005-10-14 00:08:33 +10:00
static char * writestr_buff = 0 ;
2006-02-16 23:40:25 +10:00
/**
The function used for output
*/
2006-02-17 00:21:00 +10:00
static int ( * out ) ( char c ) = & writeb_internal ;
2006-02-16 23:40:25 +10:00
2006-06-20 10:50:10 +10:00
/**
Cleanup function . Run automatically through halloc
*/
2006-02-10 01:50:20 +10:00
static void output_destroy ( )
2005-10-14 00:08:33 +10:00
{
free ( writestr_buff ) ;
}
2006-02-17 00:21:00 +10:00
void output_set_writer ( int ( * writer ) ( char ) )
2006-02-16 23:40:25 +10:00
{
2006-07-11 08:39:56 +10:00
CHECK ( writer , ) ;
2006-02-16 23:40:25 +10:00
out = writer ;
}
2006-10-02 02:02:58 +10:00
int ( * output_get_writer ( ) ) ( char )
{
return out ;
}
2005-10-14 00:08:33 +10:00
2005-09-20 23:26:39 +10:00
void set_color ( int c , int c2 )
{
2005-10-17 23:24:12 +10:00
static int last_color = FISH_COLOR_NORMAL ;
static int last_color2 = FISH_COLOR_NORMAL ;
2006-05-27 23:39:30 +10:00
static int was_bold = 0 ;
2006-06-14 23:22:40 +10:00
static int was_underline = 0 ;
2005-09-20 23:26:39 +10:00
int bg_set = 0 , last_bg_set = 0 ;
char * fg = 0 , * bg = 0 ;
2006-05-27 23:39:30 +10:00
int is_bold = 0 ;
2006-06-14 23:22:40 +10:00
int is_underline = 0 ;
2006-05-27 23:39:30 +10:00
2007-01-16 03:51:44 +10:00
/*
Test if we have at least basic support for setting fonts , colors
and related bits - otherwise just give up . . .
*/
if ( ! exit_attribute_mode )
{
return ;
}
2006-05-27 23:39:30 +10:00
is_bold | = ( c & FISH_COLOR_BOLD ) ! = 0 ;
is_bold | = ( c2 & FISH_COLOR_BOLD ) ! = 0 ;
2006-06-14 23:22:40 +10:00
is_underline | = ( c & FISH_COLOR_UNDERLINE ) ! = 0 ;
is_underline | = ( c2 & FISH_COLOR_UNDERLINE ) ! = 0 ;
c = c & ( ~ ( FISH_COLOR_BOLD | FISH_COLOR_UNDERLINE ) ) ;
c2 = c2 & ( ~ ( FISH_COLOR_BOLD | FISH_COLOR_UNDERLINE ) ) ;
2006-05-27 23:39:30 +10:00
2005-09-20 23:26:39 +10:00
if ( ( set_a_foreground ! = 0 ) & & ( strlen ( set_a_foreground ) ! = 0 ) )
{
fg = set_a_foreground ;
bg = set_a_background ;
}
else if ( ( set_foreground ! = 0 ) & & ( strlen ( set_foreground ) ! = 0 ) )
{
fg = set_foreground ;
bg = set_background ;
}
if ( ( c = = FISH_COLOR_RESET ) | | ( c2 = = FISH_COLOR_RESET ) )
{
c = c2 = FISH_COLOR_NORMAL ;
2006-05-27 23:39:30 +10:00
was_bold = 0 ;
2006-06-14 23:22:40 +10:00
was_underline = 0 ;
2005-09-20 23:26:39 +10:00
if ( fg )
2006-02-20 23:11:46 +10:00
{
2006-05-27 23:39:30 +10:00
/*
If we exit attibute mode , we must first set a color , or
previously coloured text might lose it ' s
color . Terminals are weird . . .
*/
2006-02-17 00:21:00 +10:00
writembs ( tparm ( fg , 0 ) ) ;
2006-02-20 23:11:46 +10:00
}
2006-02-17 00:21:00 +10:00
writembs ( exit_attribute_mode ) ;
2005-09-20 23:26:39 +10:00
return ;
}
2006-05-27 23:39:30 +10:00
if ( was_bold & & ! is_bold )
{
/*
Only way to exit bold mode is a reset of all attributes .
*/
writembs ( exit_attribute_mode ) ;
last_color = FISH_COLOR_NORMAL ;
last_color2 = FISH_COLOR_NORMAL ;
was_bold = 0 ;
2006-06-14 23:22:40 +10:00
was_underline = 0 ;
2006-05-27 23:39:30 +10:00
}
2005-09-20 23:26:39 +10:00
if ( last_color2 ! = FISH_COLOR_NORMAL & &
last_color2 ! = FISH_COLOR_RESET & &
last_color2 ! = FISH_COLOR_IGNORE )
{
/*
Background was set
*/
last_bg_set = 1 ;
}
if ( c2 ! = FISH_COLOR_NORMAL & &
c2 ! = FISH_COLOR_IGNORE )
{
/*
Background is set
*/
bg_set = 1 ;
c = ( c2 = = FISH_COLOR_WHITE ) ? FISH_COLOR_BLACK : FISH_COLOR_WHITE ;
}
if ( ( enter_bold_mode ! = 0 ) & & ( strlen ( enter_bold_mode ) > 0 ) )
{
if ( bg_set & & ! last_bg_set )
{
/*
2005-10-17 23:24:12 +10:00
Background color changed and is set , so we enter bold
2006-05-27 23:39:30 +10:00
mode to make reading easier . This means bold mode is
_always_ on when the background color is set .
2005-09-20 23:26:39 +10:00
*/
2006-02-17 00:21:00 +10:00
writembs ( enter_bold_mode ) ;
2005-09-20 23:26:39 +10:00
}
if ( ! bg_set & & last_bg_set )
{
/*
2005-10-17 23:24:12 +10:00
Background color changed and is no longer set , so we
exit bold mode
2005-09-20 23:26:39 +10:00
*/
2006-02-17 00:21:00 +10:00
writembs ( exit_attribute_mode ) ;
2006-06-14 23:22:40 +10:00
was_bold = 0 ;
was_underline = 0 ;
2005-09-20 23:26:39 +10:00
/*
We don ' t know if exit_attribute_mode resets colors , so
we set it to something known .
*/
if ( fg )
{
2006-02-17 00:21:00 +10:00
writembs ( tparm ( fg , 0 ) ) ;
2005-09-20 23:26:39 +10:00
last_color = 0 ;
}
}
}
if ( last_color ! = c )
{
if ( c = = FISH_COLOR_NORMAL )
{
if ( fg )
2006-02-20 23:11:46 +10:00
{
2006-02-17 00:21:00 +10:00
writembs ( tparm ( fg , 0 ) ) ;
2006-02-20 23:11:46 +10:00
}
2006-02-17 00:21:00 +10:00
writembs ( exit_attribute_mode ) ;
2005-09-20 23:26:39 +10:00
last_color2 = FISH_COLOR_NORMAL ;
2006-06-14 23:22:40 +10:00
was_bold = 0 ;
was_underline = 0 ;
2005-09-20 23:26:39 +10:00
}
2006-02-20 23:11:46 +10:00
else if ( ( c > = 0 ) & & ( c < FISH_COLOR_NORMAL ) )
2005-09-20 23:26:39 +10:00
{
if ( fg )
{
2006-02-17 00:21:00 +10:00
writembs ( tparm ( fg , c ) ) ;
2005-09-20 23:26:39 +10:00
}
}
}
last_color = c ;
if ( last_color2 ! = c2 )
{
if ( c2 = = FISH_COLOR_NORMAL )
{
if ( bg )
{
2006-02-17 00:21:00 +10:00
writembs ( tparm ( bg , 0 ) ) ;
2005-09-20 23:26:39 +10:00
}
2006-02-20 23:11:46 +10:00
writembs ( exit_attribute_mode ) ;
if ( ( last_color ! = FISH_COLOR_NORMAL ) & & fg )
2005-09-20 23:26:39 +10:00
{
2006-07-31 10:48:04 +10:00
if ( fg )
{
writembs ( tparm ( fg , last_color ) ) ;
}
2005-09-20 23:26:39 +10:00
}
2006-07-31 10:48:04 +10:00
2005-09-20 23:26:39 +10:00
2006-06-14 23:22:40 +10:00
was_bold = 0 ;
was_underline = 0 ;
2005-09-20 23:26:39 +10:00
last_color2 = c2 ;
}
2006-02-20 23:11:46 +10:00
else if ( ( c2 > = 0 ) & & ( c2 < FISH_COLOR_NORMAL ) )
2005-09-20 23:26:39 +10:00
{
if ( bg )
{
2006-02-17 00:21:00 +10:00
writembs ( tparm ( bg , c2 ) ) ;
2005-09-20 23:26:39 +10:00
}
last_color2 = c2 ;
}
}
2006-05-27 23:39:30 +10:00
/*
2006-06-14 23:22:40 +10:00
Lastly , we set bold mode and underline mode correctly
2006-05-27 23:39:30 +10:00
*/
if ( ( enter_bold_mode ! = 0 ) & & ( strlen ( enter_bold_mode ) > 0 ) & & ! bg_set )
{
if ( is_bold & & ! was_bold )
{
2006-07-31 10:48:04 +10:00
if ( enter_bold_mode )
{
writembs ( tparm ( enter_bold_mode ) ) ;
}
2006-05-27 23:39:30 +10:00
}
was_bold = is_bold ;
}
2006-06-14 23:22:40 +10:00
if ( was_underline & & ! is_underline )
{
writembs ( exit_underline_mode ) ;
}
if ( ! was_underline & & is_underline )
{
writembs ( enter_underline_mode ) ;
}
was_underline = is_underline ;
2005-09-20 23:26:39 +10:00
}
2006-06-20 10:50:10 +10:00
/**
Default output method , simply calls write ( ) on stdout
*/
2006-02-17 00:21:00 +10:00
static int writeb_internal ( char c )
{
write ( 1 , & c , 1 ) ;
return 0 ;
}
2006-02-16 23:40:25 +10:00
int writeb ( tputs_arg_t b )
{
2006-02-17 00:21:00 +10:00
out ( b ) ;
2006-02-16 23:40:25 +10:00
return 0 ;
}
2005-09-20 23:26:39 +10:00
int writembs ( char * str )
{
2006-07-11 08:39:56 +10:00
CHECK ( str , 1 ) ;
2006-02-28 23:17:16 +10:00
return tputs ( str , 1 , & writeb ) = = ERR ? 1 : 0 ;
2005-09-20 23:26:39 +10:00
}
int writech ( wint_t ch )
{
2006-02-25 04:40:50 +10:00
mbstate_t state ;
2006-02-17 00:21:00 +10:00
int i ;
2007-01-23 02:51:25 +10:00
char buff [ MB_LEN_MAX + 1 ] ;
2006-02-25 04:40:50 +10:00
size_t bytes ;
if ( ( ch > = ENCODE_DIRECT_BASE ) & &
( ch < ENCODE_DIRECT_BASE + 256 ) )
{
2006-02-25 12:21:39 +10:00
buff [ 0 ] = ch - ENCODE_DIRECT_BASE ;
2006-02-25 04:40:50 +10:00
bytes = 1 ;
}
else
{
memset ( & state , 0 , sizeof ( state ) ) ;
bytes = wcrtomb ( buff , ch , & state ) ;
switch ( bytes )
{
case ( size_t ) ( - 1 ) :
{
return 1 ;
}
}
}
2005-09-20 23:26:39 +10:00
2006-02-17 00:21:00 +10:00
for ( i = 0 ; i < bytes ; i + + )
2006-02-20 23:11:46 +10:00
{
2006-02-17 00:21:00 +10:00
out ( buff [ i ] ) ;
2006-02-20 23:11:46 +10:00
}
2005-09-20 23:26:39 +10:00
return 0 ;
}
void writestr ( const wchar_t * str )
{
2006-02-17 00:21:00 +10:00
char * pos ;
2006-07-11 08:39:56 +10:00
CHECK ( str , ) ;
2006-02-17 00:21:00 +10:00
2005-10-15 10:51:26 +10:00
// while( *str )
// writech( *str++ );
2005-10-17 23:24:12 +10:00
/*
Check amount of needed space
*/
size_t len = wcstombs ( 0 , str , 0 ) ;
if ( len = = ( size_t ) - 1 )
{
debug ( 1 , L " Tried to print invalid wide character string " ) ;
return ;
}
2005-10-15 10:51:26 +10:00
2005-10-17 23:24:12 +10:00
len + + ;
2005-10-14 00:08:33 +10:00
2005-10-17 23:24:12 +10:00
/*
Reallocate if needed
*/
2005-10-14 00:08:33 +10:00
if ( writestr_buff_sz < len )
{
2006-02-10 01:50:20 +10:00
if ( ! writestr_buff )
2006-02-20 23:11:46 +10:00
{
2006-02-10 01:50:20 +10:00
halloc_register_function_void ( global_context , & output_destroy ) ;
2006-02-20 23:11:46 +10:00
}
2006-02-10 01:50:20 +10:00
2005-10-17 23:24:12 +10:00
writestr_buff = realloc ( writestr_buff , len ) ;
2005-10-14 00:08:33 +10:00
if ( ! writestr_buff )
2006-02-20 23:11:46 +10:00
{
2006-07-03 20:39:57 +10:00
DIE_MEM ( ) ;
2006-02-20 23:11:46 +10:00
}
2005-10-14 00:08:33 +10:00
writestr_buff_sz = len ;
}
2005-10-17 23:24:12 +10:00
/*
Convert
*/
2005-10-14 00:08:33 +10:00
wcstombs ( writestr_buff ,
str ,
writestr_buff_sz ) ;
2005-10-17 23:24:12 +10:00
/*
Write
*/
2006-02-17 00:21:00 +10:00
for ( pos = writestr_buff ; * pos ; pos + + )
2006-02-20 23:11:46 +10:00
{
2006-02-17 00:21:00 +10:00
out ( * pos ) ;
2006-02-20 23:11:46 +10:00
}
2005-09-20 23:26:39 +10:00
}
void writestr_ellipsis ( const wchar_t * str , int max_width )
{
int written = 0 ;
2006-07-11 08:39:56 +10:00
int tot ;
CHECK ( str , ) ;
tot = my_wcswidth ( str ) ;
2005-09-20 23:26:39 +10:00
if ( tot < = max_width )
{
writestr ( str ) ;
return ;
}
while ( * str ! = 0 )
{
int w = wcwidth ( * str ) ;
if ( written + w + wcwidth ( ellipsis_char ) > max_width )
2006-02-20 23:11:46 +10:00
{
2005-09-20 23:26:39 +10:00
break ;
2006-02-20 23:11:46 +10:00
}
2005-09-20 23:26:39 +10:00
written + = w ;
writech ( * ( str + + ) ) ;
}
written + = wcwidth ( ellipsis_char ) ;
writech ( ellipsis_char ) ;
while ( written < max_width )
{
written + + ;
writestr ( L " " ) ;
}
}
int write_escaped_str ( const wchar_t * str , int max_len )
{
2006-07-11 08:39:56 +10:00
wchar_t * out ;
2005-09-20 23:26:39 +10:00
int i ;
2006-07-11 08:39:56 +10:00
int len ;
2005-09-20 23:26:39 +10:00
int written = 0 ;
2006-07-11 08:39:56 +10:00
CHECK ( str , 0 ) ;
out = escape ( str , 1 ) ;
len = my_wcswidth ( out ) ;
2005-09-20 23:26:39 +10:00
if ( max_len & & ( max_len < len ) )
{
for ( i = 0 ; ( written + wcwidth ( out [ i ] ) ) < = ( max_len - 1 ) ; i + + )
{
writech ( out [ i ] ) ;
written + = wcwidth ( out [ i ] ) ;
}
writech ( ellipsis_char ) ;
written + = wcwidth ( ellipsis_char ) ;
for ( i = written ; i < max_len ; i + + )
{
writech ( L ' ' ) ;
written + + ;
}
}
else
{
written = len ;
writestr ( out ) ;
}
free ( out ) ;
return written ;
}
int output_color_code ( const wchar_t * val )
{
2006-05-27 23:39:30 +10:00
int j , i , color = FISH_COLOR_NORMAL ;
array_list_t el ;
int is_bold = 0 ;
2006-06-14 23:22:40 +10:00
int is_underline = 0 ;
2006-05-27 23:39:30 +10:00
if ( ! val )
return FISH_COLOR_NORMAL ;
2005-09-20 23:26:39 +10:00
2006-05-27 23:39:30 +10:00
al_init ( & el ) ;
2006-05-29 21:13:42 +10:00
tokenize_variable_array ( val , & el ) ;
2006-05-27 23:39:30 +10:00
for ( j = 0 ; j < al_get_count ( & el ) ; j + + )
2005-09-20 23:26:39 +10:00
{
2006-05-27 23:39:30 +10:00
wchar_t * next = ( wchar_t * ) al_get ( & el , j ) ;
is_bold | = ( wcsncmp ( next , L " --bold " , wcslen ( next ) ) = = 0 ) & & wcslen ( next ) > = 3 ;
2006-06-15 23:49:15 +10:00
is_bold | = wcscmp ( next , L " -o " ) = = 0 ;
2006-05-27 23:39:30 +10:00
2006-06-14 23:22:40 +10:00
is_underline | = ( wcsncmp ( next , L " --underline " , wcslen ( next ) ) = = 0 ) & & wcslen ( next ) > = 3 ;
is_underline | = wcscmp ( next , L " -u " ) = = 0 ;
2006-05-27 23:39:30 +10:00
for ( i = 0 ; i < COLORS ; i + + )
2005-09-20 23:26:39 +10:00
{
2006-05-27 23:39:30 +10:00
if ( wcscasecmp ( col [ i ] , next ) = = 0 )
{
color = col_idx [ i ] ;
break ;
}
2005-09-20 23:26:39 +10:00
}
2006-05-27 23:39:30 +10:00
2005-09-20 23:26:39 +10:00
}
2006-05-27 23:39:30 +10:00
2006-06-13 07:47:42 +10:00
al_foreach ( & el , & free ) ;
2006-05-28 21:06:30 +10:00
al_destroy ( & el ) ;
2006-06-13 07:47:42 +10:00
2006-06-14 23:22:40 +10:00
return color | ( is_bold ? FISH_COLOR_BOLD : 0 ) | ( is_underline ? FISH_COLOR_UNDERLINE : 0 ) ;
2006-05-27 23:39:30 +10:00
2005-09-20 23:26:39 +10:00
}