source: trunk/t3q/nsis/EnvVarUpdate.nsh @ 47

Last change on this file since 47 was 7, checked in by phdmakk, 14 years ago
File size: 10.4 KB
Line 
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 
81Function ${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 
319FunctionEnd
320 
321!macroend   ; EnvVarUpdate UN
322!insertmacro EnvVarUpdate ""
323!insertmacro EnvVarUpdate "un."
324;----------------------------------- EnvVarUpdate end----------------------------------------
325 
326!verbose pop
327!endif
Note: See TracBrowser for help on using the repository browser.