fgets and utf8 functions for Windows (#87)

This commit is contained in:
Manoj Ampalam 2017-03-06 16:18:40 -08:00 committed by GitHub
parent 0ed1ef55f7
commit 70da1e67ea
10 changed files with 134 additions and 119 deletions

View File

@ -283,7 +283,6 @@
<ClCompile Include="$(OpenSSH-Src-Path)platform-tracing.c" />
<ClCompile Include="$(OpenSSH-Src-Path)platform.c" />
<ClCompile Include="$(OpenSSH-Src-Path)sandbox-pledge.c" />
<ClCompile Include="$(OpenSSH-Src-Path)utf8.c" />
<ClCompile Include="$(OpenSSH-Src-Path)contrib\win32\win32compat\ttymodes_windows.c" />
<ClCompile Include="$(OpenSSH-Src-Path)digest-openssl.c">
<ExcludedFromBuild Condition="$(UseOpenSSL)==false">true</ExcludedFromBuild>

View File

@ -282,9 +282,6 @@
<ClCompile Include="$(OpenSSH-Src-Path)sandbox-pledge.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(OpenSSH-Src-Path)utf8.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(OpenSSH-Src-Path)contrib\win32\win32compat\ttymodes_windows.c">
<Filter>Source Files</Filter>
</ClCompile>

View File

@ -160,6 +160,7 @@
<ClCompile Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\tncon.c" />
<ClCompile Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\tnnet.c" />
<ClCompile Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\utf.c" />
<ClCompile Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\win32-utf8.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\w32fd.h" />

View File

@ -19,6 +19,7 @@
<ClCompile Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\tncon.c" />
<ClCompile Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\tnnet.c" />
<ClCompile Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\utf.c" />
<ClCompile Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\win32-utf8.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\w32fd.h" />

View File

@ -5,6 +5,12 @@
FILE* w32_fopen_utf8(const char *, const char *);
#define fopen w32_fopen_utf8
char* w32_fgets(char *str, int n, FILE *stream);
#define fgets w32_fgets
int w32_setvbuf(FILE *stream,char *buffer, int mode, size_t size);
#define setvbuf w32_setvbuf
/* stdio.h additional definitions */
#define popen _popen
#define pclose _pclose
@ -14,4 +20,3 @@ FILE* w32_fdopen(int fd, const char *mode);
int w32_rename(const char *old_name, const char *new_name);
#define rename w32_rename

View File

@ -276,6 +276,75 @@ w32_fopen_utf8(const char *path, const char *mode)
return f;
}
/* fgets to support Unicode input */
char*
w32_fgets(char *str, int n, FILE *stream) {
HANDLE h = (HANDLE)_get_osfhandle(_fileno(stream));
wchar_t* str_w = NULL;
char *ret = NULL, *str_tmp = NULL;
if (h != NULL && h != INVALID_HANDLE_VALUE
&& GetFileType(h) == FILE_TYPE_CHAR) {
/*
* read only n/4 wide chars from console
* each UTF-16 char may bloat upto 4 utf-8 chars when converted to utf-8
* so we can fit in str[n] provided as input
*/
if ((str_w = malloc((n/4) * sizeof(wchar_t))) == NULL) {
errno = ENOMEM;
goto cleanup;
}
/* prepare for Unicode input */
_setmode(_fileno(stream), O_U16TEXT);
if (fgetws(str_w, n/4, stream) == NULL)
goto cleanup;
if ((str_tmp = utf16_to_utf8(str_w)) == NULL) {
errno = ENOMEM;
goto cleanup;
}
if (strlen(str_tmp) > n - 1) {
/* shouldn't happen. but handling in case */
errno = EINVAL;
goto cleanup;
}
memcpy(str, str_tmp, strlen(str_tmp) + 1);
ret = str;
}
else
ret = fgets(str, n, stream);
cleanup:
if (str_w)
free(str_w);
if (str_tmp)
free(str_tmp);
return ret;
}
/* Account for differences between Unix's and Windows versions of setvbuf */
int
w32_setvbuf(FILE *stream, char *buffer, int mode, size_t size) {
/* BUG: setvbuf on console stream interferes with Unicode I/O */
HANDLE h = (HANDLE)_get_osfhandle(_fileno(stream));
if (h != NULL && h != INVALID_HANDLE_VALUE
&& GetFileType(h) == FILE_TYPE_CHAR)
return 0;
/* BUG: setvbuf on file stream is interfering with w32_fopen */
/* short circuit for now*/
return 0;
/*
* if size is 0, set no buffering.
* Windows does not differentiate __IOLBF and _IOFBF
*/
if (size == 0)
return setvbuf(stream, NULL, _IONBF, 0);
else
return setvbuf(stream, buffer, mode, size);
}
char *
w32_programdir()
{

View File

@ -0,0 +1,52 @@
/*
* Temporary Windows versions of functions implemented in utf8.c
*/
#include <stdio.h>
#include <stdarg.h>
int
vfmprintf(FILE *f, const char *fmt, va_list list)
{
return vfprintf(f, fmt, list);
}
int
mprintf(const char *fmt, ...)
{
int ret = 0;
va_list valist;
va_start(valist, fmt);
ret = vfmprintf(stdout, fmt, valist);
va_end(valist);
return ret;
}
int
fmprintf(FILE *f, const char *fmt, ...)
{
int ret = 0;
va_list valist;
va_start(valist, fmt);
ret = vfmprintf(f, fmt, valist);
va_end(valist);
return ret;
}
int
snmprintf(char *buf, size_t len, int *written, const char *fmt, ...)
{
int num;
va_list valist;
va_start(valist, fmt);
num = vsnprintf(buf, len, fmt, valist);
va_end(valist);
*written = num;
return 0;
}
void
msetlocale(void)
{
return;
}

20
scp.c
View File

@ -1034,17 +1034,7 @@ rsource(char *name, struct stat *statp)
(void) snprintf(path, sizeof path, "D%04o %d %.1024s\n",
(u_int) (statp->st_mode & FILEMODEMASK), 0, last);
if (verbose_mode)
#ifdef WINDOWS
/* TODO - make fmprintf work for Windows */
{
printf("Entering directory: ");
wchar_t* wtmp = utf8_to_utf16(path);
WriteConsoleW(GetStdHandle(STD_ERROR_HANDLE), wtmp, wcslen(wtmp), 0, 0);
free(wtmp);
}
#else /* !WINDOWS */
fmprintf(stderr, "Entering directory: %s", path);
#endif /* !WINDOWS */
(void) atomicio(vwrite, remout, path, strlen(path));
if (response() < 0) {
closedir(dirp);
@ -1119,17 +1109,7 @@ sink(int argc, char **argv)
} while (cp < &buf[sizeof(buf) - 1] && ch != '\n');
*cp = 0;
if (verbose_mode)
#ifdef WINDOWS
/* TODO - make fmprintf work for Windows */
{
printf("Sink: ");
wchar_t* wtmp = utf8_to_utf16(buf);
WriteConsoleW(GetStdHandle(STD_ERROR_HANDLE), wtmp, wcslen(wtmp), 0, 0);
free(wtmp);
}
#else /* !WINDOWS */
fmprintf(stderr, "Sink: %s", buf);
#endif /* !WINDOWS */
if (buf[0] == '\01' || buf[0] == '\02') {
if (iamremote == 0) {

87
sftp.c
View File

@ -292,27 +292,6 @@ help(void)
"? Synonym for help\n");
}
#ifdef WINDOWS
/* printf version to account for utf-8 input */
/* TODO - merge this with vfmprint */
static void printf_utf8(char *fmt, ... ) {
/* TODO - is 1024 sufficient */
char buf[1024];
int length = 0;
va_list valist;
va_start(valist, fmt);
length = vsnprintf(buf, 1024, fmt, valist);
va_end(valist);
write(STDOUT_FILENO, buf, length);
}
/* override mprintf */
#define mprintf(a,...) printf_utf8((a), __VA_ARGS__)
#define printf(a,...) printf_utf8((a), __VA_ARGS__)
#endif /* WINDOWS */
static void
local_do_shell(const char *args)
{
@ -420,7 +399,7 @@ make_absolute(char *p, const char *pwd)
p = abs_str;
}
/* convert '\\' tp '/' */
/* convert '\\' to '/' */
convertToForwardslash(p);
/* Append "/" if needed to the absolute windows path */
@ -925,23 +904,7 @@ do_ls_dir(struct sftp_conn *conn, const char *path,
} else
mprintf("%s\n", d[n]->longname);
} else {
#ifdef WINDOWS
/* cannot use printf_utf8 becuase of width specification */
/* printf_utf8 does not account for utf-16 based argument widths */
char *p = NULL;
wchar_t buf[1024];
wchar_t* wtmp = utf8_to_utf16(fname);
swprintf(buf, 1024, L"%-*s", colspace, wtmp);
if ((p = utf16_to_utf8(buf)) == NULL)
continue;
write(STDOUT_FILENO, p, strlen(p));
free(wtmp);
free(p);
#else
mprintf("%-*s", colspace, fname);
#endif
if (c >= columns) {
printf("\n");
c = 1;
@ -1025,23 +988,7 @@ do_globbed_ls(struct sftp_conn *conn, const char *path,
mprintf("%s\n", lname);
free(lname);
} else {
#ifdef WINDOWS
/* cannot use printf_utf8 becuase of width specification */
/* printf_utf8 does not account for utf-16 based argument widths */
char *p = NULL;
wchar_t buf[1024];
wchar_t* wtmp = utf8_to_utf16(fname);
swprintf(buf, 1024, L"%-*s", colspace, wtmp);
if ((p = utf16_to_utf8(buf)) == NULL)
continue;
write(STDOUT_FILENO, p, strlen(p));
free(wtmp);
free(p);
#else
mprintf("%-*s", colspace, fname);
#endif
if (c >= columns) {
printf("\n");
c = 1;
@ -2211,20 +2158,8 @@ interactive_loop(struct sftp_conn *conn, char *file1, char *file2)
interactive = !batchmode && isatty(STDIN_FILENO);
err = 0;
#ifdef WINDOWS
/* Min buffer size allowed in Windows is 2*/
setvbuf(stdout, NULL, _IOLBF, 2);
/* We do this only in interactive mode as we are unable to read files with UTF8 BOM */
if (interactive) {
setvbuf(infile, NULL, _IOLBF, 2);
_setmode(_fileno(stdin), O_U16TEXT); /* prepare for Unicode input */
}
#else /* !WINDOWS */
setvbuf(stdout, NULL, _IOLBF, 0);
setvbuf(infile, NULL, _IOLBF, 0);
#endif /* !WINDOWS */
for (;;) {
char *cp;
@ -2232,25 +2167,6 @@ interactive_loop(struct sftp_conn *conn, char *file1, char *file2)
signal(SIGINT, SIG_IGN);
if (el == NULL) {
#ifdef WINDOWS
/* fgets on Windows does not support Unicode input*/
if (interactive) {
wchar_t wcmd[2048];
printf("sftp> ");
if (fgetws(wcmd, sizeof(cmd)/sizeof(wchar_t), infile) == NULL) {
printf("\n");
break;
}
else {
char *pcmd = NULL;
if ((pcmd = utf16_to_utf8(wcmd)) == NULL)
fatal("failed to convert input arguments");
strcpy(cmd, pcmd);
free(pcmd);
}
} else if (fgets(cmd, sizeof(cmd), infile) == NULL)
break;
#else /* !WINDOWS */
if (interactive)
printf("sftp> ");
if (fgets(cmd, sizeof(cmd), infile) == NULL) {
@ -2258,7 +2174,6 @@ interactive_loop(struct sftp_conn *conn, char *file1, char *file2)
printf("\n");
break;
}
#endif/* !WINDOWS */
if (!interactive) { /* Echo command */
mprintf("sftp> %s", cmd);
if (strlen(cmd) > 0 &&

12
utf8.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: utf8.c,v 1.4 2017/02/02 10:54:25 jsg Exp $ */
/* $OpenBSD: utf8.c,v 1.5 2017/02/19 00:10:57 djm Exp $ */
/*
* Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org>
*
@ -57,16 +57,11 @@ static int vasnmprintf(char **, size_t, int *, const char *, va_list);
static int
dangerous_locale(void) {
#ifdef WINDOWS
wchar_t loc[LOCALE_NAME_MAX_LENGTH];
GetSystemDefaultLocaleName(loc, LOCALE_NAME_MAX_LENGTH);
return wcscmp(loc, L"US-ASCII") && wcscmp(loc, L"UTF-8");
#else /* !WINDOWS */
char *loc;
loc = nl_langinfo(CODESET);
return strcmp(loc, "US-ASCII") && strcmp(loc, "UTF-8");
#endif /* !WINDOWS */
return strcmp(loc, "US-ASCII") != 0 && strcmp(loc, "UTF-8") != 0 &&
strcmp(loc, "ANSI_X3.4-1968") != 0;
}
static int
@ -337,3 +332,4 @@ msetlocale(void)
/* We can handle this locale */
setlocale(LC_CTYPE, "");
}