NSIS FileRead conditional override - conditional-statements

I should please need your help as I am not a programmer (please have mercy with me).
I should need to add in an existing NSIS script a function that does the following:
Checks the presence of a value called 169.254.1.1 into a INI file named myfile.ini and placed in
c:\mydirectory
Should it find this value into myfile.ini it should not do anything else (i.e. let the script do the next steps).
Should it NOT find this value into myfile.ini it should override the file
with another one by silently copying it from c:\dummyfile\myfile.ini
and then let the script do the next steps.
I do not know how to tell NSIS to do this, may I please ask for your help?
Thanks in advance for your expertise.
Meleena.

If your file is an actual .INI file with [sections] then you can just use the INI functions:
Section "Prepare INI example"
InitPluginsDir
WriteIniStr "$PluginsDir\MyFile.ini" ServerInfo ServerAddress "169.254.1.1"
WriteIniStr "$PluginsDir\Dummy.ini" ServerInfo ServerAddress "127.0.0.1"
SectionEnd
!include LogicLib.nsh
Section
ReadIniStr $0 "$PluginsDir\MyFile.ini" ServerInfo ServerAddress
ReadIniStr $1 "$PluginsDir\MyFile.ini" ServerInfo ServerAddressBck
${If} $0 != "169.254.1.1"
${AndIf} $1 != "169.254.1.1"
CopyFiles /SILENT /FILESONLY "$PluginsDir\Dummy.ini" "$PluginsDir\MyFile.ini"
${EndIf}
SectionEnd
If you don't have a real .INI file, just a file with name=value pairs then you have to parse manually:
Section "Prepare fake INI example"
InitPluginsDir
FileOpen $0 "$PluginsDir\MyFile.ini" w
FileWrite $0 'Foo$\r$\n'
FileWrite $0 'Bar$\r$\n'
FileWrite $0 'ServerAddress=169.254.1.1$\r$\n'
FileWrite $0 'Baz$\r$\n'
FileClose $0
WriteIniStr "$PluginsDir\Dummy.ini" ServerInfo ServerAddress "127.0.0.1"
SectionEnd
!include LogicLib.nsh
Function TrimTrailingNewlinesAndSpaces
Exch $1
Push $2
again:
StrCpy $2 $1 "" -1
StrCmp $2 " " +3
StrCmp $2 "$\r" +2
StrCmp $2 "$\n" +1 +3
StrCpy $1 $1 -1
Goto again
Pop $2
Exch $1
FunctionEnd
Section
StrCpy $2 "" ; Have not found the magic line
ClearErrors
FileOpen $0 "$PluginsDir\MyFile.ini" r
loop:
FileRead $0 $1
IfErrors done
Push $1
Call TrimTrailingNewlinesAndSpaces
Pop $1
${If} $1 == "ServerAddress=169.254.1.1"
${OrIf} $1 == "ServerAddressBck=169.254.1.1"
StrCpy $2 1
${Else}
Goto loop
${EndIf}
done:
FileClose $0
${If} $2 = 0
CopyFiles /SILENT /FILESONLY "$PluginsDir\Dummy.ini" "$PluginsDir\MyFile.ini"
${EndIf}
SectionEnd

Related

Is there a way to match a string in a file and print/append the contents of another file (single line) on the next line after string match

I am trying to match a string in a file and print/append the contents of another file after the string match
I have file "addthis" containing single line pleaseaddme:
pleaseaddme
and I have a second file "tothis" containing two lines [one] and [two] like so:
[one]
[two]
I have tried combinations resulting in the following which is close to my desired result:
awk '/\[one\]/ { printf $0; getline < "addthis" }1' tothis
Result:
[one]please add me
[two]
I would like "please add me" to be added to a new line after [one]
like so:
[one]
please add me
[two]
Also this is only printing to the screen and not into the file "tothis"
Have tried numerous variations this as close as I get
You could try with:
>> awk '/\[one\]/ {getline s < "addthis"; $0=$0 "\n" s;} /[^\s]+/{print}' tothis
[one]
pleaseaddme
[two]
If you want to replace in your file you must add the -i inplace:
>> awk -i inplace '/\[one\]/ {getline s < "addthis"; $0=$0 "\n" s;} /[^\s]+/{print}' tothis
>> cat tothis
[one]
pleaseaddme
[two]
If you couldn't use -i inplace, you should achieve the same with:
>> awk '/\[one\]/ {getline s < "addthis"; $0=$0 "\n" s;} /[^\s]+/{print}' tothis > fckmack && mv fckmack tothis
awk '/\[one\]/ {getline var< "addthis"; $0 = $0 ORS var }1' tothis
#=> [one]
#=> pleaseaddme
#=> [two]
First thing you should escape [ and ].
And then read file to a variable, and "append" it to current line.
Another way to do it could be:
awk '/\[one\]/ {print; getline var< "addthis"; print var; next }1' tothis
As of your own attempt, actually change printf to print will work:
awk '/\[one\]/ { print $0; getline < "addthis" }1' tothis
#=> [one]
#=> pleaseaddme
#=> [two]
Because printf won't print ORS but print will.
However on this account, $0 is superfluous as print without parameter will print $0 by default.
As for change in place, you can still redirect to a temp file and replace file later.
Given my awk version on mac this works
awk '/[one]/ {getline s < "addthis"; $0=$0 "\n" s;} /[^\s]+/{print}' tothis > fckmack && mv fckmack tothis

Automaticalli ignore error during NSIS installer and log the error message

I have an installer written in NSIS, and in one of it's part it tries to install some fonts, which fails:
The code part looks like this:
SetOverwrite ifnewer
File ".\target\fonts\*.*"
WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts" "Arial Narrow (TrueType)" "arialn.ttf"
WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts" "Arial Narrow Bold (TrueType)" "arialnb.ttf"
WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts" "Arial Narrow Bold Italic (TrueType)" "arialnbi.ttf"
WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts" "Arial Narrow Italic (TrueType)" "arialni.ttf"
GetTempFileName $R0
File /oname=$R0 ".\target\additions\fonts.dll"
Push "arialn.ttf"
CallInstDLL $R0 registerFont
Push "arialnb.ttf"
CallInstDLL $R0 registerFont
Push "arialnbi.ttf"
CallInstDLL $R0 registerFont
Push "arialni.ttf"
CallInstDLL $R0 registerFont
SetOverwrite on
DetailPrint "Fonts Installed"
This error message is not a big problem for me, so I can always ignore it.
I am wondering, how could I automatically ignore the error message popup for these font installation parts BUT log (DetailPrint) the error message?
That dialog is controlled by SetOverwrite but there is no way to get exactly what you want out of the box.
You need to ditch the File * command and instead handle each file manually.
If you don't care if the new file is older then you can use SetOverwrite try:
!include LogicLib.nsh
!macro TryExtractWithDetailPrint file
SetOverwrite try
ClearErrors
File "${file}"
${If} ${Errors}
DetailPrint 'Could not extract "${file}", ignoring error...'
${EndIf}
SetOverwrite lastused
!macroend
Section
SetOutPath $Fonts
!insertmacro TryExtractWithDetailPrint "c:\myfonts\font1.ttf"
!insertmacro TryExtractWithDetailPrint "c:\myfonts\font2.ttf"
SectionEnd
If you want to take the date stamps into account then you need to extract the new file to a temporary location and then decide if you need to try to overwrite by comparing the new and old files:
!macro Make64 high low result
System::Int64Op "${high}" << 32
IntFmt ${result} "%#x" "${low}" ; Must reformat as hex because we don't want negative numbers to be sign extended
System::Int64Op ${result} |
Pop ${result}
!macroend
!macro CompareFilesLastWrite oldfile newfile result
Push "${newfile}"
Push "${oldfile}"
Call CompareFilesLastWrite
Pop ${result}
!macroend
Function CompareFilesLastWrite
System::Store S
Pop $1 ; oldpath
Pop $2 ; newpath
GetFileTime $2 $R2 $R1
IntOp $R1 $R1 & 0xfc000000 ; Chop off the bottom because of FAT
GetFileTime $1 $2 $1
IntOp $1 $1 & 0xfc000000 ; Chop off the bottom because of FAT
!insertmacro Make64 $2 $1 $1 ; old
!insertmacro Make64 $R2 $R1 $2 ; new
System::Call 'KERNEL32::CompareFileTime(*lr1,*lr2)i.s'
System::Store L
FunctionEnd
!macro TryExtractIfNewer src dst
InitPluginsDir
Push $0
SetDateSave on ; Must be on for this to work
File "/oname=$PluginsDir\temp.tmp" "${src}"
!insertmacro CompareFilesLastWrite "${dst}" "$PluginsDir\temp.tmp" $0
${If} $0 < 0
SetOverwrite try
ClearErrors
File "/oname=${dst}" "${src}"
${If} ${Errors}
DetailPrint 'Could not extract "${dst}", ignoring error...'
${EndIf}
SetOverwrite lastused
${Else}
DetailPrint "Existing file is newer, skipping"
${EndIf}
Pop $0
!macroend
Section
!insertmacro TryExtractIfNewer "myfiles\myfont.ttf" "$fonts\myfont.ttf"
SectionEnd

Find "complete cases" with awk

Using awk, how can I output the lines of a file that have all fields non-null without manually specifying each column?
foo.dat
A||B|X
A|A|1|
|1|2|W
A|A|A|B
Should return:
A|A|A|B
In this case we can do:
awk -F"|" -v OFS="|" '$1 != "" && $2 != "" && $3 != "" && $4 != "" { print }' foo.dat
But is there a way to do this without specifying each column?
You can loop over all fields and skip the record if any of the fields are empty:
$ awk -F'|' '{ for (i=1; i<=NF; ++i) { if (!$i) next } }1' foo.dat
A|A|A|B
if (!$i) is "if field i is not non-empty", and 1 is short for "print the line", but it is only hit if next was not executed for any of the fields of the current line.
Another in awk:
$ awk -F\| 'gsub(/[^|]+(\||$)/,"&")==NF' file
A|A|A|B
print record if there are NF times | terminating (non-empty, |-excluding) strings.
awk '!/\|\|/&&!/\|$/&&!/^\|/' file
A|A|A|B

Does NSIS have eval functionality?

For example, is there a way to do something along these lines?
Eval "MessageBox MB_OK 'Hello, World!'"
This is obviously a useless example, but I feel that such functionality would be useful.
The NSIS compiler (MakeNSIS) parses text files and writes out binary instructions into the generated setup. The setup application itself can only execute the instructions known at compile time.
Most instructions accept variables as their parameters so you can get different behavior. Here is a rather pointless example of that:
Page InstFiles
Function MaybeShowMessageBox
IntCmp $0 0 skip
MessageBox MB_OK "$1"
skip:
FunctionEnd
Section
StrCpy $0 1 ; Display it
StrCpy $1 "Hello World"
Call MaybeShowMessageBox
StrCpy $1 "Goodbye World"
Call MaybeShowMessageBox
StrCpy $0 0 ; Don't display it
Call MaybeShowMessageBox
StrCpy $0 0
StrCpy $2 "$WinDir" 1 ; Get the first character
StrCmp $2 "C" "" skipWinDirMessage
StrCpy $0 1
skipWinDirMessage:
StrCpy $1 "$WinDir is on drive C"
Call MaybeShowMessageBox
SectionEnd
You would ordinarily never write code like that. IntFmt is as close to Eval as you are going to get but it only operates on numbers:
ShowInstDetails show
Section
StrCpy $1 42
IntFmt $0 "%d" $1
DetailPrint "$1 as a number: $0"
IntFmt $0 "%#.4x" $1
DetailPrint "$1 as a hex number with a >= 4 width: $0"
IntFmt $0 "%c" $1
DetailPrint "$1 as a character: $0"
SectionEnd

How to append lines to a new file with AWK

I am trying to append lines to some new files with awk in this way:
#!/usr/bin/awk -f
BEGIN {
FS = "[ \t|]"; }
{
print $5 "\t" $13 "\t" $14 >> "./bed/" $5 ".bed";
}
END {
}
New file is created with filename derived from a field of awk input file (5th field). I am unable to execute this script since it fails with
awk: ./blast2bed.awk:6: (FILENAME=blastout000 FNR=1) fatal: can't redirect to `./bed/AY517392.1.bed' (No such file or directory)
Any hints?
Thanks
The directory bed has to exist so create it first with mkdir bed either before you run your script or in the BEGIN block. You should also add brackets around the output file:
print $5"\t"$13"\t"$14 >> ("./bed/"$5".bed")
Notes: You don't need to end lines with ; if you have a single statement per line and the BEGIN and END blocks are optional.