2005-09-20 23:26:39 +10:00
/** \file common.c
2010-09-18 09:51:16 +08:00
2005-09-20 23:26:39 +10:00
Various functions , mostly string utilities , that are used by most
parts of fish .
*/
2005-10-05 19:58:00 +10:00
# include "config.h"
2006-02-28 23:17:16 +10:00
2006-07-28 22:50:57 +10:00
# include <unistd.h>
2006-08-01 10:35:56 +10:00
# ifdef HAVE_STROPTS_H
2006-07-28 22:50:57 +10:00
# include <stropts.h>
# endif
2006-07-31 06:26:59 +10:00
# ifdef HAVE_SIGINFO_H
# include <siginfo.h>
# endif
2005-09-20 23:26:39 +10:00
# include <stdlib.h>
# include <termios.h>
# include <wchar.h>
# include <string.h>
# include <stdio.h>
# include <dirent.h>
# include <sys/types.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-11-29 00:42:02 +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/stat.h>
# include <unistd.h>
# include <wctype.h>
# include <errno.h>
# include <limits.h>
2010-09-18 09:51:16 +08:00
# include <stdarg.h>
2005-09-20 23:26:39 +10:00
# include <locale.h>
2005-09-21 09:42:00 +10:00
# include <time.h>
2005-09-28 11:43:09 +10:00
# include <sys/time.h>
# include <fcntl.h>
2005-09-20 23:26:39 +10:00
2007-01-20 12:36:49 +10:00
# ifdef HAVE_EXECINFO_H
# include <execinfo.h>
# endif
2005-10-02 05:18:52 +10:00
# ifndef HOST_NAME_MAX
2005-10-25 01:26:25 +10:00
/**
Maximum length of hostname return . It is ok if this is too short ,
getting the actual hostname is not critical , so long as the string
is unique in the filesystem namespace .
*/
2005-10-02 05:18:52 +10:00
# define HOST_NAME_MAX 255
# endif
2005-09-20 23:26:39 +10:00
# 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
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 "common.h"
# include "expand.h"
# include "proc.h"
# include "wildcard.h"
# include "parser.h"
2006-06-13 23:43:28 +10:00
# include "util.c"
# include "halloc.c"
# include "halloc_util.c"
# include "fallback.c"
2005-09-28 11:43:09 +10:00
/**
2010-09-18 09:51:16 +08:00
The number of milliseconds to wait between polls when attempting to acquire
2005-09-28 11:43:09 +10:00
a lockfile
*/
2005-10-01 05:50:21 +10:00
# define LOCKPOLLINTERVAL 10
2005-09-28 11:43:09 +10:00
2010-09-18 09:51:16 +08:00
struct termios shell_modes ;
2005-09-20 23:26:39 +10:00
wchar_t ellipsis_char ;
char * profile = 0 ;
wchar_t * program_name ;
2005-09-25 05:31:17 +10:00
int debug_level = 1 ;
2005-10-14 21:40:33 +10:00
/**
This struct should be continually updated by signals as the term resizes , and as such always contain the correct current size .
*/
static struct winsize termsize ;
2006-01-24 06:40:14 +10:00
/**
String buffer used by the wsetlocale function
*/
2006-01-09 09:00:49 +10:00
static string_buffer_t * setlocale_buff = 0 ;
2007-01-20 12:36:49 +10:00
2010-09-18 09:51:16 +08:00
void show_stackframe ( )
2007-01-20 12:36:49 +10:00
{
void * trace [ 32 ] ;
char * * messages = ( char * * ) NULL ;
int i , trace_size = 0 ;
trace_size = backtrace ( trace , 32 ) ;
messages = backtrace_symbols ( trace , trace_size ) ;
if ( messages )
{
debug ( 0 , L " Backtrace: " ) ;
for ( i = 0 ; i < trace_size ; i + + )
{
fwprintf ( stderr , L " %s \n " , messages [ i ] ) ;
}
free ( messages ) ;
}
}
2006-02-10 01:50:20 +10:00
wchar_t * * list_to_char_arr ( array_list_t * l )
{
wchar_t * * res = malloc ( sizeof ( wchar_t * ) * ( al_get_count ( l ) + 1 ) ) ;
2005-09-20 23:26:39 +10:00
int i ;
if ( res = = 0 )
{
2006-07-03 20:39:57 +10:00
DIE_MEM ( ) ;
2005-09-20 23:26:39 +10:00
}
for ( i = 0 ; i < al_get_count ( l ) ; i + + )
2010-09-18 09:51:16 +08:00
{
2005-09-20 23:26:39 +10:00
res [ i ] = ( wchar_t * ) al_get ( l , i ) ;
2006-02-07 04:11:01 +10:00
}
2005-09-20 23:26:39 +10:00
res [ i ] = ' \0 ' ;
2010-09-18 09:51:16 +08:00
return res ;
2005-09-20 23:26:39 +10:00
}
int fgetws2 ( wchar_t * * b , int * len , FILE * f )
{
int i = 0 ;
wint_t c ;
2010-09-18 09:51:16 +08:00
2005-09-20 23:26:39 +10:00
wchar_t * buff = * b ;
while ( 1 )
{
/* Reallocate the buffer if necessary */
if ( i + 1 > = * len )
{
int new_len = maxi ( 128 , ( * len ) * 2 ) ;
buff = realloc ( buff , sizeof ( wchar_t ) * new_len ) ;
if ( buff = = 0 )
{
2006-07-03 20:39:57 +10:00
DIE_MEM ( ) ;
2005-09-20 23:26:39 +10:00
}
else
{
* len = new_len ;
* b = buff ;
2010-09-18 09:51:16 +08:00
}
2005-09-20 23:26:39 +10:00
}
2010-09-18 09:51:16 +08:00
errno = 0 ;
2005-09-20 23:26:39 +10:00
c = getwc ( f ) ;
2010-09-18 09:51:16 +08:00
2005-09-20 23:26:39 +10:00
if ( errno = = EILSEQ )
{
continue ;
}
2010-09-18 09:51:16 +08:00
2005-09-20 23:26:39 +10:00
//fwprintf( stderr, L"b\n" );
2010-09-18 09:51:16 +08:00
2005-09-20 23:26:39 +10:00
switch ( c )
{
2010-09-18 09:51:16 +08:00
/* End of line */
2005-09-20 23:26:39 +10:00
case WEOF :
case L ' \n ' :
case L ' \0 ' :
buff [ i ] = L ' \0 ' ;
2010-09-18 09:51:16 +08:00
return i ;
2005-09-20 23:26:39 +10:00
/* Ignore carriage returns */
case L ' \r ' :
break ;
2010-09-18 09:51:16 +08:00
2005-09-20 23:26:39 +10:00
default :
buff [ i + + ] = c ;
break ;
2010-09-18 09:51:16 +08:00
}
2005-09-20 23:26:39 +10:00
}
}
/**
Wrapper for wcsfilecmp
*/
2007-04-21 18:11:22 +10:00
static int str_cmp ( const void * a , const void * b )
2005-09-20 23:26:39 +10:00
{
wchar_t * c = * ( ( wchar_t * * ) a ) ;
wchar_t * d = * ( ( wchar_t * * ) b ) ;
return wcsfilecmp ( c , d ) ;
}
void sort_list ( array_list_t * comp )
{
2010-09-18 09:51:16 +08:00
qsort ( comp - > arr ,
2005-09-20 23:26:39 +10:00
al_get_count ( comp ) ,
sizeof ( void * ) ,
2007-04-21 18:11:22 +10:00
& str_cmp ) ;
2005-09-20 23:26:39 +10:00
}
wchar_t * str2wcs ( const char * in )
{
2006-01-28 12:03:29 +10:00
wchar_t * out ;
2006-02-09 00:58:47 +10:00
size_t len = strlen ( in ) ;
2010-09-18 09:51:16 +08:00
2006-02-09 00:58:47 +10:00
out = malloc ( sizeof ( wchar_t ) * ( len + 1 ) ) ;
2006-02-23 01:41:52 +10:00
if ( ! out )
{
2006-07-03 20:39:57 +10:00
DIE_MEM ( ) ;
2006-02-23 01:41:52 +10:00
}
2006-02-09 00:58:47 +10:00
return str2wcs_internal ( in , out ) ;
}
wchar_t * str2wcs_internal ( const char * in , wchar_t * out )
{
2006-01-28 12:03:29 +10:00
size_t res = 0 ;
int in_pos = 0 ;
int out_pos = 0 ;
mbstate_t state ;
2006-06-21 20:07:46 +10:00
size_t len ;
CHECK ( in , 0 ) ;
CHECK ( out , 0 ) ;
2010-09-18 09:51:16 +08:00
2006-06-21 20:07:46 +10:00
len = strlen ( in ) ;
2006-01-28 12:03:29 +10:00
memset ( & state , 0 , sizeof ( state ) ) ;
2007-09-24 07:00:07 +10:00
2006-01-28 12:03:29 +10:00
while ( in [ in_pos ] )
2005-09-20 23:26:39 +10:00
{
2006-01-28 12:03:29 +10:00
res = mbrtowc ( & out [ out_pos ] , & in [ in_pos ] , len - in_pos , & state ) ;
2007-10-02 20:09:37 +10:00
if ( ( ( out [ out_pos ] > = ENCODE_DIRECT_BASE ) & &
( out [ out_pos ] < ENCODE_DIRECT_BASE + 256 ) ) | |
( out [ out_pos ] = = INTERNAL_SEPARATOR ) )
2007-09-24 07:00:07 +10:00
{
out [ out_pos ] = ENCODE_DIRECT_BASE + ( unsigned char ) in [ in_pos ] ;
in_pos + + ;
memset ( & state , 0 , sizeof ( state ) ) ;
out_pos + + ;
}
else
2005-09-20 23:26:39 +10:00
{
2010-09-18 09:51:16 +08:00
2007-09-24 07:00:07 +10:00
switch ( res )
{
case ( size_t ) ( - 2 ) :
case ( size_t ) ( - 1 ) :
2006-06-15 20:36:46 +10:00
{
out [ out_pos ] = ENCODE_DIRECT_BASE + ( unsigned char ) in [ in_pos ] ;
in_pos + + ;
memset ( & state , 0 , sizeof ( state ) ) ;
break ;
}
2010-09-18 09:51:16 +08:00
2007-09-24 07:00:07 +10:00
case 0 :
{
return out ;
}
2010-09-18 09:51:16 +08:00
2007-09-24 07:00:07 +10:00
default :
{
in_pos + = res ;
break ;
}
2006-01-28 12:03:29 +10:00
}
2007-09-24 07:00:07 +10:00
out_pos + + ;
2005-09-20 23:26:39 +10:00
}
2010-09-18 09:51:16 +08:00
2006-01-28 12:03:29 +10:00
}
out [ out_pos ] = 0 ;
2010-09-18 09:51:16 +08:00
return out ;
2005-09-20 23:26:39 +10:00
}
char * wcs2str ( const wchar_t * in )
{
2010-09-18 09:51:16 +08:00
char * out ;
2006-01-28 12:03:29 +10:00
out = malloc ( MAX_UTF8_BYTES * wcslen ( in ) + 1 ) ;
2006-01-24 06:40:14 +10:00
2006-01-28 12:03:29 +10:00
if ( ! out )
2005-09-20 23:26:39 +10:00
{
2006-07-03 20:39:57 +10:00
DIE_MEM ( ) ;
2005-09-20 23:26:39 +10:00
}
2006-02-09 00:58:47 +10:00
return wcs2str_internal ( in , out ) ;
}
char * wcs2str_internal ( const wchar_t * in , char * out )
{
size_t res = 0 ;
int in_pos = 0 ;
int out_pos = 0 ;
mbstate_t state ;
2006-06-21 20:07:46 +10:00
CHECK ( in , 0 ) ;
CHECK ( out , 0 ) ;
2010-09-18 09:51:16 +08:00
2006-02-09 00:58:47 +10:00
memset ( & state , 0 , sizeof ( state ) ) ;
2010-09-18 09:51:16 +08:00
2006-01-28 12:03:29 +10:00
while ( in [ in_pos ] )
{
2006-09-04 09:47:51 +10:00
if ( in [ in_pos ] = = INTERNAL_SEPARATOR )
{
}
else if ( ( in [ in_pos ] > = ENCODE_DIRECT_BASE ) & &
2007-09-24 07:00:07 +10:00
( in [ in_pos ] < ENCODE_DIRECT_BASE + 256 ) )
2006-01-28 12:03:29 +10:00
{
out [ out_pos + + ] = in [ in_pos ] - ENCODE_DIRECT_BASE ;
}
else
{
res = wcrtomb ( & out [ out_pos ] , in [ in_pos ] , & state ) ;
2010-09-18 09:51:16 +08:00
2006-03-02 21:31:42 +10:00
if ( res = = ( size_t ) ( - 1 ) )
2006-01-28 12:03:29 +10:00
{
2006-09-04 09:47:51 +10:00
debug ( 1 , L " Wide character %d has no narrow representation " , in [ in_pos ] ) ;
2006-03-02 21:31:42 +10:00
memset ( & state , 0 , sizeof ( state ) ) ;
}
else
{
out_pos + = res ;
2006-01-28 12:03:29 +10:00
}
}
in_pos + + ;
}
out [ out_pos ] = 0 ;
2010-09-18 09:51:16 +08:00
return out ;
2005-09-20 23:26:39 +10:00
}
char * * wcsv2strv ( const wchar_t * * in )
{
int count = 0 ;
int i ;
while ( in [ count ] ! = 0 )
count + + ;
char * * res = malloc ( sizeof ( char * ) * ( count + 1 ) ) ;
if ( res = = 0 )
{
2010-09-18 09:51:16 +08:00
DIE_MEM ( ) ;
2005-09-20 23:26:39 +10:00
}
for ( i = 0 ; i < count ; i + + )
{
res [ i ] = wcs2str ( in [ i ] ) ;
}
res [ count ] = 0 ;
return res ;
}
2007-09-29 07:32:27 +10:00
wchar_t * wcsdupcat_internal ( const wchar_t * a , . . . )
2005-09-20 23:26:39 +10:00
{
int len = wcslen ( a ) ;
int pos ;
va_list va , va2 ;
wchar_t * arg ;
va_start ( va , a ) ;
va_copy ( va2 , va ) ;
2010-09-18 09:51:16 +08:00
while ( ( arg = va_arg ( va , wchar_t * ) ) ! = 0 )
2005-09-20 23:26:39 +10:00
{
len + = wcslen ( arg ) ;
}
va_end ( va ) ;
wchar_t * res = malloc ( sizeof ( wchar_t ) * ( len + 1 ) ) ;
if ( res = = 0 )
2005-11-03 02:49:13 +10:00
{
2006-07-03 20:39:57 +10:00
DIE_MEM ( ) ;
2005-11-03 02:49:13 +10:00
}
2010-09-18 09:51:16 +08:00
2005-09-20 23:26:39 +10:00
wcscpy ( res , a ) ;
pos = wcslen ( a ) ;
2010-09-18 09:51:16 +08:00
while ( ( arg = va_arg ( va2 , wchar_t * ) ) ! = 0 )
2005-09-20 23:26:39 +10:00
{
wcscpy ( res + pos , arg ) ;
pos + = wcslen ( arg ) ;
}
va_end ( va2 ) ;
2010-09-18 09:51:16 +08:00
return res ;
2005-09-20 23:26:39 +10:00
}
wchar_t * * strv2wcsv ( const char * * in )
{
int count = 0 ;
int i ;
while ( in [ count ] ! = 0 )
count + + ;
wchar_t * * res = malloc ( sizeof ( wchar_t * ) * ( count + 1 ) ) ;
if ( res = = 0 )
{
2006-07-03 20:39:57 +10:00
DIE_MEM ( ) ;
2005-09-20 23:26:39 +10:00
}
for ( i = 0 ; i < count ; i + + )
{
res [ i ] = str2wcs ( in [ i ] ) ;
}
res [ count ] = 0 ;
return res ;
}
2006-10-20 01:39:50 +10:00
wchar_t * wcsvarname ( const wchar_t * str )
2005-09-20 23:26:39 +10:00
{
while ( * str )
{
if ( ( ! iswalnum ( * str ) ) & & ( * str ! = L ' _ ' ) )
{
2006-10-20 01:39:50 +10:00
return ( wchar_t * ) str ;
2005-09-20 23:26:39 +10:00
}
str + + ;
}
2006-04-22 00:29:39 +10:00
return 0 ;
2005-09-20 23:26:39 +10:00
}
2006-10-20 01:47:47 +10:00
wchar_t * wcsfuncname ( const wchar_t * str )
{
return wcschr ( str , L ' / ' ) ;
}
2006-06-02 09:04:38 +10:00
int wcsvarchr ( wchar_t chr )
{
return ( ( iswalnum ( chr ) ) | | ( chr = = L ' _ ' ) ) ;
}
2005-09-20 23:26:39 +10:00
2010-09-18 09:51:16 +08:00
/**
2005-09-20 23:26:39 +10:00
The glibc version of wcswidth seems to hang on some strings . fish uses this replacement .
*/
int my_wcswidth ( const wchar_t * c )
{
int res = 0 ;
while ( * c )
{
int w = wcwidth ( * c + + ) ;
if ( w < 0 )
w = 1 ;
if ( w > 2 )
w = 1 ;
2010-09-18 09:51:16 +08:00
res + = w ;
2005-09-20 23:26:39 +10:00
}
return res ;
}
2006-06-14 23:22:40 +10:00
wchar_t * quote_end ( const wchar_t * pos )
2005-09-20 23:26:39 +10:00
{
2006-02-13 02:13:31 +10:00
wchar_t c = * pos ;
2010-09-18 09:51:16 +08:00
2006-02-13 02:13:31 +10:00
while ( 1 )
{
pos + + ;
2010-09-18 09:51:16 +08:00
2006-02-13 02:13:31 +10:00
if ( ! * pos )
return 0 ;
2010-09-18 09:51:16 +08:00
2006-02-13 02:13:31 +10:00
if ( * pos = = L ' \\ ' )
{
pos + + ;
2006-06-15 10:59:31 +10:00
if ( ! * pos )
return 0 ;
2006-02-13 02:13:31 +10:00
}
else
{
if ( * pos = = c )
{
2006-06-14 23:22:40 +10:00
return ( wchar_t * ) pos ;
2006-02-13 02:13:31 +10:00
}
}
}
return 0 ;
2010-09-18 09:51:16 +08:00
2006-02-13 02:13:31 +10:00
}
2005-09-20 23:26:39 +10:00
2010-09-18 09:51:16 +08:00
2006-01-09 09:00:49 +10:00
const wchar_t * wsetlocale ( int category , const wchar_t * locale )
2005-09-20 23:26:39 +10:00
{
2006-01-09 09:00:49 +10:00
char * lang = locale ? wcs2str ( locale ) : 0 ;
char * res = setlocale ( category , lang ) ;
2010-09-18 09:51:16 +08:00
2005-09-20 23:26:39 +10:00
free ( lang ) ;
2006-01-09 09:00:49 +10:00
2005-09-20 23:26:39 +10:00
/*
Use ellipsis if on known unicode system , otherwise use $
*/
2006-01-09 09:00:49 +10:00
char * ctype = setlocale ( LC_CTYPE , ( void * ) 0 ) ;
2010-09-18 09:51:16 +08:00
ellipsis_char = ( strstr ( ctype , " .UTF " ) | | strstr ( ctype , " .utf " ) ) ? L ' \ u2026 ' : L ' $ ' ;
2006-01-09 09:00:49 +10:00
if ( ! res )
return 0 ;
2010-09-18 09:51:16 +08:00
2006-01-09 09:00:49 +10:00
if ( ! setlocale_buff )
2005-09-20 23:26:39 +10:00
{
2006-06-21 19:58:38 +10:00
setlocale_buff = sb_halloc ( global_context ) ;
2005-09-20 23:26:39 +10:00
}
2010-09-18 09:51:16 +08:00
2006-01-09 09:00:49 +10:00
sb_clear ( setlocale_buff ) ;
sb_printf ( setlocale_buff , L " %s " , res ) ;
2010-09-18 09:51:16 +08:00
return ( wchar_t * ) setlocale_buff - > buff ;
2005-09-20 23:26:39 +10:00
}
2007-09-29 07:32:27 +10:00
int contains_internal ( const wchar_t * a , . . . )
2005-09-20 23:26:39 +10:00
{
wchar_t * arg ;
va_list va ;
int res = 0 ;
2006-05-03 02:28:30 +10:00
2006-06-21 10:48:36 +10:00
CHECK ( a , 0 ) ;
2010-09-18 09:51:16 +08:00
2005-09-20 23:26:39 +10:00
va_start ( va , a ) ;
2010-09-18 09:51:16 +08:00
while ( ( arg = va_arg ( va , wchar_t * ) ) ! = 0 )
2005-09-20 23:26:39 +10:00
{
if ( wcscmp ( a , arg ) = = 0 )
{
res = 1 ;
break ;
}
2010-09-18 09:51:16 +08:00
2005-09-20 23:26:39 +10:00
}
va_end ( va ) ;
2010-09-18 09:51:16 +08:00
return res ;
2005-09-20 23:26:39 +10:00
}
int read_blocked ( int fd , void * buf , size_t count )
{
2010-09-18 09:51:16 +08:00
int res ;
sigset_t chldset , oldset ;
2005-09-20 23:26:39 +10:00
sigemptyset ( & chldset ) ;
sigaddset ( & chldset , SIGCHLD ) ;
sigprocmask ( SIG_BLOCK , & chldset , & oldset ) ;
res = read ( fd , buf , count ) ;
sigprocmask ( SIG_SETMASK , & oldset , 0 ) ;
2010-09-18 09:51:16 +08:00
return res ;
2005-09-20 23:26:39 +10:00
}
2009-02-23 06:28:52 +10:00
ssize_t write_loop ( int fd , char * buff , size_t count )
{
ssize_t out = 0 ;
ssize_t out_cum = 0 ;
2010-09-18 09:51:16 +08:00
while ( 1 )
2009-02-23 06:28:52 +10:00
{
2010-09-18 09:51:16 +08:00
out = write ( fd ,
2009-02-23 06:28:52 +10:00
& buff [ out_cum ] ,
count - out_cum ) ;
2010-09-18 09:51:16 +08:00
if ( out = = - 1 )
2009-02-23 06:28:52 +10:00
{
if ( errno ! = EAGAIN & &
2010-09-18 09:51:16 +08:00
errno ! = EINTR )
2009-02-23 06:28:52 +10:00
{
return - 1 ;
}
2010-09-18 09:51:16 +08:00
} else
2009-02-23 06:28:52 +10:00
{
out_cum + = out ;
}
2010-09-18 09:51:16 +08:00
if ( out_cum > = count )
2009-02-23 06:28:52 +10:00
{
break ;
}
2010-09-18 09:51:16 +08:00
}
2009-02-23 06:28:52 +10:00
return out_cum ;
}
2006-01-04 22:51:02 +10:00
void debug ( int level , const wchar_t * msg , . . . )
2005-09-20 23:26:39 +10:00
{
va_list va ;
2006-12-14 20:01:31 +10:00
2005-10-12 20:34:21 +10:00
string_buffer_t sb ;
2006-05-14 19:47:21 +10:00
string_buffer_t sb2 ;
2006-12-14 20:01:31 +10:00
int errno_old = errno ;
2010-09-18 09:51:16 +08:00
2005-09-25 05:31:17 +10:00
if ( level > debug_level )
2005-09-20 23:26:39 +10:00
return ;
2006-12-14 20:01:31 +10:00
CHECK ( msg , ) ;
2010-09-18 09:51:16 +08:00
2005-10-12 20:34:21 +10:00
sb_init ( & sb ) ;
2006-05-14 19:47:21 +10:00
sb_init ( & sb2 ) ;
2006-06-01 01:40:28 +10:00
2005-10-12 20:34:21 +10:00
sb_printf ( & sb , L " %ls: " , program_name ) ;
2006-06-01 01:40:28 +10:00
2010-09-18 09:51:16 +08:00
va_start ( va , msg ) ;
2005-10-12 20:34:21 +10:00
sb_vprintf ( & sb , msg , va ) ;
2010-09-18 09:51:16 +08:00
va_end ( va ) ;
2006-01-15 21:58:05 +10:00
2006-05-14 19:47:21 +10:00
write_screen ( ( wchar_t * ) sb . buff , & sb2 ) ;
2010-09-18 09:51:16 +08:00
fwprintf ( stderr , L " %ls " , sb2 . buff ) ;
2006-01-15 21:58:05 +10:00
2010-09-18 09:51:16 +08:00
sb_destroy ( & sb ) ;
sb_destroy ( & sb2 ) ;
2006-12-14 20:01:31 +10:00
errno = errno_old ;
2006-01-15 21:58:05 +10:00
}
2006-05-14 19:47:21 +10:00
void write_screen ( const wchar_t * msg , string_buffer_t * buff )
2006-01-15 21:58:05 +10:00
{
const wchar_t * start , * pos ;
int line_width = 0 ;
int tok_width = 0 ;
int screen_width = common_get_width ( ) ;
2010-09-18 09:51:16 +08:00
2006-06-21 10:48:36 +10:00
CHECK ( msg , ) ;
CHECK ( buff , ) ;
2010-09-18 09:51:16 +08:00
2005-10-20 21:30:01 +10:00
if ( screen_width )
2005-10-12 20:34:21 +10:00
{
2006-01-15 21:58:05 +10:00
start = pos = msg ;
2005-10-20 21:30:01 +10:00
while ( 1 )
2005-10-12 20:34:21 +10:00
{
2005-10-20 21:30:01 +10:00
int overflow = 0 ;
2010-09-18 09:51:16 +08:00
2005-10-20 21:30:01 +10:00
tok_width = 0 ;
2005-10-14 21:40:33 +10:00
/*
2005-10-20 21:30:01 +10:00
Tokenize on whitespace , and also calculate the width of the token
2005-10-14 21:40:33 +10:00
*/
2005-10-20 21:30:01 +10:00
while ( * pos & & ( ! wcschr ( L " \n \r \t " , * pos ) ) )
2005-10-12 20:34:21 +10:00
{
2010-09-18 09:51:16 +08:00
2005-10-20 21:30:01 +10:00
/*
Check is token is wider than one line .
If so we mark it as an overflow and break the token .
*/
if ( ( tok_width + wcwidth ( * pos ) ) > ( screen_width - 1 ) )
{
overflow = 1 ;
2010-09-18 09:51:16 +08:00
break ;
2005-10-20 21:30:01 +10:00
}
2010-09-18 09:51:16 +08:00
2005-10-20 21:30:01 +10:00
tok_width + = wcwidth ( * pos ) ;
pos + + ;
}
2005-10-12 20:34:21 +10:00
2005-10-14 21:40:33 +10:00
/*
2005-10-20 21:30:01 +10:00
If token is zero character long , we don ' t do anything
2005-10-14 21:40:33 +10:00
*/
2005-10-20 21:30:01 +10:00
if ( pos = = start )
2005-10-12 20:34:21 +10:00
{
2005-10-20 21:30:01 +10:00
start = pos = pos + 1 ;
}
else if ( overflow )
{
/*
2006-06-01 01:40:28 +10:00
In case of overflow , we print a newline , except if we already are at position 0
2005-10-20 21:30:01 +10:00
*/
wchar_t * token = wcsndup ( start , pos - start ) ;
if ( line_width ! = 0 )
2006-05-14 19:47:21 +10:00
sb_append_char ( buff , L ' \n ' ) ;
sb_printf ( buff , L " %ls- \n " , token ) ;
2005-10-20 21:30:01 +10:00
free ( token ) ;
2005-10-12 20:34:21 +10:00
line_width = 0 ;
}
2005-10-20 21:30:01 +10:00
else
{
/*
Print the token
*/
wchar_t * token = wcsndup ( start , pos - start ) ;
if ( ( line_width + ( line_width ! = 0 ? 1 : 0 ) + tok_width ) > screen_width )
{
2006-05-14 19:47:21 +10:00
sb_append_char ( buff , L ' \n ' ) ;
2005-10-20 21:30:01 +10:00
line_width = 0 ;
}
2006-05-14 19:47:21 +10:00
sb_printf ( buff , L " %ls%ls " , line_width ? L " " : L " " , token ) ;
2005-10-20 21:30:01 +10:00
free ( token ) ;
line_width + = ( line_width ! = 0 ? 1 : 0 ) + tok_width ;
}
2010-09-18 09:51:16 +08:00
2005-10-20 21:30:01 +10:00
/*
Break on end of string
*/
if ( ! * pos )
2006-06-15 20:36:46 +10:00
{
2005-10-20 21:30:01 +10:00
break ;
2006-06-15 20:36:46 +10:00
}
2010-09-18 09:51:16 +08:00
2005-10-20 21:30:01 +10:00
start = pos ;
2005-10-12 20:34:21 +10:00
}
2005-10-20 21:30:01 +10:00
}
else
{
2006-05-14 19:47:21 +10:00
sb_printf ( buff , L " %ls " , msg ) ;
2005-10-12 20:34:21 +10:00
}
2006-05-14 19:47:21 +10:00
sb_append_char ( buff , L ' \n ' ) ;
2005-09-20 23:26:39 +10:00
}
2008-01-14 02:47:47 +10:00
/**
Perform string escaping of a strinng by only quoting it . Assumes
the string has already been checked for characters that can not be
escaped this way .
*/
2007-09-23 05:08:38 +10:00
static wchar_t * escape_simple ( const wchar_t * in )
2005-09-20 23:26:39 +10:00
{
2007-09-23 05:08:38 +10:00
wchar_t * out ;
size_t len = wcslen ( in ) ;
out = malloc ( sizeof ( wchar_t ) * ( len + 3 ) ) ;
if ( ! out )
DIE_MEM ( ) ;
2010-09-18 09:51:16 +08:00
2007-09-23 05:08:38 +10:00
out [ 0 ] = L ' \' ' ;
wcscpy ( & out [ 1 ] , in ) ;
out [ len + 1 ] = L ' \' ' ;
out [ len + 2 ] = 0 ;
return out ;
}
2010-09-18 09:51:16 +08:00
wchar_t * escape ( const wchar_t * in_orig ,
2007-10-06 20:51:31 +10:00
int flags )
2007-09-23 05:08:38 +10:00
{
const wchar_t * in = in_orig ;
2010-09-18 09:51:16 +08:00
2007-10-06 20:51:31 +10:00
int escape_all = flags & ESCAPE_ALL ;
int no_quoted = flags & ESCAPE_NO_QUOTED ;
2010-09-18 09:51:16 +08:00
2006-06-09 09:52:12 +10:00
wchar_t * out ;
wchar_t * pos ;
2007-09-23 05:08:38 +10:00
int need_escape = 0 ;
int need_complex_escape = 0 ;
2006-06-09 09:52:12 +10:00
if ( ! in )
{
debug ( 0 , L " %s called with null input " , __func__ ) ;
2007-01-22 01:03:41 +10:00
FATAL_EXIT ( ) ;
2006-06-09 09:52:12 +10:00
}
2007-09-26 02:19:59 +10:00
2007-10-06 20:51:31 +10:00
if ( ! no_quoted & & ( wcslen ( in ) = = 0 ) )
2007-09-26 02:19:59 +10:00
{
out = wcsdup ( L " '' " ) ;
if ( ! out )
DIE_MEM ( ) ;
return out ;
}
2010-09-18 09:51:16 +08:00
2006-06-09 09:52:12 +10:00
out = malloc ( sizeof ( wchar_t ) * ( wcslen ( in ) * 4 + 1 ) ) ;
pos = out ;
2010-09-18 09:51:16 +08:00
2005-10-07 20:36:51 +10:00
if ( ! out )
2006-07-03 20:39:57 +10:00
DIE_MEM ( ) ;
2010-09-18 09:51:16 +08:00
2005-10-07 20:36:51 +10:00
while ( * in ! = 0 )
2005-09-20 23:26:39 +10:00
{
2006-01-28 12:03:29 +10:00
if ( ( * in > = ENCODE_DIRECT_BASE ) & &
( * in < ENCODE_DIRECT_BASE + 256 ) )
{
int val = * in - ENCODE_DIRECT_BASE ;
int tmp ;
2010-09-18 09:51:16 +08:00
2006-01-28 12:03:29 +10:00
* ( pos + + ) = L ' \\ ' ;
* ( pos + + ) = L ' X ' ;
2010-09-18 09:51:16 +08:00
tmp = val / 16 ;
2006-01-28 12:03:29 +10:00
* pos + + = tmp > 9 ? L ' a ' + ( tmp - 10 ) : L ' 0 ' + tmp ;
2010-09-18 09:51:16 +08:00
tmp = val % 16 ;
2006-01-28 12:03:29 +10:00
* pos + + = tmp > 9 ? L ' a ' + ( tmp - 10 ) : L ' 0 ' + tmp ;
2007-09-23 05:08:38 +10:00
need_escape = need_complex_escape = 1 ;
2010-09-18 09:51:16 +08:00
2006-01-28 12:03:29 +10:00
}
else
{
2010-09-18 09:51:16 +08:00
2006-06-15 20:36:46 +10:00
switch ( * in )
{
case L ' \t ' :
* ( pos + + ) = L ' \\ ' ;
2010-09-18 09:51:16 +08:00
* ( pos + + ) = L ' t ' ;
2007-09-23 05:08:38 +10:00
need_escape = need_complex_escape = 1 ;
2006-06-15 20:36:46 +10:00
break ;
2010-09-18 09:51:16 +08:00
2006-06-15 20:36:46 +10:00
case L ' \n ' :
* ( pos + + ) = L ' \\ ' ;
2010-09-18 09:51:16 +08:00
* ( pos + + ) = L ' n ' ;
2007-09-23 05:08:38 +10:00
need_escape = need_complex_escape = 1 ;
2006-06-15 20:36:46 +10:00
break ;
2010-09-18 09:51:16 +08:00
2006-06-15 20:37:06 +10:00
case L ' \b ' :
* ( pos + + ) = L ' \\ ' ;
2010-09-18 09:51:16 +08:00
* ( pos + + ) = L ' b ' ;
2007-09-23 05:08:38 +10:00
need_escape = need_complex_escape = 1 ;
2006-06-15 20:37:06 +10:00
break ;
2010-09-18 09:51:16 +08:00
2006-06-15 20:37:06 +10:00
case L ' \r ' :
* ( pos + + ) = L ' \\ ' ;
2010-09-18 09:51:16 +08:00
* ( pos + + ) = L ' r ' ;
2007-09-23 05:08:38 +10:00
need_escape = need_complex_escape = 1 ;
2006-06-15 20:37:06 +10:00
break ;
2010-09-18 09:51:16 +08:00
2007-09-26 02:19:16 +10:00
case L ' \x1b ' :
* ( pos + + ) = L ' \\ ' ;
2010-09-18 09:51:16 +08:00
* ( pos + + ) = L ' e ' ;
2007-09-26 02:19:16 +10:00
need_escape = need_complex_escape = 1 ;
break ;
2010-09-18 09:51:16 +08:00
2007-09-26 02:19:16 +10:00
2006-06-15 20:37:06 +10:00
case L ' \\ ' :
2007-09-24 00:55:55 +10:00
case L ' \' ' :
2007-09-23 05:08:38 +10:00
{
need_escape = need_complex_escape = 1 ;
if ( escape_all )
* pos + + = L ' \\ ' ;
* pos + + = * in ;
break ;
}
2006-06-15 20:37:06 +10:00
case L ' & ' :
case L ' $ ' :
case L ' ' :
case L ' # ' :
case L ' ^ ' :
case L ' < ' :
case L ' > ' :
case L ' ( ' :
case L ' ) ' :
case L ' [ ' :
case L ' ] ' :
case L ' { ' :
case L ' } ' :
case L ' ? ' :
case L ' * ' :
case L ' | ' :
case L ' ; ' :
case L ' " ' :
case L ' % ' :
case L ' ~ ' :
2005-10-07 20:36:51 +10:00
{
2007-09-23 05:08:38 +10:00
need_escape = 1 ;
2006-06-15 20:37:06 +10:00
if ( escape_all )
* pos + + = L ' \\ ' ;
2005-10-07 20:36:51 +10:00
* pos + + = * in ;
2006-06-15 20:37:06 +10:00
break ;
}
2010-09-18 09:51:16 +08:00
2006-06-15 20:37:06 +10:00
default :
{
if ( * in < 32 )
{
2007-09-26 02:19:16 +10:00
if ( * in < 27 & & * in > 0 )
{
* ( pos + + ) = L ' \\ ' ;
* ( pos + + ) = L ' c ' ;
* ( pos + + ) = L ' a ' + * in - 1 ;
2010-09-18 09:51:16 +08:00
2007-09-26 02:19:16 +10:00
need_escape = need_complex_escape = 1 ;
break ;
2010-09-18 09:51:16 +08:00
2007-09-26 02:19:16 +10:00
}
2010-09-18 09:51:16 +08:00
2007-09-26 02:19:16 +10:00
2006-06-15 20:37:06 +10:00
int tmp = ( * in ) % 16 ;
* pos + + = L ' \\ ' ;
* pos + + = L ' x ' ;
* pos + + = ( ( * in > 15 ) ? L ' 1 ' : L ' 0 ' ) ;
* pos + + = tmp > 9 ? L ' a ' + ( tmp - 10 ) : L ' 0 ' + tmp ;
2007-09-23 05:08:38 +10:00
need_escape = need_complex_escape = 1 ;
2006-06-15 20:37:06 +10:00
}
else
{
* pos + + = * in ;
}
break ;
}
}
2006-01-28 12:03:29 +10:00
}
2010-09-18 09:51:16 +08:00
2005-10-07 20:36:51 +10:00
in + + ;
2005-09-20 23:26:39 +10:00
}
2005-10-07 20:36:51 +10:00
* pos = 0 ;
2007-09-23 05:08:38 +10:00
/*
Use quoted escaping if possible , since most people find it
2010-09-18 09:51:16 +08:00
easier to read .
2007-09-23 05:08:38 +10:00
*/
2007-10-06 20:51:31 +10:00
if ( ! no_quoted & & need_escape & & ! need_complex_escape & & escape_all )
2007-09-23 05:08:38 +10:00
{
free ( out ) ;
out = escape_simple ( in_orig ) ;
}
2010-09-18 09:51:16 +08:00
2005-09-20 23:26:39 +10:00
return out ;
}
2007-01-19 02:02:46 +10:00
wchar_t * unescape ( const wchar_t * orig , int flags )
2005-09-20 23:26:39 +10:00
{
2010-09-18 09:51:16 +08:00
int mode = 0 ;
2006-06-09 09:52:12 +10:00
int in_pos , out_pos , len ;
2005-09-20 23:26:39 +10:00
int c ;
int bracket_count = 0 ;
2010-09-18 09:51:16 +08:00
wchar_t prev = 0 ;
2006-06-09 09:52:12 +10:00
wchar_t * in ;
2007-01-19 02:02:46 +10:00
int unescape_special = flags & UNESCAPE_SPECIAL ;
int allow_incomplete = flags & UNESCAPE_INCOMPLETE ;
2010-09-18 09:51:16 +08:00
2006-06-21 10:48:36 +10:00
CHECK ( orig , 0 ) ;
2010-09-18 09:51:16 +08:00
2006-06-09 09:52:12 +10:00
len = wcslen ( orig ) ;
in = wcsdup ( orig ) ;
2005-10-07 20:36:51 +10:00
if ( ! in )
2006-07-03 20:39:57 +10:00
DIE_MEM ( ) ;
2010-09-18 09:51:16 +08:00
for ( in_pos = 0 , out_pos = 0 ;
in_pos < len ;
2005-11-03 02:49:13 +10:00
( prev = ( out_pos > = 0 ) ? in [ out_pos ] : 0 ) , out_pos + + , in_pos + + )
2005-09-20 23:26:39 +10:00
{
c = in [ in_pos ] ;
2005-11-03 02:49:13 +10:00
switch ( mode )
2005-09-20 23:26:39 +10:00
{
2005-11-03 02:49:13 +10:00
/*
Mode 0 means unquoted string
*/
case 0 :
{
if ( c = = L ' \\ ' )
2005-09-20 23:26:39 +10:00
{
2005-11-03 02:49:13 +10:00
switch ( in [ + + in_pos ] )
2005-09-20 23:26:39 +10:00
{
2010-09-18 09:51:16 +08:00
2006-09-04 09:00:06 +10:00
/*
A null character after a backslash is an
error , return null
*/
2005-11-03 02:49:13 +10:00
case L ' \0 ' :
{
2007-01-27 03:14:13 +10:00
if ( ! allow_incomplete )
{
free ( in ) ;
return 0 ;
}
2005-11-03 02:49:13 +10:00
}
2010-09-18 09:51:16 +08:00
2006-09-04 09:00:06 +10:00
/*
Numeric escape sequences . No prefix means
octal escape , otherwise hexadecimal .
*/
2010-09-18 09:51:16 +08:00
2006-02-24 22:18:29 +10:00
case L ' 0 ' :
case L ' 1 ' :
case L ' 2 ' :
case L ' 3 ' :
case L ' 4 ' :
case L ' 5 ' :
case L ' 6 ' :
case L ' 7 ' :
2006-09-04 09:00:06 +10:00
case L ' u ' :
case L ' U ' :
case L ' x ' :
case L ' X ' :
2005-11-03 02:49:13 +10:00
{
int i ;
2006-02-24 22:18:29 +10:00
long long res = 0 ;
2005-11-03 02:49:13 +10:00
int chars = 2 ;
int base = 16 ;
2010-09-18 09:51:16 +08:00
2006-01-28 12:03:29 +10:00
int byte = 0 ;
2006-05-14 23:25:10 +10:00
wchar_t max_val = ASCII_MAX ;
2010-09-18 09:51:16 +08:00
2005-11-03 02:49:13 +10:00
switch ( in [ in_pos ] )
{
case L ' u ' :
{
chars = 4 ;
2006-05-14 23:25:10 +10:00
max_val = UCS2_MAX ;
2005-11-03 02:49:13 +10:00
break ;
}
2010-09-18 09:51:16 +08:00
2005-11-03 02:49:13 +10:00
case L ' U ' :
{
chars = 8 ;
2006-02-24 22:18:29 +10:00
max_val = WCHAR_MAX ;
2005-11-03 02:49:13 +10:00
break ;
}
2010-09-18 09:51:16 +08:00
2005-11-03 02:49:13 +10:00
case L ' x ' :
{
break ;
}
2010-09-18 09:51:16 +08:00
2006-01-28 12:03:29 +10:00
case L ' X ' :
{
byte = 1 ;
2006-05-14 23:25:10 +10:00
max_val = BYTE_MAX ;
2006-01-28 12:03:29 +10:00
break ;
}
2010-09-18 09:51:16 +08:00
2006-02-24 22:18:29 +10:00
default :
2005-11-03 02:49:13 +10:00
{
base = 8 ;
chars = 3 ;
2006-02-24 22:18:29 +10:00
in_pos - - ;
2005-11-03 02:49:13 +10:00
break ;
2010-09-18 09:51:16 +08:00
}
2005-11-03 02:49:13 +10:00
}
2010-09-18 09:51:16 +08:00
2005-11-03 02:49:13 +10:00
for ( i = 0 ; i < chars ; i + + )
{
int d = convert_digit ( in [ + + in_pos ] , base ) ;
2010-09-18 09:51:16 +08:00
2005-11-03 02:49:13 +10:00
if ( d < 0 )
{
in_pos - - ;
break ;
}
2010-09-18 09:51:16 +08:00
2005-11-03 02:49:13 +10:00
res = ( res * base ) | d ;
}
2006-02-24 22:18:29 +10:00
2006-05-10 02:55:01 +10:00
if ( ( res < = max_val ) )
2006-02-24 22:18:29 +10:00
{
in [ out_pos ] = ( byte ? ENCODE_DIRECT_BASE : 0 ) + res ;
}
else
2010-09-18 09:51:16 +08:00
{
free ( in ) ;
2006-02-24 22:18:29 +10:00
return 0 ;
}
2010-09-18 09:51:16 +08:00
2005-11-03 02:49:13 +10:00
break ;
}
2005-09-20 23:26:39 +10:00
2006-09-04 09:00:06 +10:00
/*
\ a means bell ( alert )
*/
case L ' a ' :
{
in [ out_pos ] = L ' \a ' ;
break ;
}
2010-09-18 09:51:16 +08:00
2006-09-04 09:00:06 +10:00
/*
\ b means backspace
*/
case L ' b ' :
{
in [ out_pos ] = L ' \b ' ;
break ;
}
2010-09-18 09:51:16 +08:00
2006-09-04 09:00:06 +10:00
/*
\ cX means control sequence X
*/
case L ' c ' :
{
in_pos + + ;
if ( in [ in_pos ] > = L ' a ' & &
in [ in_pos ] < = ( L ' a ' + 32 ) )
{
in [ out_pos ] = in [ in_pos ] - L ' a ' + 1 ;
}
else if ( in [ in_pos ] > = L ' A ' & &
in [ in_pos ] < = ( L ' A ' + 32 ) )
{
in [ out_pos ] = in [ in_pos ] - L ' A ' + 1 ;
}
else
{
2010-09-18 09:51:16 +08:00
free ( in ) ;
2006-09-04 09:00:06 +10:00
return 0 ;
}
break ;
2010-09-18 09:51:16 +08:00
2006-09-04 09:00:06 +10:00
}
2010-09-18 09:51:16 +08:00
2006-09-04 09:00:06 +10:00
/*
2007-08-22 17:52:39 +10:00
\ x1b means escape
2006-09-04 09:00:06 +10:00
*/
2007-09-09 05:18:55 +10:00
case L ' e ' :
2006-09-04 09:00:06 +10:00
{
in [ out_pos ] = L ' \x1b ' ;
break ;
}
2010-09-18 09:51:16 +08:00
2006-09-04 09:00:06 +10:00
/*
\ f means form feed
*/
case L ' f ' :
{
in [ out_pos ] = L ' \f ' ;
break ;
}
/*
\ n means newline
*/
case L ' n ' :
{
in [ out_pos ] = L ' \n ' ;
break ;
}
2010-09-18 09:51:16 +08:00
2006-09-04 09:00:06 +10:00
/*
\ r means carriage return
*/
case L ' r ' :
{
in [ out_pos ] = L ' \r ' ;
break ;
}
2010-09-18 09:51:16 +08:00
2006-09-04 09:00:06 +10:00
/*
\ t means tab
*/
case L ' t ' :
{
in [ out_pos ] = L ' \t ' ;
break ;
}
/*
2007-09-09 05:18:55 +10:00
\ v means vertical tab
2006-09-04 09:00:06 +10:00
*/
case L ' v ' :
{
in [ out_pos ] = L ' \v ' ;
break ;
}
2010-09-18 09:51:16 +08:00
2005-11-03 02:49:13 +10:00
default :
2005-09-20 23:26:39 +10:00
{
2006-10-10 01:19:13 +10:00
if ( unescape_special )
2010-09-18 09:51:16 +08:00
in [ out_pos + + ] = INTERNAL_SEPARATOR ;
2005-11-03 02:49:13 +10:00
in [ out_pos ] = in [ in_pos ] ;
break ;
2005-09-20 23:26:39 +10:00
}
}
2005-11-03 02:49:13 +10:00
}
2010-09-18 09:51:16 +08:00
else
2005-11-03 02:49:13 +10:00
{
2006-09-04 09:00:06 +10:00
switch ( in [ in_pos ] )
{
2005-11-03 02:49:13 +10:00
case L ' ~ ' :
{
if ( unescape_special & & ( in_pos = = 0 ) )
{
in [ out_pos ] = HOME_DIRECTORY ;
}
else
{
in [ out_pos ] = L ' ~ ' ;
}
break ;
}
2005-09-20 23:26:39 +10:00
2005-11-03 02:49:13 +10:00
case L ' % ' :
{
if ( unescape_special & & ( in_pos = = 0 ) )
{
in [ out_pos ] = PROCESS_EXPAND ;
}
else
{
2010-09-18 09:51:16 +08:00
in [ out_pos ] = in [ in_pos ] ;
2005-11-03 02:49:13 +10:00
}
break ;
}
2005-09-20 23:26:39 +10:00
2005-11-03 02:49:13 +10:00
case L ' * ' :
{
if ( unescape_special )
{
if ( out_pos > 0 & & in [ out_pos - 1 ] = = ANY_STRING )
{
out_pos - - ;
in [ out_pos ] = ANY_STRING_RECURSIVE ;
}
else
in [ out_pos ] = ANY_STRING ;
}
else
{
2010-09-18 09:51:16 +08:00
in [ out_pos ] = in [ in_pos ] ;
2005-11-03 02:49:13 +10:00
}
break ;
}
2005-09-20 23:26:39 +10:00
2005-11-03 02:49:13 +10:00
case L ' ? ' :
{
if ( unescape_special )
{
in [ out_pos ] = ANY_CHAR ;
}
else
{
2010-09-18 09:51:16 +08:00
in [ out_pos ] = in [ in_pos ] ;
2005-11-03 02:49:13 +10:00
}
2010-09-18 09:51:16 +08:00
break ;
2005-11-03 02:49:13 +10:00
}
2005-09-20 23:26:39 +10:00
2005-11-03 02:49:13 +10:00
case L ' $ ' :
{
if ( unescape_special )
{
in [ out_pos ] = VARIABLE_EXPAND ;
}
else
{
2010-09-18 09:51:16 +08:00
in [ out_pos ] = in [ in_pos ] ;
2005-11-03 02:49:13 +10:00
}
2010-09-18 09:51:16 +08:00
break ;
2005-11-03 02:49:13 +10:00
}
2005-09-20 23:26:39 +10:00
2005-11-03 02:49:13 +10:00
case L ' { ' :
{
if ( unescape_special )
{
bracket_count + + ;
in [ out_pos ] = BRACKET_BEGIN ;
}
else
{
2010-09-18 09:51:16 +08:00
in [ out_pos ] = in [ in_pos ] ;
2005-11-03 02:49:13 +10:00
}
2010-09-18 09:51:16 +08:00
break ;
2005-11-03 02:49:13 +10:00
}
2010-09-18 09:51:16 +08:00
2005-11-03 02:49:13 +10:00
case L ' } ' :
{
if ( unescape_special )
{
bracket_count - - ;
in [ out_pos ] = BRACKET_END ;
}
else
{
2010-09-18 09:51:16 +08:00
in [ out_pos ] = in [ in_pos ] ;
2005-11-03 02:49:13 +10:00
}
2010-09-18 09:51:16 +08:00
break ;
2005-11-03 02:49:13 +10:00
}
2010-09-18 09:51:16 +08:00
2005-11-03 02:49:13 +10:00
case L ' , ' :
{
if ( unescape_special & & bracket_count & & prev ! = BRACKET_SEP )
{
in [ out_pos ] = BRACKET_SEP ;
}
else
{
2010-09-18 09:51:16 +08:00
in [ out_pos ] = in [ in_pos ] ;
2005-11-03 02:49:13 +10:00
}
2010-09-18 09:51:16 +08:00
break ;
2005-11-03 02:49:13 +10:00
}
2010-09-18 09:51:16 +08:00
2005-11-03 02:49:13 +10:00
case L ' \' ' :
{
mode = 1 ;
2006-10-10 01:19:13 +10:00
if ( unescape_special )
2010-09-18 09:51:16 +08:00
in [ out_pos ] = INTERNAL_SEPARATOR ;
2007-01-19 02:02:46 +10:00
else
2010-09-18 09:51:16 +08:00
out_pos - - ;
break ;
2005-11-03 02:49:13 +10:00
}
2010-09-18 09:51:16 +08:00
2005-11-03 02:49:13 +10:00
case L ' \" ' :
{
mode = 2 ;
2006-10-10 01:19:13 +10:00
if ( unescape_special )
2010-09-18 09:51:16 +08:00
in [ out_pos ] = INTERNAL_SEPARATOR ;
2007-01-19 02:02:46 +10:00
else
2010-09-18 09:51:16 +08:00
out_pos - - ;
2005-11-03 02:49:13 +10:00
break ;
}
2005-09-20 23:26:39 +10:00
2005-11-03 02:49:13 +10:00
default :
{
in [ out_pos ] = in [ in_pos ] ;
break ;
}
}
2010-09-18 09:51:16 +08:00
}
2005-11-03 02:49:13 +10:00
break ;
}
/*
Mode 1 means single quoted string , i . e ' foo '
*/
case 1 :
{
2006-02-13 02:13:31 +10:00
if ( c = = L ' \\ ' )
{
switch ( in [ + + in_pos ] )
{
2006-03-06 11:50:12 +10:00
case ' \\ ' :
2006-02-13 02:13:31 +10:00
case L ' \' ' :
2006-10-09 11:22:48 +10:00
case L ' \n ' :
2006-02-13 02:13:31 +10:00
{
in [ out_pos ] = in [ in_pos ] ;
break ;
}
2010-09-18 09:51:16 +08:00
2006-02-13 02:13:31 +10:00
case 0 :
{
2007-01-27 03:14:13 +10:00
if ( ! allow_incomplete )
{
free ( in ) ;
return 0 ;
}
else
2010-09-18 09:51:16 +08:00
out_pos - - ;
2006-02-13 02:13:31 +10:00
}
2010-09-18 09:51:16 +08:00
2006-02-13 02:13:31 +10:00
default :
{
in [ out_pos + + ] = L ' \\ ' ;
in [ out_pos ] = in [ in_pos ] ;
}
}
2010-09-18 09:51:16 +08:00
2006-02-13 02:13:31 +10:00
}
2005-11-03 02:49:13 +10:00
if ( c = = L ' \' ' )
{
2006-10-10 01:19:13 +10:00
if ( unescape_special )
2010-09-18 09:51:16 +08:00
in [ out_pos ] = INTERNAL_SEPARATOR ;
2007-01-19 02:02:46 +10:00
else
2010-09-18 09:51:16 +08:00
out_pos - - ;
2005-11-03 02:49:13 +10:00
mode = 0 ;
2005-09-20 23:26:39 +10:00
}
2005-11-03 02:49:13 +10:00
else
{
2005-09-20 23:26:39 +10:00
in [ out_pos ] = in [ in_pos ] ;
2005-11-03 02:49:13 +10:00
}
2010-09-18 09:51:16 +08:00
2005-11-03 02:49:13 +10:00
break ;
2005-09-20 23:26:39 +10:00
}
2005-11-03 02:49:13 +10:00
/*
Mode 2 means double quoted string , i . e . " foo "
*/
case 2 :
{
switch ( c )
{
case ' " ' :
{
mode = 0 ;
2006-10-10 01:19:13 +10:00
if ( unescape_special )
2010-09-18 09:51:16 +08:00
in [ out_pos ] = INTERNAL_SEPARATOR ;
2007-01-19 02:02:46 +10:00
else
2010-09-18 09:51:16 +08:00
out_pos - - ;
2005-11-03 02:49:13 +10:00
break ;
}
2010-09-18 09:51:16 +08:00
2005-11-03 02:49:13 +10:00
case ' \\ ' :
{
switch ( in [ + + in_pos ] )
{
case L ' \0 ' :
{
2007-01-27 03:14:13 +10:00
if ( ! allow_incomplete )
{
free ( in ) ;
return 0 ;
}
else
2010-09-18 09:51:16 +08:00
out_pos - - ;
2005-11-03 02:49:13 +10:00
}
2010-09-18 09:51:16 +08:00
2006-03-06 11:50:12 +10:00
case ' \\ ' :
2005-11-03 02:49:13 +10:00
case L ' $ ' :
2006-02-13 02:13:31 +10:00
case ' " ' :
2006-10-09 11:22:48 +10:00
case ' \n ' :
2005-11-03 02:49:13 +10:00
{
in [ out_pos ] = in [ in_pos ] ;
break ;
}
2006-02-13 02:13:31 +10:00
2005-11-03 02:49:13 +10:00
default :
{
in [ out_pos + + ] = L ' \\ ' ;
in [ out_pos ] = in [ in_pos ] ;
break ;
}
}
break ;
}
2010-09-18 09:51:16 +08:00
2005-11-03 02:49:13 +10:00
case ' $ ' :
{
if ( unescape_special )
{
in [ out_pos ] = VARIABLE_EXPAND_SINGLE ;
}
else
{
in [ out_pos ] = in [ in_pos ] ;
}
break ;
}
2010-09-18 09:51:16 +08:00
2005-11-03 02:49:13 +10:00
default :
{
in [ out_pos ] = in [ in_pos ] ;
break ;
}
2010-09-18 09:51:16 +08:00
}
2005-11-03 02:49:13 +10:00
break ;
}
}
2005-09-20 23:26:39 +10:00
}
2007-01-19 02:02:46 +10:00
if ( ! allow_incomplete & & mode )
{
free ( in ) ;
return 0 ;
}
2007-01-19 02:27:00 +10:00
2005-09-20 23:26:39 +10:00
in [ out_pos ] = L ' \0 ' ;
2010-09-18 09:51:16 +08:00
return in ;
2005-09-20 23:26:39 +10:00
}
2005-10-01 05:50:21 +10:00
/**
2005-10-02 05:18:52 +10:00
Writes a pid_t in decimal representation to str .
str must contain sufficient space .
2010-09-18 09:51:16 +08:00
The conservatively approximate maximum number of characters a pid_t will
2005-10-02 05:18:52 +10:00
represent is given by : ( int ) ( 0.31 * sizeof ( pid_t ) + CHAR_BIT + 1 )
2005-10-01 05:50:21 +10:00
Returns the length of the string
*/
2005-10-02 05:18:52 +10:00
static int sprint_pid_t ( pid_t pid , char * str )
2005-10-01 05:50:21 +10:00
{
int len , i = 0 ;
int dig ;
/* Store digits in reverse order into string */
while ( pid ! = 0 )
{
dig = pid % 10 ;
str [ i ] = ' 0 ' + dig ;
pid = ( pid - dig ) / 10 ;
i + + ;
}
len = i ;
/* Reverse digits */
i / = 2 ;
while ( i )
{
i - - ;
dig = str [ i ] ;
str [ i ] = str [ len - 1 - i ] ;
str [ len - 1 - i ] = dig ;
}
return len ;
}
/**
2005-10-02 05:18:52 +10:00
Writes a pseudo - random number ( between one and maxlen ) of pseudo - random
digits into str .
str must point to an allocated buffer of size of at least maxlen chars .
Returns the number of digits written .
Since the randomness in part depends on machine time it has _some_ extra
strength but still not enough for use in concurrent locking schemes on a
single machine because gettimeofday may not return a different value on
consecutive calls when :
a ) the OS does not support fine enough resolution
b ) the OS is running on an SMP machine .
Additionally , gettimeofday errors are ignored .
Excludes chars other than digits since ANSI C only guarantees that digits
are consecutive .
2005-10-01 05:50:21 +10:00
*/
2005-10-02 05:18:52 +10:00
static int sprint_rand_digits ( char * str , int maxlen )
2005-10-01 05:50:21 +10:00
{
2005-10-02 05:18:52 +10:00
int i , max ;
struct timeval tv ;
2010-09-18 09:51:16 +08:00
/*
2005-10-07 20:36:51 +10:00
Seed the pseudo - random generator based on time - this assumes
that consecutive calls to gettimeofday will return different values
and ignores errors returned by gettimeofday .
Cast to unsigned so that wrapping occurs on overflow as per ANSI C .
2005-10-01 05:50:21 +10:00
*/
2005-10-02 05:18:52 +10:00
( void ) gettimeofday ( & tv , NULL ) ;
srand ( ( unsigned int ) tv . tv_sec + ( unsigned int ) tv . tv_usec * 1000000UL ) ;
max = 1 + ( maxlen - 1 ) * ( rand ( ) / ( RAND_MAX + 1.0 ) ) ;
for ( i = 0 ; i < max ; i + + )
{
str [ i ] = ' 0 ' + 10 * ( rand ( ) / ( RAND_MAX + 1.0 ) ) ;
}
return i ;
}
/**
Generate a filename unique in an NFS namespace by creating a copy of str and
2005-10-25 01:26:25 +10:00
appending . { hostname } . { pid } to it . If gethostname ( ) fails then a pseudo -
random string is substituted for { hostname } - the randomness of the string
2010-09-18 09:51:16 +08:00
should be strong enough across different machines . The main assumption
2005-10-02 05:18:52 +10:00
though is that gethostname will not fail and this is just a " safe enough "
fallback .
The memory returned should be freed using free ( ) .
*/
static char * gen_unique_nfs_filename ( const char * filename )
{
int pidlen , hnlen , orglen = strlen ( filename ) ;
char hostname [ HOST_NAME_MAX + 1 ] ;
char * newname ;
2010-09-18 09:51:16 +08:00
2005-10-02 05:18:52 +10:00
if ( gethostname ( hostname , HOST_NAME_MAX + 1 ) = = 0 )
2005-10-01 05:50:21 +10:00
{
2005-10-02 05:18:52 +10:00
hnlen = strlen ( hostname ) ;
2005-10-01 05:50:21 +10:00
}
2005-10-02 05:18:52 +10:00
else
{
hnlen = sprint_rand_digits ( hostname , HOST_NAME_MAX ) ;
hostname [ hnlen ] = ' \0 ' ;
}
newname = malloc ( orglen + 1 /* period */ + hnlen + 1 /* period */ +
2005-10-07 20:36:51 +10:00
/* max possible pid size: 0.31 ~= log(10)2 */
( int ) ( 0.31 * sizeof ( pid_t ) * CHAR_BIT + 1 )
+ 1 /* '\0' */ ) ;
2010-09-18 09:51:16 +08:00
2005-10-02 05:18:52 +10:00
if ( newname = = NULL )
{
debug ( 1 , L " gen_unique_nfs_filename: %s " , strerror ( errno ) ) ;
return newname ;
}
memcpy ( newname , filename , orglen ) ;
newname [ orglen ] = ' . ' ;
memcpy ( newname + orglen + 1 , hostname , hnlen ) ;
newname [ orglen + 1 + hnlen ] = ' . ' ;
pidlen = sprint_pid_t ( getpid ( ) , newname + orglen + 1 + hnlen + 1 ) ;
newname [ orglen + 1 + hnlen + 1 + pidlen ] = ' \0 ' ;
/* debug( 1, L"gen_unique_nfs_filename returning with: newname = \"%s\"; "
2006-06-15 20:37:06 +10:00
L " HOST_NAME_MAX = %d; hnlen = %d; orglen = %d; "
2010-09-18 09:51:16 +08:00
L " sizeof(pid_t) = %d; maxpiddigits = %d; malloc'd size: %d " ,
newname , ( int ) HOST_NAME_MAX , hnlen , orglen ,
( int ) sizeof ( pid_t ) ,
2006-06-15 20:37:06 +10:00
( int ) ( 0.31 * sizeof ( pid_t ) * CHAR_BIT + 1 ) ,
2010-09-18 09:51:16 +08:00
( int ) ( orglen + 1 + hnlen + 1 +
2006-06-15 20:37:06 +10:00
( int ) ( 0.31 * sizeof ( pid_t ) * CHAR_BIT + 1 ) + 1 ) ) ; */
2005-10-02 05:18:52 +10:00
return newname ;
2005-10-01 05:50:21 +10:00
}
int acquire_lock_file ( const char * lockfile , const int timeout , int force )
2005-09-28 11:43:09 +10:00
{
2005-10-01 05:50:21 +10:00
int fd , timed_out = 0 ;
int ret = 0 ; /* early exit returns failure */
2005-09-28 11:43:09 +10:00
struct timespec pollint ;
struct timeval start , end ;
double elapsed ;
2005-10-01 05:50:21 +10:00
struct stat statbuf ;
2005-09-28 11:43:09 +10:00
2005-10-01 05:50:21 +10:00
/*
( Re ) create a unique file and check that it has one only link .
*/
2005-10-02 05:18:52 +10:00
char * linkfile = gen_unique_nfs_filename ( lockfile ) ;
2005-10-01 05:50:21 +10:00
if ( linkfile = = NULL )
{
goto done ;
}
( void ) unlink ( linkfile ) ;
2007-08-15 07:37:22 +10:00
if ( ( fd = open ( linkfile , O_CREAT | O_RDONLY , 0600 ) ) = = - 1 )
2005-10-01 05:50:21 +10:00
{
2005-10-02 05:18:52 +10:00
debug ( 1 , L " acquire_lock_file: open: %s " , strerror ( errno ) ) ;
2005-10-01 05:50:21 +10:00
goto done ;
}
2006-06-21 19:54:30 +10:00
/*
Don ' t need to check exit status of close on read - only file descriptors
*/
2005-10-01 05:50:21 +10:00
close ( fd ) ;
2005-10-02 05:18:52 +10:00
if ( stat ( linkfile , & statbuf ) ! = 0 )
2005-10-01 05:50:21 +10:00
{
2005-10-02 05:18:52 +10:00
debug ( 1 , L " acquire_lock_file: stat: %s " , strerror ( errno ) ) ;
goto done ;
}
if ( statbuf . st_nlink ! = 1 )
{
debug ( 1 , L " acquire_lock_file: number of hardlinks on unique "
2005-10-07 20:36:51 +10:00
L " tmpfile is %d instead of 1. " , ( int ) statbuf . st_nlink ) ;
2005-10-01 05:50:21 +10:00
goto done ;
}
if ( gettimeofday ( & start , NULL ) ! = 0 )
{
2005-10-02 05:18:52 +10:00
debug ( 1 , L " acquire_lock_file: gettimeofday: %s " , strerror ( errno ) ) ;
2005-10-01 05:50:21 +10:00
goto done ;
}
end = start ;
pollint . tv_sec = 0 ;
pollint . tv_nsec = LOCKPOLLINTERVAL * 1000000 ;
2010-09-18 09:51:16 +08:00
do
2005-10-01 05:50:21 +10:00
{
/*
2010-09-18 09:51:16 +08:00
Try to create a hard link to the unique file from the
lockfile . This will only succeed if the lockfile does not
already exist . It is guaranteed to provide race - free
semantics over NFS which the alternative of calling
open ( O_EXCL | O_CREAT ) on the lockfile is not . The lock
succeeds if the call to link returns 0 or the link count on
2005-10-01 05:50:21 +10:00
the unique file increases to 2.
*/
if ( link ( linkfile , lockfile ) = = 0 | |
2010-09-18 09:51:16 +08:00
( stat ( linkfile , & statbuf ) = = 0 & &
2005-10-07 20:36:51 +10:00
statbuf . st_nlink = = 2 ) )
2005-10-01 05:50:21 +10:00
{
/* Successful lock */
ret = 1 ;
break ;
}
2010-09-18 09:51:16 +08:00
elapsed = end . tv_sec + end . tv_usec / 1000000.0 -
2005-10-01 05:50:21 +10:00
( start . tv_sec + start . tv_usec / 1000000.0 ) ;
2010-09-18 09:51:16 +08:00
/*
The check for elapsed < 0 is to deal with the unlikely event
2005-10-07 20:36:51 +10:00
that after the loop is entered the system time is set forward
2010-09-18 09:51:16 +08:00
past the loop ' s end time . This would otherwise result in a
2005-10-07 20:36:51 +10:00
( practically ) infinite loop .
2005-10-01 05:50:21 +10:00
*/
if ( timed_out | | elapsed > = timeout | | elapsed < 0 )
{
if ( timed_out = = 0 & & force )
{
/*
Timed out and force was specified - attempt to
remove stale lock and try a final time
*/
( void ) unlink ( lockfile ) ;
timed_out = 1 ;
continue ;
}
else
{
/*
2010-09-18 09:51:16 +08:00
Timed out and final try was unsuccessful or
2005-10-01 05:50:21 +10:00
force was not specified
*/
2005-10-02 05:18:52 +10:00
debug ( 1 , L " acquire_lock_file: timed out "
2005-10-07 20:36:51 +10:00
L " trying to obtain lockfile %s using "
L " linkfile %s " , lockfile , linkfile ) ;
2005-09-28 11:43:09 +10:00
break ;
}
2005-10-01 05:50:21 +10:00
}
nanosleep ( & pollint , NULL ) ;
} while ( gettimeofday ( & end , NULL ) = = 0 ) ;
2005-10-07 20:36:51 +10:00
done :
2005-10-01 05:50:21 +10:00
/* The linkfile is not needed once the lockfile has been created */
( void ) unlink ( linkfile ) ;
free ( linkfile ) ;
2005-09-28 11:43:09 +10:00
return ret ;
}
2005-10-14 21:40:33 +10:00
void common_handle_winch ( int signal )
{
2006-07-31 06:55:44 +10:00
# ifdef HAVE_WINSIZE
2005-10-14 21:40:33 +10:00
if ( ioctl ( 1 , TIOCGWINSZ , & termsize ) ! = 0 )
{
return ;
}
2006-07-31 06:55:44 +10:00
# else
termsize . ws_col = 80 ;
2006-08-01 10:46:48 +10:00
termsize . ws_row = 24 ;
2006-07-31 06:55:44 +10:00
# endif
2005-10-14 21:40:33 +10:00
}
int common_get_width ( )
{
return termsize . ws_col ;
}
int common_get_height ( )
{
return termsize . ws_row ;
}
2006-05-29 21:13:42 +10:00
void tokenize_variable_array ( const wchar_t * val , array_list_t * out )
{
if ( val )
{
wchar_t * cpy = wcsdup ( val ) ;
wchar_t * pos , * start ;
2007-01-09 12:51:02 +10:00
wchar_t * next ;
2006-05-29 21:13:42 +10:00
if ( ! cpy )
{
2006-07-03 20:39:57 +10:00
DIE_MEM ( ) ;
2006-05-29 21:13:42 +10:00
}
for ( start = pos = cpy ; * pos ; pos + + )
{
if ( * pos = = ARRAY_SEP )
{
2010-09-18 09:51:16 +08:00
2006-05-29 21:13:42 +10:00
* pos = 0 ;
2007-01-09 12:51:02 +10:00
next = start = = cpy ? cpy : wcsdup ( start ) ;
if ( ! next )
DIE_MEM ( ) ;
al_push ( out , next ) ;
2006-05-29 21:13:42 +10:00
start = pos + 1 ;
}
}
2007-01-09 12:51:02 +10:00
next = start = = cpy ? cpy : wcsdup ( start ) ;
if ( ! next )
DIE_MEM ( ) ;
al_push ( out , next ) ;
2006-05-29 21:13:42 +10:00
}
}
2006-10-19 21:50:23 +10:00
int create_directory ( wchar_t * d )
{
int ok = 0 ;
struct stat buf ;
int stat_res = 0 ;
2010-09-18 09:51:16 +08:00
2006-10-19 21:50:23 +10:00
while ( ( stat_res = wstat ( d , & buf ) ) ! = 0 )
{
if ( errno ! = EAGAIN )
break ;
}
2010-09-18 09:51:16 +08:00
2006-10-19 21:50:23 +10:00
if ( stat_res = = 0 )
{
if ( S_ISDIR ( buf . st_mode ) )
{
ok = 1 ;
}
}
else
{
if ( errno = = ENOENT )
{
wchar_t * dir = wcsdup ( d ) ;
dir = wdirname ( dir ) ;
if ( ! create_directory ( dir ) )
{
if ( ! wmkdir ( d , 0700 ) )
{
ok = 1 ;
}
}
free ( dir ) ;
}
}
2010-09-18 09:51:16 +08:00
2006-10-19 21:50:23 +10:00
return ok ? 0 : - 1 ;
}
2006-11-18 00:58:25 +10:00
void bugreport ( )
{
debug ( 1 ,
2007-09-24 07:07:30 +10:00
_ ( L " This is a bug. "
L " If you can reproduce it, please send a bug report to %s. " ) ,
2006-11-18 00:58:25 +10:00
PACKAGE_BUGREPORT ) ;
}
2007-10-15 19:51:08 +10:00
void sb_format_size ( string_buffer_t * sb ,
long long sz )
{
wchar_t * sz_name [ ] =
{
L " kB " , L " MB " , L " GB " , L " TB " , L " PB " , L " EB " , L " ZB " , L " YB " , 0
}
;
if ( sz < 0 )
{
sb_append ( sb , L " unknown " ) ;
}
else if ( sz < 1 )
{
sb_append ( sb , _ ( L " empty " ) ) ;
}
else if ( sz < 1024 )
{
sb_printf ( sb , L " %lldB " , sz ) ;
}
else
{
int i ;
2010-09-18 09:51:16 +08:00
2007-10-15 19:51:08 +10:00
for ( i = 0 ; sz_name [ i ] ; i + + )
{
if ( sz < ( 1024 * 1024 ) | | ! sz_name [ i + 1 ] )
{
int isz = sz / 1024 ;
if ( isz > 9 )
sb_printf ( sb , L " %d%ls " , isz , sz_name [ i ] ) ;
else
sb_printf ( sb , L " %.1f%ls " , ( double ) sz / 1024 , sz_name [ i ] ) ;
break ;
}
sz / = 1024 ;
2010-09-18 09:51:16 +08:00
2007-10-15 19:51:08 +10:00
}
2010-09-18 09:51:16 +08:00
}
2007-10-15 19:51:08 +10:00
}
2009-02-03 08:46:45 +10:00
double timef ( )
{
int time_res ;
struct timeval tv ;
2010-09-18 09:51:16 +08:00
2009-02-03 08:46:45 +10:00
time_res = gettimeofday ( & tv , 0 ) ;
2010-09-18 09:51:16 +08:00
if ( time_res )
2009-02-03 08:46:45 +10:00
{
2009-02-23 06:28:52 +10:00
/*
Fixme : What on earth is the correct parameter value for NaN ?
The man pages and the standard helpfully state that this
parameter is implementation defined . Gcc gives a warning if
a null pointer is used . But not even all mighty Google gives
a hint to what value should actually be returned .
*/
return nan ( " " ) ;
2009-02-03 08:46:45 +10:00
}
2010-09-18 09:51:16 +08:00
2009-02-03 08:46:45 +10:00
return ( double ) tv . tv_sec + 0.000001 * tv . tv_usec ;
}