Archive: string replacement fun


string replacement fun
Hi,

I am a new user and have tried a few ways to multiple text replaces in a file. I have checked the macro lib and many Instructor posts. This example is an attempt to use a suggestion in the post http://forums.winamp.com/showthread.php?threadid=205146&highlight=replace

The result of running the following installer is a messagebox with "Error" in it.

; The name of the installer
Name "try"

; The default installation directory
InstallDir $PROGRAMFILES\try

; The file to write
OutFile "try.exe"

;--------------------------------
; Pages
Page directory
Page instfiles
;--------------------------------

!include "TextFunc.nsh"
!insertmacro LineFind
!include "WordFunc.nsh"
!insertmacro WordReplace

; The stuff to install
Section "" ;No components page, name is not important

File /nonfatal web.config

SetOutPath $INSTDIR

${LineFind} "web.conf" "web.conf" "1:-1" "LineFindCallback"

IfErrors 0 +2
MessageBox MB_OK "Error"

;Push "<!--<identity impersonate='true' />-->"
;Push "<identity impersonate='true' />"

WriteUninstaller uninstall.exe

IfErrors 0 +2
MessageBox MB_OK "Error"

SectionEnd ; end the section

Function LineFindCallback
${WordReplace} '$R9' '~/images/' '/images/' '+*' $R9
; ${WordReplace} '$R9' '123' '321' '+' $R9

Push $0
FunctionEnd

Section "Uninstall"

; Remove files and uninstaller
Delete $INSTDIR\try.nsi
Delete $INSTDIR\uninstall.exe

; Remove directories used
RMDir /r "$INSTDIR"

SectionEnd


Another attempt was to use the replace in file function in the macro library. What happened was that the first replace would work, but the second one would not. Even if I flip flopped them. Here is the script for that attempt.

;!include "$PROGRAMFILES\NSIS\Include\StrReplace.nsh"

; The name of the installer
Name "try"

; The default installation directory
InstallDir $PROGRAMFILES\try

; The file to write
OutFile "try.exe"

;--------------------------------
; Pages
Page directory
Page instfiles
;--------------------------------

!include "${NSISDIR}\Include\LogicLib.nsh"
!define StrRep "!insertmacro StrRep"

!macro StrRep ResultVar String SubString RepString
Push "${String}"
Push "${SubString}"
Push "${RepString}"
Call StrRep
Pop "${ResultVar}"
!macroend

Function RIF

ClearErrors ; want to be a newborn

Exch $0 ; REPLACEMENT
Exch
Exch $1 ; SEARCH_TEXT
Exch 2
Exch $2 ; SOURCE_FILE

Push $R0 ; SOURCE_FILE file handle
Push $R1 ; temporary file handle
Push $R2 ; unique temporary file name
Push $R3 ; a line to sar/save
Push $R4 ; shift puffer

IfFileExists $2 +1 RIF_error ; knock-knock
FileOpen $R0 $2 "r" ; open the door

GetTempFileName $R2 ; who's new?
FileOpen $R1 $R2 "w" ; the escape, please!

RIF_loop: ; round'n'round we go
FileRead $R0 $R3 ; read one line
IfErrors RIF_leaveloop ; enough is enough
RIF_sar: ; sar - search and replace
Push "$R3" ; (hair)stack
Push "$1" ; needle
Push "$0" ; blood
Call StrRep ; do the bartwalk
StrCpy $R4 "$R3" ; remember previous state
Pop $R3 ; gimme s.th. back in return!
StrCmp "$R3" "$R4" +1 RIF_sar ; loop, might change again!
FileWrite $R1 "$R3" ; save the newbie
Goto RIF_loop ; gimme more

RIF_leaveloop: ; over'n'out, Sir!
FileClose $R1 ; S'rry, Ma'am - clos'n now
FileClose $R0 ; me 2

Delete "$2.old" ; go away, Sire
Rename "$2" "$2.old" ; step aside, Ma'am
Rename "$R2" "$2" ; hi, baby!

ClearErrors ; now i AM a newborn
Goto RIF_out ; out'n'away

RIF_error: ; ups - s.th. went wrong...
SetErrors ; ...so cry, boy!

RIF_out: ; your wardrobe?
Pop $R4
Pop $R3
Pop $R2
Pop $R1
Pop $R0
Pop $2
Pop $0
Pop $1

FunctionEnd

!macro ReplaceInFile SOURCE_FILE SEARCH_TEXT REPLACEMENT
Push "${SOURCE_FILE}"
Push "${SEARCH_TEXT}"
Push "${REPLACEMENT}"
Call RIF
!macroend



Function StrRep
/*After this point:
------------------------------------------
$R0 = RepString (input)
$R1 = SubString (input)
$R2 = String (input)
$R3 = RepStrLen (temp)
$R4 = SubStrLen (temp)
$R5 = StrLen (temp)
$R6 = StartCharPos (temp)
$R7 = TempStrL (temp)
$R8 = TempStrR (temp)*/

;Get input from user
Exch $R0
Exch
Exch $R1
Exch
Exch 2
Exch $R2
Push $R3
Push $R4
Push $R5
Push $R6
Push $R7
Push $R8

; Return "String" if "SubString" is ""
${IfThen} $R1 == "" ${|} Goto Done ${|}

;Get "RepString", "String" and "SubString" length
StrLen $R3 $R0
StrLen $R4 $R1
StrLen $R5 $R2
;Start "StartCharPos" counter
StrCpy $R6 0

;Loop until "SubString" is found or "String" reaches its end
${Do}
;Remove everything before and after the searched part ("TempStrL")
StrCpy $R7 $R2 $R4 $R6

;Compare "TempStrL" with "SubString"
${If} $R7 == $R1
;Split "String" to replace the string wanted
StrCpy $R7 $R2 $R6 ;TempStrL

;Calc: "StartCharPos" + "SubStrLen" = EndCharPos
IntOp $R8 $R6 + $R4

StrCpy $R8 $R2 "" $R8 ;TempStrR

;Insert the new string between the two separated parts of "String"
StrCpy $R2 $R7$R0$R8
;Now calculate the new "StrLen" and "StartCharPos"
StrLen $R5 $R2
IntOp $R6 $R6 + $R3
${Continue}
${EndIf}

;If not "SubString", this could be "String" end
${IfThen} $R6 >= $R5 ${|} ${ExitDo} ${|}
;If not, continue the loop
IntOp $R6 $R6 + 1
${Loop}

Done:

;Return output to user
StrCpy $R0 $R2

/*After this point:
------------------------------------------
$R0 = ResultVar (output)*/

Pop $R8
Pop $R7
Pop $R6
Pop $R5
Pop $R4
Pop $R3
Pop $R2
Pop $R1
Exch $R0
FunctionEnd



; The stuff to install
Section "" ;No components page, name is not important

; Set output path to the installation directory.
SetOutPath $INSTDIR

File /nonfatal web.config
;!insertmacro ReplaceInFile web.config "<!--<identity impersonate='true' />-->" "<identity impersonate='true' />"
;!insertmacro ReplaceInFile web.config "~/images/" "/images/"
Push "web.config"
Push "~/images/"
Push "/images/"
Call RIF
Push "web.config"
Push "<!--<identity impersonate='true' />-->"
Push "<identity impersonate='true' />"
Call RIF

WriteUninstaller uninstall.exe
SectionEnd ; end the section


Section "Uninstall"

; Remove files and uninstaller
Delete $INSTDIR\try.nsi
Delete $INSTDIR\uninstall.exe

; Remove directories used
RMDir /r "$INSTDIR"

SectionEnd

In this script I just pasted in the text functions. Again the result was no error, but just the first string replacement would work. Any help would be appreciated.

Cheers,
JF


Maybe:

...
SetOutPath $INSTDIR
File /nonfatal web.config

${LineFind} "$INSTDIR\web.conf" "$INSTDIR\web.conf" "1:-1" "LineFindCallback"
...

Also don't forget to use ClearErrors before ${LineFind} because something else in the script before it at run time could be setting the error flag.

-Stu


In that case, it is not necessary, function LineFind have ClearErrors at the beginning. I think if function uses SetErrors command, then to avoid misoperation need to put ClearErrors at the beginning of the function code.


Originally posted by Instructor
Maybe:
...
SetOutPath $INSTDIR
File /nonfatal web.config

${LineFind} "$INSTDIR\web.conf" "$INSTDIR\web.conf" "1:-1" "LineFindCallback"
...
Greetings instructor,

I tried the above suggestion with the same result. After seaching the message boards it doesn't seem as though anyone has had this exact problem before. All I need to do is to do multiple replacements in a file. If this isn't possible, I may not be able to use nsis to assist in our deployments. Is there anything else that I can provide that would be of some help?

Cheers,
JF

I see :) File does not exist because file name is "web.config" not "web.conf"

SetOutPath $INSTDIR
File /nonfatal web.config

${LineFind} "$INSTDIR\web.config" "$INSTDIR\web.config" "1:-1" "LineFindCallback"

Quote:


Excellent, the callback is working now. Thank you.

JF

Originally posted by Instructor
I see :) File does not exist because file name is "web.config" not "web.conf"
SetOutPath $INSTDIR
File /nonfatal web.config

${LineFind} "$INSTDIR\web.config" "$INSTDIR\web.config" "1:-1" "LineFindCallback"