Old 7th May 2011, 18:46   #1
Afrow UK
Moderator
 
Afrow UK's Avatar
 
Join Date: Nov 2002
Location: Surrey, England
Posts: 8,433
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.

http://nsis.sourceforge.net/File:NsArray.zip
  • 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
Afrow UK is offline   Reply With Quote
Old 8th May 2011, 01:17   #2
zeeh3
Senior Member
 
Join Date: Aug 2005
Posts: 121
Very cool, thank you for the new plugin
zeeh3 is offline   Reply With Quote
Old 26th May 2011, 19:11   #3
disruptor108
Junior Member
 
Join Date: Jul 2009
Posts: 5
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.
disruptor108 is offline   Reply With Quote
Old 26th May 2011, 19:24   #4
Afrow UK
Moderator
 
Afrow UK's Avatar
 
Join Date: Nov 2002
Location: Surrey, England
Posts: 8,433
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
Afrow UK is offline   Reply With Quote
Old 26th May 2011, 20:01   #5
disruptor108
Junior Member
 
Join Date: Jul 2009
Posts: 5
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.
disruptor108 is offline   Reply With Quote
Old 26th May 2011, 20:07   #6
Afrow UK
Moderator
 
Afrow UK's Avatar
 
Join Date: Nov 2002
Location: Surrey, England
Posts: 8,433
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 is offline   Reply With Quote
Old 2nd June 2011, 09:37   #7
Afrow UK
Moderator
 
Afrow UK's Avatar
 
Join Date: Nov 2002
Location: Surrey, England
Posts: 8,433
Finally fixed those bugs (and a couple more):
Quote:
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 is offline   Reply With Quote
Old 2nd July 2011, 15:42   #8
Afrow UK
Moderator
 
Afrow UK's Avatar
 
Join Date: Nov 2002
Location: Surrey, England
Posts: 8,433
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.

http://nsis.sourceforge.net/File:NsArray.zip

Stu
Afrow UK is offline   Reply With Quote
Old 2nd July 2011, 16:13   #9
MSG
Major Dude
 
Join Date: Oct 2006
Posts: 1,892
Nice updating spree you got going there, Stu.
MSG is offline   Reply With Quote
Old 26th September 2011, 15:45   #10
singman
Junior Member
 
Join Date: Sep 2011
Posts: 2
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.
singman is offline   Reply With Quote
Old 29th September 2011, 09:15   #11
Afrow UK
Moderator
 
Afrow UK's Avatar
 
Join Date: Nov 2002
Location: Surrey, England
Posts: 8,433
Will take a look sometime today.

Stu
Afrow UK is offline   Reply With Quote
Old 2nd October 2011, 09:55   #12
Afrow UK
Moderator
 
Afrow UK's Avatar
 
Join Date: Nov 2002
Location: Surrey, England
Posts: 8,433
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
Afrow UK is offline   Reply With Quote
Old 3rd October 2011, 12:22   #13
singman
Junior Member
 
Join Date: Sep 2011
Posts: 2
Great !
I was using the Unicode version but my NSIS is no longer compiled with Unicode.

Thanks.
singman is offline   Reply With Quote
Old 12th October 2011, 19:01   #14
Afrow UK
Moderator
 
Afrow UK's Avatar
 
Join Date: Nov 2002
Location: Surrey, England
Posts: 8,433
New plug-in version:
Quote:
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 is offline   Reply With Quote
Old 12th February 2012, 16:39   #15
Afrow UK
Moderator
 
Afrow UK's Avatar
 
Join Date: Nov 2002
Location: Surrey, England
Posts: 8,433
New plug-in version:
Quote:
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:
code:
${ForEachIn} my_array $key $value
DetailPrint "my_array[$key] => $value"
${Next}



Stu
Afrow UK is offline   Reply With Quote
Old 12th February 2012, 19:04   #16
Afrow UK
Moderator
 
Afrow UK's Avatar
 
Join Date: Nov 2002
Location: Surrey, England
Posts: 8,433
New plug-in version:
Quote:
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 is offline   Reply With Quote
Old 13th February 2012, 09:44   #17
Afrow UK
Moderator
 
Afrow UK's Avatar
 
Join Date: Nov 2002
Location: Surrey, England
Posts: 8,433
New plug-in version (hopefully the last for a while):
Quote:
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
Afrow UK is offline   Reply With Quote
Old 5th March 2012, 23:09   #18
vicokoby
Junior Member
 
Join Date: Jun 2011
Posts: 15
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 is offline   Reply With Quote
Old 5th March 2012, 23:32   #19
vicokoby
Junior Member
 
Join Date: Jun 2011
Posts: 15
#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
vicokoby is offline   Reply With Quote
Old 6th March 2012, 09:45   #20
Afrow UK
Moderator
 
Afrow UK's Avatar
 
Join Date: Nov 2002
Location: Surrey, England
Posts: 8,433
nsArray::Set takes multiple values so you need to put /end on the end, i.e.
code:
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 is offline   Reply With Quote
Old 6th March 2012, 13:40   #21
vicokoby
Junior Member
 
Join Date: Jun 2011
Posts: 15
I must /end when I put a single elment?

eg.: nsArray::Set MyArray ´Single´ /end
vicokoby is offline   Reply With Quote
Old 6th March 2012, 16:53   #22
Afrow UK
Moderator
 
Afrow UK's Avatar
 
Join Date: Nov 2002
Location: Surrey, England
Posts: 8,433
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 is offline   Reply With Quote
Old 20th March 2012, 21:23   #23
Afrow UK
Moderator
 
Afrow UK's Avatar
 
Join Date: Nov 2002
Location: Surrey, England
Posts: 8,433
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.

http://nsis.sourceforge.net/File:NsArray.zip

Stu
Afrow UK is offline   Reply With Quote
Old 2nd June 2012, 12:50   #24
Yathosho
Forum King
 
Yathosho's Avatar
 
Join Date: Jan 2002
Location: AT-DE
Posts: 3,347
feature requests:
-unique (removes duplicate values)
-merge (two arrays)
Yathosho is offline   Reply With Quote
Old 2nd June 2012, 16:06   #25
Afrow UK
Moderator
 
Afrow UK's Avatar
 
Join Date: Nov 2002
Location: Surrey, England
Posts: 8,433
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 is offline   Reply With Quote
Old 2nd June 2012, 16:36   #26
Yathosho
Forum King
 
Yathosho's Avatar
 
Join Date: Jan 2002
Location: AT-DE
Posts: 3,347
just a suggestion, after all the same could be said about sorting
Yathosho is offline   Reply With Quote
Old 2nd June 2012, 20:52   #27
Afrow UK
Moderator
 
Afrow UK's Avatar
 
Join Date: Nov 2002
Location: Surrey, England
Posts: 8,433
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
Afrow UK is offline   Reply With Quote
Old 22nd August 2012, 13:11   #28
TVNST
Junior Member
 
Join Date: Aug 2012
Posts: 6
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
TVNST is offline   Reply With Quote
Old 28th August 2012, 18:31   #29
Afrow UK
Moderator
 
Afrow UK's Avatar
 
Join Date: Nov 2002
Location: Surrey, England
Posts: 8,433
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
Afrow UK is offline   Reply With Quote
Old 29th August 2012, 12:49   #30
TVNST
Junior Member
 
Join Date: Aug 2012
Posts: 6
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.
TVNST is offline   Reply With Quote
Old 3rd September 2012, 21:07   #31
Afrow UK
Moderator
 
Afrow UK's Avatar
 
Join Date: Nov 2002
Location: Surrey, England
Posts: 8,433
New version:
Quote:
1.1.1.4 - 3rd September 2012
* Replaced Set /list with SetList.
* Replaced Remove /list with RemoveList.
Please update your code accordingly if you switch to the new version.

Stu
Afrow UK is offline   Reply With Quote
Old 12th December 2012, 06:23   #32
T.Slappy
Senior Member
 
T.Slappy's Avatar
 
Join Date: Jan 2006
Location: Slovakia
Posts: 498
Send a message via ICQ to T.Slappy
What is correct usage of nsArray::Get? I think nsArray corrupts my stack but I cannot find the problem.

This is my code - Is this usage correct?
1)
PHP Code:
ClearErrors
nsArray
::Get UrlTree $CompleteGroup
${If} ${Errors}
    ${
DebugMsg"UrlTree($CompleteGroup) is not set!"
${Else}
    
Pop $CompleteTotal
    
There are some files
${EndIf} 

In documentation I saw this usage:
2)
PHP Code:
  ClearErrors
  nsArray
::Get MyArray 2
  Pop $R0
  
${If} ${Errors}
    
DetailPrint `Error!`
  ${EndIf} 

So in my example (1): I do POP only if ${Errors} is fine.

But the docs say (2): do the POP, then check ${Errors}.

I have many values in stack, so I think POP in (2) will remove element from stack even in case the nsArray does not contain required element.

Is this assumption correct?

Cool looking skinned Graphical Installers: www.graphical-installer.com
I offer NSIS scripting, C/C++/C#/Delphi programming: www.unsignedsw.com
Develop NSIS projects in Visual Studio 2005-2017: www.visual-installer.com
or RAD Studio 2009, 2010, XE-10.2 Tokyo: www.rad-installer.com
T.Slappy is offline   Reply With Quote
Old 12th December 2012, 12:12   #33
Afrow UK
Moderator
 
Afrow UK's Avatar
 
Join Date: Nov 2002
Location: Surrey, England
Posts: 8,433
Yes that is an error in the example script. It will not push anything onto the stack if an error occurs (element not found).

Stu
Afrow UK is offline   Reply With Quote
Old 28th January 2013, 14:33   #34
Fretje
Junior Member
 
Join Date: Nov 2005
Posts: 13
Is there a way to sort an array with version numbers using the versioncompare logic? I'm using "numeric" now, and it doesn't give the right result:

* 4.2.6_32
* 5.1.10.2_32
* 5.1.8.2_32
* 5.1.9.0_32

should be:

* 4.2.6_32
* 5.1.8.2_32
* 5.1.9.0_32
* 5.1.10.2_32

fretje

Last edited by Fretje; 28th January 2013 at 14:34. Reason: wrong order in "should be" section
Fretje is offline   Reply With Quote
Old 28th January 2013, 18:13   #35
Afrow UK
Moderator
 
Afrow UK's Avatar
 
Join Date: Nov 2002
Location: Surrey, England
Posts: 8,433
See attached.

Stu
Attached Files
File Type: nsi nsArray_VersionSort.nsi (1.2 KB, 197 views)
Afrow UK is offline   Reply With Quote
Old 29th January 2013, 09:46   #36
Fretje
Junior Member
 
Join Date: Nov 2005
Posts: 13
Thank you very much for the very fast reply, Stu.
This is exactly what I needed!
Fretje is offline   Reply With Quote
Old 30th January 2013, 11:11   #37
Yathosho
Forum King
 
Yathosho's Avatar
 
Join Date: Jan 2002
Location: AT-DE
Posts: 3,347
btw, the readme still mentions the old syntax for nsArray_ToString
Yathosho is offline   Reply With Quote
Old 9th May 2013, 14:23   #38
Marshallx7
Junior Member
 
Join Date: Oct 2012
Posts: 35
Couldn't find this documented anywhere and I think it is worth mentioning:
/at= does not work with the Set command.
Further more /key= only works on keynames, not indexes, as follows:
code:

nsArray::Set "myArray" "0"
nsArray::Set "myArray" "1"
nsArray::Set "myArray" "2"
nsArray::Set "myArray" "3"
;array now = {"0", "1", "2", "3"}
nsArray::Remove "myArray" /at=1
;array now = {"0", "2", "3"}
nsArray::Set "myArray" /key=2 "three"
;array now = {"0", "three", "3"}


Because elements with no specified keyname are presumably given a keyNAME of their initial index.
The above is correct behaviour as you might have keynames that consist only of numbers.

If you want to have /at= functionality with the Set command then you can add it yourself using the following macro
code:

!macro ArraySetAt arrayname index value
Push $R0
ClearErrors
nsArray::Get "${arrayname}" "/at=${index}"
${IfNot} ${Errors}
Pop $R0 ;key
Exch $R0 ;discard value
Pop $R0 ;discard value
nsArray::Set "${arrayname}" "/key=$R0" "${value}"
${EndIf}
Pop $R0
!macroend

Marshallx7 is offline   Reply With Quote
Old 11th May 2013, 16:56   #39
Afrow UK
Moderator
 
Afrow UK's Avatar
 
Join Date: Nov 2002
Location: Surrey, England
Posts: 8,433
Quote:
Originally Posted by Marshallx7 View Post
/at= does not work with the Set command.
That is correct - the readme does not show any uses of /at= with the Set instruction, but I could add it.
Quote:
Originally Posted by Marshallx7 View Post
Further more /key= only works on keynames, not indexes
This is not true. Your array after the Remove call is:
code:
myArray = {0 => 0, 2 => 2, 3 => 3}

After your Set call, it becomes:
code:
myArray = {0 => 0, 2 => three, 3 => 3}

There is no distinction between numeric keys and string keys. It is just that numeric keys are assigned when no key is specified when adding elements.

Edit: You probably assumed that removing element with index 1 would result in the indexes after it being decreased by 1 also. This does not happen in hashed arrays because then the association is lost. I suppose the plug-in needs a reindex function. For example in PHP you'd use array_values().

Stu
Afrow UK is offline   Reply With Quote
Old 12th May 2013, 09:36   #40
Marshallx7
Junior Member
 
Join Date: Oct 2012
Posts: 35
Sorry I wasn't clear before, yes - what you say the arrays would be is what I concur with, I just didn't mention the keynames.

I fully accept that this is intended behaviour, and I did run my own tests to be sure, because I need Set /at functionality.

To make my position clear to anyone reading, there are NO bugs in nsArray (that I can see) - just Set /at functionality is not (presently) a feature (but you can emulate it using my macro above).

A reindex method might be useful, but I imagine it is more resource intensive than a Set /at command. Using Get /at, Remove /at and Set /at would mean a reindex is not necessary, because you can then choose to either use associative keynames (without /at) or positional indexes (with /at)
Marshallx7 is offline   Reply With Quote
Reply
Go Back   Winamp & SHOUTcast Forums > Developer Center > NSIS Discussion

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump