Archive: Macro problem...


Macro problem...
Ok, I get this typical error message on compile...


Error: label "getpart1_loop:" already declared in section/function
Error in macro SPLIT_STRING on macroline 9
Error in script "C:\Program Files\NSIS\mappackager\mappackager.nsi" on line 1250 -- aborting creation process


And here is the macro...
http://nsis.sourceforge.net/archive/...ances=0,11,122

Can anyone see what is wrong with the macro, because I can only see one "getpart1_loop" label in the whole macro!

Is this some sort of NSIS bug?

-Stu

Every time you use

!insertmacro blah blah

the NSIS compiler will replace the !insertmacro line with the contents of the macro (everything between !macro and !macroend).

The first time you use that macro from the archive, the compiler will insert several labels (getpart1_loop, getpart2_top etc).

If you use that macro again later in your script, the compiler will insert the same labels ... and then give you that error message because those labels have already been used in your script (they got used the first time you used the !insertmacro line for that macro).

If you want to use labels in a macro, you need to ensure that every time you use the macro you create unique labels.

The "UpgradeDLL" macro in Appendix B of the NSIS user manual shows one way to use labels inside a macro. The secret is to use a parameter to the macro to generate unique labels, such as "upgrade_${PARAM}:"

Hope this helps.

Brian


Thanks, works ok now.

-Stu


I just found another problem now with my macro...
Doing Push $R1 (at front) and Pop $R1 (at end) does not work at all.
After calling the macro, $R1 is not the same as it was before I called the macro.

Is this a bug?

-Stu


I think the problem with $R1 is more to do with how you are using the macro than with the macro itself.

When I tried this:


StrCpy $R1 "Initialised"
MessageBox MB_OK ">$R1< (before)"
!insertmacro SPLIT_STRING ${TEST} 1
Pop ${RESULT}
MessageBox MB_OK ">$R1< (after}"

I found $R1 was left unchanged by the macro.

Brian

Strange.
I was using $R1 before it.
Before, $R1 was "textures/e1u1\metal2_2.wal|gbrdday1.map"
After, $R1 became "|" (because | is the character to signify done)

I changed to using $R2 instead of $R1, and that fixed it.
I'm also using latest cvs, so this was a bit strange!

-Stu


I think it might be safer to turn the macro into a function and pass the INPUT and PART on the stack. If you use the macro to process $R1 by using

!insertmacro SPLIT_STRING $R1 2
then the first loop in the macro

getpart1_loop_${PART}:
IntOp $R0 $R0 - 1
StrCpy $R1 ${INPUT} 1 $R0

will get compiled as

getpart1_loop_2:
IntOp $R0 $R0 - 1
StrCpy $R1 $R1 1 $R0

which means that the rest of the macro will be working on incorrect data - in this case the macro will return an error.

Brian

If the main reason for creating the SPLIT_STRING macro was to help when you run out of registers, it might be a lot easier to use an INI file to store the extra data. When you run out of registers, you could save some of them in the INI file, use those registers for different data then save that data in the INI file and restore those registers to their previous values. This process can be repeated as often as is necessary.

An example might make this idea clearer.

Here are some macros to save and restore data from an INI file:


!macro SAVE_REGISTER REGISTER DATA_NAME
WriteINIStr "$PLUGINSDIR\ioA.ini" "Installer Variables" "${DATA_NAME}" "${REGISTER}"
!macroend

!macro LOAD_REGISTER DATA_NAME REGISTER
ReadINIStr ${REGISTER} "$PLUGINSDIR\ioA.ini" "Installer Variables" "${DATA_NAME}"
!macroend

There is no need to use a special INI file for this data; if you already have an INI file defining a custom page, you could use it instead of 'ioA.ini' in the above macros (InstallOptions will ignore the [Installer Variables] section in the INI file).

Here is how these macros could be used:

; Code using $0, $1 and $2 to handle passwords
; Now we need to do some map work but have no unused registers
; so we save some registers in the INI file

!insertmacro SAVE_REGISTER $0 "Email"
!insertmacro SAVE_REGISTER $1 "Password"
!insertmacro SAVE_REGISTER $2 "Result"

; Now we can use $0, $1 and $2 for something completely different
; When we are finished, we can save this new data in the INI file

!insertmacro SAVE_REGISTER $0 "Map folder"
!insertmacro SAVE_REGISTER $1 "Map name"
!insertmacro SAVE_REGISTER $2 "Texture ID"

; Now restore registers $0, $1 and $2 to their previous values

!insertmacro LOAD_REGISTER "Email" $0
!insertmacro LOAD_REGISTER "Password" $1
!insertmacro LOAD_REGISTER "Result" $2

Using an INI file to store variables can also help when you are testing/debugging as you can examine the INI file while the installer is running.

I hope this idea makes sense.
Brian

Support for unlimited user variables ($USER) will be added very soon, so this problem will be solved anyway :)