feat(rtl): LIST/DISPLAY TO FILE — text output redirection
Wire up TO FILE for both LIST and DISPLAY: __dbList grows a 9th
parameter cFile, opens it (truncating any prior content) when non-
empty, and writes the formatted rows there via fmt.Fprintln. Default
behavior (no TO FILE) still goes to stdout.
std.ch gets two new rules placed *before* the regular LIST/DISPLAY
patterns so they win when TO FILE is present:
LIST [<v,...>] TO FILE <(f)> [OFF] [FOR] [WHILE] [NEXT] ...
DISPLAY [<v,...>] TO FILE <(f)> [OFF] [FOR] [WHILE] [NEXT] ...
Open failure raises a clear *HbError ("LIST/DISPLAY TO FILE: cannot
create <path> — <syscall reason>") so callers know exactly what went
wrong instead of getting partial-or-empty output.
TO PRINTER stays rejected via __dbNotImpl — Five doesn't drive a
printer port. Test coverage: tests/std_ch/test_list_to_file.prg
exercises four shapes (full LIST, single-row DISPLAY, OFF + FOR with
explicit fields, and confirms TO PRINTER still raises). Wired into
the std.ch runner so the regression suite now stands at 14/14.
Gates green:
go test ./... : PASS
FiveSql2 SQL:1999 : 43/43
Harbour compat : 56/56
std.ch suite : 14/14
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -23,6 +23,7 @@ TESTS=(
|
||||
test_copy
|
||||
test_sort
|
||||
test_list
|
||||
test_list_to_file
|
||||
test_total
|
||||
test_join
|
||||
test_update
|
||||
|
||||
73
tests/std_ch/test_list_to_file.prg
Normal file
73
tests/std_ch/test_list_to_file.prg
Normal file
@@ -0,0 +1,73 @@
|
||||
/* LIST / DISPLAY TO FILE — text output redirected to a file. */
|
||||
|
||||
PROCEDURE Main()
|
||||
LOCAL aStruct, cBuf, e
|
||||
|
||||
FErase("p.dbf")
|
||||
FErase("out.txt")
|
||||
|
||||
aStruct := { ;
|
||||
{ "ID", "N", 4, 0 }, ;
|
||||
{ "NAME", "C", 10, 0 }, ;
|
||||
{ "AGE", "N", 3, 0 } }
|
||||
dbCreate("p.dbf", aStruct)
|
||||
USE p.dbf NEW EXCLUSIVE ALIAS p
|
||||
dbAppend(); FieldPut(1,1); FieldPut(2,"Alice"); FieldPut(3,18)
|
||||
dbAppend(); FieldPut(1,2); FieldPut(2,"Bob"); FieldPut(3,25)
|
||||
dbAppend(); FieldPut(1,3); FieldPut(2,"Carol"); FieldPut(3,30)
|
||||
dbCommit()
|
||||
|
||||
/* 1. LIST TO FILE — full table */
|
||||
dbGoTop()
|
||||
LIST TO FILE out.txt
|
||||
|
||||
cBuf := MemoRead("out.txt")
|
||||
? "1. file size:", Len(cBuf), "bytes (expect > 0)"
|
||||
IF Len(cBuf) == 0
|
||||
? "FAIL: empty output file"
|
||||
RETURN
|
||||
ENDIF
|
||||
? "1. file content:"
|
||||
? cBuf
|
||||
|
||||
/* 2. DISPLAY TO FILE — single record */
|
||||
FErase("out.txt")
|
||||
dbGoto(2)
|
||||
DISPLAY TO FILE out.txt
|
||||
|
||||
cBuf := MemoRead("out.txt")
|
||||
? "2. DISPLAY single-row file:"
|
||||
? cBuf
|
||||
IF !("Bob" $ cBuf)
|
||||
? "FAIL: Bob row missing"
|
||||
RETURN
|
||||
ENDIF
|
||||
|
||||
/* 3. LIST TO FILE with OFF + FOR — std.ch pattern order is
|
||||
`[<off:OFF>] [FOR <for>]`, same as Harbour. */
|
||||
FErase("out.txt")
|
||||
dbGoTop()
|
||||
LIST p->id, p->name TO FILE out.txt OFF FOR p->age >= 25
|
||||
|
||||
cBuf := MemoRead("out.txt")
|
||||
? "3. selective+OFF file:"
|
||||
? cBuf
|
||||
IF "Alice" $ cBuf
|
||||
? "FAIL: Alice (age 18) shouldn't be in FOR age>=25 output"
|
||||
RETURN
|
||||
ENDIF
|
||||
|
||||
/* 4. TO PRINTER — should still reject */
|
||||
e := .F.
|
||||
BEGIN SEQUENCE
|
||||
LIST TO PRINTER
|
||||
RECOVER
|
||||
e := .T.
|
||||
END SEQUENCE
|
||||
? "4. TO PRINTER rejected:", e, "(expect .T.)"
|
||||
|
||||
dbCloseArea()
|
||||
FErase("p.dbf")
|
||||
FErase("out.txt")
|
||||
? "DONE"
|
||||
RETURN
|
||||
Reference in New Issue
Block a user