Menu

#1229 StrFunc.nsh is not very conducive to use in multiple headers

3.0 Series
closed
nobody
None
5
2019-06-23
2019-06-18
Alastair
No

To use the macros in StrFuncs.nsh, we're supposed to make a decleration that we want to use them, which in turn redefines the original macro name and prepares it for use, e.g. to use StrLoc:

!include StrFunc.nsh
${StrLoc}

Section
    Push $0
    ${StrLoc} $0 abcdefg def >
    MessageBox MB_OK "Result was $0"
    Pop $0
SectionEnd

That's fine in one .nsi or .nsh file, but if we include a second header that also does this...

!include StrFunc.nsh
${StrLoc}

... then things blow up.

!insertmacro: macro "FUNCTION_STRING_StrLoc_Call" requires 4 parameter(s), passed 0!

And we want to be able to do that so that if our headers depend on StrLoc they can be included easily in any script that might need them.

I don't know if there's an easy solution to this, since we don't have support for overloaded macros by argument count. However, it would be nice if a workaround for this design issue was available.

For example, I've currently done this:

!ifndef UnStrLoc 
${StrLoc}
!endif

This works because UnStrLoc is defined once ${StrLoc} is processed the first time. But its very non-obvious to maintainers what is going on. Maybe StrFuncs.nsh could maintain backwards-compatibility by continuing to support the old method, but provide a safer way to declare use of a mechanism that is safe to insert more than once, and just does nothing if it's being used for the nth time. E.g. perhaps I could write:

!include StrFunc.nsh
${UseStrLoc}

Discussion

  • Alastair

    Alastair - 2019-06-18

    My workaround here actually doesn't work:

    !ifndef UnStrLoc 
    ${StrLoc}
    !endif
    

    Thus I think there is currently no workaround currently except to create your own ${UseStrLoc} mechanisms.

     
  • Alastair

    Alastair - 2019-06-18

    I came up with this, for now:

    !macro STRFUNC_USEFUNC NAME
        !ifndef __Use${NAME}
        !define __Use${NAME}
            ${${NAME}}
        !endif
    !macroend
    
    !macro STRFUNC_WRAPFUNC NAME
        !define Use${NAME} "!insertmacro STRFUNC_USEFUNC ${NAME}"
        !define UseUn${NAME} "!insertmacro STRFUNC_USEFUNC Un${NAME}"    
    !macroend
    
    !insertmacro STRFUNC_WRAPFUNC StrCase
    !insertmacro STRFUNC_WRAPFUNC StrClb
    !insertmacro STRFUNC_WRAPFUNC StrIOToNSIS
    !insertmacro STRFUNC_WRAPFUNC StrLoc
    !insertmacro STRFUNC_WRAPFUNC StrNSISToIO
    !insertmacro STRFUNC_WRAPFUNC StrRep
    !insertmacro STRFUNC_WRAPFUNC StrSort
    !insertmacro STRFUNC_WRAPFUNC StrStr
    !insertmacro STRFUNC_WRAPFUNC StrStrAdv
    !insertmacro STRFUNC_WRAPFUNC StrTok
    !insertmacro STRFUNC_WRAPFUNC StrTrimNewLines
    

    Then you can do ${UseStrLoc} etc. safely.

     

    Last edit: Alastair 2019-06-18
  • Anders

    Anders - 2019-06-18

    What about theStrLoc_INCLUDED and UnStrLoc_INCLUDED defines?

     
    • Anders

      Anders - 2019-06-18
      !include StrFunc.nsh
      !define UseStrFunc '!insertmacro UseStrFunc '
      !macro UseStrFunc name
      !ifndef ${name}_INCLUDED
          ${${name}}
      !endif
      !macroend
      ${UseStrFunc} StrLoc
      ${UseStrFunc} StrLoc
      
       
  • Alastair

    Alastair - 2019-06-18

    Anders,

    These are not defined until the function has been both declared and actually used, so no good for this purpose. Even if there was a definition that could be used this way (and I don't see one so far), I think the better thing to do is to make StrFunc natively behave per the wrapper above, which could be acheived through modifying STRFUNC_DEFFUNC.

     
    • Anders

      Anders - 2019-06-18
      !include StrFunc.nsh
      !define UseStrFunc '!insertmacro UseStrFunc '
      !macro UseStrFunc name
      !ifndef ${name}_INCLUDED
          ${${name}}
      !endif
      !macroend
      ${UseStrFunc} StrLoc
      ${UseStrFunc} StrLoc
      
      Section
      ${StrLoc} $0 $0 $0 $0
      SectionEnd
      
      ${UseStrFunc} StrLoc
      
      Section
      ${StrLoc} $0 $0 $0 $0
      SectionEnd
      

      Compiles just fine, I don't see the problem.

       
      • Alastair

        Alastair - 2019-06-18

        Okay,

        So one way or the other, can we get official support in StrFunc.nsh and a doc update? Because having to use a custom wrapper to make required forward-declarations of stock-NSIS functions work in more than one header in my projects is ugly.

         
  • Anders

    Anders - 2019-06-23
    • status: open --> closed
     

Log in to post a comment.