2005-09-20 23:26:39 +10:00
/** \file wutil.c
2006-01-21 00:27:21 +10:00
Wide character equivalents of various standard unix
2006-03-02 02:53:47 +10:00
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>
2005-09-20 23:26:39 +10: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"
2006-06-14 23:22:40 +10:00
# include "halloc.h"
# include "halloc_util.h"
2005-09-20 23:26:39 +10:00
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
2005-10-28 01:21:48 +10:00
/**
Buffer for converting wide arguments to narrow arguments , used by
the \ c wutil_wcs2str ( ) function .
*/
2005-09-20 23:26:39 +10:00
static char * tmp = 0 ;
2006-08-12 00:55:28 +10:00
2006-06-20 10:50:10 +10:00
/**
Buffer for converting narrow results to wide ones , used by the \ c
wutil_str2wcs ( ) function . Avoid usign this without thinking about
2006-08-12 00:55:28 +10:00
it , since subsequent calls will overwrite previous values .
2006-06-20 10:50:10 +10:00
*/
2006-06-14 23:22:40 +10:00
static wchar_t * tmp2 ;
2006-08-12 00:55:28 +10:00
2005-10-28 01:21:48 +10:00
/**
Length of the \ c tmp buffer .
*/
2005-09-20 23:26:39 +10:00
static size_t tmp_len = 0 ;
2006-06-20 10:50:10 +10:00
/**
Length of the \ c tmp2 buffer
*/
2006-06-14 23:22:40 +10:00
static size_t tmp2_len ;
2005-09-20 23:26:39 +10:00
2005-10-28 01:21:48 +10:00
/**
Counts the number of calls to the wutil wrapper functions
*/
static int wutil_calls = 0 ;
2005-09-20 23:26:39 +10:00
2006-06-20 10:50:10 +10:00
/**
Storage for the wreaddir function
*/
2006-02-09 00:58:47 +10:00
static struct wdirent my_wdirent ;
2006-07-20 08:55:49 +10:00
/**
For wgettext : Number of string_buffer_t in the ring of buffers
*/
# define BUFF_COUNT 64
/**
For wgettext : The ring of string_buffer_t
*/
static string_buffer_t buff [ BUFF_COUNT ] ;
/**
For wgettext : Current position in the ring
*/
static int curr_buff = 0 ;
/**
For wgettext : Buffer used by translate_wcs2str
*/
static char * wcs2str_buff = 0 ;
/**
For wgettext : Size of buffer used by translate_wcs2str
*/
static size_t wcs2str_buff_count = 0 ;
/**
For wgettext : Flag to tell whether the translation library has been initialized
*/
static int wgettext_is_init = 0 ;
2005-11-03 01:41:59 +10:00
void wutil_init ( )
{
}
2005-09-20 23:26:39 +10:00
void wutil_destroy ( )
{
free ( tmp ) ;
2006-02-09 00:58:47 +10:00
free ( tmp2 ) ;
2006-06-14 23:22:40 +10:00
2005-09-20 23:26:39 +10:00
tmp = 0 ;
tmp_len = 0 ;
2005-10-28 01:21:48 +10:00
debug ( 3 , L " wutil functions called %d times " , wutil_calls ) ;
2005-09-20 23:26:39 +10:00
}
2005-10-28 01:21:48 +10:00
/**
Convert the specified wide aharacter string to a narrow character
string . This function uses an internal temporary buffer for storing
the result so subsequent results will overwrite previous results .
*/
2005-09-20 23:26:39 +10:00
static char * wutil_wcs2str ( const wchar_t * in )
{
2006-02-03 10:40:28 +10:00
size_t new_sz ;
2006-02-09 00:58:47 +10:00
2005-10-28 01:21:48 +10:00
wutil_calls + + ;
2005-09-20 23:26:39 +10:00
2006-02-03 10:40:28 +10:00
new_sz = MAX_UTF8_BYTES * wcslen ( in ) + 1 ;
2005-09-20 23:26:39 +10:00
if ( tmp_len < new_sz )
{
2005-11-03 01:41:59 +10:00
new_sz = maxi ( new_sz , TMP_LEN_MIN ) ;
tmp = realloc ( tmp , new_sz ) ;
2005-09-20 23:26:39 +10:00
if ( ! tmp )
{
2006-07-03 20:39:57 +10:00
DIE_MEM ( ) ;
2005-09-20 23:26:39 +10:00
}
tmp_len = new_sz ;
}
2006-02-09 00:58:47 +10:00
return wcs2str_internal ( in , tmp ) ;
}
/**
Convert the specified wide character string to a narrow character
string . This function uses an internal temporary buffer for storing
the result so subsequent results will overwrite previous results .
*/
static wchar_t * wutil_str2wcs ( const char * in )
{
size_t new_sz ;
wutil_calls + + ;
2005-09-20 23:26:39 +10:00
2006-02-09 00:58:47 +10:00
new_sz = sizeof ( wchar_t ) * ( strlen ( in ) + 1 ) ;
if ( tmp2_len < new_sz )
2006-02-03 10:40:28 +10:00
{
2006-02-09 00:58:47 +10:00
new_sz = maxi ( new_sz , TMP_LEN_MIN ) ;
tmp2 = realloc ( tmp2 , new_sz ) ;
if ( ! tmp2 )
2006-02-03 10:40:28 +10:00
{
2006-07-03 20:39:57 +10:00
DIE_MEM ( ) ;
2006-02-03 10:40:28 +10:00
}
2006-02-09 00:58:47 +10:00
tmp2_len = new_sz ;
2006-02-03 10:40:28 +10:00
}
2006-06-14 23:22:40 +10:00
2006-02-09 00:58:47 +10:00
return str2wcs_internal ( in , tmp2 ) ;
}
struct wdirent * wreaddir ( DIR * dir )
{
struct dirent * d = readdir ( dir ) ;
if ( ! d )
return 0 ;
my_wdirent . d_name = wutil_str2wcs ( d - > d_name ) ;
return & my_wdirent ;
2006-02-03 10:40:28 +10:00
2005-09-20 23:26:39 +10:00
}
2006-02-09 00:58:47 +10:00
2005-09-20 23:26:39 +10:00
wchar_t * wgetcwd ( wchar_t * buff , size_t sz )
{
2006-05-13 01:44:47 +10:00
char * buffc = malloc ( sz * MAX_UTF8_BYTES ) ;
char * res ;
wchar_t * ret = 0 ;
if ( ! buffc )
{
errno = ENOMEM ;
2005-09-20 23:26:39 +10:00
return 0 ;
2006-05-13 01:44:47 +10:00
}
2005-09-20 23:26:39 +10:00
2006-05-13 01:44:47 +10:00
res = getcwd ( buffc , sz * MAX_UTF8_BYTES ) ;
if ( res )
2005-09-20 23:26:39 +10:00
{
2006-05-13 01:44:47 +10:00
if ( ( size_t ) - 1 ! = mbstowcs ( buff , buffc , sizeof ( wchar_t ) * sz ) )
{
ret = buff ;
}
}
free ( buffc ) ;
return ret ;
2005-09-20 23:26:39 +10:00
}
int wchdir ( const wchar_t * dir )
{
char * tmp = wutil_wcs2str ( dir ) ;
return chdir ( tmp ) ;
}
FILE * wfopen ( const wchar_t * path , const char * mode )
{
char * tmp = wutil_wcs2str ( path ) ;
FILE * res = 0 ;
if ( tmp )
{
res = fopen ( tmp , mode ) ;
}
return res ;
}
FILE * wfreopen ( const wchar_t * path , const char * mode , FILE * stream )
{
char * tmp = wutil_wcs2str ( path ) ;
FILE * res = 0 ;
if ( tmp )
{
res = freopen ( tmp , mode , stream ) ;
}
return res ;
}
int wopen ( const wchar_t * pathname , int flags , . . . )
{
char * tmp = wutil_wcs2str ( pathname ) ;
int res = - 1 ;
va_list argp ;
if ( tmp )
{
if ( ! ( flags & O_CREAT ) )
2005-10-28 01:21:48 +10:00
{
2005-09-20 23:26:39 +10:00
res = open ( tmp , flags ) ;
2005-10-28 01:21:48 +10:00
}
2005-09-20 23:26:39 +10:00
else
2005-10-28 01:21:48 +10:00
{
va_start ( argp , flags ) ;
2005-09-20 23:26:39 +10:00
res = open ( tmp , flags , va_arg ( argp , int ) ) ;
2005-10-28 01:21:48 +10:00
va_end ( argp ) ;
}
2005-09-20 23:26:39 +10:00
}
return res ;
}
int wcreat ( const wchar_t * pathname , mode_t mode )
{
char * tmp = wutil_wcs2str ( pathname ) ;
int res = - 1 ;
if ( tmp )
{
res = creat ( tmp , mode ) ;
}
return res ;
}
DIR * wopendir ( const wchar_t * name )
{
char * tmp = wutil_wcs2str ( name ) ;
DIR * res = 0 ;
if ( tmp )
{
res = opendir ( tmp ) ;
}
return res ;
}
int wstat ( const wchar_t * file_name , struct stat * buf )
{
char * tmp = wutil_wcs2str ( file_name ) ;
int res = - 1 ;
if ( tmp )
{
res = stat ( tmp , buf ) ;
}
return res ;
}
int lwstat ( const wchar_t * file_name , struct stat * buf )
{
char * tmp = wutil_wcs2str ( file_name ) ;
int res = - 1 ;
if ( tmp )
{
res = lstat ( tmp , buf ) ;
}
return res ;
}
int waccess ( const wchar_t * file_name , int mode )
{
char * tmp = wutil_wcs2str ( file_name ) ;
int res = - 1 ;
if ( tmp )
{
res = access ( tmp , mode ) ;
}
return res ;
}
void wperror ( const wchar_t * s )
{
2006-06-21 19:54:30 +10:00
int e = errno ;
2005-09-20 23:26:39 +10:00
if ( s ! = 0 )
{
fwprintf ( stderr , L " %ls: " , s ) ;
}
2006-06-21 19:54:30 +10:00
fwprintf ( stderr , L " %s \n " , strerror ( e ) ) ;
2005-09-20 23:26:39 +10:00
}
2006-02-03 01:23:56 +10:00
# ifdef HAVE_REALPATH_NULL
wchar_t * wrealpath ( const wchar_t * pathname , wchar_t * resolved_path )
{
char * tmp = wutil_wcs2str ( pathname ) ;
char * narrow_res = realpath ( tmp , 0 ) ;
wchar_t * res ;
if ( ! narrow_res )
return 0 ;
if ( resolved_path )
{
wchar_t * tmp2 = str2wcs ( narrow_res ) ;
wcslcpy ( resolved_path , tmp2 , PATH_MAX ) ;
free ( tmp2 ) ;
res = resolved_path ;
}
else
{
res = str2wcs ( narrow_res ) ;
}
free ( narrow_res ) ;
return res ;
}
# else
wchar_t * wrealpath ( const wchar_t * pathname , wchar_t * resolved_path )
{
2006-07-21 11:08:31 +10:00
char * tmp = wutil_wcs2str ( pathname ) ;
char narrow_buff [ PATH_MAX ] ;
char * narrow_res = realpath ( tmp , narrow_buff ) ;
2006-02-03 01:23:56 +10:00
wchar_t * res ;
if ( ! narrow_res )
return 0 ;
if ( resolved_path )
{
wchar_t * tmp2 = str2wcs ( narrow_res ) ;
wcslcpy ( resolved_path , tmp2 , PATH_MAX ) ;
free ( tmp2 ) ;
res = resolved_path ;
}
else
{
res = str2wcs ( narrow_res ) ;
}
return res ;
}
# endif
2006-06-14 23:22:40 +10:00
2006-09-09 00:10:41 +10:00
wchar_t * wdirname ( wchar_t * path )
2006-06-14 23:22:40 +10:00
{
static string_buffer_t * sb = 0 ;
if ( sb )
sb_clear ( sb ) ;
else
sb = sb_halloc ( global_context ) ;
char * tmp = wutil_wcs2str ( path ) ;
char * narrow_res = dirname ( tmp ) ;
if ( ! narrow_res )
return 0 ;
sb_printf ( sb , L " %s " , narrow_res ) ;
2006-09-09 00:10:41 +10:00
wcscpy ( path , ( wchar_t * ) sb - > buff ) ;
return path ;
2006-06-14 23:22:40 +10:00
}
wchar_t * wbasename ( const wchar_t * path )
{
static string_buffer_t * sb = 0 ;
if ( sb )
sb_clear ( sb ) ;
else
sb = sb_halloc ( global_context ) ;
char * tmp = wutil_wcs2str ( path ) ;
char * narrow_res = basename ( tmp ) ;
if ( ! narrow_res )
return 0 ;
sb_printf ( sb , L " %s " , narrow_res ) ;
return ( wchar_t * ) sb - > buff ;
}
2006-07-20 08:55:49 +10:00
/**
For wgettext : Internal shutdown function . Automatically called on shutdown if the library has been initialized .
*/
static void wgettext_destroy ( )
{
int i ;
if ( ! wgettext_is_init )
return ;
wgettext_is_init = 0 ;
for ( i = 0 ; i < BUFF_COUNT ; i + + )
sb_destroy ( & buff [ i ] ) ;
free ( wcs2str_buff ) ;
}
/**
For wgettext : Internal init function . Automatically called when a translation is first requested .
*/
static void wgettext_init ( )
{
int i ;
wgettext_is_init = 1 ;
2006-07-21 11:08:31 +10:00
for ( i = 0 ; i < BUFF_COUNT ; i + + )
2006-07-20 08:55:49 +10:00
{
sb_init ( & buff [ i ] ) ;
}
halloc_register_function_void ( global_context , & wgettext_destroy ) ;
bindtextdomain ( PACKAGE_NAME , LOCALEDIR ) ;
textdomain ( PACKAGE_NAME ) ;
}
/**
For wgettext : Wide to narrow character conversion . Internal implementation that
avoids exessive calls to malloc
*/
static char * wgettext_wcs2str ( const wchar_t * in )
{
size_t len = MAX_UTF8_BYTES * wcslen ( in ) + 1 ;
if ( len > wcs2str_buff_count )
{
wcs2str_buff = realloc ( wcs2str_buff , len ) ;
if ( ! wcs2str_buff )
{
DIE_MEM ( ) ;
}
}
return wcs2str_internal ( in , wcs2str_buff ) ;
}
const wchar_t * wgettext ( const wchar_t * in )
{
if ( ! in )
return in ;
if ( ! wgettext_is_init )
wgettext_init ( ) ;
char * mbs_in = wgettext_wcs2str ( in ) ;
char * out = gettext ( mbs_in ) ;
wchar_t * wres = 0 ;
sb_clear ( & buff [ curr_buff ] ) ;
sb_printf ( & buff [ curr_buff ] , L " %s " , out ) ;
wres = ( wchar_t * ) buff [ curr_buff ] . buff ;
curr_buff = ( curr_buff + 1 ) % BUFF_COUNT ;
return wres ;
}
2006-08-12 00:55:28 +10:00
wchar_t * wgetenv ( const wchar_t * name )
{
char * name_narrow = wutil_wcs2str ( name ) ;
char * res_narrow = getenv ( name_narrow ) ;
static string_buffer_t * out = 0 ;
if ( ! res_narrow )
return 0 ;
if ( ! out )
{
out = sb_halloc ( global_context ) ;
}
else
{
sb_clear ( out ) ;
}
sb_printf ( out , L " %s " , res_narrow ) ;
return ( wchar_t * ) out - > buff ;
}