- skipFilter: skip deleted records in GoTop/GoBottom/Skip when SET DELETED ON - hbrdd.IsSetDeleted callback: avoids circular import hbrdd→hbrtl - Parser: capture ON/OFF for boolean SET commands (DELETED, EXACT, SOFTSEEK, etc.) - Parser: capture TO expr for SET DATE/DECIMALS/EPOCH - Gengo: emit proper t.Do() calls for 11 SET toggles + 3 value SETs - stmtSet: was stub (skipToEOL), now calls parseSet() - RTL: register 11 SET toggle functions (SETDELETED, SETEXACT, etc.) - RTL: DBLOCATE/DBCONTINUE for sequential search - RTL: DBSETFILTER/DBCLEARFILTER/DBFILTER - PadL/PadR: support 3rd param fill character - Area interface: added SetFound, SetLocate, LocateBlock, filter methods - MemRDD: implements new Area interface methods - Comprehensive PRG test: test_search.prg (7 test suites all pass) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
278 lines
6.9 KiB
Go
278 lines
6.9 KiB
Go
// Copyright (c) 2026 Charles KWON OhJun (charleskwonohjun@gmail.com)
|
|
// All rights reserved.
|
|
|
|
// SET command functions: SET EXACT, SET SOFTSEEK, SET DELETED, SET EXCLUSIVE,
|
|
// SET(_SET_xxx, lValue) pattern.
|
|
// Harbour: src/rtl/set.c — 47+ settings in HB_SET_ENUM.
|
|
|
|
package hbrtl
|
|
|
|
import (
|
|
"five/hbrdd"
|
|
"five/hbrt"
|
|
"sync"
|
|
)
|
|
|
|
// SET indices (Harbour HB_SET_ENUM compatible)
|
|
const (
|
|
SetExact = 1
|
|
SetFixed = 2
|
|
SetDecimals = 3
|
|
SetDateFmt = 4
|
|
SetEpoch = 5
|
|
SetPath = 6
|
|
SetDefault = 7
|
|
SetDeleted = 8
|
|
SetExclusive = 11
|
|
SetSoftSeek = 12
|
|
SetUnique = 13
|
|
SetCancel = 14
|
|
SetConfirm = 15
|
|
SetConsole = 16
|
|
SetAlternate = 17
|
|
SetDevice = 18
|
|
SetPrinter = 19
|
|
SetBell = 20
|
|
SetEscape = 21
|
|
SetInsert = 22
|
|
SetExit = 23
|
|
SetIntensity = 24
|
|
SetScoreB = 25
|
|
SetColorIdx = 26
|
|
SetCursorIdx = 27
|
|
SetWrap = 28
|
|
SetMessage = 29
|
|
)
|
|
|
|
var (
|
|
settings = map[int]hbrt.Value{
|
|
SetExact: hbrt.MakeBool(false),
|
|
SetFixed: hbrt.MakeBool(false),
|
|
SetDecimals: hbrt.MakeInt(2),
|
|
SetDeleted: hbrt.MakeBool(false),
|
|
SetExclusive: hbrt.MakeBool(true),
|
|
SetSoftSeek: hbrt.MakeBool(false),
|
|
SetUnique: hbrt.MakeBool(false),
|
|
SetCancel: hbrt.MakeBool(true),
|
|
SetConfirm: hbrt.MakeBool(false),
|
|
SetConsole: hbrt.MakeBool(true),
|
|
SetBell: hbrt.MakeBool(false),
|
|
SetEscape: hbrt.MakeBool(true),
|
|
SetInsert: hbrt.MakeBool(false),
|
|
SetExit: hbrt.MakeBool(false),
|
|
SetIntensity: hbrt.MakeBool(true),
|
|
SetWrap: hbrt.MakeBool(false),
|
|
}
|
|
setMu sync.Mutex
|
|
)
|
|
|
|
// SET(nSpecifier [, xNewValue]) → xOldValue
|
|
// Generic SET function matching Harbour's Set() function.
|
|
func SetFunc(t *hbrt.Thread) {
|
|
nParams := t.ParamCount()
|
|
t.Frame(nParams, 0)
|
|
defer t.EndProc()
|
|
|
|
nSet := t.Local(1).AsInt()
|
|
|
|
setMu.Lock()
|
|
defer setMu.Unlock()
|
|
|
|
old, exists := settings[nSet]
|
|
if !exists {
|
|
old = hbrt.MakeNil()
|
|
}
|
|
|
|
if nParams >= 2 && !t.Local(2).IsNil() {
|
|
settings[nSet] = t.Local(2)
|
|
}
|
|
|
|
t.RetVal(old)
|
|
}
|
|
|
|
// GetSetting returns a SET value (called internally).
|
|
func GetSetting(nSet int) hbrt.Value {
|
|
setMu.Lock()
|
|
defer setMu.Unlock()
|
|
v, ok := settings[nSet]
|
|
if !ok {
|
|
return hbrt.MakeNil()
|
|
}
|
|
return v
|
|
}
|
|
|
|
// GetSetDeleted returns SET DELETED state.
|
|
func GetSetDeleted() bool {
|
|
return GetSetting(SetDeleted).AsBool()
|
|
}
|
|
|
|
// GetSetExact returns SET EXACT state.
|
|
func GetSetExact() bool {
|
|
return GetSetting(SetExact).AsBool()
|
|
}
|
|
|
|
// GetSetSoftSeek returns SET SOFTSEEK state.
|
|
func GetSetSoftSeek() bool {
|
|
return GetSetting(SetSoftSeek).AsBool()
|
|
}
|
|
|
|
// GetSetDateFormat returns SET DATE format string.
|
|
func GetSetDateFormat() string {
|
|
v := GetSetting(SetDateFmt)
|
|
if v.IsString() {
|
|
return v.AsString()
|
|
}
|
|
return "mm/dd/yy"
|
|
}
|
|
|
|
// GetSetDecimals returns SET DECIMALS value.
|
|
func GetSetDecimals() int {
|
|
return GetSetting(SetDecimals).AsInt()
|
|
}
|
|
|
|
// GetSetEpoch returns SET EPOCH year.
|
|
func GetSetEpoch() int {
|
|
v := GetSetting(SetEpoch)
|
|
if v.IsNumeric() {
|
|
return v.AsInt()
|
|
}
|
|
return 1900
|
|
}
|
|
|
|
// --- Dedicated SET toggle functions ---
|
|
// Harbour: SET EXACT ON/OFF, SET DELETED ON/OFF, etc.
|
|
|
|
// SetExactFunc: SET(_SET_EXACT [, lNew]) → lOld
|
|
func SetExactFunc(t *hbrt.Thread) { setToggle(t, SetExact) }
|
|
|
|
// SetDeletedFunc: SET(_SET_DELETED [, lNew]) → lOld
|
|
func SetDeletedFunc(t *hbrt.Thread) { setToggle(t, SetDeleted) }
|
|
|
|
// SetSoftSeekFunc: SET(_SET_SOFTSEEK [, lNew]) → lOld
|
|
func SetSoftSeekFunc(t *hbrt.Thread) { setToggle(t, SetSoftSeek) }
|
|
|
|
// SetExclusiveFunc: SET(_SET_EXCLUSIVE [, lNew]) → lOld
|
|
func SetExclusiveFunc(t *hbrt.Thread) { setToggle(t, SetExclusive) }
|
|
|
|
// SetFixedFunc: SET(_SET_FIXED [, lNew]) → lOld
|
|
func SetFixedFunc(t *hbrt.Thread) { setToggle(t, SetFixed) }
|
|
|
|
// SetCancelFunc: SET(_SET_CANCEL [, lNew]) → lOld
|
|
func SetCancelFunc(t *hbrt.Thread) { setToggle(t, SetCancel) }
|
|
|
|
// SetBellFunc: SET(_SET_BELL [, lNew]) → lOld
|
|
func SetBellFunc(t *hbrt.Thread) { setToggle(t, SetBell) }
|
|
|
|
// SetConfirmFunc: SET(_SET_CONFIRM [, lNew]) → lOld
|
|
func SetConfirmFunc(t *hbrt.Thread) { setToggle(t, SetConfirm) }
|
|
|
|
// SetInsertFunc: SET(_SET_INSERT [, lNew]) → lOld
|
|
func SetInsertFunc(t *hbrt.Thread) { setToggle(t, SetInsert) }
|
|
|
|
// SetEscapeFunc: SET(_SET_ESCAPE [, lNew]) → lOld
|
|
func SetEscapeFunc(t *hbrt.Thread) { setToggle(t, SetEscape) }
|
|
|
|
// SetWrapFunc: SET(_SET_WRAP [, lNew]) → lOld
|
|
func SetWrapFunc(t *hbrt.Thread) { setToggle(t, SetWrap) }
|
|
|
|
// setToggle implements SET(n, lNew) → lOld for boolean settings
|
|
func setToggle(t *hbrt.Thread, setID int) {
|
|
nParams := t.ParamCount()
|
|
t.Frame(nParams, 0)
|
|
defer t.EndProc()
|
|
|
|
setMu.Lock()
|
|
defer setMu.Unlock()
|
|
|
|
old, ok := settings[setID]
|
|
if !ok {
|
|
old = hbrt.MakeBool(false)
|
|
}
|
|
|
|
if nParams >= 1 && !t.Local(1).IsNil() {
|
|
settings[setID] = t.Local(1)
|
|
}
|
|
t.RetVal(old)
|
|
}
|
|
|
|
// SetDateFunc: __SetDateFormat([cNew]) → cOld
|
|
func SetDateFunc(t *hbrt.Thread) {
|
|
nParams := t.ParamCount()
|
|
t.Frame(nParams, 0)
|
|
defer t.EndProc()
|
|
|
|
setMu.Lock()
|
|
defer setMu.Unlock()
|
|
|
|
old, ok := settings[SetDateFmt]
|
|
if !ok {
|
|
old = hbrt.MakeString("mm/dd/yy")
|
|
}
|
|
|
|
if nParams >= 1 && t.Local(1).IsString() {
|
|
dfmt := t.Local(1).AsString()
|
|
settings[SetDateFmt] = hbrt.MakeString(dfmt)
|
|
}
|
|
t.RetVal(old)
|
|
}
|
|
|
|
// SetDecimalsFunc: SET DECIMALS TO n
|
|
func SetDecimalsFunc(t *hbrt.Thread) {
|
|
nParams := t.ParamCount()
|
|
t.Frame(nParams, 0)
|
|
defer t.EndProc()
|
|
|
|
setMu.Lock()
|
|
defer setMu.Unlock()
|
|
|
|
old := settings[SetDecimals]
|
|
if nParams >= 1 && t.Local(1).IsNumeric() {
|
|
settings[SetDecimals] = t.Local(1)
|
|
}
|
|
t.RetVal(old)
|
|
}
|
|
|
|
// SetEpochFunc: SET EPOCH TO n
|
|
func SetEpochFunc(t *hbrt.Thread) {
|
|
nParams := t.ParamCount()
|
|
t.Frame(nParams, 0)
|
|
defer t.EndProc()
|
|
|
|
setMu.Lock()
|
|
defer setMu.Unlock()
|
|
|
|
old, ok := settings[SetEpoch]
|
|
if !ok {
|
|
old = hbrt.MakeInt(1900)
|
|
}
|
|
if nParams >= 1 && t.Local(1).IsNumeric() {
|
|
settings[SetEpoch] = t.Local(1)
|
|
}
|
|
t.RetVal(old)
|
|
}
|
|
|
|
// --- SET constants for PRG code (registered as RTL functions) ---
|
|
|
|
// _SET_EXACT etc. — return the SET index constant
|
|
func SetConstExact(t *hbrt.Thread) { t.Frame(0, 0); defer t.EndProc(); t.PushInt(SetExact); t.RetValue() }
|
|
func SetConstDeleted(t *hbrt.Thread) { t.Frame(0, 0); defer t.EndProc(); t.PushInt(SetDeleted); t.RetValue() }
|
|
func SetConstSoftSeek(t *hbrt.Thread) { t.Frame(0, 0); defer t.EndProc(); t.PushInt(SetSoftSeek); t.RetValue() }
|
|
func SetConstExclusive(t *hbrt.Thread) { t.Frame(0, 0); defer t.EndProc(); t.PushInt(SetExclusive); t.RetValue() }
|
|
func SetConstDateFmt(t *hbrt.Thread) { t.Frame(0, 0); defer t.EndProc(); t.PushInt(SetDateFmt); t.RetValue() }
|
|
func SetConstDecimals(t *hbrt.Thread) { t.Frame(0, 0); defer t.EndProc(); t.PushInt(SetDecimals); t.RetValue() }
|
|
func SetConstEpoch(t *hbrt.Thread) { t.Frame(0, 0); defer t.EndProc(); t.PushInt(SetEpoch); t.RetValue() }
|
|
|
|
// init registers default DATE format and EPOCH, and hooks into hbrdd.
|
|
func init() {
|
|
hbrdd.IsSetDeleted = GetSetDeleted
|
|
|
|
setMu.Lock()
|
|
if _, ok := settings[SetDateFmt]; !ok {
|
|
settings[SetDateFmt] = hbrt.MakeString("mm/dd/yy")
|
|
}
|
|
if _, ok := settings[SetEpoch]; !ok {
|
|
settings[SetEpoch] = hbrt.MakeInt(1900)
|
|
}
|
|
setMu.Unlock()
|
|
}
|