diff --git a/src/avrdude/CMakeLists.txt b/src/avrdude/CMakeLists.txt index 1022a5c0e..0e9b9e6d4 100644 --- a/src/avrdude/CMakeLists.txt +++ b/src/avrdude/CMakeLists.txt @@ -1,5 +1,7 @@ cmake_minimum_required(VERSION 3.0) +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) add_definitions(-D_BSD_SOURCE -D_DEFAULT_SOURCE) # To enable various useful macros and functions on Unices remove_definitions(-D_UNICODE -DUNICODE) @@ -68,6 +70,7 @@ set(AVRDUDE_SOURCES ) if (MSVC) set(AVRDUDE_SOURCES ${AVRDUDE_SOURCES} + windows/utf8.c windows/unistd.cpp windows/getopt.c ) @@ -90,7 +93,7 @@ add_custom_target(gen_conf_h add_library(avrdude STATIC ${AVRDUDE_SOURCES}) add_dependencies(avrdude gen_conf_h) -add_executable(avrdude-slic3r main-standalone.c) +add_executable(avrdude-slic3r main-standalone.cpp) target_link_libraries(avrdude-slic3r avrdude) if (WIN32) diff --git a/src/avrdude/fileio.c b/src/avrdude/fileio.c index dcd0d6a66..7803497a0 100644 --- a/src/avrdude/fileio.c +++ b/src/avrdude/fileio.c @@ -40,6 +40,9 @@ #include "avrdude.h" #include "libavrdude.h" +#if defined(WIN32NATIVE) +#include "windows/utf8.h" +#endif #define IHEX_MAXDATA 256 @@ -110,7 +113,7 @@ FILE *fopen_utf8(const char *filename, const char *mode) static wchar_t mode_buffer[MAX_MODE_LEN]; if (MultiByteToWideChar(CP_UTF8, 0, filename, -1, fname_buffer, PATH_MAX) == 0) { return NULL; } - if (MultiByteToWideChar(CP_ACP, 0, mode, -1, mode_buffer, MAX_MODE_LEN) == 0) { return NULL; } + if (MultiByteToWideChar(CP_UTF8, 0, mode, -1, mode_buffer, MAX_MODE_LEN) == 0) { return NULL; } return _wfopen(fname_buffer, mode_buffer); #else diff --git a/src/avrdude/main-standalone.c b/src/avrdude/main-standalone.c deleted file mode 100644 index 7cfc6f210..000000000 --- a/src/avrdude/main-standalone.c +++ /dev/null @@ -1,7 +0,0 @@ -#include "avrdude.h" - - -int main(int argc, char *argv[]) -{ - return avrdude_main(argc, argv); -} diff --git a/src/avrdude/main-standalone.cpp b/src/avrdude/main-standalone.cpp new file mode 100644 index 000000000..df6d79e13 --- /dev/null +++ b/src/avrdude/main-standalone.cpp @@ -0,0 +1,54 @@ +extern "C" { +#include "avrdude.h" +} + + +#ifdef WIN32 +#include +#include + +extern "C" { +#include "windows/utf8.h" +} + +struct ArgvUtf8 : std::vector +{ + int argc; + + ArgvUtf8(int argc_w, wchar_t *argv_w[]) : std::vector(argc_w + 1, nullptr), argc(0) + { + for (int i = 0; i < argc_w; i++) { + char *arg_utf8 = ::wstr_to_utf8(argv_w[i], -1); + if (arg_utf8 != nullptr) { + operator[](i) = arg_utf8; + argc = i + 1; + } else { + break; + } + } + } + + ~ArgvUtf8() + { + for (char *arg : *this) { + if (arg != nullptr) { + ::free(arg); + } + } + } +}; + +int wmain(int argc_w, wchar_t *argv_w[]) +{ + ArgvUtf8 argv_utf8(argc_w, argv_w); + return ::avrdude_main(argv_utf8.argc, &argv_utf8[0]); +} + +#else + +int main(int argc, char *argv[]) +{ + return ::avrdude_main(argc, argv); +} + +#endif diff --git a/src/avrdude/main.c b/src/avrdude/main.c index 0f8807122..8f9040349 100644 --- a/src/avrdude/main.c +++ b/src/avrdude/main.c @@ -812,7 +812,6 @@ int avrdude_main(int argc, char * argv []) // rc = read_config(sys_config); rc = read_config_builtin(); - avrdude_message(MSG_NOTICE, "\n\nread_config_builtin: %d\n\n", rc); if (rc) { // avrdude_message(MSG_INFO, "%s: error reading system wide configuration file \"%s\"\n", // progname, sys_config); diff --git a/src/avrdude/ser_win32.c b/src/avrdude/ser_win32.c index 4e1713128..c62e83608 100644 --- a/src/avrdude/ser_win32.c +++ b/src/avrdude/ser_win32.c @@ -34,16 +34,63 @@ #include #include +#include #include /* for isprint */ #include /* ENOTTY */ #include "avrdude.h" #include "libavrdude.h" +#include "windows/utf8.h" long serial_recv_timeout = 5000; /* ms */ #define W32SERBUFSIZE 1024 + +// Get last error message string in UTF-8 +// Always return a valid null-terminated string +// The returned string should be freed by the caller +char* last_error_string(int wsa) +{ + LPWSTR wbuffer = NULL; + + (void)wsa; + + DWORD wbuffer_len = FormatMessageW( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, +#ifdef HAVE_LIBWS2_32 + wsa ? WSAGetLastError() : GetLastError(), +#else + GetLastError(), +#endif + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPWSTR)&wbuffer, + 0, + NULL); + + if (wbuffer_len == 0) { + return NULL; + } + + char *res = wstr_to_utf8(wbuffer, wbuffer_len); + + LocalFree(wbuffer); + + if (res == NULL) { + // If we get here, conversion to UTF-8 failed + res = strdup("(could not get error message)"); + if (res == NULL) { + avrdude_oom("last_error_string(): out of memory\n"); + } + } + + return res; +} + + struct baud_mapping { long baud; DWORD speed; @@ -129,7 +176,6 @@ static int net_open(const char *port, union filedescriptor *fdp) { WSADATA wsaData; - LPVOID lpMsgBuf; char *hstr, *pstr, *end; unsigned int pnum; @@ -175,18 +221,10 @@ net_open(const char *port, union filedescriptor *fdp) free(hstr); if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { - FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - WSAGetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR)&lpMsgBuf, - 0, - NULL); - avrdude_message(MSG_INFO, "%s: net_open(): Cannot open socket: %s\n", progname, (char *)lpMsgBuf); - LocalFree(lpMsgBuf); + const char *error = last_error_string(1); + avrdude_message(MSG_INFO, "%s: net_open(): Cannot open socket: %s\n", progname, error); + free(error); + return -1; } @@ -196,18 +234,9 @@ net_open(const char *port, union filedescriptor *fdp) memcpy(&(sockaddr.sin_addr.s_addr), hp->h_addr, sizeof(struct in_addr)); if (connect(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) { - FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - WSAGetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR)&lpMsgBuf, - 0, - NULL); - avrdude_message(MSG_INFO, "%s: net_open(): Connect failed: %s\n", progname, (char *)lpMsgBuf); - LocalFree(lpMsgBuf); + const char *error = last_error_string(1); + avrdude_message(MSG_INFO, "%s: net_open(): Connect failed: %s\n", progname); + free(error); return -1; } @@ -221,7 +250,6 @@ net_open(const char *port, union filedescriptor *fdp) static int ser_open(char * port, union pinfo pinfo, union filedescriptor *fdp) { - LPVOID lpMsgBuf; HANDLE hComPort=INVALID_HANDLE_VALUE; char *newname = 0; @@ -261,19 +289,9 @@ static int ser_open(char * port, union pinfo pinfo, union filedescriptor *fdp) OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hComPort == INVALID_HANDLE_VALUE) { - FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - GetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language - (LPTSTR) &lpMsgBuf, - 0, - NULL); - avrdude_message(MSG_INFO, "%s: ser_open(): can't open device \"%s\": %s\n", - progname, port, (char*)lpMsgBuf); - LocalFree( lpMsgBuf ); + const char *error = last_error_string(0); + avrdude_message(MSG_INFO, "%s: ser_open(): can't open device \"%s\": %s\n", progname, port, error); + free(error); return -1; } @@ -346,14 +364,13 @@ static int ser_set_dtr_rts(union filedescriptor *fd, int is_on) #ifdef HAVE_LIBWS2_32 static int net_send(union filedescriptor *fd, const unsigned char * buf, size_t buflen) { - LPVOID lpMsgBuf; int rc; const unsigned char *p = buf; size_t len = buflen; if (fd->ifd < 0) { avrdude_message(MSG_NOTICE, "%s: net_send(): connection not open\n", progname); - exit(1); + return -1; } if (!len) { @@ -382,19 +399,10 @@ static int net_send(union filedescriptor *fd, const unsigned char * buf, size_t while (len) { rc = send(fd->ifd, p, (len > 1024) ? 1024 : len, 0); if (rc < 0) { - FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - WSAGetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR)&lpMsgBuf, - 0, - NULL); - avrdude_message(MSG_INFO, "%s: net_send(): send error: %s\n", progname, (char *)lpMsgBuf); - LocalFree(lpMsgBuf); - exit(1); + const char *error = last_error_string(1); + avrdude_message(MSG_INFO, "%s: net_send(): send error: %s\n", progname, error); + free(error); + return -1; } p += rc; len -= rc; @@ -423,8 +431,7 @@ static int ser_send(union filedescriptor *fd, const unsigned char * buf, size_t HANDLE hComPort=(HANDLE)fd->pfd; if (hComPort == INVALID_HANDLE_VALUE) { - avrdude_message(MSG_INFO, "%s: ser_send(): port not open\n", - progname); + avrdude_message(MSG_INFO, "%s: ser_send(): port not open\n", progname); return -1; } @@ -449,18 +456,18 @@ static int ser_send(union filedescriptor *fd, const unsigned char * buf, size_t } avrdude_message(MSG_INFO, "\n"); } - + serial_w32SetTimeOut(hComPort,500); - if (!WriteFile (hComPort, buf, buflen, &written, NULL)) { - avrdude_message(MSG_INFO, "%s: ser_send(): write error: %s\n", - progname, "sorry no info avail"); // TODO + if (!WriteFile(hComPort, buf, buflen, &written, NULL)) { + const char *error = last_error_string(0); + avrdude_message(MSG_INFO, "%s: ser_send(): write error: %s\n", progname, error); + free(error); return -1; } if (written != buflen) { - avrdude_message(MSG_INFO, "%s: ser_send(): size/send mismatch\n", - progname); + avrdude_message(MSG_INFO, "%s: ser_send(): size/send mismatch\n", progname); return -1; } @@ -471,7 +478,6 @@ static int ser_send(union filedescriptor *fd, const unsigned char * buf, size_t #ifdef HAVE_LIBWS2_32 static int net_recv(union filedescriptor *fd, unsigned char * buf, size_t buflen) { - LPVOID lpMsgBuf; struct timeval timeout, to2; fd_set rfds; int nfds; @@ -481,7 +487,7 @@ static int net_recv(union filedescriptor *fd, unsigned char * buf, size_t buflen if (fd->ifd < 0) { avrdude_message(MSG_INFO, "%s: net_recv(): connection not open\n", progname); - exit(1); + return -1; } timeout.tv_sec = serial_recv_timeout / 1000L; @@ -504,37 +510,19 @@ reselect: avrdude_message(MSG_NOTICE, "%s: ser_recv(): programmer is not responding, reselecting\n", progname); goto reselect; } else { - FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - WSAGetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR)&lpMsgBuf, - 0, - NULL); - avrdude_message(MSG_INFO, "%s: ser_recv(): select(): %s\n", progname, (char *)lpMsgBuf); - LocalFree(lpMsgBuf); - exit(1); + const char *error = last_error_string(1); + avrdude_message(MSG_INFO, "%s: ser_recv(): select(): %s\n", progname, error); + free(error); + return -1; } } rc = recv(fd->ifd, p, (buflen - len > 1024) ? 1024 : buflen - len, 0); if (rc < 0) { - FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - WSAGetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR)&lpMsgBuf, - 0, - NULL); - avrdude_message(MSG_INFO, "%s: ser_recv(): read error: %s\n", progname, (char *)lpMsgBuf); - LocalFree(lpMsgBuf); - exit(1); + const char *error = last_error_string(1); + avrdude_message(MSG_INFO, "%s: ser_recv(): read error: %s\n", progname, error); + free(error); + return -1; } p += rc; len += rc; @@ -579,37 +567,24 @@ static int ser_recv(union filedescriptor *fd, unsigned char * buf, size_t buflen RETURN_IF_CANCEL(); HANDLE hComPort=(HANDLE)fd->pfd; - + if (hComPort == INVALID_HANDLE_VALUE) { - avrdude_message(MSG_INFO, "%s: ser_read(): port not open\n", - progname); + avrdude_message(MSG_INFO, "%s: ser_read(): port not open\n", progname); return -1; } - + serial_w32SetTimeOut(hComPort, serial_recv_timeout); - + if (!ReadFile(hComPort, buf, buflen, &read, NULL)) { - LPVOID lpMsgBuf; - FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - GetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language - (LPTSTR) &lpMsgBuf, - 0, - NULL ); - avrdude_message(MSG_INFO, "%s: ser_recv(): read error: %s\n", - progname, (char*)lpMsgBuf); - LocalFree( lpMsgBuf ); + const char *error = last_error_string(0); + avrdude_message(MSG_INFO, "%s: ser_recv(): read error: %s\n", progname, error); + free(error); return -1; } /* time out detected */ if (read == 0) { - avrdude_message(MSG_NOTICE2, "%s: ser_recv(): programmer is not responding\n", - progname); + avrdude_message(MSG_NOTICE2, "%s: ser_recv(): programmer is not responding\n", progname); return -1; } @@ -664,20 +639,9 @@ static int ser_drain(union filedescriptor *fd, int display) readres=ReadFile(hComPort, buf, 1, &read, NULL); if (!readres) { - LPVOID lpMsgBuf; - FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - GetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language - (LPTSTR) &lpMsgBuf, - 0, - NULL ); - avrdude_message(MSG_INFO, "%s: ser_drain(): read error: %s\n", - progname, (char*)lpMsgBuf); - LocalFree( lpMsgBuf ); + const char *error = last_error_string(0); + avrdude_message(MSG_INFO, "%s: ser_drain(): read error: %s\n", progname, error); + free(error); return -1; } diff --git a/src/avrdude/windows/utf8.c b/src/avrdude/windows/utf8.c new file mode 100644 index 000000000..d3c51e67f --- /dev/null +++ b/src/avrdude/windows/utf8.c @@ -0,0 +1,45 @@ +#include "utf8.h" + + +char* wstr_to_utf8(LPWSTR wstr, int len) +{ + char *res = NULL; + + int res_size = WideCharToMultiByte(CP_UTF8, 0, wstr, len, NULL, 0, NULL, NULL); + if (res_size > 0) { + // Note: WideCharToMultiByte doesn't null-terminate if real (ie. > 0) buffer length is passed + res = malloc(len != - 1 ? res_size + 1 : res_size); + if (res == NULL) { return NULL; } + + if (WideCharToMultiByte(CP_UTF8, 0, wstr, len, res, res_size, NULL, NULL) == res_size) { + if (len != -1) { res[res_size] = '\0'; } + } else { + free(res); + return NULL; + } + } + + return res; +} + +LPWSTR utf8_to_wstr(const char *str, int len) +{ + LPWSTR res = NULL; + + int res_size = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0); + if (res_size > 0) { + // Note: MultiByteToWideChar doesn't null-terminate if real (ie. > 0) buffer length is passed + res = malloc(len != - 1 ? res_size + 1 : res_size); + + if (res == NULL) { return NULL; } + + if (MultiByteToWideChar(CP_UTF8, 0, str, len, res, res_size) == res_size) { + if (len != -1) { res[res_size] = L'\0'; } + } else { + free(res); + return NULL; + } + } + + return res; +} diff --git a/src/avrdude/windows/utf8.h b/src/avrdude/windows/utf8.h new file mode 100644 index 000000000..a99fcbb7e --- /dev/null +++ b/src/avrdude/windows/utf8.h @@ -0,0 +1,10 @@ +#ifndef SLIC3R_AVRDUDE_UTF8_H +#define SLIC3R_AVRDUDE_UTF8_H + +#include + +extern char* wstr_to_utf8(LPWSTR wstr, int len); +extern LPWSTR utf8_to_wstr(const char *str, int len); + + +#endif // SLIC3R_AVRDUDE_UTF8_H