/** \file wutil.c Wide character equivalents of various standard unix functions. */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if HAVE_LIBINTL_H #include #endif #include "fallback.h" #include "util.h" #include "common.h" #include "wutil.h" #include "halloc.h" #include "halloc_util.h" /** Minimum length of the internal covnersion buffers */ #define TMP_LEN_MIN 256 #ifndef PATH_MAX #ifdef MAXPATHLEN #define PATH_MAX MAXPATHLEN #else /** Fallback length of MAXPATHLEN. Just a hopefully sane value... */ #define PATH_MAX 4096 #endif #endif /** Buffer for converting wide arguments to narrow arguments, used by the \c wutil_wcs2str() function. */ static char *tmp=0; /** Buffer for converting narrow results to wide ones, used by the \c wutil_str2wcs() function. Avoid usign this without thinking about it, since sebseuent calls will overwrite previous values. */ static wchar_t *tmp2; /** Length of the \c tmp buffer. */ static size_t tmp_len=0; /** Length of the \c tmp2 buffer */ static size_t tmp2_len; /** Counts the number of calls to the wutil wrapper functions */ static int wutil_calls = 0; /** Storage for the wreaddir function */ static struct wdirent my_wdirent; /** 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; void wutil_init() { } void wutil_destroy() { free( tmp ); free( tmp2 ); tmp=0; tmp_len=0; debug( 3, L"wutil functions called %d times", wutil_calls ); } /** 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. */ static char *wutil_wcs2str( const wchar_t *in ) { size_t new_sz; wutil_calls++; new_sz =MAX_UTF8_BYTES*wcslen(in)+1; if( tmp_len < new_sz ) { new_sz = maxi( new_sz, TMP_LEN_MIN ); tmp = realloc( tmp, new_sz ); if( !tmp ) { DIE_MEM(); } tmp_len = new_sz; } 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++; new_sz = sizeof(wchar_t)*(strlen(in)+1); if( tmp2_len < new_sz ) { new_sz = maxi( new_sz, TMP_LEN_MIN ); tmp2 = realloc( tmp2, new_sz ); if( !tmp2 ) { DIE_MEM(); } tmp2_len = new_sz; } 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; } wchar_t *wgetcwd( wchar_t *buff, size_t sz ) { char *buffc = malloc( sz*MAX_UTF8_BYTES); char *res; wchar_t *ret = 0; if( !buffc ) { errno = ENOMEM; return 0; } res = getcwd( buffc, sz*MAX_UTF8_BYTES ); if( res ) { if( (size_t)-1 != mbstowcs( buff, buffc, sizeof( wchar_t ) * sz ) ) { ret = buff; } } free( buffc ); return ret; } 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) ) { res = open(tmp, flags); } else { va_start( argp, flags ); res = open(tmp, flags, va_arg(argp, int) ); va_end( argp ); } } 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) { int e = errno; if( s != 0 ) { fwprintf( stderr, L"%ls: ", s ); } fwprintf( stderr, L"%s\n", strerror( e ) ); } #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) { char *tmp = wutil_wcs2str(pathname); char narrow_buff[PATH_MAX]; char *narrow_res = realpath( tmp, narrow_buff ); 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 wchar_t *wdirname( 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 = dirname( tmp ); if( !narrow_res ) return 0; sb_printf( sb, L"%s", narrow_res ); return (wchar_t *)sb->buff; } 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; } /** 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 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; }