NSIS Script Parser (made with NSIS)

From NSIS Wiki
Jump to navigationJump to search
Author: Afrow UK (talk, contrib)


Description

For one of my NSIS projects to download and install products from the Internet, I needed some kind of scripting capabilities to perform certain custom tasks on the machine. Some download Zip files contained Dynamic Link Library's that needed to be registered and some registry keys needed to be written.

I decided that NSIS instructions would be ideal for performing these tasks (e.g. RegDll, WriteRegStr etc) and so I began working on a NSIS Script Parser, which is written in NSIS itself. I didn't realise how much work it involved and in the end I decided it would be much better (and more flexible) to write a wrapper for makensis.exe. I stopped working on the NSIS Script Parser, but for future reference I decided to put up what I had started on here. It works, but you're only limited to about 4 NSIS instructions and two of my own which are 'cut down' versions of MessageBox.

NSISScript.nsi

########################################
 
Name    "NSISScript"
OutFile "NSISScript.exe"
XPStyle on
 
########################################
 
Var Var0
Var Var1
Var Var2
Var Var3
Var Var4
Var Var5
Var Var6
Var Var7
Var Var8
 
!define Var0 $Var0
!define Var1 $Var1
!define Var2 $Var2
!define Var3 $Var3
!define Var4 $Var4
!define Var5 $Var5
!define Var6 $Var6
!define Var7 $Var7
!define Var8 $Var8
 
########################################
 
!include _Func.nsh
!include _Parser.nsh
 
########################################
 
Function .onInit
 
 Call GetParameters
  Pop ${Var5}
 
 StrCmp ${Var5} ""              Abort
 IfFileExists ${Var5}         +3
 IfFileExists $EXEDIR\${Var5} 0 Abort
  StrCpy ${Var5} $EXEDIR\${Var5}
 
 SetOutPath $EXEDIR
 FileOpen ${Var6} ${Var5} r
 Loop:
  ClearErrors
  FileRead ${Var6} ${Var1}
  IfErrors Done
 
   Push ${Var1}
    Call TrimNSISJunk
   Pop ${Var1}
 
   Push ${Var1}
    Call ReadNSISInstruction
    Call ExecuteNSISInstruction
 
 Goto Loop
 Done:
 FileClose ${Var6}
 
 Abort: Abort
 
FunctionEnd
 
########################################
 
Section
SectionEnd
 
########################################

_Func.nsh

########################################
 
!macro ExpandNSISVars Var
 Push `${Var}`
  Call ExpandNSISVars
 Pop `${Var}`
!macroend
!define ExpandNSISVars `!insertmacro ExpandNSISVars`
 
Function ExpandNSISVars
 Exch ${Var0}
 
 !macro _ExpandNSISVars VarName Var
  Push ${Var1}
  Push ${Var2}
  Push `${VarName}`
  Push `${Var}`
  Push ${Var0}
   Call StrReplaceV4
  Pop ${Var0}
  Pop ${Var2}
  Pop ${Var1}
 !macroend
 
  !insertmacro _ExpandNSISVars $$0 $0
  !insertmacro _ExpandNSISVars $$1 $1
  !insertmacro _ExpandNSISVars $$2 $2
  !insertmacro _ExpandNSISVars $$3 $3
  !insertmacro _ExpandNSISVars $$4 $4
  !insertmacro _ExpandNSISVars $$5 $5
  !insertmacro _ExpandNSISVars $$6 $6
  !insertmacro _ExpandNSISVars $$7 $7
  !insertmacro _ExpandNSISVars $$8 $8
  !insertmacro _ExpandNSISVars $$9 $9
 
  !insertmacro _ExpandNSISVars $$R0 $R0
  !insertmacro _ExpandNSISVars $$R1 $R1
  !insertmacro _ExpandNSISVars $$R2 $R2
  !insertmacro _ExpandNSISVars $$R3 $R3
  !insertmacro _ExpandNSISVars $$R4 $R4
  !insertmacro _ExpandNSISVars $$R5 $R5
  !insertmacro _ExpandNSISVars $$R6 $R6
  !insertmacro _ExpandNSISVars $$R7 $R7
  !insertmacro _ExpandNSISVars $$R8 $R8
  !insertmacro _ExpandNSISVars $$R9 $R9
 
 Exch ${Var0}
FunctionEnd
 
########################################
 
!macro SetNSISVar Var With
 Push ${Var0}
 Push ${Var1}
 Push `${Var}`
 Push `${With}`
  Call SetNSISVar
 Pop ${Var1}
 Pop ${Var0}
!macroend
!define SetNSISVar `!insertmacro SetNSISVar`
 
Function SetNSISVar
 Exch ${Var0}
 Exch
 Exch ${Var1}
 
 !macro _SetNSISVar Compare UseVar
  StrCmp ${Var1} ${Compare} 0 +3
   StrCpy ${UseVar} ${Var0}
  Goto Done
 !macroend
 
  !insertmacro _SetNSISVar $$0 $0
  !insertmacro _SetNSISVar $$1 $1
  !insertmacro _SetNSISVar $$2 $2
  !insertmacro _SetNSISVar $$3 $3
  !insertmacro _SetNSISVar $$4 $4
  !insertmacro _SetNSISVar $$5 $5
  !insertmacro _SetNSISVar $$6 $6
  !insertmacro _SetNSISVar $$7 $7
  !insertmacro _SetNSISVar $$8 $8
  !insertmacro _SetNSISVar $$9 $9
 
  !insertmacro _SetNSISVar $$R0 $R0
  !insertmacro _SetNSISVar $$R1 $R1
  !insertmacro _SetNSISVar $$R2 $R2
  !insertmacro _SetNSISVar $$R3 $R3
  !insertmacro _SetNSISVar $$R4 $R4
  !insertmacro _SetNSISVar $$R5 $R5
  !insertmacro _SetNSISVar $$R6 $R6
  !insertmacro _SetNSISVar $$R7 $R7
  !insertmacro _SetNSISVar $$R8 $R8
  !insertmacro _SetNSISVar $$R9 $R9
 
 Done:
 Pop ${Var1}
 Pop ${Var0}
FunctionEnd
 
########################################
 
Function StrReplaceV4
Exch ${Var0} #in
Exch 1
Exch ${Var1} #with
Exch 2
Exch ${Var2} #replace
Push ${Var3}
Push ${Var4}
Push ${Var5}
Push ${Var6}
Push ${Var7}
Push ${Var8}
 
 StrCpy ${Var3} -1
 StrLen ${Var5} ${Var0}
 StrLen ${Var6} ${Var1}
 StrLen ${Var7} ${Var2}
 Loop:
  IntOp ${Var3} ${Var3} + 1
  StrCpy ${Var4} ${Var0} ${Var7} ${Var3}
  StrCmp ${Var3} ${Var5} End
  StrCmp ${Var4} ${Var2} 0 Loop
 
   StrCpy ${Var4} ${Var0} ${Var3}
   IntOp ${Var8} ${Var3} + ${Var7}
   StrCpy ${Var8} ${Var0} "" ${Var8}
   StrCpy ${Var0} ${Var4}${Var1}${Var8}
   IntOp ${Var3} ${Var3} + ${Var6}
   IntOp ${Var3} ${Var3} - 1
   IntOp ${Var5} ${Var5} - ${Var7}
   IntOp ${Var5} ${Var5} + ${Var6}
 
 Goto Loop
 End:
 
Pop ${Var8}
Pop ${Var7}
Pop ${Var6}
Pop ${Var5}
Pop ${Var4}
Pop ${Var3}
Pop ${Var2}
Pop ${Var1}
Exch ${Var0} #out
FunctionEnd
 
########################################
 
Function GetParameters
 
  Push $R0
  Push $R1
  Push $R2
  Push $R3
 
  StrCpy $R2 1
  StrLen $R3 $CMDLINE
 
  ;Check for quote or space
  StrCpy $R0 $CMDLINE $R2
  StrCmp $R0 '"' 0 +3
    StrCpy $R1 '"'
    Goto loop
  StrCpy $R1 " "
 
  loop:
    IntOp $R2 $R2 + 1
    StrCpy $R0 $CMDLINE 1 $R2
    StrCmp $R0 $R1 get
    StrCmp $R2 $R3 get
    Goto loop
 
  get:
    IntOp $R2 $R2 + 1
    StrCpy $R0 $CMDLINE 1 $R2
    StrCmp $R0 " " get
    StrCpy $R0 $CMDLINE "" $R2
 
  Pop $R3
  Pop $R2
  Pop $R1
  Exch $R0
 
FunctionEnd
 
########################################
 
Function TrimNSISJunk
Exch ${Var0}
Push ${Var1}
Push ${Var2}
Push ${Var3}
Push ${Var4}
 
 StrLen ${Var1} ${Var0}
 StrCpy ${Var2} -1
 LoopA:
  IntOp ${Var2} ${Var2} + 1
  StrCpy ${Var3} ${Var0} 1 ${Var2}
  IntCmp ${Var2} ${Var1} DoneA 0 DoneA
 
   StrCmp ${Var3} `#` +2
   StrCmp ${Var3} `;` 0 LoopA
 
    IntOp ${Var2} ${Var2} - 1
    StrCpy ${Var0} ${Var0} ${Var2}
 
 DoneA:
 StrCmp ${Var0} "" End
 
 StrLen ${Var1} ${Var0}
 StrCpy ${Var2} -1
 LoopB:
  IntOp ${Var2} ${Var2} + 1
  StrCpy ${Var3} ${Var0} 2 ${Var2}
  IntCmp ${Var2} ${Var1} DoneB 0 DoneB
 
   StrCmp ${Var3} `/*` 0 LoopB
 
    StrCpy ${Var4} ${Var2}
 
 DoneB:
 
 LoopC:
  IntOp ${Var2} ${Var2} + 1
  StrCpy ${Var3} ${Var0} 2 ${Var2}
  IntCmp ${Var2} ${Var1} DoneC 0 DoneC
 
   StrCmp ${Var3} `*/` 0 LoopC
 
    IntOp ${Var2} ${Var2} + 2
    StrCpy ${Var3} ${Var0} ${Var4}
    StrCpy ${Var2} ${Var0} "" ${Var2}
    StrCpy ${Var0} ${Var3}${Var2}
    StrCpy ${Var2} ${Var4}
 
   Goto LoopB
 
 DoneC:
 StrCmp ${Var0} "" End
 
 StrLen ${Var1} ${Var0}
 StrCpy ${Var2} 0
 LoopD:
  IntOp ${Var2} ${Var2} + 1
  StrCpy ${Var3} ${Var0} 1 -${Var2}
  IntCmp ${Var2} ${Var1} DoneD 0 DoneD
 
   StrCmp ${Var3} `$\n` LoopD
   StrCmp ${Var3} `$\r` LoopD
   StrCmp ${Var3} ` `   LoopD
   StrCmp ${Var3} `$\t` LoopD
 
 DoneD:
 IntOp ${Var2} ${Var2} - 1
 StrCpy ${Var0} ${Var0} -${Var2}
 StrCmp ${Var0} "" End
 
 StrLen ${Var1} ${Var0}
 StrCpy ${Var2} -1
 LoopE:
  IntOp ${Var2} ${Var2} + 1
  StrCpy ${Var3} ${Var0} 1 ${Var2}
  IntCmp ${Var2} ${Var1} DoneE 0 DoneE
 
   StrCmp ${Var3} ` `   LoopE
   StrCmp ${Var3} `$\t` LoopE
 
 DoneE:
 StrCpy ${Var0} ${Var0} "" ${Var2}
 
 End:
 
Pop ${Var4}
Pop ${Var3}
Pop ${Var2}
Pop ${Var1}
Exch ${Var0}
FunctionEnd
 
########################################
 
Function ReadNSISInstruction
 Pop ${Var1}
 
 Push "/END"
 
 StrCmp ${Var1} $\n    End
 StrCmp ${Var1} $\r$\n End
 StrLen ${Var4} ${Var1}
 
  StrCpy ${Var2} 0
  LoopBefore:
   IntOp ${Var2} ${Var2} - 1
   IntCmp ${Var2} -${Var4} End End
   StrCpy ${Var0} ${Var1} 1 ${Var2}
   StrCmp ${Var0} `"`   +3
   StrCmp ${Var0} `'`   +2
   StrCmp ${Var0} '`'   0 +5
    StrCpy ${Var5} ${Var0}
    StrCpy ${Var3} ${Var2}
    IntOp ${Var3} ${Var3} - 1
   Goto LoopAfter
   StrCmp ${Var0} ` `   LoopBefore
   StrCmp ${Var0} `$\t` LoopBefore
   StrCmp ${Var0} `$\r` LoopBefore
   StrCmp ${Var0} `$\n` LoopBefore
 
  StrCpy ${Var5} ` `
  StrCpy ${Var3} ${Var2}
  LoopAfter:
   IntOp ${Var2} ${Var2} - 1
   IntCmp ${Var2} -${Var4} 0 0 +3
    IntOp ${Var2} ${Var2} - 1
   Goto PushInstruction
   StrCpy ${Var0} ${Var1} 1 ${Var2}
   StrCmp ${Var0} ${Var5} PushInstruction LoopAfter
 
  PushInstruction:
  IntOp ${Var0} ${Var2} - ${Var3}
  IntOp ${Var0} ${Var0} * -1
  IntOp ${Var3} ${Var2} + 1
  StrCpy ${Var3} ${Var1} ${Var0} ${Var3}
  Push ${Var3}
  Goto LoopBefore
 
 End:
 
FunctionEnd
 
########################################

_Parser.nsh

########################################
 
!macro _ReadRegStr RootKey1 RootKey2
 StrCmp ${Var2} ${RootKey1} +2
 StrCmp ${Var2} ${RootKey2} 0 +3
  ReadRegStr ${Var0} ${RootKey1} `${Var3}` `${Var4}`
 Goto Label${UniqueID}
!macroend
 
!macro ReadRegStr
 
 !define UniqueID ${__LINE__}
 
  Pop ${Var1}
  Pop ${Var2}
  Pop ${Var3}
  ${ExpandNSISVars} ${Var3}
  Pop ${Var4}
  ${ExpandNSISVars} ${Var4}
  Pop ${Var0} # /END
 
  !insertmacro _ReadRegStr HKCR HKEY_CLASSES_ROOT
  !insertmacro _ReadRegStr HKLM HKEY_LOCAL_MACHINE
  !insertmacro _ReadRegStr HKCU HKEY_CURRENT_USER
  !insertmacro _ReadRegStr HKU  HKEY_USERS
  !insertmacro _ReadRegStr HKCC HKEY_CURRENT_CONFIG
  !insertmacro _ReadRegStr HKDD HKEY_DYN_DATA
  !insertmacro _ReadRegStr HKPD HKEY_PERFORMANCE_DATA
  !insertmacro _ReadRegStr SHCTX SHELL_CONTEXT
 
  Label${UniqueID}:
 
   ${SetNSISVar} ${Var1} ${Var0}
 
  Goto Done
 
 !undef UniqueID
 
!macroend
 
########################################
 
!macro _WriteRegStr RootKey1 RootKey2
 StrCmp ${Var1} ${RootKey1} +2
 StrCmp ${Var1} ${RootKey2} 0 +3
  WriteRegStr ${RootKey1} `${Var2}` `${Var3}` `${Var4}`
 Goto Label${UniqueID}
!macroend
 
!macro WriteRegStr
 
 !define UniqueID ${__LINE__}
 
  Pop ${Var1}
  Pop ${Var2}
  ${ExpandNSISVars} ${Var2}
  Pop ${Var3}
  ${ExpandNSISVars} ${Var3}
  Pop ${Var4}
  ${ExpandNSISVars} ${Var4}
  Pop ${Var0} # /END
 
  !insertmacro _WriteRegStr HKCR HKEY_CLASSES_ROOT
  !insertmacro _WriteRegStr HKLM HKEY_LOCAL_MACHINE
  !insertmacro _WriteRegStr HKCU HKEY_CURRENT_USER
  !insertmacro _WriteRegStr HKU  HKEY_USERS
  !insertmacro _WriteRegStr HKCC HKEY_CURRENT_CONFIG
  !insertmacro _WriteRegStr HKDD HKEY_DYN_DATA
  !insertmacro _WriteRegStr HKPD HKEY_PERFORMANCE_DATA
  !insertmacro _WriteRegStr SHCTX SHELL_CONTEXT
 
  Label${UniqueID}:
 
  Goto Done
 
 !undef UniqueID
 
!macroend
 
########################################
 
!macro _DeleteRegKeyEmpty RootKey1 RootKey2
 StrCmp ${Var2} ${RootKey1} +2
 StrCmp ${Var2} ${RootKey2} 0 +3
  DeleteRegKey `/ifempty` ${RootKey1} `${Var3}`
 Goto Label${UniqueID}
!macroend
 
!macro _DeleteRegKey RootKey1 RootKey2
 StrCmp ${Var1} ${RootKey1} +2
 StrCmp ${Var1} ${RootKey2} 0 +3
  DeleteRegKey ${RootKey1} `${Var2}`
 Goto Label${UniqueID}
!macroend
 
!macro DeleteRegKey
 
 !define UniqueID ${__LINE__}
 
  Pop ${Var1}
  Pop ${Var2}
  StrCmp ${Var1} `/ifempty` 0 NoIfEmpty${UniqueID}
  Pop ${Var3}
  ${ExpandNSISVars} ${Var3}
 
  !insertmacro _DeleteRegKeyEmpty HKCR HKEY_CLASSES_ROOT
  !insertmacro _DeleteRegKeyEmpty HKLM HKEY_LOCAL_MACHINE
  !insertmacro _DeleteRegKeyEmpty HKCU HKEY_CURRENT_USER
  !insertmacro _DeleteRegKeyEmpty HKU  HKEY_USERS
  !insertmacro _DeleteRegKeyEmpty HKCC HKEY_CURRENT_CONFIG
  !insertmacro _DeleteRegKeyEmpty HKDD HKEY_DYN_DATA
  !insertmacro _DeleteRegKeyEmpty HKPD HKEY_PERFORMANCE_DATA
  !insertmacro _DeleteRegKeyEmpty SHCTX SHELL_CONTEXT
 
  NoIfEmpty${UniqueID}:
  ${ExpandNSISVars} ${Var2}
 
  !insertmacro _DeleteRegKey HKCR HKEY_CLASSES_ROOT
  !insertmacro _DeleteRegKey HKLM HKEY_LOCAL_MACHINE
  !insertmacro _DeleteRegKey HKCU HKEY_CURRENT_USER
  !insertmacro _DeleteRegKey HKU  HKEY_USERS
  !insertmacro _DeleteRegKey HKCC HKEY_CURRENT_CONFIG
  !insertmacro _DeleteRegKey HKDD HKEY_DYN_DATA
  !insertmacro _DeleteRegKey HKPD HKEY_PERFORMANCE_DATA
  !insertmacro _DeleteRegKey SHCTX SHELL_CONTEXT
 
  Label${UniqueID}:
  Pop ${Var0} # /END
 
  Goto Done
 
 !undef UniqueID
 
!macroend
 
########################################
 
!macro _DeleteRegValue RootKey1 RootKey2
 StrCmp ${Var1} ${RootKey1} +2
 StrCmp ${Var1} ${RootKey2} 0 +3
  DeleteRegValue ${RootKey1} `${Var2}` `${Var3}`
 Goto Label${UniqueID}
!macroend
 
!macro DeleteRegValue
 
 !define UniqueID ${__LINE__}
 
  Pop ${Var1}
  Pop ${Var2}
  ${ExpandNSISVars} ${Var2}
  Pop ${Var3}
  ${ExpandNSISVars} ${Var3}
  Pop ${Var0} # /END
 
  !insertmacro _DeleteRegValue HKCR HKEY_CLASSES_ROOT
  !insertmacro _DeleteRegValue HKLM HKEY_LOCAL_MACHINE
  !insertmacro _DeleteRegValue HKCU HKEY_CURRENT_USER
  !insertmacro _DeleteRegValue HKU  HKEY_USERS
  !insertmacro _DeleteRegValue HKCC HKEY_CURRENT_CONFIG
  !insertmacro _DeleteRegValue HKDD HKEY_DYN_DATA
  !insertmacro _DeleteRegValue HKPD HKEY_PERFORMANCE_DATA
  !insertmacro _DeleteRegValue SHCTX SHELL_CONTEXT
 
  Label${UniqueID}:
 
  Goto Done
 
 !undef UniqueID
 
!macroend
 
########################################
 
!macro AlertBox
 
  Pop ${Var1}
  ${ExpandNSISVars} ${Var1}
  Pop ${Var0} # /END
 
  MessageBox MB_OK|MB_ICONEXCLAMATION ${Var1}
 
  Goto Done
 
!macroend
 
########################################
 
!macro InfoBox
 
  Pop ${Var1}
  ${ExpandNSISVars} ${Var1}
  Pop ${Var0} # /END
 
  MessageBox MB_OK|MB_ICONINFORMATION ${Var1}
 
  Goto Done
 
!macroend
 
########################################
 
Function ExecuteNSISInstruction
 
 Pop ${Var0}
 
 StrCmp ${Var0} ReadRegStr 0 NotReadRegStr
  !insertmacro ReadRegStr
 NotReadRegStr:
 
 StrCmp ${Var0} WriteRegStr 0 NotWriteRegStr
  !insertmacro WriteRegStr
 NotWriteRegStr:
 
 StrCmp ${Var0} DeleteRegKey 0 NotDeleteRegKey
  !insertmacro DeleteRegKey
 NotDeleteRegKey:
 
 StrCmp ${Var0} DeleteRegValue 0 NotDeleteRegValue
  !insertmacro DeleteRegValue
 NotDeleteRegValue:
 
 StrCmp ${Var0} AlertBox 0 NotAlertBox
  !insertmacro AlertBox
 NotAlertBox:
 
 StrCmp ${Var0} InfoBox 0 NotInfoBox
  !insertmacro InfoBox
 NotInfoBox:
 
 Done:
 
FunctionEnd
 
########################################

Example.txt

ReadRegStr $R0 HKCU "Software\ZipCentral" "Extract1"
AlertBox $R0
InfoBox $R0

How to run

Save all the above files and then compile NSISScript.nsi. Change the above registry path to one that you know exists. Create a shortcut to NSISScript.exe and give it Example.txt as a parameter. Double click on the shortcut to run the script code.

-Stu