aboutsummaryrefslogtreecommitdiffhomepage
path: root/wutil.c
diff options
context:
space:
mode:
authorGravatar axel <axel@liljencrantz.se>2005-09-20 23:26:39 +1000
committerGravatar axel <axel@liljencrantz.se>2005-09-20 23:26:39 +1000
commit149594f974350bb364a76c73b91b1d5ffddaa1fa (patch)
tree95650e9982d5fabe4bd805d94c5d700cbbc1ca7f /wutil.c
Initial revision
darcs-hash:20050920132639-ac50b-fa3b476891e1f5f67207cf4cc7bf623834cc5edc.gz
Diffstat (limited to 'wutil.c')
-rw-r--r--wutil.c546
1 files changed, 546 insertions, 0 deletions
diff --git a/wutil.c b/wutil.c
new file mode 100644
index 00000000..6a1a4122
--- /dev/null
+++ b/wutil.c
@@ -0,0 +1,546 @@
+/** \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>
+#include <string.h>
+#include <dirent.h>
+#include <stdarg.h>
+#include <limits.h>
+
+#include "util.h"
+#include "common.h"
+#include "wutil.h"
+
+static char *tmp=0;
+static size_t tmp_len=0;
+
+int c = 0;
+
+void wutil_destroy()
+{
+ free( tmp );
+ tmp=0;
+ tmp_len=0;
+ debug( 3, L"wutil functions called %d times", c );
+}
+
+static char *wutil_wcs2str( const wchar_t *in )
+{
+ c++;
+
+ size_t new_sz =MAX_UTF8_BYTES*wcslen(in)+1;
+ if( tmp_len < new_sz )
+ {
+ free( tmp );
+ tmp = malloc( new_sz );
+ 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 )
+ {
+ va_start( argp, flags );
+
+ if( ! (flags & O_CREAT) )
+ res = open(tmp, flags);
+ else
+ 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)
+{
+ if( s != 0 )
+ {
+ fwprintf( stderr, L"%ls: ", s );
+ }
+ fwprintf( stderr, L"%s\n", strerror( errno ) );
+}
+
+
+#if !HAVE_WPRINTF
+/*
+ Here is my own implementation of *wprintf, included since NetBSD does
+ not provide one of it's own.
+*/
+
+/**
+ This function is defined to help vgwprintf when it wants to call
+ itself recursively
+*/
+static int gwprintf( void (*writer)(wchar_t),
+ const wchar_t *filter,
+ ... );
+
+
+/**
+ Generic formatting function. All other formatting functions are
+ secretly a wrapper around this function.
+*/
+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 i;
+ int is_long=0;
+ int width = 0;
+ filter++;
+ int loop=1;
+ int precision=INT_MAX;
+
+ while( loop )
+ {
+ switch(*filter)
+ {
+ case L'l':
+ /* Long variable */
+ is_long++;
+ filter++;
+ break;
+ case L'*':
+ /* Set minimum field width */
+ width = va_arg( va, int );
+ filter++;
+ break;
+ case L'.':
+ /*
+ Set precision.
+ Hasn't been tested enough yet, so I don't really trust it.
+ */
+ filter++;
+ if( *filter == L'*' )
+ {
+ precision = va_arg( va, int );
+ }
+ else
+ {
+ while( (*filter >= L'0') && (*filter <= L'9'))
+ {
+ precision=10*precision+(*filter - L'0');
+ }
+ }
+ break;
+
+ default:
+ loop=0;
+ break;
+ }
+ }
+ switch( *filter )
+ {
+ case L'c':
+ {
+ wchar_t c;
+
+ c = is_long?va_arg(va, wchar_t):btowc(va_arg(va, int));
+ if( width )
+ {
+ int i;
+ for( i=1; i<width; i++ )
+ {
+ writer( L' ' );
+ count++;
+ }
+ }
+ if( precision != 0 )
+ writer( c );
+ count++;
+
+ break;
+ }
+ case L's':
+ {
+ wchar_t *ss = is_long?va_arg(va, wchar_t*):str2wcs(va_arg(va, char*));
+
+ if( !ss )
+ return -1;
+
+ if( width )
+ {
+ int i;
+ for( i=wcslen(ss); i<width; i++ )
+ {
+ writer( L' ' );
+ count++;
+ }
+ }
+
+ wchar_t *s=ss;
+ int precount = count;
+
+ while( *s )
+ {
+ if( (precision <= (count-precount) ) )
+ break;
+
+ writer( *(s++) );
+ count++;
+ }
+
+ if( !is_long )
+ free( ss );
+
+ break;
+ }
+
+ case L'd':
+ case L'i':
+ {
+ char str[32];
+
+ switch( is_long )
+ {
+ case 0:
+ {
+ int d = va_arg( va, int );
+ snprintf( str, 32, "%.*d", precision, d );
+ break;
+ }
+
+ case 1:
+ {
+ long d = va_arg( va, long );
+ snprintf( str, 32, "%.*ld", precision, d );
+ break;
+ }
+
+ case 2:
+ {
+ long long d = va_arg( va, long long );
+ snprintf( str, 32, "%.*lld", precision, d );
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ if( width )
+ {
+ int i;
+ for( i=strlen(str); i<width; i++ )
+ {
+ writer( L' ' );
+ count++;
+ }
+ }
+
+ int c = gwprintf( writer, L"%s", str );
+ if( c==-1 )
+ return -1;
+ else
+ count += c;
+
+ break;
+ }
+
+ case L'u':
+ {
+ char str[32];
+
+
+ switch( is_long )
+ {
+ case 0:
+ {
+ unsigned d = va_arg( va, unsigned );
+ snprintf( str, 32, "%d", d );
+ break;
+ }
+
+ case 1:
+ {
+ unsigned long d = va_arg( va, unsigned long );
+ snprintf( str, 32, "%ld", d );
+ break;
+ }
+
+ case 2:
+ {
+ unsigned long long d = va_arg( va, unsigned long long );
+ snprintf( str, 32, "%lld", d );
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ if( width )
+ {
+ int i;
+ for( i=strlen(str); i<width; i++ )
+ {
+ writer( L' ' );
+ count++;
+ }
+ }
+
+ int c = gwprintf( writer, L"%s", str );
+ if( c==-1 )
+ return -1;
+ else
+ count += c;
+
+ break;
+ }
+
+ case L'n':
+ {
+ int *n = va_arg( va, int *);
+
+ *n = count;
+ break;
+ }
+ default:
+ debug( 0, L"Unknown switch %lc in string %ls\n", *filter, filter_org );
+ exit(1);
+ }
+ }
+ else
+ {
+ writer( *filter );
+ count++;
+ }
+ }
+
+ return count;
+}
+
+static int gwprintf( void (*writer)(wchar_t),
+ const wchar_t *filter,
+ ... )
+{
+ va_list va;
+ va_start( va, filter );
+ int written=vgwprintf( writer,
+ filter,
+ va );
+ va_end( va );
+ return written;
+}
+
+/**
+ Holds data for swprintf writer
+*/
+static struct
+{
+ int count;
+ int max;
+ wchar_t *pos;
+}
+sw_data;
+
+/**
+ Writer for swprintf
+*/
+static void sw_writer( wchar_t c )
+{
+ if( sw_data.count < sw_data.max )
+ *(sw_data.pos++)=c;
+ sw_data.count++;
+}
+
+
+int swprintf( wchar_t *out, size_t n, const wchar_t *filter, ... )
+{
+ va_list va;
+ va_start( va, filter );
+ sw_data.pos=out;
+ sw_data.max=n;
+ sw_data.count=0;
+ int written=vgwprintf( &sw_writer,
+ filter,
+ va );
+ if( written < n )
+ {
+ *sw_data.pos = 0;
+ }
+ else
+ {
+ written=-1;
+ }
+
+ va_end( va );
+ return written;
+}
+
+/**
+ Holds auxiliary data for fwprintf and wprintf writer
+*/
+static FILE *fw_data;
+
+static void fw_writer( wchar_t c )
+{
+ putw( c, fw_data );
+}
+
+/**
+ Writer for fwprintf and wprintf
+*/
+int fwprintf( FILE *f, const wchar_t *filter, ... )
+{
+ va_list va;
+ va_start( va, filter );
+ fw_data = f;
+
+ int written=vgwprintf( &fw_writer, filter, va );
+ va_end( va );
+ return written;
+}
+
+int wprintf( const wchar_t *filter, ... )
+{
+ va_list va;
+ va_start( va, filter );
+ fw_data = stdout;
+
+ int written=vgwprintf( &fw_writer, filter, va );
+ va_end( va );
+ return written;
+}
+
+#endif
+