github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/build/nsis.envvarupdate.nsh (about)

     1  /**
     2   *  EnvVarUpdate.nsh
     3   *    : Environmental Variables: append, prepend, and remove entries
     4   *
     5   *     WARNING: If you use StrFunc.nsh header then include it before this file
     6   *              with all required definitions. This is to avoid conflicts
     7   *
     8   *  Usage:
     9   *    ${EnvVarUpdate} "ResultVar" "EnvVarName" "Action" "RegLoc" "PathString"
    10   *
    11   *  Credits:
    12   *  Version 1.0
    13   *  * Cal Turney (turnec2)
    14   *  * Amir Szekely (KiCHiK) and e-circ for developing the forerunners of this
    15   *    function: AddToPath, un.RemoveFromPath, AddToEnvVar, un.RemoveFromEnvVar,
    16   *    WriteEnvStr, and un.DeleteEnvStr
    17   *  * Diego Pedroso (deguix) for StrTok
    18   *  * Kevin English (kenglish_hi) for StrContains
    19   *  * Hendri Adriaens (Smile2Me), Diego Pedroso (deguix), and Dan Fuhry
    20   *    (dandaman32) for StrReplace
    21   *
    22   *  Version 1.1 (compatibility with StrFunc.nsh)
    23   *  * techtonik
    24   *
    25   *  http://nsis.sourceforge.net/Environmental_Variables:_append%2C_prepend%2C_and_remove_entries
    26   *
    27   */
    28  
    29  
    30  !ifndef ENVVARUPDATE_FUNCTION
    31  !define ENVVARUPDATE_FUNCTION
    32  !verbose push
    33  !verbose 3
    34  !include "LogicLib.nsh"
    35  !include "WinMessages.NSH"
    36  !include "StrFunc.nsh"
    37  
    38  ; ---- Fix for conflict if StrFunc.nsh is already includes in main file -----------------------
    39  !macro _IncludeStrFunction StrFuncName
    40    !ifndef ${StrFuncName}_INCLUDED
    41      ${${StrFuncName}}
    42    !endif
    43    !ifndef Un${StrFuncName}_INCLUDED
    44      ${Un${StrFuncName}}
    45    !endif
    46    !define un.${StrFuncName} "${Un${StrFuncName}}"
    47  !macroend
    48  
    49  !insertmacro _IncludeStrFunction StrTok
    50  !insertmacro _IncludeStrFunction StrStr
    51  !insertmacro _IncludeStrFunction StrRep
    52  
    53  ; ---------------------------------- Macro Definitions ----------------------------------------
    54  !macro _EnvVarUpdateConstructor ResultVar EnvVarName Action Regloc PathString
    55    Push "${EnvVarName}"
    56    Push "${Action}"
    57    Push "${RegLoc}"
    58    Push "${PathString}"
    59      Call EnvVarUpdate
    60    Pop "${ResultVar}"
    61  !macroend
    62  !define EnvVarUpdate '!insertmacro "_EnvVarUpdateConstructor"'
    63  
    64  !macro _unEnvVarUpdateConstructor ResultVar EnvVarName Action Regloc PathString
    65    Push "${EnvVarName}"
    66    Push "${Action}"
    67    Push "${RegLoc}"
    68    Push "${PathString}"
    69      Call un.EnvVarUpdate
    70    Pop "${ResultVar}"
    71  !macroend
    72  !define un.EnvVarUpdate '!insertmacro "_unEnvVarUpdateConstructor"'
    73  ; ---------------------------------- Macro Definitions end-------------------------------------
    74  
    75  ;----------------------------------- EnvVarUpdate start----------------------------------------
    76  !define hklm_all_users     'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
    77  !define hkcu_current_user  'HKCU "Environment"'
    78  
    79  !macro EnvVarUpdate UN
    80  
    81  Function ${UN}EnvVarUpdate
    82  
    83    Push $0
    84    Exch 4
    85    Exch $1
    86    Exch 3
    87    Exch $2
    88    Exch 2
    89    Exch $3
    90    Exch
    91    Exch $4
    92    Push $5
    93    Push $6
    94    Push $7
    95    Push $8
    96    Push $9
    97    Push $R0
    98  
    99    /* After this point:
   100    -------------------------
   101       $0 = ResultVar     (returned)
   102       $1 = EnvVarName    (input)
   103       $2 = Action        (input)
   104       $3 = RegLoc        (input)
   105       $4 = PathString    (input)
   106       $5 = Orig EnvVar   (read from registry)
   107       $6 = Len of $0     (temp)
   108       $7 = tempstr1      (temp)
   109       $8 = Entry counter (temp)
   110       $9 = tempstr2      (temp)
   111       $R0 = tempChar     (temp)  */
   112  
   113    ; Step 1:  Read contents of EnvVarName from RegLoc
   114    ;
   115    ; Check for empty EnvVarName
   116    ${If} $1 == ""
   117      SetErrors
   118      DetailPrint "ERROR: EnvVarName is blank"
   119      Goto EnvVarUpdate_Restore_Vars
   120    ${EndIf}
   121  
   122    ; Check for valid Action
   123    ${If}    $2 != "A"
   124    ${AndIf} $2 != "P"
   125    ${AndIf} $2 != "R"
   126      SetErrors
   127      DetailPrint "ERROR: Invalid Action - must be A, P, or R"
   128      Goto EnvVarUpdate_Restore_Vars
   129    ${EndIf}
   130  
   131    ${If} $3 == HKLM
   132      ReadRegStr $5 ${hklm_all_users} $1     ; Get EnvVarName from all users into $5
   133    ${ElseIf} $3 == HKCU
   134      ReadRegStr $5 ${hkcu_current_user} $1  ; Read EnvVarName from current user into $5
   135    ${Else}
   136      SetErrors
   137      DetailPrint 'ERROR: Action is [$3] but must be "HKLM" or HKCU"'
   138      Goto EnvVarUpdate_Restore_Vars
   139    ${EndIf}
   140  
   141    ; Check for empty PathString
   142    ${If} $4 == ""
   143      SetErrors
   144      DetailPrint "ERROR: PathString is blank"
   145      Goto EnvVarUpdate_Restore_Vars
   146    ${EndIf}
   147  
   148    ; Make sure we've got some work to do
   149    ${If} $5 == ""
   150    ${AndIf} $2 == "R"
   151      SetErrors
   152      DetailPrint "$1 is empty - Nothing to remove"
   153      Goto EnvVarUpdate_Restore_Vars
   154    ${EndIf}
   155  
   156    ; Step 2: Scrub EnvVar
   157    ;
   158    StrCpy $0 $5                             ; Copy the contents to $0
   159    ; Remove spaces around semicolons (NOTE: spaces before the 1st entry or
   160    ; after the last one are not removed here but instead in Step 3)
   161    ${If} $0 != ""                           ; If EnvVar is not empty ...
   162      ${Do}
   163        ${${UN}StrStr} $7 $0 " ;"
   164        ${If} $7 == ""
   165          ${ExitDo}
   166        ${EndIf}
   167        ${${UN}StrRep} $0  $0 " ;" ";"         ; Remove '<space>;'
   168      ${Loop}
   169      ${Do}
   170        ${${UN}StrStr} $7 $0 "; "
   171        ${If} $7 == ""
   172          ${ExitDo}
   173        ${EndIf}
   174        ${${UN}StrRep} $0  $0 "; " ";"         ; Remove ';<space>'
   175      ${Loop}
   176      ${Do}
   177        ${${UN}StrStr} $7 $0 ";;"
   178        ${If} $7 == ""
   179          ${ExitDo}
   180        ${EndIf}
   181        ${${UN}StrRep} $0  $0 ";;" ";"
   182      ${Loop}
   183  
   184      ; Remove a leading or trailing semicolon from EnvVar
   185      StrCpy  $7  $0 1 0
   186      ${If} $7 == ";"
   187        StrCpy $0  $0 "" 1                   ; Change ';<EnvVar>' to '<EnvVar>'
   188      ${EndIf}
   189      StrLen $6 $0
   190      IntOp $6 $6 - 1
   191      StrCpy $7  $0 1 $6
   192      ${If} $7 == ";"
   193       StrCpy $0  $0 $6                      ; Change ';<EnvVar>' to '<EnvVar>'
   194      ${EndIf}
   195      ; DetailPrint "Scrubbed $1: [$0]"      ; Uncomment to debug
   196    ${EndIf}
   197  
   198    /* Step 3. Remove all instances of the target path/string (even if "A" or "P")
   199       $6 = bool flag (1 = found and removed PathString)
   200       $7 = a string (e.g. path) delimited by semicolon(s)
   201       $8 = entry counter starting at 0
   202       $9 = copy of $0
   203       $R0 = tempChar      */
   204  
   205    ${If} $5 != ""                           ; If EnvVar is not empty ...
   206      StrCpy $9 $0
   207      StrCpy $0 ""
   208      StrCpy $8 0
   209      StrCpy $6 0
   210  
   211      ${Do}
   212        ${${UN}StrTok} $7 $9 ";" $8 "0"      ; $7 = next entry, $8 = entry counter
   213  
   214        ${If} $7 == ""                       ; If we've run out of entries,
   215          ${ExitDo}                          ;    were done
   216        ${EndIf}                             ;
   217  
   218        ; Remove leading and trailing spaces from this entry (critical step for Action=Remove)
   219        ${Do}
   220          StrCpy $R0  $7 1
   221          ${If} $R0 != " "
   222            ${ExitDo}
   223          ${EndIf}
   224          StrCpy $7   $7 "" 1                ;  Remove leading space
   225        ${Loop}
   226        ${Do}
   227          StrCpy $R0  $7 1 -1
   228          ${If} $R0 != " "
   229            ${ExitDo}
   230          ${EndIf}
   231          StrCpy $7   $7 -1                  ;  Remove trailing space
   232        ${Loop}
   233        ${If} $7 == $4                       ; If string matches, remove it by not appending it
   234          StrCpy $6 1                        ; Set 'found' flag
   235        ${ElseIf} $7 != $4                   ; If string does NOT match
   236        ${AndIf}  $0 == ""                   ;    and the 1st string being added to $0,
   237          StrCpy $0 $7                       ;    copy it to $0 without a prepended semicolon
   238        ${ElseIf} $7 != $4                   ; If string does NOT match
   239        ${AndIf}  $0 != ""                   ;    and this is NOT the 1st string to be added to $0,
   240          StrCpy $0 $0;$7                    ;    append path to $0 with a prepended semicolon
   241        ${EndIf}                             ;
   242  
   243        IntOp $8 $8 + 1                      ; Bump counter
   244      ${Loop}                                ; Check for duplicates until we run out of paths
   245    ${EndIf}
   246  
   247    ; Step 4:  Perform the requested Action
   248    ;
   249    ${If} $2 != "R"                          ; If Append or Prepend
   250      ${If} $6 == 1                          ; And if we found the target
   251        DetailPrint "Target is already present in $1. It will be removed and"
   252      ${EndIf}
   253      ${If} $0 == ""                         ; If EnvVar is (now) empty
   254        StrCpy $0 $4                         ;   just copy PathString to EnvVar
   255        ${If} $6 == 0                        ; If found flag is either 0
   256        ${OrIf} $6 == ""                     ; or blank (if EnvVarName is empty)
   257          DetailPrint "$1 was empty and has been updated with the target"
   258        ${EndIf}
   259      ${ElseIf} $2 == "A"                    ;  If Append (and EnvVar is not empty),
   260        StrCpy $0 $0;$4                      ;     append PathString
   261        ${If} $6 == 1
   262          DetailPrint "appended to $1"
   263        ${Else}
   264          DetailPrint "Target was appended to $1"
   265        ${EndIf}
   266      ${Else}                                ;  If Prepend (and EnvVar is not empty),
   267        StrCpy $0 $4;$0                      ;     prepend PathString
   268        ${If} $6 == 1
   269          DetailPrint "prepended to $1"
   270        ${Else}
   271          DetailPrint "Target was prepended to $1"
   272        ${EndIf}
   273      ${EndIf}
   274    ${Else}                                  ; If Action = Remove
   275      ${If} $6 == 1                          ;   and we found the target
   276        DetailPrint "Target was found and removed from $1"
   277      ${Else}
   278        DetailPrint "Target was NOT found in $1 (nothing to remove)"
   279      ${EndIf}
   280      ${If} $0 == ""
   281        DetailPrint "$1 is now empty"
   282      ${EndIf}
   283    ${EndIf}
   284  
   285    ; Step 5:  Update the registry at RegLoc with the updated EnvVar and announce the change
   286    ;
   287    ClearErrors
   288    ${If} $3  == HKLM
   289      WriteRegExpandStr ${hklm_all_users} $1 $0     ; Write it in all users section
   290    ${ElseIf} $3 == HKCU
   291      WriteRegExpandStr ${hkcu_current_user} $1 $0  ; Write it to current user section
   292    ${EndIf}
   293  
   294    IfErrors 0 +4
   295      MessageBox MB_OK|MB_ICONEXCLAMATION "Could not write updated $1 to $3"
   296      DetailPrint "Could not write updated $1 to $3"
   297      Goto EnvVarUpdate_Restore_Vars
   298  
   299    ; "Export" our change
   300    SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
   301  
   302    EnvVarUpdate_Restore_Vars:
   303    ;
   304    ; Restore the user's variables and return ResultVar
   305    Pop $R0
   306    Pop $9
   307    Pop $8
   308    Pop $7
   309    Pop $6
   310    Pop $5
   311    Pop $4
   312    Pop $3
   313    Pop $2
   314    Pop $1
   315    Push $0  ; Push my $0 (ResultVar)
   316    Exch
   317    Pop $0   ; Restore his $0
   318  
   319  FunctionEnd
   320  
   321  !macroend   ; EnvVarUpdate UN
   322  !insertmacro EnvVarUpdate ""
   323  !insertmacro EnvVarUpdate "un."
   324  ;----------------------------------- EnvVarUpdate end----------------------------------------
   325  
   326  !verbose pop
   327  !endif