'===========================================================================
' Subject: XMS SORTING INTERFACE              Date: 08-06-97 (18:26)       
'  Author: Vincent D. Voois                   Code: QB, PDS                
'  Origin: vv@musician.org                  Packet: LIBRARY.ABC
'===========================================================================
  ' XMS-sorting interface by Vincent Voois
  ' This little program demonstrates sorting of various textlines from a
  ' texfile loaded into XMS memory.
  ' Note that you need the object file which handles the XMSroutines of Robin
  ' Duffy (Sequential Software Inc.) somewhere on the MEMORY.ABC Packet
  '
 
  DEFINT A-Z

  DECLARE FUNCTION GetXMS% (Handle%) 'Duffy's part of his XMS routine
  DECLARE FUNCTION GetReeks$ (Nummer&) 'Interface between XMS and Basic memory.
  DECLARE FUNCTION WhichXError% () 'Duffy's part of his XMS routine
  DECLARE FUNCTION XMSError% () 'Duffy's part of his XMS routine

  DECLARE SUB FreeHandles () 'Clearing all possible XMS-handles
  DECLARE SUB PutReeks (Variabele$, Nummer&) 'Interface between XMS and Basic memory.
  DECLARE SUB HuthSort () ' Mike Huth's SortAlgorithm
  DECLARE SUB Switch (A&, B&) 'Interface between XMS and Basic memory.
 
  TYPE StackType
    low AS LONG 'These were integers in original, i allways use long just in
                'in doubtfull case.
    hi AS LONG  'at least you can sort a few million elements now :)
  END TYPE


  TYPE Buffer
    FileLine AS STRING * 128 'Set line read limit to 128 chars, increase this
  END TYPE                   'whenever your linelengths are bigger.
                             'Do know, that enlarging the stringsize will slow
  CLEAR                      'up the sortroutine and you risk clogging up stack
                             'space even with Huth's sort-algorithm!
                             'Stackclogging danger may arise above 1024 bytes.

  DIM SHARED File(1) AS Buffer 'This is the interface variable between XMS&Bas
 
  DIM SHARED FileHandle% 'This is an XMS handle associated with file-routines
 
  DIM SHARED FileLines& 'These are the total of lines inside the loaded file
 
  DIM SHARED Leng% 'This is the length of the longest line inside the file.
                   'This one may not exceed 128, else increase the FileLine
                   'length
  CLS

  CALL InitXMS(Status%, MemSize&)

  FreeHandles 'Clear all (possible) open handles:
              'when interrupting testprocedures, you're memory can get clogged
              'up with previous test-data,closing XMS-handle pointers is must!

  ' Open file, count the lines included and measure the linelengths

  PRINT "Checking input data..."

  OPEN "text.tst" FOR INPUT AS #1 'or Any file with some textlines in it

  DO WHILE NOT EOF(1)
    LINE INPUT #1, A$

    FileLines& = FileLines& + 1

    IF LEN(A$) > Leng% THEN
      Leng% = LEN(A$)
    END IF

  LOOP

  Leng% = Leng% + 1

  CLOSE

  'The memory to allocate will be all filelines multiplied by the longest line
  'it's length, devided by 1024 and added 1K for insurance.
 
  TotalFileSize% = ((FileLines& * Leng%) \ 1024) + 1

  'Calculate statistics
 
  MustMem& = TotalFileSize%
 
  MustMem& = MustMem& * 1024
 
  PRINT "Allocating memory:"; MustMem&; "Bytes"

  'Fill Filehandle
 
  FileHandle% = GetXMS(TotalFileSize%)

  ' Open up file again and fill up XMS memory with the contents, do check on
  ' errors during xms-transfers

  OPEN "text.tst" FOR INPUT AS #1

  DO WHILE NOT EOF(1)
    LINE INPUT #1, In$

    LineNumber& = LineNumber& + 1
   
    PutReeks In$, LineNumber&

    Xerror% = WhichXError

    IF XMSError THEN
      FreeHandles

      PRINT LineNumber&

      PRINT "Error closing..."; Xerror%

      CLOSE

      END
    END IF

  LOOP

  'Sorting the stuphz in XMS through basic...

  PRINT "Sorting "; FileLines&; "Elements...."

  HuthSort
 
  ' And show the sorted stuphz
 
  FOR i& = 1 TO LineNumber&
    PRINT ">"; GetReeks$(i&); "<"

    IF NonStop% = 0 THEN

      DO
        T$ = INKEY$
      LOOP UNTIL T$ <> ""

      IF T$ = "n" THEN
        NonStop% = 1
      END IF

      IF T$ = CHR$(27) THEN
        FreeHandles

        PRINT "Aborting..."

        END
      END IF

    END IF

  NEXT i&

  FreeHandles

SUB FreeHandles
 
  ' This routine is clearing various XMS handles, i just did it to be capable
  ' to interrupt basic routines while testing them without clogging up memory
  ' with reults of previous tests.

  CALL FreeXMS(10)
  CALL FreeXMS(9)
  CALL FreeXMS(8)
  CALL FreeXMS(7)
  CALL FreeXMS(6)
  CALL FreeXMS(5)
  CALL FreeXMS(4)
  CALL FreeXMS(3)
  CALL FreeXMS(2)
  CALL FreeXMS(FileHandle%)
  
END SUB

FUNCTION GetReeks$ (Nummer&)
 
  ' This routine substitutes the [Array()] handlers of Quickbasic
  ' It get's an element out of XMS-memory and then stores it into a string
  ' value.

  File(1).FileLine = STRING$(Leng%, " ")
 
  CALL XGetElement(FileHandle%, File(1), Leng%, Nummer&)
 
  GetReeks$ = RTRIM$(File(1).FileLine)
 
END FUNCTION

SUB HuthSort

DIM Compare$


DIM aStack(1 TO 1024) AS StackType

  StackPtr = 1
 
  aStack(StackPtr).low = 1
 
  aStack(StackPtr).hi = FileLines&
 
  StackPtr = StackPtr + 1
 
  DO
    StackPtr = StackPtr - 1
   
    low& = aStack(StackPtr).low
   
    hi& = aStack(StackPtr).hi
   
    DO
      i& = low&
     
      j& = hi&
     
      Mid& = (low& + hi&) \ 2
     
      'Want to see searching results? unremark below lines.
     
      'LOCATE 5, 1
     
      'PRINT "mid:"; Mid&
      'PRINT "I:"; i&
      'PRINT "J:"; j&
     
      Compare$ = GetReeks$(Mid&)
     
      DO
       
        DO WHILE GetReeks$(i&) < Compare$
          i& = i& + 1
        LOOP
       
        DO WHILE GetReeks$(j&) > Compare$
          j& = j& - 1
        LOOP
       
        IF i& <= j& THEN
          Switch i&, j&
         
          i& = i& + 1
         
          j& = j& - 1
        END IF

      LOOP WHILE i& <= j&
     
      IF j& - low& < hi& - i& THEN
       
        IF i& < hi& THEN
         
          aStack(StackPtr).low = i&
         
          aStack(StackPtr).hi = hi&
         
          StackPtr = StackPtr + 1
        END IF
       
        hi& = j&
      ELSE
       
        IF low& < j& THEN
          aStack(StackPtr).low = low&
         
          aStack(StackPtr).hi = j&
         
          StackPtr = StackPtr + 1
        END IF
       
        low& = i&
      END IF
   
    LOOP WHILE low& < hi&
 
  LOOP WHILE StackPtr <> 1
END SUB

SUB PutReeks (Variabele$, Nummer&)

  ' This routine substitutes the [Array()] handlers of Quickbasic
  ' It set's an element into XMS-memory with a basic-string value.
  ' You can change this to your needs to let it insert other values than
  ' stringvalues.
 
  File(1).FileLine = STRING$(Leng%, " ")

  File(1).FileLine = Variabele$
 
  CALL XSetElement(FileHandle%, File(1), Leng%, Nummer&)
 
END SUB

SUB Switch (A&, B&)
 
  'This routine is the substitute of Basic's [SWAP] function.
  'It does the same with arrays and strings in XMS as Swap does in Basic.
  'You only work with the corresponding arrayelements this time.

  B$ = GetReeks$(B&)
 
  A$ = GetReeks$(A&)
 
  'I tried 'PutReeks GetReeks$(B&), A&' but that was not a wise decision i
  'made, it took me one day to find THAT bug that doubled up the lines.
  'I think that passing a Functionstring to a Subroutine causes trouble in
  'the first place. just don't adapt a trick like that avoid long debugging.

  PutReeks B$, A&
 
  PutReeks A$, B&

END SUB
