Skip to content
⌘ NSIS Forum Archive

nfUtils.nsh - a collection of macros and functions

27 posts

niteflyer#

nfUtils.nsh - a collection of macros and functions

Here is a collection of some useful macros and functions. The headerfile comes with an installer and its script, which also shows how to use some of nfUtils' macros.

Maybe there are some english-speaking people, who could review the build-in help: follow the instructions in the installer's listbox.

Currently included are:

"nfu.!AddFile"
"nfu.!AddFunction"
"nfu.!Append"
"nfu.!AppendIf"
"nfu.!Calculate"
"nfu.!Compare"
"nfu.!Exchange"
"nfu.!FileVersion"
"nfu.!FreeFile"
"nfu.!FreeSymbol"
"nfu.Function"
"nfu.FunctionEnd"
"nfu.!Help"
"nfu.HideBackButton"
"nfu.HideCancelButton"
"nfu.!IncludeFileIf"
"nfu.!IncludeTextIfExist"
"nfu.!InstallDescription"
"nfu.!InstallFunction"
"nfu.!InstallMacro"
"nfu.!MakeFile"
"nfu.!MakeSymbol"
"nfu.!Redefine"
"nfu.!Replace"
"nfu.SetInstallerName"
"nfu.SetStdAttributes"
"nfu.SetVersionInfo"
"nfu.SkipPageOnSrcExtract"
"nfu.SkipSectionOnSrcExtract"
"nfu.!Undefine"
"nfu.GetAppPath"
"nfu.UnGetAppPath"
"nfu.GetParameter"
"nfu.UnGetParameter"
"nfu.ProcessStdSwitches"
"nfu.UnProcessStdSwitches"
"nfu.myName"
"nfu.myVersion"
JasonFriday13#
I have just compiled the setup script using 2.15, and it runs the same as the one in the zip provided 👍 . Good work.
kichik#
At the very minimum, you should create a wiki page for this. I hope I'll have some time to look at it soon. I find the function macros especially interesting.
niteflyer#
I was always missing an NSIS-installer attribute, which enables 'browsing' or 'extracting' the installer and its resources (by commandline-switch) without really running it, so nfUtils was mainly aimed to provide such a functionality with nfu.ProcessStdSwitches. Did you try to start nfUtils.exe with /? in the commandline ?

All macros in nfUtils helped me building this function: so I was also missing a framework which helps me passing parameters to a function, getting them inside the function, etc. That's the way how nfu.!InstallFunction, nfu.Function and nfu.FunctionEnd were born.

Dont know when I will have the time to make a wiki page. Never did it until now...

What I am really missing in the wiki-system is an entry-page to browse the wiki. For example, http://nsis.sourceforge.net/home/ does not show up such an entry and it took me a lot of time to find this page http://nsis.sourceforge.net/Category...itory_by_Topic what comes close to what I would expect as a 'homepage' for contributors. A hierarchical system like the sidebar of http://nsis.sourceforge.net/home/ would be better though...

Stay tuned for version 1.1 with a bugfix: a compilation error will occur, when passing string constants containing single quotes to a function.
niteflyer#
Version 1.1.0.0 is out

Here is nfUtils 1.1.0.0:

fixed: string constants with single quotes (') caused compilation errors when passing them to a function. the problem persists for backward single quotes (`) and cannot be solved. escaping has no effect. workaround: when possible, copy such strings to a var and use the var for passing the parameter.

added: added nfu.StdLicense to the descriptions.

chngd: output of nfu.!Help usage info:
${funcname} out😛1 in😛2 in😛3

Minor changes to the installer, mainly more comments.
niteflyer#
Version 1.2.0.0

fixed: ${nfu.FunctionEnd} tried to generate "Exch 0", e.g. for functions with one out- and no in-parameters.

I have added a testsuite to the installer to proof the correctness of ${nfu.Function} and ${nfu.FunctionEnd}: the suite tests all 66 combinations, regarding the number of out- and in-parameters.
kichik#
The front page contains a large image link to the developer center which serves as an entry page for all of the development related topics. Creating new pages shouldn't be too difficult. You should really create a wiki page for it. Things tend to fade away in the forum.
niteflyer#
nfUtils has got a wiki !

... here: http://nsis.sourceforge.net/NfUtils_header_file

Wow. My first wiki !

Currently it is merely a copy of nfUtils' built-in descriptions, all on one page. I will add some examples next week.
Filus#
I've had a problem with including several times your nsh file. I made some "library" headers for my products, and I use your utils in some of them. But it's working great when I include nfUtils.nsh in all files only once, otherwise some errors occured. The first was about invalid number of parameters for echo in line 42, so I changed ` to ' and it's passed. But then next error occured:

Invalid command: !if${Condition}
!include: error in script: "C:\Program Files\NSIS\Include\nfUtils.nsh" on line 566
niteflyer#
Can you detect the line in _your_ source, which causes the error? I need to see NSIS' log with the lines preceding the error code, try playing with
!verbose 4
or
${nfu.!Redefine} NFU_VERBOSITY 3
or
${nfu.!Redefine} NFU_VERBOSITY 4
to get more details.
niteflyer#
Seems as if you are using ${nfu.!AppendIf} with an illegal condition:



!ifCondition has to be a valid NSIS compile time command for conditional compilation like

!ifdef
!ifndef
!ifmacrodef
!ifmacrondef
!if 1 < 2
etc.

For the last example you would have to use

${nfu.!AppendIf} " 1 < 2" "YourSymbol" "YourValue"

Notice the quotes enclosing the condition and the leading spacecharacter in the condition!
Filus#
Originally posted by niteflyer
Can you detect the line in _your_ source, which causes the error?
Ok, no problem:
In my general nsi file I have sequence of include commands:
!include LogicLib.nsh
!include "${NSHDIR}\loading.nsh"
!include "${NSHDIR}\about.nsh"
!include "${NSHDIR}\services.nsh"
[...]
I include your utils in loading (first time) and in about nsh files. loading.nsh has passed without problems, so compiler goes to about.nsh, and from then to another one nsh where I include nfuUtils directly. It looks:
!ifndef COMMONS_FILES
!define COMMONS_FILES

!include LogicLib.nsh
!include FileFunc.nsh
!include WordFunc.nsh
!include nfUtils.nsh
[...]
!endif
And compiler stops on line where nfUtils are included and produces this log:
!define: "COMMONS_FILES"=""
!include: "C:\Program Files\NSIS\Include\LogicLib.nsh"
!include: closed: "C:\Program Files\NSIS\Include\LogicLib.nsh"
!include: "C:\Program Files\NSIS\Include\FileFunc.nsh"
!include: closed: "C:\Program Files\NSIS\Include\FileFunc.nsh"
!include: "C:\Program Files\NSIS\Include\WordFunc.nsh"
!include: closed: "C:\Program Files\NSIS\Include\WordFunc.nsh"
!include: "C:\Program Files\NSIS\Include\nfUtils.nsh"
Invalid command: !if${Condition}
!include: error in script: "C:\Program Files\NSIS\Include\nfUtils.nsh" on line 566
!include: error in script: "..\src\nsis\files.nsh" on line 28
!include: error in script: "..\nsh\about.nsh" on line 14
Seems as if you are using ${nfu.!AppendIf} with an illegal condition:
Hmmm, but I'm not using this (directly in my code at least). I only use ${nfu.Function} and ${nfu.FunctionEnd} in this all "error making" script (including used nsh files).
So, I've made temporary workaround (checking defining of NFUPREFIX before including nfUtils), but it'll be better if I don't have to use it.
Well, also I'll check my code once again and try compile in another machine (and version of NSIS - I use 'long strings' build).
niteflyer#
Hmmm, strange: you don't need to check for NFUPREFIX, because nfUtils.nsh already checks this symbol to prevent multiple inclusion (in Line 1) of itself. You should be able to see if this works by turning verbosity on (see previous post).

The log says, that the error was caused by the instruction in line 28 of files.nsh - what's in there ?
Filus#
Originally posted by niteflyer
Hmmm, strange: you don't need to check for NFUPREFIX, because nfUtils.nsh already checks this symbol to prevent multiple inclusion
Yes, I saw this. But, somehow, it works in workaround and not in nfUtils.nsh. 😕
I also added (for tests) one more checking define in nfUtils.nsh in this way:
!ifndef NFUTILS_INCLUDED
!define NFUTILS_INCLUDED

[Original nfUtils content]

!endif
But it nothing changes. So, yes, this is strange.

The log says, that the error was caused by the instruction in line 28 of files.nsh - what's in there ?
There is:
        !include nfUtils.nsh
Nothing more. This is the last line of sample code in my previous post.
niteflyer#
Assuming that nfUtils would be included more than once: the first error you would get with nfUtils' line 30 (and not in line 566):

!define NFUPREFIX "nfu."

you cannot define a symbol which is already defined... So there must be something else. What really surprises me, is that if you are checking outside of nfUtils for NFUPREFIX, you will not get the error - do you get another error, a flawless compilation or a flawless installer?

You have to examine NSIS' compilerlog with full verbosity to see what went wrong.
niteflyer#
I can reproduce similar strange effects when I include nfUtils.nsh twice in the sourcecode of its installer (error in the usage of !echo in line 42 of nfUtils.nsh).

I can reproduce the behaviour of checking NFUPREFIX outside the header does work fine.

Checking inside a small header file does _also_ work fine (xxx.nsh):

!ifndef xxx
!define xxx 222
!endif

(main.nsi):

!include xxx.nsh
!include xxx.nsh

Dont know what I should think of that...

Tested with NSIS 2.21 and 2.18.
Filus#
Well, when I'm checking NFUPREFIX outside of nfUtils I get flawless compilation of flawless installer. All works great.
And also strange is, that if I use your "original" nfUtils.nsh errors occured on line 42 (but as I wrote, I made some small fix for it) and says:
!echo expects 1 parameters, got 3.
Usage: !echo message
!include: error in script: "C:\Program Files\NSIS\Include\nfUtils.nsh" on line 42
It seems like some strange errors with defines. I'll make some test on weekend and/or begining of next week to reproduce these errors with another code and building enviroment.
niteflyer#
Yes, I get the same error. But the point is that the compiler _must_ not compile line 42, but skip at line 1 to the end of the header. Everything can happen, no matter how many fixes and workarounds you find for making line 42 work...

I would suspect an error with missing ENDIFs/MACROENDs in nfUtils' code, if I would not know that nfUtils is working.

If I comment line 42 then I get the same error you have reported: Invalid command: !if${Condition}

Is there a limit for codelines between !ifndef and !endif, Kichik?
Filus#
Originally posted by niteflyer
[B]But the point is that the compiler _must_ not compile line 42, but skip at line 1 to the end of the header. Everything can happen, no matter how many fixes and workarounds you find for making line 42 work...[B]
Yes, I know this. I wrote about this line, because it is in another, internal, !ifndef-!endif block where compiler shouldn't enter. And also, it seems like the string in !echo is somehow splitted at ${NFUPREFIX} positions. So this is some clue for my hypothesis about "something wrong" with preprocessor commands in NSIS.
niteflyer#
I will try to locate the problem with a reduced header on the weekend, and - if necessary - post this issue at the SourceForge Bug Tracker. It would not be the first time, that nfUtils reveals a bug in NSIS...
davidnewcomb#
This thread has not been touched for 4 years. Is it still active?
Was the bug in NSIS addressed?
Couldn't work out from the documentation whether nfu.Function supports nested functions?
niteflyer#
The thread is still active.

I wasn't able to fix the bug for the NSIS version, which was released at that time. I did not check if the bug still persists with the current version. If you read the last posts of the thread there is an assumption that there was/is something wrong with the implementation of NSIS' preprocessor commands. As far as I recall I did not submit a bugreport to the Bug Tracker, because I had no clue how to isolate the problem.

What do you mean with nested functions? NSIS does not support nested function declarations. Nested functions calls are supported, and should also work with nfu.Function...
davidnewcomb#
By nested function I mean a function that is called from inside another function. A good example is "Trim".
Function TrimCall
exch/pop
do trim
push/exch/pop/exch/pop
EndFunction

!macro Trim WHAT
Push ${WHAT}
Call TrimCall
Pop ${WHAT}
!macroend

Function DoSomethingUsefulCall
push/pop/etc
${Trim} $0
push/pop/etc
EndFunction

!macro DoSomethingUseful P1 P2 RET
push/pop/etc
Call DoSomethingUsefulCall
push/pop/etc
!macroend
A bit rough but you get the idea. Is your stuff going to protect all my $0, that is, does it artificially create protected scope while inside each function. I'm interested in using this package but the examples are few and far between, and the ones I have found are only called from a Section and don't call out to any other nfu.Function.

Our NSIS installer is over 4,500 lines long! and so we have to nest our functions. We use the system store call to provide artificial scope, but it is really ugly.

Function WriteSomeInfoCall

# Place stack protection code here
System::Store /NOUNLOAD "s"
Pop $0
:
dostuff
:
Push $0
System::Store "l"
EndFunction
to provide artificial scope but it's really ugly.
niteflyer#
My macros do not create an artificial scope: nfu.Function and nfu.FunctionEnd only provide the code for getting and returning parameter from/to the stack. Only the registers which you have specified for nfu.Function for getting the parameters are protected as they will be restored by nfu.FunctionEnd (besides returning values to the stack, see wiki). Other registers which you need inside your function have to be protected by _you_ (with push at the beginning and pop at the end), so you may still use global registers inside your function.
niteflyer#
nfUtil.nsi (the installerscript of the headerpackage - will be extracted to the examplesdir of NSIS) shows a small example how to implement the function F1 which uses another function HelperForF1 in line 88-139. F1 is called in line 192 (simply with ${F1} $R1 $R2 $0 $1 $2 $3).

Line 111-113 and 128-129 should be used as a skeleton for every of your functions: put your code in between these two parts.

The macro in line 102 handles dependencies by issuing nfu.AddFunction for every function which is used by function F1.

Line 132-133 generate the macros with the code for calling the functions HelperForF1 and F1, so that you may use the syntax in line 115 or line 192 to invoke a function.
davidnewcomb#
Thanks, I understand now - I think. I did read your wiki page but I didn't really understand it and there were no examples. I'll go and have a play.
niteflyer#
I know it is difficult to understand without examples. Never had the time to update the wiki with some of them. nfUtils.nsi should give you an idea how to use the macros. If you watch the compileroutput of NSIS you should understand how it works.

It is simply some kind of interface which hig-level languages provide when you declare a function so the compiler knows which arguments have to be put and fetched from the stack when you call a function, when you enter/leave a function and when the calling environment continues with the results of a function.

What has to happen inside the function body still remains low-level like assembler language so _you_ have to care about the contents of registers when you need to change them for intermediate results, because they are usually already used in the calling environment and may not be changed: use push and pop like in good old assembler...