2005-09-20 23:26:39 +10:00
/** \file wutil.c
Wide character equivalents of various standard unix functions .
*/
# include "config.h"
# include <stdlib.h>
# include <stdio.h>
# include <unistd.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <unistd.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>
# include "util.h"
# include "common.h"
# include "wutil.h"
2005-11-03 01:41:59 +10:00
# define TMP_LEN_MIN 256
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 ;
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 ;
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
2005-11-03 01:41:59 +10:00
void wutil_init ( )
{
}
2005-09-20 23:26:39 +10:00
void wutil_destroy ( )
{
free ( tmp ) ;
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 )
{
2005-10-28 01:21:48 +10:00
wutil_calls + + ;
2005-09-20 23:26:39 +10:00
size_t new_sz = MAX_UTF8_BYTES * wcslen ( in ) + 1 ;
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 )
{
die_mem ( ) ;
}
tmp_len = new_sz ;
}
wcstombs ( tmp , in , tmp_len ) ;
return tmp ;
}
wchar_t * wgetcwd ( wchar_t * buff , size_t sz )
{
char buffc [ sz * MAX_UTF8_BYTES ] ;
char * res = getcwd ( buffc , sz * MAX_UTF8_BYTES ) ;
if ( ! res )
return 0 ;
if ( ( size_t ) - 1 = = mbstowcs ( buff , buffc , sizeof ( wchar_t ) * sz ) )
{
return 0 ;
}
return buff ;
}
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 )
{
if ( s ! = 0 )
{
fwprintf ( stderr , L " %ls: " , s ) ;
}
fwprintf ( stderr , L " %s \n " , strerror ( errno ) ) ;
}
# if !HAVE_WPRINTF
2005-10-15 08:33:01 +10:00
void pad ( void ( * writer ) ( wchar_t ) , int count )
{
int i ;
if ( count < 0 )
return ;
for ( i = 0 ; i < count ; i + + )
{
writer ( L ' ' ) ;
}
}
2005-09-20 23:26:39 +10:00
/**
2005-10-14 21:40:33 +10:00
Generic formatting function . All other string formatting functions
are secretly a wrapper around this function . vgprintf does not
implement all the filters supported by printf , only those that are
currently used by fish . vgprintf internally uses snprintf to
implement the % f % d and % u filters .
Currently supported functionality :
- precision specification , both through . * and . N
2005-10-15 08:33:01 +10:00
- width specification through * and N
2005-10-14 21:40:33 +10:00
- long versions of all filters thorugh l and ll prefix
- Character outout using % c
- String output through % s
- Floating point number output through % f
- Integer output through % d or % i
- Unsigned integer output through % u
2005-10-15 08:33:01 +10:00
- Left padding using the - prefix
2005-10-14 21:40:33 +10:00
For a full description on the usage of * printf , see use ' man 3 printf ' .
2005-09-20 23:26:39 +10:00
*/
static int vgwprintf ( void ( * writer ) ( wchar_t ) ,
const wchar_t * filter ,
va_list va )
{
const wchar_t * filter_org = filter ;
int count = 0 ;
for ( ; * filter ; filter + + )
{
if ( * filter = = L ' % ' )
{
int is_long = 0 ;
2005-10-12 17:06:08 +10:00
int width = - 1 ;
2005-09-20 23:26:39 +10:00
filter + + ;
int loop = 1 ;
2005-10-06 20:30:52 +10:00
int precision = - 1 ;
2005-10-15 08:33:01 +10:00
int pad_left = 1 ;
if ( iswdigit ( * filter ) )
{
width = 0 ;
while ( ( * filter > = L ' 0 ' ) & & ( * filter < = L ' 9 ' ) )
{
width = 10 * width + ( * filter + + - L ' 0 ' ) ;
}
}
2005-10-06 20:30:52 +10:00
2005-09-20 23:26:39 +10:00
while ( loop )
{
2005-10-15 08:33:01 +10:00
2005-09-20 23:26:39 +10:00
switch ( * filter )
{
case L ' l ' :
/* Long variable */
is_long + + ;
filter + + ;
break ;
2005-10-15 08:33:01 +10:00
2005-09-20 23:26:39 +10:00
case L ' * ' :
/* Set minimum field width */
width = va_arg ( va , int ) ;
filter + + ;
break ;
2005-10-15 08:33:01 +10:00
case L ' - ' :
filter + + ;
pad_left = 0 ;
break ;
2005-09-20 23:26:39 +10:00
case L ' . ' :
/*
Set precision .
*/
filter + + ;
if ( * filter = = L ' * ' )
{
precision = va_arg ( va , int ) ;
}
else
{
2005-10-12 17:06:08 +10:00
precision = 0 ;
2005-09-20 23:26:39 +10:00
while ( ( * filter > = L ' 0 ' ) & & ( * filter < = L ' 9 ' ) )
{
2005-10-12 17:06:08 +10:00
precision = 10 * precision + ( * filter + + - L ' 0 ' ) ;
2005-09-20 23:26:39 +10:00
}
}
break ;
default :
loop = 0 ;
break ;
}
}
2005-10-15 08:33:01 +10:00
2005-09-20 23:26:39 +10:00
switch ( * filter )
{
case L ' c ' :
{
wchar_t c ;
2005-10-15 08:33:01 +10:00
if ( ( width > = 0 ) & & pad_left )
2005-09-20 23:26:39 +10:00
{
2005-10-15 08:33:01 +10:00
pad ( writer , width - 1 ) ;
count + = maxi ( width - 1 , 0 ) ;
2005-09-20 23:26:39 +10:00
}
2005-10-15 08:33:01 +10:00
c = is_long ? va_arg ( va , wchar_t ) : btowc ( va_arg ( va , int ) ) ;
2005-09-20 23:26:39 +10:00
if ( precision ! = 0 )
writer ( c ) ;
2005-10-15 08:33:01 +10:00
if ( ( width > = 0 ) & & ! pad_left )
{
pad ( writer , width - 1 ) ;
count + = maxi ( width - 1 , 0 ) ;
}
2005-09-20 23:26:39 +10:00
count + + ;
break ;
}
case L ' s ' :
2005-10-06 20:30:52 +10:00
{
2005-10-15 08:33:01 +10:00
2005-10-06 20:30:52 +10:00
wchar_t * ss = 0 ;
if ( is_long )
{
2005-10-12 20:39:52 +10:00
ss = va_arg ( va , wchar_t * ) ;
2005-10-06 20:30:52 +10:00
}
else
{
char * ns = va_arg ( va , char * ) ;
if ( ns )
{
ss = str2wcs ( ns ) ;
}
}
2005-09-20 23:26:39 +10:00
if ( ! ss )
2005-10-06 20:30:52 +10:00
{
2005-09-20 23:26:39 +10:00
return - 1 ;
2005-10-06 20:30:52 +10:00
}
2005-09-20 23:26:39 +10:00
2005-10-15 08:33:01 +10:00
if ( ( width > = 0 ) & & pad_left )
2005-09-20 23:26:39 +10:00
{
2005-10-15 08:33:01 +10:00
pad ( writer , width - wcslen ( ss ) ) ;
count + = maxi ( width - wcslen ( ss ) , 0 ) ;
2005-09-20 23:26:39 +10:00
}
2005-10-06 20:30:52 +10:00
2005-09-20 23:26:39 +10:00
wchar_t * s = ss ;
int precount = count ;
while ( * s )
{
2005-10-06 20:30:52 +10:00
if ( ( precision > 0 ) & & ( precision < = ( count - precount ) ) )
2005-09-20 23:26:39 +10:00
break ;
2005-10-15 08:33:01 +10:00
2005-09-20 23:26:39 +10:00
writer ( * ( s + + ) ) ;
count + + ;
}
2005-10-15 08:33:01 +10:00
if ( ( width > = 0 ) & & ! pad_left )
{
pad ( writer , width - wcslen ( ss ) ) ;
count + = maxi ( width - wcslen ( ss ) , 0 ) ;
}
2005-09-20 23:26:39 +10:00
if ( ! is_long )
free ( ss ) ;
break ;
}
case L ' d ' :
case L ' i ' :
{
char str [ 32 ] ;
2005-10-06 20:30:52 +10:00
char * pos ;
2005-09-20 23:26:39 +10:00
switch ( is_long )
{
case 0 :
{
int d = va_arg ( va , int ) ;
2005-10-12 17:06:08 +10:00
if ( precision > = 0 )
2005-10-06 20:30:52 +10:00
snprintf ( str , 32 , " %.*d " , precision , d ) ;
else
snprintf ( str , 32 , " %d " , d ) ;
2005-09-20 23:26:39 +10:00
break ;
}
case 1 :
{
long d = va_arg ( va , long ) ;
2005-10-12 17:06:08 +10:00
if ( precision > = 0 )
2005-10-06 20:30:52 +10:00
snprintf ( str , 32 , " %.*ld " , precision , d ) ;
else
snprintf ( str , 32 , " %ld " , d ) ;
2005-09-20 23:26:39 +10:00
break ;
}
case 2 :
{
long long d = va_arg ( va , long long ) ;
2005-10-12 17:06:08 +10:00
if ( precision > = 0 )
2005-10-06 20:30:52 +10:00
snprintf ( str , 32 , " %.*lld " , precision , d ) ;
else
snprintf ( str , 32 , " %lld " , d ) ;
2005-09-20 23:26:39 +10:00
break ;
}
default :
return - 1 ;
}
2005-10-15 08:33:01 +10:00
if ( ( width > = 0 ) & & pad_left )
2005-09-20 23:26:39 +10:00
{
2005-10-15 08:33:01 +10:00
pad ( writer , width - strlen ( str ) ) ;
count + = maxi ( width - strlen ( str ) , 0 ) ;
2005-09-20 23:26:39 +10:00
}
2005-10-15 08:33:01 +10:00
2005-10-06 20:30:52 +10:00
pos = str ;
2005-09-20 23:26:39 +10:00
2005-10-06 20:30:52 +10:00
while ( * pos )
{
writer ( * ( pos + + ) ) ;
count + + ;
}
2005-10-15 08:33:01 +10:00
if ( ( width > = 0 ) & & ! pad_left )
{
pad ( writer , width - strlen ( str ) ) ;
count + = maxi ( width - strlen ( str ) , 0 ) ;
}
2005-09-20 23:26:39 +10:00
break ;
}
2005-10-06 20:30:52 +10:00
2005-09-20 23:26:39 +10:00
case L ' u ' :
{
char str [ 32 ] ;
2005-10-12 17:06:08 +10:00
char * pos ;
2005-09-20 23:26:39 +10:00
switch ( is_long )
{
case 0 :
{
unsigned d = va_arg ( va , unsigned ) ;
2005-10-14 00:08:33 +10:00
if ( precision > = 0 )
snprintf ( str , 32 , " %.*u " , precision , d ) ;
else
snprintf ( str , 32 , " %u " , d ) ;
2005-09-20 23:26:39 +10:00
break ;
}
case 1 :
{
unsigned long d = va_arg ( va , unsigned long ) ;
2005-10-14 00:08:33 +10:00
if ( precision > = 0 )
snprintf ( str , 32 , " %.*lu " , precision , d ) ;
else
snprintf ( str , 32 , " %lu " , d ) ;
2005-09-20 23:26:39 +10:00
break ;
}
case 2 :
{
unsigned long long d = va_arg ( va , unsigned long long ) ;
2005-10-14 00:08:33 +10:00
if ( precision > = 0 )
snprintf ( str , 32 , " %.*llu " , precision , d ) ;
else
snprintf ( str , 32 , " %llu " , d ) ;
2005-09-20 23:26:39 +10:00
break ;
}
default :
return - 1 ;
}
2005-10-15 08:33:01 +10:00
if ( ( width > = 0 ) & & pad_left )
2005-09-20 23:26:39 +10:00
{
2005-10-15 08:33:01 +10:00
pad ( writer , width - strlen ( str ) ) ;
count + = maxi ( width - strlen ( str ) , 0 ) ;
2005-09-20 23:26:39 +10:00
}
2005-10-15 08:33:01 +10:00
2005-10-12 17:06:08 +10:00
pos = str ;
while ( * pos )
{
writer ( * ( pos + + ) ) ;
count + + ;
}
2005-10-15 08:33:01 +10:00
if ( ( width > = 0 ) & & ! pad_left )
{
pad ( writer , width - strlen ( str ) ) ;
count + = maxi ( width - strlen ( str ) , 0 ) ;
}
2005-10-12 17:06:08 +10:00
break ;
}
case L ' f ' :
{
char str [ 32 ] ;
char * pos ;
double val = va_arg ( va , double ) ;
if ( precision > = 0 )
{
if ( width > = 0 )
{
snprintf ( str , 32 , " %*.*f " , width , precision , val ) ;
}
else
{
snprintf ( str , 32 , " %.*f " , precision , val ) ;
}
}
2005-09-20 23:26:39 +10:00
else
2005-10-12 17:06:08 +10:00
{
if ( width > = 0 )
{
snprintf ( str , 32 , " %*f " , width , val ) ;
}
else
{
snprintf ( str , 32 , " %f " , val ) ;
}
}
pos = str ;
while ( * pos )
{
writer ( * ( pos + + ) ) ;
count + + ;
}
2005-09-20 23:26:39 +10:00
break ;
}
case L ' n ' :
{
int * n = va_arg ( va , int * ) ;
* n = count ;
break ;
}
2006-01-17 01:04:24 +10:00
case L ' % ' :
{
writer ( ' % ' ) ;
count + + ;
break ;
}
2005-09-20 23:26:39 +10:00
default :
debug ( 0 , L " Unknown switch %lc in string %ls \n " , * filter , filter_org ) ;
2005-10-06 20:30:52 +10:00
// exit(1);
2005-09-20 23:26:39 +10:00
}
}
else
{
writer ( * filter ) ;
count + + ;
}
}
return count ;
}
/**
Holds data for swprintf writer
*/
static struct
{
int count ;
int max ;
wchar_t * pos ;
}
sw_data ;
/**
2005-10-06 20:30:52 +10:00
Writers for string output
2005-09-20 23:26:39 +10:00
*/
static void sw_writer ( wchar_t c )
{
if ( sw_data . count < sw_data . max )
* ( sw_data . pos + + ) = c ;
sw_data . count + + ;
}
2005-10-06 20:30:52 +10:00
int vswprintf ( wchar_t * out , size_t n , const wchar_t * filter , va_list va )
2005-09-20 23:26:39 +10:00
{
2005-10-06 20:30:52 +10:00
int written ;
2005-09-20 23:26:39 +10:00
sw_data . pos = out ;
sw_data . max = n ;
sw_data . count = 0 ;
2005-10-06 20:30:52 +10:00
written = vgwprintf ( & sw_writer ,
filter ,
va ) ;
2005-09-20 23:26:39 +10:00
if ( written < n )
{
* sw_data . pos = 0 ;
}
else
{
written = - 1 ;
}
2005-10-06 20:30:52 +10:00
return written ;
}
int swprintf ( wchar_t * out , size_t n , const wchar_t * filter , . . . )
{
va_list va ;
int written ;
va_start ( va , filter ) ;
written = vswprintf ( out , n , filter , va ) ;
2005-09-20 23:26:39 +10:00
va_end ( va ) ;
return written ;
}
/**
Holds auxiliary data for fwprintf and wprintf writer
*/
static FILE * fw_data ;
static void fw_writer ( wchar_t c )
{
2005-10-12 20:39:52 +10:00
putwc ( c , fw_data ) ;
2005-09-20 23:26:39 +10:00
}
2005-10-06 20:30:52 +10:00
/*
Writers for file output
2005-09-20 23:26:39 +10:00
*/
2005-10-06 20:30:52 +10:00
int vfwprintf ( FILE * f , const wchar_t * filter , va_list va )
{
fw_data = f ;
return vgwprintf ( & fw_writer , filter , va ) ;
}
2005-09-20 23:26:39 +10:00
int fwprintf ( FILE * f , const wchar_t * filter , . . . )
{
va_list va ;
2005-10-06 20:30:52 +10:00
int written ;
2005-09-20 23:26:39 +10:00
2005-10-06 20:30:52 +10:00
va_start ( va , filter ) ;
written = vfwprintf ( f , filter , va ) ;
2005-09-20 23:26:39 +10:00
va_end ( va ) ;
return written ;
}
2005-10-06 20:30:52 +10:00
int vwprintf ( const wchar_t * filter , va_list va )
{
2005-10-12 20:39:52 +10:00
return vfwprintf ( stdout , filter , va ) ;
2005-10-06 20:30:52 +10:00
}
2005-09-20 23:26:39 +10:00
int wprintf ( const wchar_t * filter , . . . )
{
va_list va ;
2005-10-06 20:30:52 +10:00
int written ;
2005-09-20 23:26:39 +10:00
2005-10-06 20:30:52 +10:00
va_start ( va , filter ) ;
written = vwprintf ( filter , va ) ;
2005-09-20 23:26:39 +10:00
va_end ( va ) ;
return written ;
}
# endif