Просмотр исходного кода

Added UTF-8 functions.

We want to use UTF-8 everywhere.  To that end we use new functions that
will convert strings between UTF-8 and UTF-16.

Before doing anything at all we set the console, if we have one, to
codepage UTF-8.  Before exiting we restore the console codepage to
whatever it was before.
Iain Patterson 7 лет назад
Родитель
Сommit
800ca0c4f1
8 измененных файлов с 187 добавлено и 41 удалено
  1. 5 4
      console.cpp
  2. 1 1
      console.h
  3. 27 31
      nssm.cpp
  4. 2 0
      nssm.h
  5. 12 4
      nssm.vcproj
  6. 1 1
      service.cpp
  7. 126 0
      utf8.cpp
  8. 13 0
      utf8.h

+ 5 - 4
console.cpp

@@ -1,23 +1,24 @@
 #include "nssm.h"
 #include "nssm.h"
 
 
 /* See if we were launched from a console window. */
 /* See if we were launched from a console window. */
-void check_console() {
+bool check_console() {
   /* If we're running in a service context there will be no console window. */
   /* If we're running in a service context there will be no console window. */
   HWND console = GetConsoleWindow();
   HWND console = GetConsoleWindow();
-  if (! console) return;
+  if (! console) return false;
 
 
   unsigned long pid;
   unsigned long pid;
-  if (! GetWindowThreadProcessId(console, &pid)) return;
+  if (! GetWindowThreadProcessId(console, &pid)) return false;
 
 
   /*
   /*
     If the process associated with the console window handle is the same as
     If the process associated with the console window handle is the same as
     this process, we were not launched from an existing console.  The user
     this process, we were not launched from an existing console.  The user
     probably double-clicked our executable.
     probably double-clicked our executable.
   */
   */
-  if (GetCurrentProcessId() != pid) return;
+  if (GetCurrentProcessId() != pid) return true;
 
 
   /* We close our new console so that subsequent messages appear in a popup. */
   /* We close our new console so that subsequent messages appear in a popup. */
   FreeConsole();
   FreeConsole();
+  return false;
 }
 }
 
 
 /* Helpers for drawing the banner. */
 /* Helpers for drawing the banner. */

+ 1 - 1
console.h

@@ -1,7 +1,7 @@
 #ifndef CONSOLE_H
 #ifndef CONSOLE_H
 #define CONSOLE_H
 #define CONSOLE_H
 
 
-void check_console();
+bool check_console();
 void alloc_console(nssm_service_t *);
 void alloc_console(nssm_service_t *);
 
 
 #endif
 #endif

+ 27 - 31
nssm.cpp

@@ -8,6 +8,11 @@ static TCHAR unquoted_imagepath[PATH_LENGTH];
 static TCHAR imagepath[PATH_LENGTH];
 static TCHAR imagepath[PATH_LENGTH];
 static TCHAR imageargv0[PATH_LENGTH];
 static TCHAR imageargv0[PATH_LENGTH];
 
 
+void nssm_exit(int status) {
+  unsetup_utf8();
+  exit(status);
+}
+
 /* Are two strings case-insensitively equivalent? */
 /* Are two strings case-insensitively equivalent? */
 int str_equiv(const TCHAR *a, const TCHAR *b) {
 int str_equiv(const TCHAR *a, const TCHAR *b) {
   size_t len = _tcslen(a);
   size_t len = _tcslen(a);
@@ -219,22 +224,13 @@ const TCHAR *nssm_exe() {
 }
 }
 
 
 int _tmain(int argc, TCHAR **argv) {
 int _tmain(int argc, TCHAR **argv) {
-  check_console();
-
-#ifdef UNICODE
-  /*
-    Ensure we write in UTF-16 mode, so that non-ASCII characters don't get
-    mangled.  If we were compiled in ANSI mode it won't work.
-   */
-  _setmode(_fileno(stdout), _O_U16TEXT);
-  _setmode(_fileno(stderr), _O_U16TEXT);
-#endif
+  if (check_console()) setup_utf8();
 
 
   /* Remember if we are admin */
   /* Remember if we are admin */
   check_admin();
   check_admin();
 
 
   /* Set up function pointers. */
   /* Set up function pointers. */
-  if (get_imports()) exit(111);
+  if (get_imports()) nssm_exit(111);
 
 
   /* Remember our path for later. */
   /* Remember our path for later. */
   _sntprintf_s(imageargv0, _countof(imageargv0), _TRUNCATE, _T("%s"), argv[0]);
   _sntprintf_s(imageargv0, _countof(imageargv0), _TRUNCATE, _T("%s"), argv[0]);
@@ -249,34 +245,34 @@ int _tmain(int argc, TCHAR **argv) {
       Valid commands are:
       Valid commands are:
       start, stop, pause, continue, install, edit, get, set, reset, unset, remove
       start, stop, pause, continue, install, edit, get, set, reset, unset, remove
     */
     */
-    if (str_equiv(argv[1], _T("start"))) exit(control_service(NSSM_SERVICE_CONTROL_START, argc - 2, argv + 2));
-    if (str_equiv(argv[1], _T("stop"))) exit(control_service(SERVICE_CONTROL_STOP, argc - 2, argv + 2));
+    if (str_equiv(argv[1], _T("start"))) nssm_exit(control_service(NSSM_SERVICE_CONTROL_START, argc - 2, argv + 2));
+    if (str_equiv(argv[1], _T("stop"))) nssm_exit(control_service(SERVICE_CONTROL_STOP, argc - 2, argv + 2));
     if (str_equiv(argv[1], _T("restart"))) {
     if (str_equiv(argv[1], _T("restart"))) {
       int ret = control_service(SERVICE_CONTROL_STOP, argc - 2, argv + 2);
       int ret = control_service(SERVICE_CONTROL_STOP, argc - 2, argv + 2);
-      if (ret) exit(ret);
-      exit(control_service(NSSM_SERVICE_CONTROL_START, argc - 2, argv + 2));
+      if (ret) nssm_exit(ret);
+      nssm_exit(control_service(NSSM_SERVICE_CONTROL_START, argc - 2, argv + 2));
     }
     }
-    if (str_equiv(argv[1], _T("pause"))) exit(control_service(SERVICE_CONTROL_PAUSE, argc - 2, argv + 2));
-    if (str_equiv(argv[1], _T("continue"))) exit(control_service(SERVICE_CONTROL_CONTINUE, argc - 2, argv + 2));
-    if (str_equiv(argv[1], _T("status"))) exit(control_service(SERVICE_CONTROL_INTERROGATE, argc - 2, argv + 2));
-    if (str_equiv(argv[1], _T("rotate"))) exit(control_service(NSSM_SERVICE_CONTROL_ROTATE, argc - 2, argv + 2));
+    if (str_equiv(argv[1], _T("pause"))) nssm_exit(control_service(SERVICE_CONTROL_PAUSE, argc - 2, argv + 2));
+    if (str_equiv(argv[1], _T("continue"))) nssm_exit(control_service(SERVICE_CONTROL_CONTINUE, argc - 2, argv + 2));
+    if (str_equiv(argv[1], _T("status"))) nssm_exit(control_service(SERVICE_CONTROL_INTERROGATE, argc - 2, argv + 2));
+    if (str_equiv(argv[1], _T("rotate"))) nssm_exit(control_service(NSSM_SERVICE_CONTROL_ROTATE, argc - 2, argv + 2));
     if (str_equiv(argv[1], _T("install"))) {
     if (str_equiv(argv[1], _T("install"))) {
-      if (! is_admin) exit(elevate(argc, argv, NSSM_MESSAGE_NOT_ADMINISTRATOR_CANNOT_INSTALL));
+      if (! is_admin) nssm_exit(elevate(argc, argv, NSSM_MESSAGE_NOT_ADMINISTRATOR_CANNOT_INSTALL));
       create_messages();
       create_messages();
-      exit(pre_install_service(argc - 2, argv + 2));
+      nssm_exit(pre_install_service(argc - 2, argv + 2));
     }
     }
     if (str_equiv(argv[1], _T("edit")) || str_equiv(argv[1], _T("get")) || str_equiv(argv[1], _T("set")) || str_equiv(argv[1], _T("reset")) || str_equiv(argv[1], _T("unset")) || str_equiv(argv[1], _T("dump"))) {
     if (str_equiv(argv[1], _T("edit")) || str_equiv(argv[1], _T("get")) || str_equiv(argv[1], _T("set")) || str_equiv(argv[1], _T("reset")) || str_equiv(argv[1], _T("unset")) || str_equiv(argv[1], _T("dump"))) {
       int ret = pre_edit_service(argc - 1, argv + 1);
       int ret = pre_edit_service(argc - 1, argv + 1);
-      if (ret == 3 && ! is_admin && argc == 3) exit(elevate(argc, argv, NSSM_MESSAGE_NOT_ADMINISTRATOR_CANNOT_EDIT));
+      if (ret == 3 && ! is_admin && argc == 3) nssm_exit(elevate(argc, argv, NSSM_MESSAGE_NOT_ADMINISTRATOR_CANNOT_EDIT));
       /* There might be a password here. */
       /* There might be a password here. */
       for (int i = 0; i < argc; i++) SecureZeroMemory(argv[i], _tcslen(argv[i]) * sizeof(TCHAR));
       for (int i = 0; i < argc; i++) SecureZeroMemory(argv[i], _tcslen(argv[i]) * sizeof(TCHAR));
-      exit(ret);
+      nssm_exit(ret);
     }
     }
-    if (str_equiv(argv[1], _T("list"))) exit(list_nssm_services(argc - 2, argv + 2));
-    if (str_equiv(argv[1], _T("processes"))) exit(service_process_tree(argc - 2, argv + 2));
+    if (str_equiv(argv[1], _T("list"))) nssm_exit(list_nssm_services(argc - 2, argv + 2));
+    if (str_equiv(argv[1], _T("processes"))) nssm_exit(service_process_tree(argc - 2, argv + 2));
     if (str_equiv(argv[1], _T("remove"))) {
     if (str_equiv(argv[1], _T("remove"))) {
-      if (! is_admin) exit(elevate(argc, argv, NSSM_MESSAGE_NOT_ADMINISTRATOR_CANNOT_REMOVE));
-      exit(pre_remove_service(argc - 2, argv + 2));
+      if (! is_admin) nssm_exit(elevate(argc, argv, NSSM_MESSAGE_NOT_ADMINISTRATOR_CANNOT_REMOVE));
+      nssm_exit(pre_remove_service(argc - 2, argv + 2));
     }
     }
   }
   }
 
 
@@ -302,14 +298,14 @@ int _tmain(int argc, TCHAR **argv) {
     if (! StartServiceCtrlDispatcher(table)) {
     if (! StartServiceCtrlDispatcher(table)) {
       unsigned long error = GetLastError();
       unsigned long error = GetLastError();
       /* User probably ran nssm with no argument */
       /* User probably ran nssm with no argument */
-      if (error == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) exit(usage(1));
+      if (error == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) nssm_exit(usage(1));
       log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_DISPATCHER_FAILED, error_string(error), 0);
       log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_DISPATCHER_FAILED, error_string(error), 0);
       free_imports();
       free_imports();
-      exit(100);
+      nssm_exit(100);
     }
     }
   }
   }
-  else exit(usage(1));
+  else nssm_exit(usage(1));
 
 
   /* And nothing more to do */
   /* And nothing more to do */
-  exit(0);
+  nssm_exit(0);
 }
 }

+ 2 - 0
nssm.h

@@ -46,6 +46,7 @@
 #include <shlwapi.h>
 #include <shlwapi.h>
 #include <stdarg.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdio.h>
+#include "utf8.h"
 #include "service.h"
 #include "service.h"
 #include "account.h"
 #include "account.h"
 #include "console.h"
 #include "console.h"
@@ -61,6 +62,7 @@
 #include "gui.h"
 #include "gui.h"
 #endif
 #endif
 
 
+void nssm_exit(int);
 int str_equiv(const TCHAR *, const TCHAR *);
 int str_equiv(const TCHAR *, const TCHAR *);
 int quote(const TCHAR *, TCHAR *, size_t);
 int quote(const TCHAR *, TCHAR *, size_t);
 void strip_basename(TCHAR *);
 void strip_basename(TCHAR *);

+ 12 - 4
nssm.vcproj

@@ -646,6 +646,10 @@
 				RelativePath="settings.cpp"
 				RelativePath="settings.cpp"
 				>
 				>
 			</File>
 			</File>
+			<File
+				RelativePath="utf8.cpp"
+				>
+			</File>
 		</Filter>
 		</Filter>
 		<Filter
 		<Filter
 			Name="Header Files"
 			Name="Header Files"
@@ -703,6 +707,10 @@
 				RelativePath="settings.h"
 				RelativePath="settings.h"
 				>
 				>
 			</File>
 			</File>
+			<File
+				RelativePath="utf8.h"
+				>
+			</File>
 		</Filter>
 		</Filter>
 		<Filter
 		<Filter
 			Name="Resource Files"
 			Name="Resource Files"
@@ -758,7 +766,7 @@
 				<Tool
 				<Tool
 					Name="VCCustomBuildTool"
 					Name="VCCustomBuildTool"
 					Description="Compiling messages"
 					Description="Compiling messages"
-					CommandLine="mc -u -U $(InputName).mc -r . -h ."
+					CommandLine="mc -u -U $(InputName).mc -r . -h .&#x0D;&#x0A;"
 					Outputs="$(InputName).rc;$(InputName).h"
 					Outputs="$(InputName).rc;$(InputName).h"
 				/>
 				/>
 			</FileConfiguration>
 			</FileConfiguration>
@@ -768,7 +776,7 @@
 				<Tool
 				<Tool
 					Name="VCCustomBuildTool"
 					Name="VCCustomBuildTool"
 					Description="Compiling messages"
 					Description="Compiling messages"
-					CommandLine="mc -u -U $(InputName).mc -r . -h ."
+					CommandLine="mc -u -U $(InputName).mc -r . -h .&#x0D;&#x0A;"
 					Outputs="$(InputName).rc;$(InputName).h"
 					Outputs="$(InputName).rc;$(InputName).h"
 				/>
 				/>
 			</FileConfiguration>
 			</FileConfiguration>
@@ -778,7 +786,7 @@
 				<Tool
 				<Tool
 					Name="VCCustomBuildTool"
 					Name="VCCustomBuildTool"
 					Description="Compiling messages"
 					Description="Compiling messages"
-					CommandLine="mc -u -U $(InputName).mc -r . -h ."
+					CommandLine="mc -u -U $(InputName).mc -r . -h .&#x0D;&#x0A;"
 					AdditionalDependencies=""
 					AdditionalDependencies=""
 					Outputs="$(InputName).rc;$(InputName).h"
 					Outputs="$(InputName).rc;$(InputName).h"
 				/>
 				/>
@@ -789,7 +797,7 @@
 				<Tool
 				<Tool
 					Name="VCCustomBuildTool"
 					Name="VCCustomBuildTool"
 					Description="Compiling messages"
 					Description="Compiling messages"
-					CommandLine="mc -u -U $(InputName).mc -r . -h ."
+					CommandLine="mc -u -U $(InputName).mc -r . -h .&#x0D;&#x0A;"
 					AdditionalDependencies=""
 					AdditionalDependencies=""
 					Outputs="$(InputName).rc;$(InputName).h"
 					Outputs="$(InputName).rc;$(InputName).h"
 				/>
 				/>

+ 1 - 1
service.cpp

@@ -2078,7 +2078,7 @@ void CALLBACK end_service(void *arg, unsigned char why) {
       stop_service(service, exitcode, false, default_action);
       stop_service(service, exitcode, false, default_action);
       wait_for_hooks(service, false);
       wait_for_hooks(service, false);
       free_imports();
       free_imports();
-      exit(exitcode);
+      nssm_exit(exitcode);
   }
   }
 }
 }
 
 

+ 126 - 0
utf8.cpp

@@ -0,0 +1,126 @@
+#include "nssm.h"
+
+static unsigned long cp;
+
+void setup_utf8() {
+#ifdef UNICODE
+  /*
+    Ensure we write in UTF-8 mode, so that non-ASCII characters don't get
+    mangled.  If we were compiled in ANSI mode it won't work.
+   */
+  cp = GetConsoleOutputCP();
+  SetConsoleOutputCP(CP_UTF8);
+  _setmode(_fileno(stdout), _O_U8TEXT);
+  _setmode(_fileno(stderr), _O_U8TEXT);
+#endif
+}
+
+void unsetup_utf8() {
+  if (cp) SetConsoleOutputCP(cp);
+}
+
+/*
+  Conversion functions.
+
+  to_utf8/16() converts a string which may be either utf8 or utf16 to
+  the desired format.  If no conversion is needed a new string is still
+  allocated and the old string is copied.
+
+  from_utf8/16() converts a string which IS in the specified format to
+  whichever format is needed according to whether UNICODE is defined.
+  It simply wraps the appropriate to_utf8/16() function.
+
+  Therefore the caller must ALWAYS free the destination pointer after a
+  successful (return code 0) call to one of these functions.
+
+  The length pointer is optional.  Pass NULL if you don't care about
+  the length of the converted string.
+
+  Both the destination and the length, if supplied, will be zeroed if
+  no conversion was done.
+*/
+int to_utf8(const wchar_t *utf16, char **utf8, unsigned long *utf8len) {
+  *utf8 = 0;
+  if (utf8len) *utf8len = 0;
+  int size = WideCharToMultiByte(CP_UTF8, 0, utf16, -1, NULL, 0, NULL, NULL);
+  if (! size) return 1;
+
+  *utf8 = (char *) HeapAlloc(GetProcessHeap(), 0, size);
+  if (! *utf8) return 2;
+
+  if (! WideCharToMultiByte(CP_UTF8, 0, utf16, -1, (LPSTR) utf8, size, NULL, NULL)) {
+    HeapFree(GetProcessHeap(), 0, *utf8);
+    *utf8 = 0;
+    return 3;
+  }
+
+  if (utf8len) *utf8len = (unsigned long) strlen(*utf8);
+
+  return 0;
+}
+
+int to_utf8(const char *ansi, char **utf8, unsigned long *utf8len) {
+  *utf8 = 0;
+  if (utf8len) *utf8len = 0;
+  size_t len = strlen(ansi);
+  int size = (int) len + 1;
+
+  *utf8 = (char *) HeapAlloc(GetProcessHeap(), 0, size);
+  if (! *utf8) return 2;
+
+  if (utf8len) *utf8len = (unsigned long) len;
+  memmove(*utf8, ansi, size);
+
+  return 0;
+}
+
+int to_utf16(const char *utf8, wchar_t **utf16, unsigned long *utf16len) {
+  *utf16 = 0;
+  if (utf16len) *utf16len = 0;
+  int size = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0);
+  if (! size) return 1;
+
+  *utf16 = (wchar_t *) HeapAlloc(GetProcessHeap(), 0, size * sizeof(wchar_t));
+  if (! *utf16) return 2;
+
+  if (! MultiByteToWideChar(CP_UTF8, 0, utf8, -1, *utf16, size)) {
+    HeapFree(GetProcessHeap(), 0, *utf16);
+    *utf16 = 0;
+    return 3;
+  }
+
+  if (utf16len) *utf16len = (unsigned long) wcslen(*utf16);
+
+  return 0;
+}
+
+int to_utf16(const wchar_t *unicode, wchar_t **utf16, unsigned long *utf16len) {
+  *utf16 = 0;
+  if (utf16len) *utf16len = 0;
+  size_t len = wcslen(unicode);
+  int size = ((int) len + 1) * sizeof(wchar_t);
+
+  *utf16 = (wchar_t *) HeapAlloc(GetProcessHeap(), 0, size);
+  if (! *utf16) return 2;
+
+  if (utf16len) *utf16len = (unsigned long) len;
+  memmove(*utf16, unicode, size);
+
+  return 0;
+}
+
+int from_utf8(const char *utf8, TCHAR **buffer, unsigned long *buflen) {
+#ifdef UNICODE
+  return to_utf16(utf8, buffer, buflen);
+#else
+  return to_utf8(utf8, buffer, buflen);
+#endif
+}
+
+int from_utf16(const wchar_t *utf16, TCHAR **buffer, unsigned long *buflen) {
+#ifdef UNICODE
+  return to_utf16(utf16, buffer, buflen);
+#else
+  return to_utf8(utf16, buffer, buflen);
+#endif
+}

+ 13 - 0
utf8.h

@@ -0,0 +1,13 @@
+#ifndef UTF8_H
+#define UTF8_H
+
+void setup_utf8();
+void unsetup_utf8();
+int to_utf8(const wchar_t *, char **, unsigned long *);
+int to_utf8(const char *, char **, unsigned long *);
+int to_utf16(const char *, wchar_t **utf16, unsigned long *);
+int to_utf16(const wchar_t *, wchar_t **utf16, unsigned long *);
+int from_utf8(const char *, TCHAR **, unsigned long *);
+int from_utf16(const wchar_t *, TCHAR **, unsigned long *);
+
+#endif