+Doug (I agree fully with Doug), the SORT command is actually not in my active vocabulary. As we have SKIP SET ORDER is completely sufficient to sort and display and, well, SKIP in any sort order.
Rob, I wonder how you could live without knowing SKIP, it's essential in the legacy way to do a WHILE !EOF() loop not using SCAN...ENDSCAN. At the end of such a WHILE !OEF() loop you have to SKIP 1, as otherwise, the loop will never get to EOF(), SCAN..ENDSCAN does that automatically.
+Mike (I agree fully with Mike), it's also important to think of the corner cases - here begin/end of file cases. Notice, Rob, no matter how an Index changes order from recno order, skipping past the last record in sort order always positions the record pointer at an EOF byte, that also means you can only check that
after the SKIP. What's slightly off the point with Mikes code is that BOF also only turns .T. after SKIP -1 from the first record, see here:
Code:
CREATE CURSOR crsTest (sortorder int)
INSERT INTO crsTest VALUES (2)
INSERT INTO crsTest VALUES (1)
INSERT INTO crsTest VALUES (4)
INSERT INTO crsTest VALUES (3)
INDEX on sortorder TAG xSort
GO 2
? RECNO(),BOF()
SKIP -1
? RECNO(),BOF()
GO 3
? RECNO(),EOF()
SKIP +1
? RECNO(),EOF()
I intentionally put the lowest and highest values 1 and 4 into the middle of the data at record 2 and 3.
First I explicitly GO 2 and at that moment BOF() is not yet .T., SKIP -1 activates BOF() and automatically stays at RECNO()=2. Mikes code is correctly NOT doing a SKIP +1 in that case, as VFP stays at recno 2 already. But BOF() only became .T. after you are at recno=2, SKIP -1 and still are on recno=2.
The difference with EOF() becomes clear with the code starting with GO 3 to manually go to the last record with value 4. The Skip +1 actually finds a RECNO() 5, even though we only have 4 records. The EOF is an extra byte after the last record. When you add a record this byte becomes the deleted flag of that new record and a new EOF byte is added after that. That byte position within the DBF actually is where a recno 5 starts (or will start). This is also the reason EOF is a special place in the data and REPLACE "misbehaves" at this position and doesn't replace nor error. That's the unpopular "It's by design". It's a reason Mike does SKIP -1 in that case, to get back to really point to the last record of the data. So, Mike, I see you know this subtle difference.
By the way: FOUND() also simply is NOT EOF().
The easy way out of any error of a SKIP +/-N is using TRY CATCH to do the SKIP command. The only thing to care about, if you care about it is, that when you SKIP forward EOF really means the record pointer is positioned
after the last record, whereas when BOF() becomes .T. you know you're positioned
on the first record and not any byte before it. So in case you SKIP within TRY CATCH you FINALLY only need to SKIP -1 in case of EOF().
Also notice, you can't explicitly GO 5, that's causing a "Record is out of range" error. That's also what happens even to experienced developers storing RECNO() as current position and trying to go back with GO, it fails in such corner cases and there are more, when you use buffering and new records have negative recnos before they are committed with TABLEUPDATE or by locating another record while buffering is only record buffering instead of table buffering. You then can't go back to -1, for example, it turned to recno being the new RECCOUNT().
So this whole construction leads to many problems and caused many curses, for sure. I can't think of a better concept, it might be slightly better, if BOF also was an extra byte, simply the last byte of the header part of a DBF, that would make behavior fully symmetrical, you could be at RENCO=0 but never be able to GO 0, for example, BOF would also be a place outside of the range of records, etc. The asymmetry then would only be, that extra BOF byte would not be at RECSIZE() distance to the first byte of recno 1, it would always be only 1 byte before it.
The sorting an index causes, must have begin and end somehow, and so the record pointer positioning is special about this and an asymmetry about BOF() EOF() boolean states is that RECNO() being a valid or "virtual" record number. GO Recno, therefore, is a bit flawed.
Knowing SKIP is essential anyway.
Bye, Olaf.