Browse Source

Allow adding or removing individual environment variables.

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
Iain Patterson 6 years ago
parent
commit
3e92dce871
2 changed files with 79 additions and 8 deletions
  1. 37 3
      README.txt
  2. 42 5
      settings.cpp

+ 37 - 3
README.txt

@@ -638,9 +638,10 @@ would have the same effect.
 
 Non-standard parameters
 -----------------------
-The AppEnvironment and AppEnvironmentExtra parameters recognise an
-additional argument when querying the environment.  The following syntax
-will print all extra environment variables configured for a service
+The AppEnvironment, AppEnvironmentExtra and Environment parameters
+recognise an additional argument when querying the environment.  The
+following syntax will print all extra environment variables configured
+for a service
 
     nssm get <servicename> AppEnvironmentExtra
 
@@ -655,6 +656,39 @@ KEY=VALUE pair in separate command line arguments.  For example:
 
     nssm set <servicename> AppEnvironment CLASSPATH=C:\Classes TEMP=C:\Temp
 
+Alternatively the KEY can be prefixed with a + or - symbol to respectively
+add or remove a pair from the block.
+
+The following two lines set CLASSPATH and TEMP:
+
+    nssm set <servicename> AppEnvironment CLASSPATH=C:\Classes
+    nssm set <servicename> AppEnvironment +TEMP=C:\Temp
+
+If the key is already present, specifying +KEY will override the value
+while preserving the order of keys:
+
+    nssm set <servicename> AppEnvironment +CLASSPATH=C:\NewClasses
+
+The following syntax removes a single variable from the block while
+leaving any other variables in place.
+
+    nssm set <servicename> AppEnvironment -TEMP
+
+Specifying -KEY=VALUE will remove the variable only if the existing
+value matches.
+
+The following syntax would not remove TEMP=C:\Temp
+
+    nssm set <servicename> AppEnvironment -TEMP=C:\Work\Temporary
+
+The + and - symbols are valid characters in environment variables.
+The syntax :KEY=VALUE is equivalent to KEY=VALUE and can be used to
+set variables which start with +/- or to explicitly reset the block in
+a script:
+
+    nssm set <servicename> AppEnvironment :CLASSPATH=C:\Classes
+    nssm set <servicename> AppEnvironment +TEMP=C:\Temp
+
 
 The AppExit parameter requires an additional argument specifying the exit
 code to get or set.  The default action can be specified with the string

+ 42 - 5
settings.cpp

@@ -339,17 +339,54 @@ static int setting_set_environment(const TCHAR *service_name, void *param, const
   HKEY key = (HKEY) param;
   if (! param) return -1;
 
-  if (! value || ! value->string || ! value->string[0]) {
+  TCHAR *string = 0;
+  TCHAR *unformatted = 0;
+  unsigned long envlen;
+  unsigned long newlen = 0;
+  int op = 0;
+  if (value && value->string && value->string[0]) {
+    string = value->string;
+    switch (string[0]) {
+      case _T('+'): op = 1; break;
+      case _T('-'): op = -1; break;
+      case _T(':'): string++; break;
+    }
+  }
+
+  if (op) {
+    string++;
+    TCHAR *env = 0;
+    if (get_environment((TCHAR *) service_name, key, (TCHAR *) name, &env, &envlen)) return -1;
+    if (env) {
+      int ret;
+      if (op > 0) ret = append_to_environment_block(env, envlen, string, &unformatted, &newlen);
+      else ret = remove_from_environment_block(env, envlen, string, &unformatted, &newlen);
+      if (envlen) HeapFree(GetProcessHeap(), 0, env);
+      if (ret) return -1;
+
+      string = unformatted;
+    }
+    else {
+      /*
+        No existing environment.
+        We can't remove from an empty environment so just treat an add
+        operation as setting a new string.
+      */
+      if (op < 0) return 0;
+      op = 0;
+    }
+  }
+
+  if (! string || ! string[0]) {
     long error = RegDeleteValue(key, name);
     if (error == ERROR_SUCCESS || error == ERROR_FILE_NOT_FOUND) return 0;
     print_message(stderr, NSSM_MESSAGE_REGDELETEVALUE_FAILED, name, service_name, error_string(error));
     return -1;
   }
 
-  unsigned long envlen = (unsigned long) _tcslen(value->string) + 1;
-  TCHAR *unformatted = 0;
-  unsigned long newlen;
-  if (unformat_double_null(value->string, envlen, &unformatted, &newlen)) return -1;
+  if (! op) {
+    if (unformat_double_null(string, (unsigned long) _tcslen(string), &unformatted, &newlen)) return -1;
+  }
 
   if (test_environment(unformatted)) {
     HeapFree(GetProcessHeap(), 0, unformatted);