Archive: NSISArray plugin


NSISArray plugin
  A plugin which adds fast dynamic array support to NSIS with over 20 functions for array manipulation.
It also has an array script header to mask the plugin calls with a more friendly scripting syntax.

http://nsis.sourceforge.net/wiki/File:NSISArray.zip

Please note:
If you have a previous release of NSISArray installed, please delete the Contrib\NSISArray and Examples\NSISArray folders before installing the new release.

-Stu


Hey Afrow,
I just downloaded your new plugin and from what I've seen, it looks great! (Excellent job!)

But I have one quick question:
In the Include folder, you have the file NSISArray.nsh. But the file includes another NSISArray.nsh file located in ${NSISDIR}\Contrib\NSISArray. Why not just have the one real NSISArray.nsh in the include folder? (This would be less confusing and easier to maintain in my opinion.)


If there is only source code in the Contrib folder (so nothing for the end-user), I would also recommend you to put the actual contents in Include.


Good question! I think I just did it because of Modern UI and my Self-Extractor kit. It just keeps all the source code (C++/NSIS) in one folder so if someone (or I) wants to modify the source code (plugin code or the NSIS code), we know where to find it.

The readme and some examples are also in the Contrib folder so again, everything is kept close together.

-Stu


I was testing the arrays and ran into a few problems. Please look at this dummy script:


name 'test array'
outfile 'test_array.exe'
!include NSISArray.nsh

Section
DetailPrint "Initializing array..."
${Array} "TestArray"
${TestArray->Init}
DetailPrint "adding 'dog'"
${TestArray->Push} "dog"
DetailPrint "Adding 'hippo'"
${TestArray->Push} 'hippo'
DetailPrint "Adding 'cat'"
${TestArray->Push} 'cat'
${TestArray->SizeOf} $0
DetailPrint "My Array now contains $0 items:"
${TestArray->Search} $1 "dog" 0
DetailPrint "'Dog' is item $1"
DetailPrint "All items: "
${TestArray->Concat} $2 ", "
DetailPrint $2
SectionEnd

page instfiles


During compile, on this line:
${TestArray->Search} $1 "dog" 0
I get this error:
!insertmacro: macro "Array_Search" requires 4 parameter(s), passed 5!

If I REM this line, then I get an error at runtime that says "SizeOf:parameter error"

Am I being stupid or are these both bugs?

Originally posted by Afrow UK
Good question! I think I just did it because of Modern UI and my Self-Extractor kit. It just keeps all the source code (C++/NSIS) in one folder so if someone (or I) wants to modify the source code (plugin code or the NSIS code), we know where to find it.

The readme and some examples are also in the Contrib folder so again, everything is kept close together.

-Stu
The point is that the Modern UI also puts other NSIS header files (langauge files) and data in the 'Contrib\Modern UI' folder.

Documentation and source files are indeed also in the Contrib folder on the CVS server, but for end-user releases the build system puts documentation in the Docs folder and examples in the Examples folder.

So whenever releasing a compiled plug-in for the end-user, there should be nothing in Contrib at all, just a binary in Plugins, a readme in Docs and a example in Examples (and maybe a header file in Include).

Ah right I see.
I'll change everything so it's like that (nsh in Include, docs in Docs).

Edit: Yeh they are bugs. One was an error in the plugin code and the other was in the NSH. Uploading new build now.

Edit #2: Uploaded.
Before installing, delete the Contrib\NSISArray folder, because now the readme is in Docs, and NSH in Include.

-Stu


Thanks, Afrow.

hmmm.. Technical difficulties: I can't seem to get to the Wiki at the moment. As soon as it lets me, I'll download it and try it out.


The SourceForge database server has performance issues, they are working on doubling the capacity. In the meanwhile the NSIS Site and Wiki may be slow during peak times.


Hey Afrow,
The sample script above seems to work, but I need you clarify something for me regarding the 'SizeOf' function.

Your docs describe this as:

Places the amount of items in myArray into $Var.
Based on this, I would expect it to return the total number of elements in the array. However, using the example above, I see that it returns 2, not three. While 2 is the highest element number (due to the fact that the array is zero-based), the total number of elements (items) in the array is actually 3.

So, I feel that either your function or the documentation are wrong. (either way you go is fine, but one should match ther other.) Would you agree?

That's interesting. For some reason in the source I was taking 1 away from the output (when I shouldn't have been).

I will recompile and upload v0.3

Thanks for finding this out.

-Stu


No problem. I've been wanting to check some of the other functions, but just haven't had time. From the little I've worked with it, this looks like it will be a very powerful plugin.

And I have to complement you on the array debug utility you included with this plugin. That is a really nice touch--should make problem solving a lot easier.

I can tell you put a lot of thought into this. Keep up the great work! :up: :D


Ok Afrow, now that I've buttered you up, I've got several bugs to report! :eek:

you are really gonna get tied of me! hehe!
:p

Note: this is just some quick prelim testing. Time permitting, I'd like to test all functions. (Feel free to use a PM if you think that'd be easier.) Sample scripts for each are attached.

Bug #1
(Test_01.nsi) Calling Write to an existing array overwrites the element as expected, but also adds an empty element to the end of the array.

Bug #2
(Test_02.nsi) Calling WriteListC causes the install to crash. (must be a problem in the plugin itself).
BTW: Can CHAR be a string or should it always be a single character?

Bug #3
(Test_03.nsi) My understanding of the Put command is that it should insert an item at a specfied element. However, it doen't seem to do that. I start with an array of zero,one,two,three. After I call ${TestArray->Put} 1 'insert', I end up with null,insert,one,three,null. (It'll probably make more sense once you compile the example script.)


Right thanks.
1. Easy fix (I know what the issue is :)).
2. Yes, it has to be a single character. I'll add some code to prevent people using a string.
3. Not sure why this is happening but I'll look into it.

-Stu


Thanks again Comperio, uploaded fixed version.

-Stu


All fixes worked great!
:up:

Minor detail:
You may want to mention in the docs that that CHAR in the WriteListC function is just a single character.

If I get more time this weekend, I'll continue testing the other functions.

Thanks!


Another bug. Using the function ReadToStack, I found I had to commend out line #136 of the NSISArray.nsh file:

!macro Array_ReadToStack Plugin Name
${Plugin}::ReadToStack /NOUNLOAD "${Name}"
Pop "${ArrayErrVar}" ### this is the line that needed commented out
!macroend

I didn't find ${ArrayErrVar} defined anywhere in the header file. And I didn't see that anything extra was being pushed to the stack by your plugin. (Maybe you were using ArrayErrVar when debugging and just forgot to take it out?)

Also:
When I called PushToStack, I noticed that it pushed in the reverse order than I was expecting based on your example. I pushed the Array [0,1,2,3] and when I popped, I got 3, 2, 1, and then 0. I'm not saying you need to change the code, but perhaps you could just make that clearer in the docs.:cool:

Found another bug (maybe?)
Using the Splice function this time. I start out with this array: [zero,one,two,three]

I call this command:
${TestArray->Splice} 0 3 "'0' '1' '2'"

Based on the docs, this should replace elements from index 0 up to, but not including, index 3. Therefore, I'd expect this:
[0,1,2,three]

but instead I get this:
[0,1,2]

I've attached my sample script for you to look over.


OK, 2 more bugs, and I think that's it:
Bug #1
A bug in the debug program. (how ironic is that?)

I have 2 arrays. One named TestArray1 and the other TestArray2.

If I use ${TestArray1->Debug}, I get the dialog that shows the contents of TestArray1. But if I then call ${TestArray2->Debug}, I still get the contents of TestArray1, even though the page caption tells me its TestArray2.

renaming TestArray2 to "blah" also gave the same thing. But by calling the SizeOf function, I as able to determine the Arrays themselves are OK. So it's got to be just a bug in the debug function of the plugin itself.

(Use the attached script called "copy.nsi" to test)

Bug #2
Your docs say that the search command is supposed to be case insensitive, but in my testing, it's actually not. (see attached "search.nsi")

and BTW: I see that Exists and Search do pretty much the same. So why can you specify a starting index with SEARCH and not with EXISTS?


Thanks, fixed.

-Stu :)


I still have the problems with ReadToStack and Splice. (See my first 2 posts from yesterday).

Edit:
But the other problems are OK now.


Doh I didn't see the post above it.
Will look into it soon.

Edit:
They should also all be fixed now. Just waiting to get on the machine I use for compiling.

-Stu


Uploaded new build (still v0.5 though).

-Stu


OK, getting closer...

1. SearchI is not defined in your NSISArray.nsh
2. When adding SearchI, the plugin call is working, but returns the same as the regular Search. (In other words, SearchI is not case insensitive like it's supposed to be.)
3. Both Exists and ExistsI return a 'parameter error' from the plugin

New examples attached.


Dear me, that wasn't very good :(
I've updated the readme and NSISArray.nsh properly. Just trying to upload now, but sourceforge is having problems as usual.

-Stu


Hey Afrow,
I've been having problems on an off with my own ISP.. Kind of refreshing to know I'm not the only one!

I was going to mention that I've saved all my test scripts for every function in your plugin. Just let me know if you'd like a copy of them to include as examples in with your plugin distribution. (I can either post them here, on the Wiki, or send them to you directly.)

Thanks again for all your help.


I was thinking that also. Please send them to afrowuk at tiscali dot co dot uk

-Stu


Uploaded new build. I've done a bit more than bug fixes in this release (although it's still v0.5). Check the Change Log in the readme.

-Stu


Hey Afrow,
I downloaded the new version today and it works great!

Now for a feature request:
It would be nice if you could give the developer the option to trap the plugin errors rather than having the plugin display its own message box when there's a problem. I was thinking of perhaps having the plugin place another value on the stack after the return value. A zero could mean no problems or a unique error code based on one of your predefined errors.

For example, -1 might mean "Array name already declared", -2 would mean "Parameters error.", and so on. Then, you could either wrap the 'english translation' of the error into a plugin call or just use !defines in your NSH header file in case the developer chose to display the erorr you have now. (Using the NSH file, you could even use this to set the error flag if you wanted.)

It would add another pop command to each plugin call, but for flexibility to the developer, I think it would be worth it. Whatcha think?


This is how it was before. Remember there was a Pop ${ArrayErrVar} in ReadToStack. Error messages used to get passed onto the stack, but for some reason I changed it.
I'll add this in today as the default with a compile-time define to use MessageBox's instead.

-Stu


Uploaded v0.6 with the new $ArrayErr (stack) error support. Use !define ArrayErrorMsgBox to use the old school error message boxes.

-Stu


Afrow,
Just found another bug. In your header in the macro 'Array_Delete', you are undefining ${ArrayObj}.

Since ${ArrayObj} is used goblaly (meaning that more than one array can use it), it will cause the compiler to crash when you need to undefine more than one array.

(The reason I spotted it was becuase I happend to be using 2 arrays in my installation.)


For some reason I missed out the new header file which adds support for the ArrayErrorMsgBox define (and fixes that problem you've mentioned).

-Stu


Another issue I'm still looking into, but perhaps you could guide me:

I've noticed that NSISArray.dll is not being removed from the plugins directory. I'm using 2 arrays and I'm deleting both using the ${arrayName->delete} command in my last (hidden) section.

Should I be placing this command somewhere else (like in .onInstSuccess)? Is there another command/procedure I should be using?


I'll have a look. It could be a /NOUNLOAD issue.

-Stu


I've added ${ArrayUnload} to this build (v0.6 RC3).
Also updated all your example scripts (can't use ${Array} inside a Section or Function, added ${Array->Delete} and ${ArrayUnload} to all scripts).

I found out why NSISArray.nsh wasn't included in the last Zip. It actually was, but for some reason it was put in the Plugins folder instead. So make sure you delete Plugins\NSISArray.nsh.

-Stu


Thanks! I'll check it out.

edit:
Things seem to be working great!
:D


I want to use two arrays in my installer. This basic example results in a compiling error. A bug?

!include nsisarray.nsh

outfile array.exe

${Array} "array1"
${Array} "array2"

section -array

sectionend
Error: variable "ArrayErr" already declared
Error in macro Array on macroline 3

I did some digging and found the problem (and turned up another problem in the process). My modified header file attached should fix it. (Note that I changed the name of the header file. Afrow may have another way he'd prefer to handle it so I didn't want my modifications to be confused with the 'official' version.)

Two problems addressed (which are also commented in the attached header file):
1. the variable ArrayErr was getting defined multiple times when the array messagebox handling was turned off. To correct this, I turned the !define "ArrayErrorMsgBox" into a macro. So insted of using the "!define ArrayErrorMsgBox", I can now use "${ArrayErrorMsgBox}". (This is only if you want the plugin to generate error messages instead of you handling it the script. See the original docs for more info.)

2. ArrayUnload was also getting defined more than once. To correct this, I simply enclosed the ArrayUnload define inside an "!ifndef" block.


Thanks for helping out.
I had to go about ArrayErrorMsgBox differently though as when the ArrayErrorMsgBox is defined, all functions will do a Pop $ArrayVar. However, your code had it defined constantly and therefore it couldn't work.
With the Var ArrayErr, I've just added another define so that it isn't added twice.

(Uploaded v0.6 RC4)

-Stu