_FAST SORTING USING LARGE STRING BUFFERS_ by Dale Thorn [LISTING ONE] '============================================================================== 'NSORT.BAS Sort/retrieve/index data; ascending/descending; mixed data types ' By: Dale Thorn ' Rev. 03/26/91 '============================================================================== main: defint a-w deflng x defsng y defdbl z declare function midchar(i$, i) 'use Basic function (listed) if PDQ not avail. dim ibeg(10), ilen(10), iptx(100, 1), iseq(10), char$(255) common shared compln, ddunit, grpptr, grptot, maxrcd, memndx, ndunit common shared ndxgrp, ndxlen, nosegs, nvflag, offset, opcode, opinit common shared outptr, outtot, rcdptr, rcdtot, recptr, sdunit, sortln common shared sortsq, subtot, ibeg(), ilen(), iptx(), iseq(), char$() compln = 0 'comparison length in sort data (sdat$); may be less than sortln ddunit = 0 'file channel/unit number for index-building (opcode = -3) grpptr = 0 'sort group record pointer/sort buffer pointer grptot = 0 'internal sort group size maxrcd = 0 'internal maximum sort group size memndx = 0 'internal index-load flag ndunit = 0 'file channel/unit number for sort index files ndxgrp = 0 'internal index file group record counter ndxlen = 0 'internal index file record size nosegs = 0 'no. of sort segments in sdat$; total length of segments = compln nvflag = 0 'internal optimization for least ascending/descending inversions offset = 0 'internal group-to-record offset counter opcode = 0 'sort operation (0 to -3) opinit = 0 'internal sort operation data initialization flag outptr = 0 'internal data output record pointer outtot = 0 'internal data output record counter rcdptr = 0 'internal sort data record counter (all records) rcdtot = 0 'internal sort data record total (final count) recptr = 0 'internal sort data record counter (group records) sdunit = 0 'file channel/unit number for sort data file (.sdx) sortln = 0 'length of sort data buffer (sdat$); may be greater than compln sortsq = 0 'internal sort sequence (ascending/descending) flag subtot = 0 'internal partial group data record total (final count) drcd$ = "" 'temp. sort data record buffer nrcd$ = "" 'sort index file buffer sbuf$ = "" 'main sort group memory buffer sdat$ = "" 'main sort data record buffer smsk$ = "" 'sort data mask (must be uppercased) [BBXXXBBXXXXXBB.....] sndx$ = "" 'sort index-pointer memory buffer '// NOTE: Any lines below with an asterisk (*) on the extreme ///// ' right will require a modification or replacement. ///// '/////// Modification applies to DATA statements as well. ///// sortln = 40 'total sort buffer length* pfmt$ = space$(5) 'output format buffer for integer strings sdat$ = space$(sortln) 'sort data record buffer restore sortdata1 'first tablespec to sort from read sdunit, ndunit, ddunit 'file channel/unit numbers used by NSORT.SUB read ibeg(0), ilen(0), iseq(0) 'test values from table sortdata1 nosegs = 0 'initialize total no. of sort segments while ibeg(0) 'begin loop to load segment pointers and flags nosegs = nosegs + 1 'increment total sort segments ibeg(nosegs) = ibeg(0) 'segment begin pointer for sdat$ buffer ilen(nosegs) = ilen(0) 'segment length iseq(nosegs) = iseq(0) 'segment sort sequence (ascending/descending) compln = compln + ilen(0) 'total sort compare length read ibeg(0), ilen(0), iseq(0) 'read next set of test values wend smsk$ = string$(compln, "X") 'allocate masking buffer (default type=character) mid$(smsk$, 21) = "BB" '"binary" position specified* mid$(smsk$, 33) = "BB" '"binary" position specified* restore sortdata2 'sample sort data table opcode = 0 'set flag to add records to sort (initial operation) nrcds = 0 'number of records added to the sort do 'begin loop to read data and add to sort segptr = 1 'set segment position pointer for sdat$ lset sdat$ = "" 'clear the sort data buffer prior to loading for segno = 1 to nosegs 'begin loop to load each data segment read segdata$ 'read data segment from table sortdata2 if len(segdata$) = 0 then exit do 'exit read-data loop at end-of-data if midchar(smsk$, segptr) = 66 then '16-bit integer segment mid$(sdat$, segptr) = mki$(val(segdata$)) 'convert data to integer else 'character segment mid$(sdat$, segptr) = segdata$ 'put character segment to sort buffer end if segptr = segptr + ilen(segno) 'increment segment position pointer next call nsort(drcd$, nrcd$, sbuf$, sdat$, smsk$, sndx$) 'add record to sort nrcds = nrcds + 1 'total records added to the sort loop opcode = -3 'set flag to build an external index to the sortdata file call nsort(drcd$, nrcd$, sbuf$, sdat$, smsk$, sndx$) 'build the index file open "sortdata.ddx" for binary as #ddunit 'open the external index file ddxrcd$ = space$(2) 'allocate the index buffer for rcdno = 1 to nrcds 'begin loop to retrieve and display indexed data call fileio(ddunit, 2, clng(rcdno), ddxrcd$, 0) 'retrieve an index record call fileio(sdunit, sortln, clng(cvi(ddxrcd$)), sdat$, 0) 'retrieve data for segno = 1 to nosegs 'begin loop to display sort segments if midchar(smsk$, ibeg(segno)) = 66 then '16-bit integer segment rset pfmt$ = right$(str$(cvi(mid$(sdat$, ibeg(segno), 2))), 5) print pfmt$; " "; 'print integer data else 'character segment print mid$(sdat$, ibeg(segno), ilen(segno)); " "; 'print char. data end if next print 'terminate print line next call killfile("sortdata.ddx", ddunit) 'index file closed and removed restore sortdata3 'next tablespec to sort from read ibeg(0), ilen(0), iseq(0) 'test values from table sortdata3 compln = 0 'comparison length in sort data (sdat$) nosegs = 0 'initialize total no. of sort segments while ibeg(0) 'begin loop to load segment pointers and flags nosegs = nosegs + 1 'increment total sort segments ibeg(nosegs) = ibeg(0) 'segment begin pointer for sdat$ buffer ilen(nosegs) = ilen(0) 'segment length iseq(nosegs) = iseq(0) 'segment sort sequence (ascending/descending) compln = compln + ilen(0) 'total sort compare length read ibeg(0), ilen(0), iseq(0) 'read next set of test values wend opcode = -1 'set flag to resort data from existing sort file call nsort(drcd$, nrcd$, sbuf$, sdat$, smsk$, sndx$) 'resort the data opcode = -2 'set flag to retrieve records from sort (final operation) call nsort(drcd$, nrcd$, sbuf$, sdat$, smsk$, sndx$) 'retrieve 1st data record while len(sdat$) 'begin loop to display sort data for segno = 1 to nosegs 'begin loop to display sort segments if midchar(smsk$, ibeg(segno)) = 66 then '16-bit integer segment rset pfmt$ = right$(str$(cvi(mid$(sdat$, ibeg(segno), 2))), 5) print pfmt$; " "; 'print integer data else 'character segment print mid$(sdat$, ibeg(segno), ilen(segno)); " "; 'print char. data end if next print 'terminate print line call nsort(drcd$, nrcd$, sbuf$, sdat$, smsk$, sndx$) 'retrieve next record wend close 'close all files system 'return to DOS '------------------------------------------------------------------------------ sortdata1: 'initial sort specifications '------------------------------------------------------------------------------ '_____datafile____indexfile____buildfile :'File channel/unit numbers; data 1, 2, 3 :'may be found using FREEFILE '_____segbegin____seglength____segsequence :'Segment begin pointers, lengths data 1, 20, 1 :'and sort sequences for sort data 21, 2, -1 :'data buffer (sdat$). data 23, 10, 1 :' sequence = 1; ascending data 33, 2, -1 :' sequence = -1; descending data 35, 6, 1 :' data 0, 0, 0 :'end-of-data markers '------------------------------------------------------------------------------ sortdata2: 'example sort data '------------------------------------------------------------------------------ '_______Alpha data, len=20______Num.(2)______Alpha (10)____Num.(2)____Alpha (6) data "Petrol Chemicals Ltd", "3576", "London SW3", "588", "A23456" data "Associated Factories", "112", "Richmond", "1313", "XNA" data "Dale's Containers", "12343", "Devonshire", "55", "DALE" data "", "", "", "", "" '------------------------------------------------------------------------------ sortdata3: 'specifications for alternate sorting order '------------------------------------------------------------------------------ '_____segbegin____seglength____segsequence :'Segment begin pointers, lengths data 33, 2, 1 :'and sort sequences for sort data 1, 10, 1 :'data buffer (sdat$). data 0, 0, 0 :'end-of-data markers function midchar (i$, i) static 'find ASCII value of a single character in i$ midchar = asc(mid$(i$, i, 1)) 'set midchar value end function 'return to calling program rem $include: 'nsort.sub' [LISTING TWO] '============================================================================== 'NSORT.SUB Sort/retrieve/index data; ascending/descending; mixed data types ' By: Dale Thorn ' Rev. 03/24/91 '------------------------------------------------------------------------------ ' compln - comparison length in sort data (sdat$); may be less than sortln ' ddunit - file channel/unit number for index-building (opcode = -3) ' grpptr - sort group record pointer/sort buffer pointer ' grptot - internal sort group size ' maxrcd - internal maximum sort group size ' memndx - internal index-load flag ' ndunit - file channel/unit number for sort index files ' ndxgrp - internal index file group record counter ' ndxlen - internal index file record size ' nosegs - no. of sort segments in sdat$; total length of segments = compln ' nvflag - internal optimization for least ascending/descending data inversions ' offset - internal group-to-record offset counter ' opcode - sort operation (0 to -3) ' opinit - internal sort operation data initialization flag ' outptr - internal data output record pointer ' outtot - internal data output record counter ' rcdptr - internal sort data record counter (all records) ' rcdtot - internal sort data record total (final count) ' recptr - internal sort data record counter (group records) ' sdunit - file channel/unit number for sort data file (.sdx) ' sortln - length of sort data buffer (sdat$); may be greater than compln ' sortsq - internal sort sequence (ascending/descending) flag ' subtot - internal partial group data record total (final count) ' ' ibeg() - segment begin pointers for sort data buffer (sdat$) ' ilen() - segment length pointers for sort data buffer (sdat$) ' iptx() - pointers used if merge-sort req'd. (set internally) ' iseq() - segment sequence pointers for sort data buffer (sdat$) ' 1 = ascending; -1 = descending ' char$() - high-performance substitute for Basic chr$() function ' ' drcd$ - temp. sort data record buffer (set to "" on first call) ' nrcd$ - sort index file buffer (set to "" on first call) ' sbuf$ - main sort group memory buffer (set to "" on first call) ' sdat$ - main sort data record buffer (set to actual value on first call) ' smsk$ - sort data mask (must be uppercased) ' BB = integer string; XXX.... all other bytes ' sndx$ - sort index-pointer memory buffer (set to "" on first call) ' ' ' set opcode = 0 on first call to add records to sort. ' set opcode = -1 to resort data from existing sort work file (sortdata.sdx). ' set opcode = -2 on first call to retrieve records from sort. ' set opcode = -3 to build index file (sortdata.ddx). ' ' *** Notes: opcode = 0 is always the first process (add records). ' opcode = -1 may be set to resort data, but only following ' the creation of an index with opcode set to -3. ' opcode = -2 may be set to retrieve records once all records ' have been added with opcode set to 0, or after ' a resort with opcode set to -1. Once opcode is ' set to -2 and all records are retrieved, the ' sort routine is terminated and all sort memory ' is returned to the calling program. If further ' sorting is required, begin anew with opcode = 0. ' opcode = -3 may be set to build an index file following an ' initial sort with opcode set to 0, or a resort ' with opcode set to -1. If more than 2 sorting ' sequences are required, where 2 or more index ' files are needed, rename each .ddx file to save it. ' The final sort sequence may be obtained using ' opcode = -2, and thus eliminate the need for a ' corresponding index file. Each 2 bytes in the index ' file are a pointer to a record in the .sdx file. ' ' For the first sort (opcode = 0), place all sort segments of sdat$ ' into the left part of sdat$ in sequential order (1, 2, 3, etc.). ' When re-sorting using opcode = -1, segments may be in any order. ' All data stored in sortdata.sdx will be in the original sequence. ' ' ***** Important: Minimum sort length is 2 bytes. ' ***** If free memory is minimal, more sort groups may ' ***** be needed, and dim iptx(nnn) may be too small. ' ***** Each opcode process must be completed for all ' ***** records before switching to another process. ' ***** Use named common block if chaining programs. '------------------------------------------------------------------------------ sub nsort (drcd$, nrcd$, sbuf$, sdat$, smsk$, sndx$) static if opcode > -2 then 'insert a record if opinit mod 2 = 0 then 'first-sort-record initialization opinit = opinit - 1 'adjust initialization flag sortsq = iseq(1) 'primary output sequence nvflag = 0 'data inversion flag for segno = 1 to nosegs 'build data inversion spec nvflag = nvflag + ilen(segno) * iseq(segno) 'bytes above/below 0 next if nvflag < 0 then 'data inversion optimization nvflag = 1 'set inversion flag plus else nvflag = -1 'set inversion flag minus end if '[see fillproc & writeproc subroutines] if nvflag = sortsq then sortsq = -sortsq 'primary output sequence call killfile("sortdata.ndx", ndunit) 'kill work index file open "sortdata.ndx" for binary as #ndunit 'open work index file if opcode = 0 then 'initial (add records) operation call killfile("sortdata.sdx", sdunit) 'kill work data file open "sortdata.sdx" for binary as #sdunit 'open work data file drcd$ = space$(sortln) 'temporary sort data buffer for ichr = 0 to 255 'create substitute character set char$(ichr) = chr$(ichr) 'substitute for Basic chr$() function next end if call memfree(clng(4096), clng(195840), xfree) 'reserve 4 kb memory maxrcd = xfree \ (sortln + 4) 'maximum records per memory group if maxrcd > 32640 \ sortln then maxrcd = 32640 \ sortln 'buffer size sbuf$ = space$(maxrcd * sortln) 'main sort data buffer sndx$ = space$(maxrcd * 2 + 2) 'reorderable/shiftable index buffer rcdptr = 1 'used to count total records recptr = 1 'used to count records within a sort group grpptr = 1 'sort buffer pointer end if if opcode = -1 then 'resort from existing workfile (.sdx) ndxgrp = 0 'total number of sort groups offset = 0 'internal group-to-record offset counter while rcdptr <= rcdtot 'loop until all records are read call fileio(sdunit, sortln, clng(rcdptr), sdat$, 0) 'get sort data gosub putproc 'add records in new sort sequence wend else 'original (insert) sequence gosub putproc 'add records to sort end if else 'retrieve a record or build an index offset = 0 'group-to-record offset counter if opinit mod 2 then 'first retrieval record initialization opinit = opinit - 1 'adjust initialization flag if opinit = -2 then 'first operation after original sort rcdtot = rcdptr - 1 'total records from original sort subtot = recptr - 1 'partial-group subtotal from original sort end if outptr = 1 'beginning pointer for data output outtot = rcdtot 'total records to output if ndxgrp then 'sorting was done in groups gosub writeproc 'save data left over from previous operation else 'all sorting was done in memory maxrcd = rcdtot 'reset maximum records for file write ndxlen = maxrcd * 2 'length of index data to write gosub writeproc 'save sort data ndxgrp = 0 'reset index group count to zero end if sbuf$ = "" 'erase buffer to reclaim memory sndx$ = "" 'erase buffer to reclaim memory if ndxgrp then 'merge-sort required grplen = ndxlen 'group size * 2 sbuf$ = space$(ndxgrp * sortln) 'buffer holds 1 record per group sndx$ = space$(ndxgrp * 2 + 2) 'buffer holds 1 record per group end if if opcode = -3 then 'build index from sorted data call memfree(clng(6144), clng(32640), xfree) 'reserve 2kb for .ddx else 'normal retrieval [return each record to calling program] call memfree(clng(4096), clng(32640), xfree) 'reserve normal 4 kb end if xsize = clng(outtot) * 2 'total records * 2 memndx = (xsize <= 32640 and xsize <= xfree) 'index-in-memory flag if memndx then 'retrieval index fits entirely in memory ndxlen = xsize 'buffer length is index file length else 'retrieval index does not fit in memory ndxlen = 2 'buffer length is 16-bit integer length end if nrcd$ = space$(ndxlen) 'allocate index file buffer if memndx then call fileio(ndunit, ndxlen, clng(1), nrcd$, 0)'fill it if ndxgrp then 'merge-sort initialization ixx1 = (sortsq > 0) 'used locally to shorten line ixx2 = (sortsq < 0) 'used locally to shorten line ixx3 = (memndx and ixx1) 'used locally to shorten line ixx4 = (memndx and ixx2) 'used locally to shorten line iyy1 = 1 - memndx 'used locally to shorten line iyy2 = grplen \ (1 - not memndx) 'used locally to shorten line for recptr = 1 to ndxgrp 'loop thru each index group grpptr = recptr 'sort group record pointer iyy3 = (grptot - subtot) * (ixx2 and (recptr = ndxgrp)) iyy4 = (grptot - subtot) * (ixx1 and (recptr = ndxgrp)) ircd = (recptr + ixx1) * iyy2 + iyy3 * iyy1 + ixx4 - ixx1 ircx = (recptr + ixx2) * iyy2 + iyy4 * iyy1 + ixx3 - ixx2 if memndx then 'get index pointer from memory buffer ichr = midchar(nrcd$, ircd + 1) * 256 'high byte of index rcdptr = midchar(nrcd$, ircd) + ichr 'same as cvi(mid$(... else 'get index pointer from file call fileio(ndunit, ndxlen, clng(ircd), nrcd$, 0) rcdptr = cvi(nrcd$) 'set pointer to retrieve data end if call fileio(sdunit, sortln, clng(rcdptr), sdat$, 0) 'get data gosub fillproc 'add 1 record from each sort group to buffer iptx(recptr, 0) = ircd 'begin ptr.to load ndx.rcd. from group iptx(recptr, 1) = ircx 'end ptr.to load ndx.rcd. from group next recptr = ndxgrp 'reset groups-pointer to begin output if sortsq < 0 then outptr = recptr 'begin output in reverse order else 'non-merge; all output from memory if sortsq < 0 then outptr = outtot 'begin output in reverse order end if end if if opcode = -3 then 'build index from sorted data call killfile("sortdata.ddx", ddunit) 'kill user index file open "sortdata.ddx" for binary as #ddunit 'open user index file ddxrcd$ = space$(2048) 'collection buffer for index-build filptr = 0 'record pointer for writing .ddx buffer to file ddxptr = 1 'buffer pointer for adding index values to ddxrcd$ gosub getproc 'get first index record while not closed 'retrieve index pointers and save to .ddx file mid$(ddxrcd$, ddxptr) = mki$(rcdptr) 'copy index to .ddx buffer ddxptr = ddxptr + 2 'increment buffer pointer if ddxptr > 2048 then 'write a group of data to file filptr = filptr + 1 'increment file pointer call fileio(ddunit, 2048, clng(filptr), ddxrcd$, -1) 'put data ddxptr = 1 'reset buffer pointer to beginning of buffer end if gosub getproc 'get next index records wend if ddxptr > 1 then 'save leftover index pointers call fileio(ddunit, 2048, clng(filptr + 1), ddxrcd$, -1) 'put data end if close #ddunit 'close the .ddx file ddxrcd$ = "" 'reclaim memory from .ddx buffer else 'retrieve a single sort record and return to calling program gosub getproc 'get a record pointer if not closed then 'retrieval OK as long as more records available call fileio(sdunit, sortln, clng(rcdptr), sdat$, 0) 'retrieve data end if end if if closed then 'retrieval/index completed if opcode = -2 then 'final (single-record retrieval) sequence call killfile("sortdata.ndx", ndunit) 'kill sort index workfile call killfile("sortdata.sdx", sdunit) 'kill sort data file sdat$ = "" 'kill sort data buffer end if nrcd$ = "" 'kill index file buffer sbuf$ = "" 'kill main sort group buffer sndx$ = "" 'kill sort index buffer end if end if exit sub 'return to calling program '-------------------------------------------------------------------------- fillproc: 'put sort data into sbuf$, sndx$ '-------------------------------------------------------------------------- if opcode = 0 then lset drcd$ = sdat$ 'load all segments at once iptr = 1 'initialize work buffer pointer for segno = 1 to nosegs 'load segments into work buffer and/or do invert if midchar(smsk$, ibeg(segno)) = 66 then 'invert 16-bit integer strings ichr = midchar(sdat$, ibeg(segno)) 'save first byte, then swap mid$(drcd$, iptr) = char$(midchar(sdat$, ibeg(segno) + 1)) '2nd byte mid$(drcd$, iptr + 1) = char$(ichr) 'put 1st byte in 2nd position else 'non-integer (character) sort segment if opcode then 'segments not in original (contiguous) sequence mid$(drcd$, iptr) = mid$(sdat$, ibeg(segno), ilen(segno)) end if 'insert each sort segment into temp. buffer [above] end if if iseq(segno) = nvflag then 'invert data for ascend/descend sequence for ichr = iptr to iptr + ilen(segno) - 1 'do each byte in segment mid$(drcd$, ichr) = char$(255 - midchar(drcd$, ichr)) next 'data will be re-inverted before writing to file end if iptr = iptr + ilen(segno) 'increment work buffer segment pointer next 'begin binary search for sort compare [below] topptr = recptr 'set top end of binary search lowptr = 0 'set low end of binary search while topptr - lowptr > 1 'search work data buffer using work index buffer midptr = lowptr + (topptr - lowptr) \ 2 'set mid point for compare ichx = midptr * 2 'mid-position incorporating 16-bit index width ichr = midchar(sndx$, ichx) * 256 'same as cvi(mid$(.....)) iptr = (midchar(sndx$, ichx - 1) + ichr - offset - 1) * sortln 'mid- if left$(drcd$, compln) <= mid$(sbuf$, iptr + 1, compln) then '-buff.pos topptr = midptr 'move search lower else 'sort record value > compare value in sort memory buffer lowptr = midptr 'move search higher end if wend iptr = topptr * 2 - 1 'current index-"stack" insert position mid$(sbuf$, (grpptr - 1) * sortln + 1) = drcd$ 'write sort data to buffer mid$(sndx$, iptr + 2) = mid$(sndx$, iptr, (recptr - topptr) * 2) 'shift ndx mid$(sndx$, iptr) = mki$(grpptr + offset) 'write current pointer to index return 'return to calling routine '-------------------------------------------------------------------------- getproc: 'retrieve a record from the sort '-------------------------------------------------------------------------- if ndxgrp then 'merge-retrieval from sort groups if recptr then 'sort records are still available ichr = outptr * 2 'mid-position based on 16-bit index width grpptr = midchar(sndx$, ichr - 1) + midchar(sndx$, ichr) * 256 if memndx then 'get group pointer from work index [above] ichr = midchar(nrcd$, iptx(grpptr, 0) + 1) * 256 'get record ptr rcdptr = midchar(nrcd$, iptx(grpptr, 0)) + ichr 'from memory-index else 'get record pointer from index file call fileio(ndunit, ndxlen, clng(iptx(grpptr, 0)), nrcd$, 0) rcdptr = cvi(nrcd$) 'nrcd$ is a 16-bit integer record end if if sortsq > 0 then mid$(sndx$, 1) = mid$(sndx$, 3) 'shift work index if iptx(grpptr, 0) = iptx(grpptr, 1) then 'end of group reached recptr = recptr - 1 'decrement group stack pointer if sortsq < 0 then outptr = recptr 'set output pointer if appl. else 'end of group not yet reached iptx(grpptr, 0) = iptx(grpptr, 0) + (1 - memndx) * sortsq'move ptr if memndx then 'get a data record using a pointer from memory ichr = midchar(nrcd$, iptx(grpptr, 0)) 'get the record pointer ichx = midchar(nrcd$, iptx(grpptr, 0) + 1) * 256 '..from memory call fileio(sdunit, sortln, clng(ichr + ichx), sdat$, 0) else 'get a data record using a pointer from the index file call fileio(ndunit, ndxlen, clng(iptx(grpptr, 0)), nrcd$, 0) call fileio(sdunit, sortln, clng(cvi(nrcd$)), sdat$, 0) end if gosub fillproc 'add the data record to the merge-sort end if closed = 0 'retrieval process not closed else 'no more records available closed = not 0 'retrieval process closed end if else 'non-merge sort retrieval; all data is in memory if outtot then 'sort records are still available ichr = outptr * 2 'mid-position based on 16-bit index width rcdptr = midchar(nrcd$, ichr - 1) + midchar(nrcd$, ichr) * 256 outptr = outptr + sortsq 'increment or decrement index pointer outtot = outtot - 1 'decrement remaining records closed = 0 'retrieval process not closed else 'no more records available closed = not 0 'retrieval process closed end if end if return 'return to calling routine '-------------------------------------------------------------------------- putproc: 'add a record to the sort '-------------------------------------------------------------------------- if recptr > maxrcd then 'too many records to fit in memory if ndxgrp = 0 then 'first group; initialize index group variables grptot = recptr - 1 'number of records per group ndxlen = grptot * 2 'size of index file buffer end if gosub writeproc 'save data group and index group offset = rcdptr - 1 'group-to-record offset counter recptr = 1 'reset group record counter grpptr = 1 'sort buffer pointer end if gosub fillproc 'add current record to sort rcdptr = rcdptr + 1 'increment total records counter recptr = recptr + 1 'increment group record counter grpptr = recptr 'sort buffer pointer return 'return to calling routine '-------------------------------------------------------------------------- writeproc: 'write index and sort data to files '-------------------------------------------------------------------------- ndxgrp = ndxgrp + 1 'increment the index group number call fileio(ndunit, ndxlen, clng(ndxgrp), left$(sndx$, ndxlen), -1) if opinit > -3 then 'initial sequences; save sort data to .sdx file for iptr = 0 to (maxrcd - 1) * sortln step sortln 'loop thru mem.buffer for segno = 1 to nosegs 're-invert data as appropriate iptz = iptr + ibeg(segno) 'sort group memory buffer pointer if midchar(smsk$, ibeg(segno)) = 66 then 'invert integer string ichr = midchar(sbuf$, iptz) 'save first byte, then swap mid$(sbuf$, iptz) = char$(midchar(sbuf$, iptz + 1)) '2nd byte mid$(sbuf$, iptz + 1) = char$(ichr) 'put 1st byte in 2nd pos. end if if iseq(segno) = nvflag then 'invert data for ascend/descend seq for ichr = iptz to iptz + ilen(segno) - 1 'invert each byte mid$(sbuf$, ichr) = char$(255 - midchar(sbuf$, ichr)) next end if next next sdxlen = maxrcd * sortln 'size of group memory buffer xflptr = lof(sdunit) \ sdxlen + 1 'current data "record" call fileio(sdunit, sdxlen, xflptr, sbuf$, -1) 'put data group to file end if return end sub 'return to calling program sub fileio (fcno, flen, xrec, fbuf$, fopr) static 'read/write file data 'int fcno 'file unit/channel no. 'int flen '"record" length used for positioning only 'int fopr '0 = read; non-0 = write 'long xrec 'logical "record" number 'char fbuf$ 'read/write data buffer xpos = (xrec - 1) * flen + 1 'absolute byte position in file if fopr then 'operation = write put #fcno, xpos, fbuf$ 'write data to file else 'operation = read get #fcno, xpos, fbuf$ 'read data from file end if end sub 'return to calling program sub killfile (ffil$, fcno) static 'kill a DOS file 'int fcno 'file unit/channel no. 'char ffil$ 'file name close #fcno 'close file if open open ffil$ for binary as #fcno 'open file in binary mode close #fcno 'close the file kill ffil$ 'kill the file end sub 'return to calling program sub memfree (xexc, xmax, xfree) static 'get max. free memory less exclusion 'long xexc 'amount of memory to reserve/exclude 'long xmax 'upper limit for xfree (or zero) xfree = fre("") - xexc 'total free memory less exclusion if xmax > 0 and xfree > xmax then xfree = xmax 'set maximum if applicable end sub 'return to calling program