Files
five/tests/std_ch/test_list_to_file.prg
CharlesKWON 412351b67d 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>
2026-05-01 08:15:32 +09:00

74 lines
1.7 KiB
Plaintext

/* 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