How to make an item list
BTPFIND and BTPSEQ allow all or just a range of item identifiers to be extracted from a B-tree in a pre-defined order, so that a program doesn't have to wait for a SSELECT to finish before output can be generated. For example, here's a program to output a selected range of items in our NAMES file:
LIST.NAMES.RANGE
001 OPEN "B-TREE" TO BFILE ELSE STOP
002 OPEN "NAMES" TO NFILE ELSE STOP
003 CRT ; CRT "Ready to output sorted mailing labels."
004 CRT "C (by company) or N (by name) or Z (by zip)":
005 INPUT ROOT
006 BEGIN CASE
007 CASE ROOT = "C"
008 ROOT = "COMP" ; FRAG = "company" ; AMC = 3
009 CASE ROOT = "N"
010 ROOT = "LNAME" ; FRAG = "last name" ; AMC = 2
011 CASE 1
012 ROOT = "ZIP" ; FRAG = "zip code" ; AMC = 6
013 END CASE
014 CRT "Beginning ":FRAG
015 CRT "(or just RETURN for very first)": ; INPUT FIRST
016 CRT "Ending ":FRAG
017 CRT "(or just RETURN for very last)": ; INPUT LAST
018 CRT
019 ID = "" ; ITEM = "" ; ITEM<AMC> = FIRST
020 CALL BTPFIND(ROOT,BFILE,NFILE,ID,ITEM,NODE,POS)
021 LOOP
022 IF ID = "" THEN STOP
023 READ NAMES FROM NFILE, ID ELSE NAMES = ""
024 UNTIL (NAMES<AMC> > LAST) AND (LAST # "") DO
025 PRINT NAMES<1>:" ":NAMES<2>:" ":ID
026 PRINT NAMES<3> ; PRINT NAMES<4>
027 PRINT NAMES<5>:" ":NAMES<6> ; PRINT
028 CALL BTPSEQ(BFILE, NODE, POS, "NEXT", ID)
029 REPEAT
030 STOP
031 END
Although the above code can immediately output any range of names, companies, or ZIP codes without delay, the output is generated with BASIC. Often, it would be more convenient to just extract identifiers from a B-tree as an item list, and then let the SORT or LIST verb generate the output. Unfortunately, Pick does not offer a "writenext" capability to allow a program to write an item list, to complement the way a program can read an item list with READNEXT. That leaves two choices for a program that extracts item identifiers from a B-tree, but doesn't want to generate its own output. If the identifier list is small, the program can save the list as a single item which can then be retrieved with QSELECT or FORM-LIST before using the LIST verb. If the item list is large, the program can save the identifiers in a scratch file, which can then be retrieved with a SSELECT.
For example, here is a program that saves a list of all NAMES items in ZIP code order:
MAKE.LIST.ITEM
001 OPEN "B-TREE" TO BFILE ELSE STOP
002 OPEN "NAMES" TO NFILE ELSE STOP
003 OPEN "MD" TO MFILE ELSE STOP
004 ID = "" ; ITEM = "" ; ITEM.LIST = ""
005 CALL BTPFIND("ZIP",BFILE,NFILE,ID,ITEM,NODE,POS)
006 LOOP UNTIL ID = "" DO
007 ITEM.LIST<-1> = ID
008 CALL BTPSEQ(BFILE, NODE, POS, "NEXT", ID)
009 REPEAT
010 WRITE ITEM.LIST ON MFILE, "ZLIST"
011 STOP
012 END
Execute MAKE.LIST.ITEM, then give the command QSELECT MD 'ZLIST', and you can then use the command LIST NAMES to output all items in ZIP code order without having to use SORT... BY... commands.
MAKE.LIST.ITEM will bog down if the number of items is large. In that case, save the item identifiers in a scratch file with a program like:
MAKE.LIST.FILE
001 OPEN "B-TREE" TO BFILE ELSE STOP
002 OPEN "NAMES" TO NFILE ELSE STOP
003 OPEN "SCRATCH" TO SFILE ELSE STOP
004 ID = "" ; ITEM = "" ; NEXT.ID = 1
005 CALL BTPFIND("ZIP",BFILE,NFILE,ID,ITEM,NODE,POS)
006 LOOP UNTIL ID = "" DO
007 WRITE ID ON SFILE, NEXT.ID ; NEXT.ID = NEXT.ID+1
008 CALL BTPSEQ(BFILE, NODE, POS, "NEXT", ID)
009 REPEAT
010 STOP
011 END
Execute MAKE.LIST.FILE, then SSELECT SCRATCH (using right justification), then QSELECT SCRATCH, then LIST NAMES to avoid sorting the NAMES file itself.
MAKE.LIST.ITEM and MAKE.LIST.FILE are only advantageous if their execution times plus the time necessary for subsequent SELECTs is less than the time needed to SSELECT the NAMES file itself. If MAKE.LIST.ITEM and MAKE.LIST.FILE output a range of items (like LIST.NAMES.RANGE does), then they can be very powerful tools that extract a sorted list of items much faster than a SELECT command.