2005-09-20 23:26:39 +10:00
/** \file wutil.c
2012-11-18 11:23:22 +01:00
Wide character equivalents of various standard unix
functions .
2005-09-20 23:26:39 +10:00
*/
# include "config.h"
# include <stdlib.h>
# include <stdio.h>
# include <unistd.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <errno.h>
# include <fcntl.h>
# include <wchar.h>
2005-10-15 10:51:26 +10:00
# include <wctype.h>
2005-09-20 23:26:39 +10:00
# include <string.h>
# include <dirent.h>
# include <stdarg.h>
# include <limits.h>
2006-06-14 23:22:40 +10:00
# include <libgen.h>
2012-02-17 15:55:54 -08:00
# include <pthread.h>
2011-12-26 19:18:46 -08:00
# include <string>
2012-02-24 12:13:35 -08:00
# include <map>
2005-09-20 23:26:39 +10:00
2012-02-17 15:55:54 -08:00
2006-07-20 08:55:49 +10:00
# if HAVE_LIBINTL_H
# include <libintl.h>
# endif
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 "common.h"
# include "wutil.h"
2011-12-26 19:18:46 -08:00
typedef std : : string cstring ;
2006-06-20 10:50:10 +10:00
/**
Minimum length of the internal covnersion buffers
*/
2005-11-03 01:41:59 +10:00
# define TMP_LEN_MIN 256
2006-02-03 01:23:56 +10:00
# ifndef PATH_MAX
# ifdef MAXPATHLEN
# define PATH_MAX MAXPATHLEN
# else
2006-06-20 10:50:10 +10:00
/**
Fallback length of MAXPATHLEN . Just a hopefully sane value . . .
*/
2006-02-03 01:23:56 +10:00
# define PATH_MAX 4096
# endif
# endif
2012-02-24 12:13:35 -08:00
/* Lock to protect wgettext */
static pthread_mutex_t wgettext_lock ;
/* Maps string keys to (immortal) pointers to string values */
typedef std : : map < wcstring , wcstring * > wgettext_map_t ;
static std : : map < wcstring , wcstring * > wgettext_map ;
2006-07-20 08:55:49 +10:00
2005-11-03 01:41:59 +10:00
void wutil_init ( )
{
}
2005-09-20 23:26:39 +10:00
void wutil_destroy ( )
{
}
2012-02-20 02:13:31 -08:00
bool wreaddir_resolving ( DIR * dir , const std : : wstring & dir_path , std : : wstring & out_name , bool * out_is_dir )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
struct dirent * d = readdir ( dir ) ;
if ( ! d ) return false ;
2012-11-18 11:23:22 +01:00
2012-02-20 02:13:31 -08:00
out_name = str2wcstring ( d - > d_name ) ;
2012-11-18 16:30:30 -08:00
if ( out_is_dir )
{
2012-05-07 17:31:24 -07:00
/* The caller cares if this is a directory, so check */
2012-02-20 02:13:31 -08:00
bool is_dir ;
2012-11-18 16:30:30 -08:00
if ( d - > d_type = = DT_DIR )
{
2012-02-20 02:13:31 -08:00
is_dir = true ;
2012-11-18 16:30:30 -08:00
}
else if ( d - > d_type = = DT_LNK | | d - > d_type = = DT_UNKNOWN )
{
2012-02-20 02:13:31 -08:00
/* We want to treat symlinks to directories as directories. Use stat to resolve it. */
cstring fullpath = wcs2string ( dir_path ) ;
fullpath . push_back ( ' / ' ) ;
fullpath . append ( d - > d_name ) ;
struct stat buf ;
2012-11-18 16:30:30 -08:00
if ( stat ( fullpath . c_str ( ) , & buf ) ! = 0 )
{
2012-02-20 02:13:31 -08:00
is_dir = false ;
}
2012-11-18 16:30:30 -08:00
else
{
is_dir = ! ! ( S_ISDIR ( buf . st_mode ) ) ;
}
}
else
{
2012-02-20 02:13:31 -08:00
is_dir = false ;
}
* out_is_dir = is_dir ;
}
return true ;
}
bool wreaddir ( DIR * dir , std : : wstring & out_name )
{
2012-11-18 16:30:30 -08:00
struct dirent * d = readdir ( dir ) ;
if ( ! d ) return false ;
2012-11-18 11:23:22 +01:00
2012-02-20 02:13:31 -08:00
out_name = str2wcstring ( d - > d_name ) ;
2012-02-17 18:08:08 -08:00
return true ;
2005-09-20 23:26:39 +10:00
}
2006-02-09 00:58:47 +10:00
2012-11-18 16:30:30 -08:00
wchar_t * wgetcwd ( wchar_t * buff , size_t sz )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
char * buffc = ( char * ) malloc ( sz * MAX_UTF8_BYTES ) ;
char * res ;
wchar_t * ret = 0 ;
if ( ! buffc )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
errno = ENOMEM ;
return 0 ;
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
res = getcwd ( buffc , sz * MAX_UTF8_BYTES ) ;
if ( res )
{
if ( ( size_t ) - 1 ! = mbstowcs ( buff , buffc , sizeof ( wchar_t ) * sz ) )
{
ret = buff ;
}
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
free ( buffc ) ;
return ret ;
2005-09-20 23:26:39 +10:00
}
2012-11-18 16:30:30 -08:00
int wchdir ( const wcstring & dir )
2005-09-20 23:26:39 +10:00
{
2011-12-26 19:18:46 -08:00
cstring tmp = wcs2string ( dir ) ;
2012-11-18 16:30:30 -08:00
return chdir ( tmp . c_str ( ) ) ;
2005-09-20 23:26:39 +10:00
}
2012-02-18 22:41:22 +05:30
FILE * wfopen ( const wcstring & path , const char * mode )
2005-09-20 23:26:39 +10:00
{
2012-03-02 00:27:40 -08:00
int permissions = 0 , options = 0 ;
2012-03-03 22:48:21 -08:00
size_t idx = 0 ;
2012-11-18 16:30:30 -08:00
switch ( mode [ idx + + ] )
{
2012-11-19 00:31:03 -08:00
case ' r ' :
permissions = O_RDONLY ;
break ;
case ' w ' :
permissions = O_WRONLY ;
options = O_CREAT | O_TRUNC ;
break ;
case ' a ' :
permissions = O_WRONLY ;
options = O_CREAT | O_APPEND ;
break ;
default :
errno = EINVAL ;
return NULL ;
break ;
2012-03-02 00:27:40 -08:00
}
/* Skip binary */
2012-03-03 22:48:21 -08:00
if ( mode [ idx ] = = ' b ' )
idx + + ;
2012-11-18 11:23:22 +01:00
2012-03-02 00:27:40 -08:00
/* Consider append option */
2012-03-03 22:48:21 -08:00
if ( mode [ idx ] = = ' + ' )
2012-03-02 00:27:40 -08:00
permissions = O_RDWR ;
2012-11-18 11:23:22 +01:00
2012-03-02 00:27:40 -08:00
int fd = wopen_cloexec ( path , permissions | options , 0666 ) ;
if ( fd < 0 )
return NULL ;
FILE * result = fdopen ( fd , mode ) ;
if ( result = = NULL )
close ( fd ) ;
return result ;
2005-09-20 23:26:39 +10:00
}
2012-02-18 22:41:22 +05:30
FILE * wfreopen ( const wcstring & path , const char * mode , FILE * stream )
2005-09-20 23:26:39 +10:00
{
2011-12-26 19:18:46 -08:00
cstring tmp = wcs2string ( path ) ;
return freopen ( tmp . c_str ( ) , mode , stream ) ;
2005-09-20 23:26:39 +10:00
}
2012-11-18 16:30:30 -08:00
bool set_cloexec ( int fd )
{
2012-03-02 00:27:40 -08:00
int flags = fcntl ( fd , F_GETFD , 0 ) ;
2012-11-18 16:30:30 -08:00
if ( flags < 0 )
{
2012-03-02 00:27:40 -08:00
return false ;
2012-11-18 16:30:30 -08:00
}
else if ( flags & FD_CLOEXEC )
{
2012-03-02 00:27:40 -08:00
return true ;
2012-11-18 16:30:30 -08:00
}
else
{
2012-03-02 00:27:40 -08:00
return fcntl ( fd , F_SETFD , flags | FD_CLOEXEC ) > = 0 ;
}
}
static int wopen_internal ( const wcstring & pathname , int flags , mode_t mode , bool cloexec )
2005-09-20 23:26:39 +10:00
{
2012-03-08 23:21:07 -08:00
ASSERT_IS_NOT_FORKED_CHILD ( ) ;
2011-12-26 19:18:46 -08:00
cstring tmp = wcs2string ( pathname ) ;
2012-03-02 09:58:29 -08:00
/* Prefer to use O_CLOEXEC. It has to both be defined and nonzero */
# ifdef O_CLOEXEC
2012-11-18 16:30:30 -08:00
if ( cloexec & & O_CLOEXEC )
{
2012-03-02 09:58:29 -08:00
flags | = O_CLOEXEC ;
cloexec = false ;
}
# endif
2012-03-02 00:27:40 -08:00
int fd = : : open ( tmp . c_str ( ) , flags , mode ) ;
2012-11-18 16:30:30 -08:00
if ( cloexec & & fd > = 0 & & ! set_cloexec ( fd ) )
{
2012-03-02 00:27:40 -08:00
close ( fd ) ;
fd = - 1 ;
2011-12-26 19:18:46 -08:00
}
2012-03-02 00:27:40 -08:00
return fd ;
2012-11-18 11:23:22 +01:00
2012-03-02 00:27:40 -08:00
}
int wopen ( const wcstring & pathname , int flags , mode_t mode )
{
// off the main thread, always use wopen_cloexec
ASSERT_IS_MAIN_THREAD ( ) ;
2012-03-08 23:21:07 -08:00
ASSERT_IS_NOT_FORKED_CHILD ( ) ;
2012-03-02 00:27:40 -08:00
return wopen_internal ( pathname , flags , mode , false ) ;
2005-09-20 23:26:39 +10:00
}
2012-03-02 00:27:40 -08:00
int wopen_cloexec ( const wcstring & pathname , int flags , mode_t mode )
{
return wopen_internal ( pathname , flags , mode , true ) ;
}
2012-02-18 22:41:22 +05:30
int wcreat ( const wcstring & pathname , mode_t mode )
2005-09-20 23:26:39 +10:00
{
2011-12-26 19:18:46 -08:00
cstring tmp = wcs2string ( pathname ) ;
return creat ( tmp . c_str ( ) , mode ) ;
2005-09-20 23:26:39 +10:00
}
2012-02-18 22:41:22 +05:30
DIR * wopendir ( const wcstring & name )
2005-09-20 23:26:39 +10:00
{
2011-12-26 19:18:46 -08:00
cstring tmp = wcs2string ( name ) ;
return opendir ( tmp . c_str ( ) ) ;
2005-09-20 23:26:39 +10:00
}
2012-02-18 22:41:22 +05:30
int wstat ( const wcstring & file_name , struct stat * buf )
2005-09-20 23:26:39 +10:00
{
2011-12-26 19:18:46 -08:00
cstring tmp = wcs2string ( file_name ) ;
return stat ( tmp . c_str ( ) , buf ) ;
2005-09-20 23:26:39 +10:00
}
2012-02-18 22:41:22 +05:30
int lwstat ( const wcstring & file_name , struct stat * buf )
2005-09-20 23:26:39 +10:00
{
2011-12-26 19:18:46 -08:00
cstring tmp = wcs2string ( file_name ) ;
return lstat ( tmp . c_str ( ) , buf ) ;
2005-09-20 23:26:39 +10:00
}
2012-02-18 22:41:22 +05:30
int waccess ( const wcstring & file_name , int mode )
2005-09-20 23:26:39 +10:00
{
2011-12-26 19:18:46 -08:00
cstring tmp = wcs2string ( file_name ) ;
return access ( tmp . c_str ( ) , mode ) ;
2005-09-20 23:26:39 +10:00
}
2012-02-18 22:41:22 +05:30
int wunlink ( const wcstring & file_name )
2012-02-16 00:24:27 -08:00
{
cstring tmp = wcs2string ( file_name ) ;
return unlink ( tmp . c_str ( ) ) ;
}
2012-02-18 22:41:22 +05:30
void wperror ( const wcstring & s )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
int e = errno ;
if ( ! s . empty ( ) )
{
fwprintf ( stderr , L " %ls: " , s . c_str ( ) ) ;
}
fwprintf ( stderr , L " %s \n " , strerror ( e ) ) ;
2005-09-20 23:26:39 +10:00
}
2013-04-07 12:40:08 -07:00
int make_fd_nonblocking ( int fd )
{
int flags = fcntl ( fd , F_GETFL , 0 ) ;
int err = 0 ;
2013-05-05 02:33:17 -07:00
if ( ! ( flags & O_NONBLOCK ) )
2013-04-07 12:40:08 -07:00
{
err = fcntl ( fd , F_SETFL , flags | O_NONBLOCK ) ;
}
return err = = - 1 ? errno : 0 ;
}
int make_fd_blocking ( int fd )
{
int flags = fcntl ( fd , F_GETFL , 0 ) ;
int err = 0 ;
if ( flags & O_NONBLOCK )
{
err = fcntl ( fd , F_SETFL , flags & ~ O_NONBLOCK ) ;
}
return err = = - 1 ? errno : 0 ;
}
2013-01-09 17:06:20 -08:00
static inline void safe_append ( char * buffer , const char * s , size_t buffsize )
{
strncat ( buffer , s , buffsize - strlen ( buffer ) - 1 ) ;
}
const char * safe_strerror ( int err )
{
2013-05-25 13:42:16 -07:00
# if defined(__UCLIBC__)
// uClibc does not have sys_errlist, however, its strerror is believed to be async-safe
// See #808
return strerror ( err ) ;
# else
2013-01-09 17:06:20 -08:00
if ( err > = 0 & & err < sys_nerr & & sys_errlist [ err ] ! = NULL )
{
return sys_errlist [ err ] ;
}
else
{
int saved_err = errno ;
2013-01-12 12:55:23 -08:00
2013-01-09 17:06:20 -08:00
/* Use a shared buffer for this case */
static char buff [ 384 ] ;
char errnum_buff [ 64 ] ;
format_long_safe ( errnum_buff , err ) ;
2013-01-12 12:55:23 -08:00
2013-01-09 17:06:20 -08:00
buff [ 0 ] = ' \0 ' ;
safe_append ( buff , " unknown error (errno was " , sizeof buff ) ;
safe_append ( buff , errnum_buff , sizeof buff ) ;
safe_append ( buff , " ) " , sizeof buff ) ;
2013-01-12 12:55:23 -08:00
2013-01-09 17:06:20 -08:00
errno = saved_err ;
return buff ;
}
2013-05-25 13:42:16 -07:00
# endif
2013-01-09 17:06:20 -08:00
}
void safe_perror ( const char * message )
{
// Note we cannot use strerror, because on Linux it uses gettext, which is not safe
int err = errno ;
2013-01-12 12:55:23 -08:00
2013-01-09 17:06:20 -08:00
char buff [ 384 ] ;
buff [ 0 ] = ' \0 ' ;
2013-01-12 12:55:23 -08:00
if ( message )
{
2013-01-09 17:06:20 -08:00
safe_append ( buff , message , sizeof buff ) ;
safe_append ( buff , " : " , sizeof buff ) ;
}
safe_append ( buff , safe_strerror ( err ) , sizeof buff ) ;
safe_append ( buff , " \n " , sizeof buff ) ;
2013-01-12 12:55:23 -08:00
2013-01-09 17:06:20 -08:00
write ( STDERR_FILENO , buff , strlen ( buff ) ) ;
errno = err ;
}
2006-02-03 01:23:56 +10:00
# ifdef HAVE_REALPATH_NULL
2012-02-18 22:41:22 +05:30
wchar_t * wrealpath ( const wcstring & pathname , wchar_t * resolved_path )
2006-02-03 01:23:56 +10:00
{
2012-12-19 13:31:06 -08:00
cstring narrow_path = wcs2string ( pathname ) ;
char * narrow_res = realpath ( narrow_path . c_str ( ) , NULL ) ;
2012-11-18 16:30:30 -08:00
if ( ! narrow_res )
2012-12-19 13:31:06 -08:00
return NULL ;
2012-11-18 16:30:30 -08:00
2012-12-19 13:31:06 -08:00
wchar_t * res ;
wcstring wide_res = str2wcstring ( narrow_res ) ;
2012-11-18 16:30:30 -08:00
if ( resolved_path )
{
2012-12-19 13:31:06 -08:00
wcslcpy ( resolved_path , wide_res . c_str ( ) , PATH_MAX ) ;
2012-11-18 16:30:30 -08:00
res = resolved_path ;
}
else
{
2012-12-19 13:31:06 -08:00
res = wcsdup ( wide_res . c_str ( ) ) ;
2012-11-18 16:30:30 -08:00
}
free ( narrow_res ) ;
return res ;
2006-02-03 01:23:56 +10:00
}
# else
2012-06-23 10:56:50 +05:30
wchar_t * wrealpath ( const wcstring & pathname , wchar_t * resolved_path )
2006-02-03 01:23:56 +10:00
{
2011-12-26 19:18:46 -08:00
cstring tmp = wcs2string ( pathname ) ;
2012-11-18 16:30:30 -08:00
char narrow_buff [ PATH_MAX ] ;
char * narrow_res = realpath ( tmp . c_str ( ) , narrow_buff ) ;
wchar_t * res ;
if ( ! narrow_res )
return 0 ;
2013-01-04 13:09:01 -08:00
2012-12-24 20:55:35 -08:00
const wcstring wide_res = str2wcstring ( narrow_res ) ;
2012-11-18 16:30:30 -08:00
if ( resolved_path )
{
2012-12-24 20:55:35 -08:00
wcslcpy ( resolved_path , wide_res . c_str ( ) , PATH_MAX ) ;
2012-11-18 16:30:30 -08:00
res = resolved_path ;
}
else
{
2012-12-24 20:55:35 -08:00
res = wcsdup ( wide_res . c_str ( ) ) ;
2012-11-18 16:30:30 -08:00
}
return res ;
2006-02-03 01:23:56 +10:00
}
# endif
2006-06-14 23:22:40 +10:00
2012-11-18 16:30:30 -08:00
wcstring wdirname ( const wcstring & path )
2006-06-14 23:22:40 +10:00
{
2011-12-26 19:18:46 -08:00
char * tmp = wcs2str ( path . c_str ( ) ) ;
2012-11-18 16:30:30 -08:00
char * narrow_res = dirname ( tmp ) ;
2011-12-26 19:18:46 -08:00
wcstring result = format_string ( L " %s " , narrow_res ) ;
free ( tmp ) ;
return result ;
2006-06-14 23:22:40 +10:00
}
2012-11-18 16:30:30 -08:00
wcstring wbasename ( const wcstring & path )
2006-06-14 23:22:40 +10:00
{
2011-12-26 19:18:46 -08:00
char * tmp = wcs2str ( path . c_str ( ) ) ;
2012-11-18 16:30:30 -08:00
char * narrow_res = basename ( tmp ) ;
2011-12-26 19:18:46 -08:00
wcstring result = format_string ( L " %s " , narrow_res ) ;
free ( tmp ) ;
return result ;
2006-06-14 23:22:40 +10:00
}
2012-02-17 15:55:54 -08:00
/* Really init wgettext */
2012-11-18 16:30:30 -08:00
static void wgettext_really_init ( )
{
2012-02-24 12:13:35 -08:00
pthread_mutex_init ( & wgettext_lock , NULL ) ;
2013-04-08 10:20:56 -07:00
fish_bindtextdomain ( PACKAGE_NAME , LOCALEDIR ) ;
fish_textdomain ( PACKAGE_NAME ) ;
2006-07-20 08:55:49 +10:00
}
2012-02-17 15:55:54 -08:00
/**
For wgettext : Internal init function . Automatically called when a translation is first requested .
*/
static void wgettext_init_if_necessary ( )
{
static pthread_once_t once = PTHREAD_ONCE_INIT ;
pthread_once ( & once , wgettext_really_init ) ;
}
2012-11-18 16:30:30 -08:00
const wchar_t * wgettext ( const wchar_t * in )
2006-07-20 08:55:49 +10:00
{
2012-11-18 16:30:30 -08:00
if ( ! in )
return in ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
// preserve errno across this since this is often used in printing error messages
int err = errno ;
2012-11-18 11:23:22 +01:00
2012-02-17 15:55:54 -08:00
wgettext_init_if_necessary ( ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
wcstring key = in ;
2012-02-24 12:13:35 -08:00
scoped_lock lock ( wgettext_lock ) ;
2012-11-18 11:23:22 +01:00
2012-02-24 12:13:35 -08:00
wcstring * & val = wgettext_map [ key ] ;
2012-11-18 16:30:30 -08:00
if ( val = = NULL )
{
2012-02-24 12:13:35 -08:00
cstring mbs_in = wcs2string ( key ) ;
2013-04-08 10:20:56 -07:00
char * out = fish_gettext ( mbs_in . c_str ( ) ) ;
2012-02-24 12:13:35 -08:00
val = new wcstring ( format_string ( L " %s " , out ) ) ;
}
2012-11-18 16:30:30 -08:00
errno = err ;
return val - > c_str ( ) ;
2006-07-20 08:55:49 +10:00
}
2012-11-18 16:30:30 -08:00
const wchar_t * wgetenv ( const wcstring & name )
2006-08-12 00:55:28 +10:00
{
2012-02-09 19:26:44 -08:00
ASSERT_IS_MAIN_THREAD ( ) ;
2011-12-26 19:18:46 -08:00
cstring name_narrow = wcs2string ( name ) ;
2012-11-18 16:30:30 -08:00
char * res_narrow = getenv ( name_narrow . c_str ( ) ) ;
static wcstring out ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( ! res_narrow )
return 0 ;
2006-08-12 00:55:28 +10:00
2012-02-09 19:26:44 -08:00
out = format_string ( L " %s " , res_narrow ) ;
2012-11-18 16:30:30 -08:00
return out . c_str ( ) ;
2012-11-18 11:23:22 +01:00
2006-08-12 00:55:28 +10:00
}
2012-11-18 16:30:30 -08:00
int wmkdir ( const wcstring & name , int mode )
2006-09-09 00:11:28 +10:00
{
2012-11-18 16:30:30 -08:00
cstring name_narrow = wcs2string ( name ) ;
return mkdir ( name_narrow . c_str ( ) , mode ) ;
2006-09-09 00:11:28 +10:00
}
2006-10-21 08:33:47 +10:00
2012-11-18 16:30:30 -08:00
int wrename ( const wcstring & old , const wcstring & newv )
2006-10-21 08:33:47 +10:00
{
2011-12-26 19:18:46 -08:00
cstring old_narrow = wcs2string ( old ) ;
2012-11-18 16:30:30 -08:00
cstring new_narrow = wcs2string ( newv ) ;
return rename ( old_narrow . c_str ( ) , new_narrow . c_str ( ) ) ;
2006-10-21 08:33:47 +10:00
}
2012-08-04 11:07:42 -07:00
int fish_wcstoi ( const wchar_t * str , wchar_t * * endptr , int base )
{
long ret = wcstol ( str , endptr , base ) ;
if ( ret > INT_MAX )
{
ret = INT_MAX ;
errno = ERANGE ;
}
else if ( ret < INT_MIN )
{
ret = INT_MIN ;
errno = ERANGE ;
}
return ( int ) ret ;
}