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 9 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
 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
     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
     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
 The AppExit parameter requires an additional argument specifying the exit
 code to get or set.  The default action can be specified with the string
 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;
   HKEY key = (HKEY) param;
   if (! param) return -1;
   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);
     long error = RegDeleteValue(key, name);
     if (error == ERROR_SUCCESS || error == ERROR_FILE_NOT_FOUND) return 0;
     if (error == ERROR_SUCCESS || error == ERROR_FILE_NOT_FOUND) return 0;
     print_message(stderr, NSSM_MESSAGE_REGDELETEVALUE_FAILED, name, service_name, error_string(error));
     print_message(stderr, NSSM_MESSAGE_REGDELETEVALUE_FAILED, name, service_name, error_string(error));
     return -1;
     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)) {
   if (test_environment(unformatted)) {
     HeapFree(GetProcessHeap(), 0, unformatted);
     HeapFree(GetProcessHeap(), 0, unformatted);