Skip to content
⌘ NSIS Forum Archive

nsArray plug-in

54 posts

Afrow UK#

nsArray plug-in

Wrote this light weight array plug-in which will be used in the nsL Assembler to support native language constructs for arrays. I figure people will also use it in their NSIS projects too.


  • 6KB DLL (versus 20KB for NSISArray)
  • Low memory usage
    - Linked lists
    - Allocates small blocks of memory rather than one continuous block
  • Much faster
    - Uses memory pointers
    - E.g. sorting copies memory pointers, not the data itself
  • Very simple usage
    - Bare minimum set of functions
  • No limit on the number of arrays
  • Designed to be used by NSIS Assembler (http://nslassembler.sf.net)


Stu
disruptor108#
Thanks for making this.

A couple things I've noticed while using it:

*After deleting an array, the length of the array is still 1.
*Removing items from an array do not shorten the length.

I can provide my code examples if necessary.
Afrow UK#
Ah thanks I probably forgot to reduce the counters. Will fix soon thanks. I'm thinking of allowing associative arrays (akin to PHP arrays) rather than indexed ones. Think that would be a good idea?

Stu
disruptor108#
Personally, I have no preference one way or the other. I've been doing fine with indexes, but if changing to associative arrays works for others I can change my code.
Afrow UK#
Well it would work like PHP arrays so you can have both index-associated and key-associated elements in the same array. Perhaps I'll fix these small bugs first though.

Stu
Afrow UK#
Finally fixed those bugs (and a couple more):
1.0.0.1 - 2nd June 2011
* Fixed decrementing of element and array counters on element and array
deletion.
* Fixed memory leak of array name on array deletion.
* Fixed bad pointers remaining after last element and array deletion.
This will be the last version (hopefully) to only support indexed arrays. The next version I plan to have associative and indexed arrays in one, akin to PHP. The changes I had in mind to allow for this are:

* "New" will no longer initialise the values of an array. One can just use "Insert" (will reduce some of the code size).
* "Insert" will take an optional prefix argument for each element in the format "/key=val" where val can be an index or a string. Omitting /key will result in the element being inserted at its natural index (which is the last highest index + 1).
* "Remove" and "Get" will no longer take index ranges, but instead will take a list of keys/indices followed by /end.

Stu
Afrow UK#
New plug-in version which supports associative arrays (as well as indexed). The plug-in usage and functionality has changed quite a lot since the previous version but the DLL is still the same size.



Stu
singman#
Error with ToString

If I follow the example on the DLL archive, I get that ouput :


MyArray = {0}
MyArray[0] is 11
MyArray[1] is 14
MyArray[4] is blah
MyArray[5] is /key=jajaj
MyArray[jajaj] is
Set MyArray[jajaj] = 22
MyArray[jajaj] is
MyArray = {0}
MyArray length: 1
MyArray length: 1
MyArray = {0}
MyArray = {1}
MyArray length: 1
MyArray2 values sorted numerically = {1}
MyArray2 sorted by keys = {1}
MyArray2 = {1}
MyArray2[0] is
MyArray2[1] is 14
MyArray2 = {1}
MyArray2 length: 1
MyArray2Keys = {0}
MyArray2 = {0}
MyArray2 length: 7
Completed


I think every ToString call return something wrong.
Quote from documentation :

nsArray::ToString my_array
Pop $var

Returns a string representation of `my_array` which includes keys and
values in the format key1 => value1, key2 => value2, etc.. The error
flag is set if the array does not exist or if the result cannot
completely fit into the output buffer (NSIS_MAX_STRLEN) although as
much as can fit into the output buffer will still be returned.
Afrow UK#
I have no problems with the example script. Make sure you are using the correct plug-in (i.e. Unicode or ANSI).

Edit: If there is ever a problem, the error flag is set.

Stu
singman#
Great !
I was using the Unicode version but my NSIS is no longer compiled with Unicode.

Thanks.
Afrow UK#
New plug-in version:
1.1.0.2 - 12th October 2011
* Added GetAt function.
* Added addition sort flag (16) to retain keys/indices order when sorting values.
* Removed New function. Set function now creates the array if it doesn't already exist.
Stu
Afrow UK#
New plug-in version:
1.1.1.0 - 12th February 2012
* Added Split function.
* Added /noempty switch to Join function.
* Sort function now supports ORing (|) for its sort flags.
* Replaced Delete function with Clear function.
* Replace GetAt function with /at=position switch on Get function.
* Added Get /at=-1 for array element iteration.
* Added /at=position and /val=value switches for Remove function.
* Implemented script header replacements for Copy, CopyKeys and ToString functions.
* Added script header ForEachIn LogicLib loop.
The ForEachIn loop can be used like so:
${ForEachIn} my_array $key $value
DetailPrint "my_array[$key] => $value"
${Next}
Stu
Afrow UK#
New plug-in version:
1.1.1.1 - 12th February 2012
* Optimised Get /at=-1 by using an pointer instead of a counter.
* Added Get /at=-2 to iterate in reverse order.
* Added script header ForEachInReverse LogicLib loop.
Stu
Afrow UK#
New plug-in version (hopefully the last for a while):
1.1.1.2 - 13th February 2012
* Replaced /at=-1 with /next for Get function.
* Replaced /at=-2 with /prev for Get function.
* Added /reset switch to Get function to reset /next or /prev iteration.
* The /at=position switch for Get and Remove functions now support negative numbers.
* Added call to Get /reset before entering ForEachIn loop.
* Fixed incorrect usage of Split function in the readme.
Stu
vicokoby#
When set a array outside of section, this init with some empty elements

For example:

Page custom CreateMyPage LeaveMyPage


Function CreateMyPage

InstallOptions
FunctionEnd

Function LeaveMyPage

FunctionEnd
vicokoby#
#When set a array outside any section, this aray have some empty elements,
por example in the function of a custom page.#

Page custom MyPage LeaveMyPage
Page instfiles

Function MyPage
Push $R0

InstallOptions::dialog $PLUGINSDIR\someIni.ini
Pop $R0
FunctionEnd

Function LeaveMyPage

nsArray::Set MyArray 'one'
nsArray::Set MyArray 'two'
nsArray::Set MyArray 'three'
nsArray::Length MyArray
Pop $1 ; $1 = 4 instead 3
NsArray::Get MyArray 0
Pop $0 ; $0 = ´´ ( Empty String)

#This only occur into a custom page function#
Function

Section MySection
Call LeaveMyPage ; When the call is from here, no there problems with the array
SectionEnd
Afrow UK#
nsArray::Set takes multiple values so you need to put /end on the end, i.e.
nsArray::Set MyArray one two three /end
If you don't add /end, values left on the NSIS stack will get added.

Edit: Maybe I should add a first argument of /list to add multiple elements in a single call to Set (i.e. /end can be omitted without /list).

Stu
Afrow UK#
At the moment yes because of what I said. NSIS passes arguments to plug-ins using the stack and because Set can have multiple arguments there is no way of knowing if the argument was on the stack already or passed as a plug-in argument in the call. This is why /end is necessary and not optional. Some other plug-ins require the use of /end too.

Stu
Afrow UK#
New version uploaded. Set and Remove calls no longer need the /end suffix when adding/removing a single element. If you want to specify multiple elements, start the list with /list and end it with /end. The readme has examples.



Stu
Afrow UK#
You can do both of those with the existing functions plus some loops. Perhaps I will add them to the script header when I have time.

Stu
Afrow UK#
Actually you could only do sorting with the existing functions if the array is indexed only (i.e. how would you sort if the array is associative?) Also the internal Sort function simply moves the pointers around rather than the actual data. This is far more efficient and does not require any new memory allocation or deallocation or data copying. Also writing the quick sort algorithm in NSIS code would not be very straight forward (bubble sort would be easier but is less efficient).

Removing duplicates and merging arrays both require memory deallocation and allocation so writing an internal function would serve little benefit over an NSIS script equivalent and would only add additional size to the DLL.

Stu
TVNST#
I checked the plugin code in order to maybe get a hint about what was causing the memory corruption problems I got, and there's some potential issue with the Set command and its key words.

According to my interpretation of the code, there's no accurate distinguishing between a value and a key word. Therefore the function is not able to recognize if a string value accidently has the same text as a known keyword like "/list", "/end" or "/key".

For example, if just one value is added and this value accidently starts with "/key=", it will set the error flag and abort the installation in my case.
If a list of parameters is added and one of the values is accidently "/end", like...
nsArray::Set array /list "Bla" "/end" "BlaBla" /end
... the last two parameters are not interpreted anymore, and might pollute the NSIS stack, because there's not condition for "/end" to be the last available parameter.

It would be better to have different function names for each type since every keyword reduces the set of valid values.
Since I have to add values read from various registry values, there's pretty much any value possible including the key words.
I will now check the values to add for the keywords first and use a workaround it that happens. Fore example, it's possible to add the "/list" value with the following statement:
nsArray::Set array /list "/list" /end
Afrow UK#
Yes that is indeed a problem which I was well aware of when I wrote the functions. I suppose a SetList function would not hurt and I am perhaps over-obsessed with making the plug-in as small as possible.

I have run both the ANSI and Unicode builds through the debugger and have had no memory access violations. There could still be some but I would have a look at the other plug-ins you use.

Stu
TVNST#
I checked the basic functions of the plugin and the code is rather clean.
I highly doubt the memory corruptions are caused by your plugin as well.

I also validated our own plugin code, but althouh I found memeory leaks but I couldn't find any memory corruptions.
However, I replaced some unsave functions like sprintf with their safer variant with array size limitation.

However, our installer still has some sporadic stability problems which might be caused by another plugin.
We also upgraded to the newest NSIS version but that didn't help either.