Allow adding or removing individual environment variables.
authorIain Patterson <me@iain.cx>
Thu, 21 Jul 2016 16:23:21 +0000 (17:23 +0100)
committerIain Patterson <me@iain.cx>
Thu, 28 Jul 2016 15:44:24 +0000 (16:44 +0100)
Specifying an environment string as +KEY=VALUE will append KEY=VALUE to
the existing block, or create a new one if none was previously
configured.  If KEY is already present, +KEY=VALUE will override it in
place.

Specifying -KEY=VALUE will remove KEY=VALUE from the existing block.

Specifying -KEY will remove KEY regardless of its value.

Removing the last key will delete the whole block.

Specifying :KEY=VALUE is equivalent to KEY=VALUE, ie it creates a new
block with only KEY=VALUE present.  Its main purpose is to make scripts
easier to read.

    nssm set <servicename> AppEnvironment :FIRST=one
    nssm set <servicename> AppEnvironment +SECOND=two
    nssm set <servicename> AppEnvironment +THIRD=two

README.txt
settings.cpp

index 2158741..12a8393 100644 (file)
@@ -638,9 +638,10 @@ would have the same effect.
 \r
 Non-standard parameters\r
 -----------------------\r
 \r
 Non-standard parameters\r
 -----------------------\r
-The AppEnvironment and AppEnvironmentExtra parameters recognise an\r
-additional argument when querying the environment.  The following syntax\r
-will print all extra environment variables configured for a service\r
+The AppEnvironment, AppEnvironmentExtra and Environment parameters\r
+recognise an additional argument when querying the environment.  The\r
+following syntax will print all extra environment variables configured\r
+for a service\r
 \r
     nssm get <servicename> AppEnvironmentExtra\r
 \r
 \r
     nssm get <servicename> AppEnvironmentExtra\r
 \r
@@ -655,6 +656,39 @@ KEY=VALUE pair in separate command line arguments.  For example:
 \r
     nssm set <servicename> AppEnvironment CLASSPATH=C:\Classes TEMP=C:\Temp\r
 \r
 \r
     nssm set <servicename> AppEnvironment CLASSPATH=C:\Classes TEMP=C:\Temp\r
 \r
+Alternatively the KEY can be prefixed with a + or - symbol to respectively\r
+add or remove a pair from the block.\r
+\r
+The following two lines set CLASSPATH and TEMP:\r
+\r
+    nssm set <servicename> AppEnvironment CLASSPATH=C:\Classes\r
+    nssm set <servicename> AppEnvironment +TEMP=C:\Temp\r
+\r
+If the key is already present, specifying +KEY will override the value\r
+while preserving the order of keys:\r
+\r
+    nssm set <servicename> AppEnvironment +CLASSPATH=C:\NewClasses\r
+\r
+The following syntax removes a single variable from the block while\r
+leaving any other variables in place.\r
+\r
+    nssm set <servicename> AppEnvironment -TEMP\r
+\r
+Specifying -KEY=VALUE will remove the variable only if the existing\r
+value matches.\r
+\r
+The following syntax would not remove TEMP=C:\Temp\r
+\r
+    nssm set <servicename> AppEnvironment -TEMP=C:\Work\Temporary\r
+\r
+The + and - symbols are valid characters in environment variables.\r
+The syntax :KEY=VALUE is equivalent to KEY=VALUE and can be used to\r
+set variables which start with +/- or to explicitly reset the block in\r
+a script:\r
+\r
+    nssm set <servicename> AppEnvironment :CLASSPATH=C:\Classes\r
+    nssm set <servicename> AppEnvironment +TEMP=C:\Temp\r
+\r
 \r
 The AppExit parameter requires an additional argument specifying the exit\r
 code to get or set.  The default action can be specified with the string\r
 \r
 The AppExit parameter requires an additional argument specifying the exit\r
 code to get or set.  The default action can be specified with the string\r
index f50dcc4..3ed5ec4 100644 (file)
@@ -339,17 +339,54 @@ static int setting_set_environment(const TCHAR *service_name, void *param, const
   HKEY key = (HKEY) param;\r
   if (! param) return -1;\r
 \r
   HKEY key = (HKEY) param;\r
   if (! param) return -1;\r
 \r
-  if (! value || ! value->string || ! value->string[0]) {\r
+  TCHAR *string = 0;\r
+  TCHAR *unformatted = 0;\r
+  unsigned long envlen;\r
+  unsigned long newlen = 0;\r
+  int op = 0;\r
+  if (value && value->string && value->string[0]) {\r
+    string = value->string;\r
+    switch (string[0]) {\r
+      case _T('+'): op = 1; break;\r
+      case _T('-'): op = -1; break;\r
+      case _T(':'): string++; break;\r
+    }\r
+  }\r
+\r
+  if (op) {\r
+    string++;\r
+    TCHAR *env = 0;\r
+    if (get_environment((TCHAR *) service_name, key, (TCHAR *) name, &env, &envlen)) return -1;\r
+    if (env) {\r
+      int ret;\r
+      if (op > 0) ret = append_to_environment_block(env, envlen, string, &unformatted, &newlen);\r
+      else ret = remove_from_environment_block(env, envlen, string, &unformatted, &newlen);\r
+      if (envlen) HeapFree(GetProcessHeap(), 0, env);\r
+      if (ret) return -1;\r
+\r
+      string = unformatted;\r
+    }\r
+    else {\r
+      /*\r
+        No existing environment.\r
+        We can't remove from an empty environment so just treat an add\r
+        operation as setting a new string.\r
+      */\r
+      if (op < 0) return 0;\r
+      op = 0;\r
+    }\r
+  }\r
+\r
+  if (! string || ! string[0]) {\r
     long error = RegDeleteValue(key, name);\r
     if (error == ERROR_SUCCESS || error == ERROR_FILE_NOT_FOUND) return 0;\r
     print_message(stderr, NSSM_MESSAGE_REGDELETEVALUE_FAILED, name, service_name, error_string(error));\r
     return -1;\r
   }\r
 \r
     long error = RegDeleteValue(key, name);\r
     if (error == ERROR_SUCCESS || error == ERROR_FILE_NOT_FOUND) return 0;\r
     print_message(stderr, NSSM_MESSAGE_REGDELETEVALUE_FAILED, name, service_name, error_string(error));\r
     return -1;\r
   }\r
 \r
-  unsigned long envlen = (unsigned long) _tcslen(value->string) + 1;\r
-  TCHAR *unformatted = 0;\r
-  unsigned long newlen;\r
-  if (unformat_double_null(value->string, envlen, &unformatted, &newlen)) return -1;\r
+  if (! op) {\r
+    if (unformat_double_null(string, (unsigned long) _tcslen(string), &unformatted, &newlen)) return -1;\r
+  }\r
 \r
   if (test_environment(unformatted)) {\r
     HeapFree(GetProcessHeap(), 0, unformatted);\r
 \r
   if (test_environment(unformatted)) {\r
     HeapFree(GetProcessHeap(), 0, unformatted);\r