Archive: Is it possible to do a search and replace on certain files?


Is it possible to do a search and replace on certain files?
I've just finished compiling a project consisting of 9,113 files. 79 of them have to be configured during installation in order for the applications to launch and function correctly.

A few of the most common customizations needed are...

1. Absolute system paths.
2. End User Profile.
4. etc...

My question is, is NSIS able to perform a search and replace for a marker within a file; marker names of @@marker@@ or %%marker%% or <marker>...

I would like to add a *few* custom screens which will ask for this information. A user should enter the correct information and upon hitting the submit button the value in the field replaces the markers in the files...

Some files will have more than 30 markers... Some are the same while some are different.

I am currently using HM NIS Edit 1.3 and I believe this to be an awesome application with incredible potential. A very good port of the Inno setup wizard and a very interesting .ini form designer.

I haven't the slightest clue though about how to implement the form created in the .ini to appear in a brand new modern user interface. To cover this problem with a cherry on top I haven't the slightest clue about how to map markers in files (if possible).

I checked the installoption example and it looks interesting but it leaves me hanging because the truth is I haven't the slightest clue to building an installer with NSIS. Another fact is, it gets even more complicated in trying to port the example from a tiny user interface to a modern user interface...

Can someone please write a guide on this feature for everyone to benefit from? Can someone be kind enough to help me a little further with this by providing a simpler example which works with the MUI? Also, if replacing markers is a possibility can someone please be kind enough to help in providing some steps to acheiving this?

I just applied for a sourceforge account and would make thanks to anyone who helps me with this regardless of whether it gets accepted or not. Much appreciation and thanks for anyone who reads this entire post :)

Thank you for your time


Well for the search part use the instruction "IfFileExists"


If you haven't the slightest clue about NSIS you should start with the tutorial ;) Open makensis.htm in your NSIS directory or go to http://nsis.sf.net/Docs and start reading.

To show custom designed pages with the MUI see the Examples\Modern UI\InstallOptions.nsi example.

To replace markers in the file see useful functions section in The Archive, it contains more than one function that matches your request.

Have I missed anything? :)

Oh yes, of course... Welcome to the forum :D


Thank you :)
Thank you kichik :)

I know sometimes we all need a kick in the right direction so I went to sleep to help clear my mind. This morning I got your message and I said I can do this!

I think I did but have a question...

I added four custom dialog boxes... They all seem to atleast appear without problems. The script builds flawlessly. I had a little trouble with the concept of giving the custom windows titles but I figured it out...

It all looks good but how I am duplicating these functions have me a little concerned. I am incrementing them... RabbitHole, RabbitHole1, RabbitHole2, etc...

One value which is staying the same across all functions and which hasn't presented a problem yet is the "Push $R0" and "Pop $R0"... Should I increment them too (e.g. "Push $R1" "Pop$R1)?

Thank you so much, I think I made it harder than it was but thanks so much for the kick in the right direction :)


The best way to understand Push Pop and Exch is to look at functions on the nsis archive.
That is how I understood Exch (using multiple Exch's to get multiple values from off the stack)
Push is used to save variables and then those variables can be used within the script.
Using Pop at the ens of the script returns the varianbles to the same value as before the function was called.

-Stu


There is a tutorial in The Archive about the stack (Push, Pop and Exch). The short version is you don't need to change $R0 to $R1, etc. But you should read the tutorial to know better.


Ok, I feel I accomplished a lot. Thank you to everyone with the wise words of wisdom for me.

Now basically, I am chasing just one prize in which I feel involves more than what I have in mind. I've created the four INI files I need, and have customized (*only the appearance*) of all the INI files in preparation to *collect* the required user input.

The script builds and runs perfectly. Here is an example of what I am trying to do. I looked at the archive but need either a simpler solution or a simpler example.

1. The First INI file collects the users name, age and number.
2. I have a text file which needs this information fed into it dynamically before the install finishes.
3. The markers appear more than once in the same text file...

In other words, the collected information from the customized .ini screen needs to replace markers in the text file...

I know I can build from a simpler example as I have dozens and dozens of markers and files. Can someone please provide a very simple example on how to find and replace markers by collecting information from a .ini file *AND* getting it to replace markers in a text file?

The information does *not* need to be validated...

Someone please help me out, thank you for your time.


Most archive pages contain examples. Take this one for example.

To read the values from the INI file use ReadIniStr or the MUI_INSTALLOPTIONS_READ macro if you're using the MUI (double check on this name, I'm not sure it's the right one).

To combine both, lets assume you've read the INI value into $0 then you use something like Push $0 or just put $0 at the right position according to the example of the function.


I just want to say thanks Kichik :) I haven't quite got the time at the moment but it is on my priority list to check it out in a few hours.

I am currently speaking with a very good programmer at the moment. I will let you know how things go as I am not afraid of messing with the code.

Thanks again and btw, I am using the MUI... I hope it works :)


I found the ReadIniStr in the scripting reference but couldn't find MUI_INSTALLOPTIONS_READ -OR- StrReplace -OR- StrReplace.nsh...

Assuming so far ReadIniStr is a step in the right direction how exactly would I apply it to my script? Does it go above or below sections? Above or below functions?

Also this is how the references refers to it

-----------------------------------------------------
user_var(output) ini_filename section_name entry_name
-----------------------------------------------------

I have an INI file named UserProfile.INI I don't see any sections in it but do see fields... I assume the entry_name is something like text=...

I assume I apply the above code into my script in this manner...

-----------------------------------------------------------
user_var(output) UserProfile.INI [Field 1] Text=
-----------------------------------------------------------

True or False?

I hope this is indeed a step in the right direction. I just need to know where it gets placed and the format of the string.

Thank you for any help on this :)


For information about the Modern UI and its macro's, see Contrib\Modern UI\Readme.html.

MUI_INSTALLOPTIONS_READ automatically uses the plug-ins directory (it just makes it a little easier). The plug-ins directory (a temporary directory) is the place where the Modern UI stores the INI files (extracted using MUI_INSTALLOPTIONS_EXTRACT).

The section name is "Field 1", the entry name is "Text".


StrReplace is in the Archive too, use the search link on the top right corner of the screen.

MUI_INSTALLOPTIONS_READ is indeed the right name of the macro. Search for it in the MUI readme (Appendix D or something like that in the documentation).

You've almost got it right regarding ReadIniStr. It goes like this:

[section]
entry=value

ReadIniStr should be used like this:

ReadINIStr $var Path\to\inifile.ini "section name without the brackets" "entry name without the equal sign"

For example:

ReadINIStr $0 "$PLUGINSDIR\myIni.ini" "Field 1" "State"

You should use it wherever you want to use the value. If you want to use the text replacement functions in sections then you should read it in the section and then use it. It's recommended that use it in the sections because those are executed after the user clicks Install. If you execute them before that they will replace the text before the user actually gave his/her permission to install the program.


I am trying my fastest to learn as much as possible and keep at this thread while it is still hot.

I believe the MUI_INSTALLOPTIONS_READ works in conjunction with the MUI_INSTALLOPTIONS_WRITE and will only work in replacing variables located in the INI itself? Not sure just asking...

Or, are the two following pieces of code the same thing, except one is more enhanced and/or user friendly in regards to building a MUI?

-----------------------------------------------------------------
ReadINIStr $0 "$PLUGINSDIR\myIni.ini" "Field 1" "State"
-----------------------------------------------------------------
-----------------------------------------------------------------
!insertmacro MUI_INSTALLOPTIONS_READ $VAR "ioFile.ini" "Field 1" "Value Name"
-----------------------------------------------------------------

On the MUI line is $VAR equal to $0? I assume I replace the "ioFile.ini" on the MUI line with "myIni.ini"...

In the end using the MUI line is best in regards to building a MUI or should I stick with ReadINIStr and will it work?

Heres is the modified line for the MUI

-----------------------------------------------------------------
!insertmacro MUI_INSTALLOPTIONS_READ $0 "myIni.ini" "Field 1" "State"
-----------------------------------------------------------------

Is this correct and is using the MUI line more advised than using ReadINIStr in building an MUI?

I suare a thousand times all of your help is really appreciated. Thank you to everyone for their knowledge and expertise in this field.

Best Regards


!insertmacro MUI_INSTALLOPTIONS_READ $0 "myIni.ini" "Field 1" "State"

is the correct way. $var doesn't mean anything, it was just a place holder. The line above does exactly the same thing as:

ReadINIStr $0 "$PLUGINS\myIni.ini" "Field 1" "State"

The MUI macro is just an easier, more future safe (in case MUI_INSTALLOPTIONS_EXTRACT will change) version.


I am really trying but to be honest I am getting really annoyed and this whole project is quite sickening at the install stage. :igor:

No offense, no slap in the face, I believe NSIS is awesome, I thank everyone so much for their time, its just making me feel so dumb.

I read and reread the StrReplace and ReplaceInFile steps at the archive. I re-reread them and still cannot get it to work... Even if I do get it to work, this only proves it'll get harder as now I have to somehow get it to work in accepting the values on the customized screen to applying those values in over 79 files...

I am stuck in mud at the moment... Here is my sad attempt at simply trying to get the ReplaceInFile to work following the ReplaceInFile instructions...

I copied both scripts "StrReplace & ReplaceInFile" from the archive and applied the NSH extension and have dropped them in my include folder.

I applied the following snippet directly beneath !include "MUI.nsh" located right at the very top of my script...
----------------------------
!include StrReplace.nsh
!include ReplaceInFile.nsh
----------------------------

I made a build and got two warnings... I surrounded them in quotes and I still got the two warnings...
----------------------------
!include "StrReplace.nsh"
!include "ReplaceInFile.nsh"
----------------------------

Here is the warning...
------------------------------------------------------------------
2 warnings:
Name: specified multiple times, wasting space (macro:MUI_LANGUAGEFILE_NSISCOMMAND:2)
install function "RIF" not referenced - zeroing code (57-105) out
------------------------------------------------------------------

I create the builds early to try and keep track of what is going wrong and where... I know I should probably get a warning but its really to test and see where the building process will stop or mess up...

The rest of the snippet states this is all I have left to work with but it doesn't tell me exactly where to apply it... I feel I tried everywhere but feel dumb because I know I didn't... I just tried in so many other places instead...

------------------------------------------------------------------
[...]
!insertmacro ReplaceInFile SOURCE_FILE SEARCH_TEXT REPLACEMENT
------------------------------------------------------------------

What is this [...]? The build stops there completely... I'll remove it and work with the rest of it...

I created a test file named misc.ini located in the NSIS directory.
------------------------------------------------------------------
!insertmacro ReplaceInFile "misc.ini" "crackdown" "crack up and fall down"
------------------------------------------------------------------

Creating the build leaves me with one warning...
------------------------------------------------------------------
1 warning:
Name: specified multiple times, wasting space (macro:MUI_LANGUAGEFILE_NSISCOMMAND:2)
------------------------------------------------------------------

Running the build goes smooth until the actual installing phase... a little dialog box always pops up and says "C:\thy documents\thy files\prob"

Talk about irritating... I cannot get around it... There is no C:\thy... on my system... I hit OK...

I go and check the file and it did indeed replace crackdown... Just three questions though...

1. How do I get around my last warning... I don't like it...
2. How do I prevent that little irritating dialog box from popping up?
3. How do I begin to map collected information from a customized screen to an actual file?

Sorry for my long post, I am simply trying my best *not* to state "it doesn't work, please help" and letting you know what I've tried.

Thank you for your time


Did you add a "Name" command to your script? The Modern UI adds one automatically (based on MUI_PRODUCT and MUI_VERSION), so you should not add one.


Hello Joost Verburg,

I am not really sure. I created a script using the HM Wizard and then began building from their... So far I managed to include two customized screens in which pop up first... I don't think I added an extra name...

I've attached the actual 4kb zip file I am working with. Hopefully maybe you or anyone can look it over and tell me where is it I am going wrong so far... Every file in the zip is just sort of my class room files... I am not trying to expand on it until I know how to do it comfortably...

Thank you for your time :)


Sorry, I previewed my post and then the attachment didn't attach... Here it is now... Thank you again :)


The problem is that you've copied into the nsh files the entire example scripts and not only the functions. That is why you've got all of those warnings, weird messages and weird dialogs.


On the ReplaceInFile the instructions clearly state to do that. In short it said "I suggest you save the following macro and the function together in one file..."

I did that for both files. I just noticed though in the StrReplace file (thanks Kichik) the probable lines which caused for the dialog box and errors you were referring too.

Delete this from StrReplace?
----------------------------------------------------
outfile StrReplace.exe
name StrReplace

section
Push "C:\my documents\my files\prob" ;original string
Push "\m" ;needs to be replaced
Push "\th" ;will replace wrong characters
Call StrReplace
Pop $0
MessageBox MB_OK $0
sectionend
----------------------------------------------------

I did and it builds just fine... No errors, no dialog boxes... Sorry, sometimes you work so hard and start to over look the obvious...

OK, so now to help complete my task in its entirety... Can you or someone please be kind enough to show me an example on how to use the
StrReplace & the ReplaceInFile to work with collecting information from the user and then applying it to certain files?

Am I close or still far away on this?

Please, I am just trying to make my project easier on end users.

The custom screens will collect information that is to replace markers located in 79 files... Please just show me an example on one file?

Thank you


On the ReplaceInFile the instructions clearly state to do that. In short it said "I suggest you save the following macro and the function together in one file..."
Yes but it doesn't say copy the example scripts like KiCHiK suggests you've done.

"Following function and macro..." apply to that page, not to the StrReplace page. You only need the function from the StrReplace page, nothing else.

You're close, you don't need an example. There are enough examples in those archive pages. Just use ReadINIStr / MUI_INSTALLOPTIONS_READ as instructed above and then insert the replace in file macro like instructed in the archive page.


I admitted to my mistake in the 2nd paragraph of my last reply. I admitted I undoubtedly overlooked it. I publicly apologize for any confusion I may have caused.

My greatest concern is collecting information from a custom screen and then applying that collected information into certain files.

Please show me an example...

I understand replacing markers in files using the ReplaceInFile method but that would make absolutely no sense and be completely barabic to even waste everyones time if I could predict the values...

My point is, how do I get the collected value to dynamically replace the ReplaceInFile value? If it easy and anyone thinks this is a piece of cake, I ask to please help me and show me an example.

I do not understand (I really don't) how to dynamically replace the ReplaceInFile value... Please, I really don't know how to do it. Please show me an example.

Please show me an example. Please. Thank you.


Open Examples\Modern UI\InstallOptions.nsi and put this in line number 87:

!insertmacro ReplaceInFile "$INSTDIR\myfile.ini" "@marker@" "${TEMP}"

This will replace every @marker@ in $INSTDIR\myfile.ini with 0 or 1 according to the checkbox selection on custom page number 3 (ioC.ini).


I had to add the !includes at top... I created a myfile.ini... I put your code on line 87 and all that happens is all occurences of the @marker@ in myfile.ini are replaced with nothing... no 0 or 1. But all occurences of @marker@ are deleted...

I am losing it... I don't wish to be a professional installer, I just want to package up my project and make it easier on end users... I think to be flat out honest taking this route with NSIS is a route I will ultimately regret...

No one get me wrong, I thank anyone who says hello on this post... Just everyone has either a short changed answer or everyone so far thinks I am a geek at building installations and don't have the time to better explain an example to me as if I were a child...

I think I achieved a lot but it seems I will go no where fast as this is more than complicated and I am simply too frustrated with it. I am pretty certain if I were a geek and took up building installations with NSIS at MIT I'd probably consider NSIS to be a 5 star program.

Unfortunately I am no professional lingo artist in this field and am really beginning not to care anymore for it...

Truth is I really do wish to proceed but I feel no one really wants to truly help rather than make a post...

I know I regret saying this already but I figure I will rant my frustrations without acting too much like a kid about it... I feel a little better now... No one has to help me anymore on this... Though it would be nice...

Here is a wish rather than a request... Can a GOD take my zip package from a few post ago and fix it so that it does as I've been asking... Can the GOD please post it back here for everyone who might need it one day to benefit from?

Thank you, I am still just frustrated, forgive me...


It's really simple...

Section "Replace @marker@"
!insertmacro MUI_INSTALLOPTIONS_READ $0 myIni.ini "Field 4" "State"
!insertmacro ReplaceInFile "$INSTDIR\myotherfile.ini" "@marker@" "$0"
SectionEnd


Do whatever you want with it. I have no time to write the script for you.

I am sincerely sorry for my earlier attitude between the lines. I am certain we've all been their at one point. I am not stupid but really felt if it was as simple as Kichiks last post someone should have just said to me "work with this"...

Kichik it works flawlessly, across all screens, on all fields, on all the test files I've so far worked with. It really works as I hoped it would. It is perfect.

I have just one more question I feel could just provide the icing on the cake for me. It seems I get all of these .old files as part of the installtion. I read they were supposed to be deleted but it seems they just go in as part of the installation and stay there...

How do I prevent them from being a part of the installation or from staying in the package after install?

Thank you so much, sorry for my attitude, Kichik, you certainly have a place in my thank you credits.

Thanks again and sorry for my rant.


Maybe you can make a batch file to remove 'em before you generate the installer, or you can use Delete after installing.


I can create a batch file with orders to erase files but is it possible to have the installer do it automatically?


Replace these lines in the RIF function:

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


with:

Delete $2


and you will have no .old files.

Kichik, that last line of code takes care of the .old files as requested. Thank you so much for everything. Sorry for breaking earlier :(


I know in my last post I said I have just one more question *but* I have just one more and I promise once this is solved my search and replace mission is over and I will move on.

I have many markers in my files in which require to be replaced with an absolute path (e.g. @@AbsolutePath@@). I was hoping I could take the absolute path from the "Destination Folder" field at the install location screen.

The trick though is not just getting the path from the "Destination Folder" but also reverting its "\" with "/"... I can get the user to enter this information manually but was hoping I could do it for them automatically.

So the Destination Folder looks like this...
C:\Program Files\My Application

But, when the user clicks install all markers in my files will then look like this...
C:/Program Files/My Application

I am really hoping this is not too hard. Please help me with just this last bit of code and I will be out of everyones hair in regards to search and replace.

Thank you so much as this is so important to me to get this last task out of the way.

Thank you


Always search the Archive :)

Here it is: http://nsis.sourceforge.net/archive/...php?pageid=136


Thank you Joost,

I insert this piece into my NSIS project script?

Push String to do replacement in (haystack)
Push String to replace (needle)
Push Replacement
Call StrRep
Pop $R0 result


And it is the below function I will save as an NSI script in my projects directory?

; Push $filenamestring (e.g. 'c:\this\and\that\filename.htm')
; Push "\"
; Call StrSlash
; Pop $0
; $0 == 'c:/this/and/that/filename.htm'
Function StrSlash
Exch $R3 ; $R3 = needle ("\" or "/")
Exch
Exch $R1 ; $R1 = String to replacement in (haystack)
Push $R2 ; Replaced haystack
Push $R4 ; $R4 = not $R3 ("/" or "\")
Push $R6
Push $R7 ; Scratch reg
StrCpy $R2 ""
StrLen $R6 $R1
StrCpy $R4 "\"
StrCmp $R3 "/" loop
StrCpy $R4 "/"
loop:
StrCpy $R7 $R1 1
StrCpy $R1 $R1 $R6 1
StrCmp $R7 $R3 found
StrCpy $R2 "$R2$R7"
StrCmp $R1 "" done loop
found:
StrCpy $R2 "$R2$R4"
StrCmp $R1 "" done loop
done:
StrCpy $R3 $R2
Pop $R7
Pop $R6
Pop $R4
Pop $R2
Pop $R1
Exch $R3
FunctionEnd


Can you please explain besides doing the above how I tie this into getting the value of the install directory and then applying that value to markers located through out various files?

I really am no geek but would very much like to use the NSIS installer as it allows me the freedom to customize the installation for end users. I believe it is very powerful...

Just how do I get the Directory Folder installation value, change all the "\" with "/" and then apply that value to markers through out the installation?

Please help me on this last task... I could ask the end user for the value but I trust NSIS to do it better.

Thank you for your help

Example:

Push $INSTDIR
Push "\"
Call StrSlash
Pop $0
;Now $R0 contains the $INSTDIR with forward slashes

Thank you so much Joost,

Before I run into error I just wish to confirm before moving ahead. Do I apply both codes...

The original snippet

Push String to do replacement in (haystack)
Push String to replace (needle)
Push Replacement
Call StrRep
Pop $R0 result


Your Snippet
Push $INSTDIR
Push "\"
Call StrSlash
Pop $0
;Now $R0 contains the $INSTDIR with forward slashes


or just your snippet instead?

Also do I save the function to an NSH and use it the same way I use the other files "StrReplace.nsh" and "ReplaceInFile.nsh"?

Thank you so much for your patience with me.

There other ones are macro's. You don't have to use a macro for this one.

Use my snippet. Your snippet is for the generic replacer (read the page again).


OK, I just need to confirm this before I find myself doing loops.

I use your snippet, not the other one. I save the function to a StrRep.nsh file in my project folder...

OK, once this is all done, how do I say replace this marker @@AbsolutePath@@ with $INSTDIR and your "SNIPPET", provided I've got the above mentioned solution correct so far?

Once I know a little more about the last step, I feel I can move ahead with experiment, otherwise I know I will simply be asking the same question in just a few moments.

I really am no geek and need to take it just a little slow. I hope you understand. I absolutely appreciate all the help you're giving me, I just need to know the best last step...

How to replace @@AbsolutePath@@ with $INSTDIR and your "SNIPPET"?

Thank you so much for your time I undoubtedly appreciate it all very much.


Just use the variable ($0 in my example). Like kichik said:

!insertmacro ReplaceInFile "$INSTDIR\myotherfile.ini" "@marker@" "$0"

So you have to put the last snippet above this code.


I just tried the following code...

; This snippet should help in replacing the Absolute system paths by replacing "\" with "/".
Push $INSTDIR
Push "\"
Call StrSlash
Pop $0
;Now $R0 contains the $INSTDIR with forward slashes
!insertmacro ReplaceInFile "$INSTDIR\crash.txt" "@AbsolutePath@" "$0"


But it keeps stopping at "Push $INSTDIR" with the following error "Error: Can't add entry, no section or function is open!"

Archive: Is it possible to do a search and replace on certain files?


I've also tried the following

Section "Replace @AbsolutePath@"
; This snippet should help in replacing the Absolute system paths by replacing "\" with "/".
Push $INSTDIR
Push "\"
Call StrSlash
Pop $0
;Now $R0 contains the $INSTDIR with forward slashes
!insertmacro ReplaceInFile "$INSTDIR\crash.txt" "@AbsolutePath@" "$0"
SectionEnd


But I end up with the following error...
Adding plug-ins initializing function... Done!
Error: resolving install function "StrSlash" in section "Replace @AbsolutePath@" (5)
Note: uninstall functions must begin with "un.", and install functions must not
Error - aborting creation process

I solved it Joost! I forgot to insert the !include... Excellent, Thank you so much for your time :) Everyone will get a thank you in my credits :)

Thank you for putting up with me with so far

Thanks again