Array Simulation

nchernoff

Administrator
Staff member
May 16, 2008
42
2
#1
Migrated From JP Software Wiki

Description

Arrays are not directly support by 4NT/TCMD, but a syntax similar to arrays can be simulated. The simulation is that, while the usage may be similar to array usage in syntax, standard environment variables are actually used to store the values. The combination of functions and aliases renames the referenced array position to refer to the array_ArrayName_Position environment variable.


The library file below has general functions for manipulating arrays. The array library is initialized using the

Code:
gosub "file" label
syntax introduced in version 8.0 of 4NT and TCMD. A similar syntax is used for the aliases and functions created by the InitLib subroutine. Creating an array using the arrayCreate alias (and the called Create subroutine) creates aliases and functions with that array name. For example, creating an array named 'arTest1' creates an alias named 'arTest1' and a function named 'arTest1'. Deleting the array by calling arrayDelete will delete the alias and function for that array. A list of all arrays in use is stored in an arrayNames environment variable. Calling the arrayTermLib alias created by the InitLib subroutine deletes all of the created arrays, aliases, and functions.


A better name for this library might be collection instead of array. Because this is a simulation of array usage, the position does not need to be strictly numeric. In the example test script, a two-dimensional array is simulated by using a period (.) delimiter as in this line:

Code:
echo arTest1[2.1]=%@arTest1[2.1]
In fact, any set of characters that are valid in an environment variable name can be used. So, instead of specifying 2.1 for a position, a named position could be used, similar to that of a hash collection, as shown in this example:

Code:
echo arTest1[Height]=%@arTest1[Height]
In the C/C++ world, this would also be similar to using a #DEFINE for the position name. With that explanantion out of the way, here are the Array.btm and ArrayTest.btm files. Additional comments are within the script code.


Contributed by: Tim Butterfield

Array.btm

Code:
@echo off
REM Array library
REM Library of subroutines, aliases, and functions for manipulating
REM variables in an array-like fashion.
::
:: Subroutines
:: InitLib - initialize library--create aliases and functions
::
:: Aliases
:: arrayTermLib - terminate library usage--cleans up arrays, aliases, 
::       and functions
:: arrayCreate - create an array and associated aliases and functions
:: arrayDelete - delete/cleanup an array and associated aliases and functions
:: arraySet - set the value of an array/position
::
:: Functions
:: arrayGet - get a value from an array/position
:: arrayNames - return the names of existing arrays
::
goto end


:InitLib
:: Initialize the library
alias arrayTermLib=^`gosub "%_batchname" TermLib^`
alias arrayCreate=^`gosub "%_batchname" Create %%$^`
alias arrayDelete=^`gosub "%_batchname" Delete %%$^`
alias arraySet=^`gosub "%_batchname" Set %%$^`
function arrayGet=^`%%@execstr[gosub "%_batchname" Get %%$]^`
function arrayNames=^`%%@execstr[gosub "%_batchname" ArrayNames %%$]^`
:: make sure variables are empty
set arrayNames=
set arrayName=
return


:ArrayNames
:: return name of arrays without trailing . delimiters
echo %@trim[%@replace[.,,%arrayNames]]
return


:Create [arrayName]
:: Create an array
:: Create set-alias and get-function
alias %arrayName=^`gosub "%_batchname" Value %arrayName %%$^`
function %arrayName=^`%%@execstr[gosub "%_batchname" Value %arrayName %%$]^`
:: Add array name to list of existing arrays using trailing . delimiter.
set arrayNames=%arrayNames% %arrayName%.
return


:Delete [arrayName]
:: Delete an array
:: Remove array elements
unset array_%arrayName%_*
:: Remove array name from the list
set arrayNames= %@trim[%@replace[ %arrayName.,,%arrayNames]]
:: Remove get-function and set-alias
unfunction %arrayName
unalias %arrayName
return


:Set [arrayName, position, value]
:: Set an array position to a value
set array_%arrayName%_%position%=%value
return


:Get [arrayName, position]
:: Get a value from an array position
echo %[array_%arrayName%_%position%]
return


:Value [arrayName, position, value]
:: if the position is 0, return name of environment variable
iff %position EQ 0 then
   :: return 'set' name  Example:  set %@ar[0,position]=value
   echo array_%arrayName%_%value
else
   :: Get/set an array/position value
   iff %@len[%value] GT 0 then
      set array_%arrayName%_%position%=%value
   else
      echo %[array_%arrayName%_%position%]
   endiff
endiff
return


:TermLib
:: Terminate the array library
:: Delete all of the existing arrays
do while %@words[%arrayNames] GT 0
   :: Remove trailing . delimiter from array name before calling delete
   arrayDelete %@replace[.,,%@word[-0,%arrayNames]]
enddo
:: delete aliases and functions
unalias arrayTermLib
unalias arrayCreate
unalias arrayDelete
unalias arraySet
unfunction arrayGet
unfunction arrayNames
:: make sure variables are empty
set arrayNames=
set arrayName=
return

:End
ArrayTest.btm

Code:
@echo off
REM Initialize array library
gosub "Array.btm" InitLib

REM Create a couple of arrays
arrayCreate arTest1
arrayCreate arTest2

REM Set and show an element in the first array using general array set/get
arraySet arTest1 1 "This is a test"
echo arTest1[1]=%@arrayGet[arTest1, 1]

REM Set and show an element in the first array using array name set/get
arTest1 1 "This is another test"
echo arTest1[1]=%@arTest1[1]

REM Simulate two dimensional array position using . delimiter
arTest1 2.1 "This is position 2.1 of array 1"
echo arTest1[2.1]=%@arTest1[2.1]

REM Set and show an element in the second array
arTest2 1 "This is position 1 of array 2"
echo arTest2[1]=%@arTest2[1]

REM Use '0' first parameter of function to get 'name' of variable to set
set %@arTest2[0,2]="This is position 2 of array 2"
echo arTest2[2]=%@arTest2[2]

REM Show existing arrays
echo Arrays=%@arrayNames[]

REM Delete an array
arrayDelete arTest1

REM Show existing arrays
echo Arrays=%@arrayNames[]

:end
REM Shut down array library
arrayTermLib