Files
foxbin2prg/CLAUDE.md
2026-08-03 08:30:21 +03:00

14 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

What this is

A local shared copy of FoxBin2Prg (the VFPX tool by Fernando D. Bozzo, maintained by Lutz Scheffler): a Visual FoxPro 9 program that converts VFP binary files to PRG-style text and back. Supported conversions: PJX↔PJ2, SCX↔SC2, VCX↔VC2, FRX↔FR2, LBX↔LB2, DBC↔DC2, DBF↔DB2, MNX↔MN2.

This directory is a git clone with two remotes:

  • origin = https://github.com/fdbozzo/foxbin2prg.git (upstream, read-only). master tracks origin/master and stays a pristine mirror.
  • romfast = git@gitea.romfast.ro:romfast/foxbin2prg.git (our fork on Gitea, SSH). Working branch romfast (default on Gitea) = upstream master + the ROA additions committed (vcx2txt.ps1, PROMPT_cautare_vfp.md, CLAUDE.md). The pre-git local state is kept on branch local-snapshot-v1.21.04.

Update flow (sync fork from upstream): git fetch origingit checkout master && git merge --ff-only origin/mastergit checkout romfast && git merge mastergit push romfast romfast master. After any update, regenerate binaries/EXE in VFP9 with DO ReCreate_FoxBin2Prg.prg (an error about TESTS\FXUResults.db2 is expected). Text caches live outside this folder (D:\ROA\_vfp_textcache\, see below) so ReCreate never touches them; compiled binaries are kept out of git via the upstream .gitignore plus .git/info/exclude (which also still ignores any stray local _textcache*).

It serves two purposes:

  1. Upstream tool source (for occasional patches to FoxBin2Prg itself).
  2. A shared search tool for the ROA VFP projects (D:\ROA\ROAGEST, D:\ROA\ROAIMOB, D:\ROA\ROAACNPRO, …) via the local additions below.

Local additions (ROA-specific, not part of upstream)

  • git_sync.ps1 — the in-tree flow (primary for migrated ROA projects): folder-mode recursive over the whole project tree (incl. COMUN\), generates the .??2 text next to each binary (not in an external cache) so git tracks readable text instead of binaries. Incremental, converts in a temp staging area and copies back only the text (never touches the SVN working-copy binaries), cleans up orphan .??2, continues past per-file failures and exits nonzero on any. Params: -ProjectRoot, -DbfList (tables converted to .db2 with data), -RoundtripExempt, -SubDir. Run at session start and before every git commit; do not commit while it reports failures.
  • vcx2txt.ps1 — PowerShell script that converts the VFP binaries of a project (read from its .pjx) into text under a cache folder, so the code inside .vcx/.scx/.frx/.mnx/.dbc binaries becomes greppable. Incremental (skips up-to-date files), does not need the VFP IDE open (uses the compiled FoxBin2Prg.EXE). Search-only / non-migrated projects; migrated projects use git_sync.ps1 instead.
  • vfp_symbols.ps1 — symbol index over the text cache and the project's .prg: for every class/method/procedure it records the line range, so a hit can be attributed to its owner. Answers what grep cannot in a .vc2 (where the class header may be 13k lines above the hit and ~2/3 of the file is properties/metadata): -Grep <regex> labels each match with class.method (-CodeOnly drops metadata hits), -Where 'file:line' names the enclosing member, -Find <name> locates the definition, -Class <name> prints the inheritance chain plus members with their ranges. Rebuilds automatically when the cache is newer (~4s); index is a regenerable _symbols.tsv in the cache root.
  • txt2vcx.ps1 — the write-back counterpart: regenerates .vcx/.scx binaries from edited .vc2/.sc2 text and copies them back into the project (see "Golden rule" below for scope/limits). -CacheRoot defaults to -ProjectRoot (in-tree flow: cache→project mapping is identity); pass a separate root only for the old external-cache flow.
  • vfp_filemap.ps1 — shared bin↔memo↔text extension map (.vcx/.vct/.vc2, .scx/.sct/.sc2, .pjx/.pjt/.pj2, .dbf/.fpt/.db2, …), dot-sourced by git_sync.ps1, vcx2txt.ps1 and txt2vcx.ps1 so the mapping stays in one place. Also hosts Invoke-FoxBin2PrgSafe (timeout + taskkill).
  • test_roundtrip.ps1 — standalone fidelity/regression test for the bin→text→bin→text roundtrip and for txt2vcx.ps1's guard rails (staleness, COMUN, missing binary, negative/corrupt input, multi-file runs); parametrized per project. See examples below.
  • test_git_sync.ps1 — standalone tests for git_sync.ps1 on temp fixtures: incremental (up-to-date files skipped), orphan cleanup, nonzero exit on partial failure, and binaries byte-identical after any run.
  • Text caches (external-cache flow, non-migrated / search-only projects) live outside this folder, under D:\ROA\_vfp_textcache\ (one subfolder per project: roacnpro, roagest, roaimob) — per-project regenerable text caches. Migrated projects (ROACONT, COMUN, …) keep their .??2 in-tree via git_sync.ps1 instead of a cache here. Safe to delete; never version them. They must stay outside foxbin2prg: ReCreate_FoxBin2Prg.prg does a recursive Prg2Bin over the whole tool folder (get_FilesFromDirectory recurses into every subfolder, foxbin2prg.prg:6135) and would reconvert any .??2 under it back into stray binaries.
  • PROMPT_cautare_vfp.md — reusable prompt (Romanian) explaining how to set up this search flow in any VFP project. Read it before working on VFP code search.

Golden rule: the text cache is for searching, and — for .vcx/.scx only — for making real code edits via txt2vcx.ps1. Caveats:

  • The generated text format is position-sensitive: don't reformat or reflow lines when editing; preserve the exact line layout.
  • Properties/methods are emitted alphabetically sorted — a newly added property must be inserted in alphabetical order, not appended.
  • Only .vcx/.scx support write-back. .frx/.mnx/.lbx/.pjx/.dbc/.dbf are read-only text (edit in the VFP IDE): menus still need GENMENU to produce .mpr, and the other formats are too fragile for round-trip write-back. git_sync.ps1 still generates their .??2 for readable diffs, but never writes them back.
  • Six FFC/third-party classes under COMUN\ are in git_sync.ps1's -RoundtripExempt list (#INCLUDE makes the isolated roundtrip a false-negative): accessibility.vcx, oinventar.vcx, _gdiplus.vcx, _reportlistener.vcx (in COMUN\clase\), foxcharts.vcx (COMUN\utile\foxcharts\), _webview.vcx (COMUN\utile\web\). Their text is valid (bin→text runs) but roundtrip is not guaranteed — edit them only in the IDE.
  • Targets under COMUN\ require -AllowComun and explicit approval — a change there affects every ROA app.
  • After any VFP IDE session (even one that only opened a class/form), re-run vcx2txt.ps1 to refresh the cache before editing text — otherwise txt2vcx.ps1's staleness check will (correctly) refuse to write back over unseen IDE changes.
  • Encoding: .vc2/.sc2 files declare CPID="1252" in their header, but for ROAGEST at least the Romanian-diacritics bytes are actually cp1250 (0xE3=ă, 0xBA=ş, etc.) — the header lies. Don't decode/re-encode the text with a codepage inferred from the header; treat it byte-preserving (read/write/copy as raw bytes, compare on bytes) and this doesn't matter in practice — it only bites if a script tries to interpret the text as a specific codepage string.
  • Corrupt text can trigger a modal VFP dialog, not just a nonzero exit code: if .vc2/.sc2 text is malformed, Prg2Bin can return ErrorLevel 0 while producing a corrupt binary — the real error only surfaces on a subsequent bin→text pass, sometimes as a native VFP MessageBox that blocks headlessly (not suppressible via parameters/.cfg). Any automated invocation of FoxBin2Prg.EXE must go through the Invoke-FoxBin2PrgSafe wrapper in vfp_filemap.ps1 (default 60s timeout + taskkill on hang) rather than calling the exe directly — and treat the fidelity check (bin→text→compare), not the exe's ErrorLevel, as the real backstop against corrupt/malformed text.
# Populate/refresh a project's text cache (incremental)
& 'D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1' -Project 'D:\ROA\ROAGEST\roagest.pjx' -ProjectRoot 'D:\ROA\ROAGEST' -CacheRoot 'D:\ROA\_vfp_textcache\roagest'

# Include reports/menus too: -Types vcx,scx,frx,mnx
# One-off conversion of a file/folder not in the project: -Source 'path\to\lib.vcx'
# Other flags: -Force (reconvert all), -Clean (wipe cache first)

Then search the cache with Grep (e.g. PROCEDURE do_salvare), citing file:line from the cache.

Attribute hits to their owning class/method (build the index first, or let it build itself):

& 'D:\ROA\UTIL\foxbin2prg\vfp_symbols.ps1' -CacheRoot 'D:\ROA\_vfp_textcache\roagest' -ProjectRoot 'D:\ROA\ROAGEST' -Grep 'do_salvare' -CodeOnly

# -Where 'oavize.vc2:8412'   what class/method owns that line (needed before a txt2vcx edit)
# -Find 'do_salvare'         where it is DEFINED (grep also returns the call sites)
# -Class frm_avize           inheritance chain + members with line ranges

Write back an edited .vc2/.sc2 (after reviewing the diff on text):

& 'D:\ROA\UTIL\foxbin2prg\txt2vcx.ps1' -TextFile 'D:\ROA\_vfp_textcache\roagest\Clase\oavize.vc2' -ProjectRoot 'D:\ROA\ROAGEST' -CacheRoot 'D:\ROA\_vfp_textcache\roagest'

# Preview only, no files touched in the project: add -DryRun
# Target under COMUN\: add -AllowComun (needs approval)
# Skip the staleness check (IDE binary is known up to date some other way): -Force
# Skip the fidelity re-check after regen (not recommended): -NoVerify

Run the regression/fidelity test suite (no Pester, standalone):

& 'D:\ROA\UTIL\foxbin2prg\test_roundtrip.ps1' -ProjectRoot 'D:\ROA\ROAGEST' -CacheRoot 'D:\ROA\_vfp_textcache\roagest' -Phase all

# Run a single phase: -Phase fidelity|edit|negative|smoke

Commands

All FoxBin2Prg commands run inside VFP 9 (or via the compiled FoxBin2Prg.EXE).

* After clone/pull: regenerate all binaries from text and compile the EXEs.
* NEVER run foxbin2prg.prg directly for this — it uses a special config.
DO ReCreate_FoxBin2Prg.prg

* Convert a single file (direction inferred from extension)
DO FOXBIN2PRG.PRG WITH "<path>\file.scx"     && binary -> text (.sc2)
DO FOXBIN2PRG.PRG WITH "<path>\file.sc2"     && text -> binary (.scx)

* Convert a whole directory
DO FOXBIN2PRG.PRG WITH "<path>","Bin2Prg"
DO FOXBIN2PRG.PRG WITH "<path>","Prg2Bin"

* Config templates
DO FOXBIN2PRG.PRG WITH "-c","template.cfg"      && default settings
DO FOXBIN2PRG.PRG WITH "-C","config.cfg"        && active settings
DO FOXBIN2PRG.PRG WITH "-t","table.dbf.cfg"     && per-table template

* Interactive help / option list
DO FOXBIN2PRG.PRG WITH "?"

Tests

Unit tests live in TESTS/ and use FoxUnit (path configured in TESTS/foxunit_path.txt). Files: ut__foxbin2prg__<class>__<method>.prg (unit) and ft__foxbin2prg__<class>.prg (functional). Run them from VFP via FoxUnit; test fixtures live in TESTS/DATOS_READONLY/.

Architecture

Nearly everything is in one ~34,000-line file: foxbin2prg.prg. Key class hierarchy inside it:

  • c_foxbin2prg (As Session) — entry point / public API. Parameter parsing, config resolution (evaluateConfiguration), file dispatch, progress UI, error logging. Also usable as COM-ish object (CREATEOBJECT('c_foxbin2prg'), .execute(...)), which is how the .vbs helpers and SCM integrations drive it.
  • c_conversor_base — shared conversion logic (backup handling, timestamps, comment/property parsing, exclusion blocks).
    • c_conversor_bin_a_prg and per-type subclasses (c_conversor_vcx_a_prg, c_conversor_scx_a_prg, c_conversor_pjx_a_prg, c_conversor_dbf_a_prg, …) — binary → text.
    • c_conversor_prg_a_bin and per-type subclasses — text → binary.
  • CL_* model classes (CL_CLASE, CL_PROJECT, CL_DBC*, CL_DBF_*, CL_MENU*, …) — object model the text files are parsed into / generated from.
  • CL_CFG / CL_DBF_CFG — config file handling (FOXBIN2PRG.CFG with directory inheritance, per-table .dbf.cfg).
  • CL_LANG — localization (EN/ES/FR/DE), auto-selected.

Supporting files: foxbin2prg_keywords.dbf/.cdx (VFP keyword table used during generation — has its own .db2 text form), props_*.txt (per-control default property lists used to suppress default values in output), Create_FoxBin2Prg.cfg (the special self-conversion config), Fb2P_Diff/ and FileName_Caps/ (companion sub-projects, built by ReCreate_FoxBin2Prg.prg), BuildProcess/ (VFPXDeployment build hooks), ThorUpdater/ (Thor/VFPX release plumbing).

Text format is position-sensitive: the generated .??2 files look like PRG/XML but are parsed line by line; structure and line layout must be preserved when editing them. Properties/methods are emitted alphabetically sorted.

Upstream contribution conventions (from .github/CONTRIBUTING.md)

If patching FoxBin2Prg itself:

  • Two version constants at the top of foxbin2prg.prg: bump only the minor part of DC_FB2PRG_VERSION_REAL (e.g. '1.21.04'); do not change DN_FB2PRG_VERSION (1.21) — it's written into every text file and forces mass recommits.
  • Add the change to the history section at the top of foxbin2prg.prg and to docs/ChangeLog.md; update the version in README.md.
  • Style: mixed-case keywords, tab indentation, spaces around operators and after list items; do not run BeautifyX with mDots insertion.
  • After changes, regenerate text with DO Create_FoxBin2Prg.prg and compile in VFP9 SP2.

Documentation

  • docs/FoxBin2Prg_Internals.md — settings reference and internals (ZOrder, timestamps, class-per-file, DBF export hooks, API).
  • docs/FoxBin2Prg_Run.md — full command-line/parameter reference.
  • docs/FoxBin2Prg_git.md, docs/FoxBin2Prg_SCM.md — SCM integration.
  • Spanish docs in Documentacion/ are unmaintained.