'===========================================================================
' Subject: ARRAYS OF ARRAYS                   Date: 12-19-95 (14:15)       
'  Author: Jamshid Khoshrangi                 Code: PB32                   
'  Origin: qjackson@direct.ca               Packet: PB.ABC
'===========================================================================
$IF 0

    ARRARR.BAS                                                  ARRARR.BAS

                     Arrays of Arrays Demonstration Code

                  Copyright 1995 by AhuraMazda(tm) Software

                         (FOR POWERBASIC 3.2 ONLY!)

                        Written by Jamshid Khoshrangi

                   This program is copyrighted freeware.

$ENDIF

$IF 0

    NOTE:

    The purpose of this file is to explore creating "arrays of arrays."

    I would like to create an array of string arrays, where each subarray
    can be of an indeterminite length.  The trouble with "native" two
    dimensional string arrays is that they are x by y elements in size.

    This demonstration shows how it is possible to create an array of
    arrays where each subarray has a unique number of elements.

    This is an experimental program, so I don't guarantee anything.
    It's not the prettiest code in the world.

    I hope it helps you as much as it has me!

    Jamshid

$ENDIF

DEFINT A-Z

%DESC.LENGTH = 64

DIM ListNameArray(1:32) AS SHARED STRING
DIM ListDescArray(1:32) AS SHARED STRING * %DESC.LENGTH

DIM NumLists AS SHARED INTEGER

LoggedList$ = "NONE"

DO
    CLS
    PRINT
    PRINT "Currently logged to list {"; LoggedList$; "}"
    PRINT
    PRINT "C)reate List"
    PRINT "A)dd member to list"
    PRINT "S)witch to list"
    PRINT "D)isplay list"
    PRINT "F)ind member"
    PRINT "Q)uit"

    DO
        K$ = UCASE$(INKEY$)
    LOOP UNTIL LEN(K$)

    SELECT CASE K$
        CASE "Q"
            EXIT DO

        CASE "C"
            ListCreate LoggedList$

        CASE "A"
            ListMemberAdd LoggedList$

        CASE "S"
            ListSwitch LoggedList$

        CASE "D"
            ListDisplay LoggedList$

        CASE "F"
            ListMemberFind

    END SELECT

LOOP

CLS
PRINT "Demo summary information:"

FOR i = 1 TO NumLists
    REDIM Temp(1) AS STRING
    ArrayFromArrayGet ListDescArray(i), Temp()
    PRINT "Subarray {";ListNameArray(i);"} has"; UBOUND(temp); "element(s)."
    ArrayToArrayPut ListDescArray(i), Temp()
NEXT i

PRINT
PRINT "Thank you for trying this program out!"
BEEP 2

SUB ListCreate (ListName AS STRING)

    ' creating a list has the side effect of logging onto that list

    CLS
    PRINT "Create List"
    PRINT
    LINE INPUT "New List Name: "; NewList$

    ARRAY SCAN ListNameArray(), = NewList$, TO ListPtr
    IF ListPtr THEN
        PRINT "List already exists!"
        PRINT "Hit any key to continue...."
        SLEEP
        EXIT SUB

    ELSE

        INCR NumLists
        IF NumLists < UBOUND(ListDescArray) THEN
            ListName = NewList$
            ListNameArray(NumLists) = NewList$
            DIM Holder(0:0) AS STRING
            ArrayToArrayPut ListDescArray(NumLists), Holder()
        ELSE
            PRINT "List limit reached!"
            PRINT "Hit any key to continue...."
            SLEEP
        END IF

    END IF

END SUB

SUB ListMemberAdd (LoggedList AS STRING)

    IF LoggedList = "NONE" THEN
        PRINT
        PRINT "You must first log onto a list!"
        PRINT "Hit any key to continue...."
        SLEEP
        EXIT SUB
    ELSE
        CLS
        PRINT "Add member to list {"; LoggedList; "}"
        PRINT
        LINE INPUT "New member: "; NewMember$

        ARRAY SCAN ListNameArray(), = LoggedList, TO ListPtr

        DIM Temp(1) AS STRING
        ArrayFromArrayGet ListDescArray(ListPtr), Temp()

        TopElem = UBOUND(Temp) + 1
        REDIM.PRESERVE Temp(), TopElem
        Temp(TopElem) = NewMember$

        ' we must be sure to put the array back into the holder array
        ArrayToArrayPut ListDescArray(ListPtr), Temp()

    END IF

END SUB

SUB ListSwitch (LoggedList AS STRING)

    DO
        CLS
        PRINT "Switch lists"
        PRINT

        FOR i = 1 TO NumLists
            PRINT ListNameArray(i),
        NEXT i
        PRINT
        PRINT
        LINE INPUT "Log onto list: "; NewList$

        ARRAY SCAN ListNameArray(), = NewList$, TO ListPtr
        IF ListPtr THEN
            LoggedList = NewList$
            EXIT DO
        END IF
        PRINT
        PRINT "List does not exist!"
        PRINT "Hit any key to reenter...."
        SLEEP
    LOOP

END SUB

SUB ListDisplay (LoggedList AS STRING)

    IF LoggedList = "NONE" THEN
        PRINT
        PRINT "You must first log onto a list!"
        PRINT "Hit any key to continue...."
        SLEEP
        EXIT SUB
    ELSE
        CLS
        PRINT "Display of members of list {"; LoggedList; "}"
        PRINT

        ARRAY SCAN ListNameArray(), = LoggedList, TO ListPtr

        DIM Temp(1) AS STRING
        ArrayFromArrayGet ListDescArray(ListPtr), Temp()

        FOR i = 1 TO UBOUND(Temp)
            PRINT Temp(i)
        NEXT i

        ' we must be sure to put the array back into the holder array
        ArrayToArrayPut ListDescArray(ListPtr), Temp()

        PRINT
        PRINT "Hit any key to continue...."
        SLEEP

    END IF

END SUB


SUB ListMemberFind ()

    CLS
    PRINT "Find first member"
    PRINT
    LINE INPUT "Member to find: "; TheMember$

    IF NumLists = 0 THEN
        PRINT "You must create at least one list to use this feature!"
        PRINT "Hit any key to continue...."
        SLEEP
        EXIT SUB
    END IF

    ArrayArrayScan ListDescArray(), TheMember$, OutPtr, OutElem

    IF OutElem THEN
        PRINT
        PRINT "The member '";TheMember$; "' was first found in"
        PRINT "the list called {"; ListNameArray(OutElem);"}."
        PRINT "It was element number"; OutPtr;"in that list."
        PRINT
        PRINT "Hit any key to continue...."
        SLEEP

    ELSE
        PRINT "Member not found in any list."
        PRINT "Hit any key to continue...."
        SLEEP
    END IF

END SUB

SUB ArrayArrayScan (_
    DescArray() AS STRING * %DESC.LENGTH,_
    Test AS STRING,_
    OutPtr AS INTEGER,_
    OutElem AS INTEGER)

    DIM Temp(0:0) AS STRING

    FOR i = 1 TO UBOUND(DescArray)
        IF DescArray(i) <> STRING$(%DESC.LENGTH,0) THEN
            ArrayFromArrayGet DescArray(i), Temp()

            ARRAY SCAN Temp(), =Test, TO OutPtr

            ' we must be sure to put the array back into the holder array
            ArrayToArrayPut DescArray(i), Temp()
        END IF
        IF OutPtr THEN
            OutElem = i
            EXIT SUB
        END IF
    NEXT i

END SUB

SUB ArrayFromArrayGet (_
    DescArray AS STRING * %DESC.LENGTH,_
    ANY)

    DIM Source AS DWORD

    ! mov ax, [bp+6]
    ! mov bx, [bp+8]
    ! mov Source[0], ax
    ! mov Source[2], bx

    Dest???   = VARPTR32(DescArray)

    DIM InDesc  AS STRING PTR * %DESC.LENGTH
    DIM OutDesc AS STRING PTR * %DESC.LENGTH

    InDesc = Source
    OutDesc = Dest???

    SWAP @InDesc, @OutDesc

END SUB


SUB ArrayToArrayPut (_
    DescArray AS STRING * %DESC.LENGTH,_
    ANY)

    '   NOTE:  Once the array has been PUT to the holder array, it
    '   MUST NOT BE EXPLICITLY ACCESSED!

    DIM Source AS DWORD

    ! mov ax, [bp+6]
    ! mov bx, [bp+8]
    ! mov Source[0], ax
    ! mov Source[2], bx

    Dest???   = VARPTR32(DescArray)

    DIM InDesc  AS STRING PTR * %DESC.LENGTH
    DIM OutDesc AS STRING PTR * %DESC.LENGTH

    InDesc = Source
    OutDesc = Dest???

    SWAP @InDesc, @OutDesc

END SUB

%TRUE   =   -1
%FALSE  =   NOT %TRUE

SUB REDIM.PRESERVE (InArray() AS STRING, NewMax AS INTEGER)

ArrayStart  = LBOUND (InArray)
ArrayEnd    = UBOUND(InArray)

'   We'd better make it HUGE, just in case the original array was
'   huge....
DIM HUGE OutArray(ArrayStart:NewMax) AS STRING

SELECT CASE NewMax > ArrayEnd
  CASE %TRUE
        FOR i = ArrayStart TO ArrayEnd
          OutArray(i) = InArray(i)
        NEXT i
        REDIM InArray(ArrayStart:NewMax) AS STRING
        FOR i = ArrayStart TO ArrayEnd
            InArray(i) = OutArray(i)
        NEXT i

    CASE %FALSE
        FOR i = ArrayStart TO NewMax
            OutArray(i) = InArray(i)
        NEXT i
        REDIM InArray(ArrayStart:NewMax) AS STRING
        FOR i = ArrayStart TO NewMax
            InArray(i) = OutArray(i)
        NEXT i

END SELECT

END SUB
