From c4d869921dc3ff29f97d14af7fef401ebcecc416 Mon Sep 17 00:00:00 2001 From: Marius Mutu Date: Sun, 2 Aug 2026 22:30:44 +0300 Subject: [PATCH] verificare partener: garda pe cont NULL, hook-uri de disciplina, docs compactate - ooperatii_comune: verific_partener nu mai construieste SQL NULL cand contul primit e NULL (EMPTY(.NULL.) e .F. in VFP) - utile\context_watch.ps1 si utile\docs_revizie_check.ps1: masurarea contextului sesiunii si cadenta reviziei de documentatie, prin hook-uri Claude Code (instalare in docs\monitorizare-context.md) - reguli_lucru: delegare la subagenti, modificari minime si scoped, scrierea si revizuirea documentatiei, changelog strictul necesar (regulile 3, 6, 9, 11, 12) - scripturi-migrare-db: continutul unui script (scoped, fara select, idempotent) - teste noi pentru cele doua erori din achizitia de import - restul documentatiei compactata, fara pierdere de reguli Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01RYbiinqXxdEqXi53x4Ro7K --- docs/.ultima_revizie | 1 + docs/PROMPT_cautare_vfp.md | 254 ++++---- docs/cautare_vcx_vct.md | 270 +++++---- docs/conventie_encoding_cp1252.md | 153 +++-- docs/conventie_goexecutor_alter_table.md | 120 ++-- docs/conventie_null_vfp.md | 21 + docs/conventie_ux_formulare.md | 117 ++-- docs/depanare_testare_vfp.md | 85 +-- docs/flux-editare-vfp-text.md | 2 +- docs/fluxul_svn_git.md | 111 ++-- docs/inrolare-proiect-git-text.md | 122 ++-- docs/inventar-comun.md | 53 +- docs/monitorizare-context.md | 42 ++ docs/oracle_export.md | 122 ++-- docs/orchestrare-subagenti.md | 15 +- docs/prompt_project_insights_docs.md | 2 +- docs/reguli_lucru.md | 141 +++-- docs/scripturi-migrare-db.md | 29 +- docs/testare-ui-vfp.md | 78 ++- docs/testare-vfp-mcp.md | 16 +- docs/todos.txt | 8 +- programe/ooperatii_comune.prg | 2 +- .../test_repro_partener_scc_null.prg | 543 ++++++++++++++++++ .../test_repro_partener_scc_null.ps1 | 18 + .../test_repro_anaf_path_nfjson.prg | 223 +++++++ .../test_repro_anaf_path_nfjson.ps1 | 18 + utile/context_watch.ps1 | 62 ++ utile/docs_revizie_check.ps1 | 27 + 28 files changed, 1788 insertions(+), 867 deletions(-) create mode 100644 docs/.ultima_revizie create mode 100644 docs/conventie_null_vfp.md create mode 100644 docs/monitorizare-context.md create mode 100644 utile/Teste/achizitie_import/test_repro_partener_scc_null.prg create mode 100644 utile/Teste/achizitie_import/test_repro_partener_scc_null.ps1 create mode 100644 utile/Teste/partener_anaf/test_repro_anaf_path_nfjson.prg create mode 100644 utile/Teste/partener_anaf/test_repro_anaf_path_nfjson.ps1 create mode 100644 utile/context_watch.ps1 create mode 100644 utile/docs_revizie_check.ps1 diff --git a/docs/.ultima_revizie b/docs/.ultima_revizie new file mode 100644 index 0000000..9d216f2 --- /dev/null +++ b/docs/.ultima_revizie @@ -0,0 +1 @@ +2026-08-02 diff --git a/docs/PROMPT_cautare_vfp.md b/docs/PROMPT_cautare_vfp.md index 91cd712..631f060 100644 --- a/docs/PROMPT_cautare_vfp.md +++ b/docs/PROMPT_cautare_vfp.md @@ -1,127 +1,127 @@ -# 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: - - `<>` = folderul rădăcină al proiectului (ex. `D:\ROA\ROAGEST`) - - `<>` = calea către `.pjx` (ex. `D:\ROA\ROAGEST\roagest.pjx`) - - `<>` = 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: <> -- Fișier proiect (.pjx): <> -- Cache text: D:\ROA\_vfp_textcache\<> - -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 '<>' -ProjectRoot '<>' -CacheRoot 'D:\ROA\_vfp_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 'D:\ROA\_vfp_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\_vfp_textcache\<>' - -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\<>\Clase\lib.vc2' -ProjectRoot '<>' -CacheRoot 'D:\ROA\_vfp_textcache\<>' - - 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_.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 - -- `<>` î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\`) 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`. +# Prompt: căutare și editare în cod VFP (foxbin2prg) — reutilizabil în orice proiect Visual FoxPro + +**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ă, la `D:\ROA\UTIL\foxbin2prg\` — nu se copiază 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 `<<...>>`: + - `<>` = folderul rădăcină al proiectului (ex. `D:\ROA\ROAGEST`) + - `<>` = calea către `.pjx` (ex. `D:\ROA\ROAGEST\roagest.pjx`) + - `<>` = 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: <> +- Fișier proiect (.pjx): <> +- Cache text: D:\ROA\_vfp_textcache\<> + +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 '<>' -ProjectRoot '<>' -CacheRoot 'D:\ROA\_vfp_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 'D:\ROA\_vfp_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\_vfp_textcache\<>' + +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\<>\Clase\lib.vc2' -ProjectRoot '<>' -CacheRoot 'D:\ROA\_vfp_textcache\<>' + + 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_.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 + +- `<>` poate fi orice etichetă scurtă (ex. `roagest`), unică per proiect (numele + folderului de cache). +- Ț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 e regenerabil, în afara arborelui de versionare al proiectului (și al 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`. diff --git a/docs/cautare_vcx_vct.md b/docs/cautare_vcx_vct.md index c7b5b81..4da5cb6 100644 --- a/docs/cautare_vcx_vct.md +++ b/docs/cautare_vcx_vct.md @@ -1,139 +1,131 @@ -# Căutare în codul din librăriile/formele VFP (`.vcx`/`.vct`, `.scx`/`.sct`, ...) - -Partajat între proiectele ROA* (companion narativ la `PROMPT_cautare_vfp.md` din acest folder, -care e varianta "prompt de copiat" — acest fișier e ghidul de referință complet, cu exemple). - -Cum se caută cod-sursă (proceduri, metode, parametri) care **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`), baze de date (`.dbc`+`.dct`). - -## De ce e nevoie de asta - -Un `.vcx` este de fapt o **tabelă DBF**: codul metodelor stă în câmpuri memo în `.vct`. Un -`grep` direct pe `.vct` *găsește* textul, dar îl vede ca fișier binar (octeți `\0` între linii), -fără numere de linie utile și greu de citit. Soluția: convertim binarul în reprezentarea lui -**TEXT** (`.vc2`, `.sc2`, …) — un PRG-style lizibil, cu metode sortate alfabetic — și căutăm -în text cu `grep`/`Grep`. - -> **Regula de aur:** textul generat e **doar pentru citire/căutare**, CU O EXCEPȚIE: pentru -> `.vcx`/`.scx` se poate și edita pe text, cu write-back în binar (`txt2vcx.ps1`) — vezi -> `PROMPT_cautare_vfp.md` pasul 3 pentru fluxul complet (ordine obligatorie, encoding, -> fidelity check). Pentru `.frx`/`.mnx`/`.dbc` nu există write-back — modificările se fac tot -> în **IDE-ul VFP**. - -## Unelte disponibile (verificate) - -| Unealtă | Cale | Rol | Recomandare | -|---|---|---|---| -| **FoxBin2Prg** | `D:\ROA\UTIL\foxbin2prg\FoxBin2Prg.EXE` | Binar VFP ⇄ text bidirecțional (`.vc2/.sc2/.fr2/.mn2/.dc2/.lb2`) | **De folosit.** Complet, fidel, include corpul metodelor, parametri, comentarii | -| vcx2prg | `D:\ROA\UTIL\vcx2prg\x2prg.prg` | Doar `.vcx` → `.prg` *compilabil* | Alternativă; mai vechi, doar clase, necesită IDE VFP deschis pentru a rula forma | -| prgtovcx | `D:\ROA\UTIL\prgtovcx\prgtovcx.PRG` | Invers: `.prg` → `.vcx` | **Nu** pentru căutare (e direcția opusă) | - -FoxBin2Prg e prima alegere: rulează din linia de comandă fără IDE deschis (EXE compilat), acoperă -toate tipurile de container, și produce text mult mai fidel decât vcx2prg. - -> Dacă `FoxBin2Prg.EXE` lipsește, se compilează o singură dată: deschide -> `D:\ROA\UTIL\foxbin2prg\foxbin2prg.pj2` în VFP 9 și *Build > Build Executable*. Lângă EXE trebuie -> să existe `filename_caps.exe` și fișierele `props*.txt` (sunt deja în folder). - -## Mod recomandat: scriptul `vcx2txt.ps1` - -`D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1` automatizează tot: copiază binarul + memo-ul într-un -**cache** care oglindește structura proiectului (ca să nu murdărească arborele SVN), rulează -FoxBin2Prg, păstrează doar fișierul text. E **incremental** (sare peste ce e deja la zi). - -Parametrizează scriptul cu proiectul curent și un cache separat per proiect (nu amesteca -cache-urile mai multor proiecte ROA): - -```powershell -# DOAR fișierele proiectului curent (recomandat, rapid) -> cache text propriu -powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 ` - -Project '\.pjx' -ProjectRoot '' ` - -CacheRoot 'D:\ROA\UTIL\foxbin2prg\_textcache_' - -# include și rapoartele (.frx) și meniurile (.mnx) -powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 ` - -Project '\.pjx' -ProjectRoot '' ` - -CacheRoot 'D:\ROA\UTIL\foxbin2prg\_textcache_' -Types vcx,scx,frx,mnx - -# conversie punctuală a unui fișier sau folder (chiar dacă NU e în proiect, ex. o clasă din COMUN) -powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 -Source '\COMUN\clase\caut.vcx' - -# rebuild curat (șterge cache-ul întâi) / forțează reconversia -powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 ` - -Project '\.pjx' -ProjectRoot '' ` - -CacheRoot 'D:\ROA\UTIL\foxbin2prg\_textcache_' -Clean -``` - -Exemplu concret (ROAAUTO): - -```powershell -powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 ` - -Project D:\ROA\ROAAUTO\roaauto.pjx -ProjectRoot D:\ROA\ROAAUTO ` - -CacheRoot D:\ROA\UTIL\foxbin2prg\_textcache_roaauto -``` - -Rezultatul ajunge în cache-ul indicat, cu aceeași structură de directoare ca proiectul (ex.: -`_textcache_roaauto\Clase\odevize.vc2`, `_textcache_roaauto\comun\clase\_frm_base.vc2`). Apoi: - -```bash -# cu unealta Grep (preferat) sau grep: -grep -rn "PROCEDURE do_calcul_tarife" "D:\ROA\UTIL\foxbin2prg\_textcache_" -grep -rln "factura_salvare" "D:\ROA\UTIL\foxbin2prg\_textcache_" # ce clase ating subiectul -``` - -Flux tipic pentru o problemă: rulează scriptul cu parametrii de mai sus o dată (populează -cache-ul), apoi caută cu `Grep` în cache. La sesiuni următoare rescrie doar ce s-a schimbat -(incremental). Dacă ai nevoie de o librărie din `COMUN\` care nu e în proiect, convertește-o -punctual cu `-Source`. - -## Alternativă manuală (fără script) - -FoxBin2Prg scrie textul **lângă sursă**. Ca să nu murdărești folderul de clase al proiectului, -copiază perechea binar+memo într-un folder temporar și convertește acolo: - -```powershell -# .vcx -> .vc2 (cType gol = extensia decide direcția BIN2PRG) -Copy-Item D:\ROA\\Clase\odevize.vcx, D:\ROA\\Clase\odevize.vct D:\tmp\ -& 'D:\ROA\UTIL\foxbin2prg\FoxBin2Prg.EXE' 'D:\tmp\odevize.vcx' '' '' '' '1' '0' '1' -# => D:\tmp\odevize.vc2 -``` - -Pozițiile parametrilor folosite: `fișier, cType, cTextName, lGenText, cDontShowErrors=1, -cDebug=0, cDontShowProgress=1`. **Lasă `cType` gol** — extensia (`.vcx`) determină direcția. -(Nu da explicit `"BIN2PRG"` pentru un singur fișier: în acel mod EXE-ul așteaptă un *director*.) - -Detalii complete de parametri: `D:\ROA\UTIL\foxbin2prg\docs\FoxBin2Prg_Run.md`. - -## Soluție rapidă „murdară" (un singur fișier, fără conversie) - -Pentru o verificare rapidă „există metoda X undeva în librărie?", `grep` merge direct pe `.vct` -(o vede ca binar, dar găsește potrivirile): - -```bash -grep -c "PROCEDURE" "D:\ROA\\Clase\odevize.VCT" -grep -a -o "PROCEDURE [a-zA-Z0-9_]*" "D:\ROA\\Clase\odevize.VCT" -``` - -Bun pentru „da/nu" și nume de metode; pentru citit corpul/contextul, folosește conversia în text. - -## Corespondență extensii binar → text - -| Container | Binar (+memo) | Text | -|---|---|---| -| Librărie clase | `.vcx` + `.vct` | `.vc2` | -| Formă | `.scx` + `.sct` | `.sc2` | -| Raport | `.frx` + `.frt` | `.fr2` | -| Etichetă | `.lbx` + `.lbt` | `.lb2` | -| Meniu | `.mnx` + `.mnt` | `.mn2` | -| Bază de date | `.dbc` + `.dct` | `.dc2` | - -## Note - -- Codul aplicației stă mai ales în `Clase\*.vcx`; o mare parte din `.vcx`-uri sunt în - `COMUN\` (framework partajat între toate aplicațiile ROA — vezi `CLAUDE.md` per proiect). -- Cache-ul text e regenerabil și e în afara arborelui SVN/git al proiectului — poate fi șters - oricând. -- Conversia **nu** necesită IDE-ul VFP deschis (folosește EXE-ul compilat). -- Vezi și [conventie_encoding_cp1252.md](conventie_encoding_cp1252.md) — capcană de encoding la - editarea `.sc2`/`.vc2` (nu doar la căutare). +# Căutare în codul din librăriile/formele VFP (`.vcx`/`.vct`, `.scx`/`.sct`, ...) + +Partajat între proiectele ROA* (companion narativ la `PROMPT_cautare_vfp.md` din acest folder — +varianta "prompt de copiat" — acest fișier e ghidul de referință complet, cu exemple). + +Căutare de cod-sursă (proceduri, metode, parametri) care **nu** stă în `.prg`, ci în interiorul +binarelor VFP: librării de clase (`.vcx`+`.vct`), forme (`.scx`+`.sct`), rapoarte (`.frx`+`.frt`), +meniuri (`.mnx`+`.mnt`), baze de date (`.dbc`+`.dct`). + +## De ce e nevoie de asta + +Un `.vcx` e o **tabelă DBF**: codul metodelor stă în câmpuri memo în `.vct`. `grep` direct pe +`.vct` găsește textul dar ca binar (octeți `\0` între linii), fără numere de linie și greu de +citit. Soluția: convertim binarul în reprezentarea lui **TEXT** (`.vc2`, `.sc2`, …) — PRG-style +lizibil, metode sortate alfabetic — și căutăm în text cu `grep`/`Grep`. + +> **Regula de aur:** textul generat e **doar pentru citire/căutare**, CU O EXCEPȚIE: pentru +> `.vcx`/`.scx` se poate și edita pe text, cu write-back în binar (`txt2vcx.ps1`) — vezi +> `PROMPT_cautare_vfp.md` pasul 3 (ordine obligatorie, encoding, fidelity check). Pentru +> `.frx`/`.mnx`/`.dbc` nu există write-back — modificările se fac tot în **IDE-ul VFP**. + +## Unelte disponibile (verificate) + +| Unealtă | Cale | Rol | Recomandare | +|---|---|---|---| +| **FoxBin2Prg** | `D:\ROA\UTIL\foxbin2prg\FoxBin2Prg.EXE` | Binar VFP ⇄ text bidirecțional (`.vc2/.sc2/.fr2/.mn2/.dc2/.lb2`) | **De folosit.** Fidel, include corpul metodelor, parametri, comentarii | +| vcx2prg | `D:\ROA\UTIL\vcx2prg\x2prg.prg` | Doar `.vcx` → `.prg` compilabil | Alternativă mai veche, doar clase, necesită IDE VFP deschis | +| prgtovcx | `D:\ROA\UTIL\prgtovcx\prgtovcx.PRG` | Invers: `.prg` → `.vcx` | **Nu** pentru căutare (direcție opusă) | + +FoxBin2Prg e prima alegere: rulează din linia de comandă fără IDE deschis (EXE compilat), acoperă +toate tipurile de container, text mai fidel decât vcx2prg. + +> Dacă `FoxBin2Prg.EXE` lipsește: deschide `D:\ROA\UTIL\foxbin2prg\foxbin2prg.pj2` în VFP 9 și +> *Build > Build Executable*. Lângă EXE trebuie să existe `filename_caps.exe` și `props*.txt` +> (deja în folder). + +## Mod recomandat: scriptul `vcx2txt.ps1` + +`D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1` copiază binarul + memo-ul într-un **cache** care oglindește +structura proiectului (nu murdărește arborele SVN), rulează FoxBin2Prg, păstrează doar textul. +**Incremental** (sare peste ce e deja la zi). + +```powershell +# DOAR fișierele proiectului curent (recomandat, rapid) -> cache text propriu +powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 ` + -Project '\.pjx' -ProjectRoot '' ` + -CacheRoot 'D:\ROA\UTIL\foxbin2prg\_textcache_' + +# include și rapoartele (.frx) și meniurile (.mnx) +powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 ` + -Project '\.pjx' -ProjectRoot '' ` + -CacheRoot 'D:\ROA\UTIL\foxbin2prg\_textcache_' -Types vcx,scx,frx,mnx + +# conversie punctuală a unui fișier/folder (chiar dacă NU e în proiect, ex. o clasă din COMUN) +powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 -Source '\COMUN\clase\caut.vcx' + +# rebuild curat (șterge cache-ul întâi) / forțează reconversia +powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 ` + -Project '\.pjx' -ProjectRoot '' ` + -CacheRoot 'D:\ROA\UTIL\foxbin2prg\_textcache_' -Clean +``` + +Exemplu (ROAAUTO): + +```powershell +powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 ` + -Project D:\ROA\ROAAUTO\roaauto.pjx -ProjectRoot D:\ROA\ROAAUTO ` + -CacheRoot D:\ROA\UTIL\foxbin2prg\_textcache_roaauto +``` + +Rezultatul ajunge în cache, cu aceeași structură de directoare ca proiectul (ex.: +`_textcache_roaauto\Clase\odevize.vc2`, `_textcache_roaauto\comun\clase\_frm_base.vc2`). Apoi: + +```bash +grep -rn "PROCEDURE do_calcul_tarife" "D:\ROA\UTIL\foxbin2prg\_textcache_" +grep -rln "factura_salvare" "D:\ROA\UTIL\foxbin2prg\_textcache_" # ce clase ating subiectul +``` + +Flux tipic: rulează scriptul o dată (populează cache-ul), apoi caută cu `Grep` în cache. La +sesiuni următoare rescrie doar ce s-a schimbat (incremental). Pentru o librărie din `COMUN\` care +nu e în proiect, convertește-o punctual cu `-Source`. + +## Alternativă manuală (fără script) + +FoxBin2Prg scrie textul **lângă sursă**. Ca să nu murdărești folderul de clase al proiectului, +copiază perechea binar+memo într-un folder temporar și convertește acolo: + +```powershell +# .vcx -> .vc2 (cType gol = extensia decide direcția BIN2PRG) +Copy-Item D:\ROA\\Clase\odevize.vcx, D:\ROA\\Clase\odevize.vct D:\tmp\ +& 'D:\ROA\UTIL\foxbin2prg\FoxBin2Prg.EXE' 'D:\tmp\odevize.vcx' '' '' '' '1' '0' '1' +# => D:\tmp\odevize.vc2 +``` + +Poziții parametri: `fișier, cType, cTextName, lGenText, cDontShowErrors=1, cDebug=0, +cDontShowProgress=1`. **Lasă `cType` gol** — extensia (`.vcx`) determină direcția. (Nu da explicit +`"BIN2PRG"` pentru un singur fișier: în acel mod EXE-ul așteaptă un *director*.) + +Detalii complete de parametri: `D:\ROA\UTIL\foxbin2prg\docs\FoxBin2Prg_Run.md`. + +## Soluție rapidă „murdară" (un singur fișier, fără conversie) + +Pentru „există metoda X undeva în librărie?", `grep` merge direct pe `.vct` (îl vede ca binar, dar +găsește potrivirile): + +```bash +grep -c "PROCEDURE" "D:\ROA\\Clase\odevize.VCT" +grep -a -o "PROCEDURE [a-zA-Z0-9_]*" "D:\ROA\\Clase\odevize.VCT" +``` + +Bun pentru „da/nu" și nume de metode; pentru corp/context, folosește conversia în text. + +## Corespondență extensii binar → text + +| Container | Binar (+memo) | Text | +|---|---|---| +| Librărie clase | `.vcx` + `.vct` | `.vc2` | +| Formă | `.scx` + `.sct` | `.sc2` | +| Raport | `.frx` + `.frt` | `.fr2` | +| Etichetă | `.lbx` + `.lbt` | `.lb2` | +| Meniu | `.mnx` + `.mnt` | `.mn2` | +| Bază de date | `.dbc` + `.dct` | `.dc2` | + +## Note + +- Codul aplicației stă mai ales în `Clase\*.vcx`; multe `.vcx`-uri sunt în `COMUN\` (framework + partajat între toate aplicațiile ROA — vezi `CLAUDE.md` per proiect). +- Cache-ul text e regenerabil, în afara arborelui SVN/git al proiectului — poate fi șters oricând. +- Conversia **nu** necesită IDE-ul VFP deschis (folosește EXE-ul compilat). +- Vezi și [conventie_encoding_cp1252.md](conventie_encoding_cp1252.md) — capcană de encoding la + editarea `.sc2`/`.vc2` (nu doar la căutare). diff --git a/docs/conventie_encoding_cp1252.md b/docs/conventie_encoding_cp1252.md index 16f5f9c..5a4ab22 100644 --- a/docs/conventie_encoding_cp1252.md +++ b/docs/conventie_encoding_cp1252.md @@ -1,82 +1,71 @@ -# Capcană: corupere diacritice la editarea `.sc2`/`.vc2` (encoding cp1252) - -Partajat între proiectele ROA* (similar cu `PROMPT_cautare_vfp.md` din acest folder) — capcana -ține de formatul `.sc2`/`.vc2` produs de FoxBin2Prg, nu de un proiect anume. - -Descoperit de 2 ori în aceeași sesiune (2026-07-10, în ROAAUTO): odată în -`COMUN/clase/cmd_butoane.vc2` (clasa `cmd_select_adv`), odată în `Clase/ofundal_dev.vc2` -(meniul principal) — de fiecare dată un agent anterior a editat text-cache-ul cu un tool care -nu scrie cp1252 nativ, și a corupt TOATE caracterele cu diacritice din fișier, nu doar linia -pe care voia s-o schimbe. - -## De ce se întâmplă - -Fișierele `.sc2`/`.vc2` generate de FoxBin2Prg sunt **cp1252 (Windows-1252)**, nu UTF-8 -(vezi antetul fiecărui fișier: `CPID="1252"`). Dacă un editor/tool citește fișierul ca UTF-8 -(sau alt encoding), fiecare byte >= 0x80 (diacritic) devine invalid ca secvență UTF-8 și e -înlocuit cu caracterul de replacement U+FFFD. Dacă apoi tool-ul **salvează rezultatul tot ca -UTF-8**, acel U+FFFD e scris ca 3 octeți UTF-8 (`0xEF 0xBF 0xBD`) — care, citiți înapoi ca -cp1252 (cum face FoxBin2Prg la write-back), apar ca `�`. Rezultatul: caracterul original e -**ireversibil pierdut** (nu mai există în fișier sub nicio formă) — recuperabil DOAR din altă -sursă (git history, backup). - -Codebase-ul ROA folosește un hack vechi de "reciclare" a unor caractere cp1252 needependente -de Ș/ă/ț (care nu au echivalent direct în cp1252) pentru diacritice românești: - -| Literă românească | Caracter folosit (cp1252) | Byte | -|---|---|---| -| ă | ã (a-tilde) | `0xE3` | -| Ă | à | `0xC3` | -| ț | þ (thorn minuscul) | `0xFE` | -| Ș (majusculă) | ª (ordinal masculin) | `0xAA` | -| ș (minusculă) | º (ordinal feminin) | `0xBA` | -| î, â | î, â (existente nativ în cp1252) | `0xEE`, `0xE2` | - -Aceste caractere par "gunoi"/typo la prima vedere într-un editor UTF-8 (`ã`, `þ`, `ª`, `º`) — -**sunt corecte, nu le "corecta" fără să verifici encoding-ul.** - -## Cum se verifică dacă un fișier `.sc2`/`.vc2` e corupt - -```powershell -$bytes = [System.IO.File]::ReadAllBytes(".vc2") -$text = [System.Text.Encoding]::GetEncoding(1252).GetString($bytes) -$text -split "`r`n" | Select-String ([char]0xFFFD) # cauta caracterul de replacement -``` - -Dacă apare `�` (sau `$text` conține U+FFFD) în output — fișierul are corupere de encoding. - -## Cum se repară - -1. **Nu edita orbește peste corupere** — caracterul original e deja pierdut din fișierul - curent. -2. Dacă fișierul e sub control de versiune (git) și corupera s-a întâmplat **într-o sesiune - anterioară necomisă** (deci HEAD-ul git încă are versiunea curată): recuperează originalul - convertind binarul din HEAD în text și comparând: - ```bash - git show HEAD:.vcx > /tmp/head.vcx - git show HEAD:.vct > /tmp/head.vct # (sau .VCT, dupa caz) - powershell -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 -Source /tmp/head.vcx -CacheRoot /tmp/head_out - ``` - apoi decodează ambele fișiere (HEAD curat + curent corupt) ca cp1252 și compară linie cu - linie (PowerShell, nu `diff` direct — `diff`/Bash nu decodează cp1252 corect pentru afișare, - deși detectează totuși diferența de octeți). -3. Reconstruiește fișierul text pornind de la versiunea HEAD (curată), și reaplică DOAR - modificările intenționate din sesiunea curentă peste ea (nu invers — nu încerca să "cârpești" - fișierul corupt caracter cu caracter, e mai sigur să repornești de la baza curată). -4. Scrie rezultatul înapoi ca bytes cp1252 (`[System.Text.Encoding]::GetEncoding(1252).GetBytes(...)`), - NU ca string UTF-8/`Out-File` implicit (care scrie UTF-8 sau UTF-16 după caz). -5. Rulează write-back (`txt2vcx.ps1 -Force`) și verifică fidelity check = zero diferențe. - -## Cum se evită pe viitor - -Când editezi `.sc2`/`.vc2` cu tool-uri text (Read/Edit/Write), verifică întâi dacă fișierul -conține diacritice (`ã`, `þ`, `ª`, `º`, `î`, `â` etc.) — dacă da, **orice rescrie completă a -fișierului trebuie făcută la nivel de octeți cu encoding cp1252 explicit**, nu presupunând -UTF-8 implicit. Editările punctuale (Edit tool, string replace) sunt sigure DOAR dacă tool-ul -păstrează restul fișierului byte-identic (nu rescrie tot fișierul reîncodat). - -## Vezi și - -`PROMPT_cautare_vfp.md` din acest folder, pasul 3.c — menționează deja riscul ("Headerul -CPID="1252" poate minți...") pe scurt; acest fișier e detalierea completă (tabel de caractere, -pași de recuperare din git). +# Capcană: corupere diacritice la editarea `.sc2`/`.vc2` (encoding cp1252) + +Partajat între proiectele ROA* — capcana ține de formatul `.sc2`/`.vc2` produs de FoxBin2Prg, +nu de un proiect anume. + +## De ce se întâmplă + +Fișierele `.sc2`/`.vc2` sunt **cp1252** (Windows-1252), nu UTF-8 (vezi antetul: `CPID="1252"`). +Dacă un editor/tool citește fișierul ca UTF-8, fiecare byte >= 0x80 (diacritic) devine invalid +ca secvență UTF-8 și e înlocuit cu U+FFFD. Dacă tool-ul apoi **salvează tot ca UTF-8**, acel +U+FFFD e scris ca 3 octeți (`0xEF 0xBF 0xBD`) — care, citiți înapoi ca cp1252 (cum face +FoxBin2Prg la write-back), apar ca `�`. Caracterul original e **ireversibil pierdut** +(recuperabil DOAR din altă sursă: git history, backup). + +Codebase-ul ROA "reciclează" caractere cp1252 fără echivalent direct pentru Ș/ă/ț: + +| Literă românească | Caracter folosit (cp1252) | Byte | +|---|---|---| +| ă | ã (a-tilde) | `0xE3` | +| Ă | à | `0xC3` | +| ț | þ (thorn minuscul) | `0xFE` | +| Ș (majusculă) | ª (ordinal masculin) | `0xAA` | +| ș (minusculă) | º (ordinal feminin) | `0xBA` | +| î, â | î, â (native cp1252) | `0xEE`, `0xE2` | + +Par "gunoi"/typo într-un editor UTF-8 (`ã`, `þ`, `ª`, `º`) — **sunt corecte, nu le "corecta" +fără să verifici encoding-ul.** + +## Cum se verifică dacă un fișier `.sc2`/`.vc2` e corupt + +```powershell +$bytes = [System.IO.File]::ReadAllBytes(".vc2") +$text = [System.Text.Encoding]::GetEncoding(1252).GetString($bytes) +$text -split "`r`n" | Select-String ([char]0xFFFD) # cauta caracterul de replacement +``` + +Dacă apare `�` (sau `$text` conține U+FFFD) — fișierul are corupere de encoding. + +## Cum se repară + +1. **Nu edita orbește peste corupere** — caracterul original e deja pierdut din fișierul curent. +2. Dacă corupera s-a întâmplat într-o sesiune anterioară necomisă (HEAD-ul git încă e curat): + recuperează originalul convertind binarul din HEAD în text: + ```bash + git show HEAD:.vcx > /tmp/head.vcx + git show HEAD:.vct > /tmp/head.vct # (sau .VCT, dupa caz) + powershell -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 -Source /tmp/head.vcx -CacheRoot /tmp/head_out + ``` + apoi decodează ambele fișiere (HEAD curat + curent corupt) ca cp1252 și compară linie cu + linie (PowerShell, nu `diff`/Bash direct — nu decodează cp1252 corect la afișare, deși + detectează totuși diferența de octeți). +3. Reconstruiește fișierul text pornind de la versiunea HEAD (curată), reaplicând DOAR + modificările intenționate din sesiunea curentă (nu invers — nu cârpi fișierul corupt + caracter cu caracter). +4. Scrie rezultatul înapoi ca bytes cp1252 + (`[System.Text.Encoding]::GetEncoding(1252).GetBytes(...)`), NU ca string UTF-8/`Out-File` + implicit. +5. Rulează write-back (`txt2vcx.ps1 -Force`) și verifică fidelity check = zero diferențe. + +## Cum se evită pe viitor + +Când editezi `.sc2`/`.vc2` cu tool-uri text (Read/Edit/Write), verifică întâi dacă fișierul +conține diacritice (`ã`, `þ`, `ª`, `º`, `î`, `â` etc.) — dacă da, **orice rescrie completă +trebuie făcută la nivel de octeți cu encoding cp1252 explicit**, nu presupunând UTF-8. +Editările punctuale (Edit tool, string replace) sunt sigure DOAR dacă tool-ul păstrează restul +fișierului byte-identic (nu rescrie tot fișierul reîncodat). + +## Vezi și + +`PROMPT_cautare_vfp.md` din acest folder, pasul 3.c — menționează riscul pe scurt; acest fișier +e detalierea completă (tabel de caractere, pași de recuperare din git). diff --git a/docs/conventie_goexecutor_alter_table.md b/docs/conventie_goexecutor_alter_table.md index 937eb33..3faf879 100644 --- a/docs/conventie_goexecutor_alter_table.md +++ b/docs/conventie_goexecutor_alter_table.md @@ -1,65 +1,55 @@ -# Capcană: `ALTER TABLE` pe cursorul întors de `goExecutor.oExecute()` - -Partajat între proiectele ROA* — `goExecutor` (clasa `oExecutor`, definită în -`COMUN/programe/oproceduri_comune.prg`, metoda `oExecute`) e utilitarul standard pentru -interogări SQL pass-through (`SQLExec`) către Oracle, folosit peste tot în codul ROA*. - -## Ce nu funcționează - -```foxpro -lnSucces = goExecutor.oExecute(lcSql, lcCursor) -... -ALTER TABLE (lcCursor) ADD COLUMN coloananoua L && <- pică -``` - -Cursorul întors de `oExecute()` (rezultatul unui `SQLExec`) poate refuza comenzi DDL -ulterioare, cu erori în lanț (descoperite empiric, în această ordine, în ROAAUTO -`autopass_cursor_comenzi`/`autopass_cursor_operatii`): - -1. `Function is not supported on remote tables.` — pe `ALTER TABLE` direct pe cursorul - original. -2. Chiar și după o încercare de rematerializare (`SELECT * FROM (cursor) INTO CURSOR - (acelasi_nume) READWRITE`) → `Alias name is already in use.` (sursa și ținta nu pot - avea același nume într-un `SELECT...INTO CURSOR`). -3. Cu un alias scratch diferit ca țintă (`SELECT * FROM (cursor) INTO CURSOR - (nume_final_diferit_de_sursa) READWRITE`) → tot `Invalid operation for the cursor.` pe - `ALTER TABLE`, chiar dacă acum cursorul final teoretic ar trebui să fie unul local - obișnuit. - -Nu există niciun alt loc în codul ROA* care să facă `ALTER TABLE` imediat după -`goExecutor.oExecute()` — deci acest pattern nu avea niciun precedent testat înainte de -funcțiile AUTOPASS. - -## Ce funcționează - -**Nu folosi `ALTER TABLE` deloc pe rezultatul unui `oExecute()`.** Include coloanele -suplimentare direct în `SELECT`-ul de rematerializare, ca expresii literale alături de `*` -(VFP suportă `SELECT *, expr AS coloana FROM ...`): - -```foxpro -lcCursorRaw = lcCursor + '_raw' -IF USED(lcCursorRaw) - USE IN (lcCursorRaw) -ENDIF - -lnSucces = goExecutor.oExecute(lcSql, lcCursorRaw) -IF lnSucces < 0 - * tratare eroare, RETURN -ENDIF - -SELECT *, .F. AS coloananoua, SPACE(100) AS altacoloana ; - FROM (lcCursorRaw) INTO CURSOR (lcCursor) READWRITE -USE IN (lcCursorRaw) - -* de-aici incolo doar REPLACE (date), NICIODATA ALTER TABLE (structura) pe (lcCursor) -``` - -După acest pas, cursorul (`lcCursor`) e un cursor local obișnuit — `ALTER TABLE` funcționează -normal pe el DUPĂ ACEEA (ex. dintr-o altă funcție care primește cursorul deja gata construit, -nu direct rezultatul unui `oExecute`), doar comanda imediat următoare unui `oExecute()` e -restricționată. - -## Vezi și - -Exemplu complet aplicat: ROAAUTO, `Programe/oproceduri_autopass.prg`, -`autopass_cursor_comenzi()`/`autopass_cursor_operatii()`. +# Capcană: `ALTER TABLE` pe cursorul întors de `goExecutor.oExecute()` + +Partajat între proiectele ROA* — `goExecutor` (clasa `oExecutor`, definită în +`COMUN/programe/oproceduri_comune.prg`, metoda `oExecute`) e utilitarul standard pentru +interogări SQL pass-through (`SQLExec`) către Oracle, folosit peste tot în codul ROA*. + +## Ce nu funcționează + +```foxpro +lnSucces = goExecutor.oExecute(lcSql, lcCursor) +... +ALTER TABLE (lcCursor) ADD COLUMN coloananoua L && <- pică +``` + +Cursorul întors de `oExecute()` poate refuza comenzi DDL ulterioare, cu erori în lanț +(descoperite empiric, în această ordine): + +1. `Function is not supported on remote tables.` — pe `ALTER TABLE` direct pe cursorul original. +2. Chiar și după rematerializare (`SELECT * FROM (cursor) INTO CURSOR (acelasi_nume) READWRITE`) + → `Alias name is already in use.` (sursa și ținta nu pot avea același nume). +3. Cu alias scratch diferit ca țintă → tot `Invalid operation for the cursor.` pe `ALTER TABLE`, + chiar dacă țintă ar trebui să fie deja un cursor local obișnuit. + +## Ce funcționează + +**Nu folosi `ALTER TABLE` deloc pe rezultatul unui `oExecute()`.** Include coloanele +suplimentare direct în `SELECT`-ul de rematerializare, ca expresii literale alături de `*` +(VFP suportă `SELECT *, expr AS coloana FROM ...`): + +```foxpro +lcCursorRaw = lcCursor + '_raw' +IF USED(lcCursorRaw) + USE IN (lcCursorRaw) +ENDIF + +lnSucces = goExecutor.oExecute(lcSql, lcCursorRaw) +IF lnSucces < 0 + * tratare eroare, RETURN +ENDIF + +SELECT *, .F. AS coloananoua, SPACE(100) AS altacoloana ; + FROM (lcCursorRaw) INTO CURSOR (lcCursor) READWRITE +USE IN (lcCursorRaw) + +* de-aici incolo doar REPLACE (date), NICIODATA ALTER TABLE (structura) pe (lcCursor) +``` + +După acest pas, cursorul (`lcCursor`) e un cursor local obișnuit — `ALTER TABLE` funcționează +normal pe el DUPĂ ACEEA (ex. într-o altă funcție care primește cursorul deja gata construit), +doar comanda imediat următoare unui `oExecute()` e restricționată. + +## Vezi și + +Exemplu complet aplicat: ROAAUTO, `Programe/oproceduri_autopass.prg`, +`autopass_cursor_comenzi()`/`autopass_cursor_operatii()`. diff --git a/docs/conventie_null_vfp.md b/docs/conventie_null_vfp.md new file mode 100644 index 0000000..d65be18 --- /dev/null +++ b/docs/conventie_null_vfp.md @@ -0,0 +1,21 @@ +# Garzi pe valori NULL (VFP) + +Campurile din cursoarele intoarse de Oracle pot fi `.NULL.`. In VFP `EMPTY(.NULL.)` intoarce +`.F.`, deci o garda scrisa doar cu `EMPTY()` **nu prinde NULL**, iar concatenarea cu NULL face +tot sirul NULL (inclusiv un SQL construit prin `+`). + +Forma corecta, cu tipul evaluat primul ca sa opreasca acolo: + +```foxpro +If Type('tcCont') # 'C' Or Empty(Nvl(tcCont, '')) + Return +Endif +``` + +- `Nvl(x, '')` in interiorul lui `Empty()`, nu `Isnull(x) Or Empty(x)`. +- `TYPE()` pe o variabila cu NULL de tip caracter intoarce tot `'C'` - nu tine loc de `Nvl`. +- Acelasi tratament la orice text construit prin `+` din campuri de cursor + (SQL, mesaje, chei): un singur camp NULL anuleaza tot sirul. + +Simptom tipic cand lipseste garda: `SQL statement parameter is required for non-prepared +SQLEXEC() calls` in `OEXECUTOR.OEXECUTE` - SQL-ul ajuns la `SQLEXEC` era `.NULL.`. diff --git a/docs/conventie_ux_formulare.md b/docs/conventie_ux_formulare.md index 55a1678..6e4b370 100644 --- a/docs/conventie_ux_formulare.md +++ b/docs/conventie_ux_formulare.md @@ -1,64 +1,53 @@ -# Convenție UX pentru formulare VFP (preferința lui Marius, valabilă pe toate proiectele ROA*) - -Partajat între proiectele ROA* (similar cu `PROMPT_cautare_vfp.md`, `prompt_project_insights_docs.md` -din acest folder) — pentru că `COMUN\` e clonat/sincronizat în fiecare aplicație ROA, e locul -corect pentru o convenție de design care nu ține de un singur proiect. - -Origine: confirmat de Marius pe `frm_autopass.scx` (ROAAUTO) după o rundă de regrupare vizuală -(2026-07-10) — "imi place designul acesta" pe layout-ul cu rânduri clar separate pe funcție, -butoane grupate la margini, fără elemente lipite unele de altele. - -## Ce înseamnă in practică, pe proprietăți VFP - -- **Fiecare grup funcțional pe rândul lui** — nu înghesui controale fără legătură directă pe - același `Top`. Ex: rândul de perioadă (date + Actualizează) separat de rândul de - statistici (Declarabile/Transmise/Blocate), separat de panoul de configurare. -- **Spațiere vizibilă între grupuri, strânsă în interiorul unui grup** — butoane din - aceeași acțiune (ex. Validează dry-run → Transmite → Renunță) la 6-10px unele de altele; - gap de 20-30px față de următorul grup funcțional (ex. Selectează tot vs. grupul - Validare/Transmitere vs. Actualizează statusuri). -- **Butoanele secundare/de configurare aliniate la marginea din dreapta a containerului**, - nu lipite imediat după textbox-ul pe care îl controlează — altfel nu se disting vizual ca - acțiune separată de câmpul de input. -- **Acțiunea principală + oprirea ei alăturate** — un buton de tip "Renunță/Oprește" trebuie - poziționat lângă acțiunea pe care o anulează (ex. Transmite + Renunță), nu împrăștiat în - altă parte a rândului. -- **Un singur rând de acțiuni cât se poate** — dacă mai multe grupuri de butoane încap pe - lățimea formei, preferă un singur rând orizontal în loc să adaugi rânduri noi dedesubt; - păstrează formele compacte pe verticală. -- **Caption-uri scurte, sentence case, nu ALL CAPS** — ex. "Transmite" nu "TRANSMITE"; - "Dashboard AutoPass" nu "Deschide dashboard AUTOPASS". ALL CAPS/text lung pe un buton - citește ca zgomot, nu ca ierarhie. -- **Culoare = semnal, nu decor** — folosește culoare distinctă doar pentru acțiuni cu - semnificație clară (verde = acțiune pozitivă/transmite, roșu = oprire/pericol, albastru = - navigare/deschidere link extern); restul butoanelor rămân stilul implicit din `_baza.vcx`. - -## Clase de controale (confirmat de Marius, 24.07.2026, pe frm_verif_partener_anaf ROACONT) - -- **Intotdeauna controale din `_baza.vcx`, nu controale native VFP** — orice grid, label, - textbox, checkbox etc. dintr-un formular nou se bazeaza pe clasa corespunzatoare din - `COMUN\clase\_baza.vcx`, nu pe clasa nativa Visual FoxPro. Clasele din `_baza.vcx` au - fontul default **Arial 10** — nu se suprascrie FontName pe controale (explicit: fara - Arial Narrow). -- **Butoanele de inchidere/confirmare stau in bara de titlu**, din `cmd_butoane.vcx` — - modelul Renunt/Termin (clasa de forma `frm_termin_renunt` din `_frm_child.vcx` le aduce - deja). Nu se dubleaza aceste actiuni cu butoane in corpul formei. -- **Actiunile care au corespondent `but_*` in `cmd_butoane.vcx`** (Nou/Adauga, Modifica, - Salveaza, Sterge, Verifica etc.) folosesc CU PREDILECTIE clasa dedicata `but_*` - respectiva — nu se improvizeaza un buton generic pentru o actiune care are deja clasa ei. -- **Doar actiunile FARA corespondent `but_*`** primesc butoane pe clasele `cmd_*` din - `cmd_butoane.vcx` (ex. `cmd_executa`) — nu clase improvizate si nu CommandButton nativ. - -## Vocabular - -Funcțional, compact, aerisit, minimalist, grupat, ușor de înțeles de utilizatori, aer aerisit, -modern — asta e reperul calitativ pentru orice formular nou sau refacere de layout, dincolo de -regulile mecanice de mai sus, pe orice aplicație ROA*. - -## Vezi și - -- `PROMPT_cautare_vfp.md` din acest folder — cum se caută/editează cod în binarele VFP text-cache - (relevant când aplici aceste reguli prin fluxul `.sc2`/`.vc2` + write-back). -- `conventie_encoding_cp1252.md` din acest folder — capcana de corupere a diacriticelor la - editarea `.sc2`/`.vc2`; relevantă ori de câte ori editezi text-cache-ul unui formular/librărie - pentru a aplica aceste reguli de UX. +# Convenție UX pentru formulare VFP (preferința lui Marius, valabilă pe toate proiectele ROA*) + +Partajat între proiectele ROA* — `COMUN\` e clonat/sincronizat în fiecare aplicație ROA, e locul +corect pentru o convenție de design care nu ține de un singur proiect. + +## Ce înseamnă in practică, pe proprietăți VFP + +- **Fiecare grup funcțional pe rândul lui**, nu înghesuit pe același `Top` cu altul fără + legătură (ex: perioadă / statistici / configurare, pe rânduri separate). +- **Spațiere vizibilă între grupuri, strânsă în interiorul unui grup** — butoane din aceeași + acțiune la 6-10px unele de altele; gap de 20-30px față de următorul grup funcțional. +- **Butoanele secundare/de configurare aliniate la marginea din dreapta a containerului**, nu + lipite imediat după textbox-ul pe care îl controlează — altfel nu se disting ca acțiune + separată de câmpul de input. +- **Acțiunea principală + oprirea ei alăturate** (ex. Transmite + Renunță), nu împrăștiate în + altă parte a rândului. +- **Un singur rând de acțiuni cât se poate** — un rând orizontal in loc de rânduri noi + dedesubt; formele rămân compacte pe verticală. +- **Caption-uri scurte, sentence case, nu ALL CAPS** — ex. "Transmite" nu "TRANSMITE". ALL + CAPS/text lung pe un buton citește ca zgomot, nu ca ierarhie. +- **Culoare = semnal, nu decor** — doar pentru acțiuni cu semnificație clară (verde = + pozitiv/transmite, roșu = oprire/pericol, albastru = navigare/link extern); restul butoanelor + rămân stilul implicit din `_baza.vcx`. + +## Clase de controale (confirmat de Marius, 24.07.2026, pe frm_verif_partener_anaf ROACONT) + +- **Intotdeauna controale din `_baza.vcx`, nu controale native VFP** — orice grid, label, + textbox, checkbox etc. dintr-un formular nou se bazeaza pe clasa corespunzatoare din + `COMUN\clase\_baza.vcx`, nu pe clasa nativa Visual FoxPro. Clasele din `_baza.vcx` au + fontul default **Arial 10** — nu se suprascrie FontName pe controale (explicit: fara + Arial Narrow). +- **Butoanele de inchidere/confirmare stau in bara de titlu**, din `cmd_butoane.vcx` — + modelul Renunt/Termin (clasa de forma `frm_termin_renunt` din `_frm_child.vcx` le aduce + deja). Nu se dubleaza aceste actiuni cu butoane in corpul formei. +- **Actiunile care au corespondent `but_*` in `cmd_butoane.vcx`** (Nou/Adauga, Modifica, + Salveaza, Sterge, Verifica etc.) folosesc CU PREDILECTIE clasa dedicata `but_*` + respectiva — nu se improvizeaza un buton generic pentru o actiune care are deja clasa ei. +- **Doar actiunile FARA corespondent `but_*`** primesc butoane pe clasele `cmd_*` din + `cmd_butoane.vcx` (ex. `cmd_executa`) — nu clase improvizate si nu CommandButton nativ. + +## Vocabular + +Funcțional, compact, aerisit, minimalist, grupat, ușor de înțeles de utilizatori, modern — +asta e reperul calitativ pentru orice formular nou sau refacere de layout, pe orice +aplicație ROA*. + +## Vezi și + +- `PROMPT_cautare_vfp.md` din acest folder — cum se caută/editează cod în binarele VFP text-cache + (relevant când aplici aceste reguli prin fluxul `.sc2`/`.vc2` + write-back). +- `conventie_encoding_cp1252.md` din acest folder — capcana de corupere a diacriticelor la + editarea `.sc2`/`.vc2`; relevantă ori de câte ori editezi text-cache-ul unui formular/librărie + pentru a aplica aceste reguli de UX. diff --git a/docs/depanare_testare_vfp.md b/docs/depanare_testare_vfp.md index 4cca468..3df7970 100644 --- a/docs/depanare_testare_vfp.md +++ b/docs/depanare_testare_vfp.md @@ -26,22 +26,20 @@ $p = Start-Process 'C:\Program Files (x86)\Microsoft Visual FoxPro 9\vfp9.exe' - $p.WaitForExit(120000); if (!$p.HasExited) { $p.Kill() } ``` - `-A` ignora config.fpw implicit, `-T` sare peste splash; **ambele obligatorii** - fara `-T` - procesul ramane pe ecranul de intampinare (simptom identic cu o eroare de compilare). - Un `-c` explicit (lipit de flag) e preluat chiar si impreuna cu `-A`. -- **SAFETY**: sub `-A` porneste ON, deci primul `STRTOFILE` peste un log existent (sau - `COMPILE` peste un `.err`/`.fxp` existent) scoate dialogul modal "overwrite?" si procesul - pare agatat. Pune `SET SAFETY OFF` ca PRIMA linie din script si/sau `SAFETY=OFF` + - `RESOURCE=OFF` intr-un config.fpw propriu pasat cu `-c`. Verificare: logheaza - `SET("SAFETY")`/`SET("RESOURCE")` la start. + procesul ramane pe ecranul de intampinare (simptom identic cu o eroare de compilare). `-c` + explicit (lipit de flag) e preluat si cu `-A`. +- **SAFETY**: sub `-A` porneste ON - primul `STRTOFILE` peste un log existent (sau `COMPILE` peste + un `.err`/`.fxp` existent) scoate dialogul modal "overwrite?" si procesul pare agatat. Pune + `SET SAFETY OFF` ca PRIMA linie din script si/sau `SAFETY=OFF`+`RESOURCE=OFF` intr-un config.fpw + propriu pasat cu `-c`. Verificare: logheaza `SET("SAFETY")`/`SET("RESOURCE")` la start. - In script: logare cu STRTOFILE (nu WAIT WINDOW / debugger - nu exista consola); `ON ERROR DO WITH ERROR(), MESSAGE(), PROGRAM(), LINENO()` care logheaza si continua (mimeaza ErrorHandler); `QUIT` obligatoriu la final. - `LINENO()` din handler e relativ la inceputul metodei: linia in `.vc2` = linia raportata + linia `PROCEDURE`. -- Nu rula cu IDE-ul sau exe-ul aplicatiei deschis (lock pe binare); sterge `.fxp`-ul vechi - daca ai editat scriptul intre rulari. Daca nu-l stergi, VFP ruleaza codul vechi din `.fxp` - fara niciun semn - testul poate trece si raportul poate parea valid, desi modificarea nu a - fost executata; se prinde doar dupa ce lipseste din log o linie pe care o scrie doar codul nou. +- Nu rula cu IDE-ul sau exe-ul aplicatiei deschis (lock pe binare); sterge `.fxp`-ul vechi dupa + editarea scriptului - altfel VFP ruleaza codul vechi din `.fxp` fara niciun semn (testul poate + trece fals; se prinde doar cand lipseste din log o linie scrisa doar de codul nou). - Forme modale: `Show(1)` blocheaza. Replica in script doar liniile relevante din Show, sau seteaza `WindowType = 0`. @@ -69,7 +67,7 @@ Cel mai ieftin test dupa o modificare: `COMPILE` headless, fara aplicatie si far ## 5. Bisectia versiunilor de clase (regresii) -Cand un bug apare "de azi", compara cu clasa veche fara a atinge SVN: +Cand un bug apare "de azi", compara cu clasa veche fara sa atingi SVN: 1. `git show :clase\fisier.vcx > temp\fisier.vcx` (+ `.vct`); pentru diff lizibil, `vcx2txt.ps1 -Source temp\fisier.vcx -CacheRoot temp\txt`. 2. In harness incarca DOAR copia (`SET CLASSLIB TO temp\fisier.vcx`), **nu ADDITIVE peste cea @@ -89,8 +87,8 @@ Cand un bug apare "de azi", compara cu clasa veche fara a atinge SVN: pe copie crapa; recreeaza indexul dupa copiere. Acelasi lucru pentru cursorii creati intr-un test: trebuie sa aiba EXACT indecsii pe care ii creeaza fluxul real inainte de instantiere, altfel ordinea/logica difera si testul da rezultat fals. -- **Un grid isi pierde TOATE coloanele** (`ColumnCount` devine 0, fara eroare in log) daca un - ControlSource crapa la re-evaluare in timp ce coloanele sunt atinse programatic (ex. font per +- **Un grid isi pierde TOATE coloanele** (`ColumnCount` devine 0, fara eroare in log) daca + ControlSource crapa la re-evaluare cat timp coloanele sunt atinse programatic (ex. font per coloana la Init). Simptome in aval: `attachtogrid` copiaza 0 coloane, apoi `calctotal` da "Property is not found". Similar, un cursor legat la grid recreat de Init lasa grid-ul fara coloane (eroare 1925). @@ -100,25 +98,24 @@ Cand un bug apare "de azi", compara cu clasa veche fara a atinge SVN: - **Coloana de grid cu ControlSource EXPRESIE (nu camp) cere `Bound = .F.`** Fara el: eroare 9 "Data type mismatch" la `CREATEOBJECT`-ul formei (faza de constructie, raportata la linia apelanta, Details gol). -- **Erorile de instantiere sunt raportate la linia `CREATEOBJECT`, nu la `.Init`**: daca +- **Erorile de instantiere se raporteaza la linia `CREATEOBJECT`, nu la `.Init`**: daca `Procedure` = scriptul apelant, eroarea vine din evaluarea definitiei clasei (`ADD OBJECT ... - WITH RowSource`, ControlSource-expresie), pentru ca bind-ul controalelor native se rezolva la + WITH RowSource`, ControlSource-expresie) - bind-ul controalelor native se rezolva la CONSTRUCTIE, inainte de `Init`. -- **Literal string > 255 caractere = eroare de COMPILARE, nu de runtime** (masurat 24.07.2026: - 255 trece, 256 pica). Mesaj: `Unrecognized command verb` daca linia incepe cu un apel de - metoda, `Command contains unrecognized phrase/keyword` la o atribuire. Insidios: restul - programului ruleaza, doar linia aceea lipseste din `.fxp` si da eroare 16 cand se ajunge la - ea. De aceea SQL-ul lung se scrie cu `TEXT TO [TEXTMERGE] NOSHOW ... ENDTEXT` sau - concatenat. Verificare: `awk 'length($0) > 260 {print NR": "length($0)}' fisier.prg`. -- **Linie de COD (nu doar literal string) prea lunga intr-o metoda de clasa `.vc2` poate - arunca eroarea 11 ("Function argument value, type, or count is invalid") pe PRIMA - instructiune a metodei, nu pe linia vinovata** - simptom complet derutant. Se exclude prin - diagnostic: aceeasi expresie merge normal la nivel de program, in alta clasa, intr-o - subclasa cu metoda noua, si pe instanta virgina - deci nu tine de tipul datelor, de context - sau de clasa parinte. Reper practic: linii preexistente >200 caractere intr-o clasa mare - functioneaza pana la ~250; pragul real e in jur de 255, ca la literalii de string. Remediu: - sparge expresia in pasi cu variabile locale. Verificare (comparat intre fisierul curent si - un backup anterior): +- **Literal string > 255 caractere = eroare de COMPILARE, nu runtime** (255 trece, 256 pica). + Mesaj: `Unrecognized command verb` daca linia incepe cu un apel de metoda, + `Command contains unrecognized phrase/keyword` la o atribuire. Insidios: restul programului + ruleaza, doar linia lipseste din `.fxp` si da eroare 16 cand se ajunge la ea. De aceea SQL-ul + lung se scrie cu `TEXT TO [TEXTMERGE] NOSHOW ... ENDTEXT` sau concatenat. Verificare: + `awk 'length($0) > 260 {print NR": "length($0)}' fisier.prg`. +- **Linie de COD (nu doar literal string) prea lunga intr-o metoda de clasa `.vc2` poate arunca + eroarea 11 ("Function argument value, type, or count is invalid") pe PRIMA instructiune a + metodei, nu pe linia vinovata** - simptom derutant. Se exclude prin diagnostic: aceeasi + expresie merge normal la nivel de program, in alta clasa, intr-o subclasa cu metoda noua, si + pe instanta virgina - deci nu tine de tipul datelor, de context sau de clasa parinte. Reper + practic: linii preexistente >200 caractere intr-o clasa mare functioneaza pana la ~250; pragul + real e in jur de 255, ca la literalii de string. Remediu: sparge expresia in pasi cu variabile + locale. Verificare (comparat intre fisierul curent si un backup anterior): ```powershell $l=[IO.File]::ReadAllLines($p,[Text.Encoding]::GetEncoding(28591)) for($i=0;$i -lt $l.Length;$i++){ if($l[$i].Length -gt 200){ "{0}: len={1}" -f ($i+1), $l[$i].Length } } @@ -126,27 +123,31 @@ Cand un bug apare "de azi", compara cu clasa veche fara a atinge SVN: - **Un UDF care citeste campul curent (`Nvl(camp,0)=1` sau similar) nu e de incredere intr-o clauza de filtrare** (`SELECT ... WHERE`, `LOCATE FOR`, `SCAN FOR`, `DELETE FOR`) - pointerul nu e garantat pe randul evaluat la fiecare apel, deci filtrul devine practic o valoare - constanta (fie nu se declanseaza niciodata, fie loveste tot). Simptome vazute: o comasare de - randuri care nu se mai producea deloc; un test agatat. Remediu: in clauze de filtrare - foloseste expresia INLINE pe camp (`Nvl(camp,0) <> 1`); pastreaza helper-ul doar in cod - procedural (`If`, `Replace` pe randul curent), unde pointerul e garantat pozitionat. + constanta (nu se declanseaza deloc, sau loveste tot). Simptome vazute: comasare de randuri + care nu se mai producea deloc; test agatat. Remediu: in clauze de filtrare foloseste expresia + INLINE pe camp (`Nvl(camp,0) <> 1`); pastreaza helper-ul doar in cod procedural (`If`, + `Replace` pe randul curent), unde pointerul e garantat pozitionat. + +- **`SET PROCEDURE TO x.prg`**: in `.exe` se rezolva din modulele compilate (orice `.prg` din + `.pjx`), din IDE doar prin `SET PATH`. O cale lipsa din `SET PATH` se vede deci doar necompilat, + iar in `Try` trece tacut. ## 7. Capcane la SCRIEREA scriptului de test - **`SET SAFETY OFF` in primele linii, INAINTE de orice `STRTOFILE`/`CREATE CURSOR`** (plus - `SET TALK OFF`). Fara el VFP deschide dialogul de confirmare la suprascrierea fisierului de - log, iar headless dialogul blocheaza procesul pana la timeout. Suitele existente il au deja - - capcana apare la scripturile ad-hoc, scrise repede pentru o masuratoare. + `SET TALK OFF`). Fara el VFP deschide dialogul de confirmare la suprascriere, iar headless + dialogul blocheaza procesul pana la timeout. Suitele existente il au deja - capcana apare la + scripturile ad-hoc, scrise repede pentru o masuratoare. - **`DEFINE CLASS ... ENDDEFINE` nu poate sta la mijlocul programului principal.** Toate liniile - de DUPA `ENDDEFINE` dau "Statement is not in a procedure" (vezi `