- NSIS Discussion
- NSISArray sort function
Archive: NSISArray sort function
johnny44
1st December 2005 19:47 UTC
NSISArray sort function
I just started working with arrays and I'm having problems with the sort function. It simply doesn't sort! before posting here I decided to look at the examples provided with the plugin and even the sort.nsi script provided doesn't do anything. The debug screen before and after
${TestArray->Sort} ""
are exactly the same.
Has anyone had this problem?
Thanks for your help.
Afrow UK
1st December 2005 20:24 UTC
It's been a while since I last modified the sort function but last time I checked it worked.
I'll have a look.
Edit: You are correct. The sort function is broken, and it was broken when new code was added to sort one array by another.
I'll upload v0.9 soon.
-Stu
johnny44
1st December 2005 20:32 UTC
It's in my .onInit Function, can it go there or should it be used only in sections?
Sort2Arrays.nsi seems to work....weird, the code is pretty much the same......
Afrow UK
1st December 2005 21:43 UTC
Uploaded.
http://nsis.sourceforge.net/File:NSISArray.zip
You may have noticed (or not) that the Sort function was falsely throwing the "(3) Index out of range." error message (which you'd find by checking the $ArrayErr variable). This told me exactly where the problem was thankfully.
The function throws this error message when using two sorting arrays and when the two arrays are not equal in size.
-Stu
johnny44
1st December 2005 21:59 UTC
Works great! you're quick!
I'd also like to know if the arrays are limited to 32 columns? I tried setting the size to larger numbers, but it seems limited to 32.
Afrow UK
1st December 2005 23:29 UTC
See section 1.10 Array sizes in the documentation (Docs\NSISArray\)
If you would like a custom sized arrays plugin build and don't have the tools then let me know.
-Stu
johnny44
2nd December 2005 15:14 UTC
Sorry....I read the readme until the function definitions. Didn't see 2 of the most important sections for me, array sizes and error messages. Mea culpa....
As for custom Arrays, 256 items would be enough in my case, 128 is a bit short. I ain't no programmer and I don't have the tools to recompile so I'm gonna work with 128, unless it takes only 2 seconds for you to recompile for 256 items and 128 characters. That would be much appreciated.
Could you also test the IsFull function? I tried using it and it never jumped to the full label. It's not major since I went around the problem using
StrCmp $ArrayErr "3" flush 0
Thanks to your help, my installer is now almost complete!
johnny44
2nd December 2005 19:04 UTC
Sorry to bug you again Stu, but can you also check the ReadToStack function. The ReadToStack.nsi example does not seem to work. It looks like an empty string is popped from the stack. Nothing comes out when using range 0 -1 but with 0 3 I get a blank item in between each item:
item 0:
item 1: one
item 2:
item 3:two
I looked at $ArrayErr and it holds the first item (zero).
If I leave the range at 0 3 and place
!define ArrayErrorMsgBox
at the beginning, it works. If I change the range back to 0 -1 and leave the !define, I get error message (3)index out of range. I hope this helps you find the problem.
Edit:
Here's something else regarding the WriteList and WriteListC functions. I modified the Is.nsi example like this:
!define FuncName 'Is Functions'
name '${FuncName}'
outfile 'ArrayExample - ${FuncName}.exe'
caption '${FuncName}'
!define ArrayErrorMsgBox
!include NSISArray.nsh
showinstdetails show
${Array} "TestArray"
Section
DetailPrint "Initializing array..."
${TestArray->Init}
DetailPrint "Testing 'WriteList'..."
${TestArray->WriteList} "'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 'u' 'v' 'w' 'x' 'y' 'z' '1' '2' '3' '4' '5' '6' '7' '8' '9' '0'"
${TestArray->Debug}
${TestArray->Concat} $0 "&"
DetailPrint "$0"
DetailPrint "Testing 'IsEmpty'..."
${TestArray->IsEmpty} +2 0
DetailPrint "TestArray is NOT empty!"
DetailPrint "Testing 'IsFull'..."
${TestArray->IsFull} +2 0
DetailPrint "TestArray is NOT full!"
DetailPrint "Testing 'IsInRange'..."
${TestArray->IsInRange} 3 0 +2
DetailPrint "Index of 3 is in range of TestArray!"
DetailPrint "Testing 'IsInRange' again..."
${TestArray->IsInRange} 4 +2 0
DetailPrint "Index of 4 is NOT in range of TestArray!"
${TestArray->Delete}
${ArrayUnload}
SectionEnd
page instfiles
The WriteList and WriteListC functions do not seem to care about the 32 items limit. The debug screen shows all 36 items and all of them are passed to the concatenation function.
Notice that the IsFull function still shows up as non-full.
Afrow UK
2nd December 2005 23:35 UTC
My goodness. It appears that lstrcpy redimensions the array. In other words it doesn't matter what index of the array you write to... it will still be written. I wrote to an index of 99 of a 32 dimension array and the value that I wrote is returned when refering to that index.
Therefore it seems that there is not limit to the number of items in the array. I'm now going to see if there's really a limit to the number of arrays that you can have.
I've fixed all the other problems, but this appears to be even more major.
Edit: In some cases it writes the data successfully, but in others either no data is written or the installer crashes. Therefore I'm going to stick to having fixed sized arrays like it should be (I'll make WriteList induce Index out of range error if there are too many items to be written).
-Stu
Afrow UK
2nd December 2005 23:53 UTC
Done.
IsFull was failing because you wrote >32 items to a 32 item array. IsFull does a less than or equal to comparison, not a greater than.
http://nsis.sourceforge.net/File:NSISArray.zip
Edit: What array dimensions would you like for your custom DLL. NSISArray is 32 x 1024 strings. NSISArray128 is 128 x 256 strings.
-Stu
johnny44
5th December 2005 14:10 UTC
Hi Stu,
The array size that would be best suited for my application is 256 items X 128 characters.
I confirm that the IsFull function works great, but I'm still having problems with the ReadToStack example. If I don't modify anything I still get this
Item 0:
Item 1: one
Item 2:
Item 3: two
When I change the range to 0 3 I get all empty strings. This is the opposite behavior from when I mentioned it to you in the first place.
EDIT: **DELETED**
EDIT2: My bad, !define ArrayPluginAll 128.[B]
Afrow UK
5th December 2005 16:46 UTC
Sorry about that. Properly fixed now.
http://nsis.sf.net/File:NSISArray.zip
And here is the 256 x 128 build attached.
Simply use !define ArrayPluginAll 256 after placing the .dll in the Plugins folder.
-Stu
johnny44
5th December 2005 17:47 UTC
great, I just think you forgot to attach the 256 X 128 build....
Afrow UK
5th December 2005 18:53 UTC
Hmm, here it is.
-Stu
johnny44
6th December 2005 14:29 UTC
Hey Stu, it's your favourite bugger again!
Thanks for the 256X128 array plugin. I tried it and it seems to work except in some weird cases where the first item is corrupted in my second array. I didn't do much testing on it though and it might just be me so don't worry about it.
My script is going well and now I am to the point where I need to find out if an item is alredy there. I'm using the SearchI function and there seems to be a problem with it. Only the first 3 characters are compared. If they match, it returns the first matching index value.
Could you look into it? The Search function seems to do the same thing. Here's a test script:
!define FuncName 'SearchI'
name '${FuncName}'
outfile 'ArrayExample - ${FuncName}.exe'
caption '${FuncName}'
!define ArrayNoValVar
!include NSISArray.nsh
!include StrFunc.nsh
showinstdetails show
${StrTrimNewLines}
${Array} "TestArray"
Function .onInit
GetTempFileName $R9
FileOpen $R2 $R9 w
FileWrite $R2 "Cat$\r$\n"
FileWrite $R2 "catt$\r$\n"
FileWrite $R2 "cate$\r$\n"
FileWrite $R2 "catherine$\r$\n"
FileWrite $R2 "CaDog$\r$\n"
FileWrite $R2 "CaHippo$\r$\n"
FileClose $R2
CopyFiles /SILENT $R9 "animals.txt"
Delete $R9
FunctionEnd
Section
DetailPrint "Initializing array.."
${TestArray->Init}
FileOpen $R0 animals.txt r
Loop:
ClearErrors
FileRead $R0 $0
IfErrors End
Push $0
Call StrTrimNewLines
Pop $0
DetailPrint "ArrayItem:$0"
${TestArray->SearchI} $1 "$0" 0
DetailPrint "Index:$1"
StrCmp $1 "-1" 0 same
${TestArray->Shift} "$0"
Goto Loop
Same:
DetailPrint "Item previously added"
Goto Loop
End:
DetailPrint "TestArray should contain:Cat, catt, cate, catherine, CaDog and CaHippo"
${TestArray->Debug}
${TestArray->Delete}
${ArrayUnload}
FileClose $R0
Delete "$EXEDIR\animals.txt"
SectionEnd
page instfiles
Afrow UK
6th December 2005 15:31 UTC
I'll take a look at it when I get home (2 hours from now). I wouldn't be suprised if there's an error because I wrote my own search procedures.
-Stu
johnny44
6th December 2005 16:10 UTC
I confirm the bug with !define ArrayPlugin 256.
Name "WriteListC"
OutFile "WriteListC_test.exe"
Caption "$(^Name)"
!define ArrayPlugin 256
!define ArrayNoValVar
!include NSISArray.nsh
${Array} SoftList
XPStyle on
ShowInstDetails show
Section
${SoftList->Init}
DetailPrint "Writing one, two, three..."
${SoftList->WriteListC} "one|two|three" "|"
${SoftList->Debug}
${SoftList->Delete}
${ArrayUnload}
SectionEnd
This test script shows weird characters at the end of the first item. The problem appears when used with WriteListC only. The 128 plugin seems to have a similar behaviour in this test script .
EDIT: for the 128 plugin, only the first array has this problem. The second and subsequent arrays in your script will be fine.: WriteList, Push and Shift work OK
Afrow UK
6th December 2005 21:16 UTC
Here it is. Took longer than expected mainly because there was more work needed than expected.
The strange characters appearing on the end of the strings were caused by stack corruption (I think that is the correct term). I was getting the end of the actual "WriteListC" function name appended to my first array item (so it was "oneListC")!
I've fixed this problem by using using static variables throughout instead, and by clearing the contents of each static variable when finished with.
This means the DLL's have increased in size a little (1KB) but all variables will be created when the function(s) are first ran, rather than every time they are ran.
I've also fixed the Search and SearchI functions. The original code that I wrote was very dodgy (I must have been drunk or something!)
I've also added a ${myArray->Print} instruction to the script header for debugging purposes.
-Stu
johnny44
9th December 2005 17:02 UTC
My first version is complete and working!! I'm now integrating new features and modifying certain aspects. On the wishlist side of things....Back to the sort function:
!define FuncName 'Sort'
name '${FuncName}'
outfile 'ArrayExample - ${FuncName}.exe'
caption '${FuncName}'
!define ArrayNoValVar
!include NSISArray.nsh
showinstdetails show
${Array} "TestArray"
Section
DetailPrint "Initializing array..."
${TestArray->Init}
${TestArray->WriteList} "'1' '2' '3' '13' '21'"
DetailPrint "Sorting..."
DetailPrint "Now View the sorted version:"
${TestArray->Sort} ""
${TestArray->Debug}
${TestArray->Delete}
${ArrayUnload}
SectionEnd
page instfiles
sorts in this order: (1, 13, 2, 21, 3) this is not really what we usually want for numbers. Is there any way you could modify this? That's about it for now.
BTW, A HUGE thanks for making things work for me. I just could not believe how fast you answered my requests. I now have a working application and you played a major role in it. AfrowUK rules!!!
Afrow UK
9th December 2005 18:34 UTC
I'll see what I can do. I think it's because it uses a string comparison rather than a proper number comparison.
-Stu