Compare commits
1 Commits
romfast
...
local-snap
| Author | SHA1 | Date | |
|---|---|---|---|
| dba04049b9 |
16
.github/CONTRIBUTING.md
vendored
16
.github/CONTRIBUTING.md
vendored
@@ -47,9 +47,7 @@ CD "path_to_FoxBin2Prg"
|
||||
DO ReCreate_FoxBin2Prg.prg
|
||||
```
|
||||
**Note: Do not run FoxBin2Prg.prg directly.**
|
||||
**Note: There might be an FoxBin2Prg error around _tests\datos_readonly\vw_local_encuestas_. This is intended.
|
||||
The file is in the test suit and is intended to create an error for testing purposes.**
|
||||
3. Do your changes
|
||||
3. Do your changes
|
||||
4. On top of _FoxBin2Prg.prg_ there are two version numbers:
|
||||
```
|
||||
#DEFINE DN_FB2PRG_VERSION 1.21
|
||||
@@ -78,10 +76,7 @@ CD "path_to_FoxBin2Prg"
|
||||
DO Create_FoxBin2Prg.prg
|
||||
```
|
||||
**Note: Do not run FoxBin2Prg.prg directly.**
|
||||
**Note: There might be an FoxBin2Prg error around _tests\datos_readonly\vw_local_encuestas.tbf_. This is intended.
|
||||
The file is in the test suit and is intended to create an error for testing purposes. This does not create a problem.
|
||||
If you do not see this, it's just your config.**
|
||||
15. **The following steps are not neccesary, if you use [VPXDeployment](#using-vfpxdeployment) to create a new version that is applicable for Thor use.**
|
||||
15. **The following steps are not neccesary, if you use *VPXDeployment* to create a new version that is applicable for Thor use.**
|
||||
16. Compile to EXE **in VFP9 SP2**
|
||||
17. Change Thor ([see below](#thor-conventions))
|
||||
18. commit
|
||||
@@ -102,11 +97,10 @@ The standard procedure to create the Thor files is runing VFPXDeployment via Tho
|
||||
2. Run VFPXDeployment. It will set version number to EXE, compile, set several documentation and create the files for Thor.
|
||||
3. commit
|
||||
4. push to your fork
|
||||
5. Create a pull request
|
||||
5. create a pull request
|
||||
|
||||
### Without VFPXDeployment
|
||||
If you do not use VFPXDeployment.
|
||||
|
||||
If you do not use VFPXDeployment
|
||||
There are some considerations to make to add a new version to Thor.
|
||||
Please check [Supporting Thor Updater](https://vfpx.github.io/thorupdate/)
|
||||
In special:
|
||||
@@ -125,4 +119,4 @@ In special:
|
||||
Thanks
|
||||
|
||||
----
|
||||
Last changed: _2026/06/18_ 
|
||||
Last changed: _2023/12/05_ 
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -20,8 +20,6 @@
|
||||
#programms
|
||||
!*.prg
|
||||
!*.fpw
|
||||
!*.ps1
|
||||
!*.bat
|
||||
|
||||
#header
|
||||
!*.h
|
||||
|
||||
144
CLAUDE.md
144
CLAUDE.md
@@ -1,144 +0,0 @@
|
||||
# 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 origin` → `git checkout master && git merge --ff-only origin/master` → `git checkout romfast && git merge master` → `git 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.
|
||||
|
||||
```powershell
|
||||
# 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):
|
||||
|
||||
```powershell
|
||||
& '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):
|
||||
|
||||
```powershell
|
||||
& '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):
|
||||
|
||||
```powershell
|
||||
& '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`).
|
||||
|
||||
```foxpro
|
||||
* 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.
|
||||
@@ -1,6 +1,6 @@
|
||||
*################################################################################################################
|
||||
*-- Individual DBF configuration file (syntax: filename.dbf.cfg) Defaults see FoxBin2prg.cfg
|
||||
*Version: v1.21.05
|
||||
*Version: v1.21.04
|
||||
*****************************************************************************************************************
|
||||
|
||||
*DBF_Conversion_Support: <0,1,2,4,8> && 0=No support, 1=Generate Header TXT only (Diff), 2=Generate Header TXT and BIN (Merge/Only Structure!), 4=Generate TXT with DATA (Diff), 8=Export and Import DATA (Merge/Structure & Data)
|
||||
|
||||
@@ -32,7 +32,7 @@ _AutoIncrement = "0"
|
||||
|
||||
|
||||
*<BuildProj>
|
||||
*<.HomeDir = 'd:\roa\util\foxbin2prg\fb2p_diff' />
|
||||
*<.HomeDir = 'e:\se\vfpx\foxbin2prg\fb2p_diff' />
|
||||
|
||||
FOR EACH loProject IN _VFP.Projects FOXOBJECT
|
||||
loProject.Close()
|
||||
@@ -70,9 +70,9 @@ ENDWITH
|
||||
|
||||
WITH loProject
|
||||
*<ProjectProperties>
|
||||
.SetMain("main_fb2p_diff.prg")
|
||||
.SetMain(lcCurdir + 'main_fb2p_diff.prg')
|
||||
|
||||
.Icon = "fb2p_diff.ico"
|
||||
.Icon = lcCurdir + 'fb2p_diff.ico'
|
||||
.Debug = .T.
|
||||
.Encrypted = .F.
|
||||
*<.CmntStyle = 1 />
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -3,4 +3,5 @@
|
||||
*--------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
*< FOXBIN2PRG: Version="1.21" SourceFile="fb2p_diff.scx" CPID="1252" /> (Solo para binarios VFP 9 / Only for VFP 9 binaries)
|
||||
*
|
||||
|
||||
*
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,127 +0,0 @@
|
||||
# Prompt: căutare și editare în cod VFP (foxbin2prg) — reutilizabil în orice proiect Visual FoxPro
|
||||
|
||||
Acest fișier conține un **prompt gata de copiat** pentru Claude Code (sau alt agent), care
|
||||
configurează și folosește sistemul `foxbin2prg` ca să poată **căuta** cod-sursă aflat **în interiorul
|
||||
fișierelor binare VFP** (`.vcx/.vct`, `.scx/.sct`, `.frx/.frt`, `.mnx/.mnt`, `.dbc/.dct`) într-un
|
||||
proiect nou — și, pentru `.vcx`/`.scx`, să poată și **modifica** acel cod direct pe text, cu
|
||||
write-back în binar (`txt2vcx.ps1`), fără trecere prin IDE-ul VFP.
|
||||
|
||||
Unealta e partajată și stă la `D:\ROA\UTIL\foxbin2prg\` — nu trebuie copiată per proiect. Doar
|
||||
spui agentului care e proiectul curent (folderul + fișierul `.pjx`).
|
||||
|
||||
---
|
||||
|
||||
## Cum se folosește
|
||||
|
||||
1. Deschide proiectul VFP în Claude Code.
|
||||
2. Copiază blocul de mai jos în prompt.
|
||||
3. Înlocuiește cele **3 valori** marcate `<<...>>` cu datele proiectului tău:
|
||||
- `<<RADACINA_PROIECT>>` = folderul rădăcină al proiectului (ex. `D:\ROA\ROAGEST`)
|
||||
- `<<FISIER_PJX>>` = calea către `.pjx` (ex. `D:\ROA\ROAGEST\roagest.pjx`)
|
||||
- `<<NUME_PROIECT>>` = etichetă scurtă pentru folderul de cache (ex. `roagest`)
|
||||
|
||||
---
|
||||
|
||||
## ▼▼▼ PROMPT DE COPIAT ▼▼▼
|
||||
|
||||
```
|
||||
Acest proiect este o aplicație Visual FoxPro 9. O mare parte din cod (proceduri, metode,
|
||||
parametri) NU stă în fișiere .prg, ci în interiorul fișierelor binare VFP: librării de clase
|
||||
(.vcx+.vct), forme (.scx+.sct), rapoarte (.frx+.frt), meniuri (.mnx+.mnt). Un grep direct pe
|
||||
acestea nu e lizibil (sunt tabele DBF cu memo binar).
|
||||
|
||||
Ca să poți căuta în acel cod, folosește unealta partajată foxbin2prg, care convertește binarele
|
||||
în reprezentarea lor TEXT (.vc2/.sc2/.fr2/.mn2/.dc2) într-un cache, și apoi caută în cache.
|
||||
|
||||
PARAMETRII PROIECTULUI CURENT:
|
||||
- Rădăcină proiect: <<RADACINA_PROIECT>>
|
||||
- Fișier proiect (.pjx): <<FISIER_PJX>>
|
||||
- Cache text: D:\ROA\_vfp_textcache\<<NUME_PROIECT>>
|
||||
|
||||
REGULA DE AUR: cache-ul text e sursa pentru CĂUTARE (toate tipurile de binar) și, DOAR pentru
|
||||
.vcx/.scx, și pentru EDITARE cu write-back (txt2vcx.ps1, vezi PAS 3). Pentru .frx/.mnx/.dbc
|
||||
textul rămâne doar pentru citire — modificările la ele se fac în IDE-ul VFP, pe binar.
|
||||
|
||||
PAS 1 — populează cache-ul text (la începutul sesiunii, sau după ce s-a modificat ceva în IDE).
|
||||
Rulează în PowerShell (e incremental — sare peste ce e deja la zi):
|
||||
|
||||
& 'D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1' -Project '<<FISIER_PJX>>' -ProjectRoot '<<RADACINA_PROIECT>>' -CacheRoot 'D:\ROA\_vfp_textcache\<<NUME_PROIECT>>'
|
||||
|
||||
(Folosește un -CacheRoot distinct per proiect ca să nu amesteci cache-urile. Implicit scriptul
|
||||
convertește doar .vcx și .scx; pentru a include și rapoarte/meniuri adaugă: -Types vcx,scx,frx,mnx)
|
||||
|
||||
Dacă scriptul se plânge că lipsește FoxBin2Prg.EXE, trebuie compilat o singură dată: deschide
|
||||
'D:\ROA\UTIL\foxbin2prg\foxbin2prg.pj2' în VFP 9 și Build > Build Executable. Anunță-mă să fac asta.
|
||||
|
||||
PAS 2 — caută în cache cu unealta Grep (NU în binarele originale):
|
||||
|
||||
Grep pe folderul 'D:\ROA\_vfp_textcache\<<NUME_PROIECT>>' pentru numele de metodă/procedură/variabilă căutat.
|
||||
Ex.: caută "PROCEDURE do_salvare" sau numele tabelei/cursorului implicat.
|
||||
|
||||
CONVERSIE PUNCTUALĂ (un fișier sau folder care NU e în proiect, ex. o librărie din COMUN):
|
||||
|
||||
& 'D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1' -Source 'CALE\catre\librarie.vcx' -CacheRoot 'D:\ROA\_vfp_textcache\<<NUME_PROIECT>>'
|
||||
|
||||
ALTE OPȚIUNI: -Force (reconvertește tot), -Clean (șterge cache-ul întâi).
|
||||
|
||||
PAS 3 — modificare de cod în .vcx/.scx (flux write-back pe text). Ordinea e obligatorie:
|
||||
|
||||
a. Investighează pe cache, propune modificarea și AȘTEAPTĂ ACORDUL pe abordare înainte să
|
||||
editezi ceva.
|
||||
b. Refresh cache (PAS 1) dacă a rulat vreo sesiune de IDE de la ultimul refresh (staleness-ul
|
||||
se verifică pe mtime și txt2vcx refuză corect scrierea peste modificări nevăzute). Înainte
|
||||
de write-back închide COMPLET VFP IDE și exe-ul aplicației — procesele reziduale țin lock
|
||||
pe binare.
|
||||
c. Editează .vc2/.sc2 BYTE-SAFE: formatul e position-sensitive (nu reformata/reflow linii),
|
||||
proprietățile sunt alfabetizate (una nouă se inserează la locul ei alfabetic). Headerul
|
||||
CPID="1252" poate minți despre codepage-ul real al diacriticelor — citește/scrie fișierul
|
||||
ca bytes (PowerShell), conținutul NOU doar ASCII; nu folosi unelte care re-encodează.
|
||||
d. Write-back:
|
||||
|
||||
& 'D:\ROA\UTIL\foxbin2prg\txt2vcx.ps1' -TextFile 'D:\ROA\_vfp_textcache\<<NUME_PROIECT>>\Clase\lib.vc2' -ProjectRoot '<<RADACINA_PROIECT>>' -CacheRoot 'D:\ROA\_vfp_textcache\<<NUME_PROIECT>>'
|
||||
|
||||
Regenerează + compilează binarul în staging, verifică fidelitatea (roundtrip byte-identic
|
||||
față de textul editat) și abia apoi copiază binarul în proiect; la orice eșec proiectul
|
||||
rămâne neatins. Ținte sub COMUN\ cer flag-ul -AllowComun ȘI aprobare explicită — o
|
||||
modificare acolo afectează toate aplicațiile ROA.
|
||||
e. Diff lizibil pentru review: extrage binarul vechi din git (git show HEAD:cale > temp, atât
|
||||
.vcx cât și .vct), regenerează-i textul cu vcx2txt.ps1 -Source într-un folder temporar și
|
||||
compară cu cache-ul editat: git diff --no-index. COMMIT DOAR după ce omul confirmă pe diff
|
||||
și testează în IDE.
|
||||
|
||||
EXCEPȚII: pentru .mnx (GENMENU) și .frx (fragile la round-trip) nu există write-back — scrie
|
||||
propunerea de modificare într-un fișier docs/propuneri_<subiect>.md (cod + unde se inserează),
|
||||
iar aplicarea se face manual în IDE-ul VFP.
|
||||
|
||||
FLUX TIPIC: la prima sesiune rulează PAS 1 o dată, apoi caută cu Grep în cache (PAS 2). La
|
||||
sesiunile următoare rescrie doar ce s-a schimbat. Când citești codul unei metode, dă referințe
|
||||
fișier:linie din cache.
|
||||
```
|
||||
|
||||
## ▲▲▲ SFÂRȘIT PROMPT ▲▲▲
|
||||
|
||||
---
|
||||
|
||||
## Note pentru adaptare
|
||||
|
||||
- `<<NUME_PROIECT>>` îl poți pune orice etichetă scurtă (ex. `roagest`), doar ca numele
|
||||
folderului de cache să fie unic per proiect.
|
||||
- Ține cache-ul în `D:\ROA\_vfp_textcache\`, adică **în afara** folderului `foxbin2prg`. Motiv:
|
||||
`ReCreate_FoxBin2Prg.prg` face `Prg2Bin` recursiv pe tot folderul tool-ului și ar reconverti
|
||||
`.??2`-urile din orice cache aflat sub el înapoi în binare parazitare.
|
||||
- Scriptul citește lista de fișiere direct din `.pjx`, deci convertește **doar** ce folosește
|
||||
efectiv proiectul (rapid), nu tot `COMUN\`.
|
||||
- Cache-ul (`D:\ROA\_vfp_textcache\<proiect>`) e regenerabil și e în afara arborelui de versionare
|
||||
al proiectului (și în afara clonei foxbin2prg) — poate fi șters oricând.
|
||||
- Conversia NU necesită IDE-ul VFP deschis (folosește `FoxBin2Prg.EXE` compilat).
|
||||
- Fără backup-uri `.bak` lângă binarele din proiect — git e mecanismul de restore; `txt2vcx.ps1`
|
||||
ține o copie de siguranță doar în folderul temp al rulării.
|
||||
- Editările de volum se pot delega la subagenți (Sonnet, în background) — sesiunea principală
|
||||
orchestrează, verifică diff/fidelity și intervine doar la deblocări și decizii.
|
||||
- Detalii complete despre write-back (guard-uri, encoding, dialoguri VFP modale la text corupt,
|
||||
testul de regresie `test_roundtrip.ps1`): `D:\ROA\UTIL\foxbin2prg\CLAUDE.md`.
|
||||
- Exemplu funcțional, rodat pe ROAGEST: `D:\ROA\ROAGEST\docs\flux-editare-vfp-text.md` și
|
||||
`D:\ROA\ROAGEST\docs\CLAUDE.md` (modul de lucru complet, cu review pe diff înainte de commit).
|
||||
- Ghid complet doar-căutare (varianta ROAACNPRO, cu exemple): `D:\ROA\ROAACNPRO\docs\cautare_vcx_vct.md`.
|
||||
- Tabel corespondență binar → text: `.vcx`→`.vc2`, `.scx`→`.sc2`, `.frx`→`.fr2`, `.mnx`→`.mn2`,
|
||||
`.dbc`→`.dc2`, `.lbx`→`.lb2`.
|
||||
46
README.md
46
README.md
@@ -1,5 +1,5 @@
|
||||
# FoxBin2Prg
|
||||
## Version 1.21.05
|
||||
## Version 1.21.04
|
||||
**Binary/Text Converting program for Microsoft Visual FoxPro**
|
||||
|
||||
## Lutz Scheffler
|
||||
@@ -32,31 +32,16 @@ If you like to see Fernandos blog, or value his work:
|
||||
Thank you for your support!
|
||||
|
||||
----
|
||||
## Table of contents
|
||||
- [Contribution](#contribution)
|
||||
- [What is FOXBIN2PRG](#what-is-foxbin2prg)
|
||||
- [Advantages](#advantages)
|
||||
- [Examples](#examples)
|
||||
- [Redefine extensions of _Text_](#redefine-extensions-of-text)
|
||||
- [Use FoxBin2Prg](#use-foxbin2prg)
|
||||
- [Interactive list of options](#interactive-list-of-options)
|
||||
- [Use with MS Windows SendTo](#use-with-ms-windows-sendto)
|
||||
- [How to use the links](#how-to-use-the-links)
|
||||
- [LOCALIZATION](#localization)
|
||||
- [FINAL NOTE](#final-note)
|
||||
- [LICENCE](#licence)
|
||||
- [Changes](#changes)
|
||||
- [Changes to Configuration](#changes-to-settings)
|
||||
- [Limitations](#limitations)
|
||||
- [**Documentation**](#documentation)
|
||||
- [**Helping with FoxBin2PRG / issues**](#helping-with-foxbin2prg--issues)
|
||||
- [Note](#note)
|
||||
## Important Note
|
||||
To fix a bug, this version changes the text file header.
|
||||
It is suggested to create all text files and commit in one step.
|
||||
|
||||
----
|
||||
## Contribution
|
||||
See [contribution](./.github/CONTRIBUTING.md)
|
||||
|
||||
---
|
||||
|
||||
## What is FOXBIN2PRG?
|
||||
It is a program intended to be used with **SCM tools** (Source Code Managers, like VSS, CVS, SVN)
|
||||
and *DVCS tools* (Version Control Systems such as Git, Mercurial, Plastic, and others),
|
||||
@@ -139,14 +124,14 @@ You can create up to three different shortcuts pointing to FoxBin2Prg.exe and in
|
||||
##### How to use the links
|
||||
Select a file, right-click, SendTo -> FoxBin2Prg
|
||||
|
||||
## LOCALIZATION
|
||||
## LOCALIZATION:
|
||||
Is automatic starting at v1.19.38 (Languages: EN,ES,FR,DE)
|
||||
|
||||
## FINAL NOTE
|
||||
## FINAL NOTE:
|
||||
This program is Open Source and "libre", and I don't make any guaranties that it fulfills your expectations or that it will be free of bugs.
|
||||
I will try to fix bugs if my obligations let me do it.
|
||||
|
||||
## LICENCE
|
||||
## LICENCE:
|
||||
This work is licensed under the Creative Commons Attribution 4.0 International License.
|
||||
To view a copy of this license, visit http://creativecommons.org/licenses/by/4.0/.
|
||||
|
||||
@@ -154,7 +139,7 @@ To view a copy of this license, visit http://creativecommons.org/licenses/by/4.0
|
||||
## Changes
|
||||
See [Changes](./docs/ChangeLog.md)
|
||||
|
||||
### Changes to Configuration
|
||||
### Changes to Settings
|
||||
To get the new settings in config file, use the new create-a-template function:
|
||||
|
||||
```
|
||||
@@ -162,23 +147,23 @@ DO FOXBIN2PRG.PRG WITH "-c","template.cfg" ==> Generates a template for Fox
|
||||
DO FOXBIN2PRG.PRG WITH "-C","template.cfg" ==> Generates a template for FoxBin2Prg.cfg config file with active settings
|
||||
DO FOXBIN2PRG.PRG WITH "-t","template.dbf.cfg" ==> Generates a template for table.dbf.cfg per table config file with newest settings
|
||||
```
|
||||
See [Configuration](./FoxBin2Prg_Settings.md) for more information about configuration file(s).
|
||||
|
||||
----
|
||||
## Limitations
|
||||
- If dealing with project files, FoxBin2Prg will fail if files of the project are not stored on the drive of the project.
|
||||
If dealing with project files, FoxBin2Prg will fail if files of the project are not stored on the drive of the project.
|
||||
See [issue #93](https://github.com/fdbozzo/foxbin2prg/issues/93).
|
||||
- FoxBin2Prg could be used as exe or prg. See [Usage](./docs/FoxBin2Prg.md#usage) for details and problems.
|
||||
|
||||
----
|
||||
## Documentation
|
||||
## Usage
|
||||
For usage see [documentation](./docs/FoxBin2Prg.md)
|
||||
|
||||
----
|
||||
## Helping with FoxBin2PRG / issues
|
||||
|
||||
## Helping with FoxBin2PRG
|
||||
See [contribution](./.github/CONTRIBUTING.md)
|
||||
|
||||
---
|
||||
|
||||
## Note
|
||||
The spanish documentation is not longer maintained - it would fade.
|
||||
For fast access a quick run is [introduced](#use-foxbin2prg), more [complex](./docs/FoxBin2Prg_Run.md#usage-1), and a large [documentation](./docs/FoxBin2Prg.md) exists too.
|
||||
@@ -189,4 +174,5 @@ If you like to see Fernando's blog, or value his work:
|
||||
- [](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=fdbozzo%40gmail%2ecom&lc=ES&item_name=FoxBin2Prg&item_number=FoxBin2Prg&currency_code=USD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted)
|
||||
|
||||
----
|
||||
Last changed: _2026/06/21_ 
|
||||
|
||||
Last changed: _2024/08/26_ 
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -3,8 +3,8 @@ lparameters toUpdateObject
|
||||
* Set the properties of the passed updater object.
|
||||
|
||||
with toUpdateObject
|
||||
.VersionNumber = '1.21.05 - 20260618'
|
||||
.AvailableVersion = 'FoxBin2PRG-1.21.05-update-20260618'
|
||||
.VersionNumber = '1.21.04 - 20240826'
|
||||
.AvailableVersion = 'FoxBin2PRG-1.21.04-update-20240826'
|
||||
.Notes = GetNotes()
|
||||
.RegisterWithThor = GetRegisterWithThor()
|
||||
endwith
|
||||
@@ -63,4 +63,4 @@ text to lcCommand noshow
|
||||
endtext
|
||||
return lcCommand
|
||||
|
||||
*created by VFPX Deployment, 18.06.2026 19:36:46
|
||||
*created by VFPX Deployment, 08/26/2024 2:08:42 PM
|
||||
@@ -27,21 +27,14 @@ _**Note:** you can click on the version number for downloading this version from
|
||||
|
||||
| Rel.Date | Developer | Version | Details |
|
||||
| - | - | - | - |
|
||||
| 2026/06/18 | LScheffler | [v1.21.05](https://github.com/fdbozzo/foxbin2prg/releases/tag/v1.21.05) | **Bug Fix**: Brute force fixed Datatype error for tcDontShowProgress, #114 (omirian) |
|
||||
| | | | **Bug Fix**: Fixed missing link SCM documentation, #116 (ToniKoehler) |
|
||||
| | | | **Bug Fix**: Fixed a problem that cDontShowProgress parameter will be ignored if ShowProgressbar property is used. #118 (LScheffler) |
|
||||
| | | | **Enhancement**: Added documentation of properties of settings object |
|
||||
| | | | **Enhancement**: Better documentation if a settings us ignored when a parameter is set. Voth in in docu and setting files generated via -Cc options. |
|
||||
| | | | **Enhancement**: Some settings will not follow inheritence, documented in docu and setting files generated via -Cc options. |
|
||||
| | | | **Enhancement**: Minor changes |
|
||||
| 2024/08/26 | DHennig | [v1.21.04](https://github.com/fdbozzo/foxbin2prg/releases/tag/v1.21.04) | **Enhancement**: Added support for BodyDevInfo = 2 in CFG file to prevent both DevInfo and ObjRev from being written to PJ2 file |
|
||||
| 2024/08/26 | DHennig | v1.21.04 | **Enhancement**: Added support for BodyDevInfo = 2 in CFG file to prevent both DevInfo and ObjRev from being written to PJ2 file |
|
||||
| 2024/04/24 | LScheffler | [v1.21.03](https://github.com/fdbozzo/foxbin2prg/releases/tag/v1.21.03) | **Bug Fix**: Text To Bin with Fieldcaption = "NULL" (misnomer. it's the field name); #106; #106 (griessbach14943) |
|
||||
| 2024/01/03 | LScheffler | [v1.21.02](https://github.com/fdbozzo/foxbin2prg/releases/tag/v1.21.02) | **Bug Fix**: Problems regenerating single classes and forms from text files in class-per-file form; #105 (LScheffler) |
|
||||
| 2023/11/19 | LScheffler | [v1.21.01](https://github.com/fdbozzo/foxbin2prg/releases/tag/v1.21.01) | **Enhancement**: Source files not longer included in Thor. The file you will found are old and will be removed with subsequent installs. (LScheffler) |
|
||||
| | | | **Bug Fix**: Problems regenerating databases with splited contents due to the removed Spanish characters in comment. (LScheffler) |
|
||||
| 2023/11/19 | LScheffler | [v1.21.01](https://github.com/fdbozzo/foxbin2prg/releases/tag/v1.21.01) | **Bug Fix**: Problems regenerating databases with splited contents due to the removed Spanish characters in comment. (LScheffler) |
|
||||
| 2023/10/20 | LScheffler | [v1.21.00](https://github.com/fdbozzo/foxbin2prg/releases/tag/v1.21.00) | **Bug Fix**: Problems with Spanish characters in comment. (ccantrell72) |
|
||||
| 2023/09/06 | LScheffler | [v1.20.07](https://github.com/fdbozzo/foxbin2prg/releases/tag/v1.20.07) | **Enhancement**: Option to block processing of directories. If file ".FoxBin2Prg_Ignore" is existing, this directories and all subdirectries will be ignored. (Mainly set up to ignore local GoFish settings) (LScheffler) |
|
||||
| | | | **Bug Fix**: Problems recreating tables (LScheffler) |
|
||||
| 2023/09/06 | LScheffler | [v1.20.06](https://github.com/fdbozzo/foxbin2prg/releases/tag/v1.20.06) | **Bug Fix**: Problems recreating tables (LScheffler) |
|
||||
| 2023/09/03 | LScheffler | [v1.20.05](https://github.com/fdbozzo/foxbin2prg/releases/tag/v1.20.05) | **Bug Fix**: Problems recreating menu files (introduced with codepage) (LScheffler) |
|
||||
| | | | **Enhancement:** Inserted options to allow splitting of SCX handling from VCX. |
|
||||
| 2023/09/01 | LScheffler | [v1.20.04](https://github.com/fdbozzo/foxbin2prg/releases/tag/v1.20.04) | **Enhancement**: New option "tcDebug" for get_DirSettings method. |
|
||||
@@ -457,4 +450,4 @@ _**Note:** you can click on the version number for downloading this version from
|
||||
This project is part of [VFPX](https://vfpx.github.io/).
|
||||
|
||||
----
|
||||
Last changed: _2016/06/18_ 
|
||||
Last changed: _2024/08/26_ 
|
||||
@@ -12,24 +12,18 @@ As far as possible these are the original documents. Changes are added where fun
|
||||
## Table of contents
|
||||
- [Use](#use)
|
||||
- [Download for development](#download-for-development)
|
||||
- [Source](#source)
|
||||
- [Rebuild additional files](#rebuild-additional-files)
|
||||
- [Requirements](#requirements)
|
||||
- [Demo video](#demo-video)
|
||||
- [What is FoxBin2Prg](#what-is-foxbin2prg)
|
||||
- [Advantages](#advantages)
|
||||
- [Example](#example)
|
||||
- [Limitations](#limitations)
|
||||
- [Usage](#usage)
|
||||
- [**Configuration**](#configuration)
|
||||
- [Keep reading](#keep-reading)
|
||||
|
||||
## Use
|
||||
- Download the [runtime](https://github.com/fdbozzo/foxbin2prg/blob/master/ThorUpdater/FoxBin2Prg.zip) (same as used by Thor)
|
||||
- Or (best) install via [Thor](https://github.com/VFPX/Thor/blob/master/Docs/Thor_install.md), this keeps you on the latest version.
|
||||
|
||||
See [Usage](#usage) for details and problems.
|
||||
|
||||
## Download for development
|
||||
### Source
|
||||
Original repository at https://github.com/fdbozzo/foxbin2prg.
|
||||
@@ -83,31 +77,26 @@ for which a _Text_ version is generated with pj2, sc2, vc2, fr2, lb2, dc2, db2,
|
||||
The extensions may be reconfigured to be compatible with SCCAPI (just tested with SourceSafe).
|
||||
|
||||
## Example
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
## Limitations
|
||||
- If dealing with project files, FoxBin2Prg will fail if files of the project are not stored on the drive of the project.
|
||||
If dealing with project files, FoxBin2Prg will fail if files of the project are not stored on the drive of the project.
|
||||
See [issue #93](https://github.com/fdbozzo/foxbin2prg/issues/93).
|
||||
- FoxBin2Prg could be used as exe or prg. See [Usage](#usage) for details and problems.
|
||||
|
||||
## Usage
|
||||
FoxBin2Prg can be used in tree ways:
|
||||
1. [EXE version](./FoxBin2Prg_Run.md): (Recommended and fastest)
|
||||
- All-inclusive, you just need _foxbin2prg.exe_ and _filename_caps.exe/cfg_.
|
||||
- All-inclusive, you just need foxbin2prg.exe and filename_caps.exe/cfg.
|
||||
- Runs from windows
|
||||
- **If run from IDE, the EXE needs to be compiled for the version of FoxPro.**
|
||||
- If run from IDE, the EXE needs to be compiled for the version of FoxPro.
|
||||
1. [PRG version](./FoxBin2Prg_Run.md):
|
||||
- You need various files: _foxbin2prg.prg_, all the _props*.txt_ files and _filename_caps.exe/cfg_. Keep in one folder.
|
||||
- You need various files: foxbin2prg.prg, all the props*.txt files and filename_caps.exe/cfg.
|
||||
- Runs out of VFP IDE, no problems mixing VFP 9 and VFPA
|
||||
1. [Object version](./FoxBin2Prg_Object.md):
|
||||
- Based on EXE or PRG
|
||||
- Usable out of own code
|
||||
- expandable
|
||||
|
||||
## Configuration
|
||||
See [Configuration](./FoxBin2Prg_Settings.md) for more information about configuration file(s).
|
||||
|
||||
## Keep reading
|
||||
- [FoxBin2Prg Full Change History](./ChangeLog.md)
|
||||
- [FoxBin2Prg Internals and Configuration](./FoxBin2Prg_Internals.md)
|
||||
@@ -119,4 +108,4 @@ See [Configuration](./FoxBin2Prg_Settings.md) for more information about configu
|
||||
This project is part of [VFPX](https://vfpx.github.io/).
|
||||
|
||||
----
|
||||
Last changed: _2026/06/21_ 
|
||||
Last changed: _2023/12/05_ 
|
||||
@@ -12,21 +12,23 @@ As far as possible these are the original documents. Changes are added where fun
|
||||
## Table of contents
|
||||
- [Why to use this tool](#why-to-use-this-tool)
|
||||
- [Limitations](#limitations)
|
||||
- [Configuration file](#configuration-file)
|
||||
- [Configuration file per table](#configuration-file-per-table)
|
||||
- [Excluding directories](#excluding-directories)
|
||||
- [FoxBin2Prg Internals](#foxbin2prg-internals)
|
||||
- [**Configuration**](#configuration)
|
||||
- [Configuration per table](#configuration-per-table)
|
||||
- [Parameters](#parameters)
|
||||
- [ZOrder](#zorder)
|
||||
- [RemoveZOrderSetFromProps setting](#removezordersetfromprops-setting)
|
||||
- [VFP ZOrder bug and fix](#vfp-zorder-bug-and-fix)
|
||||
- [RemoveZOrderSetFromProps setting](#removezordersetfromprops-setting)
|
||||
- [VFP ZOrder bug and fix](#vfp-zorder-bug-and-fix)
|
||||
- [DBC ordered fields](#dbc-ordered-fields)
|
||||
- [PAM Section](#pam-section)
|
||||
- [Property Ordering](#property-ordering)
|
||||
- [Timestamps and UniqueIDs](#timestamps-and-uniqueids)
|
||||
- [DBF Data Export/Import for Diff/Merge](#dbf-data-export/import-for-diff/merge)
|
||||
- [Order and range of records](#order-and-range-of-records)
|
||||
- [Configuration per table](#configuration-per-table)
|
||||
- [DBF/DB2 Convertion Hooks](#dbf/db2-convertion-hooks)
|
||||
- [Language Support for messages](#language-support-for-messages)
|
||||
- [Multi-config](#multi-config)
|
||||
- [File Capitalization](#file-capitalization)
|
||||
- [Conversion processes Logging](#conversion-processes-logging)
|
||||
- [Storing paths for pjx](#storing-paths-for-pjx)
|
||||
@@ -89,16 +91,139 @@ but the result must be compilable and keep the structure.
|
||||
All limitations that occur to a binary format must be kept on the text representation -
|
||||
the definition of a HEADER class to a VCX will fail.
|
||||
|
||||
## Configuration file
|
||||
It is possible to create a template or a config with all options and comments via
|
||||
```
|
||||
DO FOXBIN2PRG.PRG WITH "-c","template.cfg" &&==> Generates a template for FoxBin2Prg.cfg config file with newest settings
|
||||
DO FOXBIN2PRG.PRG WITH "-C","config.cfg" &&==> Generates a config file like FoxBin2Prg.cfg with recent settings of path of second parameter
|
||||
```
|
||||
See [command line](./FoxBin2Prg_Run.md#usage-2).
|
||||
The config file is used to move local setting to a different comupter or for changes while branching.
|
||||
|
||||
The options in the template (or in the config that ships with FoxBin2Prg) are commented out.
|
||||
To activate an option remove the asterix and set appropriate value.
|
||||
These are the FoxBin2Prg.cfg configuration file settings and their meaning:
|
||||
|
||||
| FoxBin2Prg.cfg keywords | Value (_Default_) | Description |
|
||||
| ----- | ----- | ----- |
|
||||
| Language | _(auto)_, EN, FR, ES, DE | Language of templates, shown messages and LOGs. EN=English, FR=French, ES=Español, DE=German, Not defined = AUTOMATIC (using VERSION(3)) ||
|
||||
| DontShowProgress | 0 | **Deprecated**. Replaced by ShowProgressbar option from v1.19.40 |
|
||||
| ShowProgressbar | 0, _1_, 2 | 0=Don't show progressbar,<br/>1=Always show a progress bar,<br/>2=Only show it when processing multiple-files |
|
||||
| DontShowErrors | _0_, 1 | 0=show message errors in a modal messagebox. (default)<br/>1=don't show errors |
|
||||
| ExtraBackupLevels | 0, _1_, n | <br/>0=No backup<br/>1=One backupfile _\_filename\_.BAK_ (default)<br/>n=n levels of backup in style _\_filename\_.n.BAK_ |
|
||||
| Debug | _0_, 1, 2 | 0=Off<br/>1=Normal<br/>2=Extended<br/>By default, don't generate individual \<file\>.Log with process hints.<br/>Activate with "1" to find possible error causes and for debugging,<br/>"2" is special logging.<br/>**If cDebug is set via parameter, this is ignored.** |
|
||||
| BackgroundImage | \<cFile\> | Backgroundimage for process form |
|
||||
| HomeDir | 0, _1_ | 0=don't save HomeDir in PJ2,<br/>1=save HomeDir in PJ2.<br/>Setting this to 0 prevents the PJ2 file from changing just because two developers have the project in different folders |
|
||||
| BodyDevInfo | _0_, 1, 2 | 0=Don't keep DevInfo for body pjx records, 1=Keep DevInfo, 2 = Don't keep DevInfo or ObjRev.<br/>Setting this to 2 prevents the PJ2 file from changing just because two developers built the project on their machines |
|
||||
|||
|
||||
| InhibitInheritance | _0_, 1, 2, 3 | **This settings is for config file via parameter only** <br/>Settings for config file via parameter only0=Allow scanning "regular" config files (file via parameter is just additional default)<br/>1=Only read tree from root of the file given by parameter, not FoxBin2Prg default<br/>2=Only read folder and subfolder of the file given by parameter<br/>3=Read no other file<br/>This is like<br/>0 Default \| Parameter file \| Default near FoxBin2Prg \| all other config files<br/>1 Default \| Parameter file \| Inheritance from root to parent of folder \| folder and subdirs<br/>2 Default \| Parameter file \| folder and subdirs<br/>3 Default \| Parameter file |
|
||||
|||
|
||||
| XXX_Conversion_Support | n | Defines the conversion operation per filetype |
|
||||
| | | For code:<br/> 0=No support,<br/>1=Generate _Text_ (Diff),<br/>2=Generate _Text_ and _Bin_ (Merge) |
|
||||
| | | For complex data:<br/> (PJX / DBC / DBF): 0=No support,<br/>1=Generate Header _Text_ only (Diff),<br/>2=Generate Header _Text_ and _Bin_ (Merge/Only Structure!),<br/>4=Generate _Text_ with DATA (Diff),<br/>8=Export and Import DATA (Merge/Structure & Data) |
|
||||
| PJX_Conversion_Support | 0, 1, _2_ | Default value is 2 - Bidirectional ((Merge/Only Structure!),<br/>4=Generate _Text_ with DATA (Diff), 8=Export and Import DATA (Merge/Structure & Data) and _bin_) support activated |
|
||||
| VCX_Conversion_Support | 0, 1, _2_ | Default value is 2 - Bidirectional (_Text_ and _bin_) support activated |
|
||||
| SCX_Conversion_Support | 0, 1, _2_ | Default value is 2 - Bidirectional (_Text_ and _bin_) support activated |
|
||||
| FRX_Conversion_Support | 0, 1, _2_ | Default value is 2 - Bidirectional (_Text_ and _bin_) support activated |
|
||||
| LBX_Conversion_Support | 0, 1, _2_ | Default value is 2 - Bidirectional (_Text_ and _bin_) support activated |
|
||||
| MNX_Conversion_Support | 0, 1, _2_ | Default value is 2 - Bidirectional (_Text_ and _bin_) support activated |
|
||||
| DBC_Conversion_Support | 0, 1, _2_ | Default value is 2 - Bidirectional (_Text_ and _bin_) support activated |
|
||||
| DBF_Conversion_Support | 0, _1_, 2, 4, 8 | Default value is 1 - just _Text_ support activated.<br/>The support for regenerating DBFs structures (value = 2) are disabled by default to not overrite data accidentally. When activating bidirectional support, keep in mind that Data is not restored, just the structure and indexes!.<br/>A value of 4 is used to export Structure and Data, but exported data is not imported again.<br/>A value of 8 is used for bidirectional support (No General fields!). <br/> **Note:** This can be [changed per table](#configuration-file-per-table). |
|
||||
| FKY_Conversion_Support | 0, _1_ | Default value is 1 - _Text_ support activated |
|
||||
| MEM_Conversion_Support | 0, _1_ | Default value is 1 - _Text_ support activated |
|
||||
|||
|
||||
| CheckFileInPath | _0_, 1, 2, 3 |Determines how 2Txt deals with files not in the subfolders of the PJX. No handler for UNC paths.<br />0 = Ignore. Default<br />1 = Check and error out if file is not on same structure (for source control)<br />2 = Create absolute path if file is on different drive.<br />3 = Create absolute path if file is not in structure<br />See [Storing paths for pjx](#storing-paths-for-pjx) |
|
||||
|||
|
||||
| UseClassPerFile | _0_, 1, 2 | 0=One library _Text_ file,<br/>1=Multiple file.class.vc2 files,<br/>2=Multiple file.baseclass.class.vc2 files<br/>See [Create Class-Per-File](#create-class-per-file) |
|
||||
| [RedirectClassPerFileToMain:](#redirectclassperfiletomain:) | _0_, 1 | 0=Don't redirect to file.vcx,<br/>1=Redirect to file.vcx when selecting file.class.vc2<br/>RedirectClassType: 1 precedes this setting |
|
||||
| RedirectClassType | _0_, 1, 2 | For classes created with UseClassPerFile>0 in the form file[.baseclass].class.tx2 (vcx only) |
|
||||
| | | 0=creates / refresh class in file.VCX and add / replace all other classes of this library |
|
||||
| | | 1=creates / refresh class file[.baseclass].class.VCX and do not touch file.VCX |
|
||||
| | | 2=creates / refresh class in file.VCX and do not touch other classes of file.VCX |
|
||||
| [ClassPerFileCheck](#classperfilecheck) | _0_, 1 | 0=Don't check file.class.vc2 inclusion,<br/>1=Check file.class.vc2 inclusion<br/>Only used if import file is in file[.baseclass].class.tx2 syntax.<br/>Ignored for RedirectClassType: 2 |
|
||||
|||
|
||||
| [UseFormSettings](#create-file-per-form) | _0_, 1 | 0=Old Style, like the class settings<br/>1=Form style, special for form<br/>This controls the use of the _UseFormPerFile_, _RedirectFormPerFileToMain_, _RedirectFormType_ and _FormPerFileCheck_ options.<br/>Only if this option is set, the options will be read. |
|
||||
| UseFormPerFile | _0_, 1, 2 | 0=One library _Text_ file,<br/>1=Multiple Form.Object.sc2 files,<br/>2=Multiple Form.baseclass.Object.sc2 files<br/>See [Create Class-Per-File](#create-class-per-file) |
|
||||
| [RedirectFormPerFileToMain](#redirectclassperfiletomain) | _0_, 1 | 0=Don't redirect to Form.scx,<br/>1=Redirect to Form.scx when selecting Form.Object.sc2<br/>RedirectClassType: 1 precedes this setting |
|
||||
| RedirectFormType | _0_, 1, 2 | For classes created with UseClassPerFile>0 in the form Form[.baseclass].Object.sx2 (scx only) |
|
||||
| | | 0=creates / refresh class in Form.SCX and add / replace all other classes of this library |
|
||||
| | | 1=creates / refresh class Form[.baseclass].Object.SCX and do not touch Form.SCX |
|
||||
| | | 2=creates / refresh class in Form.SCX and do not touch other classes of Form.SCX |
|
||||
| [FormPerFileCheck](#classperfilecheck) | _0_, 1 | 0=Don't check Form.Object.sc2 inclusion,<br/>1=Check Form.Object.sc2 inclusion<br/>Only used if import file is in Form[.baseclass].Object.sc2 syntax.<br/>Ignored for RedirectClassType: 2 |
|
||||
|||
|
||||
| OldFilesPerDBC | _0_, 1 | 0=Old Style,<br/>1=New style<br/>This controls the use of the _UseFilesPerDBC_, _RedirectFilePerDBCToMain_ and _ItemPerDBCCheck_ options.<br/>Only if this option is set, the **Form** options below will be read. |
|
||||
| | | 0=New version inactive, options follow:<br/>UseFilesPerDBC=UseClassPerFile<br/>RedirectFilePerDBCToMain=RedirectClassPerFileToMain<br/>ItemPerDBCCheck=ClassPerFileCheck |
|
||||
| | | 1=New version active, options active |
|
||||
| | | Note: The options will be set to old style, if option is turned off. |
|
||||
| UseFilesPerDBC | _0_, 1 | 0=One database dc2 file,<br/>1=Multiple file.\*.\*.dc2 files.<br/>See [Create File-Per-DBC](#create file-per-dbc)<br/>**Only if OldFilesPerDBC is 1** |
|
||||
| | | 0=creates only a file.dc2 with all DBC (file) data |
|
||||
| | | 1=creates a file.dc2 with DBC properties |
|
||||
| | | and additional DBC files per DBC item (stored-proc, table, ..) |
|
||||
| | | Note: recration only if RedirectFilePerDBCToMain is 1 |
|
||||
| [RedirectFilePerDBCToMain](#redirectfileperdbctomain) | _0_, 1 | 0=Don't redirect to file.dc2,<br/>1=Redirect to file.tx2 when selecting file.item.*.dc2<br/>**Only if OldFilesPerDBC is 1** |
|
||||
| [ItemPerDBCCheck](#itemperdbccheck) | _0_, 1 | 0=Don't check file.item.*.dc2 inclusion,<br/> 1=Check file.item.*.dc2 inclusion<br/>**Only if OldFilesPerDBC is 1**|
|
||||
|||
|
||||
| NoTimestamps | 0, _1_ | 0=Do not clear<br/>1=Clear<br/>By default, timestamp fields are cleared on _Text_ files, because a lot of differencies are generated on _Binaries_ and _Text_ files with Timestamps activated. This timestamp field is part of the vcx, scx and other Foxpro binary source code files. |
|
||||
| ClearUniqueID | 0, _1_ | 0=Keep UniqueID,<br/>1=Clear Unique ID.<br/>Very useful for Diff and Merge.<br/>By default, UniqueID fields are cleared on _Text_ files, because a lot of differencies are generated with UniqueID activated |
|
||||
| OptimizeByFilestamp | _0_, 1 | 0=Don't optimize (always generate),<br/>1=Optimize (generate only when destination filestamp es older). By default this optimization is deactivated, and it is not recommended if using for merge, so _Bin_ and _Text_ files can be modified seperately.<br/><span style="background-color: gold;">Dangerous while working with branches!</span> |
|
||||
| RemoveNullCharsFromCode | 0, _1_ | 1=Drop NULL chars from source code,<br/>0=Leave NULL chars in source code |
|
||||
| RemoveZOrderSetFromProps | _0_, 1 | 1=Remove ZOrderSet from the properties,<br/>0=Leave ZOrderSet in the properties |
|
||||
|||
|
||||
| ClearDBFLastUpdate | 0, _1_ | 0=Keep DBF LastUpdate,<br/>1=Clear DBF LastUpdate.<br/>Useful for Diff, minimizes differences. |
|
||||
| ExcludeDBFAutoincNextval | _0_, 1 | 0=Do not exclude this value from db2,<br/>1=Exclude this value from db2 |
|
||||
| DBF_Conversion_Included | * | If DBF_Conversion_Support:4, you can specify multiple filemasks: www,fb2p_free.dbf.<br/>See [Order and range of records](#order-and-range-of-records).<br/>**Note:** This can be [changed per table](#configuration-file-per-table). |
|
||||
| DBF_Conversion_Excluded | | If DBF_Conversion_Support:4, you can specify multiple filemasks: www,fb2p_free.dbf.<br/>See [Order and range of records](#order-and-range-of-records).<br/>**Note:** This can be [changed per table](#configuration-file-per-table). |
|
||||
| DBF_BinChar_Base64 | 0, _1_ | 0=For character type fields, if NoCPTrans 0=do not transform,<br/>1=use Base64 transform (default)<br/>**Note:** This can be [changed per table](#configuration-file-per-table). |
|
||||
| DBF_IncludeDeleted | _0_, 1 | 0=Do not include deleted records (default),<br/>1=Include deleted records<br/>**Note:** This can be [changed per table](#configuration-file-per-table). |
|
||||
| | | **Note:**<br/>This is only true for tables. Generating DBC to _Text_ and back to _Binary_ will act as PACK DATABASE.<br/>The data added by _DBF_IncludeDeleted: 1_ will be ignored by old versions generating _Binary_ files. |
|
||||
|||
|
||||
| extension: xx2 | | FoxBin2Prg extensions ends in '2' (pj2, vc2, sc2, etc), but you can change that. |
|
||||
| extension: pj2= | \<extension\> | Text file for project PJX |
|
||||
| extension: vc2= | \<extension\> | Text file for classlibray VCX, or a class out of a VCX |
|
||||
| extension: sc2= | \<extension\> | Text file for form SCX, or a class out of a SCX (Form; Dataenbironment) |
|
||||
| extension: fr2= | \<extension\> | Text file for report FRX |
|
||||
| extension: lb2= | \<extension\> | Text file for label LBX |
|
||||
| extension: mn2= | \<extension\> | Text file for menu MNX |
|
||||
| extension: db2= | \<extension\> | Text file for table DBF, free or DBC bound |
|
||||
| extension: dc2= | \<extension\> | Text file for database container DBC, or records from database container DBC |
|
||||
| extension: fk2= | \<extension\> | Text file for macro file FKY |
|
||||
| extension: me2= | \<extension\> | Text file for variable memory MEM, created with SAVE TO |
|
||||
| | | **Example for for making it SourceSafe (sccapi v1) compatible:**<br/>extension: pj2=pja<br/>extension: vc2=vca<br/>extension: sc2=sca<br/>extension: fr2=fra<br/>extension: lb2=lba<br/>extension: mn2=mna<br/>extension: db2=dba<br/>extension: dc2=dca |
|
||||
|
||||
### Note
|
||||
The options will be read outside in, top to down. See [Multi-config](#multi-config)
|
||||
|
||||
## Configuration file per table
|
||||
Those configuration files are valid for a single table only. The idea is to have special settings for single tables.
|
||||
It is possible to create a template with all options and comments via
|
||||
```
|
||||
DO FOXBIN2PRG.PRG WITH "-t","template.dbf.cfg" &&==> Generates a template for table.dbf.cfg per table config file with newest settings
|
||||
```
|
||||
|
||||
See [command line](./FoxBin2Prg_Run.md#usage-2).
|
||||
The options in the template (or in the config that ships with FoxBin2Prg) are commented out.
|
||||
To activate an option remove the asterix and set appropriate value.
|
||||
These are the Table.dbf.cfg configuration file settings and their meaning:
|
||||
|
||||
| FoxBin2Prg.cfg keywords | Value | per<br/>file | Description |
|
||||
| ----- | ----- | ----- | ----- |
|
||||
| DBF_Conversion_Support | 0, 1, 2, 4, 8 | | 0=No support,<br/>1=Generate Header _Text_ only (Diff),<br/>2=Generate Header _Text_ and _Bin_ (Merge/Only Structure!),<br/>4=Generate _Text_ with DATA (Diff),<br/>8=Export and Import DATA (Merge/Structure & Data) |
|
||||
| DBF_Conversion_Order | c_Expression | x | Field expresion (For _INDEX ON_). ie: name+str(age,3),<br/>Empty means no sort order. <br/> usefull only if _DBF_Conversion_Support_>0 |
|
||||
| DBF_Conversion_Condition | c_Expression | x | Logical expression (For _SCAN FOR_). ie: age > 10 AND NOT DELETED(),<br/>empty means all records, except _DBF_IncludeDeleted_ <br/> usefull only if _DBF_Conversion_Support_>0 |
|
||||
| DBF_IndexList | c_FileList | x | A comma delimited list of additional index files ( cdx or idx ). **Not the structural index file.** |
|
||||
| DBF_BinChar_Base64 | 0, 1 | | 0=For character type fields, if NoCPTrans 0=do not transform,<br/>1=use Base64 transform <br/> usefull only if _DBF_Conversion_Support_>2 |
|
||||
| DBF_IncludeDeleted | 0, 1 | | 0=Do not include deleted records,<br/>1=Include deleted records <br/> usefull only if _DBF_Conversion_Support_>2 |
|
||||
|
||||
Setting **per file** could only be used via this configuration file.
|
||||
For defaults, see [Configuration file](#configuration-file).
|
||||
|
||||
## Excluding directories
|
||||
It is possible to exclude directory structures from processing. Placing a file **.FoxBin2Prg_Ignore** into a directory will stop FoxBin2Prg from processing any file in this directory and it's subdirectories. The file must just exist and could otherwise be empty.
|
||||
The difference to setting all *XXX_Conversion_Support to 0* is, that it could not be turned on again down the directory structure.
|
||||
|
||||
This was set up to ignore the local GoFish_ settings and history folder, the file will be automatically created by GoFish starting with version 6.2.004.
|
||||
|
||||
## FoxBin2Prg Internals
|
||||
### Configuration
|
||||
The internals found on this document are set via [Configuration file(s)](./FoxBin2Prg_Settings.md). See there for a complete list of all settings.
|
||||
|
||||
#### Configuration per table
|
||||
New \<filename.dbf.cfg> configuration options. See [Configuration file per table](./FoxBin2Prg_Settings.md#configuration-file-per-table).
|
||||
|
||||
### Parameters
|
||||
Some of the internals might be influenced by parameters of either the call of the [program / executable](./FoxBin2Prg_Run.md#usage-1) or [API, Execute method](./FoxBin2Prg_Object.md#execute).
|
||||
|
||||
### ZOrder
|
||||
In _Text_ files and starting from v1.19.12, the ZOrder,
|
||||
that determines the order on which objects are instantiated and which one is on top,
|
||||
@@ -154,7 +279,7 @@ This section is generated for classes and forms, it is delimited with the \<Defi
|
||||
and have the definition of Properties, Arrays and Methods, with their comments, like this example:
|
||||
````
|
||||
DEFINE CLASS c1 AS custom OLEPUBLIC && Description of "c1" class
|
||||
* <DefinedPropArrayMethod>
|
||||
*<DefinedPropArrayMethod>
|
||||
*m: emptymethod_with_comments && This method have no code, just comments!
|
||||
*m: mymethod && My Method
|
||||
*p: prop1 && My prop 1
|
||||
@@ -163,7 +288,7 @@ DEFINE CLASS c1 AS custom OLEPUBLIC && Description of "c1" class
|
||||
*a: array_1_d[1,0](1,0) && 1 dimension array (1)
|
||||
*a: array_2_d[1,2](1,2) && 2 dimension array (1,2)
|
||||
*p: _memberdata && XML Metadata for customizable properties
|
||||
* </DefinedPropArrayMethod>
|
||||
*</DefinedPropArrayMethod>
|
||||
````
|
||||
Starting from v1.19.21 arrays don't need to be preceded with "^" symbol, and methods don't need to be preceded with "*" symbol,
|
||||
which makes this section more easy to maintain.
|
||||
@@ -190,9 +315,9 @@ and a list with all in it ("props_all.txt") for the second case, so in case of a
|
||||
rearranging some props will be an easy thing.
|
||||
|
||||
#### Warning
|
||||
These "props_*" files are necessary in the FoxBin2Prg install directory.
|
||||
These "props_**" files are necessary in the FoxBin2Prg install directory.
|
||||
|
||||
It's recommended to use the EXE version that have all files included and is faster. **Note, the EXE must fit your version of VFP**.
|
||||
It's recommended to use the EXE version that have all files included and is faster._
|
||||
Several Unit Tests (in TESTS directory) are made to make the best effort to cover the most typical use cases.
|
||||
There is also an Excel spreedsheet with the compilation of properties of each class with the order that FoxPro uses internally,
|
||||
and a tab with the all-in-one order for the worst case.
|
||||
@@ -215,7 +340,7 @@ Since version v1.19.47, importing of Data can be activated with **"DBF_Conversio
|
||||
If you want to export the data of just some tables and not for all of them, one way is moving the tables
|
||||
for data export to another directory, or even a subdirectory of main data files,
|
||||
and write a foxbin2prg.cfg with **"DBF_Conversion_Support: 4 or 8"** for this diretory only,
|
||||
taking advantage of [Multi configuration](./multi-configuration#multi-configuration) capability introduced on v1.19.25
|
||||
taking advantage of multi-configuration capability introduced on v1.19.25
|
||||
A much better option that join the best of the two worlds, available from v1.19.44,
|
||||
could be using the default setting **"DBF_Conversion_Support: 1"** and using **individual cfg files** for each table
|
||||
(table.dbf.cfg) on which you want to export their data, so this way you can have only the structure in DB2 files
|
||||
@@ -237,6 +362,26 @@ Example of multiple file masks (separte with ","):
|
||||
"DBF_Conversion_Included: PET**.**, ??ME.DBF, ???.DBF, ?.**"
|
||||
````
|
||||
|
||||
### Configuration per table
|
||||
New \<filename.dbf.cfg> configuration options. See [Configuration file per table](#configuration-file-per-table).
|
||||
|
||||
These options can be used in any combination inside a dbf particular cfg file,
|
||||
if you create a text file using your dbf filename and adding ".cfg".
|
||||
|
||||
#### Syntax for filename.dbf.cfg contents
|
||||
````
|
||||
"DBF_Conversion_Support: <4 for export only or 8 for bidirectional support>"
|
||||
"DBF_Conversion_Order: <C_Expression>"
|
||||
"DBF_Conversion_Condition: <C_Expression>"
|
||||
````
|
||||
|
||||
#### Example: customers.dbf.cfg
|
||||
````
|
||||
"DBF_Conversion_Support: 4"
|
||||
"DBF_Conversion_Order: cust_no"
|
||||
"DBF_Conversion_Condition: cust_no > 10"
|
||||
````
|
||||
|
||||
### DBF/DB2 Convertion Hooks
|
||||
From version v1.19.19 there is a new property "run_AfterCreateTable" and from version v1.19.24 "run_AfterCreate_DB2".
|
||||
The purpose of both properties is to allow the execution of an external program each time a DBF is converted to DB2 or a DB2
|
||||
@@ -292,6 +437,32 @@ and send it to me. I will include it in the next release ;-)
|
||||
.h language files are not supported anymore, and are now implemented inside FoxBin2Prg,
|
||||
in the "C_LANG" class at the end of the PRG_
|
||||
|
||||
### Multi-config
|
||||
Starting at version v1.19.25 FoxBin2Prg allow configuration per directory,
|
||||
overriding the main configuration of FoxBin2Prg directory.
|
||||
The override is by each setting, so you can reconfigure one or more settings and the
|
||||
remaining settings are inherited from main CFG.
|
||||
|
||||
From v1.19.42 CFGs are inherited between directories from parent to child,
|
||||
so if you have all your developments under, let's say, "c:\devs" directory and subdirs,
|
||||
de CFG in "c:\devs" will be inherited on subdirs, and settings can be overriden one by one if you want to.
|
||||
This inheritance saves a lot of time and minimizes the CFGs needed \:\)
|
||||
|
||||
##### Note
|
||||
Options will be read outside in, top to down.
|
||||
If an option is defined multiple times, even in the same file, last occurance wins.
|
||||
|
||||
The exception are the group controlling the new style to split DBC files and the one for forms.
|
||||
The options _UseFilesPerDBC_, _RedirectFilePerDBCToMain_ and _ItemPerDBCCheck_ will be ignored for DBC,
|
||||
if _OldFilesPerDBC_ is set to 0.
|
||||
Setting _OldFilesPerDBC_ to 1 will inhertit the values from the \*class\* options.
|
||||
If _OldFilesPerDBC_ is set to 0 after it was active, the values of the three options are rejected at all and reset to the corresponding \*class\* values.
|
||||
For Forms, options _UseFormPerFile_, _RedirectFormPerFileToMain_, _RedirectFormType_ and _FormPerFileCheck_ will be ignored,
|
||||
if _UseFormSettings_ is set to 0.
|
||||
Setting _UseFormSettings_ to 1 will inhertit the values from the \*class\* options.
|
||||
If _UseFormSettings_ is set to 0 after it was active, the values of the four options are rejected at all and reset to the corresponding \*class\* values.
|
||||
|
||||
|
||||
### File Capitalization
|
||||
FoxBin2Prg takes care of file capitalization (their extension, specifically),
|
||||
using another program called ("filename_caps.exe") for capitalizing input files and output files.
|
||||
@@ -509,22 +680,20 @@ This is a list of available methods and properties:
|
||||
|
||||
| Method()/Property<br/>Syntax | Description |
|
||||
| -| - |
|
||||
| **execute**<br/>loCnv.execute( cInputFile [,cType [,cTextName;<br/>[,lGenText [,cDontShowErrors [,cDebug;<br/>[,cDontShowProgress [,oModule [,oEx;<br/>[,lRelanzarError [,cOriginalFileName [,cRecompile;<br/>[,cNoTimestamps [,cBackupLevels [,cClearUniqueID;<br/>[,cOptimizeByFilestamp ,cCFG_File ] ] ] ] ] ] ] ] ] ] ] ] ] ] ) | Main execution method to start a conversion<br/> See [Object version](./FoxBin2Prg_Object.md#execute) |
|
||||
| **execute**<br/>loCnv.execute( cInputFile [,cType [,cTextName [,lGenText [,cDontShowErrors [,cDebug [,cDontShowProgress [,oModule [,oEx [,lRelanzarError [,cOriginalFileName [,cRecompile [,cNoTimestamps [,cBackupLevels [,cClearUniqueID [,cOptimizeByFilestamp [,cCFG_File](,cType-[,cTextName-[,lGenText-[,cDontShowErrors-[,cDebug-[,cDontShowProgress-[,oModule-[,oEx-[,lRelanzarError-[,cOriginalFileName-[,cRecompile-[,cNoTimestamps-[,cBackupLevels-[,cClearUniqueID-[,cOptimizeByFilestamp-[,cCFG_File ] ] ] ] ] ] ] ] ] ] ] ] ] ] ) | Main execution method to start a conversion<br/> See [Object version](./FoxBin2Prg_Object.md#execute) |
|
||||
| **conversionSupportType**<br/>loCnv.conversionSupportType( cFilename ) | Return the code of the support type (0,1,2,4,8) |
|
||||
| **get_DBF_Configuration**<br/>loCnv.get_DBF_Configuration( cInputFile, @oOutDbfCfg ) | Returns 1 if a CFG is found for the indicated DBF, or 0 if not |
|
||||
| **hasSupport_Bin2Prg**<br/>loCnv.hasSupport_Bin2Prg( cFilename.ext )<br/>loCnv.hasSupport_Bin2Prg( cExt ) | Returns .T. if there is support for converting the file or filetype indicated to _text_ |
|
||||
| **hasSupport_Prg2Bin**<br/>loCnv.hasSupport_Prg2Bin( cFilename.ext )<br/>loCnv.hasSupport_Prg2Bin( cExt ) | Returns .T. if there is support for converting the file or filetype indicated to _Binary_ |
|
||||
| **evaluateConfiguration**<br/>loCnv.evaluateConfiguration( cDontShowProgress;<br/>[,cDontShowErrors [,cNoTimestamps [,cDebug;<br/>[,cRecompile [,cBackupLevels [,cClearUniqueID;<br/>[,cOptimizeByFilestamp [,cInputFile [,cInputFileTypeType;<br/>[,cCFG_File] ] ] ] ] ] ] ] ] ) | Forces FoxBin2Prg to process the directory indicated in the cInputFile and update any CFG in the directory or their parents |
|
||||
| **evaluateConfiguration**<br/>loCnv.evaluateConfiguration( cDontShowProgress [,cDontShowErrors [,cNoTimestamps [,cDebug [,cRecompile [,cBackupLevels [,cClearUniqueID [,cOptimizeByFilestamp [,cInputFile [,cInputFileTypeType [,cCFG_File](,cDontShowErrors-[,cNoTimestamps-[,cDebug-[,cRecompile-[,cBackupLevels-[,cClearUniqueID-[,cOptimizeByFilestamp-[,cInputFile-[,cInputFileTypeType-[,cCFG_File) ] ] ] ] ] ] ] ] ) | Forces FoxBin2Prg to process the directory indicated in the cInputFile and update any CFG in the directory or their parents |
|
||||
| **loadProgressbarForm**<br/>loCnv.loadProgressbarForm() | Load and show the progressbar form as upper level window |
|
||||
| **unloadProgressbarForm**<br/>loCnv.unloadProgressbarForm() | Hide and unload the progressbar form |
|
||||
| **updateProgressbar**<br/>loCnt.updateProgressbar( cText, nValue, nTotal, nType ) | Update the progressbar and the message. nType indicates which progressbar to update, being 0=1st PB and 1=2nd PB |
|
||||
| **get_DirSettings**<br/>loCnv.get_DirSettings( cDir ) | Returns a CFG object with the settings that are applied on the indicated directory<br/>See [Configuration file](./FoxBin2Prg_Settings.md#configuration-file) for the properties and how they fit to the settings file. |
|
||||
| **get_DirSettings**<br/>loCnv.get_DirSettings( cDir ) | Returns a CFG object with the settings that are applied on the indicated directory |
|
||||
| **get_Ext2FromExt**<br/>loCnv.get_Ext2FromExt( cExt ) | Returns the _text extension_ corresponding to the _Binary_ extension indicated |
|
||||
| **get_Processed**<br/>loCnv.get_Processed( @aProcessed, cFileMask ) | Returns an array with the status of the files being processed or that will be processed in no-real-process-mode.<br/>No-real-process-mode is set if `l_ProcessFiles=.F.` before the call.<br/>Columns returned are 6: "cFile, cInOutType, cProcessed, cHasErrors, cSupported, cExpanded"` |
|
||||
| **get_Processed**<br/>loCnv.get_Processed( @aProcessed, cFileMask ) | Returns an array with the status of the files being processed or that will be processed in no-real-process-mode if you set `l_ProcessFiles=.F.` before the call. Columns returned are 6: "cFile, cInOutType, cProcessed, cHasErrors, cSupported, cExpanded"` |
|
||||
| **clearProcessedFiles**<br/>loCnv.clearProcessedFiles() | Clear the statistics and the cache about processed files. If a file was processed and is already processed, being not cached will force to process it again |
|
||||
| **wasProcessed**<br/>loCnv.wasProcessed( cFile ) | Returns .T. if the fullpath-file was processed, searching in the internal cache |
|
||||
| **c_OutputFile**<br/>loCnv.c_OutputFile = cPath | A folder (or file) to write the output to. If not used, output be the source path.<br/>Similar to exe/prgs parameter. _cOutputFolder_- |
|
||||
| **l_ProcessFiles**<br/>loCnv.l_ProcessFiles = Boolean | Controls if _Execute_ will process the files or simulate. If simulated, the files in the process can be read via _get_Processed_ method. Intended for expansions of FoxBin2Prg. |
|
||||
|
||||
#### Renamed
|
||||
This is the translation table of old method names up to v1.19.41 and the new names:
|
||||
@@ -608,8 +777,9 @@ For options on integrating FoxBin2Prg with SCM tools, look at this topic:
|
||||
See [FoxBin2Prg and use with git](./FoxBin2Prg_git.md)
|
||||
|
||||
----
|
||||
Last changed: _2023/09/06_
|
||||

|
||||
This project is part of [VFPX](https://vfpx.github.io/).
|
||||
|
||||
----
|
||||
Last changed: _2026/06/21_ 
|
||||
Last changed: _2024/08/26_ 
|
||||
@@ -5,7 +5,7 @@ Documentation of FoxBin2Prg - A Binary to Text converter for MS Visual Foxpro 9
|
||||
FoxBin2Prg might be used as an EXE either from Windows or VFP, or as as prg from inside VFP in a [command line](./FoxBin2Prg_Run.md) way.
|
||||
This document deals with the integration as an VFP Object using VFP based objects.
|
||||
|
||||
For settings see [Configuration](./FoxBin2Prg_Settings.md), for API and other related stuff see [Internals](./FoxBin2Prg_Internals.md).
|
||||
For settings, API and other realted stuff see [Internals](./FoxBin2Prg_Internals.md).
|
||||
|
||||
The original document was created by [Fernando D. Bozzo](https://github.com/fdbozzo) whom I like to thank for the great project.
|
||||
Pictures are taken from the original project.
|
||||
@@ -42,10 +42,7 @@ Transforming file(s) works like
|
||||
`obj.execute(cInputFile [,cType [,cTextName [,lGenText [,cDontShowErrors [,cDebug [,cDontShowProgress [,oModule [,oEx [,lRelanzarError [,cOriginalFileName [,cRecompile [,cNoTimestamps [,cBackupLevels [,cClearUniqueID [,cOptimizeByFilestamp [,cCFG_File] ] ] ] ] ] ] ] ] ] ] ] ] ] ])`
|
||||
A lot of the parameters are the same as calling the [command line](./FoxBin2Prg_Run.md),
|
||||
some additional are added and some are not string type.
|
||||
Some settings will overwrite configuration.
|
||||
Using an file as cCFG_File with `InhibitInheritance=3` set will overwrite all configuration. See [Configuration file(s)](./FoxBin2Prg_Settings.md) for more information. This file will be read as first setting, see [Multi config](./FoxBin2Prg_Settings.md#multi-configuration).
|
||||
Using an object as oCFG (instead of cCFG_File) will overwrite all configuration and only this settings will be used.
|
||||
|
||||
Some settings will overwrite configuration. Using an object as cCFG_File will overwrite all configuration.
|
||||
|
||||
| Parameter | Value (_Default_) | Description |
|
||||
| ----- | ----- | ----- |
|
||||
@@ -64,21 +61,21 @@ Using an object as oCFG (instead of cCFG_File) will overwrite all configuration
|
||||
| | -t | Create per-table configuration file template <cInputFile> or, if first parameter is empty and a table open, \<tablename\>._cfg in table folder. With inactive default values. |
|
||||
| cTextName | Text filename. | Only for SCCAPI (SCCTEXT.PRG) compatibility mode. File to use. |
|
||||
| lGenText | .T., .F. | Only for SCCAPI (SCCTEXT.PRG) compatibility mode. .T.=Generates Text, .F.=Generates Binary. <br/> **Note:** _cType_ have predominance over _lGenText_ |
|
||||
| cDontShowErrors | _0_, 1 | '1' for NOT showing errors in MESSAGEBOX.<br/>This has precedence over the _DontShowErrors_ setting. |
|
||||
| cDebug | _0_, 1, 2 | '0 'no debug, '1' for generating process LOGs, stop on errors, '2' like '1' and special log.<br/>This has precedence over the _Debug_ value in the config files. |
|
||||
| cDontShowProgress | 0, _1_, 2 | '0' show progress, '1' for **not** showing the process window, '2' Show only for multi-file processing.<br/>This has precedence over the _ShowProgressbar_ setting. Value "0","1" is inverted to the setting. |
|
||||
| cDontShowErrors | _0_, 1 | '1' for NOT showing errors in MESSAGEBOX |
|
||||
| cDebug | _0_, 1, 2 | '0 'no debug, '1' for generating process LOGs, stop on errors, '2' like '1' and special log.<br/>This has precedence over any value in the config files. Only the first valid value will be used. |
|
||||
| cDontShowProgress | 0, _1_, 2 | '0' show progress, '1' for **not** showing the process window, '2' Show only for multi-file processing |
|
||||
| oModule | | Internal use for Unit Testing |
|
||||
| oEx | | Exception object, return for errorhandling |
|
||||
| lRelanzarError | .T.. _.F._ | Throw error to caller of _.Execute()_ |
|
||||
| cOriginalFileName | text | used in those cases in which inputFile is a temporary filename and you want to generate the correct filename on the header of the text version |
|
||||
| cRecompile | 0, _1_ | Indicates recompile ('1') the binary once generated. <br/> True if called from SCCAPI (SCCTEXT.PRG) compatibility mode. |
|
||||
| | path | The binary is compiled from this path |
|
||||
| cNoTimestamps | 0, _1_ | Indicates if timestamp must be cleared ('1' or empty) or not ('0'),<br/>This has precedence over the _NoTimestamps_ setting. |
|
||||
| cNoTimestamps | 0, _1_ | Indicates if timestamp must be cleared ('1' or empty) or not ('0') |
|
||||
| cBackupLevels | 0, _1_, .. | "0" no Bakup, "1", one level _filename_.bak, "n" n levels of Backup _filename_.n.bak |
|
||||
| cClearUniqueID | 0, _1_ | 0=Keep UniqueID in text files, 1=Clear Unique ID. Useful for Diff and Merge.<br/>This has precedence over the _ClearUniqueID_ setting. |
|
||||
| cOptimizeByFilestamp | _0_, 1 | 1=Optimize file regeneration depending on file timestamp.<br/>This has precedence over the _OptimizeByFilestamp_ setting.<br/><span style="background-color: gold;">Dangerous while working with branches!</span> |
|
||||
| cCFG_File<br/>or oCFG | filename | Indicates a CFG filename for not using the default on foxbin2prg directory or path.<br/>See [Configuration file(s)](./FoxBin2Prg_Settings.md) and [Multi config](./FoxBin2Prg_Settings.md#multi-configuration) for more information. |
|
||||
| | object | An object containing configuration options to use. See [Internals](./FoxBin2Prg_Internals.md) for object creation.<br/>If this is set, no additional configuration file will be read. |
|
||||
| cClearUniqueID | 0, _1_ | 0=Keep UniqueID in text files, 1=Clear Unique ID. Useful for Diff and Merge |
|
||||
| cOptimizeByFilestamp | _0_, 1 | 1=Optimize file regeneration depending on file timestamp.<br/><span style="background-color: gold;">Dangerous while working with branches!</span> |
|
||||
| cCFG_File | filename | Indicates a CFG filename for not using the default on foxbin2prg directory or path. |
|
||||
| | object | An object containing configuration options to use. See [Internals](./FoxBin2Prg_Internals.md) for object creation. |
|
||||
|
||||
#### cOutputFolder
|
||||
The procedural call of FoxBin2Prg like
|
||||
@@ -108,4 +105,4 @@ Return value is 0=OK, 1=Error.
|
||||
This project is part of [VFPX](https://vfpx.github.io/).
|
||||
|
||||
----
|
||||
Last changed: _2026/06/21_ 
|
||||
Last changed: _2023/11/26_ 
|
||||
@@ -16,13 +16,8 @@ As far as possible these are the original documents. Changes are added where fun
|
||||
- [PRG](#prg)
|
||||
- [Parameters](#parameters)
|
||||
- [Usage](#usage)
|
||||
- [Usage 1](#usage-1)
|
||||
- [Usage 2](#usage-2)
|
||||
- [Usage 3](#usage-3)
|
||||
- [Return values](#return-values)
|
||||
- [Examples](#Examples)
|
||||
- [Using the "EXE" version](#using-the-exe-version)
|
||||
- [Using the "PRG" version](#using-the-prg-version)
|
||||
- [Explorer SendTo](#explorer-sendto)
|
||||
|
||||
----
|
||||
@@ -33,23 +28,22 @@ Since the EXE is basically the prg packed with some controling files, the way to
|
||||
The knowledge of differences in calling, DO .. WITH syntax separating parameters with "," and the DOS way off calling will be assumed.
|
||||
Do the similarity of the call, the prg version takes all parameters as strings too.
|
||||
|
||||
For settings see [Configuration](./FoxBin2Prg_Settings.md), for API and other related stuff see [Internals](./FoxBin2Prg_Internals.md).
|
||||
For settings and other related stuff see [Internals](./FoxBin2Prg_Internals.md).
|
||||
|
||||
## Differences on excecution
|
||||
### EXE
|
||||
The exe contains the most controling structures and the program itself.
|
||||
Alongside the _FoxBin2Prg.exe_ must be _\_FileName\_Caps.exe_.
|
||||
It is recomended to have a general _FoxBin2Prg.cfg_ configuration file in the folder with the EXE, but it will run without.
|
||||
See [Configuration](./FoxBin2Prg_Settings.md) for information about settings.
|
||||
Alongside the _FoxBin2Prg.exe_ must be _\_FileName\_Caps.exe_ .
|
||||
It is recomended to have a general _FoxBin2Prg.cfg_ configuration file in the folder with the EXE, but it will run without.
|
||||
|
||||
Remember, the exe(s) needs to be created first, and they must be compiled with the version of VFP you use, for example VFPA.
|
||||
Remember, the Exe needs to be created first.
|
||||
|
||||
### PRG
|
||||
The prg is just the program and needs to find the controling structures. In particular:
|
||||
- _FileName_Caps.exe_
|
||||
- _Props*.txt_
|
||||
- _FileName_Caps.exe_
|
||||
- _FoxBin2Prg.cfg_ is recomended, see [Configuration](./FoxBin2Prg_Settings.md)
|
||||
- _FoxBin2Prg.cfg_ is recomended
|
||||
|
||||
#### Note
|
||||
All mentioned files need to be in the same folder. You can't use just the PRG without the rest of the mentioned files.
|
||||
@@ -67,13 +61,12 @@ Remember that using the prg style, parameters must be wrapped in string delimite
|
||||
#### Note
|
||||
Do to the compatibility with VSS the usage of _cInputFile_ and _cType_ is odd.
|
||||
|
||||
#### Important note
|
||||
#### Important note:
|
||||
When you process a directory, it is used as the base for the compilation of _Binaries_,
|
||||
and because of this, never process more than one directory in the same process,
|
||||
because the compilation may not be ok. To process more than one directory (or project),
|
||||
just select and process each one independently, in parallel if you like, but in different processes.
|
||||
|
||||
---
|
||||
## Usage
|
||||
### Usage 1
|
||||
`FoxBin2Prg.EXE cInputFile [,cType [,cTextName [,lGenText [,cDontShowErrors [,cDebug [,cDontShowProgress [,cOriginalFileName [,cRecompile [,cNoTimestamps [,cCFG_File [,cOutputFolder ] ] ] ] ] ] ] ] ] ] ] ]`
|
||||
@@ -93,14 +86,14 @@ just select and process each one independently, in parallel if you like, but in
|
||||
| | d, D, K, B, M, R, V | SCCAPI (SCCTEXT.PRG) compatibility mode, query the conversion support for the file type specified <br /> Types: d=DBC, D=DBF, K=Form, B=Label, M=Menu, R=Report, V=Class |
|
||||
| cTextName | Text filename. | Only for SCCAPI (SCCTEXT.PRG) compatibility mode. File to use. |
|
||||
| lGenText | .T., .F. | Only for SCCAPI (SCCTEXT.PRG) compatibility mode.<br/>.T.=Generates _Text_, .F.=Generates _Binary_.<br/>**Note:** _cType_ have predominance over _lGenText_ |
|
||||
| cDontShowErrors | _0_, 1 | '1' for NOT showing errors in MESSAGEBOX.<br/>This has Precedence Over The _Dontshowerrors_ setting. |
|
||||
| cDebug | _0_, 1, 2 | '0 'no debug, '1' for generating process LOGs, stop on errors, '2' like '1' and special log.<br/>This has precedence over any value in the config files.<br/>This has Precedence Over The _Debug_ setting. |
|
||||
| cDontShowProgress | 0, _1_, 2 | '0' show progress, '1' for **not** showing the process window, '2' Show only for multi-file processing<br/>This has Precedence Over The _ShowProgressbar_ setting. Value "0","1" is inverted to the setting. |
|
||||
| cDontShowErrors | _0_, 1 | '1' for NOT showing errors in MESSAGEBOX |
|
||||
| cDebug | _0_, 1, 2 | '0 'no debug, '1' for generating process LOGs, stop on errors, '2' like '1' and special log.<br/>This has precedence over any value in the config files. |
|
||||
| cDontShowProgress | 0, _1_, 2 | '0' show progress, '1' for **not** showing the process window, '2' Show only for multi-file processing |
|
||||
| cOriginalFileName | text | used in those cases in which inputFile is a temporary filename and you want to generate the correct filename on the header of the _Text_ version |
|
||||
| cRecompile | 0, _1_ | Indicates recompile ('1') the _Binary_ once generated. <br/> True if called from SCCAPI (SCCTEXT.PRG) compatibility mode. |
|
||||
| | path | The _Binary_ is compiled from this path |
|
||||
| cNoTimestamps | 0, _1_ | Indicates if timestamp must be cleared ('1' or empty) or not ('0').<br/>This has Precedence Over The _NoTimestamps_ setting. |
|
||||
| cCFG_File | filename | Indicates a special CFG filename for default values.<br/>Note, if the "regular" config files are used or not, is controlled by the setting *AllowInheritance* in *this** file.<br/>See [Configuration](./FoxBin2Prg_Settings.md) |
|
||||
| cNoTimestamps | 0, _1_ | Indicates if timestamp must be cleared ('1' or empty) or not ('0') |
|
||||
| cCFG_File | filename | Indicates a special CFG filename for default values.<br/>Note, if the "regular" config files are used or not, is controlled by the setting *AllowInheritance* in *this** file. |
|
||||
| cOutputFolder | folder | Optional. A folder to write the output to. If not used, output be the source path. |
|
||||
|
||||
#### Note #1
|
||||
@@ -116,17 +109,16 @@ The filename is an external variable parameter received when SendingTo FoxBin2Pr
|
||||
|
||||
### Usage 2
|
||||
`FoxBin2Prg.EXE c|C|t [OutFileName [ cCFG_File[ cDebug]]]`
|
||||
`DO FoxBin2Prg.EXE WITH -c|-C|-t [, cOutputFile [, cCFG_File[, cDebug]]]`
|
||||
`DO FoxBin2Prg.EXE WITH -c|-C|-t [, OutFileName [, cCFG_File[, cDebug]]]`
|
||||
|
||||
| Parameter | Description |
|
||||
| ----- | ----- |
|
||||
| none | Call Info screen |
|
||||
| -c (c) | creates a template config-file _cOutputFile_ ( like FOXBIN2PRG.CFG ) |
|
||||
| -C (C) | creates a config-file _cOutputFile_ ( like FOXBIN2PRG.CFG ) with the recent options used on the path of cOutputFile |
|
||||
| | If _cOutputFile_ is empty, a file FOXBIN2PRG.\_CFG will be created in default foder. |
|
||||
| | If cOutputFile is empty, a file FOXBIN2PRG.\_CFG will be created in default foder. |
|
||||
| -t (t) | creates a template table-config-file _cOutputFile_ ( like \_TableName\_.dbf.cfg ) |
|
||||
| cOutputFile | config file to create<br/>**Note: if empty it creates *and overwrite* FOXBIN2PRG.CFG or the table config file in default folder.** |
|
||||
| cCFG_File | Indicates a special *input* CFG filename for default values<br/> **Note, if the "regular" config files are used or not, is controlled by the setting *AllowInheritance* in *this* file.**<br/>See [Configuration](./FoxBin2Prg_Settings.md) |
|
||||
| cCFG_File | Indicates a special CFG filename for default values<br/>Note, if the "regular" config files are used orn not, is controlled by the setting *AllowInheritance* in *this** file. |
|
||||
| cDebug | '1' for generating process LOGs, stop on errors<br/>This has precedence over any value in the config files. |
|
||||
|
||||
### Usage 3
|
||||
@@ -140,7 +132,7 @@ The filename is an external variable parameter received when SendingTo FoxBin2Pr
|
||||
|
||||
|
||||
#### Note
|
||||
From MS Windows command line the call with paramters like -c, -C -t is not possible. Those parameters will be removed by VFP itself.
|
||||
From command line the call with paramters like -c, -C -t is not possible. Those parameters will be removed by VFP itself.
|
||||
Just call without the dash.
|
||||
Calling inside VFP with `DO FoxBin2Prg.EXE` works with this dashed parameters.
|
||||
|
||||
@@ -148,9 +140,7 @@ Calling inside VFP with `DO FoxBin2Prg.EXE` works with this dashed parameters.
|
||||
Return value via _ErrorLevel_ is 0=OK, 1=Error.
|
||||
|
||||
## Examples
|
||||
### Using the "EXE" version
|
||||
**Useful for calling from 3rd party programs.**
|
||||
Note, the EXE must be compiled to the VFP version you are using.
|
||||
### Using the "EXE" version: (useful for calling from 3rd party programs)
|
||||
|
||||
| command | description |
|
||||
| - | - |
|
||||
@@ -162,8 +152,7 @@ Note, the EXE must be compiled to the VFP version you are using.
|
||||
| `FOXBIN2PRG.EXE "<path>\file.vcx::cus_client"` | Generates only the _Text_ version of the individual class cus_client of file.vcx (with UseClassPerFile:1 or 2) |
|
||||
| `FOXBIN2PRG.EXE "<path>\proj.pj2" "*" \| find /V ""` | Generates the _Binary_ files for all the files in the PJ2 and outputs to stdOut |
|
||||
|
||||
### Using the "PRG" version
|
||||
**Useful for calling from in IDE, in special if several versions of VFP are active.**
|
||||
### Using the "PRG" version:
|
||||
|
||||
| command | description |
|
||||
| - | - |
|
||||
@@ -194,4 +183,4 @@ FoxBin2Prg.lnk <path>\foxbin2prg.exe "INTERACTIVE-SHOWMSG"
|
||||
This project is part of [VFPX](https://vfpx.github.io/).
|
||||
|
||||
----
|
||||
Last changed: _2026/06/21_ 
|
||||
Last changed: _2023/11/26_ 
|
||||
|
||||
@@ -69,11 +69,11 @@ how to configure and how to begin working with Visual FoxPro 9 projects using br
|
||||
If you already are using FoxBin2Prg with another SCM tool,
|
||||
feel free to share how you are using it so others can benefit.
|
||||
|
||||
- [See YouTube demo video of FoxBin2Prg used with PlasticSCM](http://youtu.be/sE4wQ50Itqg)
|
||||
- [Using FoxBin2Prg with PlasticSCM](Using-FoxBin2Prg-with-PlasticSCM)
|
||||
|
||||
----
|
||||

|
||||
This project is part of [VFPX](https://vfpx.github.io/).
|
||||
|
||||
----
|
||||
Last changed: _2026/06/17_ 
|
||||
Last changed: _2023/03/20_ 
|
||||
@@ -1,397 +0,0 @@
|
||||
# FoxBin2Prg Configuration
|
||||
Documentation of FoxBin2Prg - A Binary to Text converter for MS Visual Foxpro 9
|
||||
|
||||
## Purpose of this document
|
||||
This document shows the use of configuration files and the varius setrtings on FoxBin2Prg.
|
||||
|
||||
----
|
||||
## Table of contents
|
||||
- [Configuration file](#configuration-file)
|
||||
- [Multi config](#multi-configuration)
|
||||
- [Example](#example)
|
||||
- [Configuration file per table](#configuration-file-per-table)
|
||||
- [Excluding directories](#excluding-directories)
|
||||
|
||||
## Configuration file
|
||||
The configuration how to run FoxBin2Prg is stored in configuration files, FoxBin2Prg.cfg for general settings, and [Configuration file per table](#configuration-file-per-table).
|
||||
|
||||
It is possible to create a template or a config with all options and comments via
|
||||
```
|
||||
DO FOXBIN2PRG.PRG WITH "-c","template.cfg" &&==> Generates a template for FoxBin2Prg.cfg config file with newest settings
|
||||
DO FOXBIN2PRG.PRG WITH "-C","config.cfg" &&==> Generates a config file like FoxBin2Prg.cfg with recent settings of path of second parameter
|
||||
```
|
||||
|
||||
An example of a template is given in [Example](#example)
|
||||
See [command line](./FoxBin2Prg_Run.md#usage-2).
|
||||
The config file is used to move local setting to a different comupter or for changes while branching.
|
||||
|
||||
The options in the template (or in the config that ships with FoxBin2Prg) are commented out.
|
||||
To activate an option remove the asterix and set appropriate value.
|
||||
|
||||
There is a [Multi config](#multi-configuration), that allows to have global settings with specific local settings.
|
||||
If a setting does not follow inheritance, it is mentioned in the table below.
|
||||
|
||||
These are the FoxBin2Prg.cfg configuration file settings and their meaning.
|
||||
The second line in the keyword column is the name of the respective property (if there is one)
|
||||
in the settings object returned by get_DirSettings method of the API object. See [PEM](./FoxBin2Prg_Internals.md#pem).
|
||||
|
||||
| FoxBin2Prg.cfg keywords<br/>Property of settings object | Value (_Default_) | Description |
|
||||
| ----- | ----- | ----- |
|
||||
| Language | _(auto)_,<br/>EN, FR, ES, DE | Language of templates, shown messages and LOGs. EN=English, FR=French, ES=Espa<70>ol, DE=German, Not defined = AUTOMATIC (using VERSION(3)) ||
|
||||
| DontShowProgress<br/>n_ShowProgressbar | 0 | **Deprecated**. Replaced by ShowProgressbar option from v1.19.40, see below.<br/>The values of 0 and 1 are inverted to ShowProgressbar. |
|
||||
| ShowProgressbar<br/>n_ShowProgressbar | 0, _1_, 2 | 0=Don't show progressbar,<br/>1=Always show a progress bar,<br/>2=Only show it when processing multiple-files.<br/>**If set via parameter _cDontShowProgress_, this is ignored.<br/>_cDontShowProgress_ has value "0","1" inverted to the property.** |
|
||||
| DontShowErrors<br/>n/a | _0_, 1 | 0=show message errors in a modal messagebox. (default)<br/>1=don't show errors<br/>**If set via parameter _cDontShowErrors_, this is ignored.**<br/>**There is no inheritance for this setting. First occurance wins.** |
|
||||
| ExtraBackupLevels<br/>n/a | 0, _1_, n | <br/>0=No backup<br/>1=One backupfile _\_filename\_.BAK_ (default)<br/>n=n levels of backup in style _\_filename\_.n.BAK_<br/>**There is no inheritance for this setting. First occurance wins.** |
|
||||
| Debug<br/>n_Debug | _0_, 1, 2 | 0=Off<br/>1=Normal<br/>2=Extended<br/>By default, don't generate individual \<file\>.Log with process hints.<br/>Activate with "1" to find possible error causes and for debugging,<br/>"2" is special logging.<br/>**If set via parameter _cDebug_, this is ignored.** |
|
||||
| BackgroundImage<br/>c_BackgroundImage | \<cFile\> | Backgroundimage for process form |
|
||||
| HomeDir<br/>n_HomeDir | 0, _1_ | 0=don't save HomeDir in PJ2,<br/>1=save HomeDir in PJ2.<br/>Setting this to 0 prevents the PJ2 file from changing just because two developers have the project in different folders |
|
||||
| BodyDevInfo<br/>n_BodyDevInfo | _0_, 1, 2 | 0=Don't keep DevInfo for body pjx records, 1=Keep DevInfo, 2 = Don't keep DevInfo or ObjRev.<br/>Setting this to 2 prevents the PJ2 file from changing just because two developers built the project on their machines |
|
||||
|||
|
||||
| InhibitInheritance<br/>n_InhibitInheritance | _0_, 1, 2, 3 | **This settings is for config file via parameter only**. See [Multi config](#multi-configuration).<br/>Settings for config file via parameter only0=Allow scanning "regular" config files (file via parameter is just additional default)<br/>1=Only read tree from root of the file given by parameter, not FoxBin2Prg default<br/>2=Only read folder and subfolder of the file given by parameter<br/>3=Read no other file<br/>This is like<br/>0 Default \| Parameter file \| Default near FoxBin2Prg \| all other config files<br/>1 Default \| Parameter file \| Inheritance from root to parent of folder \| folder and subdirs<br/>2 Default \| Parameter file \| folder and subdirs<br/>3 Default \| Parameter file |
|
||||
|||
|
||||
| XXX_Conversion_Support | n | Defines the conversion operation per filetype |
|
||||
| | | For code:<br/> 0=No support,<br/>1=Generate _Text_ (Diff),<br/>2=Generate _Text_ and _Bin_ (Merge) |
|
||||
| | | For complex data:<br/> (PJX / DBC / DBF): 0=No support,<br/>1=Generate Header _Text_ only (Diff),<br/>2=Generate Header _Text_ and _Bin_ (Merge/Only Structure!),<br/>4=Generate _Text_ with DATA (Diff),<br/>8=Export and Import DATA (Merge/Structure & Data) |
|
||||
| PJX_Conversion_Support<br/>.n_PJX_Conversion_Support | 0, 1, _2_ | Default value is 2 - Bidirectional ((Merge/Only Structure!),<br/>4=Generate _Text_ with DATA (Diff), 8=Export and Import DATA (Merge/Structure & Data) and _bin_) support activated |
|
||||
| VCX_Conversion_Support<br/>.n_VCX_Conversion_Support | 0, 1, _2_ | Default value is 2 - Bidirectional (_Text_ and _bin_) support activated |
|
||||
| SCX_Conversion_Support<br/>.n_SCX_Conversion_Support | 0, 1, _2_ | Default value is 2 - Bidirectional (_Text_ and _bin_) support activated |
|
||||
| FRX_Conversion_Support<br/>.n_FRX_Conversion_Support | 0, 1, _2_ | Default value is 2 - Bidirectional (_Text_ and _bin_) support activated |
|
||||
| LBX_Conversion_Support<br/>.n_LBX_Conversion_Support | 0, 1, _2_ | Default value is 2 - Bidirectional (_Text_ and _bin_) support activated |
|
||||
| MNX_Conversion_Support<br/>.n_MNX_Conversion_Support | 0, 1, _2_ | Default value is 2 - Bidirectional (_Text_ and _bin_) support activated |
|
||||
| DBC_Conversion_Support<br/>.n_DBC_Conversion_Support | 0, 1, _2_ | Default value is 2 - Bidirectional (_Text_ and _bin_) support activated |
|
||||
| DBF_Conversion_Support<br/>.n_DBF_Conversion_Support | 0, _1_, 2, 4, 8 | Default value is 1 - just _Text_ support activated.<br/>The support for regenerating DBFs structures (value = 2) are disabled by default to not overrite data accidentally. When activating bidirectional support, keep in mind that Data is not restored, just the structure and indexes!.<br/>A value of 4 is used to export Structure and Data, but exported data is not imported again.<br/>A value of 8 is used for bidirectional support (No General fields!). <br/> **Note:** This can be [changed per table](#configuration-file-per-table). |
|
||||
| FKY_Conversion_Support<br/>.n_FKY_Conversion_Support | 0, _1_ | Default value is 1 - _Text_ support activated |
|
||||
| MEM_Conversion_Support<br/>.n_MEM_Conversion_Support | 0, _1_ | Default value is 1 - _Text_ support activated |
|
||||
|||
|
||||
| CheckFileInPath<br/>n_CheckFileInPath | _0_, 1, 2, 3 |Determines how 2Txt deals with files not in the subfolders of the PJX. No handler for UNC paths.<br />0 = Ignore. Default<br />1 = Check and error out if file is not on same structure (for source control)<br />2 = Create absolute path if file is on different drive.<br />3 = Create absolute path if file is not in structure<br />See [Storing paths for pjx](./FoxBin2Prg_Internals.md#storing-paths-for-pjx) |
|
||||
|||
|
||||
| UseClassPerFile<br/>n_UseClassPerFile | _0_, 1, 2 | 0=One library _Text_ file,<br/>1=Multiple file.class.vc2 files,<br/>2=Multiple file.baseclass.class.vc2 files<br/>See [Create Class-Per-File](./FoxBin2Prg_Internals.md#create-class-per-file) |
|
||||
| [RedirectClassPerFileToMain:](./FoxBin2Prg_Internals.md#redirectclassperfiletomain:)<br/>l_RedirectClassPerFileToMain | _0_, 1 | 0=Don't redirect to file.vcx,<br/>1=Redirect to file.vcx when selecting file.class.vc2<br/>RedirectClassType: 1 precedes this setting |
|
||||
| RedirectClassType<br/>n_RedirectClassType | _0_, 1, 2 | For classes created with UseClassPerFile>0 in the form file[.baseclass].class.tx2 (vcx only) |
|
||||
| | | 0=creates / refresh class in file.VCX and add / replace all other classes of this library |
|
||||
| | | 1=creates / refresh class file[.baseclass].class.VCX and do not touch file.VCX |
|
||||
| | | 2=creates / refresh class in file.VCX and do not touch other classes of file.VCX |
|
||||
| [ClassPerFileCheck](./FoxBin2Prg_Internals.md#classperfilecheck)<br/>l_ClassPerFileCheck | _0_, 1 | 0=Don't check file.class.vc2 inclusion,<br/>1=Check file.class.vc2 inclusion<br/>Only used if import file is in file[.baseclass].class.tx2 syntax.<br/>Ignored for RedirectClassType: 2 |
|
||||
|||
|
||||
| [UseFormSettings](./FoxBin2Prg_Internals.md#create-file-per-form)<br/>l_UseFormSettings | _0_, 1 | 0=Old Style, like the class settings<br/>1=Form style, special for form<br/>This controls the use of the _UseFormPerFile_, _RedirectFormPerFileToMain_, _RedirectFormType_ and _FormPerFileCheck_ options.<br/>Only if this option is set, the options will be read. |
|
||||
| UseFormPerFile<br/>n_UseFormPerFile | _0_, 1, 2 | 0=One library _Text_ file,<br/>1=Multiple Form.Object.sc2 files,<br/>2=Multiple Form.baseclass.Object.sc2 files<br/>See [Create Class-Per-File](./FoxBin2Prg_Internals.md#create-class-per-file) |
|
||||
| [RedirectFormPerFileToMain](./FoxBin2Prg_Internals.md#redirectclassperfiletomain)<br/>l_RedirectFormPerFileToMain | _0_, 1 | 0=Don't redirect to Form.scx,<br/>1=Redirect to Form.scx when selecting Form.Object.sc2<br/>RedirectClassType: 1 precedes this setting |
|
||||
| RedirectFormType<br/>n_RedirectFormType | _0_, 1, 2 | For classes created with UseClassPerFile>0 in the form Form[.baseclass].Object.sx2 (scx only) |
|
||||
| | | 0=creates / refresh class in Form.SCX and add / replace all other classes of this library |
|
||||
| | | 1=creates / refresh class Form[.baseclass].Object.SCX and do not touch Form.SCX |
|
||||
| | | 2=creates / refresh class in Form.SCX and do not touch other classes of Form.SCX |
|
||||
| [FormPerFileCheck](./FoxBin2Prg_Internals.md#classperfilecheck)<br/>l_FormPerFileCheck | _0_, 1 | 0=Don't check Form.Object.sc2 inclusion,<br/>1=Check Form.Object.sc2 inclusion<br/>Only used if import file is in Form[.baseclass].Object.sc2 syntax.<br/>Ignored for RedirectClassType: 2 |
|
||||
|||
|
||||
| OldFilesPerDBC<br/>l_OldFilesPerDBC | _0_, 1 | 0=Old Style,<br/>1=New style<br/>This controls the use of the _UseFilesPerDBC_, _RedirectFilePerDBCToMain_ and _ItemPerDBCCheck_ options.<br/>Only if this option is set, the **Form** options below will be read. |
|
||||
| | | 0=New version inactive, options follow:<br/>UseFilesPerDBC=UseClassPerFile<br/>RedirectFilePerDBCToMain=RedirectClassPerFileToMain<br/>ItemPerDBCCheck=ClassPerFileCheck |
|
||||
| | | 1=New version active, options active |
|
||||
| | | Note: The options will be set to old style, if option is turned off. |
|
||||
| UseFilesPerDBC<br/>n_UseFilesPerDBC | _0_, 1 | 0=One database dc2 file,<br/>1=Multiple file.\*.\*.dc2 files.<br/>See [Create File-Per-DBC](./FoxBin2Prg_Internals.md#create file-per-dbc)<br/>**Only if OldFilesPerDBC is 1** |
|
||||
| | | 0=creates only a file.dc2 with all DBC (file) data |
|
||||
| | | 1=creates a file.dc2 with DBC properties |
|
||||
| | | and additional DBC files per DBC item (stored-proc, table, ..) |
|
||||
| | | Note: recration only if RedirectFilePerDBCToMain is 1 |
|
||||
| [RedirectFilePerDBCToMain](./FoxBin2Prg_Internals.md#redirectfileperdbctomain)<br/>l_RedirectFilePerDBCToMain | _0_, 1 | 0=Don't redirect to file.dc2,<br/>1=Redirect to file.tx2 when selecting file.item.*.dc2<br/>**Only if OldFilesPerDBC is 1** |
|
||||
| [ItemPerDBCCheck](./FoxBin2Prg_Internals.md#itemperdbccheck)<br/>l_ItemPerDBCCheck | _0_, 1 | 0=Don't check file.item.*.dc2 inclusion,<br/> 1=Check file.item.*.dc2 inclusion<br/>**Only if OldFilesPerDBC is 1**|
|
||||
|||
|
||||
| NoTimestamps<br/>n/a | 0, _1_ | 0=Do not clear<br/>1=Clear<br/>By default, timestamp fields are cleared on _Text_ files, because a lot of differencies are generated on _Binaries_ and _Text_ files with Timestamps activated. This timestamp field is part of the vcx, scx and other Foxpro binary source code files.<br/>**If set via parameter _cNoTimestamps_, this is ignored.**<br/>**There is no inheritance for this setting. First occurance wins.** |
|
||||
| ClearUniqueID<br/>n/a | 0, _1_ | 0=Keep UniqueID,<br/>1=Clear Unique ID.<br/>Very useful for Diff and Merge.<br/>By default, UniqueID fields are cleared on _Text_ files, because a lot of differencies are generated with UniqueID activated.<br/>**If set via parameter _cClearUniqueID_, this is ignored.**<br/>**There is no inheritance for this setting. First occurance wins.** |
|
||||
| OptimizeByFilestamp<br/>n/a | _0_, 1 | 0=Don't optimize (always generate),<br/>1=Optimize (generate only when destination filestamp es older). By default this optimization is deactivated, and it is not recommended if using for merge, so _Bin_ and _Text_ files can be modified seperately.<br/><span style="background-color: gold;">Dangerous while working with branches!</span>.<br/>**If set via parameter _cOptimizeByFilestamp_, this is ignored.**<br/>**There is no inheritance for this setting. First occurance wins.** |
|
||||
| RemoveNullCharsFromCode<br/>l_RemoveNullCharsFromCode | 0, _1_ | 1=Drop NULL chars from source code,<br/>0=Leave NULL chars in source code |
|
||||
| RemoveZOrderSetFromProps<br/>l_RemoveZOrderSetFromProps | _0_, 1 | 1=Remove ZOrderSet from the properties,<br/>0=Leave ZOrderSet in the properties |
|
||||
|||
|
||||
| PRG_Compat_Level<br/>n_PRG_Compat_Level | _0_, 1 | 0=Legacy,<br/>1=Use HELPSTRING as Class Procedure comment. |
|
||||
| ClearDBFLastUpdate<br/>l_ClearDBFLastUpdate | 0, _1_ | 0=Keep DBF LastUpdate,<br/>1=Clear DBF LastUpdate.<br/>Useful for Diff, minimizes differences. |
|
||||
| ExcludeDBFAutoincNextval<br/>n_ExcludeDBFAutoincNextval | _0_, 1 | 0=Do not exclude this value from db2,<br/>1=Exclude this value from db2 |
|
||||
| DBF_Conversion_Included<br/>c_DBF_Conversion_Included | * | If DBF_Conversion_Support:4, you can specify multiple filemasks: www,fb2p_free.dbf.<br/>See [Order and range of records](./FoxBin2Prg_Internals.md#order-and-range-of-records).<br/>**Note:** This can be [changed per table](./FoxBin2Prg_Internals.md#configuration-file-per-table). |
|
||||
| DBF_Conversion_Excluded<br/>c_DBF_Conversion_Excluded | | If DBF_Conversion_Support:4, you can specify multiple filemasks: www,fb2p_free.dbf.<br/>See [Order and range of records](./FoxBin2Prg_Internals.md#order-and-range-of-records).<br/>**Note:** This can be [changed per table](./FoxBin2Prg_Internals.md#configuration-file-per-table). |
|
||||
| DBF_BinChar_Base64<br/>l_DBF_BinChar_Base64 | 0, _1_ | 0=For character type fields, if NoCPTrans 0=do not transform,<br/>1=use Base64 transform (default)<br/>**Note:** This can be [changed per table](./FoxBin2Prg_Internals.md#configuration-file-per-table). |
|
||||
| DBF_IncludeDeleted<br/>l_DBF_IncludeDeleted | _0_, 1 | 0=Do not include deleted records (default),<br/>1=Include deleted records<br/>**Note:** This can be [changed per table](./FoxBin2Prg_Internals.md#configuration-file-per-table). |
|
||||
| | | **Note:**<br/>This is only true for tables. Generating DBC to _Text_ and back to _Binary_ will act as PACK DATABASE.<br/>The data added by _DBF_IncludeDeleted: 1_ will be ignored by old versions generating _Binary_ files. |
|
||||
|||
|
||||
| extension: xx2 | | FoxBin2Prg extensions ends in '2' (pj2, vc2, sc2, etc), but you can change that. |
|
||||
| extension: pj2=<br/>c_pj2 | \<extension\> | Extension for text file representing project PJX |
|
||||
| extension: vc2=<br/>c_vc2 | \<extension\> | Extension for text file representing classlibray VCX, or a class out of a VCX |
|
||||
| extension: sc2=<br/>c_sc2 | \<extension\> | Extension for text file representing form SCX, or a class out of a SCX (Form; Dataenbironment) |
|
||||
| extension: fr2=<br/>c_fr2 | \<extension\> | Extension for text file representing report FRX |
|
||||
| extension: lb2=<br/>c_lb2 | \<extension\> | Extension for text file representing label LBX |
|
||||
| extension: mn2=<br/>c_mn2 | \<extension\> | Extension for text file representing menu MNX |
|
||||
| extension: db2=<br/>c_db2 | \<extension\> | Extension for text file representing table DBF, free or DBC bound |
|
||||
| extension: dc2=<br/>c_dc2 | \<extension\> | Extension for text file representing database container DBC, or records from database container DBC |
|
||||
| extension: fk2=<br/>c_fk2 | \<extension\> | Extension for text file representing macro file FKY |
|
||||
| extension: me2=<br/>c_me2 | \<extension\> | Extension for text file representing variable memory MEM, created with SAVE TO |
|
||||
| | | **Example for for making it SourceSafe (sccapi v1) compatible:**<br/>extension: pj2=pja<br/>extension: vc2=vca<br/>extension: sc2=sca<br/>extension: fr2=fra<br/>extension: lb2=lba<br/>extension: mn2=mna<br/>extension: db2=dba<br/>extension: dc2=dca |
|
||||
|
||||
### Note
|
||||
The options will be read outside in, top to down. See [Multi config](#multi-configuration)
|
||||
|
||||
#### Multi configuration
|
||||
Starting at version v1.19.25 FoxBin2Prg allow configuration per directory,
|
||||
overriding the main configuration of FoxBin2Prg directory.
|
||||
The override is by each setting, so you can reconfigure one or more settings and the
|
||||
remaining settings are inherited from main CFG.
|
||||
|
||||
From v1.19.42 CFGs are inherited between directories from parent to child,
|
||||
so if you have all your developments under, let's say, "c:\devs" directory and subdirs,
|
||||
de CFG in "c:\devs" will be inherited on subdirs, and settings can be overriden one by one if you want to.
|
||||
This inheritance saves a lot of time and minimizes the CFGs needed \:\)
|
||||
|
||||
The order is:
|
||||
1. An optional configuration file given by the parameters [program / executable](./FoxBin2Prg_Run.md#usage-1) or [API, Execute method](./FoxBin2Prg_Object.md#execute)
|
||||
2. An optional default configuration file next to the prg/exe
|
||||
3. Any configuration file drive root up to current folder
|
||||
3. Folder and subfolder of current folder. *This is, if called for a pjx, not only the pjx folder, any subfolder could have configuration file, valid for the files of this subfolder and it's subfolders.*
|
||||
|
||||
If the _optional configuration file given by the parameter_ sets `InhibitInheritance` on a different value the 0, the chain of inheritance will be different, see above.
|
||||
|
||||
##### Note
|
||||
Options will be read outside in, top to down.
|
||||
If an option is defined multiple times, even in the same file, last occurance wins. There are some exceptions, see below.
|
||||
|
||||
A different exception are the group controlling the new style to split DBC files and the one for forms.
|
||||
The options _UseFilesPerDBC_, _RedirectFilePerDBCToMain_ and _ItemPerDBCCheck_ will be ignored for DBC,
|
||||
if _OldFilesPerDBC_ is set to 0.
|
||||
Setting _OldFilesPerDBC_ to 1 will inhertit the values from the \*class\* options.
|
||||
If _OldFilesPerDBC_ is set to 0 after it was active, the values of the three options are rejected at all and reset to the corresponding \*class\* values.
|
||||
For Forms, options _UseFormPerFile_, _RedirectFormPerFileToMain_, _RedirectFormType_ and _FormPerFileCheck_ will be ignored,
|
||||
if _UseFormSettings_ is set to 0.
|
||||
Setting _UseFormSettings_ to 1 will inhertit the values from the \*class\* options.
|
||||
If _UseFormSettings_ is set to 0 after it was active, the values of the four options are rejected at all and reset to the corresponding \*class\* values.
|
||||
|
||||
### Example
|
||||
This is a template of a configuration file as created with
|
||||
```
|
||||
DO FOXBIN2PRG.PRG WITH "-c","template.cfg" &&==> Generates a template for FoxBin2Prg.cfg config file with newest settings
|
||||
```
|
||||
|
||||
```
|
||||
*################################################################################################################
|
||||
*FOXBIN2PRG.CFG configuration options: (If no values given, these are the DEFAULTS)
|
||||
*Version: v1.21.05
|
||||
*****************************************************************************************************************
|
||||
|
||||
* Note, configuration files will follow an inheritance.
|
||||
* 1. Default values
|
||||
* 2., optional FOXBIN2PRG.CFG in folder of FOXBIN2PRG.EXE
|
||||
* or, if defined, a config file given by a parameter calling FOXBIN2PRG
|
||||
* if used, the InhibitInheritance setting controls if other config files will be evaluated (default). See below.
|
||||
* 3., optional FOXBIN2PRG.CFG in root of working directory
|
||||
* 4., optional FOXBIN2PRG.CFG in every folder up to the working directory
|
||||
* 5., optional Special settings per single DBF's (Syntax: <TableName>.dbf.cfg in tables folder)
|
||||
|
||||
* Some Parameter calling FOXBIN2PRG.EXE overturn this settings (except Defaults)
|
||||
*****************************************************************************************************************
|
||||
|
||||
*-- Settings for internal work, not processing
|
||||
*Language: (auto) && Language of shown messages and LOGs. EN=English, FR=French, ES=Espa<70>ol, DE=German, Not defined = AUTOMATIC [DEFAULT]
|
||||
*ShowProgressbar: 1 && 0=Don't show, 1=Allways show, 2=Show only for multi-file processing
|
||||
* && Note: This setting will be ignored, if cDontShowProgress parameter is set.
|
||||
*DontShowErrors: 0 && Show message errors by default
|
||||
* && Note: This setting will be ignored, if cDontShowError parameter is set.
|
||||
* && Note: There is no inheritance for this setting. First occurance wins.
|
||||
*ExtraBackupLevels: 1 && By default 1 BAK is created. With this you can make more .N.BAK, or none
|
||||
* && Note: There is no inheritance for this setting. First occurance wins.
|
||||
*Debug: 0 && 0=Don't Activate individual <file>.Log by default
|
||||
* && 1=Activate individual <file>.Log by default
|
||||
* && 2=???
|
||||
* && Only valid if not controlled by parameter cDebug
|
||||
*BackgroundImage: <cFile> && Backgroundimage for process form. Empty for empty Background. File not found uses default.
|
||||
*HomeDir: 1 && Home directory in PJX
|
||||
* && 0 don't save HomeDir in PJ2
|
||||
* && 1 save HomeDir in PJ2
|
||||
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*-- Settings for config file via parameter only
|
||||
*InhibitInheritance: 0 && 0=Allow scanning "regular" config files (file via parameter is just additional default)
|
||||
* && 1=Only read tree from root of the file given by parameter, not FoxBin2Prg default
|
||||
* && 2=Only read folder and subfolder of the file given by parameter
|
||||
* && 3=Read no other file
|
||||
* && This is like
|
||||
* && 0 Default | Parameter file | Default near FoxBin2Prg | all other config files
|
||||
* && 1 Default | Parameter file | Inheritance from root to parent of folder | folder and subdirs
|
||||
* && 2 Default | Parameter file | folder and subdirs
|
||||
* && 3 Default | Parameter file
|
||||
*----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
*-- Conversion operation by type
|
||||
*PJX_Conversion_Support: 2 && 0=No support, 1=Generate TXT only (Diff), 2=Generate TXT and BIN (Merge)
|
||||
*VCX_Conversion_Support: 2 && 0=No support, 1=Generate TXT only (Diff), 2=Generate TXT and BIN (Merge)
|
||||
*SCX_Conversion_Support: 2 && 0=No support, 1=Generate TXT only (Diff), 2=Generate TXT and BIN (Merge)
|
||||
*FRX_Conversion_Support: 2 && 0=No support, 1=Generate TXT only (Diff), 2=Generate TXT and BIN (Merge)
|
||||
*LBX_Conversion_Support: 2 && 0=No support, 1=Generate TXT only (Diff), 2=Generate TXT and BIN (Merge)
|
||||
*MNX_Conversion_Support: 2 && 0=No support, 1=Generate TXT only (Diff), 2=Generate TXT and BIN (Merge)
|
||||
*DBC_Conversion_Support: 2 && 0=No support, 1=Generate TXT only (Diff), 2=Generate TXT and BIN (Merge)
|
||||
*DBF_Conversion_Support: 1 && 0=No support, 1=Generate Header TXT only (Diff), 2=Generate Header TXT and BIN (Merge/Only Structure!), 4=Generate TXT with DATA (Diff), 8=Export and Import DATA (Merge/Structure & Data)
|
||||
*FKY_Conversion_Support: 1 && 0=No support, 1=Generate TXT only (Diff)
|
||||
*MEM_Conversion_Support: 1 && 0=No support, 1=Generate TXT only (Diff)
|
||||
*----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
*Setting for pjx files
|
||||
*CheckFileInPath: 0 && Determines 2Txt deals with files not in the subfolders of the PJX. No handler for UNC paths.
|
||||
* && 0 Ignore. Default
|
||||
* && 1 Check and error out if file is not on same structure (for source control)
|
||||
* && 2 Create absolute path if file is on different drive.
|
||||
* && 3 Create absolute path if file is not in structure
|
||||
*----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
*Setting for container files (not pjx)
|
||||
*-- CLASS (, FORM and DBC) options (tx2 is to read as vc2 or sc2, VCX might be SCX)
|
||||
*-- FORM and DBC options default to this settings, if not set otherwise. See below.
|
||||
*- Class per file options (UseClassPerFile: 1)
|
||||
*UseClassPerFile: 0 && Determines how a library (or form) will handle included class (or, for forms, objects)
|
||||
* && 0 One library.tx2 file
|
||||
* && 1 Multiple file.class.tx2 files
|
||||
* && 2 Multiple file.baseclass.class.tx2 files
|
||||
*RedirectClassPerFileToMain: 0 && When regenerating binary files, determine target file
|
||||
* && 0 Don't redirect to file.vcx/scx
|
||||
* && 1 Redirect to file.vcx/scx when selecting file[.baseclass].class.tx2
|
||||
* && RedirectClassType: 1 has precedence
|
||||
*RedirectClassType: 0 && For classes created with UseClassPerFile>0 in the form file[.baseclass].class.tx2
|
||||
* && Those files could be imported like file.tx2::Class::import or like file[.baseclass].class.tx2
|
||||
* && For the second form:
|
||||
* && 0 Redirect file[.baseclass].class.tx2 to file.VCX and add / replace all other classes of this library
|
||||
* && 1 Redirect file[.baseclass].class.tx2 to file[.baseclass].class.VCX and do not touch file.VCX
|
||||
* && 2 Redirect file[.baseclass].class.tx2 to file.VCX and do not touch other classes of file.VCX
|
||||
*ClassPerFileCheck: 0 && Check, if files listed in the main file of a library or form will be included
|
||||
* && 0 Don't check file inclusion
|
||||
* && 1 Check file[.baseclass].class.tx2 inclusion
|
||||
* && Only used if import file is in file[.baseclass].class.tx2 syntax
|
||||
* && Ignored for RedirectClassType: 2
|
||||
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
*-- FORM options
|
||||
*- Form per file options (UseFormSettings: 1)
|
||||
*UseFormSettings: 0 && 1=Turns the File per SCX options on, 0 uses the old UseClassPerFile etc settings.
|
||||
* && Options below will only read if UseFormSettings is set 1 before!
|
||||
* && If UseFormSettings is set 0 later, all setting will be lost
|
||||
*UseFormPerFile: 0 && Determines how a form will handle included objects
|
||||
* && 0 One Form.sc2 file
|
||||
* && 1 Multiple Form.Obj.sc2 files
|
||||
* && 2 Multiple Form.baseclass.Obj.sc2 files
|
||||
*RedirectFormPerFileToMain: 0 && When regenerating binary files, determine target file
|
||||
* && 0 Don't redirect to Form.scx
|
||||
* && 1 Redirect to Form.scx when selecting Form[.baseclass].Obj.sc2
|
||||
* && RedirectFormType: 1 has precedence
|
||||
*RedirectFormType: 0 && For classes created with UseFormPerFile>0 in the form Form[.baseclass].Obj.sc2
|
||||
* && Those files could be imported like Form.sc2::Class::import or like Form[.baseclass].Obj.sc2
|
||||
* && For the second form:
|
||||
* && 0 Redirect Form[.baseclass].Obj.sc2 to Form.SCX and add / replace all other classes of this library
|
||||
* && 1 Redirect Form[.baseclass].Obj.sc2 to Form[.baseclass].Obj.SCX and do not touch Form.SCX
|
||||
* && 2 Redirect Form[.baseclass].Obj.sc2 to Form.SCX and do not touch other classes of Form.SCX
|
||||
*FormPerFileCheck: 0 && Check, if files listed in the main file of a library or form will be included
|
||||
* && 0 Don't check file inclusion
|
||||
* && 1 Check Form[.baseclass].Obj.sc2 inclusion
|
||||
* && Only used if import file is in Form[.baseclass].Obj.sc2 syntax
|
||||
* && Ignored for RedirectFormType: 2
|
||||
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
*-- DBC options
|
||||
*- File per DBC options (UseFilesPerDBC: 1)
|
||||
*OldFilesPerDBC: 0 && 1=Turns the File per DBC options on, 0 uses the old UseClassPerFile etc settings.
|
||||
* && Options below will only read if OldFilesPerDBC is set 1 before!
|
||||
* && If OldFilesPerDBC is set 0 later, all setting will be lost
|
||||
*UseFilesPerDBC: 0 && 0=One database dc2 file, 1=Multiple file.*.*.dc2 files
|
||||
* && 0 creates only a file.dc2 with all DBC (file) data
|
||||
* && 1 creates a file.dc2 with DBC properties
|
||||
* && and additional DBC files per DBC item (stored-proc, table, ..)
|
||||
* && Note: recration only if RedirectFilePerDBCToMain is 1
|
||||
*RedirectFilePerDBCToMain: 0 && 0=Don't redirect to file.dc2, 1=Redirect to file.tx2 when selecting file.item.*.dc2
|
||||
*ItemPerDBCCheck: 0 && 0=Don't check file.item.*.dc2 inclusion, 1=Check file.item.*.dc2 inclusion
|
||||
*----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
*-- General files
|
||||
*NoTimestamps: 1 && Clear timestamps of several file types by default for minimize text-file differences
|
||||
* && Note: This setting will be ignored, if cNoTimestamps parameter is set.
|
||||
* && Note: There is no inheritance for this setting. First occurance wins.
|
||||
*ClearUniqueID: 1 && 0=Keep UniqueID in text files, 1=Clear Unique ID. Useful for Diff and Merge
|
||||
* && Note: There is no inheritance for this setting. First occurance wins.
|
||||
*OptimizeByFilestamp: 0 && 1=Optimize file regeneration depending on file timestamp. Dangerous while working with branches!
|
||||
* && Note: There is no inheritance for this setting. First occurance wins.
|
||||
*RemoveNullCharsFromCode: 1 && 1=Drop .Null. chars from source code
|
||||
*RemoveZOrderSetFromProps: 0 && 0=Do not remove ZOrderSet property from object, 1=Remove ZOrderSet property from object
|
||||
*PRG_Compat_Level: 0 && 0=Legacy, 1=Use HELPSTRING as Class Procedure comment
|
||||
*----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
*-- PJX special
|
||||
*BodyDevInfo: 0 && 0=Don't keep DevInfo for body pjx records, 1=Keep DevInfo, 2 = Don't keep DevInfo or ObjRev
|
||||
*----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
*-- DBF special
|
||||
*ClearDBFLastUpdate: 1 && 0=Keep DBF LastUpdate, 1=Clear DBF LastUpdate. Useful for Diff.
|
||||
*ExcludeDBFAutoincNextval: 0 && 0=Do not exclude this value from db2, 1=Exclude this value from db2
|
||||
*DBF_Conversion_Included: * && If DBF_Conversion_Support:4, you can specify multiple filemasks: www,fb2p_free.dbf
|
||||
*DBF_Conversion_Excluded: && If DBF_Conversion_Support:4, you can specify multiple filemasks: www,fb2p_free.dbf
|
||||
*DBF_BinChar_Base64: 1 && For character type fields, if NoCPTrans 0=do not transform, 1=use Base64 transform (default)
|
||||
*DBF_IncludeDeleted: 0 && 0=Do not include deleted records (default), 1=Include deleted records
|
||||
*----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
*-- Text file extensions
|
||||
*extension: tx2=newext && Specify extensions to use. Default FoxBin2Prg extensions ends in '2' (see at the bottom)
|
||||
*-- Example configuration for SourceSafe compatibility:
|
||||
*extension: pj2=pja && Text file to PJX
|
||||
*extension: vc2=vca && Text file to VCX
|
||||
*extension: sc2=sca && Text file to SCX
|
||||
*extension: fr2=fra && Text file to FRX
|
||||
*extension: lb2=lba && Text file to LBX
|
||||
*extension: mn2=mna && Text file to MNX
|
||||
*extension: db2=dba && Text file to DBF
|
||||
*extension: dc2=dca && Text file to DBC
|
||||
*-- Additional extensions
|
||||
*extension: fk2=fkx && Text file to FKY
|
||||
*extension: me2=fkx && Text file to MEM
|
||||
*
|
||||
```
|
||||
|
||||
## Configuration file per table
|
||||
Those configuration files are valid for a single table only. The idea is to have special settings for single tables.
|
||||
|
||||
It is possible to create a template with all options and comments via
|
||||
```
|
||||
DO FOXBIN2PRG.PRG WITH "-t","template.dbf.cfg" &&==> Generates a template for table.dbf.cfg per table config file with newest settings.
|
||||
```
|
||||
|
||||
See [command line](./FoxBin2Prg_Run.md#usage-2).
|
||||
The options in the template (or in the config that ships with FoxBin2Prg) are commented out.
|
||||
To activate an option remove the asterix and set appropriate value.
|
||||
These are the Table.dbf.cfg configuration file settings and their meaning:
|
||||
|
||||
| FoxBin2Prg.cfg keywords | Value | per<br/>file | Description |
|
||||
| ----- | ----- | ----- | ----- |
|
||||
| DBF_Conversion_Support | 0, 1, 2, 4, 8 | | 0=No support,<br/>1=Generate Header _Text_ only (Diff),<br/>2=Generate Header _Text_ and _Bin_ (Merge/Only Structure!),<br/>4=Generate _Text_ with DATA (Diff),<br/>8=Export and Import DATA (Merge/Structure & Data) |
|
||||
| DBF_Conversion_Order | c_Expression | x | Field expresion (For _INDEX ON_). ie: name+str(age,3),<br/>Empty means no sort order. <br/> usefull only if *DBF_Conversion_Support* >0 |
|
||||
| DBF_Conversion_Condition | c_Expression | x | Logical expression (For _SCAN FOR_). ie: age > 10 AND NOT DELETED(),<br/>empty means all records, except *DBF_IncludeDeleted* <br/> usefull only if *DBF_Conversion_Support* >0 |
|
||||
| DBF_IndexList | c_FileList | x | A comma delimited list of additional index files ( cdx or idx ). __Not the structural index file.__ |
|
||||
| DBF_BinChar_Base64 | 0, 1 | | 0=For character type fields, if NoCPTrans 0=do not transform,<br/>1=use Base64 transform <br/> usefull only if *DBF_Conversion_Support* > 2 |
|
||||
| DBF_IncludeDeleted | 0, 1 | | 0=Do not include deleted records,<br/>1=Include deleted records <br/> usefull only if *DBF_Conversion_Support* > 2 |
|
||||
|
||||
Setting *per file** could only be used via this configuration file.
|
||||
For defaults, see [Configuration file](#configuration-file).
|
||||
|
||||
These options can be used in any combination inside a dbf particular cfg file,
|
||||
if you create a text file using your dbf filename and adding ".cfg".
|
||||
|
||||
#### Syntax for filename.dbf.cfg contents
|
||||
````
|
||||
"DBF_Conversion_Support: <4 for export only or 8 for bidirectional support>"
|
||||
"DBF_Conversion_Order: <C_Expression>"
|
||||
"DBF_Conversion_Condition: <C_Expression>"
|
||||
````
|
||||
|
||||
#### Example: customers.dbf.cfg
|
||||
````
|
||||
"DBF_Conversion_Support: 4"
|
||||
"DBF_Conversion_Order: cust_no"
|
||||
"DBF_Conversion_Condition: cust_no > 10"
|
||||
````
|
||||
|
||||
## Excluding directories
|
||||
It is possible to exclude directory structures from processing. Placing a **.FoxBin2Prg_Ignore** file into a directory will stop FoxBin2Prg from processing any file in this directory and it's subdirectories. The file must just exist and could otherwise be empty.
|
||||
The difference to setting all *XXX_Conversion_Support to 0* is, that it could not be turned on again down the directory structure.
|
||||
|
||||
This was set up to ignore the local GoFish_ settings and history folder, the file will be automatically created by GoFish starting with version 6.2.004.
|
||||
|
||||
----
|
||||

|
||||
This project is part of [VFPX](https://vfpx.github.io/).
|
||||
|
||||
----
|
||||
Last changed: _2026/06/21_ 
|
||||
@@ -15,7 +15,6 @@ See [Use with SCM tools](./FoxBin2Prg_SCM.md)
|
||||
- [settings per project](#settings-per-project)
|
||||
- [gitignore](#gitignore)
|
||||
- [gitattributes](#gitattributes)
|
||||
- [Fixing line endings](#fixing-line-endings)
|
||||
- [config](#foxbin2prg-config)
|
||||
|
||||
## Introduction
|
||||
@@ -109,7 +108,7 @@ Also on blame.
|
||||
If you go for the _lib.baseclass.classname.vc2_ or _lib.classname.vc2_ style is a matter of taste.
|
||||
I can see baseclass on classname, so there is not much value, other might think different.
|
||||
But split into classes makes life easy.
|
||||
This is to be done in the [config file](./FoxBin2Prg_Settings.md), setting _UseClassPerFile_ option to 1 or 2.
|
||||
This is to be done in the [config file](#foxbin2prg-config), setting _UseClassPerFile_ option to 1 or 2.
|
||||
|
||||
#### Forms
|
||||
Side effect of splitting VCX is that SCX will be split into 3 files too.
|
||||
@@ -138,10 +137,9 @@ Those settings are mainly per user (in _git_ terms **global**)
|
||||
Assuming you do a fresh install of git, you will be asked questions over questions. The most you left unchanged.
|
||||
The one I recommend is the dealing with line endings. You know all the odd uses of LF and CR.
|
||||
_git_ offers to alter this while dealing with your files. I recommend not.
|
||||
Just _Check in as is, check out as is_ while installing _git for windows_.
|
||||
Just "Check in as is, check out as is" while installing _git for windows_.
|
||||
This will keep your files, and any modern editor or WEB UI will not care anyway.
|
||||
If you missed on install - just install again.
|
||||
**If you have an issue with CRLF/LF so that you will get odd commits due to changing line endings, see [Fixing line endings](#fixing-line-endings).**
|
||||
|
||||
Do not forget to set up username, email and a ssh key. The following script sets up git and creates the key.
|
||||
It will copy the public key to _clipboard_ too - ready to paste into github. Anyway, you allways can copy the contents of `~/.ssh/id_rsa.pub`.
|
||||
@@ -188,11 +186,11 @@ For some odd reasons, the people on git-scm are going the way of evil. If you st
|
||||
If you not check _Run as Adminstrator_, it will install into your user folder. Even if installed in Programs folder earlier!
|
||||
|
||||
### Settings per project
|
||||
Those settings are mainly per project (repository) (in _git_ terms **local**). One can argue to put the one or other in different levels.
|
||||
Those settings are mainly per project (in _git_ terms **local**). One can argue to put the one or other in different levels.
|
||||
I recommend those inside the project to keep the repository as self contained as possible.
|
||||
#### gitignore
|
||||
The _.gitignore_ file controls which files **go not** into the git repository by default. It goes by folder with inheritance.
|
||||
If you understand the inheritance of .gitignore, you grok [FoXBin2Prg.cfg](./FoxBin2Prg_Settings.md#configuration-file) and vice versa. Very close.
|
||||
If you understand the inheritance of .gitignore, you grok [FoXBin2Prg.cfg](#foxbin2prg-config) and vice versa. Very close.
|
||||
|
||||
But git would not be git if one could not teach .gitignore to define the files **included**.
|
||||
Again, see pro-git.
|
||||
@@ -208,9 +206,9 @@ An example for _Text_ only use.
|
||||
|
||||
#include general
|
||||
#dbx data
|
||||
#!*.dbf
|
||||
#!*.cdx
|
||||
#!*.fpt
|
||||
!*.dbf
|
||||
!*.cdx
|
||||
!*.fpt
|
||||
|
||||
!*.dbc
|
||||
!*.dc[tx]
|
||||
@@ -244,7 +242,7 @@ An example for _Text_ only use.
|
||||
!*.mn2
|
||||
!*.sc2
|
||||
!*.lb2
|
||||
!*.d[bc]2
|
||||
#!*.d[bc]2
|
||||
|
||||
#include special
|
||||
#default git
|
||||
@@ -262,51 +260,169 @@ An example for _Text_ only use.
|
||||
foxuser.*
|
||||
_command.prg
|
||||
````
|
||||
As you see, this assumes that tables and databases are stored as binary.
|
||||
I think I will swap to use them as _Text_ too, since version 1.19.55 of FoxBin2Prg eleminates some problems with this idea.
|
||||
|
||||
Also this approach ignores any bak / log / tmp / err files by default.
|
||||
|
||||
#### gitattributes
|
||||
The _.gitattributes_ file controls some things that might be set to as local computer / user / repository (via `git config`). Note, using `git config` to alter the behaviour of the _repository_ will still be local to your computer, so a remote computer is not influenced. IOW, this is not pushed.
|
||||
It should be constant to the repository, no matter the local settings of any collaborator. This while we should use _.gitattributes_ file and included into the repository.
|
||||
|
||||
For VFP purposes, _.gitattributes_ controls the processing of line ending on git commit / checkout.
|
||||
The _.gitattributes_ file controls some things that might be set to as local computer / user / repository (via _git config_),
|
||||
but should be constant to the repository, no matter the local settings. This file is included into the repository.
|
||||
for VFP purposes, it controls the processing of line ending on commit / checkout.
|
||||
As mentioned [above](#git-settings) git might manipulate CRLF and LF. If the settings are different on different computers ,
|
||||
it might checkout with LF instead of CRLF. This creates useless files in the commit, but also might create havoc using the files.
|
||||
See [GoFish](https://github.com/VFPX/GoFish/issues/27) for an example.
|
||||
See [this](https://github.com/VFPX/GoFish/issues/27) for an example.
|
||||
To solve this, add a _.gitattributes_ file to any of your projects, next to the _.gitignore_ file. It should look like this:
|
||||
````
|
||||
#.gitattributes
|
||||
# disable newline conversion on checkout with no conversion on check-in for all files
|
||||
* -text
|
||||
````
|
||||
If you have a project running, check the line endings and make shure they follow DOS standard CRLF:
|
||||
|
||||
##### Fixing line endings
|
||||
If you run into the problem that you have set up different computers different for dealing with line endings so commits of all files or all lines of a file without reason, you might need to change to git to keep CRLF and set your files line endings to CRLF.
|
||||
- create a backup of your folder
|
||||
- create _.gitattributes_ file as above
|
||||
run following lines in bash:
|
||||
```
|
||||
git add . -u
|
||||
git commit -m "Saving files before refreshing line endings"
|
||||
git add --renormalize .
|
||||
git commit -m "Normalize all the line endings"
|
||||
```
|
||||
**Note: You must do this to *every repository* and, if there are several branches of a repository, with *every (active) branch*.**
|
||||
**Note: Be careful, this will not alter any older commit, so `git reset` (or the like) to an old commit could create the problem again. Recreating _.gitattributes_ and the code snippet should solve the problem, for single files like:***
|
||||
```
|
||||
git add --renormalize filename
|
||||
git commit
|
||||
```
|
||||
If you have a project running, check the line endings and make shure they follow DOS standard CRLF.
|
||||
|
||||
#### FoxBin2Prg config
|
||||
The config of FoxBin2Prg using FoxBin2Prg.cfg files is relative simple. As you might see above, I carry the file within the repo.
|
||||
The good on this is, if I change my mind and alter settings in it, FoxBin2Prg will find the setting that fit to the data on each commit.
|
||||
If I have to checkout old stuff - the setting will fit. See [Configuration file(s)](./FoxBin2Prg_Settings.md) for detailed information.
|
||||
If I have to checkout old stuff - the setting will fit.
|
||||
|
||||
````
|
||||
*################################################################################################################
|
||||
*FOXBIN2PRG.CFG configuration options: (If no values given, these are the DEFAULTS)
|
||||
*Version: v1.21.01
|
||||
*****************************************************************************************************************
|
||||
|
||||
* Note, configuration files will follow an inheritance.
|
||||
* 1. Default values
|
||||
* 2. optional FOXBIN2PRG.CFG in folder of FOXBIN2PRG.EXE,
|
||||
* or, if defined, a config file given by a parameter calling FOXBIN2PRG,
|
||||
* if used, the AllowInheritance setting controls if other config files will be evaluated,
|
||||
* 3. optional FOXBIN2PRG.CFG in root of working directory,
|
||||
* 4. optional FOXBIN2PRG.CFG in every folder up to the working directory,
|
||||
* 5. optional Special settings per single DBF's Syntax:<TableName>.dbf.cfg in tables folder),
|
||||
* 6. Parameter calling FOXBIN2PRG.EXE.
|
||||
|
||||
* Some Parameter calling FOXBIN2PRG.EXE overturn this settings (except Defaults)
|
||||
*****************************************************************************************************************
|
||||
|
||||
*-- Settings for internal work, not processing
|
||||
*Language: (auto) && Language of shown messages and LOGs. EN=English, FR=French, ES=Espa<70>ol, DE=German, Not defined = AUTOMATIC [DEFAULT]
|
||||
*ShowProgressbar: 1 && 0=Don't show, 1=Allways show, 2=Show only for multi-file processing
|
||||
*DontShowErrors: 0 && Show message errors by default
|
||||
*ExtraBackupLevels: 1 && By default 1 BAK is created. With this you can make more .N.BAK, or none
|
||||
*Debug: 0 && Don't Activate individual <file>.Log by default
|
||||
*BackgroundImage: <cFile> && Backgroundimage for process form. Empty for empty Background. File not found uses default.
|
||||
*HomeDir: 1 && Home directory in PJX
|
||||
* && 0 don't save HomeDir in PJ2
|
||||
* && 1 save HomeDir in PJ2
|
||||
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*-- Settings for config file via parameter only
|
||||
*AllowInheritance: 1 && 0=Not allow, 1=Allow scanning "regular" config files
|
||||
*----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
*-- Conversion operation by type
|
||||
*PJX_Conversion_Support: 2 && 0=No support, 1=Generate TXT only (Diff), 2=Generate TXT and BIN (Merge)
|
||||
*VCX_Conversion_Support: 2 && 0=No support, 1=Generate TXT only (Diff), 2=Generate TXT and BIN (Merge)
|
||||
*SCX_Conversion_Support: 2 && 0=No support, 1=Generate TXT only (Diff), 2=Generate TXT and BIN (Merge)
|
||||
*FRX_Conversion_Support: 2 && 0=No support, 1=Generate TXT only (Diff), 2=Generate TXT and BIN (Merge)
|
||||
*LBX_Conversion_Support: 2 && 0=No support, 1=Generate TXT only (Diff), 2=Generate TXT and BIN (Merge)
|
||||
*MNX_Conversion_Support: 2 && 0=No support, 1=Generate TXT only (Diff), 2=Generate TXT and BIN (Merge)
|
||||
*DBC_Conversion_Support: 2 && 0=No support, 1=Generate TXT only (Diff), 2=Generate TXT and BIN (Merge)
|
||||
*DBF_Conversion_Support: 1 && 0=No support, 1=Generate Header TXT only (Diff), 2=Generate Header TXT and BIN (Merge/Only Structure!), 4=Generate TXT with DATA (Diff), 8=Export and Import DATA (Merge/Structure & Data)
|
||||
*FKY_Conversion_Support: 1 && 0=No support, 1=Generate TXT only (Diff)
|
||||
*MEM_Conversion_Support: 1 && 0=No support, 1=Generate TXT only (Diff)
|
||||
*----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
*Setting for pjx files
|
||||
*CheckFileInPath: 0 && Determines 2Txt deals with files not in the subfolders of the PJX. No handler for UNC paths.
|
||||
* && 0 Ignore. Default
|
||||
* && 1 Check and error out if file is not on same structure (for source control)
|
||||
* && 2 Create absolute path if file is on different drive.
|
||||
* && 3 Create absolute path if file is not in structure
|
||||
*----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
*Setting for container files (not pjx)
|
||||
*-- CLASS and FORM options (tx2 is to read as vc2 or sc2, VCX might be SCX)
|
||||
*- Class per file options (UseClassPerFile: 1)
|
||||
*UseClassPerFile: 0 && Determines how a library (or form) will handle included class (or, for forms, objects)
|
||||
* && 0 One library.tx2 file
|
||||
* && 1 Multiple file.class.tx2 files
|
||||
* && 2 Multiple file.baseclass.class.tx2 files
|
||||
*RedirectClassPerFileToMain: 0 && When regenerating binary files, determine target file
|
||||
* && 0 Don't redirect to file.tx2
|
||||
* && 1 Redirect to file.tx2 when selecting file[.baseclass].class.tx2
|
||||
* && RedirectClassType: 1 has precedence
|
||||
*RedirectClassType: 0 && For classes created with UseClassPerFile>0 in the form file[.baseclass].class.tx2
|
||||
* && Those files could be imported like file.tx2::Class::import or like file[.baseclass].class.tx2
|
||||
* && For the second form:
|
||||
* && 0 Redirect file[.baseclass].class.tx2 to file.VCX and add / replace all other classes of this library
|
||||
* && 1 Redirect file[.baseclass].class.tx2 to file[.baseclass].class.VCX and do not touch file.VCX
|
||||
* && 2 Redirect file[.baseclass].class.tx2 to file.VCX and do not touch other classes of file.VCX
|
||||
*ClassPerFileCheck: 0 && Check, if files listed in the main file of a library or form will be included
|
||||
* && 0 Don't check file inclusion
|
||||
* && 1 Check file[.baseclass].class.tx2 inclusion
|
||||
* && Only used if import file is in file[.baseclass].class.tx2 syntax
|
||||
* && Ignored for RedirectClassType: 2
|
||||
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
*-- DBC options
|
||||
*- File per DBC options (UseFilesPerDBC: 1)
|
||||
*OldFilesPerDBC: 0 && 1=Turns the File per DBC options on, 0 uses the old UseClassPerFile etc settings.
|
||||
* && Options below will only read if OldFilesPerDBC is set 1 before!
|
||||
* && If OldFilesPerDBC is set 0 later, alle setting will be lost
|
||||
*UseFilesPerDBC: 0 && 0=One database dc2 file, 1=Multiple file.*.*.dc2 files
|
||||
* && 0 creates only a file.dc2 with all DBC (file) data
|
||||
* && 1 creates a file.dc2 with DBC properties
|
||||
* && and additional DBC files per DBC item (stored-proc, table, ..)
|
||||
* && Note: recration only if RedirectFilePerDBCToMain is 1
|
||||
*RedirectFilePerDBCToMain: 0 && 0=Don't redirect to file.dc2, 1=Redirect to file.tx2 when selecting file.item.*.dc2
|
||||
*ItemPerDBCCheck: 0 && 0=Don't check file.item.*.dc2 inclusion, 1=Check file.item.*.dc2 inclusion
|
||||
*----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
*-- General files
|
||||
*NoTimestamps: 1 && Clear timestamps of several file types by default for minimize text-file differences
|
||||
*ClearUniqueID: 1 && 0=Keep UniqueID in text files, 1=Clear Unique ID. Useful for Diff and Merge
|
||||
*OptimizeByFilestamp: 0 && 1=Optimize file regeneration depending on file timestamp. Dangerous while working with branches!
|
||||
*RemoveNullCharsFromCode: 1 && 1=Drop .Null. chars from source code
|
||||
*RemoveZOrderSetFromProps: 0 && 0=Do not remove ZOrderSet property from object, 1=Remove ZOrderSet property from object
|
||||
*PRG_Compat_Level: 0 && 0=Legacy, 1=Use HELPSTRING as Class Procedure comment
|
||||
*----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
*-- PJX special
|
||||
*BodyDevInfo: 0 && 0=Don't keep DevInfo for body pjx records, 1=Keep DevInfo
|
||||
*----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
*-- DBF special
|
||||
*ClearDBFLastUpdate: 1 && 0=Keep DBF LastUpdate, 1=Clear DBF LastUpdate. Useful for Diff.
|
||||
*ExcludeDBFAutoincNextval: 0 && 0=Do not exclude this value from db2, 1=Exclude this value from db2
|
||||
*DBF_Conversion_Included: * && If DBF_Conversion_Support:4, you can specify multiple filemasks: www,fb2p_free.dbf
|
||||
*DBF_Conversion_Excluded: && If DBF_Conversion_Support:4, you can specify multiple filemasks: www,fb2p_free.dbf
|
||||
*DBF_BinChar_Base64: 1 && For character type fields, if NoCPTrans 0=do not transform, 1=use Base64 transform (default)
|
||||
*DBF_IncludeDeleted: 0 && 0=Do not include deleted records (default), 1=Include deleted records
|
||||
*----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
*-- Text file extensions
|
||||
*extension: tx2=newext && Specify extensions to use. Default FoxBin2Prg extensions ends in '2' (see at the bottom)
|
||||
*-- Example configuration for SourceSafe compatibility:
|
||||
*extension: pj2=pja && Text file to PJX
|
||||
*extension: vc2=vca && Text file to VCX
|
||||
*extension: sc2=sca && Text file to SCX
|
||||
*extension: fr2=fra && Text file to FRX
|
||||
*extension: lb2=lba && Text file to LBX
|
||||
*extension: mn2=mna && Text file to MNX
|
||||
*extension: db2=dba && Text file to DBF
|
||||
*extension: dc2=dca && Text file to DBC
|
||||
*-- Additional extensions
|
||||
*extension: fk2=fkx && Text file to FKY
|
||||
*extension: me2=fkx && Text file to MEM
|
||||
````
|
||||
All use off this are the last four lines. But I like to keep the template (recent as version 1.19.69).
|
||||
- Using single classes - because it's much more easy to merge a single class then a whole library.
|
||||
- A single class selected might be added to the VCX
|
||||
- Turn off DBC and DBF conversion
|
||||
|
||||
----
|
||||

|
||||
This project is part of [VFPX](https://vfpx.github.io/).
|
||||
|
||||
----
|
||||
Last changed: _2026/06/21_ 
|
||||
Last changed: _2023/11/26_ 
|
||||
@@ -1,6 +1,6 @@
|
||||
*################################################################################################################
|
||||
*FOXBIN2PRG.CFG configuration options: (If no values given, these are the DEFAULTS)
|
||||
*Version: v1.21.05
|
||||
*Version: v1.21.04
|
||||
*****************************************************************************************************************
|
||||
|
||||
* Note, configuration files will follow an inheritance.
|
||||
@@ -10,7 +10,7 @@
|
||||
* if used, the InhibitInheritance setting controls if other config files will be evaluated (default). See below.
|
||||
* 3., optional FOXBIN2PRG.CFG in root of working directory
|
||||
* 4., optional FOXBIN2PRG.CFG in every folder up to the working directory
|
||||
* 5., optional Special settings per single DBF's (Syntax: <TableName>.dbf.cfg in tables folder)
|
||||
* 5., optional Special settings per single DBF's Syntax: <TableName>.dbf.cfg in tables folder)
|
||||
|
||||
* Some Parameter calling FOXBIN2PRG.EXE overturn this settings (except Defaults)
|
||||
*****************************************************************************************************************
|
||||
@@ -18,16 +18,12 @@
|
||||
*-- Settings for internal work, not processing
|
||||
*Language: (auto) && Language of shown messages and LOGs. EN=English, FR=French, ES=Espa<70>ol, DE=German, Not defined = AUTOMATIC [DEFAULT]
|
||||
*ShowProgressbar: 1 && 0=Don't show, 1=Allways show, 2=Show only for multi-file processing
|
||||
* && Note: This setting will be ignored, if cDontShowProgress parameter is set.
|
||||
*DontShowErrors: 0 && Show message errors by default
|
||||
* && Note: This setting will be ignored, if cDontShowError parameter is set.
|
||||
* && Note: There is no inheritance for this setting. First occurance wins.
|
||||
*ExtraBackupLevels: 1 && By default 1 BAK is created. With this you can make more .N.BAK, or none
|
||||
* && Note: There is no inheritance for this setting. First occurance wins.
|
||||
*Debug: 0 && 0=Don't Activate individual <file>.Log by default
|
||||
* && 1=Activate individual <file>.Log by default
|
||||
* && 2=???
|
||||
* && Only valid if not controlled by parameter cDebug
|
||||
* && Only valid if not controlled by parameter
|
||||
*BackgroundImage: <cFile> && Backgroundimage for process form. Empty for empty Background. File not found uses default.
|
||||
*HomeDir: 1 && Home directory in PJX
|
||||
* && 0 don't save HomeDir in PJ2
|
||||
@@ -133,12 +129,8 @@
|
||||
|
||||
*-- General files
|
||||
*NoTimestamps: 1 && Clear timestamps of several file types by default for minimize text-file differences
|
||||
* && Note: This setting will be ignored, if cNoTimestamps parameter is set.
|
||||
* && Note: There is no inheritance for this setting. First occurance wins.
|
||||
*ClearUniqueID: 1 && 0=Keep UniqueID in text files, 1=Clear Unique ID. Useful for Diff and Merge
|
||||
* && Note: There is no inheritance for this setting. First occurance wins.
|
||||
*OptimizeByFilestamp: 0 && 1=Optimize file regeneration depending on file timestamp. Dangerous while working with branches!
|
||||
* && Note: There is no inheritance for this setting. First occurance wins.
|
||||
*RemoveNullCharsFromCode: 1 && 1=Drop .Null. chars from source code
|
||||
*RemoveZOrderSetFromProps: 0 && 0=Do not remove ZOrderSet property from object, 1=Remove ZOrderSet property from object
|
||||
*PRG_Compat_Level: 0 && 0=Legacy, 1=Use HELPSTRING as Class Procedure comment
|
||||
|
||||
@@ -25,7 +25,7 @@ _LegalTrademark = "MIT License"
|
||||
_ProductName = "FOXBIN2PRG"
|
||||
_MajorVer = "1"
|
||||
_MinorVer = "21"
|
||||
_Revision = "05"
|
||||
_Revision = "1"
|
||||
_LanguageID = "1034"
|
||||
_AutoIncrement = "0"
|
||||
*</DevInfo>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#DEFINE DN_FB2PRG_VERSION 1.21
|
||||
#DEFINE DC_FB2PRG_VERSION_REAL '1.21.05'
|
||||
#DEFINE DC_FB2PRG_VERSION_REAL '1.21.04'
|
||||
|
||||
*---------------------------------------------------------------------------------------------------
|
||||
* Module.........: FOXBIN2PRG.PRG - FOR VISUAL FOXPRO 9.0
|
||||
@@ -326,13 +326,6 @@
|
||||
* 03/01/2024 LScheffler v1.21.02 Bug Fix: Problems regenerating single classes and forms from text files in class-per-file form; #105 (LScheffler)
|
||||
* 24/04/2024 LScheffler v1.21.03 Bug Fix: Text To Bin with Fieldcaption = "NULL" (misnomer. it's the field name); #106; #106 (griessbach14943)
|
||||
* 26/08/2024 DHennig v1.21.04 Added support for BodyDevInfo = 2 in CFG file to prevent both DevInfo and ObjRev from being written to PJ2 file
|
||||
* 18/06/2026 LScheffler v1.21.05 Bug Fix: Brute force fixed Datatype error for tcDontShowProgress, #114 (omirian)
|
||||
* 18/06/2026 LScheffler v1.21.05 Bug Fix: Fixed missing link SCM documentation, #116 (ToniKoehler)
|
||||
* 18/06/2026 LScheffler v1.21.05 Bug Fix: Fixed a problem that cDontShowProgress parameter will be ignored if ShowProgressbar property is used. #118 (LScheffler)
|
||||
* 18/06/2026 LScheffler v1.21.05 Docu: Added documentation of properties of settings object
|
||||
* 18/06/2026 LScheffler v1.21.05 Docu: Better documentation if a settings us ignored when a parameter is set. Voth in in docu and setting files generated via -Cc options.
|
||||
* 18/06/2026 LScheffler v1.21.05 Docu: Some settings will not follow inheritence, documented in docu and setting files generated via -Cc options.
|
||||
* 18/06/2026 LScheffler v1.21.05 Docu: Minor changes
|
||||
* </HISTORIAL DE CAMBIOS Y NOTAS IMPORTANTES>
|
||||
*
|
||||
*---------------------------------------------------------------------------------------------------
|
||||
@@ -515,9 +508,6 @@
|
||||
* 19/09/2023 LScheffler Bug REPORT v1.21.00 Splitted database file is not regenerated. Problem with removed Spanish comment.
|
||||
* 03/01/2024 LScheffler Bug REPORT v1.21.01 Problems regenerating single classes and forms from text files in class-per-file form; #105
|
||||
* 25/03/2024 griessbach14943 Bug REPORT v1.21.02 Text To Bin with Fieldcaption = "NULL" (misnomer. it's the field name); #106
|
||||
* 25/02/2026 omirian Bug REPORT v1.21.05 Brute force fixed Datatype error for tcDontShowProgress, #114
|
||||
* 09/04/2026 ToniKoehler Bug REPORT v1.21.05 Fixed missing link SCM documentation, #116
|
||||
* 18/06/2026 LScheffler Bug REPORT v1.21.05 Fixed a problem that cDontShowProgress parameter will be ignored if ShowProgressbar property is used. #118
|
||||
|
||||
* </TESTEO Y REPORTE DE BUGS (AGRADECIMIENTOS)>
|
||||
*
|
||||
@@ -2779,15 +2769,7 @@ Define Class c_foxbin2prg As Session
|
||||
Case Left( laConfig(m.I), 17 ) == Lower('DontShowProgress:')
|
||||
lcValue = Alltrim( Substr( laConfig(m.I), 18 ) )
|
||||
If Not Inlist( Transform(tcDontShowProgress), '0', '1', '2' ) And Inlist( lcValue, '0', '1', '2' ) Then
|
||||
*!* Changed by: SF 18.06.2026
|
||||
*!* <pdm>
|
||||
*!* <change date="{^2026-06-18,14:47:00}">Changed by: SF<br />
|
||||
*!* No need for tcDontShowProgress, it runs on .n_ShowProgressbar
|
||||
*!* </change>
|
||||
*!* </pdm>
|
||||
* tcDontShowProgress = lcValue
|
||||
tcDontShowProgress = ''
|
||||
*!* /Changed by: SF 18.06.2026
|
||||
tcDontShowProgress = lcValue
|
||||
lo_CFG.n_ShowProgressbar = Icase(lcValue=='0',1, lcValue=='1',0, 2)
|
||||
.writeLog( C_TAB + Justfname(lcConfigFile) + ' > tcDontShowProgress: ' + Transform(tcDontShowProgress) )
|
||||
Endif
|
||||
@@ -2801,16 +2783,7 @@ Define Class c_foxbin2prg As Session
|
||||
|
||||
Case Left( laConfig(m.I), 16 ) == Lower('ShowProgressbar:')
|
||||
lcValue = Alltrim( Substr( laConfig(m.I), 17 ) )
|
||||
*!* Changed by: SF 18.06.2026
|
||||
*!* <pdm>
|
||||
*!* <change date="{^2026-06-18,14:49:00}">Changed by: SF<br />
|
||||
*!* Parameter tcDontShowProgress has priority, as in DontShowProgress
|
||||
*!* If tcDontShowProgress has a valid value, the setting will be ignored, and the parameter sets .n_ShowProgressbar further below.
|
||||
*!* </change>
|
||||
*!* </pdm>
|
||||
* If Inlist( lcValue, '0', '1', '2' ) Then
|
||||
If Not Inlist( Transform(tcDontShowProgress), '0', '1', '2' ) And Inlist( lcValue, '0', '1', '2' ) Then
|
||||
*!* /Changed by: SF 18.06.2026
|
||||
If Inlist( lcValue, '0', '1', '2' ) Then
|
||||
lo_CFG.n_ShowProgressbar = Int( Val(lcValue) )
|
||||
tcDontShowProgress = ''
|
||||
.writeLog( C_TAB + Justfname(lcConfigFile) + ' > ShowProgressbar: ' + lcValue )
|
||||
@@ -3238,15 +3211,7 @@ Define Class c_foxbin2prg As Session
|
||||
*-- ESTOS SE EVALÚAN FUERA DEL IF PORQUE NO DEPENDEN DEL CFG
|
||||
*-- Y PUEDEN VENIR TAMBIÉN DE PARÁMETROS EXTERNOS.
|
||||
If Inlist( Transform(tcDontShowProgress), '0', '1', '2' ) Then
|
||||
*!* Changed by: SF 18.06.2026
|
||||
*!* <pdm>
|
||||
*!* <change date="{^2026-06-18,14:45:00}">Changed by: SF<br />
|
||||
*!* Problem with removed type Error in tcDontShowProgress
|
||||
*!* </change>
|
||||
*!* </pdm>
|
||||
* lo_CFG.n_ShowProgressbar = Icase(tcDontShowProgress=='0',1, tcDontShowProgress=='1',0, 2)
|
||||
lo_CFG.n_ShowProgressbar = Icase(Transform(tcDontShowProgress)=='0',1, Transform(tcDontShowProgress)=='1',0, 2)
|
||||
*!* /Changed by: SF 18.06.2026
|
||||
lo_CFG.n_ShowProgressbar = Icase(tcDontShowProgress=='0',1, tcDontShowProgress=='1',0, 2)
|
||||
Endif
|
||||
If Inlist( Transform(tcDontShowErrors), '0', '1' ) Then
|
||||
lo_CFG.l_ShowErrors = Not (Transform(tcDontShowErrors) == '1')
|
||||
@@ -31741,7 +31706,7 @@ Define Class CL_LANG As Custom
|
||||
<<>> if used, the InhibitInheritance setting controls if other config files will be evaluated (default)
|
||||
<<>> 3., optional FOXBIN2PRG.CFG in root of working directory
|
||||
<<>> 4., optional FOXBIN2PRG.CFG in every folder up to the working directory
|
||||
<<>> 5., optional Special settings per single DBF's (Syntax: <TableName>.dbf.cfg in tables folder)
|
||||
<<>> 5., optional Special settings per single DBF's Syntax: <TableName>.dbf.cfg in tables folder)
|
||||
<<>>
|
||||
<<>> Some Parameter calling FOXBIN2PRG.EXE overturn this settings (except Defaults)
|
||||
<<>>****************************************************************************************************************
|
||||
@@ -31749,17 +31714,12 @@ Define Class CL_LANG As Custom
|
||||
<<>>-- Settings for internal work, not processing
|
||||
<<>>Language: (auto) && Language of shown messages and LOGs. EN=English, FR=French, ES=Español, DE=German, Not defined = AUTOMATIC [DEFAULT]
|
||||
<<>>ShowProgressbar: 1 && 0=Don't show, 1=Allways show, 2=Show only for multi-file processing
|
||||
<<>> && Note: This setting will be ignored, if cDontShowProgress parameter is set.
|
||||
<<>>DontShowErrors: 0 && Show message errors by default
|
||||
<<>> && Note: This setting will be ignored, if cDontShowError parameter is set.
|
||||
<<>> && Note: There is no inheritance for this setting. First occurance wins.
|
||||
<<>>ExtraBackupLevels: 1 && By default 1 BAK is created. With this you can make more .N.BAK, or none
|
||||
<<>> && Note: There is no inheritance for this setting. First occurance wins.
|
||||
<<>>Debug: 0 && 0=Don't Activate individual <file>.Log by default
|
||||
<<>> && 1=Activate individual <file>.Log by default
|
||||
<<>> && 2=???
|
||||
<<>> && Only valid if not controlled by parameter cDebug
|
||||
<<>> && Note: This setting will be ignored, if cDebug parameter is set.
|
||||
<<>> && Only valid if not controlled by parameter
|
||||
<<>>BackgroundImage: <cFile> && Backgroundimage for process form. Empty for empty Background. File not found uses default.
|
||||
<<>>HomeDir: 1 && Home directory in PJX
|
||||
<<>> && 0 don't save HomeDir in PJ2
|
||||
@@ -31865,12 +31825,8 @@ Define Class CL_LANG As Custom
|
||||
<<>>
|
||||
<<>>-- General files
|
||||
<<>>NoTimestamps: 1 && Clear timestamps of several file types by default for minimize text-file differences
|
||||
<<>> && Note: This setting will be ignored, if cNoTimestamps parameter is set.
|
||||
<<>> && Note: There is no inheritance for this setting. First occurance wins.
|
||||
<<>>ClearUniqueID: 1 && 0=Keep UniqueID in text files, 1=Clear Unique ID. Useful for Diff and Merge
|
||||
<<>> && Note: There is no inheritance for this setting. First occurance wins.
|
||||
<<>>OptimizeByFilestamp: 0 && 1=Optimize file regeneration depending on file timestamp. Dangerous while working with branches!
|
||||
<<>> && Note: There is no inheritance for this setting. First occurance wins.
|
||||
<<>>RemoveNullCharsFromCode: 1 && 1=Drop .Null. chars from source code
|
||||
<<>>RemoveZOrderSetFromProps: 0 && 0=Do not remove ZOrderSet property from object, 1=Remove ZOrderSet property from object
|
||||
<<>>PRG_Compat_Level: 0 && 0=Legacy, 1=Use HELPSTRING as Class Procedure comment
|
||||
@@ -32100,7 +32056,7 @@ Define Class CL_LANG As Custom
|
||||
<<>> if used, the InhibitInheritance setting controls if other config files will be evaluated (default)
|
||||
<<>> 3., optional FOXBIN2PRG.CFG in root of working directory
|
||||
<<>> 4., optional FOXBIN2PRG.CFG in every folder up to the working directory
|
||||
<<>> 5., optional Special settings per single DBF's (Syntax: <TableName>.dbf.cfg in tables folder)
|
||||
<<>> 5., optional Special settings per single DBF's Syntax: <TableName>.dbf.cfg in tables folder)
|
||||
<<>>
|
||||
<<>> Some Parameter calling FOXBIN2PRG.EXE overturn this settings (except Defaults)
|
||||
<<>>****************************************************************************************************************
|
||||
@@ -32108,17 +32064,12 @@ Define Class CL_LANG As Custom
|
||||
<<>>-- Settings for internal work, not processing
|
||||
<<>>Language: (auto) && Language of shown messages and LOGs. EN=English, FR=French, ES=Español, DE=German, Not defined = AUTOMATIC [DEFAULT]
|
||||
<<>>ShowProgressbar: 1 && 0=Don't show, 1=Allways show, 2=Show only for multi-file processing
|
||||
<<>> && Note: This setting will be ignored, if cDontShowProgress parameter is set.
|
||||
<<>>DontShowErrors: 0 && Show message errors by default
|
||||
<<>> && Note: This setting will be ignored, if cDontShowError parameter is set.
|
||||
<<>> && Note: There is no inheritance for this setting. First occurance wins.
|
||||
<<>>ExtraBackupLevels: 1 && By default 1 BAK is created. With this you can make more .N.BAK, or none
|
||||
<<>> && Note: There is no inheritance for this setting. First occurance wins.
|
||||
<<>>Debug: 0 && 0=Don't Activate individual <file>.Log by default
|
||||
<<>> && 1=Activate individual <file>.Log by default
|
||||
<<>> && 2=???
|
||||
<<>> && Only valid if not controlled by parameter cDebug
|
||||
<<>> && Note: This setting will be ignored, if cDebug parameter is set.
|
||||
<<>> && Only valid if not controlled by parameter
|
||||
<<>>BackgroundImage: <cFile> && Backgroundimage for process form. Empty for empty Background. File not found uses default.
|
||||
<<>>HomeDir: 1 && Home directory in PJX
|
||||
<<>> && 0 don't save HomeDir in PJ2
|
||||
@@ -32224,12 +32175,8 @@ Define Class CL_LANG As Custom
|
||||
<<>>
|
||||
<<>>-- General files
|
||||
<<>>NoTimestamps: 1 && Clear timestamps of several file types by default for minimize text-file differences
|
||||
<<>> && Note: This setting will be ignored, if cNoTimestamps parameter is set.
|
||||
<<>> && Note: There is no inheritance for this setting. First occurance wins.
|
||||
<<>>ClearUniqueID: 1 && 0=Keep UniqueID in text files, 1=Clear Unique ID. Useful for Diff and Merge
|
||||
<<>> && Note: There is no inheritance for this setting. First occurance wins.
|
||||
<<>>OptimizeByFilestamp: 0 && 1=Optimize file regeneration depending on file timestamp. Dangerous while working with branches!
|
||||
<<>> && Note: There is no inheritance for this setting. First occurance wins.
|
||||
<<>>RemoveNullCharsFromCode: 1 && 1=Drop .Null. chars from source code
|
||||
<<>>RemoveZOrderSetFromProps: 0 && 0=Do not remove ZOrderSet property from object, 1=Remove ZOrderSet property from object
|
||||
<<>>PRG_Compat_Level: 0 && 0=Legacy, 1=Use HELPSTRING as Class Procedure comment
|
||||
@@ -32467,16 +32414,12 @@ Define Class CL_LANG As Custom
|
||||
<<>>Interne Einstellungen
|
||||
<<>>Language: (auto) && Sprache für Anzeigen und Logs. EN=English, FR=Français, ES=Español, DE=Deutsch, Nicht definiert = Automatisch [DEFAULT]
|
||||
<<>>ShowProgressbar: 1 && 0=Zeige Fortschrittsfenster, 1=Zeige es nicht, 2=Zeige Fortschrittsfenster nur, wenn mehrere Dateien konvertiert werden.
|
||||
<<>> && Achtung: Wird der Parameter cDontShowProgress genutzt, wird diese einstellung ignoriert.
|
||||
<<>>DontShowErrors: 0 && 0=Zeige Fehler an, 1=Zeige keine Fehler an
|
||||
<<>> && Achtung: Wird der Parameter cDontShowError genutzt, wird diese einstellung ignoriert.
|
||||
<<>> && Achtung: Diese Einstellung folgt nicht der Vererbung. Der erste Eintrag wird genutzt.
|
||||
<<>>ExtraBackupLevels: 1 && Anzahl der Backup-Ebenen der Binärdateien 0=kein Backup, 1=<Datei>.BAK, n>1= n-Backup-Ebenen, <Datei>.n.BAK
|
||||
<<>> && Achtung: Diese Einstellung folgt nicht der Vererbung. Der erste Eintrag wird genutzt.
|
||||
<<>>Debug: 0 && 0=Individuelles Logging ist aus
|
||||
<<>> && 1=Individuelles Log per Datei <Datei>.Log
|
||||
<<>> && 2=???
|
||||
<<>> && Nur gültig, wenn nicht durch einen Parameter cDebug übersteuert
|
||||
<<>> && Nur gültig, wenn nicht durch einen Parameter übersteuert
|
||||
<<>>BackgroundImage: <cFile> && Hintergrundbild für das Formular zur Fortschrittsanzeige.
|
||||
<<>> && Leer erzeugt kein Hintergrundbild. Wird die Datei nicht gefunden, wird der Standardhintergrund verwendet.
|
||||
<<>>HomeDir: 1 && Speichern der HomeDir Eigenschaft in die PJX
|
||||
@@ -32593,19 +32536,15 @@ Define Class CL_LANG As Custom
|
||||
<<>>
|
||||
<<>>Allgemeine Dateien
|
||||
<<>>NoTimestamps: 1 && 0=Zeitstempel einiger Dateiarten werden nicht gelöscht 1=Zeitstempel werden zum Minimieren der Text-Datei-Unterschiede gelöscht
|
||||
<<>> && Achtung: Wird der Parameter cNoTimestamps genutzt, wird diese einstellung ignoriert.
|
||||
<<>> && Achtung: Diese Einstellung folgt nicht der Vererbung. Der erste Eintrag wird genutzt.
|
||||
<<>>ClearUniqueID: 1 && 0=Erhalte die Unique ID in den Text-Dateien, 1=Lösche Unique ID. Nützlich für Diff und Merge
|
||||
<<>> && Achtung: Diese Einstellung folgt nicht der Vererbung. Der erste Eintrag wird genutzt.
|
||||
<<>>OptimizeByFilestamp: 0 && 0=Aus, 1=Optimierte Erzeugung der Binärdateien in Abhängigkeit vom Zeitstempel. Gefährlich beim Arbeiten mit Zweigen!
|
||||
<<>> && Achtung: Diese Einstellung folgt nicht der Vererbung. Der erste Eintrag wird genutzt.
|
||||
<<>>RemoveNullCharsFromCode: 1 && 0=Aus 1=Lösche .Null. (CHR(0)) Zeichen aus dem Quellcode
|
||||
<<>>RemoveZOrderSetFromProps: 0 && 0=Aus, 1=Entferne ZOrderSet Eigenschaft von Objekten
|
||||
<<>>PRG_Compat_Level: 0 && 0=Legacy, 1=Nutze HELPSTRING als Class Procedure Kommentar
|
||||
<<>>----------------------------------------------------------------------------------------------------------------
|
||||
<<>>
|
||||
<<>>-- speziell PJX
|
||||
<<>>BodyDevInfo: 0 && 0=DevInfo im body-pjx-Datensatz wird nicht erhalten, 1=DevInfo wird erhalten, 2=DevInfo und ObjRev werden nicht erhalten.
|
||||
<<>>BodyDevInfo: 0 && 0=DevInfo im body-pjx-Datensatz wird nicht erhalten], 1=DevInfo wird erhalten
|
||||
<<>>----------------------------------------------------------------------------------------------------------------
|
||||
<<>>
|
||||
<<>>-- speziell DBF
|
||||
@@ -32844,7 +32783,7 @@ Define Class CL_LANG As Custom
|
||||
<<>> if used, the InhibitInheritance setting controls if other config files will be evaluated (default). See below.
|
||||
<<>> 3., optional FOXBIN2PRG.CFG in root of working directory
|
||||
<<>> 4., optional FOXBIN2PRG.CFG in every folder up to the working directory
|
||||
<<>> 5., optional Special settings per single DBF's (Syntax: <TableName>.dbf.cfg in tables folder)
|
||||
<<>> 5., optional Special settings per single DBF's Syntax: <TableName>.dbf.cfg in tables folder)
|
||||
<<>>
|
||||
<<>> Some Parameter calling FOXBIN2PRG.EXE overturn this settings (except Defaults)
|
||||
<<>>****************************************************************************************************************
|
||||
@@ -32852,16 +32791,12 @@ Define Class CL_LANG As Custom
|
||||
<<>>-- Settings for internal work, not processing
|
||||
<<>>Language: (auto) && Language of shown messages and LOGs. EN=English, FR=French, ES=Español, DE=German, Not defined = AUTOMATIC [DEFAULT]
|
||||
<<>>ShowProgressbar: 1 && 0=Don't show, 1=Allways show, 2=Show only for multi-file processing
|
||||
<<>> && Note: This setting will be ignored, if cDontShowProgress parameter is set.
|
||||
<<>>DontShowErrors: 0 && Show message errors by default
|
||||
<<>> && Note: This setting will be ignored, if cDontShowError parameter is set.
|
||||
<<>> && Note: There is no inheritance for this setting. First occurance wins.
|
||||
<<>>ExtraBackupLevels: 1 && By default 1 BAK is created. With this you can make more .N.BAK, or none
|
||||
<<>> && Note: There is no inheritance for this setting. First occurance wins.
|
||||
<<>>Debug: 0 && 0=Don't Activate individual <file>.Log by default
|
||||
<<>> && 1=Activate individual <file>.Log by default
|
||||
<<>> && 2=???
|
||||
<<>> && Only valid if not controlled by parameter cDebug
|
||||
<<>> && Only valid if not controlled by parameter
|
||||
<<>>BackgroundImage: <cFile> && Backgroundimage for process form. Empty for empty Background. File not found uses default.
|
||||
<<>>HomeDir: 1 && Home directory in PJX
|
||||
<<>> && 0 don't save HomeDir in PJ2
|
||||
@@ -32967,12 +32902,8 @@ Define Class CL_LANG As Custom
|
||||
<<>>
|
||||
<<>>-- General files
|
||||
<<>>NoTimestamps: 1 && Clear timestamps of several file types by default for minimize text-file differences
|
||||
<<>> && Note: This setting will be ignored, if cNoTimestamps parameter is set.
|
||||
<<>> && Note: There is no inheritance for this setting. First occurance wins.
|
||||
<<>>ClearUniqueID: 1 && 0=Keep UniqueID in text files, 1=Clear Unique ID. Useful for Diff and Merge
|
||||
<<>> && Note: There is no inheritance for this setting. First occurance wins.
|
||||
<<>>OptimizeByFilestamp: 0 && 1=Optimize file regeneration depending on file timestamp. Dangerous while working with branches!
|
||||
<<>> && Note: There is no inheritance for this setting. First occurance wins.
|
||||
<<>>RemoveNullCharsFromCode: 1 && 1=Drop .Null. chars from source code
|
||||
<<>>RemoveZOrderSetFromProps: 0 && 0=Do not remove ZOrderSet property from object, 1=Remove ZOrderSet property from object
|
||||
<<>>PRG_Compat_Level: 0 && 0=Legacy, 1=Use HELPSTRING as Class Procedure comment
|
||||
|
||||
331
git_sync.ps1
331
git_sync.ps1
@@ -1,331 +0,0 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Sincronizeaza in ARBORE (langa binare) versiunile text FoxBin2Prg ale binarelor VFP
|
||||
ale unui proiect ROA, pentru ca git sa urmareasca text lizibil in loc de binare.
|
||||
|
||||
.DESCRIPTION
|
||||
Folder-mode recursiv pe TOT arborele proiectului (inclusiv COMUN\), NU project-mode din .pjx:
|
||||
altfel binarele nereferentiate in .pjx ar disparea din git. Pentru fiecare binar suportat
|
||||
genereaza fisierul text (.vc2/.sc2/.fr2/.mn2/.lb2/.pj2/.dc2/.db2) IN ACELASI FOLDER cu binarul.
|
||||
|
||||
Tipuri convertite: vcx, scx, frx, mnx, lbx, pjx, dbc (recursiv) + dbf-urile dintr-o lista
|
||||
explicita per proiect (-DbfList). Incremental: sare peste text-ul deja la zi (mtime binar vs text).
|
||||
|
||||
CONVERSIE IN STAGING TEMP (nu in arbore): FoxBin2Prg.EXE lasa artefacte (.err, _*.BAK) si
|
||||
vcx2txt sterge copia binara la final - cu destinatia = arborele ar sterge binarul din working
|
||||
copy-ul SVN. Aici copiem binar+memo (+.dbf.cfg) intr-un temp, convertim acolo, si copiem inapoi
|
||||
DOAR textul (raw bytes, byte-preserving - encoding real cp1250 sub header CPID=1252, nu decodam).
|
||||
Binarele din arbore NU sunt atinse niciodata.
|
||||
|
||||
Fidelitate per tip:
|
||||
- vcx/scx: roundtrip complet (bin->text->bin->text, comparare pe octeti) - au write-back.
|
||||
- frx/mnx/lbx/pjx/dbc/dbf: doar bin->text cu exit-code + timeout + text nevid (write-back nesuportat).
|
||||
|
||||
Esec partial: la esecul unui fisier continua cu restul, colecteaza esecurile, le raporteaza la
|
||||
final si iese cu exit code nenul.
|
||||
|
||||
Curatare orfani: textele .??2 fara binar corespondent (binar sters din SVN) si .db2-urile ale
|
||||
caror tabele au IESIT din lista -DbfList sunt DOAR RAPORTATE implicit; se sterg numai cu
|
||||
-OrphanCleanup explicit. Textele din -OrphanExempt sunt sarite de la verificare (text fara
|
||||
binar prin design).
|
||||
|
||||
Toate invocarile FoxBin2Prg.EXE trec prin Invoke-FoxBin2PrgSafe (timeout + taskkill).
|
||||
|
||||
.PARAMETER ProjectRoot
|
||||
Radacina proiectului (implicit D:\ROA\ROACONT).
|
||||
|
||||
.PARAMETER Types
|
||||
Tipurile binare (fara dbf) convertite recursiv (implicit vcx,scx,frx,mnx,lbx,pjx,dbc).
|
||||
|
||||
.PARAMETER DbfList
|
||||
Lista de pattern-uri relative la ProjectRoot pentru dbf-urile convertite in .db2 cu DATE
|
||||
(implicit lista ROACONT: Locale\locale*.dbf, Help\*.dbf, DATE\Optiuni_*.dbf).
|
||||
|
||||
.PARAMETER SubDir
|
||||
Optional. Limiteaza rularea la un subfolder (relativ la ProjectRoot) - util pentru rulari in pasi.
|
||||
Curatarea de orfani se face doar cand se ruleaza pe tot arborele (SubDir gol).
|
||||
|
||||
.PARAMETER TimeoutSeconds
|
||||
Timeout per invocare FoxBin2Prg (implicit 60s).
|
||||
|
||||
.PARAMETER MaxDb2Mb
|
||||
Prag: un .db2 peste aceasta dimensiune e raportat (tabela ar trebui scoasa din lista). Implicit 5.
|
||||
|
||||
.PARAMETER Force
|
||||
Reconverteste chiar daca textul e la zi.
|
||||
|
||||
.PARAMETER NoOrphanCleanup
|
||||
Pastrat pentru compatibilitate: forteaza doar-raportare chiar si cu -OrphanCleanup.
|
||||
|
||||
.PARAMETER OrphanCleanup
|
||||
Sterge efectiv textele orfane. Implicit orfanii sunt DOAR raportati, nu stersi.
|
||||
|
||||
.PARAMETER OrphanExempt
|
||||
Pattern-uri (-like, relative la ProjectRoot) de texte .??2 care NU sunt orfani chiar fara binar
|
||||
langa ele: binarul e gitignored si se genereaza local din text (txt2vcx), textul e sursa.
|
||||
|
||||
.EXAMPLE
|
||||
powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\git_sync.ps1 -ProjectRoot D:\ROA\ROACONT
|
||||
#>
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[string]$ProjectRoot = 'D:\ROA\ROACONT',
|
||||
[string[]]$Types = @('vcx','scx','frx','mnx','lbx','pjx','dbc'),
|
||||
[string[]]$DbfList = @('Locale\locale*.dbf','Help\*.dbf','DATE\Optiuni_*.dbf',
|
||||
'COMUN\clase\Locale\*.dbf','COMUN\datemenu\*.dbf','COMUN\datemenu\xold\*.dbf',
|
||||
'COMUN\Drepturi utilizatori\*\*.dbf','COMUN\utile\GridExtras\gridextras.dbf',
|
||||
'COMUN\utile\ListProperty\lproperty.dbf','COMUN\utile\hpdf\*.dbf','COMUN\utile\hpdf\ReportOutput\*.dbf',
|
||||
# acelasi set si fara prefixul COMUN\, pentru rulari cu -ProjectRoot chiar pe radacina COMUN
|
||||
'clase\Locale\*.dbf','datemenu\*.dbf','datemenu\xold\*.dbf',
|
||||
'Drepturi utilizatori\*\*.dbf','utile\GridExtras\gridextras.dbf',
|
||||
'utile\ListProperty\lproperty.dbf','utile\hpdf\*.dbf','utile\hpdf\ReportOutput\*.dbf'),
|
||||
# clase FFC/third-party cu #INCLUDE: roundtrip izolat = fals-negativ; editare doar in IDE, fara write-back
|
||||
[string[]]$RoundtripExempt = @('COMUN\clase\accessibility.vcx','COMUN\clase\oinventar.vcx','COMUN\clase\_gdiplus.vcx','COMUN\clase\_reportlistener.vcx','COMUN\utile\foxcharts\foxcharts.vcx','COMUN\utile\web\_webview.vcx'),
|
||||
# texte a caror sursa de adevar e textul: binarul e gitignored si se genereaza local, nu sunt orfani
|
||||
[string[]]$OrphanExempt = @('*utile\Teste\achizitie_import\stub_verificare\verificare.sc2'),
|
||||
[string]$SubDir = '',
|
||||
[int]$TimeoutSeconds = 60,
|
||||
[int]$MaxDb2Mb = 5,
|
||||
[switch]$Force,
|
||||
[switch]$NoOrphanCleanup,
|
||||
[switch]$OrphanCleanup
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$exe = 'D:\ROA\UTIL\foxbin2prg\FoxBin2Prg.EXE'
|
||||
if (-not (Test-Path $exe)) {
|
||||
throw "Nu gasesc $exe. Compileaza intai FoxBin2Prg (deschide foxbin2prg.pj2 in VFP si Build)."
|
||||
}
|
||||
if (-not (Test-Path -LiteralPath $ProjectRoot -PathType Container)) {
|
||||
throw "ProjectRoot nu exista: $ProjectRoot"
|
||||
}
|
||||
. (Join-Path $PSScriptRoot 'vfp_filemap.ps1')
|
||||
$map = $script:VfpFileMap
|
||||
$ProjectRoot = (Get-Item -LiteralPath $ProjectRoot).FullName
|
||||
|
||||
# extensiile text valide (pt curatare orfani), lowercase
|
||||
$script:TextExts = @{}
|
||||
foreach ($k in $map.Keys) { $script:TextExts[$map[$k][1]] = $k } # .vc2 -> .vcx
|
||||
|
||||
# set cai absolute (lowercase) ale binarelor scutite de garda roundtrip - doar bin->text valid
|
||||
$script:ExemptSet = New-Object System.Collections.Generic.HashSet[string]
|
||||
foreach ($rel in $RoundtripExempt) { [void]$script:ExemptSet.Add((Join-Path $ProjectRoot $rel).ToLower()) }
|
||||
|
||||
$runStamp = "{0}-{1}" -f $PID, (Get-Date -Format 'yyyyMMddHHmmssfff')
|
||||
$stagingRoot = Join-Path $env:TEMP ("git_sync_" + (Split-Path $ProjectRoot -Leaf) + "\$runStamp")
|
||||
|
||||
function Invoke-Fb2p {
|
||||
# toate apelurile trec prin watchdog (timeout + taskkill) - vezi vfp_filemap.ps1
|
||||
param([string]$InputFile, [string]$Recompile = '')
|
||||
if ($Recompile) {
|
||||
$r = Invoke-FoxBin2PrgSafe -ExePath $exe -ExeArgs @($InputFile,'','','','1','0','1','',$Recompile) -TimeoutSeconds $TimeoutSeconds
|
||||
} else {
|
||||
$r = Invoke-FoxBin2PrgSafe -ExePath $exe -ExeArgs @($InputFile,'','','','1','0','1') -TimeoutSeconds $TimeoutSeconds
|
||||
}
|
||||
return $r
|
||||
}
|
||||
|
||||
function Find-InDir([string]$dir, [string]$name) {
|
||||
# gaseste un fisier dupa nume (case-insensitive) intr-un folder; $null daca lipseste
|
||||
if (-not (Test-Path -LiteralPath $dir -PathType Container)) { return $null }
|
||||
return (Get-ChildItem -LiteralPath $dir -Filter $name -File -ErrorAction SilentlyContinue | Select-Object -First 1)
|
||||
}
|
||||
|
||||
function Test-BytesEqual([byte[]]$a, [byte[]]$b) {
|
||||
# normalizeaza CRLF/CR->LF si compara ca string Latin1 (byte<->char lossless) - rapid pe fisiere mari;
|
||||
# bucla per-octet in PowerShell era patologic de lenta (minute/fisier) pe textele de sute de KB.
|
||||
$enc = [System.Text.Encoding]::GetEncoding(28591)
|
||||
$sa = $enc.GetString($a) -replace "`r`n?", "`n"
|
||||
$sb = $enc.GetString($b) -replace "`r`n?", "`n"
|
||||
return $sa -eq $sb
|
||||
}
|
||||
|
||||
# --- Converteste un binar in staging si copiaza inapoi DOAR textul. Intoarce status string. ---
|
||||
function Convert-One {
|
||||
param([Parameter(Mandatory)][System.IO.FileInfo]$Bin)
|
||||
|
||||
$ext = $Bin.Extension.ToLower()
|
||||
$memoX = $map[$ext][0]
|
||||
$txtX = $map[$ext][1]
|
||||
$dir = $Bin.DirectoryName
|
||||
$base = [IO.Path]::GetFileNameWithoutExtension($Bin.Name)
|
||||
$memo = Find-InDir $dir ($base + $memoX)
|
||||
|
||||
# text tinta existent (case-insensitive) pentru incremental + destinatie
|
||||
$txtExisting = Find-InDir $dir ($base + $txtX)
|
||||
if (-not $Force -and $txtExisting) {
|
||||
$newestBin = $Bin.LastWriteTime
|
||||
if ($memo -and $memo.LastWriteTime -gt $newestBin) { $newestBin = $memo.LastWriteTime }
|
||||
if ($txtExisting.LastWriteTime -ge $newestBin) { return 'uptodate' }
|
||||
}
|
||||
|
||||
$stageDir = Join-Path $stagingRoot ([Guid]::NewGuid().ToString('N').Substring(0,12))
|
||||
New-Item -ItemType Directory -Force -Path $stageDir | Out-Null
|
||||
try {
|
||||
# cfg in staging (mostenit si de subfolderul rc): DontShowErrors suprima MessageBox-ul propriu
|
||||
# "End of Process (with errors)"; ShowProgressbar 0 = fara fereastra de progres (rulare headless).
|
||||
$cfgLines = [System.Collections.Generic.List[string]]@('DontShowErrors: 1','ShowProgressbar: 0')
|
||||
if ($ext -eq '.dbf') { $cfgLines.Add('DBF_Conversion_Support: 4') } # forteaza exportul DATELOR
|
||||
Set-Content -LiteralPath (Join-Path $stageDir 'foxbin2prg.cfg') -Value $cfgLines -Encoding Ascii
|
||||
|
||||
$stageBin = Join-Path $stageDir $Bin.Name
|
||||
Copy-Item -LiteralPath $Bin.FullName -Destination $stageBin -Force
|
||||
if ($memo) { Copy-Item -LiteralPath $memo.FullName -Destination (Join-Path $stageDir $memo.Name) -Force }
|
||||
|
||||
if ($ext -eq '.dbc') {
|
||||
# dbc = tabela cu index structural .dcx; fara el FoxBin2Prg cere indexul intr-un dialog modal (hang)
|
||||
$dcx = Find-InDir $dir ($base + '.dcx')
|
||||
if ($dcx) { Copy-Item -LiteralPath $dcx.FullName -Destination (Join-Path $stageDir $dcx.Name) -Force }
|
||||
}
|
||||
|
||||
if ($ext -eq '.dbf') {
|
||||
# index structural + (daca e tabela legata de DBC) containerul: FoxBin2Prg le cere ca sa deschida tabela
|
||||
$cdx = Find-InDir $dir ($base + '.cdx')
|
||||
if ($cdx) { Copy-Item -LiteralPath $cdx.FullName -Destination (Join-Path $stageDir $cdx.Name) -Force }
|
||||
Get-ChildItem -LiteralPath $dir -File -ErrorAction SilentlyContinue |
|
||||
Where-Object { '.dbc','.dct','.dcx' -contains $_.Extension.ToLower() } |
|
||||
ForEach-Object { Copy-Item -LiteralPath $_.FullName -Destination (Join-Path $stageDir $_.Name) -Force }
|
||||
# onoreaza order/condition custom din .dbf.cfg comis, daca exista
|
||||
$cfg = Find-InDir $dir ($base + '.dbf.cfg')
|
||||
if ($cfg) { Copy-Item -LiteralPath $cfg.FullName -Destination (Join-Path $stageDir $cfg.Name) -Force }
|
||||
}
|
||||
|
||||
$r = Invoke-Fb2p -InputFile $stageBin
|
||||
if ($r.TimedOut) { return 'fail:timeout bin->text' }
|
||||
if ($r.ExitCode -ne 0) { return "fail:bin->text ErrorLevel=$($r.ExitCode)" }
|
||||
|
||||
$stageTxt = Find-InDir $stageDir ($base + $txtX)
|
||||
if (-not $stageTxt) { return 'fail:text negenerat' }
|
||||
if ($stageTxt.Length -eq 0) { return 'fail:text gol' }
|
||||
|
||||
# scutite (clase FFC cu #INCLUDE): roundtrip izolat = fals-negativ; doar bin->text valid, fara write-back
|
||||
$exempt = $script:ExemptSet.Contains($Bin.FullName.ToLower())
|
||||
|
||||
# fidelitate per tip: roundtrip complet doar vcx/scx (mai putin cele scutite)
|
||||
if (($ext -eq '.vcx' -or $ext -eq '.scx') -and -not $exempt) {
|
||||
$rc2 = Join-Path $stageDir 'rc'
|
||||
New-Item -ItemType Directory -Force -Path $rc2 | Out-Null
|
||||
$txt1 = Join-Path $rc2 $stageTxt.Name
|
||||
Copy-Item -LiteralPath $stageTxt.FullName -Destination $txt1 -Force
|
||||
$r2 = Invoke-Fb2p -InputFile $txt1 -Recompile $ProjectRoot
|
||||
if ($r2.TimedOut -or $r2.ExitCode -ne 0) { return "fail:roundtrip text->bin ErrorLevel=$($r2.ExitCode)" }
|
||||
$bin2 = Find-InDir $rc2 ($base + $ext)
|
||||
if (-not $bin2) { return 'fail:roundtrip bin nerecreat' }
|
||||
$r3 = Invoke-Fb2p -InputFile $bin2.FullName
|
||||
if ($r3.TimedOut -or $r3.ExitCode -ne 0) { return "fail:roundtrip bin->text2 ErrorLevel=$($r3.ExitCode)" }
|
||||
$txt2 = Find-InDir $rc2 ($base + $txtX)
|
||||
if (-not $txt2) { return 'fail:roundtrip text2 negenerat' }
|
||||
if (-not (Test-BytesEqual ([IO.File]::ReadAllBytes($stageTxt.FullName)) ([IO.File]::ReadAllBytes($txt2.FullName)))) {
|
||||
return 'fail:roundtrip text1 != text2'
|
||||
}
|
||||
}
|
||||
|
||||
if ($ext -eq '.dbf' -and $stageTxt.Length -gt ($MaxDb2Mb * 1MB)) {
|
||||
$script:BigDb2 += ("{0} ({1:N1} MB)" -f (Get-RelPath $Bin.FullName), ($stageTxt.Length / 1MB))
|
||||
}
|
||||
|
||||
# copiaza inapoi DOAR textul (raw bytes), pastrand numele produs de FoxBin2Prg
|
||||
$destTxt = if ($txtExisting) { $txtExisting.FullName } else { Join-Path $dir $stageTxt.Name }
|
||||
Copy-Item -LiteralPath $stageTxt.FullName -Destination $destTxt -Force
|
||||
# mtime text >= mtime binar, altfel pare stale si se reconverteste mereu
|
||||
$destItem = Get-Item -LiteralPath $destTxt
|
||||
$newestBin = $Bin.LastWriteTime
|
||||
if ($memo -and $memo.LastWriteTime -gt $newestBin) { $newestBin = $memo.LastWriteTime }
|
||||
if ($destItem.LastWriteTime -lt $newestBin) { $destItem.LastWriteTime = $newestBin.AddSeconds(1) }
|
||||
if ($exempt) { return 'ok-exempt' }
|
||||
return 'ok'
|
||||
} finally {
|
||||
Remove-Item -Recurse -Force -LiteralPath $stageDir -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
|
||||
function Get-RelPath([string]$full) {
|
||||
if ($full.ToLower().StartsWith($ProjectRoot.ToLower())) { return $full.Substring($ProjectRoot.Length).TrimStart('\') }
|
||||
return $full
|
||||
}
|
||||
|
||||
# =========================== MAIN ===========================
|
||||
$scanRoot = if ($SubDir) { Join-Path $ProjectRoot $SubDir } else { $ProjectRoot }
|
||||
if (-not (Test-Path -LiteralPath $scanRoot)) { throw "SubDir nu exista: $scanRoot" }
|
||||
|
||||
Write-Host "=== git_sync: ProjectRoot=$ProjectRoot SubDir=$(if($SubDir){$SubDir}else{'(tot)'}) Types=$($Types -join ',') ==="
|
||||
|
||||
# --- lista dbf din patternurile per proiect (cai absolute, set pt orfani) ---
|
||||
$script:DbfInList = New-Object System.Collections.Generic.HashSet[string]
|
||||
foreach ($pat in $DbfList) {
|
||||
$full = Join-Path $ProjectRoot $pat
|
||||
Get-ChildItem -Path $full -File -ErrorAction SilentlyContinue |
|
||||
Where-Object { $_.Extension.ToLower() -eq '.dbf' } |
|
||||
ForEach-Object { [void]$script:DbfInList.Add($_.FullName.ToLower()) }
|
||||
}
|
||||
|
||||
# --- construieste lista de binare de convertit ---
|
||||
$script:BigDb2 = @()
|
||||
$binList = @()
|
||||
$typeExts = $Types | ForEach-Object { '.' + $_.ToLower() }
|
||||
$binList += Get-ChildItem -LiteralPath $scanRoot -Recurse -File -ErrorAction SilentlyContinue |
|
||||
Where-Object { $typeExts -contains $_.Extension.ToLower() }
|
||||
# dbf-urile din lista aflate sub scanRoot
|
||||
$binList += $script:DbfInList | ForEach-Object { Get-Item -LiteralPath $_ -ErrorAction SilentlyContinue } |
|
||||
Where-Object { $_ -and $_.FullName.ToLower().StartsWith(((Get-Item -LiteralPath $scanRoot).FullName).ToLower()) }
|
||||
|
||||
$ok=0; $up=0; $failures=@()
|
||||
foreach ($b in $binList) {
|
||||
$status = Convert-One -Bin $b
|
||||
$rel = Get-RelPath $b.FullName
|
||||
switch -Wildcard ($status) {
|
||||
'ok' { $ok++; Write-Host "OK $rel" }
|
||||
'ok-exempt' { $ok++; Write-Host "OK $rel (roundtrip scutit)" }
|
||||
'uptodate' { $up++ }
|
||||
'fail:*' { $failures += [PSCustomObject]@{ File=$rel; Reason=$status.Substring(5) }; Write-Warning "ESEC $rel -- $($status.Substring(5))" }
|
||||
}
|
||||
}
|
||||
|
||||
# --- curatare orfani (doar pe tot arborele) ---
|
||||
$orphansDeleted = @()
|
||||
if (-not $SubDir) {
|
||||
$allText = Get-ChildItem -LiteralPath $ProjectRoot -Recurse -File -ErrorAction SilentlyContinue |
|
||||
Where-Object { $script:TextExts.ContainsKey($_.Extension.ToLower()) }
|
||||
foreach ($t in $allText) {
|
||||
$tRel = Get-RelPath $t.FullName
|
||||
if (@($OrphanExempt | Where-Object { $tRel -like $_ }).Count -gt 0) { continue }
|
||||
$tExt = $t.Extension.ToLower()
|
||||
$binExt = $script:TextExts[$tExt]
|
||||
$base = [IO.Path]::GetFileNameWithoutExtension($t.Name)
|
||||
$bin = Find-InDir $t.DirectoryName ($base + $binExt)
|
||||
$isOrphan = $false
|
||||
if (-not $bin) {
|
||||
$isOrphan = $true # binar sters
|
||||
} elseif ($tExt -eq '.db2' -and -not $script:DbfInList.Contains($bin.FullName.ToLower())) {
|
||||
$isOrphan = $true # tabela a iesit din lista
|
||||
}
|
||||
if ($isOrphan) {
|
||||
$orphansDeleted += $tRel
|
||||
if ($OrphanCleanup -and -not $NoOrphanCleanup) { Remove-Item -LiteralPath $t.FullName -Force -ErrorAction SilentlyContinue }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Remove-Item -Recurse -Force -LiteralPath $stagingRoot -ErrorAction SilentlyContinue
|
||||
|
||||
# --- raport ---
|
||||
Write-Host ''
|
||||
Write-Host "--- Sumar git_sync ---"
|
||||
Write-Host "Convertite: $ok Sarite(la zi): $up Esuate: $($failures.Count)"
|
||||
if ($orphansDeleted.Count -gt 0) {
|
||||
$verb = if ($OrphanCleanup -and -not $NoOrphanCleanup) { 'sterse' } else { 'raportate (nesterse)' }
|
||||
Write-Host "Orfani ${verb}: $($orphansDeleted.Count)"
|
||||
$orphansDeleted | ForEach-Object { Write-Host " orfan: $_" }
|
||||
}
|
||||
if ($script:BigDb2.Count -gt 0) {
|
||||
Write-Warning "db2 peste ${MaxDb2Mb} MB (scoate tabela din lista, ramane binara):"
|
||||
$script:BigDb2 | ForEach-Object { Write-Warning " $_" }
|
||||
}
|
||||
if ($failures.Count -gt 0) {
|
||||
Write-Host ''
|
||||
Write-Host "ESECURI (nu comite pana nu sunt explicate):"
|
||||
$failures | ForEach-Object { Write-Host " $($_.File) -- $($_.Reason)" }
|
||||
exit 1
|
||||
}
|
||||
Write-Host "OK: fara esecuri."
|
||||
exit 0
|
||||
45
roa_sync.ps1
45
roa_sync.ps1
@@ -1,45 +0,0 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
STUB de compatibilitate: roa_sync.ps1 s-a MUTAT in COMUN\scripts\roa_sync.ps1
|
||||
(se distribuie automat prin svn update, ca restul COMUN).
|
||||
|
||||
.DESCRIPTION
|
||||
Deleaga la copia proiectului: <ProjectRoot>\COMUN\scripts\roa_sync.ps1. Daca lipseste
|
||||
(working copy neactualizat inca), face intai svn update pe proiect ca sa o aduca.
|
||||
Actualizeaza lansatoarele (roa_sync.bat) sa cheme direct COMUN\scripts\roa_sync.ps1.
|
||||
#>
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[string]$ProjectRoot = '',
|
||||
[switch]$GitOnly
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
if (-not $ProjectRoot) {
|
||||
$cwd = (Get-Location).Path
|
||||
$hasGit = Test-Path -LiteralPath (Join-Path $cwd '.git')
|
||||
$hasPjx = @(Get-ChildItem -LiteralPath $cwd -Filter '*.pjx' -File -ErrorAction SilentlyContinue).Count -gt 0
|
||||
if ($hasGit -and $hasPjx) {
|
||||
$ProjectRoot = $cwd
|
||||
} else {
|
||||
Write-Host "EROARE: -ProjectRoot nedat si directorul curent nu pare radacina de proiect ROA (lipseste .git sau .pjx): $cwd"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
$target = Join-Path $ProjectRoot 'COMUN\scripts\roa_sync.ps1'
|
||||
if (-not (Test-Path -LiteralPath $target)) {
|
||||
Write-Host "roa_sync.ps1 s-a mutat in COMUN\scripts si lipseste inca din working copy - rulez svn update ca sa il aduc."
|
||||
& svn update $ProjectRoot
|
||||
if (-not (Test-Path -LiteralPath $target)) {
|
||||
Write-Host "EROARE: $target lipseste si dupa svn update. Verifica externalul COMUN."
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "NOTA: roa_sync.ps1 s-a mutat in COMUN\scripts\. Actualizeaza lansatorul sa cheme direct: $target"
|
||||
$extra = @()
|
||||
if ($GitOnly) { $extra += '-GitOnly' }
|
||||
& powershell -ExecutionPolicy Bypass -NoProfile -File $target -ProjectRoot $ProjectRoot @extra
|
||||
exit $LASTEXITCODE
|
||||
@@ -1,72 +0,0 @@
|
||||
@echo off
|
||||
rem Sincronizeaza romfast cu upstream. Fara /push: doar local. Cu /push: trimite pe Gitea.
|
||||
rem Se auto-copiaza in TEMP si ruleaza de acolo, ca sa nu dispara de pe disc
|
||||
rem cand scriptul face "git checkout master" (fisierul exista doar pe romfast).
|
||||
setlocal enabledelayedexpansion
|
||||
if not "%SYNC_ROMFAST_RELAUNCHED%"=="1" (
|
||||
set "SYNC_ROMFAST_ORIGDIR=%~dp0"
|
||||
set "SYNC_ROMFAST_RELAUNCHED=1"
|
||||
set "SYNC_ROMFAST_TMPBAT=!TEMP!\sync_romfast_!RANDOM!.bat"
|
||||
copy /y "%~f0" "!SYNC_ROMFAST_TMPBAT!" >nul
|
||||
call "!SYNC_ROMFAST_TMPBAT!" %*
|
||||
set "SYNC_ROMFAST_EC=!ERRORLEVEL!"
|
||||
del "!SYNC_ROMFAST_TMPBAT!" >nul 2>&1
|
||||
exit /b !SYNC_ROMFAST_EC!
|
||||
)
|
||||
cd /d "%SYNC_ROMFAST_ORIGDIR%"
|
||||
|
||||
for /f "delims=" %%u in ('git remote get-url origin') do set GITHUB=%%u
|
||||
for /f "delims=" %%u in ('git remote get-url romfast') do set GITEA=%%u
|
||||
|
||||
set STASHED=0
|
||||
set DIRTY=
|
||||
for /f "delims=" %%s in ('git status --porcelain') do set DIRTY=1
|
||||
if defined DIRTY (
|
||||
echo Ai modificari necomise:
|
||||
git status -s
|
||||
set /p ANSWER="Ce fac cu ele? (c = commit, s = stash, n = opresc) [c/s/n] "
|
||||
if /i "!ANSWER!"=="s" (
|
||||
git stash push -u -m "sync_romfast auto-stash" -- . ":(exclude)sync_romfast.bat" ":(exclude)sync_romfast.ps1" || exit /b 1
|
||||
set STASHED=1
|
||||
) else if /i "!ANSWER!"=="c" (
|
||||
set /p MSG="Mesaj de commit (Enter = mesaj implicit): "
|
||||
if "!MSG!"=="" set MSG=Actualizari locale inainte de sincronizare
|
||||
git add -A
|
||||
git commit -m "!MSG!"
|
||||
) else (
|
||||
echo Oprit. Comite sau fa stash manual, apoi ruleaza din nou scriptul.
|
||||
exit /b 1
|
||||
)
|
||||
)
|
||||
|
||||
echo GitHub (origin) %GITHUB% --^> master
|
||||
echo Gitea (romfast) %GITEA% --^> romfast
|
||||
|
||||
git fetch origin || exit /b 1
|
||||
git checkout master || exit /b 1
|
||||
git merge --ff-only origin/master || (echo master a divergat de origin/master, verifica manual. & exit /b 1)
|
||||
|
||||
git checkout romfast || exit /b 1
|
||||
git merge master || (echo Conflicte la merge master -^> romfast, rezolva manual ^(git status^). & exit /b 1)
|
||||
|
||||
git log --oneline -5
|
||||
|
||||
if "%STASHED%"=="1" (
|
||||
echo Restaurez modificarile din stash...
|
||||
git stash pop || (echo Conflicte la restaurarea stash-ului, rezolva manual ^(git stash list / git stash pop^). & exit /b 1)
|
||||
)
|
||||
|
||||
set DOPUSH=0
|
||||
if /i "%~1"=="/push" set DOPUSH=1
|
||||
if "%DOPUSH%"=="0" (
|
||||
set /p ANSWER="Local la zi. Fac push acum catre Gitea (romfast)? (y/n) "
|
||||
if /i "!ANSWER!"=="y" set DOPUSH=1
|
||||
)
|
||||
|
||||
if "%DOPUSH%"=="1" (
|
||||
git push romfast master || exit /b 1
|
||||
git push romfast romfast || exit /b 1
|
||||
echo Push facut catre %GITEA%
|
||||
) else (
|
||||
echo Push sarit. Inainte de push: DO ReCreate_FoxBin2Prg.prg in VFP9, apoi ruleaza cu /push.
|
||||
)
|
||||
@@ -1,65 +0,0 @@
|
||||
# Sincronizeaza romfast cu upstream. Fara -Push: doar local. Cu -Push: trimite pe Gitea.
|
||||
param([switch]$Push)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
Set-Location $PSScriptRoot
|
||||
|
||||
$GITHUB = git remote get-url origin
|
||||
$GITEA = git remote get-url romfast
|
||||
|
||||
$stashed = $false
|
||||
$dirty = git status --porcelain
|
||||
if ($dirty) {
|
||||
Write-Host "Ai modificari necomise:" -ForegroundColor Yellow
|
||||
git status -s
|
||||
$answer = Read-Host "Ce fac cu ele? (c = commit, s = stash, n = opresc) [c/s/n]"
|
||||
switch ($answer) {
|
||||
's' {
|
||||
git stash push -u -m "sync_romfast auto-stash" -- . ":(exclude)sync_romfast.bat" ":(exclude)sync_romfast.ps1"
|
||||
$stashed = $true
|
||||
}
|
||||
'c' {
|
||||
$msg = Read-Host "Mesaj de commit (Enter = mesaj implicit)"
|
||||
if (-not $msg) { $msg = "Actualizari locale inainte de sincronizare" }
|
||||
git add -A
|
||||
git commit -m $msg
|
||||
}
|
||||
default {
|
||||
Write-Host "Oprit. Comite sau fa stash manual, apoi ruleaza din nou scriptul." -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "GitHub (origin) $GITHUB --> master" -ForegroundColor Cyan
|
||||
Write-Host "Gitea (romfast) $GITEA --> romfast" -ForegroundColor Cyan
|
||||
|
||||
git fetch origin
|
||||
git checkout master
|
||||
git merge --ff-only origin/master
|
||||
if ($LASTEXITCODE -ne 0) { throw "master a divergat de origin/master, verifica manual." }
|
||||
|
||||
git checkout romfast
|
||||
git merge master
|
||||
if ($LASTEXITCODE -ne 0) { throw "Conflicte la merge master -> romfast, rezolva manual (git status)." }
|
||||
|
||||
git log --oneline -5
|
||||
|
||||
if ($stashed) {
|
||||
Write-Host "Restaurez modificarile din stash..." -ForegroundColor Cyan
|
||||
git stash pop
|
||||
if ($LASTEXITCODE -ne 0) { throw "Conflicte la restaurarea stash-ului, rezolva manual (git stash list / git stash pop)." }
|
||||
}
|
||||
|
||||
if (-not $Push) {
|
||||
$answer = Read-Host "Local la zi. Fac push acum catre Gitea (romfast)? (y/n)"
|
||||
if ($answer -eq 'y') { $Push = $true }
|
||||
}
|
||||
|
||||
if ($Push) {
|
||||
git push romfast master
|
||||
git push romfast romfast
|
||||
Write-Host "Push facut catre $GITEA" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "Push sarit. Inainte de push: DO ReCreate_FoxBin2Prg.prg in VFP9, apoi ruleaza cu -Push." -ForegroundColor Yellow
|
||||
}
|
||||
@@ -1,256 +0,0 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Teste standalone (fara Pester) pentru git_sync.ps1, pe fixture-uri construite in TEMP.
|
||||
Acopera cele 4 comportamente noi cerute de plan (Sectiunea 8, decizie eng-review D2):
|
||||
(A) incremental - a doua rulare pe fixture neschimbat nu reconverteste nimic (Convertite=0, Sarite>0);
|
||||
(B) curatare orfani - un .vc2 fara binar se sterge si se raporteaza; un .db2 a carui
|
||||
tabela a iesit din -DbfList se sterge si se raporteaza;
|
||||
(C) esec partial - un .vcx corupt produce exit nenul si apare in esecuri, DAR fisierele
|
||||
valide din aceeasi rulare se convertesc totusi;
|
||||
(D) protectia binarului - dupa orice rulare, toate binarele fixture-ului sunt byte-identice
|
||||
(SHA256 inainte/dupa). Verificat si dupa fiecare rulare din A/B/C.
|
||||
(E) scutire roundtrip - fisierul din -RoundtripExempt produce text fara garda de roundtrip;
|
||||
(F) scutire orfani - textul din -OrphanExempt nu e raportat ca orfan, restul da.
|
||||
|
||||
Fixture: copie a celui mai mic .vcx+.vct real din Clase si a setului Locale (dbf+memo+indecsi+
|
||||
container dbc) din proiectul sursa. NU se scrie nimic in proiectul sursa - doar se citeste/copiaza.
|
||||
Se copiaza DOAR binarele si memo-urile, niciodata textul .??2 deja prezent in sursa.
|
||||
|
||||
.PARAMETER SourceProject
|
||||
Proiectul din care se copiaza esantioanele de binare (implicit ROACONT).
|
||||
#>
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[string]$SourceProject = 'D:\ROA\ROACONT'
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$script:GitSync = 'D:\ROA\UTIL\foxbin2prg\git_sync.ps1'
|
||||
$script:Failures = @()
|
||||
# extensiile considerate "binar" in fixture (tot ce NU e text .??2 generat)
|
||||
$script:BinExts = @('.vcx','.vct','.dbf','.fpt','.cdx','.dbc','.dct','.dcx')
|
||||
|
||||
function Assert([bool]$cond, [string]$msg) {
|
||||
if ($cond) { Write-Host " PASS: $msg" -ForegroundColor Green }
|
||||
else { Write-Host " FAIL: $msg" -ForegroundColor Red; $script:Failures += $msg }
|
||||
}
|
||||
|
||||
# --- Ruleaza git_sync.ps1 ca proces copil si parseaza sumarul + orfanii + exit code ---
|
||||
function Invoke-GitSync {
|
||||
param([string]$Fixture, [string[]]$DbfList, [string[]]$Exempt, [string[]]$OrphanExempt, [int]$TimeoutSeconds = 30)
|
||||
# -Command (nu -File): powershell.exe -File colapseaza 'a','b' intr-un singur token, DbfList ar fi gol
|
||||
$dbfLit = if ($DbfList -and $DbfList.Count) { '@(' + (($DbfList | ForEach-Object { "'" + $_ + "'" }) -join ',') + ')' } else { '@()' }
|
||||
$exLit = if ($Exempt -and $Exempt.Count) { '@(' + (($Exempt | ForEach-Object { "'" + $_ + "'" }) -join ',') + ')' } else { '@()' }
|
||||
$cmd = "& '$script:GitSync' -ProjectRoot '$Fixture' -DbfList $dbfLit -RoundtripExempt $exLit -TimeoutSeconds $TimeoutSeconds"
|
||||
# fara -OrphanExempt explicit ramane valoarea implicita din git_sync.ps1 (testul F o verifica)
|
||||
if ($OrphanExempt) {
|
||||
$cmd += ' -OrphanExempt @(' + (($OrphanExempt | ForEach-Object { "'" + $_ + "'" }) -join ',') + ')'
|
||||
}
|
||||
# EAP=Continue local: git_sync ruleaza FoxBin2Prg care scrie pe stderr (ex. 'not a table');
|
||||
# sub EAP=Stop, capturarea 2>&1 a acelui stderr ar arunca NativeCommandError si ar opri testul.
|
||||
$prevEAP = $ErrorActionPreference
|
||||
$ErrorActionPreference = 'Continue'
|
||||
$sw = [Diagnostics.Stopwatch]::StartNew()
|
||||
$raw = & powershell -ExecutionPolicy Bypass -Command $cmd 2>&1 | Out-String
|
||||
$exit = $LASTEXITCODE
|
||||
$sw.Stop()
|
||||
$ErrorActionPreference = $prevEAP
|
||||
$conv = $null; $skip = $null; $fail = $null
|
||||
$m = [regex]::Match($raw, 'Convertite:\s*(\d+)\s+Sarite\(la zi\):\s*(\d+)\s+Esuate:\s*(\d+)')
|
||||
if ($m.Success) { $conv = [int]$m.Groups[1].Value; $skip = [int]$m.Groups[2].Value; $fail = [int]$m.Groups[3].Value }
|
||||
$orphans = @()
|
||||
foreach ($line in ($raw -split "`r?`n")) {
|
||||
$om = [regex]::Match($line, '^\s*orfan:\s*(.+?)\s*$')
|
||||
if ($om.Success) { $orphans += $om.Groups[1].Value }
|
||||
}
|
||||
return [PSCustomObject]@{ Exit=$exit; Convertite=$conv; Sarite=$skip; Esuate=$fail; Orphans=$orphans; Raw=$raw; ElapsedSec=[math]::Round($sw.Elapsed.TotalSeconds,1); TimeoutSec=$TimeoutSeconds }
|
||||
}
|
||||
|
||||
# --- Snapshot SHA256 al tuturor binarelor din fixture (pt protectia binarului) ---
|
||||
function Get-BinSnapshot([string]$root) {
|
||||
$h = @{}
|
||||
Get-ChildItem -LiteralPath $root -Recurse -File -ErrorAction SilentlyContinue |
|
||||
Where-Object { $script:BinExts -contains $_.Extension.ToLower() } |
|
||||
ForEach-Object { $h[$_.FullName.ToLower()] = (Get-FileHash -LiteralPath $_.FullName -Algorithm SHA256).Hash }
|
||||
return $h
|
||||
}
|
||||
|
||||
function Assert-BinariesUnchanged([hashtable]$before, [string]$root, [string]$ctx) {
|
||||
$after = Get-BinSnapshot $root
|
||||
$why = ''
|
||||
if ($before.Count -ne $after.Count) { $why = "numar binare $($before.Count)->$($after.Count)" }
|
||||
else {
|
||||
foreach ($k in $before.Keys) {
|
||||
if (-not $after.ContainsKey($k)) { $why = "lipsa dupa rulare: $k"; break }
|
||||
if ($after[$k] -ne $before[$k]) { $why = "modificat: $k"; break }
|
||||
}
|
||||
}
|
||||
Assert ($why -eq '') "${ctx}: toate binarele byte-identice dupa rulare$(if($why){" ($why)"})"
|
||||
}
|
||||
|
||||
# --- Construieste un fixture in TEMP: atentie.vcx+.vct + setul Locale (fara text .??2) ---
|
||||
function New-Fixture([string]$tag) {
|
||||
$fx = Join-Path $env:TEMP ("gs_test_{0}_{1}_{2}" -f $tag, $PID, ([Guid]::NewGuid().ToString('N').Substring(0,8)))
|
||||
New-Item -ItemType Directory -Force -Path (Join-Path $fx 'Clase'), (Join-Path $fx 'Locale') | Out-Null
|
||||
# doar .vcx + .vct (memo); NU .vc2 care exista deja in sursa dintr-o rulare anterioara
|
||||
Get-ChildItem (Join-Path $SourceProject 'Clase') -Filter 'atentie.*' -File |
|
||||
Where-Object { @('.vcx','.vct') -contains $_.Extension.ToLower() } |
|
||||
ForEach-Object { Copy-Item -LiteralPath $_.FullName -Destination (Join-Path $fx 'Clase') -Force }
|
||||
# set Locale: doua tabele (pt scenariul de scoatere din lista) + indecsi + container dbc
|
||||
foreach ($f in 'locale.dbf','locale.FPT','locale.CDX','locale.dbc','locale.DCT','locale.DCX','locale_lang.dbf','locale_lang.FPT','locale_lang.cdx') {
|
||||
$s = Join-Path $SourceProject "Locale\$f"
|
||||
if (Test-Path -LiteralPath $s) { Copy-Item -LiteralPath $s -Destination (Join-Path $fx 'Locale') -Force }
|
||||
}
|
||||
return $fx
|
||||
}
|
||||
|
||||
# Sterge fixture-ul + folderul-parinte de staging lasat de git_sync (TEMP\git_sync_<leaf>, ramane gol)
|
||||
function Remove-Fixture([string]$fx) {
|
||||
Remove-Item -Recurse -Force -LiteralPath $fx -ErrorAction SilentlyContinue
|
||||
$stagingParent = Join-Path $env:TEMP ("git_sync_" + (Split-Path $fx -Leaf))
|
||||
Remove-Item -Recurse -Force -LiteralPath $stagingParent -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
$script:BothDbf = @('Locale\locale.dbf','Locale\locale_lang.dbf')
|
||||
|
||||
# ============================== SCENARIILE ==============================
|
||||
|
||||
function Test-Incremental {
|
||||
Write-Host "`n--- (A) incremental: a doua rulare nu reconverteste nimic ---"
|
||||
$fx = New-Fixture 'inc'
|
||||
try {
|
||||
$snap = Get-BinSnapshot $fx
|
||||
$r1 = Invoke-GitSync -Fixture $fx -DbfList $script:BothDbf
|
||||
Assert ($r1.Exit -eq 0) "A: prima rulare exit 0 (exit=$($r1.Exit))"
|
||||
Assert ($r1.Convertite -gt 0) "A: prima rulare converteste (Convertite=$($r1.Convertite) > 0)"
|
||||
Assert-BinariesUnchanged $snap $fx "A(run1)"
|
||||
|
||||
$r2 = Invoke-GitSync -Fixture $fx -DbfList $script:BothDbf
|
||||
Assert ($r2.Exit -eq 0) "A: a doua rulare exit 0 (exit=$($r2.Exit))"
|
||||
Assert ($r2.Convertite -eq 0) "A: a doua rulare NU reconverteste (Convertite=$($r2.Convertite) = 0)"
|
||||
Assert ($r2.Sarite -gt 0) "A: a doua rulare sare fisierele la zi (Sarite=$($r2.Sarite) > 0)"
|
||||
Assert-BinariesUnchanged $snap $fx "A(run2)"
|
||||
} finally { Remove-Fixture $fx }
|
||||
}
|
||||
|
||||
function Test-Orphans {
|
||||
Write-Host "`n--- (B) curatare orfani: .vc2 fara binar + .db2 iesit din lista ---"
|
||||
$fx = New-Fixture 'orf'
|
||||
try {
|
||||
# orfan de tip 1: text .vc2 fara binar .vcx corespondent
|
||||
$orfVc2 = Join-Path $fx 'Clase\_orfan.vc2'
|
||||
Set-Content -LiteralPath $orfVc2 -Value '* text orfan fara binar corespondent' -Encoding Ascii
|
||||
$snap = Get-BinSnapshot $fx
|
||||
|
||||
# run1: ambele tabele in lista -> produce db2-uri; orfanul fara binar se sterge
|
||||
$r1 = Invoke-GitSync -Fixture $fx -DbfList $script:BothDbf
|
||||
Assert (-not (Test-Path -LiteralPath $orfVc2)) "B: .vc2 orfan (fara binar) sters"
|
||||
Assert (($r1.Orphans -join ';') -match '(?i)_orfan\.vc2') "B: .vc2 orfan raportat in sumar"
|
||||
Assert (Test-Path -LiteralPath (Join-Path $fx 'Locale\locale_lang.db2')) "B: locale_lang.db2 creat in run1"
|
||||
Assert-BinariesUnchanged $snap $fx "B(run1)"
|
||||
|
||||
# run2: locale_lang scos din lista -> db2-ul lui iese din lista -> orfan
|
||||
$r2 = Invoke-GitSync -Fixture $fx -DbfList @('Locale\locale.dbf')
|
||||
Assert (-not (Test-Path -LiteralPath (Join-Path $fx 'Locale\locale_lang.db2'))) "B: db2 al tabelei iesite din lista sters"
|
||||
Assert (($r2.Orphans -join ';') -match '(?i)locale_lang\.db2') "B: db2 iesit din lista raportat in sumar"
|
||||
Assert (Test-Path -LiteralPath (Join-Path $fx 'Locale\locale.db2')) "B: db2 al tabelei ramase in lista pastrat"
|
||||
Assert-BinariesUnchanged $snap $fx "B(run2)"
|
||||
} finally { Remove-Fixture $fx }
|
||||
}
|
||||
|
||||
function Test-PartialFailure {
|
||||
Write-Host "`n--- (C) esec partial: binar corupt esueaza, restul se convertesc ---"
|
||||
$fx = New-Fixture 'fail'
|
||||
try {
|
||||
# binar corupt: octeti garbage in .vcx si .vct (FoxBin2Prg: 'not a table', ErrorLevel != 0)
|
||||
$g1 = New-Object byte[] 800; (New-Object Random).NextBytes($g1)
|
||||
[IO.File]::WriteAllBytes((Join-Path $fx 'Clase\corupt.vcx'), $g1)
|
||||
$g2 = New-Object byte[] 600; (New-Object Random).NextBytes($g2)
|
||||
[IO.File]::WriteAllBytes((Join-Path $fx 'Clase\corupt.vct'), $g2)
|
||||
$snap = Get-BinSnapshot $fx
|
||||
|
||||
$r = Invoke-GitSync -Fixture $fx -DbfList @('Locale\locale.dbf')
|
||||
Assert ($r.Exit -ne 0) "C: exit nenul la esec partial (exit=$($r.Exit))"
|
||||
Assert ($r.Esuate -ge 1) "C: cel putin un esec raportat (Esuate=$($r.Esuate))"
|
||||
Assert ($r.Raw -match '(?i)corupt\.vcx') "C: fisierul corupt apare in lista de esecuri"
|
||||
Assert ($r.Convertite -ge 1) "C: fisierele valide se convertesc totusi (Convertite=$($r.Convertite))"
|
||||
Assert (Test-Path -LiteralPath (Join-Path $fx 'Clase\atentie.vc2')) "C: text valid (atentie.vc2) produs in ciuda esecului"
|
||||
# esecul trebuie sa fie rapid (ErrorLevel, nu dialog modal): sub watchdog inseamna ca nu a aparut MessageBox VFP
|
||||
Assert ($r.ElapsedSec -lt $r.TimeoutSec) "C: esec rapid fara dialog modal ($($r.ElapsedSec)s < watchdog $($r.TimeoutSec)s)"
|
||||
Assert-BinariesUnchanged $snap $fx "C"
|
||||
} finally { Remove-Fixture $fx }
|
||||
}
|
||||
|
||||
function Test-BinaryProtection {
|
||||
Write-Host "`n--- (D) protectia binarului: byte-identic dupa conversie completa ---"
|
||||
$fx = New-Fixture 'bin'
|
||||
try {
|
||||
$snap = Get-BinSnapshot $fx
|
||||
Assert ($snap.Count -gt 0) "D: fixture-ul contine binare de protejat ($($snap.Count))"
|
||||
$r = Invoke-GitSync -Fixture $fx -DbfList $script:BothDbf
|
||||
Assert ($r.Exit -eq 0) "D: rulare curata (exit=$($r.Exit))"
|
||||
Assert-BinariesUnchanged $snap $fx "D"
|
||||
} finally { Remove-Fixture $fx }
|
||||
}
|
||||
|
||||
function Test-Exempt {
|
||||
Write-Host "`n--- (E) scutire roundtrip: fisierul din -RoundtripExempt produce text fara garda roundtrip ---"
|
||||
$fx = New-Fixture 'exempt'
|
||||
try {
|
||||
$snap = Get-BinSnapshot $fx
|
||||
$r = Invoke-GitSync -Fixture $fx -DbfList @('Locale\locale.dbf') -Exempt @('Clase\atentie.vcx')
|
||||
Assert ($r.Exit -eq 0) "E: rulare curata cu scutire (exit=$($r.Exit))"
|
||||
Assert ($r.Raw -match '(?i)atentie\.vcx \(roundtrip scutit\)') "E: fisierul scutit raportat 'roundtrip scutit'"
|
||||
Assert (Test-Path -LiteralPath (Join-Path $fx 'Clase\atentie.vc2')) "E: text produs pentru fisierul scutit"
|
||||
Assert-BinariesUnchanged $snap $fx "E"
|
||||
} finally { Remove-Fixture $fx }
|
||||
}
|
||||
|
||||
function Test-OrphanExempt {
|
||||
Write-Host "`n--- (F) scutire orfani: textul din -OrphanExempt nu e raportat, restul da ---"
|
||||
$fx = New-Fixture 'orphanexempt'
|
||||
try {
|
||||
# textul scutit implicit: stub-ul de test din COMUN, al carui .scx e gitignored si generat local
|
||||
$stubDir = Join-Path $fx 'COMUN\utile\Teste\achizitie_import\stub_verificare'
|
||||
New-Item -ItemType Directory -Path $stubDir -Force | Out-Null
|
||||
$stub = Join-Path $stubDir 'verificare.sc2'
|
||||
Set-Content -LiteralPath $stub -Value '* stub de test, binarul se genereaza local' -Encoding Ascii
|
||||
# martor: text fara binar in afara scutirii -> trebuie raportat in continuare
|
||||
$ctrl = Join-Path $fx 'Clase\_orfan.sc2'
|
||||
Set-Content -LiteralPath $ctrl -Value '* text orfan fara binar corespondent' -Encoding Ascii
|
||||
|
||||
$r = Invoke-GitSync -Fixture $fx -DbfList @('Locale\locale.dbf')
|
||||
$orf = $r.Orphans -join ';'
|
||||
Assert ($r.Exit -eq 0) "F: rulare curata cu scutire de orfani (exit=$($r.Exit))"
|
||||
Assert ($orf -notmatch '(?i)verificare\.sc2') "F: textul scutit NU e raportat ca orfan"
|
||||
Assert (Test-Path -LiteralPath $stub) "F: textul scutit ramane pe disc"
|
||||
Assert ($orf -match '(?i)_orfan\.sc2') "F: orfanul din afara scutirii e raportat in continuare"
|
||||
|
||||
# cu pattern explicit care nu-l acopera, stub-ul redevine orfan raportat
|
||||
$r2 = Invoke-GitSync -Fixture $fx -DbfList @('Locale\locale.dbf') -OrphanExempt @('*\nimic_care_nu_exista.sc2')
|
||||
Assert ((($r2.Orphans -join ';')) -match '(?i)verificare\.sc2') "F: fara pattern-ul potrivit, stub-ul e raportat ca orfan"
|
||||
} finally { Remove-Fixture $fx }
|
||||
}
|
||||
|
||||
# ============================== MAIN ==============================
|
||||
if (-not (Test-Path -LiteralPath $script:GitSync)) { throw "Nu gasesc git_sync.ps1: $script:GitSync" }
|
||||
if (-not (Test-Path -LiteralPath $SourceProject)) { throw "Proiect sursa inexistent: $SourceProject" }
|
||||
|
||||
Write-Host "=== test_git_sync.ps1 -- SourceProject=$SourceProject ==="
|
||||
Test-Incremental
|
||||
Test-Orphans
|
||||
Test-PartialFailure
|
||||
Test-BinaryProtection
|
||||
Test-Exempt
|
||||
Test-OrphanExempt
|
||||
|
||||
Write-Host "`n=== REZULTAT ==="
|
||||
if ($script:Failures.Count -eq 0) {
|
||||
Write-Host "TOATE testele au trecut." -ForegroundColor Green
|
||||
exit 0
|
||||
} else {
|
||||
Write-Host "$($script:Failures.Count) test(e) esuate:" -ForegroundColor Red
|
||||
$script:Failures | ForEach-Object { Write-Host " - $_" -ForegroundColor Red }
|
||||
exit 1
|
||||
}
|
||||
|
||||
@@ -1,507 +0,0 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Teste standalone (fara Pester) pentru fluxul bin<->text VFP (FoxBin2Prg) si scriptul
|
||||
de write-back txt2vcx.ps1. Parametrizat per proiect (implicit ROAGEST).
|
||||
|
||||
.DESCRIPTION
|
||||
Faze:
|
||||
- fidelity : esantion din FIECARE tip convertit, auto-descoperit din arborele proiectului.
|
||||
vcx/scx -> roundtrip complet bin->text1->bin->text2 (comparare pe octeti);
|
||||
frx/mnx/lbx/dbc/pjx/dbf -> doar validare bin->text (exit code + timeout + text nevid).
|
||||
Totul in temp, nimic scris in proiect.
|
||||
- edit : editare reala via txt2vcx.ps1 pe fixture-uri cunoscute (implicit ROAGEST);
|
||||
daca fixture-ul lipseste in proiect, se sare (warn). Restaurarea binarelor
|
||||
se face din backup temp (NU git checkout - binarele sunt git-ignored dupa migrare).
|
||||
- negative : text stricat, fisier gol, guard-uri (staleness, binar lipsa, cale in afara
|
||||
cache-ului, extensie nesuportata, COMUN, folder-foxbin2prg, -DryRun),
|
||||
test multi-fisier. Textul stricat ruleaza DOAR in cache temp, niciodata in arbore.
|
||||
- smoke : fidelity pe cate un .vcx din proiectele frate (-SmokeProjects).
|
||||
- all : toate cele de mai sus, in ordine.
|
||||
|
||||
Restaurare: orice binar atins de write-back e copiat in backup temp INAINTE si restaurat
|
||||
la final (in finally), cu asertie byte-identic fata de original. Cache-ul text implicit e
|
||||
un director temporar creat pentru rulare (decuplat de arborele proiectului).
|
||||
|
||||
Exit 1 daca orice Assert a esuat, CU EXCEPTIA celor marcate warn-only.
|
||||
|
||||
.PARAMETER ProjectRoot
|
||||
Radacina proiectului principal testat (implicit ROAGEST).
|
||||
|
||||
.PARAMETER CacheRoot
|
||||
Cache-ul text folosit de teste. Gol (implicit) => director temporar creat/sters de test,
|
||||
ca sa nu se scrie niciodata text in arborele proiectului.
|
||||
|
||||
.PARAMETER Phase
|
||||
all | fidelity | edit | negative | smoke
|
||||
|
||||
.PARAMETER SmokeProjects
|
||||
Lista proiectelor frate pentru faza smoke.
|
||||
#>
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[string]$ProjectRoot = 'D:\ROA\ROAGEST',
|
||||
[string]$CacheRoot = '',
|
||||
[ValidateSet('all','fidelity','edit','negative','smoke')]
|
||||
[string]$Phase = 'all',
|
||||
[string[]]$SmokeProjects = @('D:\ROA\ROAIMOB','D:\ROA\ROAACNPRO')
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$exe = 'D:\ROA\UTIL\foxbin2prg\FoxBin2Prg.EXE'
|
||||
$vcx2txt = 'D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1'
|
||||
$txt2vcx = 'D:\ROA\UTIL\foxbin2prg\txt2vcx.ps1'
|
||||
. (Join-Path $PSScriptRoot 'vfp_filemap.ps1')
|
||||
|
||||
$script:Failures = @()
|
||||
$script:Enc = [Text.Encoding]::GetEncoding(1252)
|
||||
$script:BackupRoot = Join-Path $env:TEMP ("fb2p_test_backup_{0}_{1}" -f $PID, ([Guid]::NewGuid().ToString('N').Substring(0,8)))
|
||||
$script:Backups = @{} # cheie: cale binar (lower) -> info backup, pt restaurare la final
|
||||
|
||||
function Assert([bool]$cond, [string]$msg) {
|
||||
if ($cond) { Write-Host " PASS: $msg" -ForegroundColor Green }
|
||||
else { Write-Host " FAIL: $msg" -ForegroundColor Red; $script:Failures += $msg }
|
||||
}
|
||||
|
||||
function AssertWarn([bool]$cond, [string]$msg) {
|
||||
if ($cond) { Write-Host " PASS(warn-only): $msg" -ForegroundColor Green }
|
||||
else { Write-Warning " WARN (non-blocant): $msg" }
|
||||
}
|
||||
|
||||
function Normalize-Crlf([byte[]]$bytes) {
|
||||
$out = New-Object System.Collections.Generic.List[byte]
|
||||
for ($i = 0; $i -lt $bytes.Length; $i++) {
|
||||
if ($bytes[$i] -eq 0x0D) {
|
||||
if ($i + 1 -lt $bytes.Length -and $bytes[$i+1] -eq 0x0A) { continue }
|
||||
$out.Add(0x0A) | Out-Null
|
||||
} else { $out.Add($bytes[$i]) | Out-Null }
|
||||
}
|
||||
return $out.ToArray()
|
||||
}
|
||||
|
||||
function Test-BytesEqual([byte[]]$a, [byte[]]$b) {
|
||||
$na = Normalize-Crlf $a; $nb = Normalize-Crlf $b
|
||||
if ($na.Length -ne $nb.Length) { return $false }
|
||||
for ($i = 0; $i -lt $na.Length; $i++) { if ($na[$i] -ne $nb[$i]) { return $false } }
|
||||
return $true
|
||||
}
|
||||
|
||||
function Invoke-Fb2p {
|
||||
# Watchdog obligatoriu - FoxBin2Prg poate afisa un MessageBox modal nativ VFP la text stricat;
|
||||
# fara asta, faza negativa ar ramane agatata la infinit intr-o rulare automata.
|
||||
param([string]$InputFile, [string]$Recompile = '', [int]$TimeoutSeconds = 60)
|
||||
# cfg in dir-ul input-ului: DontShowErrors suprima MessageBox-ul propriu FoxBin2Prg (ca in git_sync)
|
||||
$cfgLines = [System.Collections.Generic.List[string]]@('DontShowErrors: 1','ShowProgressbar: 0')
|
||||
if ([IO.Path]::GetExtension($InputFile).ToLower() -eq '.dbf') { $cfgLines.Add('DBF_Conversion_Support: 4') }
|
||||
Set-Content -LiteralPath (Join-Path (Split-Path -Parent $InputFile) 'foxbin2prg.cfg') -Value $cfgLines -Encoding Ascii
|
||||
if ($Recompile) {
|
||||
$r = Invoke-FoxBin2PrgSafe -ExePath $exe -ExeArgs @($InputFile,'','','','1','0','1','',$Recompile) -TimeoutSeconds $TimeoutSeconds
|
||||
} else {
|
||||
$r = Invoke-FoxBin2PrgSafe -ExePath $exe -ExeArgs @($InputFile,'','','','1','0','1') -TimeoutSeconds $TimeoutSeconds
|
||||
}
|
||||
if ($r.TimedOut) { Write-Warning "Invoke-Fb2p: timeout pe '$InputFile' - tratat ca ESEC." }
|
||||
return $r.ExitCode
|
||||
}
|
||||
|
||||
function Get-FileHashBytes([string]$path) {
|
||||
if (-not (Test-Path -LiteralPath $path)) { return $null }
|
||||
return (Get-FileHash -LiteralPath $path -Algorithm SHA256).Hash
|
||||
}
|
||||
|
||||
function Get-RelPath([string]$Root, [string]$Full) {
|
||||
return $Full.Substring($Root.TrimEnd('\').Length).TrimStart('\')
|
||||
}
|
||||
|
||||
# --- Auto-descoperire: un esantion mic non-COMUN de tipul cerut, cu memo companion ---
|
||||
function Find-SampleBinary {
|
||||
param(
|
||||
[Parameter(Mandatory)][string]$ProjRoot,
|
||||
[Parameter(Mandatory)][string]$Ext,
|
||||
[bool]$RequireMemo = $true,
|
||||
[int]$MaxBytes = 500000
|
||||
)
|
||||
if (-not (Test-Path -LiteralPath $ProjRoot)) { return $null }
|
||||
$memoExt = $script:VfpFileMap[$Ext][0]
|
||||
Get-ChildItem -LiteralPath $ProjRoot -Recurse -File -Filter ("*" + $Ext) -ErrorAction SilentlyContinue |
|
||||
Where-Object {
|
||||
$_.FullName -notmatch '(?i)\\COMUN\\' -and
|
||||
$_.Length -le $MaxBytes -and $_.Length -gt 0 -and
|
||||
(-not $RequireMemo -or (Test-Path -LiteralPath ([IO.Path]::ChangeExtension($_.FullName, $memoExt))))
|
||||
} |
|
||||
Sort-Object Length |
|
||||
Select-Object -First 1
|
||||
}
|
||||
|
||||
# --- Backup/restore binare din temp (inlocuieste git checkout - binarele sunt git-ignored) ---
|
||||
function Backup-ProjectBinary([string]$fullBin) {
|
||||
$key = $fullBin.ToLower()
|
||||
if ($script:Backups.ContainsKey($key)) { return }
|
||||
$ext = [IO.Path]::GetExtension($fullBin).ToLower()
|
||||
$memoExt = $script:VfpFileMap[$ext][0]
|
||||
$dir = Split-Path $fullBin -Parent
|
||||
$base = [IO.Path]::GetFileNameWithoutExtension($fullBin)
|
||||
$memoEntry = Get-ChildItem -LiteralPath $dir -Filter ($base + $memoExt) -ErrorAction SilentlyContinue | Select-Object -First 1
|
||||
$memoFull = if ($memoEntry) { $memoEntry.FullName } else { [IO.Path]::ChangeExtension($fullBin, $memoExt) }
|
||||
$bdir = Join-Path $script:BackupRoot ([Guid]::NewGuid().ToString('N').Substring(0,8))
|
||||
New-Item -ItemType Directory -Force -Path $bdir | Out-Null
|
||||
$binBak = Join-Path $bdir (Split-Path $fullBin -Leaf)
|
||||
Copy-Item -LiteralPath $fullBin -Destination $binBak -Force
|
||||
$memoBak = $null
|
||||
if (Test-Path -LiteralPath $memoFull) {
|
||||
$memoBak = Join-Path $bdir (Split-Path $memoFull -Leaf)
|
||||
Copy-Item -LiteralPath $memoFull -Destination $memoBak -Force
|
||||
}
|
||||
$script:Backups[$key] = @{ BinFull=$fullBin; BinBak=$binBak; MemoFull=$memoFull; MemoBak=$memoBak; OrigHash=(Get-FileHashBytes $fullBin) }
|
||||
}
|
||||
|
||||
function Restore-ProjectBinaries {
|
||||
foreach ($k in @($script:Backups.Keys)) {
|
||||
$b = $script:Backups[$k]
|
||||
Copy-Item -LiteralPath $b.BinBak -Destination $b.BinFull -Force
|
||||
if ($b.MemoBak) { Copy-Item -LiteralPath $b.MemoBak -Destination $b.MemoFull -Force }
|
||||
$now = Get-FileHashBytes $b.BinFull
|
||||
Assert ($now -eq $b.OrigHash) "Restore: $(Split-Path $b.BinFull -Leaf) byte-identic cu originalul dupa restore"
|
||||
}
|
||||
}
|
||||
|
||||
# --- Fidelitate: roundtrip complet bin->text1->bin->text2 (doar in temp) - pt vcx/scx ---
|
||||
function Test-FidelityRoundtrip {
|
||||
param(
|
||||
[Parameter(Mandatory)][string]$RelPath,
|
||||
[Parameter(Mandatory)][string]$ProjRoot,
|
||||
[bool]$WarnOnly = $false
|
||||
)
|
||||
$full = Join-Path $ProjRoot $RelPath
|
||||
if (-not (Test-Path -LiteralPath $full)) { AssertWarn $false "Faza A: fisier lipsa, sarit: $RelPath"; return }
|
||||
$ext = [IO.Path]::GetExtension($full).ToLower()
|
||||
$pair = $script:VfpFileMap[$ext]
|
||||
if (-not $pair) { AssertWarn $false "Faza A: extensie necunoscuta, sarit: $RelPath"; return }
|
||||
$memoExt = $pair[0]; $txtExt = $pair[1]
|
||||
$memoFull = [IO.Path]::ChangeExtension($full, $memoExt)
|
||||
|
||||
$work = Join-Path $env:TEMP ("fb2p_fidelity_{0}_{1}" -f $PID, ([Guid]::NewGuid().ToString('N').Substring(0,8)))
|
||||
New-Item -ItemType Directory -Force -Path $work | Out-Null
|
||||
try {
|
||||
$baseName = [IO.Path]::GetFileNameWithoutExtension($full)
|
||||
$bin1 = Join-Path $work ($baseName + $ext); $memo1 = Join-Path $work ($baseName + $memoExt)
|
||||
Copy-Item -LiteralPath $full -Destination $bin1 -Force
|
||||
if (Test-Path -LiteralPath $memoFull) { Copy-Item -LiteralPath $memoFull -Destination $memo1 -Force }
|
||||
$rc1 = Invoke-Fb2p -InputFile $bin1
|
||||
$text1 = Join-Path $work ($baseName + $txtExt)
|
||||
if ($rc1 -ne 0 -or -not (Test-Path -LiteralPath $text1)) {
|
||||
if ($WarnOnly) { AssertWarn $false "Faza A ($RelPath): Bin2Prg #1 a esuat (ErrorLevel=$rc1)"; return }
|
||||
Assert $false "Faza A ($RelPath): Bin2Prg #1 a esuat (ErrorLevel=$rc1)"
|
||||
return
|
||||
}
|
||||
|
||||
$stage2 = Join-Path $work 'stage2'
|
||||
New-Item -ItemType Directory -Force -Path $stage2 | Out-Null
|
||||
$text1copy = Join-Path $stage2 ($baseName + $txtExt)
|
||||
Copy-Item -LiteralPath $text1 -Destination $text1copy -Force
|
||||
$rc2 = Invoke-Fb2p -InputFile $text1copy -Recompile $ProjRoot
|
||||
$bin2 = Join-Path $stage2 ($baseName + $ext); $memo2 = Join-Path $stage2 ($baseName + $memoExt)
|
||||
if ($rc2 -ne 0 -or -not (Test-Path -LiteralPath $bin2) -or -not (Test-Path -LiteralPath $memo2)) {
|
||||
$ok = $false
|
||||
} else {
|
||||
$rc3 = Invoke-Fb2p -InputFile $bin2
|
||||
$text2 = Join-Path $stage2 ($baseName + $txtExt)
|
||||
$ok = ($rc3 -eq 0) -and (Test-Path -LiteralPath $text2) -and (Test-BytesEqual ([IO.File]::ReadAllBytes($text1)) ([IO.File]::ReadAllBytes($text2)))
|
||||
}
|
||||
if ($WarnOnly) { AssertWarn $ok "Faza A ($RelPath): text1 == text2 dupa roundtrip complet" }
|
||||
else { Assert $ok "Faza A ($RelPath): text1 == text2 dupa roundtrip complet" }
|
||||
} finally {
|
||||
Remove-Item -Recurse -Force -LiteralPath $work -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
|
||||
# --- Validare bin->text (fara roundtrip) - pt frx/mnx/lbx/dbc/pjx/dbf (write-back nesuportat) ---
|
||||
function Test-BinToTextValid {
|
||||
param(
|
||||
[Parameter(Mandatory)][string]$RelPath,
|
||||
[Parameter(Mandatory)][string]$ProjRoot,
|
||||
[bool]$WarnOnly = $false
|
||||
)
|
||||
$full = Join-Path $ProjRoot $RelPath
|
||||
if (-not (Test-Path -LiteralPath $full)) { AssertWarn $false "Faza A: fisier lipsa, sarit: $RelPath"; return }
|
||||
$ext = [IO.Path]::GetExtension($full).ToLower()
|
||||
$pair = $script:VfpFileMap[$ext]
|
||||
if (-not $pair) { AssertWarn $false "Faza A: extensie necunoscuta, sarit: $RelPath"; return }
|
||||
$memoExt = $pair[0]; $txtExt = $pair[1]
|
||||
$memoFull = [IO.Path]::ChangeExtension($full, $memoExt)
|
||||
|
||||
$work = Join-Path $env:TEMP ("fb2p_valid_{0}_{1}" -f $PID, ([Guid]::NewGuid().ToString('N').Substring(0,8)))
|
||||
New-Item -ItemType Directory -Force -Path $work | Out-Null
|
||||
try {
|
||||
$baseName = [IO.Path]::GetFileNameWithoutExtension($full)
|
||||
$bin1 = Join-Path $work ($baseName + $ext)
|
||||
Copy-Item -LiteralPath $full -Destination $bin1 -Force
|
||||
if (Test-Path -LiteralPath $memoFull) { Copy-Item -LiteralPath $memoFull -Destination (Join-Path $work ($baseName + $memoExt)) -Force }
|
||||
$rc = Invoke-Fb2p -InputFile $bin1
|
||||
$text1 = Join-Path $work ($baseName + $txtExt)
|
||||
$ok = ($rc -eq 0) -and (Test-Path -LiteralPath $text1) -and ((Get-Item -LiteralPath $text1).Length -gt 0)
|
||||
$msg = "Faza A ($RelPath): bin->text valid (exit=$rc, text nevid)"
|
||||
if ($WarnOnly) { AssertWarn $ok $msg } else { Assert $ok $msg }
|
||||
} finally {
|
||||
Remove-Item -Recurse -Force -LiteralPath $work -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
|
||||
# specificatie per tip convertit: roundtrip doar vcx/scx; restul doar validare bin->text
|
||||
$script:FidelitySpec = @(
|
||||
@{ Ext='.vcx'; Roundtrip=$true; WarnOnly=$false; RequireMemo=$true }
|
||||
@{ Ext='.scx'; Roundtrip=$true; WarnOnly=$false; RequireMemo=$true }
|
||||
@{ Ext='.frx'; Roundtrip=$false; WarnOnly=$true; RequireMemo=$true }
|
||||
@{ Ext='.mnx'; Roundtrip=$false; WarnOnly=$true; RequireMemo=$true }
|
||||
@{ Ext='.lbx'; Roundtrip=$false; WarnOnly=$true; RequireMemo=$true }
|
||||
@{ Ext='.dbc'; Roundtrip=$false; WarnOnly=$true; RequireMemo=$true }
|
||||
@{ Ext='.pjx'; Roundtrip=$false; WarnOnly=$true; RequireMemo=$true }
|
||||
@{ Ext='.dbf'; Roundtrip=$false; WarnOnly=$true; RequireMemo=$false }
|
||||
)
|
||||
|
||||
function Invoke-FidelityForProject([string]$ProjRoot) {
|
||||
foreach ($s in $script:FidelitySpec) {
|
||||
$sample = Find-SampleBinary -ProjRoot $ProjRoot -Ext $s.Ext -RequireMemo $s.RequireMemo
|
||||
if (-not $sample) { AssertWarn $false "Faza A: niciun esantion $($s.Ext) in $ProjRoot, sarit"; continue }
|
||||
$rel = Get-RelPath $ProjRoot $sample.FullName
|
||||
Write-Host " esantion $($s.Ext): $rel ($([int]($sample.Length/1024)) KB)"
|
||||
if ($s.Roundtrip) { Test-FidelityRoundtrip -RelPath $rel -ProjRoot $ProjRoot -WarnOnly $s.WarnOnly }
|
||||
else { Test-BinToTextValid -RelPath $rel -ProjRoot $ProjRoot -WarnOnly $s.WarnOnly }
|
||||
}
|
||||
}
|
||||
|
||||
# --- Editare reala prin txt2vcx.ps1, cu backup/restore (nu git) ---
|
||||
function Test-EditRoundtrip {
|
||||
param(
|
||||
[Parameter(Mandatory)][string]$RelPath,
|
||||
[Parameter(Mandatory)][string]$CaptionOld,
|
||||
[Parameter(Mandatory)][string]$CaptionNew,
|
||||
[Parameter(Mandatory)][string]$ProcedureMarker
|
||||
)
|
||||
$full = Join-Path $ProjectRoot $RelPath
|
||||
if (-not (Test-Path -LiteralPath $full)) { AssertWarn $false "Faza B: fixture lipsa in proiect, sarit: $RelPath"; return }
|
||||
$ext = [IO.Path]::GetExtension($RelPath).ToLower()
|
||||
$pair = $script:VfpFileMap[$ext]
|
||||
$txtExt = $pair[1]
|
||||
$relDir = Split-Path $RelPath -Parent
|
||||
$base = [IO.Path]::GetFileNameWithoutExtension($RelPath)
|
||||
$relText = if ($relDir) { Join-Path $relDir ($base + $txtExt) } else { $base + $txtExt }
|
||||
|
||||
Write-Host "-- Faza B: $RelPath --"
|
||||
Backup-ProjectBinary $full
|
||||
$origHash = $script:Backups[$full.ToLower()].OrigHash
|
||||
|
||||
& $vcx2txt -Source $full -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot -Force | Out-Null
|
||||
$cacheText = Join-Path $CacheRoot $relText
|
||||
Assert (Test-Path -LiteralPath $cacheText) "Faza B ($RelPath): cache text regenerat"
|
||||
|
||||
$text = $script:Enc.GetString([IO.File]::ReadAllBytes($cacheText))
|
||||
Assert ($text.Contains($CaptionOld)) "Faza B ($RelPath): linia Caption originala gasita"
|
||||
$text = $text.Replace($CaptionOld, $CaptionNew)
|
||||
$marker = "`t" + $ProcedureMarker + "`r`n"
|
||||
$idx = $text.IndexOf($marker)
|
||||
Assert ($idx -ge 0) "Faza B ($RelPath): marker '$ProcedureMarker' gasit"
|
||||
if ($idx -ge 0) {
|
||||
$insertPos = $idx + $marker.Length
|
||||
$text = $text.Substring(0,$insertPos) + "`t`t* test roundtrip`r`n" + $text.Substring($insertPos)
|
||||
}
|
||||
[IO.File]::WriteAllBytes($cacheText, $script:Enc.GetBytes($text))
|
||||
|
||||
& $txt2vcx -TextFile $cacheText -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot
|
||||
$rc = $LASTEXITCODE
|
||||
Assert ($rc -eq 0) "Faza B ($RelPath): txt2vcx.ps1 exit 0"
|
||||
|
||||
Assert ((Get-FileHashBytes $full) -ne $origHash) "Faza B ($RelPath): binarul din proiect a fost rescris (hash diferit de original)"
|
||||
$bakStray = Join-Path (Join-Path $ProjectRoot $relDir) ($base + '.bak')
|
||||
Assert (-not (Test-Path -LiteralPath $bakStray)) "Faza B ($RelPath): fara .bak lasat in proiect"
|
||||
|
||||
$regenText = $script:Enc.GetString([IO.File]::ReadAllBytes($cacheText))
|
||||
Assert ($regenText.Contains($CaptionNew)) "Faza B ($RelPath): textul regenerat contine Caption editat"
|
||||
Assert ($regenText.Contains('* test roundtrip')) "Faza B ($RelPath): textul regenerat contine comentariul adaugat"
|
||||
# binarul e restaurat din backup in finally-ul global
|
||||
}
|
||||
|
||||
# ============================== MAIN ==============================
|
||||
$ownCache = $false
|
||||
if ([string]::IsNullOrWhiteSpace($CacheRoot)) {
|
||||
$CacheRoot = Join-Path $env:TEMP ("fb2p_test_cache_{0}_{1}" -f $PID, ([Guid]::NewGuid().ToString('N').Substring(0,8)))
|
||||
$ownCache = $true
|
||||
}
|
||||
if (-not (Test-Path -LiteralPath $CacheRoot)) { New-Item -ItemType Directory -Force -Path $CacheRoot | Out-Null }
|
||||
New-Item -ItemType Directory -Force -Path $script:BackupRoot | Out-Null
|
||||
|
||||
Write-Host "=== test_roundtrip.ps1 -- ProjectRoot=$ProjectRoot CacheRoot=$CacheRoot Phase=$Phase ==="
|
||||
|
||||
# fixture-uri de editare cunoscute (implicit ROAGEST); se sar automat daca lipsesc in proiect
|
||||
$editFixtures = @(
|
||||
@{ Rel='Clase\oavize.vcx'; Old='Lb_titlu_alb_b121.Caption = "Date aviz"'; New='Lb_titlu_alb_b121.Caption = "Atentie-diacritice-ok"'; Marker='PROCEDURE Init' }
|
||||
@{ Rel='Ferestre\fundal.scx'; Old='Caption = ""'; New='Caption = "test"'; Marker='PROCEDURE Show' }
|
||||
)
|
||||
|
||||
try {
|
||||
if ($Phase -eq 'all' -or $Phase -eq 'fidelity') {
|
||||
Write-Host "`n--- FAZA A: fidelitate (esantion din fiecare tip convertit) ---"
|
||||
Invoke-FidelityForProject $ProjectRoot
|
||||
}
|
||||
|
||||
if ($Phase -eq 'all' -or $Phase -eq 'edit') {
|
||||
Write-Host "`n--- FAZA B: editare reala (write-back) ---"
|
||||
foreach ($fx in $editFixtures) {
|
||||
Test-EditRoundtrip -RelPath $fx.Rel -CaptionOld $fx.Old -CaptionNew $fx.New -ProcedureMarker $fx.Marker
|
||||
}
|
||||
}
|
||||
|
||||
if ($Phase -eq 'all' -or $Phase -eq 'smoke') {
|
||||
Write-Host "`n--- FAZA C: smoke pe proiecte frate ---"
|
||||
foreach ($sp in $SmokeProjects) {
|
||||
if (-not (Test-Path -LiteralPath $sp)) { AssertWarn $false "Faza C: proiect lipsa $sp, sarit"; continue }
|
||||
$s = Find-SampleBinary -ProjRoot $sp -Ext '.vcx'
|
||||
if ($s) { Test-FidelityRoundtrip -RelPath (Get-RelPath $sp $s.FullName) -ProjRoot $sp }
|
||||
else { AssertWarn $false "Faza C: niciun .vcx in $sp, sarit" }
|
||||
}
|
||||
}
|
||||
|
||||
if ($Phase -eq 'all' -or $Phase -eq 'negative') {
|
||||
Write-Host "`n--- FAZA D: negativ + guard-uri + multi-fisier ---"
|
||||
$vcxSample = Find-SampleBinary -ProjRoot $ProjectRoot -Ext '.vcx'
|
||||
if (-not $vcxSample) {
|
||||
AssertWarn $false "Faza D: niciun .vcx in $ProjectRoot, faza sarita"
|
||||
} else {
|
||||
$vcxRel = Get-RelPath $ProjectRoot $vcxSample.FullName
|
||||
$vcxFull = $vcxSample.FullName
|
||||
$vcxDir = Split-Path $vcxRel -Parent
|
||||
$vcxBase = [IO.Path]::GetFileNameWithoutExtension($vcxRel)
|
||||
$vcxRelText = if ($vcxDir) { Join-Path $vcxDir ($vcxBase + '.vc2') } else { $vcxBase + '.vc2' }
|
||||
Write-Host " esantion negativ .vcx: $vcxRel"
|
||||
Backup-ProjectBinary $vcxFull
|
||||
$origVcxHash = Get-FileHashBytes $vcxFull # baseline curent (independent de backup) pt asertii "neatins"
|
||||
|
||||
& $vcx2txt -Source $vcxFull -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot -Force | Out-Null
|
||||
$cacheText = Join-Path $CacheRoot $vcxRelText
|
||||
Assert (Test-Path -LiteralPath $cacheText) "Faza D: text esantion generat pentru $vcxRel"
|
||||
$origBytes = [IO.File]::ReadAllBytes($cacheText)
|
||||
|
||||
# (a) text stricat: adauga o clasa neinchisa -> recompilare esueaza (doar in cache temp)
|
||||
$text = $script:Enc.GetString($origBytes)
|
||||
$brokenSuffix = "`r`nDEFINE CLASS _brokenzzz AS Custom`r`n"
|
||||
[IO.File]::WriteAllBytes($cacheText, $script:Enc.GetBytes($text + $brokenSuffix))
|
||||
& $txt2vcx -TextFile $cacheText -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot
|
||||
Assert ($LASTEXITCODE -ne 0) "Faza D (a): txt2vcx exit != 0 pe text stricat (DEFINE CLASS neinchis)"
|
||||
Assert ((Get-FileHashBytes $vcxFull) -eq $origVcxHash) "Faza D (a): binarul esantion neatins in proiect"
|
||||
[IO.File]::WriteAllBytes($cacheText, $origBytes)
|
||||
|
||||
# (b) fisier text gol
|
||||
[IO.File]::WriteAllBytes($cacheText, [byte[]]@())
|
||||
& $txt2vcx -TextFile $cacheText -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot
|
||||
Assert ($LASTEXITCODE -ne 0) "Faza D (b): txt2vcx exit != 0 pe fisier text gol"
|
||||
Assert ((Get-FileHashBytes $vcxFull) -eq $origVcxHash) "Faza D (b): binarul esantion neatins in proiect"
|
||||
[IO.File]::WriteAllBytes($cacheText, $origBytes)
|
||||
|
||||
# (guard) staleness: binar mai nou decat textul -> refuz fara -Force
|
||||
$origMtime = (Get-Item -LiteralPath $vcxFull).LastWriteTime
|
||||
(Get-Item -LiteralPath $vcxFull).LastWriteTime = (Get-Date).AddDays(1)
|
||||
try {
|
||||
[IO.File]::WriteAllBytes($cacheText, $origBytes)
|
||||
& $txt2vcx -TextFile $cacheText -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot
|
||||
Assert ($LASTEXITCODE -ne 0) "Faza D (guard staleness): refuz fara -Force cand binarul e mai nou"
|
||||
Assert ((Get-FileHashBytes $vcxFull) -eq $origVcxHash) "Faza D (guard staleness): binar neatins"
|
||||
} finally {
|
||||
(Get-Item -LiteralPath $vcxFull).LastWriteTime = $origMtime
|
||||
}
|
||||
|
||||
# (guard) binar tinta lipsa -> refuz PERMANENT (si cu -Force)
|
||||
$missingCacheText = Join-Path $CacheRoot $(if ($vcxDir) { Join-Path $vcxDir '_nu_exista_deloc.vc2' } else { '_nu_exista_deloc.vc2' })
|
||||
New-Item -ItemType Directory -Force -Path (Split-Path $missingCacheText -Parent) | Out-Null
|
||||
[IO.File]::WriteAllBytes($missingCacheText, $script:Enc.GetBytes("* fake`r`nDEFINE CLASS x AS y`r`nENDDEFINE`r`n"))
|
||||
try {
|
||||
& $txt2vcx -TextFile $missingCacheText -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot -Force
|
||||
Assert ($LASTEXITCODE -ne 0) "Faza D (guard binar lipsa): refuz chiar si cu -Force"
|
||||
} finally { Remove-Item -LiteralPath $missingCacheText -Force -ErrorAction SilentlyContinue }
|
||||
|
||||
# (guard) cale text in afara CacheRoot -> refuz
|
||||
$outsideText = Join-Path $env:TEMP ('_outside_' + [Guid]::NewGuid().ToString('N').Substring(0,8) + '.vc2')
|
||||
[IO.File]::WriteAllBytes($outsideText, $origBytes)
|
||||
try {
|
||||
& $txt2vcx -TextFile $outsideText -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot
|
||||
Assert ($LASTEXITCODE -ne 0) "Faza D (guard cale in afara CacheRoot): refuz"
|
||||
} finally { Remove-Item -LiteralPath $outsideText -Force -ErrorAction SilentlyContinue }
|
||||
|
||||
# (guard) extensie nesuportata (.mn2)
|
||||
$unsupported = Join-Path $CacheRoot $(if ($vcxDir) { Join-Path $vcxDir '_fake.mn2' } else { '_fake.mn2' })
|
||||
[IO.File]::WriteAllBytes($unsupported, $script:Enc.GetBytes("* fake mn2`r`n"))
|
||||
try {
|
||||
& $txt2vcx -TextFile $unsupported -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot
|
||||
Assert ($LASTEXITCODE -ne 0) "Faza D (guard extensie nesuportata .mn2): refuz"
|
||||
} finally { Remove-Item -LiteralPath $unsupported -Force -ErrorAction SilentlyContinue }
|
||||
|
||||
# (guard) COMUN fara -AllowComun -> refuz (-DryRun, zero scrieri)
|
||||
$comunText = Join-Path $CacheRoot 'COMUN\clase\_fake.vc2'
|
||||
New-Item -ItemType Directory -Force -Path (Split-Path $comunText -Parent) | Out-Null
|
||||
[IO.File]::WriteAllBytes($comunText, $origBytes)
|
||||
try {
|
||||
& $txt2vcx -TextFile $comunText -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot -DryRun
|
||||
Assert ($LASTEXITCODE -ne 0) "Faza D (guard COMUN, fara -AllowComun): refuz"
|
||||
} finally { Remove-Item -Recurse -Force -LiteralPath (Split-Path $comunText -Parent) -ErrorAction SilentlyContinue }
|
||||
|
||||
# (guard) folder-foxbin2prg -> refuz necondiționat (-DryRun)
|
||||
$fb2pCache = Join-Path $env:TEMP ('_fb2pguard_' + [Guid]::NewGuid().ToString('N').Substring(0,8))
|
||||
New-Item -ItemType Directory -Force -Path $fb2pCache | Out-Null
|
||||
$fb2pText = Join-Path $fb2pCache 'fake.vc2'
|
||||
[IO.File]::WriteAllBytes($fb2pText, $origBytes)
|
||||
try {
|
||||
& $txt2vcx -TextFile $fb2pText -ProjectRoot 'D:\ROA\UTIL\foxbin2prg' -CacheRoot $fb2pCache -DryRun
|
||||
Assert ($LASTEXITCODE -ne 0) "Faza D (guard folder-foxbin2prg): refuz necondiționat"
|
||||
} finally { Remove-Item -Recurse -Force -LiteralPath $fb2pCache -ErrorAction SilentlyContinue }
|
||||
|
||||
# (-DryRun caz valid): nimic modificat in proiect, exit 0
|
||||
[IO.File]::WriteAllBytes($cacheText, $origBytes)
|
||||
& $txt2vcx -TextFile $cacheText -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot -DryRun
|
||||
Assert ($LASTEXITCODE -eq 0) "Faza D (-DryRun, caz valid): exit 0"
|
||||
Assert ((Get-FileHashBytes $vcxFull) -eq $origVcxHash) "Faza D (-DryRun, caz valid): binar neatins in proiect"
|
||||
|
||||
# --- multi-fisier: un scx valid (scris) + vcx stricat (refuzat) in aceeasi rulare ---
|
||||
$scxSample = Find-SampleBinary -ProjRoot $ProjectRoot -Ext '.scx'
|
||||
if ($scxSample) {
|
||||
$scxRel = Get-RelPath $ProjectRoot $scxSample.FullName
|
||||
$scxFull = $scxSample.FullName
|
||||
$scxDir = Split-Path $scxRel -Parent
|
||||
$scxBase = [IO.Path]::GetFileNameWithoutExtension($scxRel)
|
||||
$scxRelText = if ($scxDir) { Join-Path $scxDir ($scxBase + '.sc2') } else { $scxBase + '.sc2' }
|
||||
Backup-ProjectBinary $scxFull
|
||||
$scxOrigMtime = (Get-Item -LiteralPath $scxFull).LastWriteTime
|
||||
|
||||
& $vcx2txt -Source $scxFull -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot -Force | Out-Null
|
||||
$scxCacheText = Join-Path $CacheRoot $scxRelText
|
||||
$scxText = $script:Enc.GetString([IO.File]::ReadAllBytes($scxCacheText))
|
||||
$m = [regex]::Match($scxText, "(?m)^\tPROCEDURE \w+\r?\n")
|
||||
if ($m.Success) {
|
||||
$pos = $m.Index + $m.Length
|
||||
$scxText = $scxText.Substring(0,$pos) + "`t`t* test multi`r`n" + $scxText.Substring($pos)
|
||||
[IO.File]::WriteAllBytes($scxCacheText, $script:Enc.GetBytes($scxText))
|
||||
}
|
||||
[IO.File]::WriteAllBytes($cacheText, $script:Enc.GetBytes($text + $brokenSuffix))
|
||||
|
||||
& $txt2vcx -TextFile @($scxCacheText, $cacheText) -ProjectRoot $ProjectRoot -CacheRoot $CacheRoot
|
||||
Assert ($LASTEXITCODE -eq 1) "Faza D (multi-fisier): exit agregat = 1 (unul din doua a esuat)"
|
||||
Assert ((Get-FileHashBytes $vcxFull) -eq $origVcxHash) "Faza D (multi-fisier): vcx stricat neatins in proiect"
|
||||
Assert (((Get-Item -LiteralPath $scxFull).LastWriteTime) -ne $scxOrigMtime) "Faza D (multi-fisier): scx valid a fost scris in proiect (mtime schimbat)"
|
||||
[IO.File]::WriteAllBytes($cacheText, $origBytes)
|
||||
} else {
|
||||
AssertWarn $false "Faza D (multi-fisier): niciun .scx in $ProjectRoot, sarit"
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
Write-Host "`n--- Cleanup final: restore binare din backup + curatare temp ---"
|
||||
Restore-ProjectBinaries
|
||||
if ($ownCache -and (Test-Path -LiteralPath $CacheRoot)) { Remove-Item -Recurse -Force -LiteralPath $CacheRoot -ErrorAction SilentlyContinue }
|
||||
if (Test-Path -LiteralPath $script:BackupRoot) { Remove-Item -Recurse -Force -LiteralPath $script:BackupRoot -ErrorAction SilentlyContinue }
|
||||
}
|
||||
|
||||
Write-Host "`n=== REZULTAT ==="
|
||||
if ($script:Failures.Count -eq 0) {
|
||||
Write-Host "TOATE testele au trecut (Phase=$Phase)." -ForegroundColor Green
|
||||
exit 0
|
||||
} else {
|
||||
Write-Host "$($script:Failures.Count) test(e) esuate:" -ForegroundColor Red
|
||||
$script:Failures | ForEach-Object { Write-Host " - $_" -ForegroundColor Red }
|
||||
exit 1
|
||||
}
|
||||
320
txt2vcx.ps1
320
txt2vcx.ps1
@@ -1,320 +0,0 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Scrie inapoi in proiect binarele VFP (.vcx+.vct / .scx+.sct) regenerate din textul editat
|
||||
in cache (.vc2/.sc2). Fratele "invers" al vcx2txt.ps1.
|
||||
|
||||
.DESCRIPTION
|
||||
Flux complet text->bin, cu verificari de siguranta inainte de a atinge proiectul:
|
||||
1. Mapare cache -> proiect (calea text trebuie sa fie sub -CacheRoot).
|
||||
2. Guard-uri: extensie suportata (.vc2/.sc2 - faza 1), tinta nu e sub folderul
|
||||
foxbin2prg, tinta sub COMUN\ necesita -AllowComun, staleness (binarul din
|
||||
proiect mai nou decat textul din cache => refuz fara -Force), binar tinta
|
||||
lipsa => refuz PERMANENT (nici -Force nu trece peste asta).
|
||||
3. Regenerare (Prg2Bin + compilare) intr-un folder de staging unic per rulare.
|
||||
4. Fidelity check IN STAGING (bin -> text, comparat pe octeti cu textul editat,
|
||||
normalizat CRLF) inainte de orice copiere in proiect.
|
||||
5. Copiere in proiect (.vct intai, apoi .vcx), cu backup temporar (nu in proiect)
|
||||
si acces exclusiv verificat inainte.
|
||||
6. Refresh cache: textul canonic de la fidelity check se scrie peste .vc2-ul din
|
||||
cache, cu LastWriteTime >= mtime-ul noilor binare (evita staleness fals la
|
||||
urmatoarea rulare).
|
||||
7. Sumar OK/ESEC per fisier; proceseaza toate fisierele; exit 1 daca vreunul a esuat.
|
||||
|
||||
Encoding: fisierele .vc2/.sc2 sunt Windows-1252 (VFP CODEPAGE=1252). Orice citire/
|
||||
scriere foloseste explicit acest encoding; comparatiile de fidelitate se fac PE
|
||||
OCTETI (ReadAllBytes), normalizate CRLF -> nu pe stringuri cu encoding implicit.
|
||||
|
||||
.PARAMETER TextFile
|
||||
Unul sau mai multe fisiere .vc2/.sc2 (absolute sau relative la locatia curenta),
|
||||
care trebuie sa fie sub -CacheRoot.
|
||||
|
||||
.PARAMETER ProjectRoot
|
||||
Radacina proiectului tinta (implicit D:\ROA\ROAACNPRO, ca vcx2txt.ps1).
|
||||
|
||||
.PARAMETER CacheRoot
|
||||
Radacina versiunilor text. Implicit egala cu ProjectRoot (flux text in-arbore,
|
||||
langa binare): maparea cache->proiect devine identitate, iar refresh-ul textului
|
||||
e in-place. Da o radacina separata pentru fluxul vechi cu cache extern.
|
||||
|
||||
.PARAMETER AllowComun
|
||||
Obligatoriu pentru a scrie tinte aflate sub COMUN\ (repo partajat intre toate
|
||||
aplicatiile ROA - blast radius mare).
|
||||
|
||||
.PARAMETER Force
|
||||
Sare peste verificarea de staleness (binar mai nou decat textul din cache).
|
||||
NU acopera cazul "binar tinta lipsa" - acela e refuz permanent.
|
||||
|
||||
.PARAMETER NoVerify
|
||||
Sare peste fidelity check (bin->text->compara). Cache-ul tot se reimprospateaza
|
||||
(ruleaza bin->text pe binarul nou doar pentru refresh).
|
||||
|
||||
.PARAMETER DryRun
|
||||
Ruleaza maparea, guard-urile si regenerarea/compilarea/fidelity check-ul IN STAGING,
|
||||
dar nu copiaza nimic in proiect si nu atinge cache-ul.
|
||||
|
||||
.EXAMPLE
|
||||
powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\txt2vcx.ps1 `
|
||||
-TextFile 'D:\ROA\_vfp_textcache\roagest\Clase\atentie.vc2' `
|
||||
-ProjectRoot 'D:\ROA\ROAGEST' -CacheRoot 'D:\ROA\_vfp_textcache\roagest'
|
||||
#>
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory)][string[]]$TextFile,
|
||||
[string]$ProjectRoot = 'D:\ROA\ROAACNPRO',
|
||||
[string]$CacheRoot = $ProjectRoot,
|
||||
[switch]$AllowComun,
|
||||
[switch]$Force,
|
||||
[switch]$NoVerify,
|
||||
[switch]$DryRun
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$exe = 'D:\ROA\UTIL\foxbin2prg\FoxBin2Prg.EXE'
|
||||
if (-not (Test-Path $exe)) {
|
||||
throw "Nu gasesc $exe. Compileaza intai FoxBin2Prg (deschide foxbin2prg.pj2 in VFP si Build)."
|
||||
}
|
||||
. (Join-Path $PSScriptRoot 'vfp_filemap.ps1')
|
||||
|
||||
$script:Enc = [Text.Encoding]::GetEncoding(1252)
|
||||
$script:FoxBin2PrgFolder = 'D:\ROA\UTIL\foxbin2prg'
|
||||
|
||||
function Normalize-Crlf([byte[]]$bytes) {
|
||||
# normalizeaza CRLF -> LF, pe octeti, ca sa compare fidelity-ul indiferent de terminatorul de linie
|
||||
$out = New-Object System.Collections.Generic.List[byte]
|
||||
for ($i = 0; $i -lt $bytes.Length; $i++) {
|
||||
if ($bytes[$i] -eq 0x0D) {
|
||||
if ($i + 1 -lt $bytes.Length -and $bytes[$i+1] -eq 0x0A) { continue } # skip CR of CRLF
|
||||
$out.Add(0x0A) | Out-Null # CR izolat -> LF
|
||||
} else {
|
||||
$out.Add($bytes[$i]) | Out-Null
|
||||
}
|
||||
}
|
||||
return $out.ToArray()
|
||||
}
|
||||
|
||||
function Test-BytesEqual([byte[]]$a, [byte[]]$b) {
|
||||
$na = Normalize-Crlf $a
|
||||
$nb = Normalize-Crlf $b
|
||||
if ($na.Length -ne $nb.Length) { return $false }
|
||||
for ($i = 0; $i -lt $na.Length; $i++) { if ($na[$i] -ne $nb[$i]) { return $false } }
|
||||
return $true
|
||||
}
|
||||
|
||||
function Test-ExclusiveAccess([string]$path) {
|
||||
try {
|
||||
$fs = [IO.File]::Open($path, [IO.FileMode]::Open, [IO.FileAccess]::ReadWrite, [IO.FileShare]::None)
|
||||
$fs.Close()
|
||||
return $true
|
||||
} catch {
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
function Invoke-FoxBin2Prg {
|
||||
# Watchdog obligatoriu: FoxBin2Prg.EXE poate afisa un MessageBox MODAL nativ al
|
||||
# motorului VFP (nu al propriului error-handler) cand recompilarea unui text stricat
|
||||
# esueaza - cDontShowErrors='1' NU suprima acest dialog. Fara watchdog, o rulare
|
||||
# automata ar ramane agatata la infinit. Orice timeout => tratat ca ESEC (ExitCode -1).
|
||||
param([string]$InputFile, [string]$Recompile = '', [int]$TimeoutSeconds = 60)
|
||||
if ($Recompile) {
|
||||
$r = Invoke-FoxBin2PrgSafe -ExePath $exe -ExeArgs @($InputFile,'','','','1','0','1','',$Recompile) -TimeoutSeconds $TimeoutSeconds
|
||||
} else {
|
||||
$r = Invoke-FoxBin2PrgSafe -ExePath $exe -ExeArgs @($InputFile,'','','','1','0','1') -TimeoutSeconds $TimeoutSeconds
|
||||
}
|
||||
if ($r.TimedOut) { Write-Warning "Invoke-FoxBin2Prg: timeout pe '$InputFile' - tratat ca ESEC." }
|
||||
return $r.ExitCode
|
||||
}
|
||||
|
||||
function Write-Summary($results) {
|
||||
Write-Host ''
|
||||
Write-Host '--- Sumar txt2vcx ---'
|
||||
$fail = 0
|
||||
foreach ($r in $results) {
|
||||
if ($r.Ok) { Write-Host "OK $($r.Text)" }
|
||||
else { Write-Host "ESEC $($r.Text) -- $($r.Reason)"; $fail++ }
|
||||
}
|
||||
Write-Host ''
|
||||
if ($fail -gt 0) {
|
||||
Write-Host "$fail/$($results.Count) fisier(e) au esuat."
|
||||
Write-Host 'Ruleaza git diff --stat in proiect pentru a revizui ce s-a schimbat.'
|
||||
} else {
|
||||
Write-Host "Toate cele $($results.Count) fisier(e) au fost scrise cu succes."
|
||||
Write-Host 'Ruleaza git diff --stat in proiect pentru a revizui ce s-a schimbat.'
|
||||
}
|
||||
return $fail
|
||||
}
|
||||
|
||||
$results = @()
|
||||
$runStamp = "{0}-{1}" -f $PID, (Get-Date -Format 'yyyyMMddHHmmssfff')
|
||||
$stagingRoot = Join-Path $env:TEMP ("txt2bin_" + (Split-Path $ProjectRoot -Leaf) + "\$runStamp")
|
||||
|
||||
foreach ($tf in $TextFile) {
|
||||
$reason = $null
|
||||
$ok = $false
|
||||
$stagingDir = $null
|
||||
try {
|
||||
# --- resolve full path fara sa ceara existenta anterioara garantata pe alte disk-uri ---
|
||||
$fullTextPath = if ([IO.Path]::IsPathRooted($tf)) { $tf } else { Join-Path (Get-Location) $tf }
|
||||
if (-not (Test-Path -LiteralPath $fullTextPath -PathType Leaf)) {
|
||||
throw "Fisierul text nu exista: $fullTextPath"
|
||||
}
|
||||
$fullTextPath = (Get-Item -LiteralPath $fullTextPath).FullName
|
||||
|
||||
# --- 1. Mapare cache -> proiect ---
|
||||
$cacheRootFull = (Get-Item -LiteralPath $CacheRoot).FullName
|
||||
if (-not $fullTextPath.ToLower().StartsWith($cacheRootFull.ToLower() + '\')) {
|
||||
throw "Calea text trebuie sa fie sub CacheRoot ($cacheRootFull): $fullTextPath"
|
||||
}
|
||||
$relText = $fullTextPath.Substring($cacheRootFull.Length).TrimStart('\')
|
||||
$textExt = [IO.Path]::GetExtension($fullTextPath).ToLower()
|
||||
|
||||
# --- 2a. Guard extensie (doar .vc2/.sc2 in faza 1) ---
|
||||
$pair = Get-VfpBinExtensionForTextExtension -TextExtension $textExt
|
||||
if (-not $pair -or ($pair[0] -ne '.vcx' -and $pair[0] -ne '.scx')) {
|
||||
throw "Extensie nesuportata in faza 2 (doar .vc2/.sc2): $textExt"
|
||||
}
|
||||
$binExt = $pair[0]
|
||||
$memoExt = $pair[1]
|
||||
|
||||
$relBinNoExt = [IO.Path]::ChangeExtension($relText, $null).TrimEnd('.')
|
||||
$relBin = [IO.Path]::ChangeExtension($relText, $binExt)
|
||||
$binDir = Split-Path (Join-Path $ProjectRoot $relBin) -Parent
|
||||
$binBaseName = [IO.Path]::GetFileNameWithoutExtension($relBin)
|
||||
|
||||
# --- 2b. Guard: refuz necondiționat sub folderul foxbin2prg ---
|
||||
$projectRootFull = if (Test-Path -LiteralPath $ProjectRoot) { (Get-Item -LiteralPath $ProjectRoot).FullName } else { $ProjectRoot }
|
||||
$prospectiveBinFull = Join-Path $projectRootFull $relBin
|
||||
if ($prospectiveBinFull.ToLower().StartsWith($script:FoxBin2PrgFolder.ToLower() + '\')) {
|
||||
throw "Refuz: tinta sub folderul foxbin2prg ($script:FoxBin2PrgFolder) - nu e permis sa scrii aici."
|
||||
}
|
||||
|
||||
# --- 2c. Guard COMUN ---
|
||||
if ($relBin -match '(?i)^COMUN\\' -and -not $AllowComun) {
|
||||
throw "Tinta e sub COMUN\ (repo partajat) - ruleaza cu -AllowComun daca esti sigur."
|
||||
}
|
||||
|
||||
# --- Rezolva numele real (casing) al binarului si memo-ului din director ---
|
||||
if (-not (Test-Path -LiteralPath $binDir -PathType Container)) {
|
||||
throw "Director tinta lipsa: $binDir"
|
||||
}
|
||||
$binEntry = Get-ChildItem -LiteralPath $binDir -Filter ($binBaseName + $binExt) -ErrorAction SilentlyContinue | Select-Object -First 1
|
||||
$memoEntry = Get-ChildItem -LiteralPath $binDir -Filter ($binBaseName + $memoExt) -ErrorAction SilentlyContinue | Select-Object -First 1
|
||||
|
||||
# --- 2d. Guard: binar tinta lipsa -> refuz PERMANENT, -Force nu trece peste asta ---
|
||||
if (-not $binEntry -or -not $memoEntry) {
|
||||
throw "Binarul/memo-ul tinta nu exista in proiect ($binBaseName$binExt / $binBaseName$memoExt) - fisier nou, trebuie creat in IDE (SET CLASSLIB/.pjx) inainte de write-back."
|
||||
}
|
||||
$binFull = $binEntry.FullName
|
||||
$memoFull = $memoEntry.FullName
|
||||
|
||||
# --- 2e. Guard staleness ---
|
||||
$binMtime = $binEntry.LastWriteTime
|
||||
$memoMtime = $memoEntry.LastWriteTime
|
||||
$newestBinMtime = if ($binMtime -gt $memoMtime) { $binMtime } else { $memoMtime }
|
||||
$textMtime = (Get-Item -LiteralPath $fullTextPath).LastWriteTime
|
||||
if ($newestBinMtime -gt $textMtime -and -not $Force) {
|
||||
throw "Staleness: binarul/memo-ul din proiect ($newestBinMtime) e mai nou decat textul din cache ($textMtime) - probabil modificat in IDE. Ruleaza vcx2txt.ps1 -Force intai, sau -Force aici daca esti sigur ca vrei sa suprascrii."
|
||||
}
|
||||
|
||||
# --- 3. Regenerare in staging ---
|
||||
$stagingDir = Join-Path $stagingRoot $relBinNoExt
|
||||
New-Item -ItemType Directory -Force -Path $stagingDir | Out-Null
|
||||
# cfg in staging: DontShowErrors suprima MessageBox-ul propriu la write-back esuat (mostenit de verify/refresh)
|
||||
Set-Content -LiteralPath (Join-Path $stagingDir 'foxbin2prg.cfg') -Value @('DontShowErrors: 1','ShowProgressbar: 0') -Encoding Ascii
|
||||
$stagingText = Join-Path $stagingDir ($binBaseName + $textExt)
|
||||
Copy-Item -LiteralPath $fullTextPath -Destination $stagingText -Force
|
||||
|
||||
$rc = Invoke-FoxBin2Prg -InputFile $stagingText -Recompile $ProjectRoot
|
||||
$stagingBin = Join-Path $stagingDir ($binBaseName + $binExt)
|
||||
$stagingMemo = Join-Path $stagingDir ($binBaseName + $memoExt)
|
||||
if ($rc -ne 0 -or -not (Test-Path -LiteralPath $stagingBin) -or -not (Test-Path -LiteralPath $stagingMemo)) {
|
||||
throw "Prg2Bin/compilare esuata (ErrorLevel=$rc) sau lipsesc $binExt/$memoExt in staging."
|
||||
}
|
||||
|
||||
# --- 4. Fidelity check IN STAGING ---
|
||||
$canonicalText = $null
|
||||
if (-not $NoVerify) {
|
||||
$verifyDir = Join-Path $stagingDir 'verify'
|
||||
New-Item -ItemType Directory -Force -Path $verifyDir | Out-Null
|
||||
$verifyBin = Join-Path $verifyDir ($binBaseName + $binExt)
|
||||
$verifyMemo = Join-Path $verifyDir ($binBaseName + $memoExt)
|
||||
Copy-Item -LiteralPath $stagingBin -Destination $verifyBin -Force
|
||||
Copy-Item -LiteralPath $stagingMemo -Destination $verifyMemo -Force
|
||||
$rc2 = Invoke-FoxBin2Prg -InputFile $verifyBin
|
||||
$verifyText = Join-Path $verifyDir ($binBaseName + $textExt)
|
||||
if ($rc2 -ne 0 -or -not (Test-Path -LiteralPath $verifyText)) {
|
||||
throw "Fidelity check: Bin2Prg pe binarul regenerat a esuat (ErrorLevel=$rc2) - probabil text stricat (ex. lipsa ENDPROC)."
|
||||
}
|
||||
$editedBytes = [IO.File]::ReadAllBytes($stagingText)
|
||||
$verifyBytes = [IO.File]::ReadAllBytes($verifyText)
|
||||
if (-not (Test-BytesEqual $editedBytes $verifyBytes)) {
|
||||
throw "Fidelity check: textul regenerat difera de textul editat (posibil proprietate nealfabetizata sau linie reformatata)."
|
||||
}
|
||||
$canonicalText = $verifyText
|
||||
}
|
||||
|
||||
if ($DryRun) {
|
||||
$ok = $true
|
||||
$reason = '(dry-run: regenerare+fidelity OK in staging, nimic copiat in proiect)'
|
||||
} else {
|
||||
# --- 5. Copiere in proiect ---
|
||||
if (-not (Test-ExclusiveAccess $binFull) -or -not (Test-ExclusiveAccess $memoFull)) {
|
||||
throw "Nu pot obtine acces exclusiv la $binBaseName$binExt/$memoExt - inchide IDE-ul VFP si reincearca."
|
||||
}
|
||||
$backupDir = Join-Path $stagingDir 'backup_proiect'
|
||||
New-Item -ItemType Directory -Force -Path $backupDir | Out-Null
|
||||
$backupBin = Join-Path $backupDir ($binBaseName + $binExt)
|
||||
$backupMemo = Join-Path $backupDir ($binBaseName + $memoExt)
|
||||
Copy-Item -LiteralPath $binFull -Destination $backupBin -Force
|
||||
Copy-Item -LiteralPath $memoFull -Destination $backupMemo -Force
|
||||
|
||||
Copy-Item -LiteralPath $stagingMemo -Destination $memoFull -Force
|
||||
try {
|
||||
Copy-Item -LiteralPath $stagingBin -Destination $binFull -Force
|
||||
} catch {
|
||||
# restaureaza memo-ul vechi din backup, ca sa nu ramana o pereche rupta
|
||||
Copy-Item -LiteralPath $backupMemo -Destination $memoFull -Force
|
||||
throw "Copierea $binExt a esuat, memo-ul a fost restaurat din backup: $_"
|
||||
}
|
||||
|
||||
# --- 6. Refresh cache ---
|
||||
if (-not $NoVerify -and $canonicalText) {
|
||||
Copy-Item -LiteralPath $canonicalText -Destination $fullTextPath -Force
|
||||
} else {
|
||||
# fara fidelity text disponibil (NoVerify) - ruleaza bin->text pe binarul nou doar pentru refresh
|
||||
$refreshDir = Join-Path $stagingDir 'refresh'
|
||||
New-Item -ItemType Directory -Force -Path $refreshDir | Out-Null
|
||||
$refreshBin = Join-Path $refreshDir ($binBaseName + $binExt)
|
||||
$refreshMemo = Join-Path $refreshDir ($binBaseName + $memoExt)
|
||||
Copy-Item -LiteralPath $binFull -Destination $refreshBin -Force
|
||||
Copy-Item -LiteralPath $memoFull -Destination $refreshMemo -Force
|
||||
Invoke-FoxBin2Prg -InputFile $refreshBin | Out-Null
|
||||
$refreshText = Join-Path $refreshDir ($binBaseName + $textExt)
|
||||
if (Test-Path -LiteralPath $refreshText) {
|
||||
Copy-Item -LiteralPath $refreshText -Destination $fullTextPath -Force
|
||||
}
|
||||
}
|
||||
$newBinMtime = (Get-Item -LiteralPath $binFull).LastWriteTime
|
||||
$newMemoMtime = (Get-Item -LiteralPath $memoFull).LastWriteTime
|
||||
$newestMtime = if ($newBinMtime -gt $newMemoMtime) { $newBinMtime } else { $newMemoMtime }
|
||||
(Get-Item -LiteralPath $fullTextPath).LastWriteTime = $newestMtime.AddSeconds(1)
|
||||
|
||||
$ok = $true
|
||||
}
|
||||
|
||||
# curatare staging la succes
|
||||
if ($ok -and -not $DryRun) {
|
||||
Remove-Item -Recurse -Force -LiteralPath $stagingDir -ErrorAction SilentlyContinue
|
||||
} elseif ($ok -and $DryRun) {
|
||||
Remove-Item -Recurse -Force -LiteralPath $stagingDir -ErrorAction SilentlyContinue
|
||||
}
|
||||
} catch {
|
||||
$ok = $false
|
||||
$reason = $_.Exception.Message
|
||||
if ($stagingDir) { Write-Warning "Staging pastrat pentru diagnostic: $stagingDir" }
|
||||
}
|
||||
$results += [PSCustomObject]@{ Text = $tf; Ok = $ok; Reason = $reason }
|
||||
}
|
||||
|
||||
$failCount = Write-Summary $results
|
||||
exit ([int]($failCount -gt 0))
|
||||
168
vcx2txt.ps1
168
vcx2txt.ps1
@@ -1,168 +0,0 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Converteste in TEXT (.vc2/.sc2/.fr2/.mn2/.dc2/.lb2) librariile/formele VFP binare,
|
||||
ca sa poata fi cautat codul din proceduri/metode cu grep.
|
||||
|
||||
.DESCRIPTION
|
||||
Implicit ("project mode"), converteste DOAR fisierele incluse in proiect (citite din .pjx),
|
||||
nu tot folderul COMUN (care contine multe librarii nefolosite in ROAACNPRO).
|
||||
|
||||
Pentru fiecare fisier copiaza binarul + memo-ul (.vct/.sct/...) intr-un folder de cache care
|
||||
oglindeste structura proiectului (ca sa NU murdareasca arborele SVN), ruleaza FoxBin2Prg.exe
|
||||
acolo, si pastreaza doar fisierul TEXT. Incremental: sare peste ce e deja la zi.
|
||||
|
||||
NU e nevoie de IDE-ul VFP deschis (se foloseste FoxBin2Prg.exe compilat).
|
||||
|
||||
.PARAMETER Source
|
||||
Optional. Daca e dat, ignora proiectul si converteste exact: un fisier .vcx/.scx/... SAU un
|
||||
folder (recursiv). Folosit pentru conversii punctuale.
|
||||
|
||||
.PARAMETER Project
|
||||
Fisierul .pjx din care se citeste lista de fisiere (implicit roaacnpro.PJX).
|
||||
|
||||
.PARAMETER Types
|
||||
Ce extensii sa includa in project mode (implicit vcx,scx = cod). Ex: -Types vcx,scx,frx,mnx
|
||||
|
||||
.PARAMETER ProjectRoot
|
||||
Radacina proiectului (implicit D:\ROA\ROAACNPRO). Caile din .pjx sunt relative la ea.
|
||||
|
||||
.PARAMETER CacheRoot
|
||||
Unde se scrie textul (implicit D:\ROA\_vfp_textcache\roacnpro).
|
||||
IMPORTANT: tine cache-ul in AFARA folderului foxbin2prg, altfel ReCreate_FoxBin2Prg.prg
|
||||
(care face Prg2Bin recursiv pe tot folderul tool-ului) reconverteste .??2-urile din cache in binare.
|
||||
|
||||
.PARAMETER Clean
|
||||
Sterge tot cache-ul inainte de conversie (util dupa ce s-au convertit accidental fisiere extra).
|
||||
|
||||
.PARAMETER Force
|
||||
Reconverteste chiar daca textul exista si e mai nou decat sursa.
|
||||
|
||||
.EXAMPLE
|
||||
# doar fisierele proiectului (recomandat, rapid)
|
||||
powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1
|
||||
|
||||
.EXAMPLE
|
||||
# include si rapoartele si meniurile
|
||||
powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 -Types vcx,scx,frx,mnx
|
||||
|
||||
.EXAMPLE
|
||||
# conversie punctuala a unei librarii (chiar daca nu e in proiect)
|
||||
powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 -Source D:\ROA\ROAACNPRO\COMUN\clase\caut.vcx
|
||||
#>
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[string]$Source,
|
||||
[string]$Project = 'D:\ROA\ROAACNPRO\roaacnpro.PJX',
|
||||
[string[]]$Types = @('vcx','scx'),
|
||||
[string]$ProjectRoot = 'D:\ROA\ROAACNPRO',
|
||||
[string]$CacheRoot = 'D:\ROA\_vfp_textcache\roacnpro',
|
||||
[switch]$Clean,
|
||||
[switch]$Force
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$exe = 'D:\ROA\UTIL\foxbin2prg\FoxBin2Prg.EXE'
|
||||
if (-not (Test-Path $exe)) {
|
||||
throw "Nu gasesc $exe. Compileaza intai FoxBin2Prg (deschide foxbin2prg.pj2 in VFP si Build)."
|
||||
}
|
||||
|
||||
# binar -> (memo, extensie text) -- harta comuna, partajata cu txt2vcx.ps1
|
||||
. (Join-Path $PSScriptRoot 'vfp_filemap.ps1')
|
||||
$map = $script:VfpFileMap
|
||||
|
||||
function Convert-One($fullPath) {
|
||||
$f = Get-Item -LiteralPath $fullPath
|
||||
$ext = $f.Extension.ToLower()
|
||||
if (-not $map.ContainsKey($ext)) { return 'skip' }
|
||||
$memoX = $map[$ext][0]; $txtX = $map[$ext][1]
|
||||
$memo = [IO.Path]::ChangeExtension($f.FullName, $memoX)
|
||||
|
||||
$rel = $f.FullName
|
||||
if ($rel.ToLower().StartsWith($ProjectRoot.ToLower())) {
|
||||
$rel = $rel.Substring($ProjectRoot.Length).TrimStart('\')
|
||||
} else { $rel = $f.Name }
|
||||
$relDir = Split-Path $rel -Parent
|
||||
$workDir = if ($relDir) { Join-Path $CacheRoot $relDir } else { $CacheRoot }
|
||||
$txtOut = Join-Path $workDir ([IO.Path]::GetFileNameWithoutExtension($f.Name) + $txtX)
|
||||
|
||||
if (-not $Force -and (Test-Path $txtOut) -and ((Get-Item $txtOut).LastWriteTime -ge $f.LastWriteTime)) {
|
||||
return 'uptodate'
|
||||
}
|
||||
if (-not (Test-Path $workDir)) { New-Item -ItemType Directory -Force -Path $workDir | Out-Null }
|
||||
|
||||
$binCopy = Join-Path $workDir $f.Name
|
||||
Copy-Item -LiteralPath $f.FullName -Destination $binCopy -Force
|
||||
if (Test-Path $memo) { Copy-Item -LiteralPath $memo -Destination (Join-Path $workDir (Split-Path $memo -Leaf)) -Force }
|
||||
|
||||
# FoxBin2Prg.EXE e aplicatie GUI: "&" poate preda controlul inainte de final, iar stergerea
|
||||
# binarului copiat ar omori conversia in curs -> Start-Process -Wait asteapta terminarea reala.
|
||||
$started = Get-Date
|
||||
$outLog = Join-Path $workDir ([IO.Path]::GetFileNameWithoutExtension($f.Name) + '.fb2p_out.tmp')
|
||||
Start-Process -FilePath $exe -ArgumentList "`"$binCopy`" `"`" `"`" `"`" 1 0 1" -Wait -WindowStyle Hidden -RedirectStandardOutput $outLog
|
||||
$exeOut = ''
|
||||
if (Test-Path $outLog) { $exeOut = Get-Content -Raw $outLog; Remove-Item -LiteralPath $outLog -Force -ErrorAction SilentlyContinue }
|
||||
|
||||
Remove-Item -LiteralPath $binCopy -Force -ErrorAction SilentlyContinue
|
||||
$memoCopy = Join-Path $workDir (Split-Path $memo -Leaf)
|
||||
if (Test-Path $memoCopy) { Remove-Item -LiteralPath $memoCopy -Force -ErrorAction SilentlyContinue }
|
||||
|
||||
# succes = textul rescris acum SAU exe-ul raporteaza 0 erori (linia "O,P1,E0,S1,X0,<txt>").
|
||||
# FoxBin2Prg NU actualizeaza mtime cand textul regenerat e identic cu cel existent (ex. binar
|
||||
# reatins de Project > Build fara schimbari reale) -> sincronizam mtime-ul textului, altfel
|
||||
# fisierul pare stale si se reconverteste la fiecare rulare.
|
||||
$fresh = (Test-Path $txtOut) -and ((Get-Item $txtOut).LastWriteTime -ge $started)
|
||||
if ($fresh -or ((Test-Path $txtOut) -and ($exeOut -match ',E0,'))) {
|
||||
if ((Get-Item $txtOut).LastWriteTime -lt $f.LastWriteTime) { (Get-Item $txtOut).LastWriteTime = Get-Date }
|
||||
return 'ok'
|
||||
}
|
||||
return 'fail'
|
||||
}
|
||||
|
||||
# --- Construieste lista de fisiere ---
|
||||
$list = @()
|
||||
if (-not [string]::IsNullOrWhiteSpace($Source)) {
|
||||
if (Test-Path $Source -PathType Leaf) { $list = @((Get-Item -LiteralPath $Source).FullName) }
|
||||
elseif (Test-Path $Source -PathType Container) {
|
||||
$list = Get-ChildItem -LiteralPath $Source -Recurse -File |
|
||||
Where-Object { $map.ContainsKey($_.Extension.ToLower()) } |
|
||||
ForEach-Object { $_.FullName }
|
||||
} else { throw "Sursa nu exista: $Source" }
|
||||
} else {
|
||||
# PROJECT MODE: citeste .pjx -> pj2 si extrage fisierele
|
||||
if (-not (Test-Path $Project)) { throw "Nu gasesc proiectul: $Project" }
|
||||
$tmp = Join-Path $env:TEMP ('pjx_' + [IO.Path]::GetFileNameWithoutExtension($Project))
|
||||
New-Item -ItemType Directory -Force -Path $tmp | Out-Null
|
||||
$pjxName = [IO.Path]::GetFileName($Project)
|
||||
Copy-Item -LiteralPath $Project -Destination (Join-Path $tmp $pjxName) -Force
|
||||
$pjt = [IO.Path]::ChangeExtension($Project, '.pjt')
|
||||
if (Test-Path $pjt) { Copy-Item -LiteralPath $pjt -Destination (Join-Path $tmp ([IO.Path]::GetFileName($pjt))) -Force }
|
||||
& $exe (Join-Path $tmp $pjxName) '' '' '' '1' '0' '1' | Out-Null
|
||||
$pj2 = Join-Path $tmp ([IO.Path]::GetFileNameWithoutExtension($Project) + '.pj2')
|
||||
if (-not (Test-Path $pj2)) { throw "Conversia .pjx a esuat: $pj2" }
|
||||
|
||||
$extPat = ($Types | ForEach-Object { [regex]::Escape($_) }) -join '|'
|
||||
$rx = [regex]("(?i)\.ADD\('([^']*\.(?:$extPat))'\)")
|
||||
foreach ($m in $rx.Matches((Get-Content -Raw $pj2))) {
|
||||
$relp = $m.Groups[1].Value
|
||||
$abs = Join-Path $ProjectRoot $relp
|
||||
if (Test-Path $abs) { $list += (Get-Item -LiteralPath $abs).FullName }
|
||||
else { Write-Warning "lipsa: $relp" }
|
||||
}
|
||||
$list = $list | Sort-Object -Unique
|
||||
}
|
||||
|
||||
if ($Clean -and (Test-Path $CacheRoot)) { Remove-Item -Recurse -Force $CacheRoot }
|
||||
if (-not $list) { Write-Host 'Nimic de convertit.'; return }
|
||||
|
||||
$ok=0;$up=0;$fail=0
|
||||
foreach ($p in $list) {
|
||||
switch (Convert-One $p) {
|
||||
'ok' { $ok++; $r = $p; if ($r.ToLower().StartsWith($ProjectRoot.ToLower())) { $r = $r.Substring($ProjectRoot.Length).TrimStart('\') }; Write-Host "OK $r" }
|
||||
'uptodate' { $up++ }
|
||||
'fail' { $fail++; Write-Warning "ESEC $p" }
|
||||
}
|
||||
}
|
||||
Write-Host ''
|
||||
Write-Host "Gata. Convertite: $ok Sarite(la zi): $up Esuate: $fail (tipuri: $($Types -join ','))"
|
||||
Write-Host "Text in: $CacheRoot"
|
||||
Write-Host "Cauta cu: grep -rn 'expresie' `"$CacheRoot`""
|
||||
@@ -1,81 +0,0 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Harta comuna bin<->memo<->text pentru conversiile VFP (FoxBin2Prg), dot-sourced de
|
||||
vcx2txt.ps1 (Bin2Prg) si txt2vcx.ps1 (Prg2Bin), ca sa nu existe doua copii ale hartii.
|
||||
|
||||
.DESCRIPTION
|
||||
Defineste $script:VfpFileMap: extensie-binar (lowercase, cu punct) -> @(extensie-memo, extensie-text).
|
||||
Si o functie inversa Get-VfpBinExtensionForTextExtension pentru txt2vcx.ps1 (text -> binar).
|
||||
#>
|
||||
|
||||
$script:VfpFileMap = @{
|
||||
'.vcx' = @('.vct', '.vc2'); '.scx' = @('.sct', '.sc2'); '.frx' = @('.frt', '.fr2')
|
||||
'.lbx' = @('.lbt', '.lb2'); '.mnx' = @('.mnt', '.mn2'); '.dbc' = @('.dct', '.dc2')
|
||||
'.pjx' = @('.pjt', '.pj2'); '.dbf' = @('.fpt', '.db2')
|
||||
}
|
||||
|
||||
function Get-VfpBinExtensionForTextExtension {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Data o extensie text (.vc2, .sc2, ...), intoarce @(extensie-binar, extensie-memo), sau $null daca nu e cunoscuta.
|
||||
#>
|
||||
param([Parameter(Mandatory)][string]$TextExtension)
|
||||
$t = $TextExtension.ToLower()
|
||||
foreach ($binExt in $script:VfpFileMap.Keys) {
|
||||
if ($script:VfpFileMap[$binExt][1] -eq $t) {
|
||||
return @($binExt, $script:VfpFileMap[$binExt][0])
|
||||
}
|
||||
}
|
||||
return $null
|
||||
}
|
||||
|
||||
function Invoke-FoxBin2PrgSafe {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Ruleaza FoxBin2Prg.EXE cu un watchdog de timp, ca sa nu ramana blocat la infinit.
|
||||
|
||||
.DESCRIPTION
|
||||
FoxBin2Prg.EXE poate afisa un MessageBox MODAL nativ al motorului VFP (nu al
|
||||
propriului sau error-handler) cand recompilarea textului esueaza (ex. text
|
||||
stricat, ENDPROC lipsa) - vazut concret: "Error 1098, Procedure not closed...".
|
||||
Parametrul cDontShowErrors='1' NU suprima acest dialog (acela controleaza doar
|
||||
raportarea de erori proprie a FoxBin2Prg, nu eroarea nativa de compilare VFP).
|
||||
Fara acest watchdog, un rulaj automat/CI ar ramane agatat la infinit asteptand
|
||||
un om sa apese OK. Orice timeout se trateaza ca ESEC pentru fisierul respectiv.
|
||||
|
||||
.PARAMETER ExePath
|
||||
Calea catre FoxBin2Prg.EXE.
|
||||
|
||||
.PARAMETER ExeArgs
|
||||
Lista de argumente pozitionale, in ordinea folosita de FoxBin2Prg (inclusiv
|
||||
string-urile goale intre ele, ca in apelul cu "&").
|
||||
|
||||
.PARAMETER TimeoutSeconds
|
||||
Cat asteapta procesul sa termine normal inainte sa-l omoare (implicit 60s -
|
||||
conversiile uzuale dureaza sub o secunda; un timeout mare inseamna aproape
|
||||
sigur un dialog modal blocat).
|
||||
|
||||
.OUTPUTS
|
||||
PSCustomObject cu TimedOut (bool) si ExitCode (int; -1 daca a fost omorat la timeout).
|
||||
#>
|
||||
param(
|
||||
[Parameter(Mandatory)][string]$ExePath,
|
||||
[Parameter(Mandatory)][AllowEmptyCollection()][AllowEmptyString()][string[]]$ExeArgs,
|
||||
[int]$TimeoutSeconds = 60
|
||||
)
|
||||
$psi = New-Object System.Diagnostics.ProcessStartInfo
|
||||
$psi.FileName = $ExePath
|
||||
$psi.Arguments = ($ExeArgs | ForEach-Object { '"' + ($_ -replace '"', '\"') + '"' }) -join ' '
|
||||
$psi.UseShellExecute = $false
|
||||
|
||||
$proc = [System.Diagnostics.Process]::Start($psi)
|
||||
$finished = $proc.WaitForExit($TimeoutSeconds * 1000)
|
||||
if (-not $finished) {
|
||||
Write-Warning "Invoke-FoxBin2PrgSafe: TIMEOUT dupa $TimeoutSeconds s (probabil MessageBox modal blocat) - omor procesul (PID $($proc.Id)) si eventualele lui ferestre/copii."
|
||||
try { & taskkill /PID $proc.Id /T /F 2>&1 | Out-Null } catch {}
|
||||
try { if (-not $proc.HasExited) { $proc.Kill() } } catch {}
|
||||
Start-Sleep -Milliseconds 300
|
||||
return [PSCustomObject]@{ TimedOut = $true; ExitCode = -1 }
|
||||
}
|
||||
return [PSCustomObject]@{ TimedOut = $false; ExitCode = $proc.ExitCode }
|
||||
}
|
||||
321
vfp_symbols.ps1
321
vfp_symbols.ps1
@@ -1,321 +0,0 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Index de simboluri (clase, metode, proceduri) peste cache-ul text VFP si peste .prg-urile
|
||||
proiectului. Raspunde la "in ce clasa/metoda e linia N" si "unde e definit X".
|
||||
|
||||
.DESCRIPTION
|
||||
Grep-ul gaseste textul, dar intr-un .vc2 de 18.000 de linii nu spune in ce metoda a carei clase
|
||||
a nimerit (header-ul clasei poate fi cu 13.000 de linii mai sus, iar ~2/3 din fisier sunt
|
||||
proprietati si metadata, nu cod). Scriptul construieste un index cu intervalul de linii al
|
||||
fiecarei clase/metode si il foloseste ca sa etichete rezultatele.
|
||||
|
||||
Indexul e derivat 100% din cache-ul text (vezi vcx2txt.ps1) - se poate sterge oricand.
|
||||
|
||||
.PARAMETER Grep
|
||||
Cauta expresia (regex) in fisierele indexate si eticheteaza fiecare rezultat cu clasa.metoda.
|
||||
|
||||
.PARAMETER CodeOnly
|
||||
Cu -Grep: arata doar potrivirile din corpul metodelor/procedurilor (taie metadata si listele
|
||||
de proprietati din .vc2/.sc2).
|
||||
|
||||
.PARAMETER Where
|
||||
"fisier:linie" -> ce clasa/metoda contine linia respectiva.
|
||||
|
||||
.PARAMETER Find
|
||||
Numele unui simbol (accepta * si ?) -> unde e DEFINIT (nu si unde e apelat).
|
||||
|
||||
.PARAMETER Class
|
||||
Numele unei clase -> lantul de mostenire + metodele ei, cu intervalele de linii.
|
||||
|
||||
.PARAMETER Build
|
||||
Reconstruieste indexul (implicit se reconstruieste automat cand e invechit).
|
||||
|
||||
.EXAMPLE
|
||||
# construieste/actualizeaza indexul
|
||||
powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\vfp_symbols.ps1
|
||||
|
||||
.EXAMPLE
|
||||
# cautare etichetata, doar in cod
|
||||
... vfp_symbols.ps1 -Grep 'calcul_cheiaj' -CodeOnly
|
||||
|
||||
.EXAMPLE
|
||||
... vfp_symbols.ps1 -Where 'oacnpro.vc2:14937'
|
||||
... vfp_symbols.ps1 -Find 'do_calcul_*'
|
||||
... vfp_symbols.ps1 -Class frm_calcul_cheiaj
|
||||
#>
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[string]$Grep,
|
||||
[switch]$CodeOnly,
|
||||
[string]$Where,
|
||||
[string]$Find,
|
||||
[string]$Class,
|
||||
# implicit: fluxul in-tree din ROAACNPRO (textul .vc2/.sc2 sta langa binare, nu intr-un cache)
|
||||
[string]$CacheRoot = 'D:\ROA\ROAACNPRO',
|
||||
[string]$ProjectRoot = 'D:\ROA\ROAACNPRO',
|
||||
[string[]]$PrgDirs = @('Programe', 'COMUN\programe'),
|
||||
[string]$ExcludePrg = '\\programe\\roa\\',
|
||||
[string]$IndexFile,
|
||||
[switch]$Build,
|
||||
[switch]$Stats
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
if (-not $IndexFile) {
|
||||
# la fluxul in-tree indexul nu se scrie in repo, ci in zona de cache comuna
|
||||
$IndexFile = if ($CacheRoot -like 'D:\ROA\_vfp_textcache\*') { Join-Path $CacheRoot '_symbols.tsv' }
|
||||
else { Join-Path ('D:\ROA\_vfp_textcache\' + (Split-Path $ProjectRoot -Leaf).ToLower()) '_symbols.tsv' }
|
||||
}
|
||||
|
||||
# Codepage-ul din antetul .vc2 nu e de incredere (vezi CLAUDE.md), dar aici se citesc doar
|
||||
# cuvinte-cheie si identificatori ASCII, iar fisierele nu sunt niciodata rescrise.
|
||||
$cp1252 = [System.Text.Encoding]::GetEncoding(1252)
|
||||
|
||||
# .vc2/.sc2 = clase/forme convertite din binar; .prg = sursa directa (are si Define Class, ex. roa.prg)
|
||||
$rxClass = [regex]'(?i)^\s*DEFINE\s+CLASS\s+([\w]+)\s+AS\s+([\w\.]+)\s*(?:OF\s+"?([^"]*?)"?\s*)?$'
|
||||
$rxEndDef = [regex]'(?i)^\s*ENDDEFINE\b'
|
||||
$rxProc = [regex]'(?i)^\s*(?:(?:HIDDEN|PROTECTED)\s+)*(?:PROCEDURE|FUNCTION)\s+([\w\.]+)'
|
||||
$rxEndPrc = [regex]'(?i)^\s*(?:ENDPROC|ENDFUNC)\b'
|
||||
|
||||
function Get-SourceFiles {
|
||||
$files = @()
|
||||
# -Include e ignorat cu -LiteralPath in PS 5.1 -> filtrarea se face cu Where-Object
|
||||
if (Test-Path $CacheRoot) {
|
||||
$files += Get-ChildItem -LiteralPath $CacheRoot -Recurse -File |
|
||||
Where-Object { $_.Extension -match '(?i)^\.(vc2|sc2)$' }
|
||||
}
|
||||
foreach ($d in $PrgDirs) {
|
||||
$full = Join-Path $ProjectRoot $d
|
||||
if (Test-Path $full) {
|
||||
$files += Get-ChildItem -LiteralPath $full -Recurse -File -Filter *.prg |
|
||||
Where-Object { $_.FullName -notmatch '\\\.svn\\' -and
|
||||
($ExcludePrg -eq '' -or $_.FullName -notmatch "(?i)$ExcludePrg") }
|
||||
}
|
||||
}
|
||||
$files
|
||||
}
|
||||
|
||||
function Parse-File($file) {
|
||||
$lines = [System.IO.File]::ReadAllLines($file.FullName, $cp1252)
|
||||
$recs = New-Object System.Collections.ArrayList
|
||||
|
||||
$cls = $null; $clsLine = 0; $clsParent = ''; $clsOf = ''
|
||||
$prc = $null; $prcLine = 0
|
||||
|
||||
# inchide procedura curenta la linia $end si o adauga in lista
|
||||
$closeProc = {
|
||||
param($end)
|
||||
if ($prc) {
|
||||
$q = if ($cls) { "$cls.$prc" } else { $prc }
|
||||
$k = if ($cls) { 'method' } else { 'proc' }
|
||||
[void]$recs.Add([pscustomobject]@{
|
||||
kind = $k; qname = $q; class = [string]$cls; member = $prc
|
||||
file = $file.FullName; line = $prcLine; endline = $end
|
||||
parent = ''; parentfile = ''
|
||||
})
|
||||
$script:prcClosed = $true
|
||||
}
|
||||
}
|
||||
|
||||
for ($i = 0; $i -lt $lines.Length; $i++) {
|
||||
$ln = $lines[$i]
|
||||
$num = $i + 1
|
||||
$t = $ln.TrimStart()
|
||||
if ($t.Length -eq 0 -or $t[0] -eq '*') { continue } # comentariile nu deschid blocuri
|
||||
|
||||
$m = $rxClass.Match($ln)
|
||||
if ($m.Success) {
|
||||
& $closeProc ($num - 1); $prc = $null
|
||||
if ($cls) {
|
||||
[void]$recs.Add([pscustomobject]@{
|
||||
kind='class'; qname=$cls; class=$cls; member=''
|
||||
file=$file.FullName; line=$clsLine; endline=($num-1)
|
||||
parent=$clsParent; parentfile=$clsOf })
|
||||
}
|
||||
$cls = $m.Groups[1].Value; $clsLine = $num
|
||||
$clsParent = $m.Groups[2].Value; $clsOf = $m.Groups[3].Value
|
||||
continue
|
||||
}
|
||||
if ($rxEndDef.IsMatch($ln)) {
|
||||
& $closeProc ($num - 1); $prc = $null
|
||||
if ($cls) {
|
||||
[void]$recs.Add([pscustomobject]@{
|
||||
kind='class'; qname=$cls; class=$cls; member=''
|
||||
file=$file.FullName; line=$clsLine; endline=$num
|
||||
parent=$clsParent; parentfile=$clsOf })
|
||||
$cls = $null
|
||||
}
|
||||
continue
|
||||
}
|
||||
$m = $rxProc.Match($ln)
|
||||
if ($m.Success) {
|
||||
& $closeProc ($num - 1) # VFP permite proceduri fara ENDPROC
|
||||
$prc = $m.Groups[1].Value; $prcLine = $num
|
||||
continue
|
||||
}
|
||||
if ($rxEndPrc.IsMatch($ln) -and $prc) {
|
||||
& $closeProc $num; $prc = $null
|
||||
continue
|
||||
}
|
||||
}
|
||||
& $closeProc $lines.Length
|
||||
if ($cls) {
|
||||
[void]$recs.Add([pscustomobject]@{
|
||||
kind='class'; qname=$cls; class=$cls; member=''
|
||||
file=$file.FullName; line=$clsLine; endline=$lines.Length
|
||||
parent=$clsParent; parentfile=$clsOf })
|
||||
}
|
||||
$recs
|
||||
}
|
||||
|
||||
function Build-Index {
|
||||
$src = Get-SourceFiles
|
||||
if (-not $src) { throw "Nu am gasit surse. Ruleaza intai vcx2txt.ps1 (cache: $CacheRoot)." }
|
||||
$all = New-Object System.Collections.ArrayList
|
||||
foreach ($f in $src) { foreach ($r in (Parse-File $f)) { [void]$all.Add($r) } }
|
||||
|
||||
$dir = Split-Path $IndexFile -Parent
|
||||
if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Force -Path $dir | Out-Null }
|
||||
$all | Select-Object kind, qname, class, member, file, line, endline, parent, parentfile |
|
||||
Export-Csv -LiteralPath $IndexFile -Delimiter "`t" -NoTypeInformation -Encoding UTF8
|
||||
|
||||
$nc = ($all | Where-Object kind -eq 'class').Count
|
||||
$nm = ($all | Where-Object kind -eq 'method').Count
|
||||
$np = ($all | Where-Object kind -eq 'proc').Count
|
||||
Write-Host "Index: $($src.Count) fisiere -> $nc clase, $nm metode, $np proceduri"
|
||||
Write-Host "Scris in: $IndexFile"
|
||||
$all
|
||||
}
|
||||
|
||||
function Test-IndexStale {
|
||||
if (-not (Test-Path $IndexFile)) { return $true }
|
||||
# acelasi -IndexFile poate veni dintr-o alta radacina (alt -CacheRoot): datele vechi nu par invechite
|
||||
$head = Get-Content -LiteralPath $IndexFile -TotalCount 2
|
||||
if ($head.Count -ge 2) {
|
||||
$cols = $head[1].Split("`t")
|
||||
if ($cols.Count -gt 4) {
|
||||
$src = $cols[4].Trim('"')
|
||||
if (-not ($src.StartsWith($CacheRoot, 'OrdinalIgnoreCase') -or
|
||||
$src.StartsWith($ProjectRoot, 'OrdinalIgnoreCase'))) { return $true }
|
||||
}
|
||||
}
|
||||
$idx = (Get-Item $IndexFile).LastWriteTime
|
||||
foreach ($f in (Get-SourceFiles)) { if ($f.LastWriteTime -gt $idx) { return $true } }
|
||||
$false
|
||||
}
|
||||
|
||||
function Get-Index {
|
||||
if ($Build -or (Test-IndexStale)) { return Build-Index }
|
||||
Import-Csv -LiteralPath $IndexFile -Delimiter "`t" | ForEach-Object {
|
||||
$_.line = [int]$_.line; $_.endline = [int]$_.endline; $_
|
||||
}
|
||||
}
|
||||
|
||||
# Indexul se grupeaza o singura data pe fisier: cautarea liniara prin toate inregistrarile
|
||||
# la fiecare potrivire face -Grep de ~100x mai lent pe simboluri des folosite (ex. goExecutor).
|
||||
$script:ownerIdx = $null
|
||||
function Init-OwnerIndex($index) {
|
||||
$h = @{}
|
||||
foreach ($r in $index) {
|
||||
$k = $r.file.ToLower()
|
||||
if (-not $h.ContainsKey($k)) { $h[$k] = New-Object System.Collections.ArrayList }
|
||||
[void]$h[$k].Add($r)
|
||||
}
|
||||
$script:ownerIdx = $h
|
||||
}
|
||||
|
||||
# proprietarul unei linii: metoda bate clasa (intervalul cel mai strans)
|
||||
function Get-Owner($file, $lineNo) {
|
||||
$k = $file.ToLower()
|
||||
$recs = $script:ownerIdx[$k]
|
||||
if (-not $recs) {
|
||||
foreach ($kk in $script:ownerIdx.Keys) { # accepta si doar numele fisierului
|
||||
if ($kk.EndsWith('\' + $k)) { $recs = $script:ownerIdx[$kk]; break }
|
||||
}
|
||||
}
|
||||
if (-not $recs) { return $null }
|
||||
$best = $null; $bestSpan = [int]::MaxValue
|
||||
foreach ($r in $recs) {
|
||||
if ($r.line -le $lineNo -and $r.endline -ge $lineNo) {
|
||||
$span = $r.endline - $r.line
|
||||
if ($span -lt $bestSpan) { $bestSpan = $span; $best = $r }
|
||||
}
|
||||
}
|
||||
$best
|
||||
}
|
||||
|
||||
# --- moduri ---
|
||||
|
||||
if ($Where) {
|
||||
$idx = Get-Index
|
||||
if ($Where -notmatch '^(?<f>.+?):(?<l>\d+)\s*$') { throw "Format asteptat: 'fisier:linie'" }
|
||||
Init-OwnerIndex $idx
|
||||
$o = Get-Owner $Matches['f'] ([int]$Matches['l'])
|
||||
if ($o) { "{0} [{1}] {2}:{3}-{4}" -f $o.qname, $o.kind, (Split-Path $o.file -Leaf), $o.line, $o.endline }
|
||||
else { "(in afara oricarei clase/metode - metadata sau cod la nivel de fisier)" }
|
||||
return
|
||||
}
|
||||
|
||||
if ($Find) {
|
||||
$idx = Get-Index
|
||||
# numele unei clase intoarce definitia ei, nu toti membrii (pentru membri: -Class)
|
||||
$hits = $idx | Where-Object { $_.member -like $Find -or $_.qname -like $Find -or
|
||||
($_.kind -eq 'class' -and $_.class -like $Find) }
|
||||
if (-not $hits) { Write-Host "Nicio definitie pentru '$Find'."; return }
|
||||
$hits | Sort-Object kind, qname | ForEach-Object {
|
||||
"{0,-7} {1,-45} {2}:{3}" -f $_.kind, $_.qname, $_.file.Replace($CacheRoot + '\', '').Replace($ProjectRoot + '\', ''), $_.line
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if ($Class) {
|
||||
$idx = Get-Index
|
||||
$c = $idx | Where-Object { $_.kind -eq 'class' -and $_.class -eq $Class } | Select-Object -First 1
|
||||
if (-not $c) { Write-Host "Clasa '$Class' nu e in index."; return }
|
||||
|
||||
Write-Host "Lant de mostenire:"
|
||||
$cur = $c; $depth = 0; $seen = @{}
|
||||
while ($cur -and $depth -lt 12) {
|
||||
"{0}{1} ({2}:{3})" -f (' ' * $depth), $cur.class, (Split-Path $cur.file -Leaf), $cur.line
|
||||
if (-not $cur.parent -or $seen[$cur.parent]) { break }
|
||||
$seen[$cur.class] = $true
|
||||
$next = $idx | Where-Object { $_.kind -eq 'class' -and $_.class -eq $cur.parent } | Select-Object -First 1
|
||||
if (-not $next) { "{0}{1} (clasa de baza VFP sau librarie neindexata: {2})" -f (' ' * ($depth+1)), $cur.parent, $cur.parentfile; break }
|
||||
$cur = $next; $depth++
|
||||
}
|
||||
Write-Host ''
|
||||
Write-Host "Metode proprii ($($c.class)):"
|
||||
$idx | Where-Object { $_.kind -eq 'method' -and $_.class -eq $Class } | Sort-Object line |
|
||||
ForEach-Object { " {0,-50} {1}-{2}" -f $_.member, $_.line, $_.endline }
|
||||
return
|
||||
}
|
||||
|
||||
if ($Grep) {
|
||||
$idx = Get-Index
|
||||
$files = Get-SourceFiles
|
||||
$res = $files | Select-String -Pattern $Grep -Encoding default
|
||||
if (-not $res) { Write-Host "Nicio potrivire pentru '$Grep'."; return }
|
||||
Init-OwnerIndex $idx
|
||||
$shown = 0; $hidden = 0
|
||||
foreach ($r in $res) {
|
||||
$o = Get-Owner $r.Path $r.LineNumber
|
||||
if (-not $o -or $o.kind -eq 'class') {
|
||||
if ($CodeOnly) { $hidden++; continue }
|
||||
}
|
||||
$owner = if ($o -and $o.kind -ne 'class') { $o.qname } elseif ($o) { "$($o.qname) (metadata)" } else { '(nivel fisier)' }
|
||||
$rel = $r.Path.Replace($CacheRoot + '\', '').Replace($ProjectRoot + '\', '')
|
||||
"{0}:{1}: [{2}] {3}" -f $rel, $r.LineNumber, $owner, $r.Line.Trim()
|
||||
$shown++
|
||||
}
|
||||
Write-Host ''
|
||||
Write-Host "$shown potriviri$(if ($hidden) { " ($hidden ascunse: metadata/proprietati)" })"
|
||||
return
|
||||
}
|
||||
|
||||
if ($Stats) {
|
||||
$idx = Get-Index
|
||||
$idx | Group-Object kind | Sort-Object Count -Descending | ForEach-Object { "{0,-8} {1}" -f $_.Name, $_.Count }
|
||||
return
|
||||
}
|
||||
|
||||
Build-Index | Out-Null
|
||||
Reference in New Issue
Block a user