From d873d52aeab4d2c83cf52f10421a4c15a98269db Mon Sep 17 00:00:00 2001 From: Marius Date: Thu, 9 Jul 2026 11:42:07 +0300 Subject: [PATCH] Adaugari locale ROA: vcx2txt.ps1 (cautare cod in binare VFP), prompturi si CLAUDE.md --- CLAUDE.md | 93 +++++++++++++++++++ PROMPT_cautare_vfp.md | 83 +++++++++++++++++ git_svn_parallel_init_prompt.md | 86 ++++++++++++++++++ vcx2txt.ps1 | 153 ++++++++++++++++++++++++++++++++ 4 files changed, 415 insertions(+) create mode 100644 CLAUDE.md create mode 100644 PROMPT_cautare_vfp.md create mode 100644 git_svn_parallel_init_prompt.md create mode 100644 vcx2txt.ps1 diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..26a5f3e --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,93 @@ +# 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 of `https://github.com/fdbozzo/foxbin2prg.git` (`master` tracks `origin/master`; the pre-update local state is kept on branch `local-snapshot-v1.21.04`). Local-only files (`vcx2txt.ps1`, `_textcache_*`, compiled binaries) are ignored via the upstream `.gitignore` plus `.git/info/exclude`. After a `git pull`, the binaries/EXE must be regenerated in VFP9 with `DO ReCreate_FoxBin2Prg.prg`. 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) + +- **`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`). +- **`_textcache_*` folders** (`_textcache`, `_textcache_roagest`, `_textcache_roaimob`) — per-project regenerable text caches. Safe to delete; never version them. +- **`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 generated text cache is **read-only, for searching only**. Code changes to a VFP project are made in the VFP IDE on the binary files (`.vcx/.scx/...`), never by editing the cached 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\UTIL\foxbin2prg\_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. + +## 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 "\file.scx" && binary -> text (.sc2) +DO FOXBIN2PRG.PRG WITH "\file.sc2" && text -> binary (.scx) + +* Convert a whole directory +DO FOXBIN2PRG.PRG WITH "","Bin2Prg" +DO FOXBIN2PRG.PRG WITH "","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____.prg` (unit) and `ft__foxbin2prg__.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. diff --git a/PROMPT_cautare_vfp.md b/PROMPT_cautare_vfp.md new file mode 100644 index 0000000..2cf8740 --- /dev/null +++ b/PROMPT_cautare_vfp.md @@ -0,0 +1,83 @@ +# Prompt: căutare î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. + +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 **2 valori** marcate `<<...>>` cu datele proiectului tău: + - `<>` = folderul rădăcină al proiectului (ex. `D:\ROA\ROAGEST`) + - `<>` = calea către `.pjx` (ex. `D:\ROA\ROAGEST\roagest.pjx`) + +--- + +## ▼▼▼ 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: <> +- Fișier proiect (.pjx): <> + +REGULA DE AUR: textul generat e DOAR pentru citire/căutare. Orice modificare de cod se face în +IDE-ul VFP, în fișierul binar (.vcx/.scx/...), niciodată în text. + +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 '<>' -ProjectRoot '<>' -CacheRoot 'D:\ROA\UTIL\foxbin2prg\_textcache_<>' + + (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 '_textcache_<>' 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\UTIL\foxbin2prg\_textcache_<>' + +ALTE OPȚIUNI: -Force (reconvertește tot), -Clean (șterge cache-ul întâi). + +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, dar reține: editarea efectivă se face în IDE-ul VFP pe binar. +``` + +## ▲▲▲ SFÂRȘIT PROMPT ▲▲▲ + +--- + +## Note pentru adaptare + +- `<>` îl poți pune orice etichetă scurtă (ex. `roagest`), doar ca numele + folderului de cache să fie unic per proiect. +- 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 (`_textcache_*`) e regenerabil și e în afara arborelui de versionare al proiectului — + poate fi șters oricând. +- Conversia NU necesită IDE-ul VFP deschis (folosește `FoxBin2Prg.EXE` compilat). +- Ghid complet (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`. diff --git a/git_svn_parallel_init_prompt.md b/git_svn_parallel_init_prompt.md new file mode 100644 index 0000000..e0fb5cd --- /dev/null +++ b/git_svn_parallel_init_prompt.md @@ -0,0 +1,86 @@ +# Prompt: init git in paralel cu SVN pentru un proiect ROA + +Foloseste acest prompt intr-o sesiune Claude Code noua, deschisa in radacina proiectului +tinta (ex. `D:\ROA\ROAIMOB`). Functioneaza generic pentru orice proiect VFP din `D:\ROA\` +care are structura ROAACNPRO (proiect + subfolder COMUN\ partajat, ambele in SVN). + +--- + +``` +Vreau sa initializezi git pentru proiectul VFP din directorul curent, in paralel cu SVN-ul +existent (nu atinge SVN, nu rula comenzi svn, doar adauga .svn/ in .gitignore). + +Structura e identica cu D:\ROA\ROAACNPRO: acest folder e propriul proiect VFP (are un .PJX +al lui), si contine un subfolder COMUN\ care e framework-ul PARTAJAT intre toate aplicatiile +ROA, versionat separat prin SVN (are propriul .svn\). + +Fa exact ce s-a facut deja pentru ROAACNPRO (poti citi acolo ca referinta/sablon): +- D:\ROA\ROAACNPRO\.gitignore (sablon pentru .gitignore-ul proiectului principal) +- D:\ROA\ROAACNPRO\COMUN\.gitignore (sablon pentru .gitignore-ul din COMUN) +- D:\ROA\ROAACNPRO\CLAUDE.md (conventii proiect) si docs\cautare_vcx_vct.md (cum se cauta + cod in interiorul .vcx/.scx binare, via D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1) + +Pasi: + +1. Verifica intai ce exista deja: `git status`/`.git` in radacina si in COMUN\, si + `git remote -v` daca exista deja vreun remote configurat gresit (asa cum a fost cazul la + ROAACNPRO, unde originul proiectului principal pointa gresit catre repo-ul comun.git). + +2. REPO PRINCIPAL (radacina acestui folder): + - Daca nu exista .git, `git init -b main`. + - Creeaza/adapteaza .gitignore dupa modelul ROAACNPRO/.gitignore (artefacte VFP compilate: + *.fxp, *.mpx, *.bak, *.mpr, *.err, log.txt, *.tmp, *.dct, *.exe, cruft Windows), plus + obligatoriu `COMUN/` (COMUN e gestionat de git-ul lui separat, nu de-al acestui repo) + si `.svn/`. + - Deduce numele repo-ului gitea dupa conventia romfast/.git + (ex. romfast/roaimob.git). INAINTE sa creezi/pushezi orice, verifica cu + `git ls-remote git@gitea.romfast.ro:romfast/.git` daca exista deja si ce contine + (clone --depth 1 intr-un folder temporar din scratchpad daca ai dubii). Daca exista deja + cu istoric care nu se potriveste cu ce ai local, OPRESTE-TE si intreaba-ma inainte sa + faci push sau orice suprascriere. + - Daca remote-ul e gol/nou: add -A, commit "Initial commit — sursa ", adauga + origin, push normal (fara --force). + +3. COMUN\ (subfolder-ul partajat): + - Initializeaza un git SEPARAT, propriu, in interiorul COMUN\ (COMUN are propriul .git, + nu e tracked de repo-ul principal — de-asta l-am exclus mai sus). + - .gitignore propriu in COMUN\ dupa modelul ROAACNPRO/COMUN/.gitignore (artefacte VFP + + `.svn/` + `bash.exe.stackdump`). + - Origin-ul din COMUN\ trebuie sa fie EXACT acelasi repo pentru toate proiectele ROA: + git@gitea.romfast.ro:romfast/comun.git — repo-ul asta e deja populat (din COMUN-ul lui + ROAACNPRO). NU face commit+push orbeste peste el. + - Fa intai `git fetch origin`, compara continutul de pe origin/main cu fisierele locale + din acest COMUN\ (diff pe folder, nu doar pe nume). Daca sunt identice sau diferentele + sunt neglijabile, seteaza pur si simplu branch-ul local sa urmareasca origin/main (fara + sa strici fisierele din working copy SVN). Daca sunt diferente reale intre COMUN-ul + acestui proiect si cel deja impins pe gitea, arata-mi un rezumat al diferentelor si + intreaba-ma explicit cum procedez (nu face force-push fara aprobarea mea explicita — + ar sterge ireversibil istoricul comun tuturor proiectelor ROA). + +4. Cautare in cod VFP binar (.vcx/.scx) pentru acest proiect: + - Foloseste acelasi vcx2txt.ps1, dar parametrizat pentru proiectul curent (nu ROAACNPRO): + powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 ` + -Project D:\ROA\\.PJX -ProjectRoot D:\ROA\ ` + -CacheRoot D:\ROA\UTIL\foxbin2prg\_textcache_ + - Cache separat per proiect (nu-l amesteca cu _textcache al ROAACNPRO). Grep in cache-ul + respectiv, la fel ca in docs\cautare_vcx_vct.md. + +5. La final, adauga/actualizeaza CLAUDE.md al acestui proiect cu o sectiune scurta: git ruleaza + in paralel cu SVN legacy (SVN ramane sursa "vie" pentru COMUN, sincronizat manual catre git); + COMUN e partajat intre toate aplicatiile ROA prin acelasi git@gitea.romfast.ro:romfast/comun.git; + cautarile in .vcx/.scx se fac cu vcx2txt.ps1 parametrizat pentru acest proiect (vezi mai sus). + +Inainte de orice `push --force` sau orice operatie care ar suprascrie istoric remote deja +existent (mai ales pe romfast/comun.git, care e comun mai multor proiecte), opreste-te si +intreaba-ma explicit — nu decide singur. +``` + +--- + +## Note + +- Cel mai sensibil pas e COMUN\: daca versiunea de COMUN a noului proiect difera de cea deja + impinsa pe `comun.git` (din ROAACNPRO), Claude trebuie sa se opreasca si sa intrebe cum se + reconciliaza, nu sa faca force-push automat. +- Daca `romfast/.git` nu exista inca pe gitea, trebuie creat gol acolo inainte de push + (manual sau prin API) — altfel push-ul esueaza cu "repository not found". diff --git a/vcx2txt.ps1 b/vcx2txt.ps1 new file mode 100644 index 0000000..875edfe --- /dev/null +++ b/vcx2txt.ps1 @@ -0,0 +1,153 @@ +<# +.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\UTIL\foxbin2prg\_textcache). + +.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\UTIL\foxbin2prg\_textcache', + [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) +$map = @{ + '.vcx' = @('.vct', '.vc2'); '.scx' = @('.sct', '.sc2'); '.frx' = @('.frt', '.fr2') + '.lbx' = @('.lbt', '.lb2'); '.mnx' = @('.mnt', '.mn2'); '.dbc' = @('.dct', '.dc2') +} + +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 } + + & $exe $binCopy '' '' '' '1' '0' '1' | Out-Null + + 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 } + + if (Test-Path $txtOut) { return 'ok' } else { 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`""